ryanheise / audio_service

Flutter plugin to play audio in the background while the screen is off.
797 stars 479 forks source link

Buffer Stream & Volume Stream not available #763

Open TheStarkster opened 3 years ago

TheStarkster commented 3 years ago

Is your feature request related to a problem? Please describe. we don't have buffer stream like we have in just_audio package as we're not able to access audio player instance from the background task class, so we're left with no choice but to rely on methods and streams which are being exposed from AudioService class

Describe the solution you'd like Provide a buffer stream in this package like just_audio

Describe alternatives you've considered we've no alternatives i presume

Additional context N/A

ryanheise commented 3 years ago

Describe alternatives you've considered we've no alternatives i presume

An alternative would be to implement your own streams as needed because everything can be derived from playbackState.

E.g.:

  final ValueStream<Duration> bufferedPosition =
      BehaviorSubject.seeded(Duration.zero)
        ..addStream(_handler.playbackState
            .map((state) => state.bufferedPosition)
            .distinct());

But I'll leave this issue open since I may eventually consider adding such a stream in audio_service.

TheStarkster commented 3 years ago

thanks man! i saw there's almost everything in playbackstate that i need and im already streaming events to my bloc something like that

AudioService.playbackStateStream.listen((event) {
     add(AudioEvent.updatePlaybackState(event));
});
TheStarkster commented 3 years ago

hey @ryanheise what about volume stream? we can set a custom action to set the volume but how we can get the stream of it like just_audio? are we supposed to preserve in some local storage?

ryanheise commented 3 years ago

Because everything is now in one isolate, i.e. in the same address space, you can share a reference to that just_audio stream with your UI.

TheStarkster commented 3 years ago

i am afraid, i don't know how to do so can you please elaborate? however i am trying this right now haven't tested this yet

player.volumeStream.listen((event) {
   AudioServiceBackground.sendCustomEvent(event);
});

and will try to listen to this in my bloc

ryanheise commented 3 years ago

As a very simple example, you can copy player.bufferedPositionStream into a global variable and access it from anywhere. That's not great from a design point of view, but just as a means of explaining that it is possible to share a reference to the stream anywhere.

TheStarkster commented 3 years ago

ok but im not a big fan of global variables but i tried something else, what i did is sending custom events to my bloc

player.bufferedPositionStream.listen((event) {
      AudioServiceBackground.sendCustomEvent({"buffer": event});
    });

as i mentioned above and listening to those custom events in my bloc like this

AudioService.customEventStream.listen((event) {
            if(event["volume"] != null) {
              add(AudioEvent.updateVolumeStream(event["volume"] ?? 0));
            } else if(event["position"] != null) {
              add(AudioEvent.updatePositionStream(event["position"]));
            } else if(event["buffer"] != null) {
              add(AudioEvent.updateBufferStream(event["buffer"]));
            } else if(event["duration"] != null) {
              add(AudioEvent.updateDuration(event["duration"]));
            }
          });

and in those events which im calling (bloc events) im updating this state

class AudioDataStream extends Equatable {
  final Duration? bufferPosition;
  final Duration? audioPosition;
  final Duration? audioLength;
  final PlaybackState? playbackState;
  final bool? playing;
  final double? volume;
 // ...

i am putting this 👆 code just in case someone stumbled upon here, so it will be helpful.

and now there's something i would like to mention because i don't know if its my lack of knowledge for the playbackstate thing, but what it's doing is that it's streaming buffer and position after a delay of few second better say after a minute or so do you have any idea @ryanheise why is that, because of this thing i switched to AudioPlayer 's streams.

ryanheise commented 3 years ago

I see from your code that you're asking about the stable release, whereas my answer was about the version that is development in Git (on the one-isolate branch). A global variable (again I'm not saying that's a good design) will not work in the current stable release, only in the latest development version. The point of that global variable example was not to say you should do it as a global variable but rather to explain that in the new "one isolate" version of audio_service, everything is in a single address space and so it is possible to pass references from anywhere to anywhere. It is up to you to take that and implement reference passing in a good architectural style.

I'm not sure about the delay issue you're running into, but any fix would be implemented on the development version anyway, so I would suggest testing on that.

TheStarkster commented 3 years ago

yea i somewhat assumed that there must be some other block of memory would've been allocated for that background class where we encapsulates all the business logic for audio. now i got your point when you just mentioned the "one-isolate" word all of that makes sense, thanks for helping out, i didn't knew about that branch

so im closing this issue for now & i'll open this if i see any issue regarding this whole thing, thanks a ton again!

ryanheise commented 3 years ago

As per the reasons mentioned above, I still want to keep this open.