Audio_service: Confused with positionIndicator Widget

Created on 17 Apr 2020  路  6Comments  路  Source: ryanheise/audio_service

in your positionIndicator Widget in example ,

Widget positionIndicator(MediaItem mediaItem, PlaybackState state) {
    double seekPos;
    print(state.currentPosition); //*********************************** HERE 1
    return StreamBuilder(
      stream: Rx.combineLatest2<double, double, double>(
          _dragPositionSubject.stream,
          Stream.periodic(Duration(milliseconds: 200)),
          (dragPosition, _) => dragPosition),
      builder: (context, snapshot) {
        print(state.currentPosition); //++++++++++++++++++++++++++++++HERE 2
        double position = snapshot.data ?? state.currentPosition.toDouble();
        double duration = mediaItem?.duration?.toDouble();
        return Column(
          children: [
           ...

I added 2 printline , HERE 1 and HERE 2,
but I don't know why the value of HERE 2 will be updated but the value of HERE 1 is constant after a little wihle after play the audio.

because I see the positionIndicator Widget is in StreamBuilder of type ScreenState
and also ScreenState includes final state = screenState?.playbackState; which it includes currentPosition getter.

so I think the source of HERE 1 and HERE 2 are both from ScreenState and only because HERE 2 resides into :

stream: Rx.combineLatest2<double, double, double>(
        _dragPositionSubject.stream,
        Stream.periodic(Duration(milliseconds: 200)),
        (dragPosition, _) => dragPosition,
      ),

should not affect the value of currentPosition.

so if it is possible , some one explain why the value of HERE 2 will be updated during the time ( I know the HERE 2 should be printed at least every 200 mil ) but I don't understand 2 thing :
1- why HERE 1 and HERE 2 value are not same after a little time after play the audio?
2- why do you don't update PlaybackState every 200 mil in AudioService , because it contains currentPosition and should add its value to stream ?

Thanks to community.

All 6 comments

You will need to learn about the widget lifecycle to understand when a widget is rebuilt vs understanding when a stream builder is rebuilt.

Hi @ryanheise
I know the widget lifecycle
but I am sure the PlayBackState will not rebuild ( it will not add value to behavior subject when the position of audio changes)

my question is that I know that in :
stream: Rx.combineLatest2(
_dragPositionSubject.stream,
Stream.periodic(Duration(milliseconds: 200)),
(dragPosition, _) => dragPosition,
),

will rebuild the streamBuilder but my question is about the value of position is different in 2 place.

please help me @ryanheise

You can look at the implementation of currentPosition.

@MohamedAbdallah-14 it's because Stream.periodic(Duration(milliseconds: 200) get the current position value so it will be updated

You can look at the implementation of currentPosition.

I have exactly the same confusion!
Spent 1day to dig around here and there, so it might be +- common issue...

I got how it works right now.
But it is not what you expect when you subscribe to a stream.
What I expect - that stream will return me a value with a position within some interval. But instead events come randomly without any (obvious) logic.
Also it's not super obvious, cos there are position (which should be the main param) and currentPosition (which IS the main param technically).

Also might be a good idea to create a separate stream just for the position updates (without states). cos right now playbackStateStream is overloaded with logic.
From my point of view, it would be much better to separate them.

There is currently no stream corresponding to the currentPosition convenience getter, although I see how it could be convenient to have one, similarly to how I created one in just_audio. All it would do is periodically (say, every 200ms or by some period that is customisable) query the value of currentPosition and emit that value on the stream.

In the absence of such a stream in the plugin, you will see that the example does its own periodic querying of currentPosition every 200ms.

But it is not what you expect when you subscribe to a stream.
What I expect - that stream will return me a value with a position within some interval. But instead
events come randomly without any (obvious) logic.

Since there currently is no stream that reports the current position, I assume you are subscribing to something like playbackStateStream which is broadcast not at random times, but explicitly when you decide to broadcast it by calling AudioServiceBackground.setState. The documentation for setState mentions this which may be enlightening on this question:

The playback position should be explicitly updated only when the normal
continuity of time is disrupted, such as when the user performs a seek,
or buffering occurs, etc. Thus, the position parameter indicates the
playback position at the time the state was updated while the
updateTime parameter indicates the precise time of that update.

So you should expect updates precisely when you call setState to broadcast those updates.

It would be quite inefficient and wasteful to call setState continuously as the position keeps changing when its value can better be predicted from the values updateTime, position, and then looking at the system clock to see how much time has elapsed since updateTime and add that onto position. This is how the underlying platform API works, and I wrap that API, but I also provide currentPosition as a convenience getter to do the calculation for you.

Until a convenience stream is provided which queries this value every 200ms or so, you can create your own with Stream.periodic(Duration(milliseconds: 200), and emit the value of currentPosition each time the period cycles.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MahdiPishguy picture MahdiPishguy  路  5Comments

mohammadne picture mohammadne  路  7Comments

lain-ke picture lain-ke  路  6Comments

MohamedAbdallah-14 picture MohamedAbdallah-14  路  7Comments

Okladnoj picture Okladnoj  路  6Comments