I'm making an alarm clock app with multitasking support. However, I'm stuck with some limitations of the sdk.
I need to play selected alarm sound whenever the alarm time comes with some properties set by the user.
These properties:
- Alarm sound can be a music from the user's iPod library, and also some sound files in application bundle.
- Alarm sound can be set to play as progressive.
Moreover, alarm sound must be played in background in a loop until the user cancels or wakes the app.
First logical thing that came to my mind was to use local notifications, but with local notifications you can play sound files that are only in app bundle(not iPod music) and that are at most 30 seconds long. Also you are not get notified when the user cancels the notification alert, iOS just stops playing your sound.
Now I'm thinking of using background audio playing option and play silence until the alarm time, and then play the alarm sound while also showing a local notification without sound. But again how will I know if user cancelled the local notification alert and stop playing audio. However according to Apple's documentation iPod music playing(and use of shared resources) is still not allowed for an app that is playing background audio.
I also can't understand how some other apps are doing some of these features. For example, Night Stand HD can play iPod music while in the background, and an app named "Progressive Alarm Clock" can play progressive sound while in the background.
Any ideas and suggestions on these issues? Any of your help will be greatly appreciated
I would say what you want to do is not possible with the current restrictions of iOS. That said you can probably fake a progressive alarm by doing what the developer of Progressive Alarm Clock do to play the progressive alarm. By scheduling many local notifications, one after each other. He has divided the alarm sounds into chunks of say 10 s each with progressive volume levels. This is a very crude example to show how the progressive alarm can be faked.
UILocalNotification *notif1 = [[UILocalNotification alloc] init];
notif1.fireDate = [NSDate dateWithTimeIntervalSinceNow:15];
notif1.soundName = UILocalNotificationDefaultSoundName;
notif1.alertBody = #"Alarm";
[[UIApplication sharedApplication] scheduleLocalNotification:notif1];
[notif1 release];
UILocalNotification *notif2 = [[UILocalNotification alloc] init];
notif2.fireDate = [NSDate dateWithTimeIntervalSinceNow:20];
notif2.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:notif2];
[notif2 release];
This will first display a notification and play the default sound after 15 seconds. After 5 seconds more the sound will be played again. By having a bunch of sound files where the volume is increasing the progressive sound can be faked just by scheduling more local notifications. This will of course only work if you have an alarm sound that can be easily divided into chunks, just like the bells in Progressive Alarm Clock. Unfortunately you can't cancel the alarm by tapping cancel in the notification. You have to start the application to do that.
Whatever the Progressive Alarm Clock developer is doing, it's not what Robert Höglund is describing, AFAIK, since the alarm will sound even if the phone is in silent, and UILocalNotification doesn't seem to have any way to allow for this. In addition, if you kill the app manually while an alarm is pending, the app will notify you that it needs to relaunch. This seems to suggest that it must be somehow running in the background.
Related
Apple resources contain a lot of informations but there's one thing which I can't clearly understand reading about audio and notification.
Is it possible to make an app, running in background which produce sound (even if phone is locked and/or silenced) and when it's happend user must solve eg. equation to turn it off?
p.s. For now I mostly use Cordova framework but Obj-C tip will also be nice.
Yes it is posssible.
You can use UILocalNotification for this.
Also apple allows apps that are playing music in background.
Please check these links for the background task feature:
ManagingYourApplicationsFlow
ios multitasking background tasks
How to handle background audio playing while ios device is locked or on another
You can change Local Notifications for NSTimers (keeping them alive in inactive mode with https://github.com/mruegenberg/MMPDeepSleepPreventer) and calculate the time interval for each alarm. That way you can then play an audio even with the screen locked and the sound off pasting this in your - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions:
// Let the sound run with the screen blocked
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];
[[AVAudioSession sharedInstance] setActive:YES error:&activationErr];
But you will have some problems:
The app must be playing an audio file each 10 seconds so it doesn´t deep sleep and kills all NSTimers.
Apple could reject your app for doing so.
You can´t close the app with the home button, otherwise, it won´t work.
You must open the app every time you need to use the alarm (you can´t schedule and forget).
When the alarm fires, you only have the lock screen of the iPhone and need to unlock it first and then stop the alarm from inside the app.
In Apple they don´t want competitors for their alarm clock app, that's for sure! Almost all the alarm clock apps you see in the App Store use this poor approach.
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.
I have an application that uses location services in the background. Works fine.
But what I want to do, at a certain point, is to check some audio levels while the application is in the background. For some reason it doesn't seem to work. When running in foreground, the function works fine, but when in the back ground, the audio recorder average and peak input is always -120..
This is what I use to do the trick (that doesn't seem to work apparently..)
....
[recorder record];
if (levelTimer == nil) {
bgTask = 0;
app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.02 target: self selector: #selector(levelTimerCallback:) userInfo: nil repeats: YES];
}
...
And yes, the levelTimerCallback is called every 0.02 seconds, even when in the background, so I assume that the beginBackgroundTaskWithExpirationHandler works fine.
Any thoughts or some hints?
Currently, the only supported way to record in the background on an iOS device is to include audio for the UIBackgroundModes key in the app's plist, enable an appropriate Audio Session for recording, and start recording (or playing) audio before the app goes into the background.
If the app uses the Audio Queues or the RemoteIO Audio Unit API for recording, the buffer callbacks can just throw away all the audio buffers until the time of interest, and then compute the energy represented by the PCM samples for the amount of time required when needed.
I dont think iPhone will allow recording in the background. Only few services are allowed when the app goes into background. Logically if your app stays into background for a long time it would then consume a lot of battery as well as buffer to store audio, unless you have time and memory managed these resources. This would also pose issues for your app when you submit it to the App Store.
Although you can refer to this link for knowing what can be run in the background.
I hope this might help u clear things in a way.
iPhone : Running services in the background
Good Luck!!!
There is an app I know of that has background recording. Beatmaker 2. You need to turn run in the background on in the settings of device under beatmaker 2. In beatmaker create an audio track and start recording. Them use the home button on device to exit app but its still recording. You can get creative with different interfaces as well. I do this to feed the iPhone 4 line out into an audio track in beatmaker 2. You can record the audio of anything playing in the foreground. (YouTube videos apps music from your iTunes library. You can edit the waves also after recorded.
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.
I have a small application which is much like a clock. It has been working great on IOS3, but now I am updating it to iOS4.
What I want to do in iOS4 is to let it play a sound any giving time. For instance, if I set it to play at 4.00 PM I want it to play a sound, a sound from the application not from the OS. This works if the app is launced, but if the user went back to the home screen I want the same to happen.
It is OK if a UIAlertView pops up istead of the application.
How can I do this?
Best regards,
Paul Peelen
Sounds like you'll need to use a local notification:
http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Introduction/Introduction.html
and
http://developer.apple.com/iphone/library/documentation/iPhone/Reference/UILocalNotification_Class/Reference/Reference.html#//apple_ref/occ/cl/UILocalNotification
Read http://developer.apple.com/iphone/library/documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html.
What you want is UIApplication setKeepAliveTimeout:handler: which let you register a handler that will be called. You can use that to start playing audio. (Of course, compute the timeout when your app goes to background)
EDIT: Use UILocalNotification as andy said.
Two things you could possibly try under iOS 4.
Local Notifications can pop up an alert and play a short sound.
Another power hungry option is to register as a background music player, and play silence until time for the alarm to go off, then add your chosen sound to the "music" output. This will fail if the user switches to another media player app.