Welcome to Adopting Multitasking on iPhone OS, Part Two.
My name is Charles Srisuwananukorn, and I'm a software engineer on the iPhone Performance Team.
Joining me later in the talk will be David Myszewski, who manages the iPhone Performance Team.
Now, let's recap a little bit what we learned in Part One.
Multitasking on iOS 4 doesn't mean that applications need to run all of the time in the background.
In fact, we believe that most applications don't need to run all of the time in the background.
Most applications only need to switch quickly between each other, which we covered extensively in Part One.
But, we recognize that there are some applications that do benefit from executing in the background, and that's what we're going to focus on in this session.
We're going to survey several new services in iOS 4 that you can use in your apps to run in the background and implement features that just weren't possible before in iPhone OS 3.
In particular, we'll look at the task completion service, which allows your application to request some extra time to run in the background as it enters the background to complete a task on behalf of a user.
And then, we'll look at the background audio services, which your applications can use to play audible content to the user in the background, and respond to the remote control events.
And then, we'll look at a few location based services.
The first is a navigation service for turn-by-turn navigation apps.
And, a couple of location tracking services, so your applications can respond to location changes while in the background.
And finally, we'll look at some Voice over IP services in iOS 4 that your applications can use to make and receive phone calls while in the background.
Now, let's get started with task completion.
As I said earlier, task completion allows you to request some extra time to run in the background to complete a task on behalf of a user.
So, when the user taps the Home button, for example, if your application was in the middle of uploading some photos or videos, or applying an image filter to some photos, or even downloading a digital asset like a magazine or a book, you can continue running in the background before being suspended, so the user doesn't have to wait.
In iPhone OS 3, your application would have had to remain in the foreground while it finished these tasks, and so the user would have had to wait for your application to finish these tasks before using the device or using another application.
With task completion in iOS 4, you can do this in the background and the user doesn't have to wait.
But, if we let applications use the task completion API to run arbitrarily or indefinitely in the background, that would be really bad for battery life.
So, the amount of time you get to run in the background with this API is limited, to prevent excessive battery drain.
So, let's review the states that your application goes through as it enters the background.
On the left there, we have the state diagram that we saw in Part One earlier this morning.
When your application is in the foreground, it's in the active state, and then when the user taps the Home button to dismiss your application, it transitions from the active state into the inactive state briefly, and then into the background running state for a short period of time, where it can prepare for suspension by saving out the application state and reducing its memory usage.
And then, after that short period of time in the background running state, it transitions into the suspended state, where it's not actually executing, but it is still resident in memory.
But, what if your application was in the middle of doing something; for example, uploading some photos?
Well, with the task completion API, you can ask the system to keep the application in the background running state longer than it normally would.
And so, you have some time while you're running there in the background running state to finish that photo upload.
And then, once you've finished the photo upload, you tell the system that this task is complete, and your application will transition from the background running state there into the suspended state, and then it stays in the suspended state until it comes back to the foreground.
To use the task completion API, all you have to do is bracket the operation that you'd like to finish in the background, with calls to begin background task with expiration handler, and end background task.
And, we'll talk a little bit more about what the expiration handler is later.
But, in this code example here, assume the upload photos method implements the photo uploading.
Well, before we call upload photos, you simply call beginBackgroundTaskWithExpirationHandler, which will return to you a handle for the background task, and this tells the system that you're about to start an operation that shouldn't be interrupted in the background.
And, the system will try its best not to suspend your application while that background task handle is active.
And then, once upload photos finishes, you simply call endBackgroundTask, passing the background task handle, and then the system will suspend your application.
But, as I said earlier, you only have a certain amount of time to finish this task in the background.
And so, in our photo upload example, say the photo upload is taking a little bit longer than it normally does.
And, we run up against this timeout that we have for task completion.
Well, if you don't call endBackgroundTask with passing it that background task handle, the system will then terminate your application and generate a crash log.
And of course, when that happens, your application transitions from the background running state into the not running state.
To help prevent this ungraceful termination, you can register what we call an expiration handler with the system.
And, the expiration handler is just a block of code that's executed immediately before you hit the timeout.
And, when you get this call back, you can then pause that long running task or the background task, and then call endBackgroundTask to let your application suspend.
Now, you should be aware that this expiration handler may actually be called on a separate thread; on a different thread from the one that's executing the background task.
So, you may have some synchronization issues that you need to be aware of.
And so, again, because you're about to be suspended, you should prepare for suspend by saving state and reducing memory usage, as you saw in Part One.
And then again, just pause the background task; in this case, the photo upload.
And then, call endBackgroundTask to let your application suspend.
Now, here's the example we saw earlier, in a little bit more detail.
Again, we have the upload photos method, but imagine now that this upload photos operation can be paused.
And, when we pause the upload photos operation, it remembers that it was uploading; it had uploaded, say three out of ten photos, and then it returns from this upload photos method.
And, here is the expiration handler, and beginBackgroundTaskWithExpirationHandler takes a block as its first parameter.
And, if you haven't seen blocks before, the syntax may look a little bit odd, but for the purposes of this talk, it's similar to just passing a function pointer to begin background task with expiration handler, except we can define that function in line, as we do here between the curly braces.
Now, there's actually a lot more to blocks than I've just said, and if you'd like to learn more, I encourage you to come to the Introducing Blocks and GCV on iPhone OS talk later this week.
Now, back to the example here.
This block here, these two lines here are the expiration handler for our upload photos example.
And, when the upload photos process takes too long and the system is about to timeout the operation and terminate the application, it calls back the expiration handler, which executes prepareForSuspend and pauseUpload.
PrepareForSuspend is a helper function I have here that, say just saves the application state and reduces memory usage, because we won't get another chance to save out our state after our application has been suspended.
And then pauseUpload there is the method that will actually pause the photo upload, and again, this expiration handler may run on a separate thread from the one that's running upload photos.
And so, pauseUpload there handles all of the synchronization and messages back to the upload thread, and then the upload thread returns from upload photos, and we call endBackgroundTask, and then our application suspends.
Now, there are a few things you should be aware of with task completion.
When your application is running using the task completion API's in the background, the system will try to prioritize all foreground activity above any background task completion activity.
In particular, your application will be running at a lower CPU priority, and your network and file I/O will be prioritized lower than the foreground applications network and file I/O.
And again, as we saw in Part One, the GPU and real-time threads are off limits to background applications, and so if you try to use the GPU, the system will actually terminate your application.
That said, you should still try to minimize your resource usage as much as you can in the background, and of course, this involves CPU and memory, as always.
But, it's also important to end the background task as soon as possible.
So, as you saw in the upload photos example, we called endBackgroundTask as soon as endUploadPhotos returned, whether or not we were about to hit the background task timeout.
And then, it's also important to make the background task resumable in case we do hit that timeout and the expiration handler is called, and we suspend the application.
And finally, it's also important to avoid that ungraceful termination due to timeout by making sure to end the background task in your expiration handler, or as a consequence of calling the expiration handler.
Now, I'd like to hand it over to Dave Myszewski, who's going to tell us a little bit about background audio.
[ Applause ]
So, I'm David Myszewski.
I manage one of the iPhone Performance Teams.
And, we'll talk a little bit about background audio, and in particular, in this section we'll focus on media playback applications.
There are many different ways in which you can play audio in the background, and this one will focus on kind of the long term, canonical media playback apps, something like Pandora that you saw.
So, this type of app will play audible content to the user, while streaming the audio data over the network, and of course, continue playing audio in the background.
And, one of the great things about our Multitasking UI in this whole Multitasking solution is that we integrate really well with the remote controls.
So, as you see in the screenshot there, when the user swipes to the left, they have these media playback controls that are available to them, and these controls are available to the application that's currently playing audio, or the last app that's playing audio.
And, all of these remote controls handle a few different types of controlling the audio, of media controls.
There's the multitasking UI; there's, of course, the lock screen controls.
And, of course, integration with the headset, so we can double-path to move to the next track, for example.
So, we'll give you a very brief overview about the audio system.
The main thing is that the audio system kind of acts like an air traffic controller to make sure that we have the best user experience.
And, we do things like prioritize audio, so that the right audio, the audio that the user expects, is playing at any given point in time, that some audio mixes and ducks when necessary; we'll describe an example of that in a moment.
And, of course, integrating well with headsets and external speakers.
So, today, like I said, we'll focus on the audio services for a media player style application.
So, to adopt background audio, it's fairly simple.
The main thing is there's an info plist key.
And, the info plist key, you just choose the app Plays Audio Entry; and then, as long as your application is playing audio with certain audio categories, it will continue playing when the user puts the application into the background.
So, to give you an idea about what the application life cycle looks for one of these applications, when the application is in the front, it's of course in the active state.
And then, when the user hits the Home button, the application transitions from the active state through the inactive state and in the background running state.
Now, because the developer had chosen to add the audio key list entry, the UI background modes, to the plist, the application continues playing in the background, and you'll note that there's a Play icon in the upper right corner, denoting that there is an application that's actively playing audio.
Now, as long as the application is playing audio, the application will continue to run, so when the user presses the Home button, it'll continue to run until the point at which, say the user pauses the audio.
When the user pauses the audio, then there's no longer a need for the application to run, so when the music is paused, we transition the application from the background running state to background suspended, to preserve system resources.
So, how does all of this work?
Well, every application can have an AV audio session of singleton object, and some sort of delegate.
Now, you need to set the correct category on the AV audio session, which in this case is AVAudioSessionCategoryPlayback.
This is what you would use for a long term media playback sort of application.
And, this particular category has a certain number of behaviors.
It silences other audio, so if, for example, the user was playing the iPod app, and then they started using your app, you wouldn't want the iPod app to continue playing; you want your app to be the one that's playing.
So, this category says; well, we should silence the iPod audio so that your music can play.
It also allows you to play the audio behind the locked screen, which is really desirable.
When the user locks, if your app's the front most, you want it to continue playing.
We ignore the ringer switch, and of course, for multitasking, we continue playing the audio in the background.
So, all of these behaviors are defined by the audio category, and audio categories help us get the right user experience here.
If you're a background audio app, you need to handle audio interruptions appropriately, so that we get the correct kind of behavior for the user experience.
So, audio interruptions can happen in a few different places; we'll describe one in a moment.
But, during this interruption, the audio system will silence your application.
And, in that case, say you're running in the foreground.
You'd want to, of course, update your UI appropriately so that when they go to the app, the UI looks correctly.
And, of course, you may want to resume the audio after the interruption, if the audio system says that your application should.
So, how does this all work?
Well, again we have your audio session delegate and the AV audio session objects.
If there's an incoming phone call and your application is playing audio in the background, so, it's Erwin.
So, Erwin's our good friend; we're going to accept the call and talk to him.
When we hit the Accept button, then the AV audio session will send a beginInterruption event to your application, and this denotes that your application was interrupted.
And, you should do a few things here, of course.
If you were busy downloading a stream from the network; well, your audio isn't going to play, so you should stop downloading the stream.
You should update the UI.
Maybe your app was in the foreground, and so you should toggle the Play/Pause button, et.
cetera, just like you would; or, the Play Time, things like that.
And, of course, if you had some sort of, maybe 3D visualization, you'd want to stop the visualization when this happens.
So, then your audio will be interrupted, and then let's say the user hits the End Call button.
So, the user is no longer talking to the person.
Your audio isn't playing.
Now, the AV audio session will send you an endInterruption method; an endInterruption with flags.
And, this will tell you that the interruption is over and it's maybe time for your application to continue playing.
In this particular method, there's a flag; the AV audio session interruption flag should resume, and that's a flag that's set by the audio system that tells you whether or not you should resume.
So, as an example, for the phone call case you would want to resume your audio.
But, if the iPod were the one who interrupted you, then when the user stops playing the iPod, you wouldn't want to resume.
So, as long as you implement the right behavior with this flag, your application will work really well with the audio system, and everything will work just like the user really expected it to.
So, we have these nice media playback controls, and we give you some API's to take advantage of these.
As I said before, that the last app that was playing the audio receives the events.
So, if the user paused your app, you know, five hours ago and decides; boy, I want to hit the Play button, I want to listen to some audio.
The last app wins, so the user will start playing your application's audio.
All of these events are routed through the responder chain; we'll show you which method to implement here.
And, one of the things about audio behavior is, like we showed before, once the user pauses your application, the application remains in the suspended state until the user either relaunches your application or uses the media controls to play your application.
So, how does this work?
So, the user paused their application a few hours ago, but the app is still alive in the background.
So then, when the user; so, you're in the background suspended state and then the user presses the Play button in one of those media controls.
Then, we resume your application for just a little bit of time to allow you to handle this incoming event.
So, we'll move your application to the background running state.
Then, let's say that you saw that; oh, this was a play event.
If it was a play event, you would start playing audio.
And of course, if you start playing audio, because you're a background audio app, you will continue running and playing audio in the background.
So, that's how the app life cycle works for a media playback app with media controls.
So, how do you implement this?
Well, it's fairly easy.
You have a UI application method called beginReceivingRemoteControlEvents.
This tells the system that your audio application is interested in receiving these events that happen from the multitasking UI, the lock screen controls and the headsets.
And then, somewhere in the responder chain, you implement this method; remoteControlReceivedWithEvent.
The documentation for this is in UIEvent, but there are several different event sub-types that you can handle appropriately, so one to toggle Play and Pause, one to go to the next track, one to go to the previous track, and there are about a dozen of these.
And, you should implement any of these that are specific to your application, that make sense for your application.
It's also important to use these sub-types for exactly the kind of behavior that the users would expect.
So, Play/Pause should play/pause; you shouldn't overload it with a different meaning.
That way, everything behaves as correctly; Play button really plays, et cetera.
So, this is the method that will be called to handle the event, if say your application is unsuspended.
So, for the background audio solution, we make sure that you, as developers, have access to all of the tools that you need in order to play background audio.
So, if you, for example, are an application that synthesizes audio; those applications have some really hard real-time deadlines that have to be made, so we make sure that we allow you to play those kinds of apps, because we want those kinds of apps to be available.
And so, as part of this, it's really important to minimize your resource usage, just as it is for any other background application.
You know, we'll make sure that you get the CPU, the file I/O, the networking that you need.
And then, on the other side, if you can minimize your resource consumption, then it'll be a better experience for all of the users because this is one system, and so you should reduce your memory usage and CPU usage, since we have a lot of shared resources that we need to have.
And, a lot of the audio apps are really good about this.
One important bit; if you're an application that's streaming data to the network, it's really important to request and download data in chunks.
So, if I have, say a three-minute audio track, it's probably a good idea to try to download, say all three megabytes of that audio track.
And, the reason is, particularly over 3G, it's very expensive to send and receive data.
The radios are some of the most power hungry parts of the system.
So, as an example, let's say that I downloaded maybe, I don't know, 30 seconds of the music.
So, that's denoted by the orange box.
Then, the red box shows how the 3G radio behaves.
So, the cell towers tell the 3G radio to stay in a high powered state shortly after the transmission is done.
So, there's some period of time after which the last byte is sent or received for which the 3G radio will stay on high power, because the cell towers said that we needed to stay in the high power state.
And then, at a certain period of time, the cell towers will tell us to go into a lower power state.
So, what that means is that if we're trying to send and receive, say a few bytes at a time, then our 3G radio power will be pretty high for a pretty long period of time.
So, what you really want to do is just request data in bulk.
Get all of the data that you can, and that way the 3G radios kind of are, you know, are in the right power states.
So, you want to send and receive data in bulk, and that's true for anything; it's not just background audio.
Send and receive data in bulk will be better for power.
Now, the last thing about background audio is, of course, we provide background audio recording as well.
And, this works conceptually just the same way the background playback does.
There are a few quick differences.
One is, of course, you need to use a different audio category; the record category, which tells us that you're recording audio in the background.
And, on your behalf, if your application is recording in the background, the system will create a double-height status bar that's read, so that the user knows that there's some application out there recording audio; so, for privacy reasons.
And then also, we provide great functionality to tap the status bar, so that the user can return right to your app, and then maybe stop the recording or make a new recording.
So, these are a couple of the capabilities that we provide for background recording.
And, so that's Background Audio, and Charles is going to show you a quick example here.
Charles Srisuwananukorn: So, I'd like to demo now how to create a background audio application.
But, since we only have a limited amount of time, I'm going to cheat a little bit and start with some example code from developer.apple.com.
So, let me switch over to the device here.
And, here I have a slightly modified version of the AV Touch sample from developer.apple.com.
And, you'll notice that if I tap Play, [Music] the audio starts playing and it shows the current track name, the play time of the track, and it has this nice level meter visualization and actually uses GL to draw the level meter.
But, if I tap the Home button now, to send it to the background, the audio actually fades out and stops.
So, let's look at how we can modify AV Touch so that its audio continues to play in the background and it behaves well as a background audio application.
So, I'm going to switch over to Xcode now, and the first thing I'm going to do is edit the info plist for the AV Touch application.
And so, I'm going to add a row down here, but now I'm going to zoom in so that you can actually read that.
And, I'm going to select the required background modes key in the info plist.
This is actually an array, so I have to drop down the disclosure triangle there, and the first item that I'm going to add, or the only item I'm going to add for this background audio application, is the App Plays audio value.
And now, let me zoom up.
Now, with this key, AV Touch can actually play audio in the background, but if I build and deploy this to the device, I'll find that when I tap Home, the audio still stops.
And if I take a look at the crash logs in Xcode, or in the console in the Xcode organizer, it'll tell me that my application was using the GPU in the background, for that GL level meter.
So, what I need to do is stop the level meter when AV Touch enters the background, and then resume the level meter when AV Touch returns to the foreground.
And, I'm going to do that in the Awake from NIB of this AV Touch controller class, which is called when the AV Touch controller is loaded from the NIB.
And then, the first thing I'm going to do is register for the UI application, didEnterBackgroundNotification, which was sent whenever AV Touch goes into the background, and I'm going to do that by grabbing the default notification center and adding in observer on the default notification center that calls this pause level meter helper function.
So, this will actually pause the level meter when it goes into the background, and so it can continue playing audio without terminating due to background GPU access.
But, I also need to resume the level meter when it comes back to the foreground, so to do that I'm going to register for the UI application, WillEnterForegroundNotification, which as its name suggests, will be sent when the application comes back to the foreground.
And again, I do that by adding an observer to the default notification center and this time, I'm going to call the resume level meter helper function.
Now, I'm not going to show you what these two helper functions do, because it actually touches quite a few files and we don't have the time.
But, it essentially stops the update timer from my GL drawing, and if you'd like to see that in more detail, please come to the labs.
Now I've paused the GPU access while in the background.
The next thing I want to do is respond to interruptions appropriately, as Dave mentioned earlier.
And, I'm going to do that down here where we see that the AV Touch controller is already implementing the beginInterruption and endInterruption methods.
The beginInterruption method is okay, but the endInterruption method really should be endInterruptionWithFlags.
So, I'm going to replace this method with endInterruptionWithFlags, and then in endInterruptionWithFlags, I check whether the ShouldResume flag is set on the flags parameter sent to this delegate method, and if it's set, then I call Start Playback.
Now, the last thing I'd like to do as a background audio application is respond to the remote control events.
And, as we said earlier, the remote control events are sent through the normal UI responder chain, so I'm going to edit the AV Touch view controller, which is the view controller for that main view that you saw in AV Touch.
And, the first thing I'm going to do is override canBecomeFirstResponder, so that we can receive those remote control events in this class, and I'm going to return Yes.
And then, I need to tell the system that my application is interested in these remote control events, and handle the remote control events.
So, I'm going to do that in the viewDidAppear for this view controller, and I'm going to call beginReceivingRemoteControlEvents, which tells the system to route remote control events to my application if I was the last application to play audio.
And then, I'm going to call becomeFirstResponder, which makes the AV Touch view controller the first responder in the responder chain, so when those events come to my application or come to AV Touch, the AV Touch view controller is the first class to handle these events.
Now, of course, I need to actually process the events, and I'm going to do that by overriding the remoteControlReceivedWithEvent method from UI responder, and then switching on the event sub-type.
And in this case, the only event that I'm handling is the Toggle Play/Pause event, but I could also handle the previous Track and Fast Forward Track if needed.
So, I'm going to go ahead and build and run that.
So, now when I press Play, [Music] you'll notice that again, it has the track name and the play time, the level meter, but now in the upper right corner by the battery meter, you see a little Play icon indicating that there's an application playing audio in the system.
If I now tap Home, the audio continues playing.
And now, if I double-tap to bring up the multitasking UI, and slide over to the remote controls in the multitasking UI, I can actually pause it from here.
And in addition, I can lock the device, bring up the controls on the lock screen, resume playing from the lock screen.
[Music] And also, one last thing.
If you look at the remote controls in the multitasking UI again, you notice that the icon next to the remote controls actually changed to the icon for AV Touch.
If I now tap the icon there next to the remote controls, it returns me back to AV Touch.
The track was looping there, it didn't stop playing; sorry.
David Myszewski: So, that's Background Audio.
So now, we have a few more categories that we want to cover, starting with Navigation.
So, Navigation works a lot like Background Audio, as you'll see.
So, we're going to create a very simple example application here, which is kind of a turn-by-turn directions app.
And, that app would want to keep the users informed of their current location at a very granular level, so that we don't miss any turns, and speak out turn-by-turn directions.
So, how do we do this?
Well, this type of application would want to register for both background location and background audio in the info key list.
So, there are entries for both of these.
As Charles mentioned, this is an array and you would simply add both location and audio to your UI background modes array.
And, the application life cycle works just like Background Audio.
When the user has the application in the foreground, they're in the active state.
And then, when the user presses the Home button, the application transitions through the foreground inactive state to the background running state, and as long as the application was tracking your location, the application remains running in the background.
So, to put this on the timeline view, if the user is updating your location, and then the user presses the Home button, the application will continue to run until, say you reached your destination.
Now, when you reach your destination, the application might stop location services, as we recommend.
And then, at that point, because you're not updating the location constantly, then the application will be suspended.
So, the application transitions from background running to background suspended.
So, how does all of this work?
Well, we have the CL Location Manager, just like we did in iPhone OS 3.
And, you may have a delegate object here that's going to call this particular method on the CL Location Manager to say that we really want the best accuracy here for navigation.
This will be the finest grain controls that we have for location updates.
Then, the CL Location Manager will provide updates after you make this call to start updating the location.
So, this tells us; great, let's turn on the GPS.
Give me quick location updates.
And, the CL Location Manager will send you these updates to say that you've moved from one particular location or to one particular location from another, and so, you'll get many of these as your location changes over time.
Now, for Background Audio support, so if we want to speak these directions, we want to do three things in the background.
The first thing is we need to, as before, set the appropriate audio session category, so again, we're going to use the AV audio session category playback.
But, this time we're going to set a couple of properties on the audio session so that we get the intended behavior.
So, in particular, we're going to set the AV audio session property OverrideCategoryMixWithOthers.
That will say that we should mix with other sounds, so you'll want this in an application that speaks location, because you may have other sounds that are going on at the system at the same time, and so you want to mix with others.
Then, there's also the property to mix with others, or that other mixable audio should duck.
The economical example her is sort of, you're listening to your iPod app because you're moving down the road.
You know, it's heavy metal; you probably don't hear directions over that.
So, what you really want is for that other mixable audio, i.e., the iPod app, to duck a little bit, so that you can hear your directions, because that's what you want to hear.
You don't want to miss your turn.
So, I think this property is important for a navigation app and it'll allow the user to hear want you want them to hear for that brief period of time, as the iPod app quiets down so that the user can hear it.
For Navigation, we have the similar best practices.
You should minimize CPU usage.
Hopefully, it shouldn't need a whole lot of CPU as you're updating from location to location.
And, as we said before, for power reasons it's great if you can turn off location updates after you reach the destination, because GPS is a fairly high power operation.
So, once you're there, then turn off location updates and then if the user wants to navigate to another place, they can return to your app and choose another place to go to.
And, that's really all there is to Navigation.
But, there are some other important location categories, and Charles will describe all of those.
[ Applause ]
Charles Srisuwananukorn: So now, I'd like to talk about a couple of new location tracking services in iOS 4 that allow your application to track the device as it moves around.
To motivate these services though, imagine we're implementing a location aware, Capture the Flag app.
And, the first thing you do in this application is set two coordinates as the two flags, and then set a couple of regions around each flag.
And, to capture the opponent's flag, you enter the region around your opponent's flag and then return to the region around your own flag.
So, that's how that works, basically.
But in addition, it can also display a map of all of the players that are currently playing the game, and approximately where they are in the city.
To implement this, we'll use two new services in Core Location; one called Significant Location Changes, and the other one called Region Monitoring.
Significant Location Changes will notify your application when the device has moved cell towers, and we use cell towers as a proxy for when the device moves a significant distance.
The Region Monitoring API, on the other hand, will notify your application when the device enters or exits certain geographic regions of interest that you've previously registered with Core Location.
Both services use less power than the standard location services, because they are based on cell positioning.
Both services will resume applications that have been suspended.
Both will also relaunch applications that have been terminated for, say low memory conditions.
But, there are also a couple of caveats that you should be aware of.
If the device is sleeping, significant location change notifications may actually be coalesced or delayed, in order to preserve battery life, but region monitoring notifications won't be.
And also, since both services are based on cell positioning, they're only available on devices with cell radios.
But, in particular, region monitoring is only available on iPhone 4, whereas significant location changes is available on both iPhone 4 and iPhone 3GS.
So, let's talk some more about the Significant Location Changes API.
So, as I said earlier, the Significant Location Changes API is meant to send you a notification when a device has moved a significant distance.
And, it does this by calculating an approximate position for the device whenever the device changes cell towers, and then sends your application that approximate position.
The accuracy of that position, of course, will be similar to the cell positioning.
And, also again, you should be aware that these notifications may be coalesced while the device sleeps to prevent that excessive battery drain.
So, our Capture the Flag application can then use the significant location changes service to implement the player map that we saw earlier.
And so, whenever a player enters a game, the first thing our Capture the Flag application does is start up the significant location changes service.
Then, when the player moves cell towers, this Core Location will notify your application with that approximate, current location, and our application can then upload that location to a server.
And then, if they move cell towers again, the same thing happens, and every time they move the cell towers, we can upload a new location to the server.
Now to set this up, our application first creates a CL location manager and a location manager delegate and associates the two together, and then calls startMonitoringSignificantLocationChanges on the location manager.
Once we've done this, whenever the device changes cell towers again, the location manager will call back the delegates; locationManager:didUpdateToLocation:fromLocation: delegate method.
Now, this is the same method that's called when you used the standard location services, as we saw earlier in the Navigation example.
But, the position that it passes you is the approximate position based on cell positioning.
When you receive this notification, you might actually be in the background, so you don't have much time to run and process the notification.
But, you can also use the Task Completion API to continue running in the background while you upload that location to the server.
Now, let's talk more about region monitoring.
Region Monitoring will send a notification to your app, again, when it enters or exits a region of interest.
And, the big benefit of region monitoring is that your application can be suspended while it's moving around, and it's not crossing any of these boundaries between the regions of interest.
Again, this service is also based on cell positioning, so it also uses less power than the standard location services, but your application is also limited by the number of regions that you can register, and it is only supported on iPhone 4.
So, now assume that this red pin over here, it represents one of the flags in our Capture the Flag game, and we've registered a region of interest around the flag, represented by those red circles.
Now, and then assume that the Capture the Flag application suspended, because there was nothing else to do.
Now when the device moves, core location won't notify your application, because it hasn't actually crossed into this region yet.
It's not until the device actually enters the region that it then sends a notification saying we've entered the region, and your application has a chance to process this notification.
So, to use region monitoring, again we create a CL location manager and a delegate and associate the two together, and then call startMonitoringForRegion, passing it a description of a geographic region.
Now, whenever the device enters or exits one of these regions, the location manager will call back; the locationManager:didEnter or didExitRegion:, depending on what happened, and then your application can process those appropriately.
In the case of the Capture the Flag application, we may want to notify the user, saying; hey, you've entered your own base.
Congratulations, you've won!
But, your application may be in the background again, and so it won't be able to actually display its own UI to the user, and instead, it can also use the local notifications service to display an alert to the user, very similar to a push notification alert, that the user can then use to bring the Capture the Flag app back to the foreground.
Now, let's review what states the application goes through as each of these events are received.
Now, assume that the application is suspended again; the Capture the Flag application is suspended again.
And then, we either enter one of these regions or we get a Significant Location Changes event.
So, there we are in the suspended state, and the system will unsuspend our application to handle the event, which transitions us from the suspended state into the background running state.
And then, once the event is handled, we can then transition back from background running into the suspended state and we can be suspended until another interesting location event happens.
But, as I said earlier, your application may also be relaunched.
So, assume that the Capture the Flag app had been terminated, again due to low memory or for some other reason, so that it's in the not running state.
Then the system will relaunch your application when one of these events happens, which transitions your app from the not running state into the background running state.
And then, it'll deliver the event to your application so you can handle it.
And then, once you're done handling the event, the application will then become suspended again, so we transition from background running to suspended, and then it's suspended until, again, one of these events happens.
But, your application may not want to start location services every time your app is launched, and so to help you detect when you've been launched in the background for one of these location updates, the iPhone iOS 4 will pass the, or will set the UIApplicationLaunchOptionsLocationKey, in the options dictionary, pass to your application, didFinishLaunchingWithOptions.
So, you can then check this key and if it's set, create a CL location manager and start monitoring those significant location changes again, or start up the location services.
So, a few best practices you should be aware of would be services; you should use significant location changes and region monitoring only if possible, and only use the standard location services if you need the extra precision or the extra accuracy.
You could even do a somewhat hybrid approach and fire up the standard location services when you receive a significant location changed event, so that you'll only use the high power GPS when the device has actually moved a significant distance.
And, even though these services use less power than the standard location services, they still use some amount of power.
So, it's best to stop using those services as soon as they're not needed, and you can do that by calling Stop Significant Location Changes on the location manager, or Stop Monitoring Region when the region's no longer interesting.
Now, the last multitasking service or set of multitasking services I'd like to talk about today are those geared toward VoIP, or Voice over IP applications.
A VoIP application is an application that makes and receives phone calls using an Internet connection.
It notifies users of incoming calls, whether it's in the foreground or in the background.
It can receive calls in the background.
And, it can stay on a call as it enters the background.
And, the first thing you do as a VoIP application is set the appropriate background modes in Xcode, and for a VoIP application, you want the App provides Voice over IP services, which enables you to call the VoIP API's, and the App Plays Audio background mode, which allows you to play the call's audio while it's in the background.
And, almost every VoIP application will probably need both of these keys.
[ Silence ]
So, there are a few things that every VoIP application will want to do.
First is respond to incoming calls quickly.
If your VoIP application receives an incoming call, the incoming call notification should be delivered to your application as quickly as possible.
In the same vein, it also should maintain a persistent signaling connection to the VoIP server, so that it doesn't have to reconnect and re-authenticate that signaling connection when it receives the incoming call.
It should notify the user of the incoming call, whether it's in the foreground or in the background.
And, if the user accepts the incoming call, it should implement the appropriate audio behaviors for a VoIP call.
And finally, it should integrate well with cellular calls, which usually means simply putting the VoIP call on hold while you're on a cellular call.
So, let's look now at how the system helps you first respond to those incoming calls, or receive those incoming call notifications quickly.
So, if the device receives an incoming call notification intended for your VoIP app, it's much better if your VoIP app is already running, so we don't have to relaunch the application and incur that delay of relaunching the application before delivering the notification.
And so, what the system does is on device boot, it will actually launch your application, and it will also relaunch your application if it's been terminated for, again, low memory or for some other reason.
But, after it's done launching, it can actually be suspended again until something interesting happens for your VoIP application.
For example, if your application receives an incoming call, then the system will unsuspend your application, and as long as the user or the application is on that incoming call, your application runs until the call completes.
Once the call completes though, it can then suspend again until some other event happens; for example, a network keep-alive, and we'll talk more about what network keep-alives are in a second.
But, they are a way for your application to maintain this persistent network connection.
And so, then when one of these events happens, it unsuspends your application again to send the keep-alive, and then re-suspends it.
Now, let's take a look at how to maintain that persistent signaling connection so that when the incoming call notification comes in to your application, you don't have to reconnect the connection and re-authenticate the connection.
So, the first thing you do is you create a CF stream, and to create the CF stream, you can use any of the CF stream API's that we have, and in this case, I'm going to use the CF stream, Create Pair With Socket To Host, which will return a read stream and a write stream to this host.
Then, I call this prepare stream method, passing it both the read stream and the write stream.
The prepare stream method then does all of the things you would normally do with a stream, like setting the delegate, scheduling in the run loop, and calling open on those streams.
But, most importantly for our VoIP app, it sets the NS stream, Network Service Type VoIP Property, for the NS stream network service type.
And, this tells the system, or iOS 4, that it should wake up or unsuspend your application for any incoming data on this CF stream.
So, in that way, you can actually be unsuspended whenever there's incoming data on the stream.
A couple of other notes about this CF stream, or VoIP CF stream.
As I said earlier, you can use any of the CF stream API's that create CF streams.
In addition, you can use the ones that wrap POSIX or VSD sockets, which is a common question on the forums.
And, you should be aware that the CF stream API only supports TCP streams, but this is OK because you only need the VoIP property on your signaling channel.
If the call's audio channel uses UDP, for example, just by playing audio your application remains unsuspended and you can continue to play the audio.
But, even though your application is now unsuspended whenever there's incoming data on this channel, it can still be subject to certain timeouts, like NAT timeouts anywhere along the route, or it might even be using some protocol that requires the client to check in with the VoIP server periodically, and if it doesn't, then the server will close down the connection.
So, to help your application maintain these connections, you can register a keep-alive handler with the system by calling setKeepAliveTimeout:handler: on the UI application class.
And, so that KeepAliveTimeout:handler takes as its first parameter a time interval, and a block as its second parameter.
It will then unsuspend your application on the interval that you specify, and execute that block that you've passed in.
And so, using this you can actually send periodic keep-alive packets to prevent these NAT timeouts or protocol level timeouts.
And, you should also note that the minimum keep-alive timeout for this mechanism is ten minutes.
So, now we've set up this persistent signaling connection and we can receive incoming call notifications, and we don't have to reconnect to the VoIP server when we get an incoming call notification.
But, how do we tell the user that they have an incoming call, because your VoIP application may again be in the background, and so it can't present any of its own UI?
Well, again we have the local notification service, which your VoIP app can use to present a push notification-like alert in front of the user, and you do this by calling presentLocalNotificationNow, which will actually display the alert that you see there.
Note that you can also dismiss local notifications if the user receives multiple calls before looking at the device to prevent these alerts from stacking up.
So, we've alerted the user that they have an incoming call.
Imagine now that the user clicks Accept, and we have to connect the call and start playing the call's audio and take input for the call.
To do so, we have to implement the appropriate audio behaviors, and so the first thing we have to do to implement the appropriate audio behaviors is set the right audio category on our AV audio session.
And for VoIP apps, the right audio category is the AV audio session category, Play and Record category.
This category is similar to the Playback category that we saw earlier, but it allows simultaneous access to both input and output, so you can take an input for the call at the same time as playing the output from the other side.
Like Playback, it silences other audio, so if you were playing iPod when you started the call, it will actually silence iPod.
And, it also enables output to both the receiver or the earpiece, and the speaker, so you can implement a speakerphone in your VoIP app, if you like.
But, we would also like other audio to resume after a VoIP call ends, because this is the way that phone calls behave.
So, if the user was playing the iPod before receiving the VoIP call, and then we connect the VoIP call, when we end the VoIP call, iPod should resume playing again.
And, to do that, you set the AVAaudioSessionSetActiveFlags_NotifyOthersOnDeactivation flag when you deactivate the session after the call ends.
And, what this does is it just tells other applications that were playing audio, that had their audio interrupted, that they need to resume their audio.
And, more specifically what it does is it sets that AVAudioSessionInterruptionFlags_ShouldResume flag when it calls those other applications and interruption with flags methods.
So finally, VoIP applications should integrate with cellular calls, and again, usually that means just putting the VoIP call on hold while on a cellular call.
And so, in iOS 4, we provide the CoreTelephony framework, and in the CoreTelephony framework we have an API called setCallEventHandler: on the CTCallCenter object.
And, setCallEventHandler: takes a block that is executed whenever the user receives an incoming cellular call, or ends the current cellular call.
And so, your application can then use this to put the VoIP app's call on hold whenever the user is on a cellular call.
So, a couple of best practices for VoIP apps.
VoIP apps are also audio applications.
So, everything that we've said about audio applications also applies to VoIP apps.
In particular, we try to ensure that VoIP apps have all of the CPU and all of the network and file I/O that they need to play the call smoothly, which means you should try to minimize your resource usage as much as possible by minimizing your CPU, and to avoid using large amounts of memory.
And, more specifically to VoIP applications, you should try to use as long of a keep-alive interval as you can to maximize battery life.
And, we've found empirically that 29 minutes is a pretty good tradeoff between timing out our sockets and battery life.
Multitasking, again, on iOS 4 doesn't mean that applications run all of the time, but, you know, there are some applications that do benefit from executing in the background, and for those applications we provide some new services to run in the background.
We have the task completion API, which allows your application to request extra time to finish up a task on behalf of the user while in the background.
The background audio API, to play audible content to the user and respond to remote control events in the background.
The navigation service, to implement turn-by-turn navigation applications.
A couple of location tracking services; significant location changes and region monitoring, to monitor the device's location in the background in an efficient manner.
And finally, the VoIP services, which allow your application to make and receive phone calls using an Internet connection.
And again, if you missed part one earlier today, we'll be repeating part one on Friday at 9:00AM.
And, we've covered a lot of ground today, and so we've only scratched the surface what each of these services can do.
If you'd like to learn more about each of those services, please come to the related sessions here.
In particular, we didn't cover push notifications at all, so if you'd like to learn more about push notifications, please come to the Implementing Local and Push Notifications session.