Repository navigation
User setPlaybackParameters() is overwritten by live adjusment #10882
Description
ExoPlayer Version
2.18.2
Devices that reproduce the issue
Evolution Digital eStream 4k (https://evolutiondigital.com/estream-4k/) (probably many others)
Easiest to reproduce if device is running AC-3 audio with off-board decode.
Devices that do not reproduce the issue
No response
Reproducible in the demo app?
Yes
Reproduction steps
Pretty difficult, working on a ExoPlayer unit test case (not sure it is even possible)
The steps are to repeatedly tune to a live channel, while speed adjustment is progress, then:
- Disable the audio
- Set the speed to > 1.0. (eg 8x)
Expected result
Media plays at 2.0x (or whatever the setting was).
Actual result
Playback reverts immediately to 1.0 (with adjustment +/- 3% default).
The branch x-live-speed-overwrites-user-logging has the logging shown in the description below. Here's the sequence that causes the bug with my analysis:
DO_SOME_WORK— sees renderer clock is 1.0, does live speed adjustment, sets speed to 1.03
12-21 14:34:41.564 7303 7343 I ExoPlayerImplInternal: updatePlaybackPositions() changing speed -
old: PlaybackParameters(speed=1.00, pitch=1.00)
new speed: 1.03
MediaClock: DefaultMediaClock isUsingStandaloneClock: false standaloneClockIsStarted: true
rendererClock: PlaybackParameters(speed=1.00, pitch=1.00)
standaloneClock: PlaybackParameters(speed=1.00, pitch=1.00)
12-21 14:34:41.564 7303 7343 I ExoPlayerImplInternal: handlePlaybackParameters() updatePlaybackInfo:false acknowledgeCommand:false
currentPlaybackSpeed: 1.03 currentParameters: PlaybackParameters(speed=1.00, pitch=1.00) playbackParameters: PlaybackParameters(speed=1.00, pitch=1.00)
2a. DO_SOME_WORK — Renderer reports speed 1.0 (ignore 1.03 setting), and this queues a MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL, and resets standalone clock to 1.0
12-21 14:34:41.580 7303 7343 I DefaultMediaClock: syncClocks() mismatch - renderer: PlaybackParameters(speed=1.00, pitch=1.00) standalone: PlaybackParameters(speed=1.03, pitch=1.00)
2b. In same DO_SOME_WORK message, live speed again sees speed is 1.0 (from 2a), and again trys to set it to 1.03
12-21 14:34:41.581 7303 7343 I ExoPlayerImplInternal: updatePlaybackPositions() changing speed -
old: PlaybackParameters(speed=1.00, pitch=1.00)
new speed: 1.03
MediaClock: DefaultMediaClock isUsingStandaloneClock: false standaloneClockIsStarted: true
rendererClock: PlaybackParameters(speed=1.00, pitch=1.00)
standaloneClock: PlaybackParameters(speed=1.00, pitch=1.00)
12-21 14:34:41.581 7303 7343 I ExoPlayerImplInternal: handlePlaybackParameters() updatePlaybackInfo:false acknowledgeCommand:false
currentPlaybackSpeed: 1.03 currentParameters: PlaybackParameters(speed=1.00, pitch=1.00) playbackParameters: PlaybackParameters(speed=1.00, pitch=1.00)
-
MSG_TRACK_SELECTION_INVALIDATED— disable audio renderer, this messages does the following:- update tracks, then calls
updatePlaybackPositions(), which does asyncClocks(), again clocks don't match so queuesMSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL - disables audio renderer, so standalone clock is now master, standalone clock has 1.03 and renderer vetoed it (so it has 1.0)
- update tracks, then calls
12-21 14:34:41.592 7303 7343 D ExoPlayerImplInternal: handleMessage() - msg: 10 playbackInfo.playbackParametersPlaybackParameters(speed=1.00, pitch=1.00)
MSG_SET_PLAYBACK_PARAMETERS— handle the user requested speed.
12-21 14:34:41.655 7303 7343 D ExoPlayerImplInternal: handleMessage() - msg: 4 playbackInfo.playbackParametersPlaybackParameters(speed=1.00, pitch=1.00)
12-21 14:34:41.655 7303 7343 I ExoPlayerImplInternal: setPlaybackParametersInternal() - parameters: PlaybackParameters(speed=8.00, pitch=1.00)
MediaClock: DefaultMediaClock isUsingStandaloneClock: true standaloneClockIsStarted: true
rendererClock: none
standaloneClock: PlaybackParameters(speed=1.03, pitch=1.00)
12-21 14:34:41.655 7303 7343 I ExoPlayerImplInternal: handlePlaybackParameters() updatePlaybackInfo:true acknowledgeCommand:true
currentPlaybackSpeed: 8.0 currentParameters: PlaybackParameters(speed=1.00, pitch=1.00) playbackParameters: PlaybackParameters(speed=8.00, pitch=1.00)
- Then the
MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL, queued in step 3 (track selection) overwrites the 8x speed back to 1.0
12-21 14:34:41.657 7303 7343 D ExoPlayerImplInternal: handleMessage() - msg: 16 playbackInfo.playbackParametersPlaybackParameters(speed=8.00, pitch=1.00)
12-21 14:34:41.657 7303 7343 I ExoPlayerImplInternal: MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL updatedParameters : PlaybackParameters(speed=1.00, pitch=1.00)
EPII.playbackParameters: PlaybackParameters(speed=8.00, pitch=1.00)
MediaClock: DefaultMediaClock isUsingStandaloneClock: true standaloneClockIsStarted: true
rendererClock: none
standaloneClock: PlaybackParameters(speed=8.00, pitch=1.00)
12-21 14:34:41.657 7303 7343 I ExoPlayerImplInternal: handlePlaybackParameters() updatePlaybackInfo:true acknowledgeCommand:false
currentPlaybackSpeed: 1.0 currentParameters: PlaybackParameters(speed=8.00, pitch=1.00) playbackParameters: PlaybackParameters(speed=1.00, pitch=1.00)
- Lastly, again main loop sees renderer clock is 1.0, does live speed adjustment, sets speed to 1.03
12-21 14:34:41.658 7303 7343 I ExoPlayerImplInternal: updatePlaybackPositions() changing speed -
old: PlaybackParameters(speed=8.00, pitch=1.00)
new speed: 1.03
MediaClock: DefaultMediaClock isUsingStandaloneClock: true standaloneClockIsStarted: true
rendererClock: none
standaloneClock: PlaybackParameters(speed=8.00, pitch=1.00)
12-21 14:34:41.658 7303 7343 I ExoPlayerImplInternal: handlePlaybackParameters() updatePlaybackInfo:false acknowledgeCommand:false
currentPlaybackSpeed: 1.03 currentParameters: PlaybackParameters(speed=1.00, pitch=1.00) playbackParameters: PlaybackParameters(speed=1.00, pitch=1.00)
Media
I'll send a live URL.
Bug Report
- You will email the zip file produced by
adb bugreportto dev.exoplayer@gmail.com after filing this issue.
Activity
stevemayhew commentedon Dec 22, 2022
PS, this bug is related to #10865 as the fact the renderer does not parrot the speed setting causes repeated
MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNALevents.tonihei commentedon Jan 5, 2023
If this is the same device/setup as #10865, doesn't this imply that no speed adjustment is possible (neither automatic for live adjustment nor manual)? If so, the speed is correctly reset to 1.0 presumably.
google-oss-bot commentedon Jan 25, 2023
Hey @stevemayhew. We need more information to resolve this issue but there hasn't been an update in 14 weekdays. I'm marking the issue as stale and if there are no new updates in the next 7 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
stevemayhew commentedon Jan 25, 2023
@tonihei Sorry for my late reply to this. The issues are different, it is a bit confusing, I'll get to that.
It just turns out that having an audio track that does not support speed adjustment is the easiest way to trigger this issue, that is the only real relation.
This issue occurs because two sequences of ExoPlayer internal messages on the playback thread can result in the player overwriting the user speed setting request. The pull request #10883 explains it a little better (I hope), the core sequence is:
MSG_SET_PLAYBACK_PARAMETERS)MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL) overrides user speed settingAs I remember, when we discussed this, the design was only the renderer/audio track would retain this internal speed setting. I agree with you, this is the correct way to treat the internal playback speed.
Thanks for having a look, this is definitely a complicated flow.
stevemayhew commentedon Jan 25, 2023
PS, we think the
LivePlaybackSpeedControlis a key feature for hospitality live playback use cases, happy to work on expanding it to more audio sink's19 remaining items
stevemayhew commentedon Feb 21, 2023
Ah, thanks @tonihei excellent enumeration of the 4 cases. So, I think what is happening is an unexpected consequence of case 1 or case 2.
I put some numbers on the sequence in the original bug description, you can see the logging associated with the in the description that shows the sequence of messages in the branch. Again, the Application Thread
You can see the sequences in 2b. and 3. in the updated main bug description setup the errant
MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL. The fact that the change from this callback is queued to the player handler message queue sets up the possibility of state changes that invalidate the message.I'm very clear why my pull request is invalid, Just to riff on some ideas for
MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNAL, this is obviously a very complicated sequence:MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNALin step 5 when the renderer clock is no longer active seems wrong.PlaybackParametersListener.onPlaybackParametersChanged()synchronously (that eliminates all possible sequencing errors)MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNALis pending (seems a bit like a hack, adding more conditions to the already complex check:Again, thanks for your patience on this use case.
It is on my plate to proposing a proper API for ROLE_TRICK_PLAY track usage (I'm thinking of a
PlaybackParameters.setTrickplayMode(boolean)). Hopefully that can bring these use cases more front and center.tonihei commentedon Feb 24, 2023
Ah! Thanks for the updated logs. I can see the problem now, which only happens if we switch from renderer to stand-alone clock while
MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNALis still pending. The pending change back to 1.0 is stale at this point because it refers to the renderer clock, whereas the stand-alone clock is of course perfectly happy to play any speed. Let me think about this a bit to see what we can do.I agree. The main complication is that setting a speed on the renderer clock is not checked immediately for support, but only slightly later when it's actually applied. That's why we blindly assume it works and then use the additional
MSG_PLAYBACK_PARAMETERS_CHANGED_INTERNALcallback to signal when something changed.Yes, see beginning of my reply where I came to the same conclusion. This event must not be handled, not triggered, or handled before the switch to the stand-alone clock.
Might be a possibility, but needs to be checked carefully. We always send incoming tasks as a new message (even on the same thread) to ensure the order of event execution is always the same as the order in which the events are triggered. This is more of a general rule that avoids that we even have to think about re-entrance scenarios.
Sounds wrong, yes. It would make more sense to implement go/exoghi/10865 to avoid setting the speed at all if it's not supported.
Not really part of this bug, but I'm curious why you'd want to put it in there? The
PlaybackParametersare really more ofAudioOutputConfigurationParametersat the moment and trick-play doesn't seem to fit logically. If it's just about having an API to configure the player to change it's internal behavior for trick-play, then we probably need a separate ExoPlayer for this.tonihei commentedon Feb 24, 2023
I'll will upload a fix for this (with a test case). The solution I went for is to remove pending internal speed updates when a new speed is set. This makes sense because any newly set speed makes the previous pending message stale.
stevemayhew commentedon Feb 25, 2023
Fix some playback parameter signalling problems.
Fix some playback parameter signalling problems.
Fix some playback parameter signalling problems.
Fix some playback parameter signalling problems.