flutter_sound icon indicating copy to clipboard operation
flutter_sound copied to clipboard

[BUG]: onBufferUnderflow parameter not working in startPlayerFromStream

Open superplain99 opened this issue 4 months ago • 3 comments

Flutter Sound Version :

  • FULL or LITE flavor ?

    • After version 9.26.0
  • Important: Result of the command : flutter pub deps | grep flutter_sound


Describe the bug I confirmed that a new onBufferUnderflow parameter was introduced to replace whenFinished for handling stream data in the player. However, this parameter does not seem to work. In the definition of startPlayerFromStream, it is written as onBufferUnderlow (missing the f) instead of onBufferUnderflow. Also, in the code, if fromStream is set to true, it looks like this parameter is not being used at all. Could you please confirm if my understanding is correct?

superplain99 avatar Sep 18 '25 11:09 superplain99

Any news on that? I'm having the same issue using 9.28.0, the callback onBufferUnderflow is never being called

FossaMalaEnt avatar Nov 12 '25 21:11 FossaMalaEnt

It's not working currently but there is a workaround for that. Prerequiste: make sure that your backend returns last chunk for given audio section with isFinal flag marking the last chunk that you are sending.

When you send chunk to the stream wrap that in a method and calculate how many bytes you are sending: // Track bytes for duration calculation _totalBytesSent += audioBytes.length;

When you receive final chunk calculate audio duration and start the timer after which you trigger your own callback.

// Schedule playback finished callback when final chunk is received
if (isFinal && _isPlaying) {
    _schedulePlaybackFinished();
}
...

/// Schedule the playback finished callback based on remaining audio duration
  void _schedulePlaybackFinished() {
    // Calculate total audio duration from bytes sent
    final totalDurationMs =
        (_totalBytesSent * 1000) ~/ (kSampleRate * kNumChannels * kBytesPerSample);

    // Calculate how much time has already elapsed since playback started
    final elapsedMs = _playbackStartTime != null
        ? DateTime.now().difference(_playbackStartTime!).inMilliseconds
        : 0;

    // Remaining time to play (with small buffer for safety)
    final remainingMs = (totalDurationMs - elapsedMs + 100).clamp(0, totalDurationMs + 100);

    debugPrint(
      'StoryAudio: Final chunk received. Total: ${totalDurationMs}ms, Elapsed: ${elapsedMs}ms, Remaining: ${remainingMs}ms',
    );

    // Cancel any existing timer
    _playbackFinishedTimer?.cancel();

    // Schedule playback finished
    _playbackFinishedTimer = Timer(Duration(milliseconds: remainingMs), () {
      if (_isPlaying) {
        _isPlaying = false;
        _totalBytesSent = 0;
        _playbackStartTime = null;
        debugPrint('StoryAudio: Playback finished');
        onPlaybackFinished?.call();
      }
    });
  }

Hope that helps!

ggwozdz avatar Nov 26 '25 22:11 ggwozdz

@ggwozdz, @FossaMalaEnt , @superplain99 Hi guys and girls :)

Yes, the callback "onBufferUnderflow" did not work correctly. I begun to work on that today. What platform are you interested about ?

  • on iOS : it is fixed in # 9.30.0
  • on Android : work is on progress
  • on Web : things must be checked

I expect to deliver a fix on Android next week. Be patient.

9.30.0

  • iOS : fixes the "onBufferUnderflow" bug ( #1205)
  • Android : work is on progress
  • Web : must be checked

Larpoux avatar Nov 27 '25 17:11 Larpoux