Is it possible to run an NSThread or NSTimer on iOS 4 device when it enters the background state? - iphone

I am writing an audio application which plays media items from the iPod music library using the iPod music player.
Now I know it is possible for the iPod to carry on playing when it is in the background, but I want to also run either a Thread or a Timer in the background where a selector method periodically checks the state of the music player so that the app can apply rules in order to apply delays between tracks, and automatically load up new media collections into the player all while in the background.
Is this possible?
If not, is there any other method for achieving this functionality?

The trick is to not use MPMusicPlayerController as when your app enters the background it actually relinquishes control to the iPod app (you can check this by closing your app and opening the iPod app).
For the music app I'm currently developing I've rolled my own music player using AVAudioSession and AVPlayer (not AVAudioPlayer). I've implemented a queue on the player, and a datasource (similar to UITableViewDatasource) which feeds the queue. All of this works eloquently whilst running in the background and has no association what ever with the iPod app (and as an added bonus you apps icon appears next to the remote controls on mulitasking bar).
If you developed something similar then when you ask your datasource for the next item in the queue, you could query your rule set and take a decision on what to do next.

Sure. You can do this in the application delegate's applicationDidEnterBackground:.
From the template:
If your application supports background execution, this method is
called instead of applicationWillTerminate: when the user quits.

Well yes and now, you can't use NSTimer because they are invalidated.
You can start a block of code to run via GCD to run in background which will have the max. execute time of 10 min.

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.

Responding to events when device has been locked

I'm working on a radio alarm clock, and i have some issues.
I am using local notifications for the alarms, so it has a gentle fallback if the app is not running.
I am well aware of the limitations of the device, and i know what i can and cannot do when the device has gone into background.
But my question is this:
I have seen other apps starting an audio streamer when i've locked the device. How is this possible? May this be inside an execution-timeframe?
How is the best way to implement this? Is it any way i can activate a streaming session when the device is locked?
Edit
To clarify: I know how i make audio play in the background. But the issue is triggering the audio-playback when an local notification or some other event fires.
One app that seems to do this, is Radio Alarm Clock. I haven't tried it for long period of times yet. But it seems to do this. A video demo of the app: http://www.youtube.com/watch?v=KJQiFOcdBWk
Have you already declared your background task?
Support for some types of background execution must be declared in advance by the app that uses them. An app declares support for a service using its Info.plist file. Add the UIBackgroundModes key to your Info.plist file and set its value to an array containing one or more of the following strings:
audio — The app plays audible content to the user while in the background. (This content includes streaming audio or video content using AirPlay.)
iOS App Programming Guide - Implementing Long Running Background Tasks
You can add this by clicking on your main project icon, then under the Info tab you can add "Required Background Modes" to the "Custom iOS Target Properties" section. "App Plays Audio" will be one of the three default values.
Big Edit With New Answer:
If everything else is already in order, you can keep your app running in the background using the UIApplication method
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler
detailed here: UIApplication Class Reference
with an example here: Hour 21: Building Background-Aware Applications
This allows you to run an instance of NSTimer which triggers your music player. The difference between this approach and UILocalNotifications is that this method never lets the app fully enter the background mode, the music player exists the entire time which subverts the need to create it from the background, which looks to be impossible.
There may be limitations to how long of a timer you can set, I haven't tested this past 14 minutes out.

iPhone How to prevent my app from entering background when lock screen?

When press the lock button in app,system will call :
-(void) applicationWillResignActive:(UIApplication *)application and
-(void) applicationDidEnterBackground:(UIApplication *)application
So how can I do to make my app only resignActive but not enter background,and I can run my timer when screen locked(Timer can't execute in background mode).
One method is set the property "Application does not run in background" in .plist to YES,it worked, but my app can never enter background again,however I want it will enter background when press the home button.
Update: I want to play some music in my app at a certain time,just like a music alarm,and I still want it works fine when the screen locked,because keep the screen on may waste a lot of battery,and I don't need to do any thing when user press the home button and exit my app.
Open your Info.plist file and add Application does not run in background. Set value to YES.
Application must have special privileges to do any processing in background such as Audio service/Voip service/Location service.
"I can run my timer when screen locked(Timer can't execute in background mode)"
you cannot run a timer in background which will keep running without using any tentrum and doing so...apple will not accept your application on appstore - that's the worst side if you are targeting appstore...
You can not prevent your app from entering the background. This is decided by the operating system (iOS) and is out of control from applications. However, from reading your updated question, I don't think this is what you need to do.
You can execute background tasks with [UIApplication beginBackgroundTaskWithExpirationHandler;] (see reference). If you want to have something happening after a certain interval, check out [UIApplication scheduleLocalNotification:].
Some services such as VOIP, Audio and CoreLocation are allowed to run in background. Using these for other than their intended purposes (for example, playing silent audio) may risk your app being rejected.
Note that there is nothing you can do to prevent your application from entering the background. It is just that some tasks are allowed to execute in the background. Because of this, you cannot do GUI operations and NSTimers will probably not fire (at least I know some cases where they don't).
It would help knowing what you want to run in the background in order to suggest a solution.
Unless you are playing audio BEFORE the move to background you cannot start audio playback when the app is moved to the background or the screen is locked (which has some weird specifics) suffice to say, its as if you were in the background without actually receiving the applicationDidEnterBackground notification.
The best you can do is schedule a local notification, but in this case your music is limited to 30 seconds and must be part of your application bundle.

Receiving Notifications with App in background mode

I have an app, that will keep track of everything the user do in the iPod app. To do this, I added few observers to NSNotificationCenter, like MPMusicPlayerControllerNowPlayingItemDidChangeNotification. But my problem is, I only get those notifications when my app is in the foreground, if its in the background, the system add the notification to a queue, and then the next time my app becomes active it delivers it to me. I have no interest in this queue, since I want to receive real-time notifications.
Is there any way for me to get those notifications even if my app is in suspended state? I want to run just 3 lines of code everytime I get this NowPlayingItemDidChange notifications for example.
Here is where I add the observer.
MPMusicPlayerController *iPodMediaPlayer = [MPMusicPlayerController iPodMusicPlayer];
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver: self selector: #selector(handle_NowPlayingItemChanged:) name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object:iPodMediaPlayer];
[iPodMediaPlayer beginGeneratingPlaybackNotifications];
Also, if I add another kind of object to the observer instead of iPodMediaPlayer, the observer won't call the method.
Thanks a lot,
Abras
iOS applications are suspended when they are not in the foreground. There are three exceptions to this rule. You can have code execute in the background if your application is
a) Playing audio. This means the application itself is actually generating audio. My understanding is that the MPMediaPlayerController iPodMusicPlayer object only controls the playback of the external iPod process, rather than playing audio from the app itself. Perhaps you could have some success if you called applicationMusicPlayer instead of iPodMusicPlayer and set the appropriate background flags in your applications Info.plist. This seems like the most legitimate way to get your application to work, but you wouldn't be able to control iPod playback from the iPod app, only your app and the system audio controls.
b) Get your app to monitor the location. If the app is using the GPS it can continue to execute in the background. Downside to this is that the GPS will drain battery, and users might be creeped out that you're requesting their location.
c) Ask UIApplication for extra time. If you use UIApplication's beginBackgroundTask method, your application will continue to run for a finite amount of time in the background. If your users are going to come into your application once every ten minutes or so, this could work as well.
Hope that helps.
Multitasking in iOS is currently a very restricted one. You may start a background task using beginBackgroundTaskWithExpirationHandler: method (of an UIApplication object), but it is intended to finish a finite-length task before going suspended. All background tasks may expire (and get terminated) before it finishes its job. You can check how much longer your application can run by checking backgroundTimeRemaining property of the application object.
As I explained here iOS receive Media Player Notifications when app is in background, there seems no way to get notifications from iPodMusicPlayer.
About Omar Raul Qazi answer:
a) i tried and I had no success. The music kept going down when pressing home button. I think this background flag only works for normal AudioSessions and not for MPMusicPlayer...
b) I am not sure this would work and I don't think Apple would like it when looking for approval
c) You can run in background only synchronous task. You cannot wait there for a notification. Am I wrong?

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.