IMPLEMENTING VOICE CHATTING

Another cool feature of the Game Kit framework is its support for voice chat.

The Voice Chat service in the Game Kit enables two devices to establish a voice chat. The voice chat takes place over either an Internet connection or a Bluetooth connection. This section shows you how to implement voice chatting over a Bluetooth communication channel.

TRY IT OUT: Enabling Bluetooth Voice Chatting

image

  1. Using Xcode, create a new Single View Application (iPhone) project and name it BluetoothChat. You need to use the project name as the Class Prefix and ensure that you have the Use Automatic Reference Counting option unchecked.
  2. Add the GameKit and AVFoundation frameworks to the Frameworks folder of the project (see Figure 17-8).
  3. Drag and drop a WAV file (see Figure 17-9) onto the Resources folder in Xcode.

    image

    FIGURE 17-8

    image

    FIGURE 17-9

  4. Select the BluetoothViewController.xib file to edit it in Interface Builder.
  5. Populate the View window with three Round Rect Button views (see Figure 17-10). Label them MUTE, Disconnect, and Connect.
  6. Add the following bold statements to the BluetoothChatViewController.h file:
    #import <UIKit/UIKit.h>
    #import <GameKit/GameKit.h>
    #import <AVFoundation/AVFoundation.h>
    
    @interface BluetoothChatViewController : UIViewController
        <GKVoiceChatClient,
        GKPeerPickerControllerDelegate,
        GKSessionDelegate>
    {
        GKSession *currentSession;
        IBOutlet UIButton *connect;
        IBOutlet UIButton *disconnect;
        GKPeerPickerController *picker;
    }
    
    @property (nonatomic, retain) GKSession *currentSession;
    @property (nonatomic, retain) UIButton *connect;
    @property (nonatomic, retain) UIButton *disconnect;
    -(IBAction)btnMute:(id) sender;
    -(IBAction)btnUnmute:(id) sender;
    -(IBAction)btnConnect:(id) sender;
    -(IBAction)btnDisconnect:(id) sender;
    
    @end

    image

    FIGURE 17-10

  7. In the BluetoothViewController.xib window, perform the following connections:
    • Control-click the File's Owner item and drag and drop it over the Connect button. Select connect.
    • Control-click the File's Owner item and drag and drop it over the Disconnect button. Select disconnect.
    • Control-click the Connect button and drag and drop it over the File's Owner item. Select btnConnect:.
    • Control-click the Disconnect button and drag and drop it over the File's Owner item. Select btnDisconnect:.
    • Right-click the Mute button and connect the Touch Down event to the File's Owner item. Select btnMute:.
    • Right-click the MUTE button and connect the Touch Up Inside event to the File's Owner item. Select btnUnmute:.
  8. To verify that all the connections are made correctly, right-click the File's Owner item and view its connections (see Figure 17-11).

    image

    FIGURE 17-11

  9. Add the following bold statements to the BluetoothViewController.m file:
    #import “BluetoothChatViewController.h”
    
    @implementation BluetoothChatViewController
    
    
    @synthesize currentSession;
    @synthesize connect;
    @synthesize disconnect;
    
    NSString *recorderFilePath;
    AVAudioPlayer *audioPlayer;
    
    - (void)viewDidLoad
    {
        [connect setHidden:NO];
        [disconnect setHidden:YES];
        [super viewDidLoad];
    }
    
    - (GKSession *)peerPickerController:(GKPeerPickerController *)picker
              sessionForConnectionType:(GKPeerPickerConnectionType)type {
        if (!self.currentSession) {
            self.currentSession =
            [[[GKSession alloc] initWithSessionID:@“Session_ID_Here”
                                           displayName:nil
                                           sessionMode:GKSessionModePeer] autorelease];
           self.currentSession.delegate = self;
        }
        return self.currentSession;
    }
    
    //---select a nearby Bluetooth device---
    -(IBAction) btnConnect:(id) sender {
        picker = [[GKPeerPickerController alloc] init];
        picker.delegate = self;
        picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
        [connect setHidden:YES];
        [disconnect setHidden:NO];
        [picker show];
    }
    
    //---disconnect from the other device---
    -(IBAction) btnDisconnect:(id) sender {
        [self.currentSession disconnectFromAllPeers];
        currentSession = nil;
        [connect setHidden:NO];
        [disconnect setHidden:YES];
    }
    
    //---did connect to a peer---
    -(void) peerPickerController:(GKPeerPickerController *)pk
                    didConnectPeer:(NSString *)peerID
                          toSession:(GKSession *) session {
        self.currentSession = session;
        session.delegate = self;
        [session setDataReceiveHandler:self withContext:nil];
        picker.delegate = nil;
        [picker dismiss];
        [picker autorelease];
    }
    
    //---connection was cancelled---
    -(void) peerPickerControllerDidCancel:(GKPeerPickerController *)pk {
        picker.delegate = nil;
        [picker autorelease];
        [connect setHidden:NO];
        [disconnect setHidden:YES];
    }
    
    //---mute the voice chat---
    -(IBAction) btnMute:(id) sender {
        [GKVoiceChatService defaultVoiceChatService].microphoneMuted = YES;
    }
    
    //---unmute the voice chat---
    -(IBAction) btnUnmute:(id) sender {
        [GKVoiceChatService defaultVoiceChatService].microphoneMuted = NO;
    }
    
    //---returns a unique ID that identifies the local user---
    -(NSString *) participantID {
        return currentSession.peerID;
    
    }
    
    //---sends voice chat configuration data to the other party---
    -(void) voiceChatService:(GKVoiceChatService *) voiceChatService
    sendData:(NSData *) data
                  toParticipantID:(NSString *) participantID {
         [currentSession sendData:data
                          toPeers:[NSArray arrayWithObject:participantID]
                     withDataMode:GKSendDataReliable error:nil];
    }
    
    //---session state changed---
    -(void) session:(GKSession *)session
               peer:(NSString *)peerID
     didChangeState:(GKPeerConnectionState)state {
         switch (state) {
             case GKPeerStateAvailable:
                 NSLog(@“State Available”);
                 break;
             case GKPeerStateConnecting:
                 NSLog(@“State Connecting”);
                 break;
             case GKPeerStateUnavailable:
                 NSLog(@“State Unavailable”);
                 break;
             case GKPeerStateConnected: {
                 //---plays an audio file---
                 NSString *soundFilePath =
                     [[NSBundle mainBundle] pathForResource:@“beep”
                                                     ofType:@“wav”];
                 NSURL *fileURL =
                     [[NSURL alloc] initFileURLWithPath:soundFilePath];
                 AVAudioPlayer *audioPlayer =
                     [[[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
                                                                 error:nil] autorelease];
                 [fileURL release];
                 [audioPlayer play];
    
                 NSError *error;
                 AVAudioSession *audioSession = [AVAudioSession sharedInstance];
                 if (![audioSession
                       setCategory:AVAudioSessionCategoryPlayAndRecord
                       error:&error]) {
                    NSLog(@“Error setting category: %@”,
                        [error localizedDescription]);
                 }
                 if (![audioSession setActive:YES error:&error]) {
                     NSLog(@“Error activating audioSession: %@”,
                         [error description]);
                 }
                 [GKVoiceChatService defaultVoiceChatService].client = self;
    
                 //---initiating the voice chat---
                 if (![[GKVoiceChatService defaultVoiceChatService]
                         startVoiceChatWithParticipantID:peerID error:&error]) {
                     NSLog(@“Error starting startVoiceChatWithParticipantID:%@”,
                         [error userInfo]);
                 )
    } break;
            case GKPeerStateDisconnected: {
                [[GKVoiceChatService defaultVoiceChatService]
                    stopVoiceChatWithParticipantID:peerID];
                currentSession = nil;
                [connect setHidden:NO];
                [disconnect setHidden:YES];
            } break;
        }
    }
    
    //---data received from the other party---
    -(void) receiveData:(NSData *)data
               fromPeer:(NSString *)peer
              inSession:(GKSession *)session
                context:(void *)context {
        //---start the voice chat when initiated by the client---
        [[GKVoiceChatService defaultVoiceChatService]
             receivedData:data fromParticipantID:peer];
    }
    
    //---session failed with error---
    -(void) session:(GKSession *)session
    didFailWithError:(NSError *)error {
        NSLog(@“%@”,[error description]);
    }
    
    - (void)dealloc {
        [currentSession release];
        [connect release];
        [disconnect release];
        [super dealloc];
    }
  10. To test the application, deploy it onto two devices (or the Simulator and a real device). For the iPod touch, you need to connect it to an external microphone, as it does not include one. Then run the application and press the Connect button to use Bluetooth to connect the two devices. As soon as the two devices are connected, you can start chatting! To temporarily mute the conversation, press and hold the MUTE button. When it is released, the conversation resumes. Have fun!

How It Works

When two Bluetooth devices are connected, you first play the beep sound and start the audio session (via the session:peer:didChangeState: method):

//---plays an audio file---
NSString *soundFilePath =
    [[NSBundle mainBundle] pathForResource:@“beep”
                                    ofType:@“wav”];
NSURL *fileURL =
    [[NSURL alloc] initFileURLWithPath:soundFilePath];
AVAudioPlayer *audioPlayer =
[[[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
                                            error:nil] autorelease];
[fileURL release];
[audioPlayer play];

NSError *error;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if (![audioSession
      setCategory:AVAudioSessionCategoryPlayAndRecord
      error:&error]) {
    NSLog(@“Error setting category: %@”,
        [error localizedDescription]);
}
if (![audioSession setActive:YES error:&error]) {
    NSLog(@“Error activating audioSession: %@”,
        [error description]);
}
[GKVoiceChatService defaultVoiceChatService].client = self;

You then retrieve a singleton instance of the GKVoiceChatService class and call its startVoiceChatWithParticipantID:error: method to start the voice chat:

//---initiating the voice chat---
if (![[GKVoiceChatService defaultVoiceChatService]
      startVoiceChatWithParticipantID:peerID error:&error]) {
    NSLog(@“Error starting startVoiceChatWithParticipantID:%@”,
        [error userInfo]);
}

Notice that you needed to implement the participantID method declared in the GKVoiceChatClient protocol:

//---returns a unique ID that identifies the local user---
-(NSString *) participantID {
    return currentSession.peerID;
}

This method should return a string that uniquely identifies the current user. Since you are using Bluetooth, you used the peerID property of the GKSession object.

Calling the startVoiceChatWithParticipantID:error: method invokes the voiceChatService:sendData:toParticipantID: method (defined in the GKVoiceChatClient protocol), which makes use of the current Bluetooth session to send the configuration data to the other connected device:

//---sends voice chat configuration data to the other party---
-(void) voiceChatService:(GKVoiceChatService *) voiceChatService
                sendData:(NSData *) data
         toParticipantID:(NSString *) participantID {
    [currentSession sendData:data
                     toPeers:[NSArray arrayWithObject:participantID]
                withDataMode:GKSendDataReliable error:nil];
}

When it has received the configuration data, the other device starts the Voice Chat service by calling the receivedData:fromParticipantID: method (also defined in the GKVoiceChatClient protocol):

//---data received from the other party---
-(void) receiveData:(NSData *)data
           fromPeer:(NSString *)peer
          inSession:(GKSession *)session
            context:(void *)context {
    //---start the voice chat when initiated by the client---
    [[GKVoiceChatService defaultVoiceChatService]
        receivedData:data fromParticipantID:peer];
}

The GKVoiceChatService uses the configuration information that was exchanged between the two devices and creates its own connection to transfer voice data.

You can mute the microphone by setting the microphoneMuted property to YES:

[GKVoiceChatService defaultVoiceChatService].microphoneMuted = YES;
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.180.252