Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2009-318
$eventId
ID of event: wwdc2009
$eventContentId
ID of session without event part: 318
$eventShortId
Shortened ID of event: wwdc09
$year
Year of session: 2009
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2009] [Session 318] Peer to Pee...

WWDC09 • Session 318

Peer to Peer Networking with Game Kit

iPhone • 58:33

Add multi-player functionality to your games using the peer to peer networking capabilities of Game Kit, a new framework in iPhone OS 3.0. See how to access the standard interface for discovering remote players and sending data or game state over a Bluetooth connection. Learn how this new framework can be used for more than just games and discuss how you can take advantage of in-game voice over Wi-Fi.

Speakers: Joe Abuan, Jonathan Bennett, Roberto Garcia

Unlisted on Apple Developer site

Downloads from Apple

SD Video (96.2 MB)

Transcript

This transcript has potential transcription errors. We are working on an improved version.

So welcome to our WWDC Session, Peer-to-Peer Networking with Game Kit. My name is Joe and I'll be the first of three presenters who will talk to you about this brand new technology in iPhone 3.0. Some of you may be new to the iPhone and we welcome you. And others of you are veteran developers on iPhone and you may have one or more apps on the App Store.

Of course you're all welcome and in either case what you'll find in Game Kit is an amazingly easy API to use to connect your application across multiple devices. If you already have an application that connects multiple users and works over the internet, what you'll find in Game Kit is a very simple API that you can use to add voice chat functionality. To show you how you're going to learn about all this today, let's go over the agenda. We'll go over a brief overview of the capabilities of Game Kit, following this we're going to go into the APIs.

There are three classes in Game Kit, the GKSession which we'll refer to as the Session, the GKPeerPickerController which we'll call the Peer Picker, and then there's the GKVoiceChatService which we'll call Voice Chat. Now as we talk to you about the APIs in these classes, you're going to see some code samples and at the same time we hope that you hear some tips and best practices to using them. Now let me talk about what you're going to learn. You're going to essentially learn two main things this morning. The first of course is how to use Game Kit to connect to your application.

In Game Kit, we have two classes for this purpose. There is the GKSession, the session object which will handle all the networking for you, and then there is the Peer Picker object which will give you an instant UI that you can use to quickly connect two users of your application. The network that Game Kit creates is a peer-to-peer network composed of devices running your application. Your application doesn't need to be online for this to happen, so this means of course you don't need a WiFi router, you don't need a cell data network connection.

What you do need is Bluetooth, and the hardware that supports this new Bluetooth functionality are the iPhone 3G including of course their brand new 3GS and the second generation iPod touch. The second thing that you're going to learn this morning will be to how to use Game Kit to integrate voice chat.

We essentially have voice chat in the box where you just need to provide the network. So the API is designed to integrate with your existing network code. Now as well as handling some obvious things for you such as audio encoding and decoding, it includes usage of that voice processing unit that Eric Allamanche spoke about in a previous CoreAudio session yesterday. So it includes echo cancellation. Now let's see how Game Kit may fit into your application.

Here is the application at the top. Your application has access to one or more of the Game Kit objects, the session, Peer Picker and voice chat. Game Kit itself to handle all of its networking, is built on Bonjour and sockets. Game Kit uses Bonjour Service Discovery to find your application running on different devices. And then Game Kit is using socket APIs to establish network connections between the devices, between your applications running on these devices, and to deliver your data. There are a couple of things I want to mention about Bonjour.

The first is that in iPhone 3.0, peer-to-peer connectivity over Bluetooth is integrated at the Bonjour layer. What this means for you is that if you already have an application that works over Bonjour, then if your users are an iPhone 3.0 and they're on the supported hardware, your application will automatically just work over Bluetooth. You don't have to make any code changes for this functionality.

Now I do want to point that if this is the first time you've heard about Bonjour or if you know every little about it, or if you don't know much about socket APIs, you don't have to know these things in order to use Game Kit. Game Kit interfaces with these APIs directly and can handle all this for you.

Now I'm going to go and talk about the session API. Before I get into the details of the API, let's talk about some terminology. In Game Kit we use the term peer to refer to an instance of a GKSession. Now since your application will typically just use one instance of GKSession, what this essentially means is that a peer is your application running on a device. Now to differentiate between the different devices running your application, Game Kit has what we call a peer ID. This is some string that's a unique identifier for peer.

Note that even though this is a string, you should not display this to your user. If you wanted a public name for the peer ID or display name, we have a method called displayNameForPeerID which will give you this name, and when I talk about how to create the GKSession you'll see how you can set this display name to whatever value you'd like.

Now there are only three stages to using GKSession in your application. You first need to initialize the GKSession. Once you've done that you can proceed to connect to other users, and once you've connected at least two users or two instances of your application, you can then begin to send and receive data.

Now I'm going to go through each of these stages in turn. Stage 1, initialize the GKSession. You first of course need to create a GKSession object. So what you see up here is code that alloc inits a GKSession. You'll note that it takes three parameters. The first parameter is what we call a session ID. This is an ID that uniquely identifies your application.

Game Kit will use your session ID to differentiate it from the session IDs of other applications written by other developers such as yourself. To help insure that your session ID is indeed unique to you, we recommend that you register your session ID as a Bonjour service type. Now in my case I have my session ID and that could certainly be a registered service type or it could just be some string that I've come up with.

Now if you're wondering what string to use or if you haven't had the chance to go and register a service type, you could certainly pass a nil as a first parameter. If you do this, what Game Kit will do is generate a session ID for you that is based on the bundle identifier in your application.

So you can do this to quickly get started with GKSession but we really recommend that you register it as a Bonjour service type, and I believe in Allan Schaffer's talk yesterday he showed you a website where you can go do that. So check that out. It's easy, you send an email, it's free, and your service type as well as your company's name will actually be posted on a webpage.

So we'll have a free advertising for you. Now let's go to the second parameter, the display name. This is how you set that public name that is returned when you call the display name for peer method. In my example on passing a nil, if you pass a nil here, Game Kit will just use your device name as the display name.

If you're not satisfied with the device name, if you want to pass in your own name like a real name like Andy or Bob, or you want to use a gamer handle, pass it in as a second parameter. The third parameter is a session mode. The session mode affects how Game Kit will find and connect peers.

There are three modes in Game Kit, server, client, and peer. In server mode the peer is just advertising your session ID. It's doing this because it's expecting to be found by other peers searching for your session ID so that it can then receive connection requests. Client mode is a mode where the peer will search for your session ID.

So a peer in client mode will find a peer in server mode assuming their session IDs match. The third mode is peer mode. It's a combination of client and server. A peer in peer mode will both advertise your session ID and search for it. Now you'll note in the diagram here, you could see that we have four devices connected using server and client mode. And what we recommend is that if you want, you know, if your application requires the need to connect more than two instances together, we recommend that you use client mode and server mode to do this.

It's the most efficient way for you to get more than two devices or more than two instances of your application connected together. Now I've finished talking about how to create the object, there are two remaining things you need to do. You need to set the delegate. GKSession has a delegate protocol called the GKSession Delegate Protocol and it is through this delegate where you can get events from Game Kit.

The last thing you need to do in stage 1 is to set the session as available. Setting the session as available starts this process of either advertising your session ID, searching for it, or the combination of the two depending on the mode that you have selected for the session. We're now at stage 2, connecting to other users.

To establish a connection to another peer, Game Kit has a method called connectToPeer and this just takes the peer ID of the peer that you want to connect to. This peer in order to handle this connection invitation will need to watch for incoming connections. And to do this the delegate must implement the session didReceiveConnectionRequestFromPeer method. It is through this method that the session will tell you the delegate that hey, here is an incoming connection. And what you'll get is the peer ID of the peer that wants to connect to you.

So you're expected to respond to this invitation and you could accept or deny it. In my example here you could see us accepting the connection and to do so we call acceptConnectionFromPeer and we pass in the peer ID of that peer that sent us the connection request. Now you might be wondering, how do I know the peer ID of the peer that I want to connect to? Or if I was able to send a connection request and it was accepted, how do I know that it succeeded? How do I know that I'm now connected to this other peer? Well the key thing here to handle this or to find out is to watch for peer state changes.

To do this, your delegate must implement the session peer didChangeState method. It is through this method that the session will tell the delegate the new state for a particular peer. One example state is the available state. A peer that comes in with the available states is a peer that was found that matches your session ID and it's a peer that can accept connection requests.

So if your application has a UI and you want to present a UI to your user, of the available users around who are also running your application, if you get this callback you can update your UI with the name of that user. And you can get the name by calling the displayNameForPeerID method.

And then if they click that name, you can then call that connect to peer method that I showed you on the previous slide, connect to peer and pass in that peer ID. Now if you've sent the connection request and it's been accepted, each peer will know that it's now connected to the other peer by callback where the state is connected. A peer that comes in to this callback to this didChangeState callback with the connected state is now connected to your session.

So now your peer can send and receive data with this peer. Now these are just two states that I mentioned. If you look at the API documentation there is actually more. One state here that's missing which you may have seen in Allan's slides yesterday is the disconnected state. So you'll also know that you're no longer connected to a particular peer if you get this callback and the state is disconnected. We're now at stage 3, send and receive data.

In Game Kit we have two methods to send data. The method that you see up here is one that allows you to send data to all the peers that are connected to you. The other method which you can see in the documentation is one that allows you to send data to a subset of peers, just one peer or two out of four if you have a team based type of application. In both cases, the data that you want to send needs to be wrapped in an NSData, so you simply take your application data, wrap it in an NSData and then pass it as a first parameter in this method. Game Kit supports two modes of data delivery.

There is a reliable mode and an unreliable mode. You'll want to use reliable mode for data that is critical to your application, data that needs to arrive at all the peers. In reliable mode, Game Kit will take care of retransmitting this data for you as well as delivering this data in order if you've called send data with reliable mode multiple times in a row. Now there is some overhead because of the retransmissions. So if you have app data that updates frequently such as real-time data for example, or more obviously a positional data, you should use the unreliable mode for send data.

The last parameter is an error parameter, and note that if there is invalid error returned here, it's more an error about data transmission. Send data as well as many other methods in Game Kit is non-blocking. So when you call send data it's going to return right away. If there is an error, you should check that and one error that you may encounter especially if you're first playing with this and using a reliable mode all the time is a buffer full type of error. Now if you're sending data you're going to want a way to receive it, so to do this you need to set what we call a data receive handler.

This is an object that implements the receive data from peer in session context method. You'll note that the data that you receive will come to you as an NSData object. So you could simply access the bytes there and parse your data as you see fit. You'll also note that you get the peer ID of the peer who sent you that data. So, you know, that comes in as a second parameter here.

Now I'm done with stage 3 and that's pretty much it. Those are the three stages that you would need to follow if you want to integrate GKSession directly in your application. So a slide for review, Game Kit creates a peer-to-peer network and delivers your data. In iPhone 3.0 this support is over Bluetooth.

Game Kit uses the notion of peers and peer IDs to refer to devices that are running your application or your application instances on different devices. And then there are just three stages to using GKSession in your application. You initialize the GKSession passing it important information such as the session ID and then choosing a mode. You could then proceed to connect to your peers.

Implement that didChangeState callback and know when a peer is available so that you could then call that connect to peer method to connect to them. And then once you're connected to at least one other peer, you can deliver your data and call the send data receive methods and make sure you have it set, a data receive handler so you can receive the data. Now earlier on I mentioned that the first thing that you're going to learn today is how to use Game Kit to connect your application. And then I mentioned that there are two classes that you can use to help you with this.

I've just told you about the GKSession. The other object is the Peer Picker and it can actually take care of stages 1 and 2 for you as well as provide you with a standard UI that you can immediately use to connect your application across two devices and to tell you all about this, I would like to introduce my colleague Jonathan Bennett.

Thank you.

[ Applause ]

Thanks Joe. So I'm Jonathan Bennett and I'm a software engineer on the Game Kit team. So you just heard Joe talked about how you can use the Game Kit session to easily discover, connect, and send data to other peers. Now if you have a multiplayer game or a multiuser application, one of the most important things you're going to need to do is provide your users with a way to find and connect to other peers. Now we also know that you as developers are more interested in what happens after your peers are connected.

It's your in-game multiplayer experience that's going to have your players coming back for more. So to help with this, if you have a one-on-one multiplayer game, we provided a facility called the Peer Picker to make finding and connecting to peers even easier. So what is the Peer Picker? Simply it's a standard Apple user interface that you can show to your users to have them connect two peers together into the Game Kit session that you can then use to start your multiplayer game.

So how does this fit in to your application? As Joe talked about, your application sits on top and can call the Game Kit session to do this discovery connection and sending data back and forth. Now if you have a one-on-one multiplayer application, you can use the Peer Picker to sit in between your application and the Game Kit session and it will handle everything you need to do for connect-- finding and connecting to another peer.

So that's what the Peer Picker does for you, what does it do for your users? Well first and importantly it provides a list of nearby iPhones and iPod touches that your user can connect to in order to play a game. If your user wants to select somebody in the list it will send an invitation to that other iPhone. The other iPhone will receive an invitation where they can choose to accept or decline the invitation. And if they accept the Peer Picker manages the connection of those two peers into a Game Kit session.

Additionally, the Peer Picker provides your users with a way to turn on Bluetooth from within your application so they don't have to go outside of your application to turn on Bluetooth and come back in, in order to do peer-to-peer gaming. So let's go through a workflow of how this looks and how your application and your users interact with the Peer Picker.

So here we have John's iPhone and John wants to play a game so he taps multiplayer and your application sends messages to Game Kit saying that they want to show the Peer Picker. The Peer Picker asks your session if you have a Game Kit session that you'd like to provide to help do this. Your application provides it and now you have a session that is sending and receiving data. So Jane's iPhone comes along and they discover each other and the session tells the Peer Picker that they have found a peer.

So the Peer Picker shows who is available on the list and now let's say that John's iPhone or John wants to play a game with Jane so he taps Jane in the list, automatically sends an invitation to Jane's iPhone and Jane receives this invitation. Now Jane also wants to play with John so she accepts this invitation. Again, automatically this notifies John's iPhone that she has accepted.

The sessions become connected and the Peer Picker tells your application that it is connected to another peer. Now that your application is done with the Peer Picker, it dismisses it and it now has a fully configured and connected Game Kit session that you can use to start your multiplayer game. So how do we get this into your application? There's three main steps.

First you need to show the Peer Picker to your users. You then need to be able to respond to Peer Picker events such as when a peer is connected. And when a peer is connected you need to take over responsibility for the Game Kit session in order to start your multiplayer game.

Let's go into this first part showing the Peer Picker. It's pretty simple. First you need to initialize a Peer Picker by calling the GKPeerPickerController object and allocating it. You then need to set the picker's delegate. And then lastly you need to show the picker by calling the show method and this is all you need in order to display the Peer Picker to your users and have it automatically start finding nearby peers over Bluetooth.

And we also realized that some of you may be developing games that you want to provide your users with an option to either do nearby peer-to-peer connections over Bluetooth or you may have a remote internet service that you provide for internet connections. Well if your app supports this, you can tell the Peer Picker this and we'll provide an additional UI to the user when it initially comes up that allows them to select whether they want to do a nearby connection or they want to connect to your remote internet service.

So how do you tell the Peer Picker this? It's really simple, same basic steps as we saw before except for before we call the show method we set the connection types-- the connectionTypesMask property to both nearby and online connection types. And this is all you need to show that UI for your users to select.

So now you have shown your users the Peer Picker, how do you interact with it? Oh sorry, there is one important note to this. The Peer Picker only handles configuring network connections over nearby Bluetooth connections so if your application supports remote internet service, you will need to provide a UI and a way for your users to configure your remote internet connections. So how do you interact with it, you do it through the delegate and the delegate has a few responsibilities.

First, it needs to respond to some user actions, then it also needs to provide a way to tell the Peer Picker who to look for and it does that by providing a GKSession object. And then lastly and importantly it needs to respond when peers have been connected so you can start your game. And it does this through the GKPeerPickerControllerDelegate.

So a first interaction to deal with is a user cancelled. This happens when the user taps on the Cancel button and you can respond to this by implementing the -peerPickerController:didCancelDelegate method. And basically this is your opportunity to clean up any state, deal with any memory management and show any new UI or enable any new UI. So what might this look like in code, here is a quick example.

Here we are releasing the Peer Picker since we're done with it and in this example we have a reference to a Game Kit session so we're cleaning that up because we're not going to use it since the user cancelled. And then we go and display our main menu UI if we need to and that's it.

The Peer Picker automatically dismisses when the user cancels it so there is no need to programmatically dismiss it here. So your implementation will probably look somewhat similar to this. Another user interaction that you'll need to deal with is if the user taps on a connection type in that connection panel. Again, this is only shown if you told the Peer Picker that you support multiple connection types and if you do you'll need to respond to this. And you do that through the -peerPickerController:didSelectConnectionTypeDelegate method.

Now as I mentioned, the Peer Picker only supports a way to configure nearby connections over Bluetooth.

So if you have a-- if you support multiple connection types and the user taps the online button, you'll need to programmatically dismiss the Peer Picker, and how do you do this.

Quite simply, you just check if the selected type is the online type and if so, you programmatically dismiss the Peer Picker by calling the dismiss method. You release the Peer Pickers as you're done with it because you're going to dismiss it and then show your own UI for configuring remote internet connections. So another thing you may want to do is tell the Peer Picker who to look for and you do this by providing a Game Kit session.

And you provide it through the peerPickerController session for ConnectionTypeDelegate method. And this is, excuse me, the reason why you may want to do this is as Joe mentioned, when you create a Game Kit session you can provide a session ID and a display name. Joe mentioned that you may register your-- a Bonjour service type and use that as a session ID.

And you may also want to provide a custom display name such as a gamer handle. And it's this display name that we show in the list to other peers and that's how other peers will see you in the Peer Picker. So if you're just trying to get things up and running or you don't really care about those two aspects, if you decide not to implement this delegate method, the Peer Picker will automatically create a default Game Kit session for you to use to find peers and connect them. So what does this look like in code? There's a few ways you can do this.

The real simple way is allocating a GKSession object, setting your custom session ID, setting your display name and then we also, you can see here, set the session mode to the peer mode and that's required for any session you provide the Peer Picker. And we provide the Peer Picker by returning it and we auto release it just so we don't leak. So lastly, importantly, you'll need to be able to respond to when the Peer Picker has connected to another peer. And you can do this by implementing the peerPickerController:didConnectPeer:toSession delegate method.

And there's a couple of things you need to do here. One is, if you haven't it already, you'll need to retain a reference to the Game Kit session and that's basically so you can use it later to send data back and forth in your multiplayer game. The other thing is that the Peer Picker does not automatically dismiss when a peer is connected so you'll need to programmatically dismiss it and you want to do it within this delegate method.

So what will this look like? Here we are setting the session to a property that retains it. And then down below we programmatically dismiss by calling the dismiss method and then we release the Peer Picker as we're done with it and then basically you start your multiplayer game. Now there's one more aspect I want to talk about which is the relationship between the Peer Picker and the Game Kit session.

Now the Peer Picker is there and it makes it really easy to provide a user interface that finds and connects to other devices. So, but to do this you want to wait to respond to any Session events until after the Peer Picker has told you that it is connected to another peer. So this is a snippet from the previous slide and focusing in on here is that after we retain a reference to the Game Kit session, we then set ourselves as the delegate and set the data receive handler so we can start responding to Session events.

So with that I invite you all to start playing around with Game Kit, the Game Kit Peer Picker and the Game Kit session. And to help you do this we are providing some sample code called GKTank and this is a simple two-player game that uses the Peer Picker for peer discovery and connection and uses the Game Kit session to drive that multiplayer game, and this is available on the attendee site for download. And with that I'd like to invite Roberto up on stage to talk to you how you can take your game to the next level by adding voice chat.

Hi my name is Roberto and I had the pleasure of working on the GKVoiceChatService. Today we're going to tell you how you can add voice chat to your application. Now some of you maybe thinking why add voice chat, and the answer is simple. It's fun. Your customers are going to love it and we've made it easy for you to add this to your application. So if you attended Allan's talk yesterday you got a short preview, and if you haven't and you've never seen this API before, today you're going to learn enough to go back and get started.

And if you already have an application and you want to know, well, is the voice chat service compatible with my existing code or my existing server infrastructure, after today's session you'll be able to make an informed decision. And lastly, if you're anything like me and you need to see a concrete example, we're presenting a working implementation of the voice chat service built right on top of an existing piece of Bonjour sample code called WiTap voice.

So let's dive right in. What exactly does your application get when it uses the voice chat service? Well, you heard Joe mention this earlier but I'll reiterate. We're going to do all of the audio processing for you. We're going to pull from the mic, we're going to encode, we're going to decode, and we're even going to do echo suppression thanks to the voice processing audio unit.

If you're not a real-time network engineer you can breathe a sigh of relief. We're going to do the packetization, we're going to do NAT traversal and we're even going to send and receive audio on our own socket. So, you've heard a lot about what your application doesn't need to do and you're probably thinking well what do I need to do.

Your application needs to do two things. The first thing is called the VoiceChatService methods. The second thing is implement the GKVoiceChatClient protocol. The VoiceChatClient protocol does two things. The first thing is that it acts as a delegate to the voice chat service. And the second thing, this is really the important thing that it does and the thing that you'll need to pay attention to, is that it provides a mechanism for the voice chat service to exchange a few control packets so that we can do our NAT traversal and set up our own peer-to-peer connection.

So how does your application use the voice chat service? Well if you want to send a voice chat invitation all you have to do is call startVoiceChatWithParticipantID. Don't get hang up on what a participant ID is yet. We're going to cover that in great detail later. When your application receives a voice chat invitation you should call acceptCallID or denyCallID. Don't worry about what a call ID is, that's going to be passed to you when you receive the invitation and it's just an NSInteger.

And lastly, you can tear down the call at any point by calling stopVoiceChatWithParticipantID. So these methods were all designed with the metaphor that should seem very familiar to you and that is placing a phone call on your iPhone. When you dial a number this is like calling startVoiceChatWithParticipantID. When you receive a call you can either accept or decline it and this is like calling acceptCallID or declineCallID. And lastly either party can press the End Call button at any point. Likewise in the voice chat service API you can call stopVoiceChatWithParticipantID.

So how exactly is a voice chat set up, let's look at that. Earlier you heard me mention that your application is going to provide a mechanism to exchange a few control packets. What does that look like? Well when your application call startVoiceChat, the voice chat service is going to create what we'll call an invite packet.

From your applications perspective this is really just an opaque data blob. The voice chat service is going to pass the voice chat invite up to the application.

The application is going to forward it across your application's existing infrastructure and the remote instance of your application is going to pass it down to the remote instance of the voice chat service.

Should you accept the call or should your user accept the call The voice chat service is going to create an appropriate reply and repeat the process in reverse. So this is what I mean by exchange packets. So now that these packets have been exchanged, the voice chat service, each instance of it, has enough information to do NAT traversal and set up its own peer-to-peer audio connection using its own socket.

[ Pause ]

So the key takeaway is that your application will be providing a mechanism or a channel that the voice chat service can use to exchange these control packets and you'll provide this channel by implementing the VoiceChatClient protocol. So it has two methods, two required methods.

The first is named participantID and it returns an NSString. For now you can think of this as how other instances of your application will address the local instance of your application. The next method is voiceChatService:sendData:toParticipantID. This is the method that the voice chat service is going to call when it wants to send one of these control packets. And lastly although this isn't part of the protocol, it's implied that when you receive a voice chat service packet you'll pass it down to the voice chat service later and you'll do that by calling the receivedData:fromParticipantID of voice chat service method.

So let's address each one of these respectively. ParticipantID, this is a string that only has meaning to your application, the voice chat service doesn't know anything about this and it's going to depend greatly on the service that your application uses to communicate. For instance, hypothetically, if you are running a name client you would return the screen name for your participantID because this is how the other name clients would address you when they wanted to send you a message.

If you were going to run the GKSession you would return your peer ID because that's how other remote GKSessions refer to your local GKSessions. For the next few slides I'm going to present an example and that is my name is Bob and I'm running a client or an application on the iPhone on the new fooim.org instant messenger service. Well what participantID would I return? It would be [email protected] and that's because that's how the other fooim.org clients would address me when they sent Bob a message.

So voiceChatService:sendData:toParticipantID. This is the method that the voice chat service is going to call when it wants to send one of these control packets. If you were to take a peek inside of the voice chat service implementation, the codes that you see above would be representative of a call to this method. The first parameter pass would be self since the voice chat service is calling this method.

The second parameter would be this opaque data blob, and the last parameter would be the destination participantID or where the blob is going. In this case Bob is trying to start a voice chat with Alice so the voice chat service is sending Alice a voice chat invitation. So that's what a call to this method looks like.

What will your implementation look like? Your implementation will wrap the voice chat service packet in such a way that they can be distinguished from native application packets. By that I mean you should encapsulate the voice chat service packet inside one of your native application packets and give it a type identifier, so that when it's received by the remote instance of your application it can be distinguished, it can be distinguished and unpacked and passed back down to the voice chat service layer. And your application will do that by calling the receivedData:fromParticipantID method. So an example call of how your client will call that method, you can see that above, the first parameter will be this opaque data blob, and the second parameter would be where you got the blob from.

Now this is up to your application so you know where you got the message from and all you're doing is you're telling the voice chat service later. In this case Alice's fooim.org client knows that she received the message from Bob. So you've seen all of the relevant methods in the voice chat service and the voice chat client. And I gave you a sort of a high level graph of what the voice chat setup looks like. Now let's go fill in some of those gaps and see a more detailed explanation.

So Bob is going to want to start a voice chat with Alice. So he calls startVoiceChatWithParticipantID. The voice chat service will then create an invite packet. It will pass the invite packet up to the voice chat client by calling sendData:toParticipantID where the participantID in this case is [email protected].

The voice chat client will then wrap the packet so that it looks like a native application packet and forward it across the fooim.org server. When Alice's application receives the packet it will distinguish it first of all as a voice chat packet and pass it back down to voice chat service later. Remember, this is completely opaque to your application so you don't need to worry about what the packet contains. So the voice chat service knows that it's an invitation so it will tell Alice's client.

Alice, yeah she is kind of fond of Bob so she decides to accept the call. The voice chat service then will create an appropriate reply and the process will be repeated in reverse. Now, both instances of the voice chat service have enough information to do NAT traversal and set up a peer-to-peer audio channel. So this isn't a metaphorical dotted line.

The voice chat service packets will be running over on socket and both applications will be informed that they started a voice chat. So you've seen all the methods for both the voice chat client and the voice chat service, and now you've seen a detailed call flow setup Let's put it into practice. We'll do that by showing you the WiTap example. WiTap is the simplest game that Apple ships and it's built right on top of Bonjour and we're going to add voice chat today.

So what is WiTap, how does that work? It starts off by showing you a table where each entry of the table is an instance of the WiTap application being advertised over Bonjour. When a user clicks on an entry in the table a TCP connection is created between the instances of the application and the game is started.

When one user clicks on the square the square is highlighted and the same square is highlighted on the reverse side. So now we're going to dive into how you add voice chat. So the first thing you do is you want to initialize the voice chat client or voice chat service. You do that by first calling defaultVoiceChatService.

So this is a singleton. You're going to get the one instance of the voice chat service. Once you have that you can set the client. In this case it's going to be self because the voice chat client is implemented-- voice chat client protocol is going to be implemented by the app controller.

And lastly, and this is really important, we're not going to show it today but you'll set up an audio session and this is so that the voice chat service audio will integrate well with the audio session audio or with your in-game audio. The sample code will have this so when you leave the session and you want to use this, go back and look at it. So to add voice chat to your application you need to implement the voice chat client protocol, and remember there are two methods.

The first is participantID. In this case since we're running on top of Bonjour, we're going to return the local service instance name, because this is how the other services, the other applications can resolve the local instance of my application or the local service.

For the send data method we're going to just go ahead and call a convenience method called voiceChatSend. Now you'll see that we're performing the selector on main thread and the reason for that is we don't want to end or leave rights to the TCP string.

This will provide some thread safety because the other right is also happening on the main thread. So before we dive into how voiceChatSend is implemented now let's go back and look at how it currently is implemented in the original WiTap source code. So this is-- the code you'll see today will be a slight simplification just for brevity's sake and to fit everything on one slide.

But you'll see there's a variable name outStream and this is an NSoutputStream which is an abstruction over the TCP string. And all you do when you want to send which square is being highlighted as you send one by-- and that tells the remote instance everything it needs to know to highlight or unhighlight a square. Well earlier I mentioned that you'll need to wrap the voice chat service packets. What that also means is that if you don't wrap your packets currently you'll need to do so.

So we've added a WiTap message header, a very simple network header. All it does is it contains a length and this is the length of the message not including the header and the type. In this case we're sending a WiTap packet type so we're letting the other instance of the WiTap application know we're sending it a screen update.

We then write the message header and write the byte. So voice chats then will look very similar to this, the difference being instead of a WiTap packet type we're going to send a voice packet type. And instead of sending the 1 byte we're going to send the data blob.

So that's sent. So now we have implemented the two required methods, participantID and sendData. So the last implied method, so this isn't in the protocol, this isn't the voice chat client protocol, it's a voice chat service method, it's that you need to be able to pass to receive voice chat service packets down to the voice chat service later.

So let's look at the current implementation of WiTap. All it does is that when it receives the stream delegate event it's going to use the inStream which is an abstraction over the input side of the TCP stream and it's an NSinputStream to read the 1 byte. But now you're receiving more than 1 byte, you're receiving a header and whatever the message is.

So the first thing we'll do is we'll read the WiTap message header. After we've done that and of course you can see I put it back in the host by order so this is also good network practice, I can receive the rest of the message, so if it's a WiTap-- so we'll check the Witap message header type and if it's a voice packet type we'll create an instance of an NSData and pass it out down to the voice chat service later by calling receiveData:fromParticipantID and the participantID is going to be the remoteInstanceName because that's how our local instance resolves the remote instance.

All right, so that was the meat of it, this is very simple. So just to handle the initial calls that your API will make, so to start a voice chat, if you haven't already started the voice chat, call it and this will happen whenever the TCP stream opens so that way you have a way of sending the data blobs. So the first-- so it's just voice chat service startVoiceChatWithParticipantID where the participantID of the person that you want to talk to or the application you want to talk to is remoteInstanceName once again.

And of course if the voice chat succeeds, what you want to do is update your UI and this will depend on your application. And if it doesn't you should look at the error and this will be very helpful when you're trying to get this set up and debugged. And accepting the chat, all you have to do is implement the optional method so you don't have to implement this.

It would be a good idea if you want to know if you have a voice chat invitation though. And that is the voiceChatService didReceiveInvitationFromParticipantID. So normally you probably want to-- well depending again, once again on your application. You want to inform the user, hey, you got a voice chat and they can decide if they want to accept or decline it. Now depending on your game, you might not want to do that.

In any case you want to call if you want to accept the chat VoiceChatService acceptCallID and you notice that the callID that I used is the one pass sensitive method. And if the voice chat fails, once again, you need to inspect the error or if it succeeds, update your UI.

So what's missing from this code? So a very important piece is working with the AudioSession to handle interrupts because when you receive a phone call and your user comes back to it, to your application, you want to handle that as smoothly as possible. So in the sample code that you'll get with the WiTap voice sample app will show you how to do that. The other thing you want to do is you want to ensure that the resources that you're playing in your game are going to integrate well with the voice chat data or the voice chat audio.

We'll also show you how to do that. And lastly the code I showed you for the receive bit of this was a tad simplified again for brevity's sake, the spirit is there, but we'll show you how to be a good non-blocking citizen so you don't want to hang up your main thread, you want to be able to receive each asynchronous call in turn. And so again, once again the sample code will have all of this.

And lastly the recap, so the big thing you need to know is that once you implement the voice chat client protocol which once again provides a mechanism just to exchange these packets, we're going to do everything else for you and it's going to be a lot of fun. Go ahead and implement it. And with that I'll hand it to Joe.

Thank you Roberto. So I hope that you've learn from us the capabilities of Game Kit and how you may use Game Kit in the application that you write or any existing application that you already have. When I spoke I talked to you about the GKSession and the key point there that I want to point out is that there is essentially only three stages that you need to follow to use GKSession in your application.

Now note that GKSession doesn't have any UI to help you with this, however, from Jonathan you learned about the Peer Picker and it's really easy to get things connected with the Peer Picker. You initialize it then you basically show it and then as long as you're handling the correct delegate methods, everything will be taken care for you.

And then most recently you just heard from Roberto about the voice chat service and how it itself should be very easy for you to implement. Now to review, there are some sample code available for you. There is the GKTank sample that illustrates how to use the Peer Picker and Session and then there is the WiTap voice sample which shows a modified version of the WiTap sample but now with voice chat. Now if you want any other additional information please contact our Evangelist Allan Schaffer. His email is here on the slide.