SimformSolutionsPvtLtd / audio_waveforms

Use this plugin to generate waveforms while recording audio in any file formats supported by given encoders or from audio files. We can use gestures to scroll through the waveforms or seek to any position while playing audio and also style waveforms
https://pub.dev/packages/audio_waveforms
MIT License
283 stars 150 forks source link

Multiple PlayerController Android issue #347

Open Yousef-Alabdulhadi opened 3 weeks ago

Yousef-Alabdulhadi commented 3 weeks ago

Describe the bug I have a chat app where if one waveform exists, it's fine. Adding another widget to the list that's not related to it breaks it. Works fine on iOS. To Reproduce Steps to reproduce

Have multiple widgets that use a playercontroller in the widget tree.

Expected behavior On iOS you should be able to play which ever you want. On android it just break and it also does not throw an error. It will be stuck in prepare player. Smartphone (please complete the following information):

ujas-m-simformsolutions commented 3 weeks ago

@Yousef-Alabdulhadi Can you please share reproducible code so that we can find the issue?

Yousef-Alabdulhadi commented 3 weeks ago

This is how im preparing it

late final PlayerController playerController;

@override initState() { super.initState(); playerController = PlayerController(); }

Future preparePlayer() async { if (audioPath == null) return; debugPrint('Preparing player');

preparing = true;
if (mounted) setState(() {});

try {
  await playerController
      .preparePlayer(
    path: audioPath!,
    volume: 1.0,
  )
      .timeout(Duration(seconds: 6), onTimeout: () {
    debugPrint('Timeout');
    preparing = false;
    prepared = false;
    if (mounted) setState(() {});
    return;
  });
} catch (e) {
  debugPrint(e.toString());
  debugPrint('Timeout');
  preparing = false;
  prepared = false;
  if (mounted) setState(() {});
  return;
}

await playerController.extractWaveformData(
  path: audioPath!,
  noOfSamples: playerWaveStyle.getSamplesForWidth(width),
);

playDuration = playerController.maxDuration ~/ 1000;
widget.message.duration = playDuration;

await db.messageDao.updateDuration(widget.message.id, playDuration);
playerController.onPlayerStateChanged.listen((state) {
  if (mounted) setState(() {});
});

playerController.onCurrentDurationChanged.listen((duration) {
  playDuration = duration ~/ 1000;
  if (mounted) setState(() {});
});
prepared = true;
preparing = false;
if (mounted) setState(() {});

}

ujas-m-simformsolutions commented 3 weeks ago

@Yousef-Alabdulhadi The only issue with shared code I see is that you're calling extractWaveformData and preparePlayer(shouldExtractWaveform: true(default)) so waveforms are extracted by default with preparePlayer. In this case, you don't have call extractWaveformData again for this. Other than that I will check how you using it in the widget tree and are you using same controller for all widget?