Open defagos opened 4 years ago
I investigated this issue.
When playback ends, the app is suspended since there is no active audio anymore. This is why the continuous timer does not fire until the app is woken up again.
I tried using the background processing capability and the associated API to ask for some more time. The notification is fired correctly, but playback does not start and remains paused in background.
Actually, when AVPlayer
is in background, calling -play
sets the player rate to 1, but the system resets it automatically to 0, preventing playback from starting.
Using AVQueuePlayer
seems to work and is probably the recommended way to fix this issue. This requires support to be implemented in SRG Media Player. We will probably have to extend the existing API to support item enqueueing, maybe add a playlist API.
Rewriting SRG Media Player to support item enqueuing with a single controller would be a huge task. This would require us to store the media to be played with its context (initial position, segments, etc.), but also to add dedicated APIs to mange the queue itself (e.g. cancel playback of the current item and all remaining ones).
I verified that the issue we have with continuous playback is due to the fact that we are recreating an AVPlayer
instance after the current item has ended (AVPlayerItemDidPlayToEndTimeNotification
). This is namely how SRGMediaPlayerController
is implemented.
If we use an AVQueuePlayer
instead and do not destroy the player, but only insert the new item after the first has ended (the same AVPlayerItemDidPlayToEndTimeNotification
), playback will continue. Note that this only works if insertion is made directly, we cannot delay playback.
Note that using AVPlayer
and its -replaceCurrentItemWithPlayerItem:
to achieve a similar result does not work.
I therefore recommend the following strategy to ensure SRGMediaPlayerController
can chain playback:
AVQueuePlayer
instead of AVPlayer
in SRG Media Player. Make the necessary adjustments so that the behavior stays the same.Of course, this means we don't use AVQueuePlayer
in the best possible way for gapless playback, but this is not really the purpose here.
As noted by @pyby, the above approach assumes we readily have the URL at the end of the first media. But with Letterbox, and if the controller does not fetch the next media in advance, the URL is not known directly, and can take some time to be retrieved with a network request.
Using AVQueuePlayer
is probably the right way to go, but we definitely need a better strategy to chain medias.
A rough draft of what we could make:
AVQueuePlayer
. The player must be created once and for all at initialisation time, then reused with player item insertion.Anyway, this is no small task (and the above idea might probably need some thoughts).
Of course chaining should not break PiP or AirPlay playback if active.
Our SRF fellow colleagues found a workaround by registering a dummy remote control center command enabled at all times. Seems the command must not be the first registered, so the code should be inserted somewhere after the first play command has been registered (in the current codebase).
We should:
If the trick works on all iOS versions and the last answer is negative we can then deliver this workaround officially in Letterbox, but likely as an opt-in. It is namely likely that if the app does some kind of periodic work in the background (which Letterbox demo doesn't), the fact it is kept alive will make this work continue while the app seems to be dormant, possibly leading to battery drain (e.g. if network interfaces are woken up periodically, especially on mobile networks).
Note that since Xcode 13 / iOS 15 the energy log tool is not available anymore. This makes it more complicated to evaluate the energy impact of the workaround.
Workaround works on iOS 16 beta 3.
This issue is fixed in Letterbox successor Pillarbox. I will keep it open as it was one of the major reasons why Pillarbox exists in the first place, but Letterbox itself will never be able to fix this behavior as this requires the whole implementation to be built on AVQueuePlayer
, which is impractical.
In background, continuous playback does not chain medias automatically. This is probably due to the fact that timers are paused in background and do not fire, and probably is a consequence of the changes made to reduce player activity in background.
Issue type
Incorrect behavior
Environment information
Reproducibility
Always reproducible
Steps to reproduce