skip to Main Content

I have like 10 – 15 audio, and I need to play them one after another or you can say merge them. They are dynamic(I get the urls from server). I’m using the just_audio packege for playing audio. I’m using ConcatenatingAudioSource to play one audio after another

This is how I initialize the player

late AudioPlayer _audioPlayer;
  List<AudioPlayer> players = [];
  ConcatenatingAudioSource concatenatingAudioSource =
      ConcatenatingAudioSource(children: []);

@override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      final state = ref.watch(homeController);
      state.ayahList.forEach((element) async {
        final player = AudioPlayer();
        await player.setUrl('https://example.com/$element.mp3');
        players.add(player);
      });
      final audioSources = players
          .map((player) => player.audioSource ?? AudioSource.uri(Uri()))
          .toList();
      concatenatingAudioSource =
          ConcatenatingAudioSource(children: audioSources);
      _audioPlayer = AudioPlayer()..setAudioSource(concatenatingAudioSource);
    });
  }

This is the UI, it’s very simple

@override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: audioPlayer.playerStateStream,
        builder: (context, snapshot) {
          final playerState = snapshot.data;
          final processingState = playerState?.processingState;
          final playing = playerState?.playing;
          if (!(playing ?? false)) {
            return IconButton(
                onPressed: () => audioPlayer.play(),
                icon: const Icon(Icons.play_arrow_rounded));
          } else if (processingState != ProcessingState.completed) {
            return IconButton(
                onPressed: () => audioPlayer.pause(),
                icon: const Icon(Icons.pause_rounded));
          }
          return const Icon(Icons.play_arrow_rounded);
        });
  }

Now when I click the play button, nothing happens, nothing on the log as well. Maybe I got the whole wrong idea about concatenatingAudioSource, I don’t know. Please help me

2

Answers


  1. Chosen as BEST ANSWER

    I figured out another way to play one audio after another

    onPressed: () {
                  audioPlayer.setUrl(
                      'https:example.com/${state.ayahList[i-1]}.mp3');
                  audioPlayer.play();
    
                  audioPlayer.playerStateStream.listen((event) async {
                    if (event.processingState == ProcessingState.completed) {
                      if (i < state.ayahList.length) {
                        audioPlayer.setUrl(
                            'https://example.com/${state.ayahList[i]}.mp3');
                        await audioPlayer.play().then((value) => i++);
    
                      } else {
                        i = 0;
                      }
                    }
                  });
                },
    

  2. It might be because ref.watch is used during initState. This is not the place to put a watch as it will not be "watched".

    At this point, if you’re sure that homeController is well initialized and you don’t want to re-trigger the code block within addPostframeCallback, you can use ref.read instead.

    Otherwise you should define a function like handleHomeControllerChanged, listen to your homeController inside build method (you should change your statefulWidget to consumerWidget in order to be able to have access to ref.listen). This way, you can listen to changes on homeController and re-trigger the function each time the controller changes.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search