Home > OS >  Flutter and audioplayer: cannot stop playing audio between 2 classes
Flutter and audioplayer: cannot stop playing audio between 2 classes

Time:04-30

**Hello,

I am new to Flutter, I hope you will be able to understand my problem. I am using “AudioPlayers” and would like to play audio from a defined page and class, and be able to stop music from another class which is in the same page. In my code, if I stay in the same class, everything works, but as soon as the audio is started and I switch to another class (by a link), the audio continues to play, and the STOP button does not work. Here is my code which I explain a bit.

There are 3 classes:

note: it will be possible to see in which class we are, thanks to the appbar.

class 1 : 2 buttons, play/pause and stop this class works perfectly. When I click STOP the audio stops and we go to class 2.

class 2 : 2 buttons also, play/pause and "to class 3" The play/pause button works fine, and when I click "to class 3" it works too, and the audio keeps playing, that's also what I want, so so far so good.

class 3 = 2 buttons, play/pause and stop. The problem is that the stop button does not work. It does not stop the Audi launched from the Class2

What I could see is:

  • that the buttons work as long as they are in the same class
  • audio continues to play even after changing a class
  • the stop button only works on audio launched on its own class. If the audio was started on another class, the stop button does not work.

Can you help me solve this problem?

If you also have this possibility which is less important to solve: I would like for example that when I am in class 1 and I click on the stop button, that the audio stops and I switch to class 2 , that the class 2 audio starts automatically, without having to click on the play button.

Thank you in advance for your help.

Here is the full code : **

import 'dart:typed_data';

import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';



class Class1 extends  StatefulWidget {
  @override
  State<Class1> createState() => _Class1State();
}

class _Class1State extends State<Class1> {

  int maxduration = 100;
  int currentpos = 0;
  String currentpostlabel = "00:00";
  String audioasset = "assets/audio/audio1.mp3";
  bool isplaying = false;
  bool audioplayed = false;
  late Uint8List audiobytes;


  AudioPlayer player = AudioPlayer();

  @override
  void initState() {
    Future.delayed(Duration.zero, () async {

      ByteData bytes = await rootBundle.load(audioasset); //load audio from assets
      audiobytes = bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes);
      //convert ByteData to Uint8List

      player.onDurationChanged.listen((Duration d) { //get the duration of audio
        maxduration = d.inMilliseconds;
        setState(() {

        });
      });

      player.onAudioPositionChanged.listen((Duration  p){
        currentpos = p.inMilliseconds; //get the current position of playing audio

        //generating the duration label
        int shours = Duration(milliseconds:currentpos).inHours;
        int sminutes = Duration(milliseconds:currentpos).inMinutes;
        int sseconds = Duration(milliseconds:currentpos).inSeconds;

        int rhours = shours;
        int rminutes = sminutes - (shours * 60);
        int rseconds = sseconds - (sminutes * 60   shours * 60 * 60);

        currentpostlabel = "$rhours:$rminutes:$rseconds";

        setState(() {
          //refresh the UI
        });
      });

    });
    super.initState();


  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text("Class1"),
            backgroundColor: Colors.blue
        ),
        body: Container(
            margin: EdgeInsets.only(top:50),
            child: Column(
              children: [

                Container(
                  child: Wrap(
                    spacing: 10,
                    children: [
                      ElevatedButton.icon(
                          onPressed: () async {
                            if(!isplaying && !audioplayed){
                              int result = await player.playBytes(audiobytes);
                              if(result == 1){ //play success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error while playing audio.");
                              }
                            }else if(audioplayed && !isplaying){
                              int result = await player.resume();
                              if(result == 1){ //resume success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error on resume audio.");
                              }
                            }else{
                              int result = await player.pause();
                              if(result == 1){ //pause success
                                setState(() {
                                  isplaying = false;
                                });
                              }else{
                                print("Error on pause audio.");
                              }
                            }
                          },
                          icon: Icon(isplaying?Icons.pause:Icons.play_arrow),
                          label:Text(isplaying?"Pause":"Play")
                      ),

                      ElevatedButton.icon(
                          onPressed: ()  {

                            setState(() {
                              Navigator.pushReplacement(
                                  context,
                                  PageRouteBuilder(
                                    pageBuilder: (context, animation1, animation2) => Class2(),
                                    transitionDuration: Duration.zero,
                                  )
                              );
                            });

                            setState(() async {
                              int result = await player.stop();
                              if(result == 1){ //stop success
                                setState(() {
                                  isplaying = false;
                                  audioplayed = false;
                                  currentpos = 0;
                                });
                              }else{
                                print("Error on stop audio.");
                              }
                            });

                          },
                          icon: Icon(Icons.stop),
                          label:Text("Stop")
                      ),



                    ],
                  ),
                )

              ],
            )

        )
    );
  }

}








class Class2 extends  StatefulWidget {
  @override
  State<Class2> createState() => _Class2State();
}

class _Class2State extends State<Class2> {

  int maxduration = 100;
  int currentpos = 0;
  String currentpostlabel = "00:00";
  String audioasset = "assets/audio/audio2.mp3";
  bool isplaying = false;
  bool audioplayed = false;
  late Uint8List audiobytes;


  AudioPlayer player = AudioPlayer();

  @override
  void initState() {
    Future.delayed(Duration.zero, () async {

      ByteData bytes = await rootBundle.load(audioasset); //load audio from assets
      audiobytes = bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes);
      //convert ByteData to Uint8List

      player.onDurationChanged.listen((Duration d) { //get the duration of audio
        maxduration = d.inMilliseconds;
        setState(() {

        });
      });

      player.onAudioPositionChanged.listen((Duration  p){
        currentpos = p.inMilliseconds; //get the current position of playing audio

        //generating the duration label
        int shours = Duration(milliseconds:currentpos).inHours;
        int sminutes = Duration(milliseconds:currentpos).inMinutes;
        int sseconds = Duration(milliseconds:currentpos).inSeconds;

        int rhours = shours;
        int rminutes = sminutes - (shours * 60);
        int rseconds = sseconds - (sminutes * 60   shours * 60 * 60);

        currentpostlabel = "$rhours:$rminutes:$rseconds";

        setState(() {
          //refresh the UI
        });
      });

    });

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text("Class2"),
            backgroundColor: Colors.blueAccent
        ),
        body: Container(
            margin: EdgeInsets.only(top:50),
            child: Column(
              children: [


                Container(
                  child: Wrap(
                    spacing: 10,
                    children: [
                      ElevatedButton.icon(
                          onPressed: () async {
                            if(!isplaying && !audioplayed){
                              int result = await player.playBytes(audiobytes);
                              if(result == 1){ //play success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error while playing audio.");
                              }
                            }else if(audioplayed && !isplaying){
                              int result = await player.resume();
                              if(result == 1){ //resume success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error on resume audio.");
                              }
                            }else{
                              int result = await player.pause();
                              if(result == 1){ //pause success
                                setState(() {
                                  isplaying = false;
                                });
                              }else{
                                print("Error on pause audio.");
                              }
                            }
                          },
                          icon: Icon(isplaying?Icons.pause:Icons.play_arrow),
                          label:Text(isplaying?"Pause":"Play")
                      ),

                      ElevatedButton.icon(
                          onPressed: ()  {

                            setState(() {
                              Navigator.pushReplacement(
                                  context,
                                  PageRouteBuilder(
                                    pageBuilder: (context, animation1, animation2) => Class3(),
                                    transitionDuration: Duration.zero,
                                  )
                              );
                            });


                          },
                          icon: Icon(Icons.stop),
                          label:Text("To Class3")
                      ),


                    ],
                  ),
                )

              ],
            )

        )
    );
  }





}





class Class3 extends  StatefulWidget {
  @override
  State<Class3> createState() => _Class3State();
}

class _Class3State extends State<Class3> {

  int maxduration = 100;
  int currentpos = 0;
  String currentpostlabel = "00:00";
  String audioasset = "assets/audio/audio3.mp3";
  bool isplaying = false;
  bool audioplayed = false;
  late Uint8List audiobytes;


  AudioPlayer player = AudioPlayer();


  @override
  void initState() {
    Future.delayed(Duration.zero, () async {

      ByteData bytes = await rootBundle.load(audioasset); //load audio from assets
      audiobytes = bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes);
      //convert ByteData to Uint8List

      player.onDurationChanged.listen((Duration d) { //get the duration of audio
        maxduration = d.inMilliseconds;
        setState(() {

        });
      });

      player.onAudioPositionChanged.listen((Duration  p){
        currentpos = p.inMilliseconds; //get the current position of playing audio

        //generating the duration label
        int shours = Duration(milliseconds:currentpos).inHours;
        int sminutes = Duration(milliseconds:currentpos).inMinutes;
        int sseconds = Duration(milliseconds:currentpos).inSeconds;

        int rhours = shours;
        int rminutes = sminutes - (shours * 60);
        int rseconds = sseconds - (sminutes * 60   shours * 60 * 60);

        currentpostlabel = "$rhours:$rminutes:$rseconds";

        setState(() {
          //refresh the UI
        });
      });

    });
    super.initState();


  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text("Class3"),
            backgroundColor: Colors.blueGrey
        ),
        body: Container(
            margin: EdgeInsets.only(top:50),
            child: Column(
              children: [

                Container(
                  child: Wrap(
                    spacing: 10,
                    children: [
                      ElevatedButton.icon(
                          onPressed: () async {
                            if(!isplaying && !audioplayed){
                              int result = await player.playBytes(audiobytes);
                              if(result == 1){ //play success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error while playing audio.");
                              }
                            }else if(audioplayed && !isplaying){
                              int result = await player.resume();
                              if(result == 1){ //resume success
                                setState(() {
                                  isplaying = true;
                                  audioplayed = true;
                                });
                              }else{
                                print("Error on resume audio.");
                              }
                            }else{
                              int result = await player.pause();
                              if(result == 1){ //pause success
                                setState(() {
                                  isplaying = false;
                                });
                              }else{
                                print("Error on pause audio.");
                              }
                            }
                          },
                          icon: Icon(isplaying?Icons.pause:Icons.play_arrow),
                          label:Text(isplaying?"Pause":"Play")
                      ),



                      ElevatedButton.icon(
                          onPressed: ()  {

                            setState(() async {
                              int result = await player.stop();
                              if(result == 1){ //stop success
                                setState(() {
                                  isplaying = false;
                                  audioplayed = false;
                                  currentpos = 0;
                                });
                              }else{
                                print("Error on stop audio.");
                              }
                            });



                          },
                          icon: Icon(Icons.stop),
                          label:Text("Stop")
                      ),


                    ],
                  ),
                )

              ],
            )

        )
    );
  }





}

CodePudding user response:

I believe the reason that the stop button is not working is due to each class having it's own instance of the AudioPlayer. Meaning they cannot interact with the previous classes player and why the stop button is not working.

There are several ways to fix this. However, looking at the code in your example there is alot of duplicated code and unsure why you require three classes (not fully read all the lines of code). One solution is to separate the AudioPlayer and its functionalities into its own class and manage it state in each of the classes. Essentially only having one instance of the AudioPlayer in which all you classes can interact with.

CodePudding user response:

I am not quite sure what you want to achieve in the class3 especially. For each class you have audio player object that are independent from each other. Therefore they act totally independent. And I assume when you switch the classes the audio still playing because you do not call to dispose it.

@override
  void dispose() {
    viewModel.dispose();
    super.dispose();
  }

Besides that, If you want to stop an audio which has started from another class, you should pass the object to other class and make use of it. In your case this is

class Class3 extends  StatefulWidget {
final AudioPlayer player;
  const Class3 ({
  required this.player,
   Key? key
}) : super(key: key);

  @override
  State<Class3> createState() => _Class3State();
}

And while switching classes:

Navigator.pushReplacement(
  context,
  PageRouteBuilder(
        pageBuilder: (context, animation1, animation2) => Class3(player),
                     ....

Therefore this will be passing the audioplayer from class2 to class3 therefore, it can be stopped from class3.

  • Related