iOS 5 Audio Alarms Don't Sound Without kAudioSessionProperty_OverrideCategoryMixWithOthers On - iphone

I have an audio app that is having some problems with the way iOS 5 has changed audio behaviors. When my app's audio is playing (AVAudioSessionCategoryPlayback), and a Clock.app alarm or timer is fired from the OS, the UIAlertView notification pops up, but without the audio alert. My application sound ducks fine to get out of the way of the audio alert, but the alarm app's audio alert does not sound.
Naturally, tons of support requests poured in over the iOS 5 change. I have solved this temporarily by setting kAudioSessionProperty_OverrideCategoryMixWithOthers which lets the alarm audio come through, but there are a few very undesirable side-effects when doing this:
Other app's audio can play with/over mine.
The remote control events are not routed to my app, but to iPod.app.
None of the above drawbacks are acceptable for my app's requirements. I have been hacking away at this for some time now but haven't been able to crack it. How can I setup my audio such that:
My app's audio still uses the AVAudioSessionCategoryPlayback category for background audio.
The Clock.app alarms still have their audio alerts make sound
The app still responds to remote control notifications

After writing this question I went to file a bug report on this. I created a small sample project that I thought would replicate the issue, but I could not replicate it! This caused me to dig in deep once again and try to figure out what was up here…
I fired up an iOS alarm, then I placed a break point in audioPlayerBeginInterruption: and traced through my code line by line in the debugger. I noticed that before my code ran (while I was paused in the debugger), the iOS 5 alarm was sounding! Luckily it still sounded even as I was stepping through my app, so I was able to figure out which pieces of code specifically caused it to stop sounding.
Part of my interruptionHandler is to (obviously) stop the internal audio of my app to let the interruption come through. I never thought to inspect this method before, but turns out the problem existed in there. My stop method would call prepareToPlay immediately after stopping to make resuming faster the next time.
[self.player stop];
[self.player prepareToPlay]; // <- iOS 5 alarm sound stopped here.
The docs state the prepareToPlay method
preloads buffers and acquires the audio hardware needed for playback, which minimizes the lag between calling the play method and the start of sound output.
Sounds reasonable, and this worked for lesser iOS versions. My hypothesis is that  must have made a change to the Clock.app alarm system such that the new alarm sounds use the hardware, whereas before it used the software. This is what I think is causing the iOS 5 alarms to be silent in some apps.
Removing the prepareToPlay lines caused the alarm to sound without using kAudioSessionProperty_OverrideCategoryMixWithOthers, thus solving all my issues laid out in this question.
TL;DR
Remove the prepareToPlay calls from your stop sound code logic. It will take a microsecond longer to start later, but will allow interruptions to sound.

Related

iPhone: MPMusicPlayerController stops AVAudioPlayer

I'm playing a silent music with AVAudioPlayer when user locks the screen, so that my timers won't stop.
However, when I play an iPod music with [MPMusicPlayerController applicationMusicPlayer], AVAudioPlayer stops,without receiving any call back.
Is there any way so that I can start [MPMusicPlayerController applicationMusicPlayer] playing without stoping AVAudioPlayer playing?
EDIT:
Thanks guys, this is the app I'm working on:
It is an Alarm app, this app allows user to lock screen while app is running,and when it is the time of the alarm, app can play iPod music to wake the user.Local notification can not use iPod music as alert sound, so I have to keep the app running while screen is locked.
If user quit the app, it will use local notification as alarm, whose sound is limited to files in bundle.
I can't use UILocalNotification as timer since when in screen locked status(in UIApplicationStatusInactive), app can't receive local notification generated by the system.
Apple has architected their backgrounding system to really limit things like this from happening. Essentially, there is no way for the you to keep the application running in the background unless it needs to be there. If you explain what you are trying to accomplish, maybe a better solution can be found but as good practice, never use random backgrounding methods to do other things. I am assuming that you might be using the faint music as a way to show something custom on the main screen, this is not a good idea.
Your app will get rejected if you play a silent audio.
Also as per apple's documentation https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.html#//apple_ref/doc/uid/TP40008194-CH103, notifications cannot have sounds (soundName) which play more than 30 seconds.
So you wont be able to release your app in the store.
I figured it out myself.
It is not calling [MPMusicPlayerController +applicationMusicPlayer] that stops AVAudioPlayer, but calling [MPMusicPlayerController -setShuffleMode:], I don't know why calling this would stop AVAudioPlayer, but it is where the problem lies in.
Thanks everyone, I think I should paste my complete code next time.

Iphone sdk - How to play a sound during a phone call after some elapsed time?

Well I am having two issues that i can't get to work, related to audio and calls.
The first one is to play a sound during a phone call. I don't want to play continuous music or stream anything, it is just a simple and short sound that the user will hear at one time during his call.
I have read some posts claiming that this is possible, and I even have an application that does so, but I can't get it to work. My app identifies the call using CTCallCenter and print the logs but never plays the sound or plays it after the app comes to foreground again. I have the .plist property of required background mode App plays audio.
The second issue, is to play the sound after some elapsed time. NSTimers doesn't work when on background mode, nor NSThread sleep on my background process or NSOperation. So how could I play this sound after say 10 seconds of the call?
Also, this behavior has to work also when the application is already on background mode. With CTCallCenter I am only getting the event when the application is interrupted from use, but I don't see any logs when i send the app to background and then begin/receive a call
.
If anyone could point me to the right direction I'll be really grateful.
I havent done this, but NSLocalNotifcation, schedule a notification to play when you app get the call to move into the background. I would expect this to work. Interested to find out if it does.

AVAudioPlayer lag when calling play

I have set up an AVAudioPlayer object in viewDidLoad, as per the Apple guidelines, calling prepareToPlay as the last line in viewDidLoad (i have tried in awakeFromNib also).
When i press my play button, there is a pause, as it would appear to load the file, then it plays.
In audioPlayerDidFinishPlaying, i reload the player with a different sound, and when clicking play for a second time, the file plays instantly.
What would cause the player to lag on the first play?
Thanks.
The delay is due to AVAudioPlayer being initialised. Please see this answer.
The audio system runs on several asynchronous software processes (audio units, OS drivers, etc.) and hardware systems (DMA, DACs, audio amp power supplies, etc.) that never really all completely finish initialization until some sound is actually played all the way out the speakers or earphones.
Here's one method to do that: Create a sound file containing a half second of silence. On app start up, while your app and view controller are still loading, use AVAudioPlayer to play this file of silence. Now when your view finishes loading, AVAudioPlayer should be ready to play subsequent non-silent sounds much faster, since some audio (silence) has already already gone all the way out to the speakers.
What kind of sound are you playing? Alerts, something longer? If alerts, I did go this way and it's much better with lags ...
create system sound with AudioServicesCreateSystemSoundID
play system sound with AudioServicesPlaySystemSound
dispose system sound with AudioServicesDisposeSystemSoundID
... you only need to store SystemSoundID for each sound you would like to play.

Multitasking: Stop Background Audio at Specific Time

I am developing an iphone app which uses background audio (on an infinite loop) to continue playing after the app has entered the background.
My problem is I want to implement a "sleep timer" which stops playback after a specified period of time.
Is this possible? I have spent an hour looking for a method to do this with no avail.
EDIT: My current thought is to use a lower level API, the Audio Queue Services, and manually re-fill the queue with another instance of the loop during the AudioQueueOutputCallback. If the timer has expired I do not fill the loop. I'm assuming this should work since the documentation says audio callbacks are still fired when an app is playing multitasking background audio. Can anyone think of a better way or a reason why this wouldn't work?
While you queue sound data on the background your app remains fully functional and running as if it was in the foreground (well almost), so yes, you should just write a timer that stops the playback at a given time and it will be fired as expected.
Now to the second question: once you stop queueing things up, your app will be "frozen" until the user manually brings it to the foreground... So what you should do is start queueing audio data from the second file before the first one is done playing, and if you DO need to pause or stop, maybe a solution is to play 0 bytes (silence)?
I'm not actually sure this would be allowed in the App Store. An app is not allowed to execute at all in the background, with the exception of VoIP apps and push notifications.

idleTimerDisabled not working since iPhone 3.0

I have used:
[UIApplication sharedApplication].idleTimerDisabled = YES;
in a number of Apps developed and running under iPhone OS 2.x and never had any problems with it. They were clock apps so needed to run constantly and ignore the iPhone's idle Timer setting.
However, trying to achieve the same with a new App running OS 3.0 (and which needs to be deployed under 3.0 as it uses some 3.0 APIs) I've found the idle Timer to be either ignored or inconsistent.
My App plays music from the iPod library and when the music is playing it auto-locks regardless of the above setting. But once you unlock it, it then doesn't auto-lock again unless you play music again, in which case it locks again after the iPhone auto-lock time setting.
I'm amazed no-one else has come across this as I imagine it would affect a large number of Apps.
Just to clarify:
1. The above code is in ApplicationDidFinishLaunching
2. I know that the phone won't auto-lock when testing from xCode regardless of settings
If anyone has any thoughts I'd be very grateful...
Our app uses the MPMediaPLayer. We also had the idleTimerDisabled=YES code in the ApplicationFinishedLaunching, which works EXCEPT if untethered, and there is already a current nowPlayingItem which is left playing (or unpaused, if paused at app startup). Obviously this is all with the Settings -> General -> Autolock set to some timed value.
By adding idleTimerDisabled=NO, immedately followed by idleTimerDisabled=YES in one of the other bits of code AFTER we had figured out what bit of music we would get playing seemed to solve the problem. Just setting it to YES was insufficient.. and subsequent queries had always indicated the correct value (YES).. so it appears the Apple code ignores the setting of the value IF there is a current piece of music and that is not changed by your code.. but does notice a change of value.
This is all under iOS 3.0.
Even in 2015, using iOS 8.2, this bug is still alive and kicking.
Here's my solution, using XCode 6.2.
iPhone - phone goes to sleep even if idleTimerDisabled is YES
Basically, even now, in 2015, the only way to safely make sure that the device doesn't go to sleep is to repeatedly call a piece of code to keep the device awake.
-(void)callEveryTwentySeconds
{
// DON'T let the device go to sleep during our sync
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}
Sounds like a bug, file with Radar - I am not too surprised this has not been seen much as there are probably not a lot of apps that try to lock the screen open and play music.
Having same issue. It does work when the device is plugged in. You can press lock button on top, and my NSTimer fires later and causes a vibrate. However if the device is not plugged in pressing the lock button puts the device to sleep. Any solution would be greatly appreciated.
iCodeblog posted about the idletimer, I said it didn't work, and the person who develops 'cute clock' was nice enough to reply. You have to do a hack, play a 1 second or longer silent sound every 10 or so seconds with NSTimer. This keeps the device awake even if the user hits the lock button.
I develop Seconds - Interval Timer for iPhone and iPod touch and I've had no end of trouble with this. The idea of my app is that people create timers based on a number of intervals where each interval can have it's own playlist or track played.
In iOS3 I had the problem that I couldn't disable the idle timer by just setting idleTimerDisabled = YES. In the end I came up with the same solution as Neil whereby I would periodically set it to NO, then immediately to YES again. This seemed to work.
I'm now updating the app to iOS4 (I know, iOS5 is just around the corner...) and now I have the opposite problem. If the MPMediaPlayer changes track before the idle timer reaches it's limit it gets reset. I've just tested this by creating an interval in my app that was 55 seconds, my auto-lock was set to a minute. At 50 seconds the screen dimmed as it prepared to lock, but at 55 seconds when the music changed it went back to full brightness and then didn't lock as it should.
Overall, the implementation of this seems flakey at best.