Kodi Community Forum

Full Version: iOS background playing music - regression/discussion with ActiveAE sink
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
This is about the feature of playing music in the background on iOS Touch Devices and controlling it via the player remote controls (to be found in the task switcher on ios < 7 or in the control center in ios 7).

Current state of the feature with our current (and deprecated) audioengine:

iOS5: Start music, kick XBMC into background (music gets paused) and go to the very left of the task switcher - the player control shows the play button (indicating that the music in XBMC is paused). Music can be paused/resumed and skipped with the controls. This works like intended.

iOS6: Start music, kick XBMC into background (music gets paused) and go to the very left of the task switcher - the player control shows the pause button (indicating that the music in XBMC is playing! - this is wrong). Music can be paused/resumed and skipped with the controls - but the play button always shows the "pause" symbol. This works mostly but has the cosmetic issue with the wrongly indicating play/pause button. (there seem to be related bugs in iOS for example see: http://stackoverflow.com/questions/10118...r-in-ios-5 )

iOS7: Start music, kick XBMC into background (music gets paused) and swipe up the control center - the player control shows the pause button (indicating that the music in XBMC is playing! - this is wrong). Music can't(!) be resumed. Music can(!) be skipped and starts playing then though. The Play button always shows the "pause" symbol and seems to do nothing. The problem in iOS7 is that the pause button doesn't send a UIEventSubtypeRemoteControlTogglePlayPause anymore. It instead only sends UIEventSubtypeRemoteControlPause and UIEventSubtypeRemoteControlPlay. See

The problem is, that the play/pause button always stays at "pause" this meanse that ios7 only sends UIEventSubtypeRemoteControlPause. The problem can be worked around by treating "UIEventSubtypeRemoteControlPause" like "UIEventSubtypeRemoteControlTogglePlayPause" on iOS7.

On all iOS versions the current implementation kills the gui sounds after stopping or pausing any playback (music or video doesn't matter) because this suspends the audioengine (for getting the correct "play" button on iOS5).

Current state of the feature with our new audioengine (ActiveAE) as it will be merged to mainline soon:

1. I removed the suspend of the audioengine as in the new engine nobody would start it again after pause/stop. So in that case it not only kills gui sounds - but kills the complete engine until forcing a reinit of the sink
2. Because of that - music background playing behaves like on iOS6 for iOS5 too (meaning the play/pause button always shows pause - but works feature wise).

The plan for the new audioengine is to change the background playing as follows:

1. Get rid of audiosession/interruption management in the sink (as it is handled already in UIApplication)
2. Runtimedetect iOS7 and treat UIEventSubtypeRemoteControlPause like UIEventSubtypeRemoteControlTogglePlayPause for iOS7
3. Remove all CAEFactory:Confuseduspend/CAEFactory::resume calls from UIApplication.

If i am right this should lead to the behavior from iOS6 on all other iOS versions too (can't test iOS4 though) - leaving only the cosemtic regression of the play/pause button always showing "pause". (which all people > iOS5 are experiencing already - its "only" a regression for iOS5 users).

Another thing would be to track down which call in CAEFactory::Suspend() really leads to the play/pause button switching to "play" on the current (deprecated) audioengine in iOS5. But i hadn't have time to debug this yet. (and it has low prio as it is broken by apple since ios6 anyway).

I just wanted to write my findings down so ulion can read and discuss it here (instead of using github for those lengthy texts Wink ).

@ulion - what do you say?
thank you for the hard work on testing on different ios version with/without the old audio engine.

I do not know that play/pause not works on ios6 before saw your this test result.

at least on ios 5 (maybe 4 too), the play/pause button, which is controlled by ios itself, according to the audio engine or sink's status, not so sure.

as a suggestion, the audio engine should support suspend as a feature if it is possible.

currently I can not work on the ios build so you can do what you want.
The audio engine supports suspend. The problem in the old code is that nobody resumes the engine (seems the old engine gets auto resumed when a player starts - this behaviour changed in the new engine). Will try to figure out more over time - but for now my goal is to keep the regression on the wrongly indicating play/pause button (which would be acceptable from my point of view).
Isn't it enough to suspend the Sink when pause state is reached?

E.g. when engine gets knowlege of PAUSE do something special for IOS?

https://github.com/xbmc/xbmc/blob/master...E.cpp#L428 <- take care to do the correct transition.
Well as written above - the whole approach of suspending the engine does only work on iOS5 ... it is ignored on later iOS versions and i think that we don't have control over the iOS play/pause button at all and apple has just alot of broken code in that area. So don't bother - we will go without even touching AE as it just doesn't make any sense to me anyways. And yeah we can of course tear down the engine in the sink on our own (thats what we do already) - didn't try if this works on ios5 - but as said - the wohle play/pause button is just fucked up by apple and i don't think there is a solution for it.
I thought of the following:

Handle the PAUSE event special for IOS in the Engine. We can do whatever we want to the sink to immitate the behaviour we will need. The Engine's connection to the "System" is not existing, when the Sink is unconfigured - so that would easily immitate that behaviour - the cost is of course "resume" will be a bit slow, cause we need to reinit.
Ok i digged a bit more. I would need some sort of suspend / resume for the sink. Or even better some sort of suspend(bool autoresume), and resume() for getting this feature complete on all ios versions. Not sure what is the best here. I could of course go around the engine and implant some static helper methods in the sink itself which i can call during background playback - or we would do a generic addition to the sink interface which could be accessed via CAEFactory then.


@ulion - i got the control over the play button and tracked down what is needed in minimum for making it appear as play or pause button Smile
ActiveAESink does already autoresume from suspend. We just need to send it to suspend state on pause. Currently the keep alive setting is only considered for gui sounds but I see no reason why we should ignore it for streaming.
I can change the behavior to suspend the sink on pause after keep alive timer is expired.
That doesn't do any good. I need to suspend the sink instantly when paused and XBMC is backgrounded. Else iOS will not show the "Play" Button in the control center (it would after the keep alive timer runs out after 1 minute for example - which will give a "not so good user experience" Wink).

I also only want to pause the sink when we are backgrounded by iOS (else it doesn't make sense and isn't needed). I don't think a automagic approach like you suggested will be very usefull here.
That can be adjusted, by e.g. draining immediately on mac osx, when pausing and don't use the "long idle timer".
I don't get that one?
First, we make it working with the idle timeout, e.g. add the transitions we have when no stream is active (menu sounds and so on). When this is working, we reduce the timeout to zero in mac osx, e.g. drain() and unconfigure completely.
ios - not needed for osx - but fine by me.