Giter Site home page Giter Site logo

Comments (28)

ryanheise avatar ryanheise commented on July 23, 2024

I generally try to use the preconditions imposed by the platform. That's the goal, but I haven't quite gotten there when it comes to the connecting and buffering states where the logic is a little more difficult. I'm with you in that the goal should be for these preconditions to be as few as possible. I'm not there yet, but that is the direction.

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

The latest git commit should address this for Android.

I've also updated the state model on both Android and iOS so that the buffering state is treated independently of the other states. So now you can be buffering while playing, and you can be buffering while pausing, and these states are distinguishable. However, on iOS, the way I've implemented it, I can't really detect buffering while pausing anyway.

Also, I noticed a bug on Android where if you switched between play/pause or pause/play in the middle of seeking (i.e. while buffering), it would get confused about which state to return to after seeking. This bug goes away after changing the state model.

Let me know how that goes for you, and if it also doesn't break anything on iOS, I'll publish it.

from just_audio.

volgin avatar volgin commented on July 23, 2024

This sounds promising. I will try it ASAP. My immediate reaction is that from a UX perspective, the most important state is “I cannot play because I am buffering”. I hope the new update makes this primary use case possible.

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

Answering @ReaganRealones from #33

@ryanheise, okay sure have checked it out. Understood, that but the issue is still, while the player is connecting and the user cancels, it still continues to connect and thereafter plays. i.e calling stop while the player is in connecting state does not cancel playing music,

Hi @ReaganRealones , are you experiencing this issue on iOS or Android or both?

from just_audio.

ReaganRealones avatar ReaganRealones commented on July 23, 2024

Yeah I am experiencing this on Android

from just_audio.

ReaganRealones avatar ReaganRealones commented on July 23, 2024

@ryanheise found a new issue with the commit.. Should I open a new issue or just mention it here too?

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

This issue is about making the state transitions more permissive so that, for example, you can call stop() while connecting or buffering (which you couldn't do before). Comment here if it's related to that, or start a new issue if not.

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

@ReaganRealones I've just tested the example on Android and was unable to reproduce the issue. If I press the stop button while the player is connecting, it just stops and you don't hear it play.

If what you really mean is that you can still then invoke play after stopping, then probably what you want to do is to invoke dispose instead of stop which puts the player into the none state. From here, it is illegal to transition to the playing state without first transitioning into the stopped state via setUrl.

In hindsight, it probably doesn't make sense to allow stop to be called during connecting, but in an effort to make state transitions more permissible, I've just made it effectively stop giving the exception. But it doesn't really do anything because this method is intended to stop audio that is playing.

from just_audio.

ReaganRealones avatar ReaganRealones commented on July 23, 2024

This issue is about making the state transitions more permissive so that, for example, you can call stop() while connecting or buffering (which you couldn't do before). Comment here if it's related to that, or start a new issue if not.

Its another issue, going to open it too

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

OK. regarding the present issue, have you tried dispose to interrupt the connection?

from just_audio.

ReaganRealones avatar ReaganRealones commented on July 23, 2024

@ReaganRealones I've just tested the example on Android and was unable to reproduce the issue. If I press the stop button while the player is connecting, it just stops and you don't hear it play.

If what you really mean is that you can still then invoke play after stopping, then probably what you want to do is to invoke dispose instead of stop which puts the player into the none state. From here, it is illegal to transition to the playing state without first transitioning into the stopped state via setUrl.

In hindsight, it probably doesn't make sense to allow stop to be called during connecting, but in an effort to make state transitions more permissible, I've just made it effectively stop giving the exception. But it doesn't really do anything because this method is intended to stop audio that is playing.

I am working on a music application, so to ensure that the player can be stopped or played from whichever page, I am using the provider package so I have reference to it anywhere. Now When a user taps on a song to play it, I pop up a bottom bar showing the song details and a preloader in the play pause button if the player is still loading, and a cancel button.

But some times a user may tap on a song and choose to cancel while it's still loading, there I call stop , but if the player is in playing, paused, or stopped states, it works okay, it stops the music. But while it's in loading state, this is what I have observed.

When user taps play song, I call setUrl that now puts the player into connecting state. Now when the user presses cancel. Calling stop puts the player into stopped state. And the subsequent call to play finds it in stopped state.

from just_audio.

ReaganRealones avatar ReaganRealones commented on July 23, 2024

@ReaganRealones I've just tested the example on Android and was unable to reproduce the issue. If I press the stop button while the player is connecting, it just stops and you don't hear it play.
If what you really mean is that you can still then invoke play after stopping, then probably what you want to do is to invoke dispose instead of stop which puts the player into the none state. From here, it is illegal to transition to the playing state without first transitioning into the stopped state via setUrl.
In hindsight, it probably doesn't make sense to allow stop to be called during connecting, but in an effort to make state transitions more permissible, I've just made it effectively stop giving the exception. But it doesn't really do anything because this method is intended to stop audio that is playing.

I am working on a music application, so to ensure that the player can be stopped or played from whichever page, I am using the provider package so I have reference to it anywhere. Now When a user taps on a song to play it, I pop up a bottom bar showing the song details and a preloader in the play pause button if the player is still loading, and a cancel button.

But some times a user may tap on a song and choose to cancel while it's still loading, there I call stop , but if the player is in playing, paused, or stopped states, it works okay, it stops the music. But while it's in loading state, this is what I have observed.

When user taps play song, I call setUrl that now puts the player into connecting state. Now when the user presses cancel. Calling stop puts the player into stopped state. And the subsequent call to play finds it in stopped state.


UPDATE

Fixed. The problem was with my custom play method as it setUrl was always immediately followed by play without checking if the int(duration) returned by setUrl was null (Maybe as a result of calling stop while it's connecting). So play was always called immediately after and since the player by this time is in stopped state at this time, it is legal to call play so it would play again.

Anyways, solution was to first check if the returned duration by setUrl was not null before playing. So I am going to close issue #33 If that's okay?

from just_audio.

ReaganRealones avatar ReaganRealones commented on July 23, 2024

But still @ryanheise thanks for the work as I dont think calling stop on connecting would work before the new commit.

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

Great to hear. Note that I already closed #33 after folding it into this existing issue.

from just_audio.

paulobreim avatar paulobreim commented on July 23, 2024

Hi,
I am using very simple function: My program have only 2 commands:

playsound () async {
await player.setAsset('asset/sound.mp3');
await player.play()
}

and some times I got the exception bellow.
Exception has occurred.
PlatformException (PlatformException(Illegal state: Cannot call play from connecting/none states (connecting), null, null))

I think that it is occurs when I call this function several times is a short interval.

How I can fix it?

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

Currently the best way to avoid this error is to await the result of audioPlayer.setUrl and do not call audioPlayer.play until after that first await completes. This will guarantee that you do not call play until it is actually ready to play.

from just_audio.

paulobreim avatar paulobreim commented on July 23, 2024

but I don't use URL, I use local sound file with await player.setAsset('asset/sound.mp3');

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

Awaiting setAsset would be the same as awaiting setUrl, but if you're still getting that error I may need you to create a minimal reproduction project to allow me to see what's happening in your program.

from just_audio.

paulobreim avatar paulobreim commented on July 23, 2024

Awaiting setAsset would be the same as awaiting setUrl, but if you're still getting that error I may need you to create a minimal reproduction project to allow me to see what's happening in your program.

Here is. The point with comment // is where I got error.

import 'package:flutter/material.dart';
import 'package:batalha_naval/dados.dart';
import 'package:batalha_naval/telamontaesquadra.dart';
import 'package:just_audio/just_audio.dart';
import 'dart:math';
import 'dart:async';

AudioPlayer player;

class TelaJogo extends StatefulWidget {
@OverRide
TelaJogoState createState() {
return TelaJogoState();
}
}

class TelaJogoState extends State {
TextStyle estilo = TextStyle(
fontSize: hsizeItem * .9,
fontWeight: FontWeight.bold,
color: Colors.white,
decoration: TextDecoration.none);
TextStyle estilo2 = TextStyle(
fontSize: hsizeItem * .9,
fontWeight: FontWeight.bold,
color: Colors.black87,
decoration: TextDecoration.none);

bool bloqueia = false;

@OverRide
void initState() {
super.initState();

player = AudioPlayer();

}

@OverRide
void dispose() {
player.dispose();
super.dispose();
}

@OverRide
Widget build(BuildContext context) {

Timer.periodic(Duration(seconds: 1), (timer)  {
  print(DateTime.now());
  if (bloqueia) {
    tiroRecebido();
    setState(() {
      getImageAtaque(0);
      if (acertou) {
        mensagem = 'continue aguardando';
      } else {
        bloqueia = false;
        mensagem = 'Sua vez!';
      }
    });
  }
});

var size = MediaQuery.of(context).size;
final double itemHeight = (size.height - kToolbarHeight - 24) / 2.97;
final double itemWidth = size.width / 2;

return Scaffold(
    body: Column(
  mainAxisAlignment: MainAxisAlignment.start,
  crossAxisAlignment: CrossAxisAlignment.start,
  mainAxisSize: MainAxisSize.max,
  children: <Widget>[
    Flexible(
        flex: 64,
        child: Container(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height, // * .58,
            color: Colors.black,
            child: GridView.count(
                crossAxisCount: 15,
                childAspectRatio: (itemWidth / itemHeight),
                children: List.generate(225, (index) {
                  return IgnorePointer(
                      ignoring: bloqueia,
                      child: Padding(
                          padding: EdgeInsets.all(0.5),
                          child: GestureDetector(
                            onTap: () async {
                              if ((tirosAtaqueCerto != 39) &&
                                  (tirosDefesaCerto != 39)) {
                                setState(() {
                                  bloqueia = true;
                                  mensagem = 'Aguarde...';
                                });
                                await atacarInimigo(index);
                                if ((acertou) && (tirosAtaqueCerto != 39)){
                                  mensagem = 'Atire novamente';
                                  bloqueia = false;
                                }
                                setState(() {
                                  getImageAtaque(index);
                                });
                                // await tiroRecebido();
                              }
                              // setState(() {
                              //   getImageAtaque(index);
                              //   bloqueia = false;
                              // });
                            },
                            child: getImageAtaque(
                                index), // handle your image tap here
                          )));
                })))),
    Flexible(
        flex: 36,
        child: Container(
            height: MediaQuery.of(context).size.height, // * .42,
            width: MediaQuery.of(context).size.width,
            color: Colors.blue,
            child: Row(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                //mainAxisSize: MainAxisSize.max,
                children: [
                  Container(
                    width: MediaQuery.of(context).size.width * .50,
                    height: MediaQuery.of(context).size.height,
                    color: Colors.blue,
                    child: Column(
                        // mainAxisAlignment: MainAxisAlignment.start,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        // mainAxisSize: MainAxisSize.max,
                        children: [
                          Flexible(
                              child: GridView.count(
                                  crossAxisCount: 15,
                                  children: List.generate(225, (index) {
                                    return Padding(
                                        padding: EdgeInsets.all(0.2),
                                        child: GestureDetector(
                                          onTap: () {},
                                          child: getImageDefesa(
                                              index), // handle your image tap here
                                        ));
                                  })))
                        ]),
                  ),
                  Container(
                      width: MediaQuery.of(context).size.width * .50,
                      color: Colors.blue,
                      child: Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          mainAxisSize: MainAxisSize.max,
                          children: [
                            Text(mensagem, style: estilo2),
                            Text(
                              '\n\n Tiros no Alvo: $tirosAtaqueCerto',
                              style: estilo,
                            ),
                            Text(
                              ' Tiros na Água: $tirosAtaqueErrado',
                              style: estilo,
                            ),
                            Text(
                              '\n Tiros Recebidos do Alvo: $tirosDefesaCerto',
                              style: estilo,
                            ),
                            Text(
                              ' Tiros Recebidos na Água: $tirosDefesaErrado\n\n',
                              style: estilo,
                            ),
                            Center(
                                child: RaisedButton(
                                    child: Text('Voltar'),
                                    color:
                                        Color.fromRGBO(0x51, 0x7d, 0xa2, 1),
                                    textColor: Colors.white,
                                    padding: const EdgeInsets.all(5.0),
                                    shape: RoundedRectangleBorder(
                                        borderRadius:
                                            BorderRadius.circular(30.0)),
                                    onPressed: () async {
                                      resetEstato();
                                      Navigator.pop(context, true);
                                    }))
                          ])),
                ]))),
  ],
));

}
}

String pegaImagemDefesa(int index) {
if ((celulaDefesa[index]) == 100) {
//tiro errado
return ('assets/images/azul.jpg');
}
if ((celulaDefesa[index]) == 200) {
//tiro certo
return ('assets/images/vermelho.jpg');
}

if ((celulaDefesa[index]) > 0) {
var cor = cores[corEsquadra - 1];
return ('assets/images/$cor.jpg');
} else {
return ('assets/images/branco.jpg');
}
}

Widget getImageDefesa(int index) {
AssetImage assetImage;
assetImage = AssetImage(pegaImagemDefesa(index));
Image image;

image = Image(image: assetImage, fit: BoxFit.cover);

return image;
}

String pegaImagemAtaque(int index) {
if ((celulaAtaque[index]) == 100) {
//tiro errado
return ('assets/images/azul.jpg');
}
if ((celulaAtaque[index]) == 200) {
//tiro certo
return ('assets/images/vermelho.jpg');
}

return ('assets/images/branco.jpg');
}

Widget getImageAtaque(int index) {
AssetImage assetImage;
assetImage = AssetImage(pegaImagemAtaque(index));
Image image;

image = Image(image: assetImage, fit: BoxFit.cover);

return image;
}

atacarInimigo(int index) async {
var qSom;

if (tirosAtaqueCerto == 39) {
return;
}

if ((celulaAtaque[index]) > 99) {
return;
}

if ((celulaAtaque[index]) > 0) {
//acertou
celulaAtaque[index] = 200;
tirosAtaqueCerto++;
acertou = true;
qSom = 'assets/sound/explosao.mp3';
} else {
//água
celulaAtaque[index] = 100;
tirosAtaqueErrado++;
acertou = false;
qSom = 'assets/sound/agua.mp3';
}
// HERE SOMETIMES I GOT ERROR
// await player.setAsset(qSom);
// try {
// await player.play();
// } catch (e) {}
// await player.stop();

if (tirosAtaqueCerto == 39) {
mensagem = 'YOU WIN !';
} else {
// mensagem = 'Wait.';
}
}

tiroRecebido() async {
String qSom;
if (tirosDefesaCerto == 39) {
return;
}

var rng = new Random();
int x = rng.nextInt(225);

while (celulaDefesa[x] > 99) {
x = rng.nextInt(225);
}

acertou = false;

if (celulaDefesa[x] == 0) {
celulaDefesa[x] = 100;
tirosDefesaErrado++;
qSom = 'assets/sound/agua.mp3';
} else {
if (celulaDefesa[x] != 100) {
celulaDefesa[x] = 200;
acertou = true;
tirosDefesaCerto++;
qSom = 'assets/sound/explosao.mp3';
}
}
// HERE SOMETIMES I GOT ERROR
// await player.setAsset(qSom);
// try {
// await player.play();
// } catch (e) {}
// await player.stop();

if (tirosDefesaCerto == 39) {
mensagem = 'You Lost"';
} else {
mensagem = 'Your turn. Fire';
}
}

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

This is strange. Given the strangeness of it, I'd like you to try a strange test: can you insert the following code after awaiting setAsset and before calling play?

await Future.delayed(Duration(seconds: 1));

from just_audio.

paulobreim avatar paulobreim commented on July 23, 2024

This is strange. Given the strangeness of it, I'd like you to try a strange test: can you insert the following code after awaiting setAsset and before calling play?

await Future.delayed(Duration(seconds: 1));

Here is:
image

Are there away to check if the state is connecting?

from just_audio.

paulobreim avatar paulobreim commented on July 23, 2024

I made o small program to you test.
Just do it:
in the pubspec.yaml put
dependencies:
just_audio: ^0.1.4
assets:

  • assets/sound/
    into folder assets/sound put any mp3 file with 2 seconds sound
    and here is the full source:

import 'package:just_audio/just_audio.dart';
import 'package:flutter/material.dart';
import 'dart:async';

AudioPlayer player;

void main() async {
WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null) WidgetsFlutterBinding();
return WidgetsBinding.instance;
}

ensureInitialized();

player = AudioPlayer();
print('start');
test();
}

test() {
Timer.periodic(Duration(seconds: 1), (timer) async {
print('X');
await player.setAsset('assets/sound/agua.mp3');
await Future.delayed(Duration(seconds: 1));
try {
await player.play();
} catch (e) {}
await player.stop();
});
}

we will get the same problem.

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

I wasn't aware that you were running this code periodically. You do not do anything to guarantee that the previous periodic execution completes before the next one starts, so the previous one still could be trying to play while the current one is in the middle of loading the asset.

it would be safer to do this kind of periodic execution in a loop.

from just_audio.

paulobreim avatar paulobreim commented on July 23, 2024

but await player.play(); does not guarantee the end of the execution?
Are there a function that I can check if the sound are executing?
So I could to like this:
if (player.isstopped) {
await player.setAsset('assets/sound/agua.mp3');
await player.play();
}

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

periodic does not wait for that because it's programmed to repeat at a specific time - i.e. the problem is with periodic.

from just_audio.

paulobreim avatar paulobreim commented on July 23, 2024

OK, thank you. I will change it. Thank you.
I think that we can close this issue.

from just_audio.

ryanheise avatar ryanheise commented on July 23, 2024

I was awating @volgin 's confirmation on the original issue, although I'll assume by now that all is good.

from just_audio.

github-actions avatar github-actions commented on July 23, 2024

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs, or use StackOverflow if you need help with just_audio.

from just_audio.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.