iPhone蓝牙编程之实现语音聊天

       感谢原创人。致敬!!

IT168技术】在我之前的iPhone文章中,我们已经介绍过使用GameKit框架在两个设备之间通过蓝牙通信,在这篇文章中,我将为大家介绍GameKit框架另一个很酷的功能 — 语音聊天。

  Gamekit中的语音聊天服务允许两台iPhone/iPod Touch之间建立语音聊天,语音聊天要么通过互联网,要么通过蓝牙实现,你将在本文中看到如何通过蓝牙通信信道实现语音聊天。

  创建项目

  首先使用Xcode创建一个新的基于视图的iPhone应用程序,取名为Bluetooth,在Xcode的框架组上点击右键,选择“增加”,从现有框架中选择一个增加到项目上,这里选择GameKit.framework,同时再增加一个AVFoundation框架。

  在BluetoothViewController.h文件中,增加下面的代码:

1 #import & lt;UIKit / UIKit.h & gt;
2 #import & lt;GameKit / GameKit.h & gt;
3 #import & lt;AVFoundation / AVFoundation.h & gt;
4 @interface BluetoothViewController : UIViewController
5 & nbsp; & nbsp; & nbsp; & lt;GKVoiceChatClient & gt; {
6
7 & nbsp; & nbsp; & nbsp;GKSession * currentSession;
8 & nbsp; & nbsp; & nbsp;
9 & nbsp; & nbsp; & nbsp;IBOutlet UIButton * connect;
10 & nbsp; & nbsp; & nbsp;IBOutlet UIButton * disconnect;
11 }
12 @ property (nonatomic, retain) GKSession * currentSession;
13 @ property (nonatomic, retain) UIButton * connect;
14 @ property (nonatomic, retain) UIButton * disconnect;
15
16 - (IBAction) btnMute:(id) sender;
17 - (IBAction) btnUnmute:(id) sender;
18 - (IBAction) btnConnect:(id) sender;
19 - (IBAction) btnDisconnect:(id) sender;
20 @ end
21

  拖动一个wav文件(如无特殊说明,指beep.wav)到Xcode的Resources文件夹上。

  双击BluetoothViewController.xib文件在Interface Builder编辑它,使用三个圆形按钮填充到视图窗口中,如图1所示。

  图 1 使用三个圆形按钮填充视图窗口

  在BluetoothViewController.xib窗口中,执行以下连接:

  按住CTRL键,点击文件所有者项目,将其拖放到Connect按钮上,选择连接;

  按住CTRL键,点击文件所有者项目,将其拖放到Disconnect按钮上,选择断开连接;

  按住CTRL键,点击Connect按钮,将其拖放到文件所有者项目上,选择btnConnect;

  按住CTRL键,点击Disconnect按钮,将其拖放到文件所有者项目上,选择btnDisconnect;

  在Mute按钮上点击右键,将Touch Down事件连接到文件所有者项目上,选择btnMute;

  在Mute按钮上点击右键,将Touch Up Inside事件连接到文件所有者项目上,选择btnUnmute;

  为了验证所有连接是否正确,在文件所有者项目上点击右键,查看其连接,如图2所示。

  图 2 验证出口和行为的连接

  在BluetoothViewController.m文件中,增加下面的代码:

  1 #import " BluetoothViewController.h "
  2 #import < GameKit / GameKit.h >
  3 #import < AVFoundation / AVFoundation.h >
  4
  5 @implementation BluetoothViewController
  6 @synthesize currentSession;
  7 @synthesize connect;
  8 @synthesize disconnect;
  9
10 GKPeerPickerController * picker;
11 NSString * recorderFilePath;
12
13 AVAudioPlayer * audioPlayer;
14
15 - (void)viewDidLoad {
16
17     [connect setHidden:NO];
18     [disconnect setHidden:YES];
19
20     [super viewDidLoad];
21 }
22
23 - (IBAction) btnConnect:(id) sender {
24
25      //--- 选择一个附近的蓝牙设备 ---
26     picker = [[GKPeerPickerController alloc] init];
27     picker.delegate = self;
28     picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;  
29     
30     [connect setHidden:YES];
31     [disconnect setHidden:NO];
32     
33     [picker show];    
34
35 }
36
37 - (IBAction) btnDisconnect:(id) sender {
38
39      //--- 从其它设备断开连接 ---
40     [self.currentSession disconnectFromAllPeers];
41     [self.currentSession release];
42     currentSession = nil;
43     
44     [connect setHidden:NO];
45     [disconnect setHidden:YES];
46
47 }
48
49 - (void)peerPickerController:(GKPeerPickerController * )picker
50               didConnectPeer:(NSString * )peerID
51                    toSession: (GKSession * ) session {
52
53     self.currentSession = session;
54     session.delegate = self;
55     [session setDataReceiveHandler: self withContext:nil];
56     picker.delegate = nil;
57     [picker dismiss];
58     [picker autorelease];    
59
60 }
61     
62 - (void)peerPickerControllerDidCancel:(GKPeerPickerController * )picker {
63
64     picker.delegate = nil;
65     [picker autorelease];
66     
67     [connect setHidden:NO];
68     [disconnect setHidden:YES];
69
70 }
71
72 - (IBAction) btnMute:(id) sender {
73
74      //--- 静音语音聊天 ---
75     [GKVoiceChatService defaultVoiceChatService].microphoneMuted = YES;    
76
77 }
78
79 - (IBAction) btnUnmute:(id) sender {
80
81      //--- 取消静音 ---
82     [GKVoiceChatService defaultVoiceChatService].microphoneMuted = NO;
83
84 }
85
86 //--- 返回一个表示本地用户的唯一ID ---
87 - (NSString * ) participantID
88 {
89     return currentSession.peerID;
90 }
91
92 - (void) voiceChatService:(GKVoiceChatService * ) voiceChatService
93                 sendData:(NSData * ) data
94          toParticipantID:(NSString * )participantID {
95
96     [currentSession sendData:data toPeers:
97         [NSArray arrayWithObject:participantID]
98         withDataMode:GKSendDataReliable error :nil];
99
100 }
101
102 - (void)session:(GKSession * )session
103            peer:(NSString * )peerID
104 didChangeState:(GKPeerConnectionState)state {
105
106     switch (state)
107     {
108          case GKPeerStateConnected:
109         {            
110              //--- 播放一个音频文件 ---
111             NSString * soundFilePath = [[NSBundle mainBundle]
112                 pathForResource:@ " beep " ofType:@ " wav " ];
113
114             NSURL * fileURL = [[NSURL alloc]
115                 initFileURLWithPath: soundFilePath];
116
117             AVAudioPlayer * audioPlayer =
118                 [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
119                      error :nil];
120
121             [fileURL release];
122             [audioPlayer play];            
123             
124             NSError * error ;
125             AVAudioSession * audioSession =
126                 [AVAudioSession sharedInstance];
127
128              if (![audioSession  
129                 setCategory:AVAudioSessionCategoryPlayAndRecord
130                  error : & error ]) {
131                 NSLog(@ " Error setting the AVAudioSessionCategoryPlayAndRecord category: %@ " ,
132                 [ error localizedDescription]);
133             }
134             
135              if (![audioSession setActive: YES error : & error ]) {
136                 NSLog(@ " Error activating audioSession: %@ " ,
137                     [ error description]);
138             }
139             
140             [GKVoiceChatService defaultVoiceChatService].client = self;
141             
142              //--- 初始化语音聊天 ---
143              if (![[GKVoiceChatService defaultVoiceChatService]
144                  startVoiceChatWithParticipantID:peerID error : & error ]) {
145                 NSLog(@ " Error starting startVoiceChatWithParticipantID: %@ " ,
146                     [ error userInfo]);
147             }
148         } break;
149             
150          case GKPeerStateDisconnected:
151         {
152             [[GKVoiceChatService defaultVoiceChatService]
153                 stopVoiceChatWithParticipantID:peerID];
154             
155             [self.currentSession release];
156             currentSession = nil;        
157             
158             [connect setHidden:NO];
159             [disconnect setHidden:YES];
160         
161         } break;
162     }
163 }
164
165 - (void) receiveData:(NSData * )data
166             fromPeer:(NSString * )peer
167            inSession:(GKSession * )session
168              context:(void * )context {
169
170      //--- 初始化完成后开始语音聊天 ---
171     [[GKVoiceChatService defaultVoiceChatService]
172         receivedData:data fromParticipantID:peer];
173
174 }
175
176 - (void)dealloc {
177
178      if (currentSession) [currentSession release];
179     [connect release];
180     [disconnect release];
181
182     [super dealloc];
183 }
184 @ end
185

  理解语音聊天是如何工作的

  当两个蓝牙设备连接时,首先播放beep.wav文件发出嘟嘟声,然后启动语音会话(通过session:peer:didChangeState:方法实现)。

1 NSString * soundFilePath = [[NSBundle mainBundle]
2                 pathForResource:@ " beep " ofType:@ " wav " ];
3
4             NSURL * fileURL = [[NSURL alloc]
5                 initFileURLWithPath: soundFilePath];
6
7             AVAudioPlayer * audioPlayer =
8                 [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
9                      error :nil];
10
11             [fileURL release];
12             [audioPlayer play];            
13             
14             NSError * error ;
15             AVAudioSession * audioSession =
16                 [AVAudioSession sharedInstance];
17
18              if (![audioSession  
19                 setCategory:AVAudioSessionCategoryPlayAndRecord
20                  error : & error ]) {
21                 NSLog(@ " Error setting the AVAudioSessionCategoryPlayAndRecord category: %@ " ,
22                 [ error localizedDescription]);
23             }
24             
25              if (![audioSession setActive: YES error : & error ]) {
26                 NSLog(@ " Error activating audioSession: %@ " ,
27                     [ error description]);
28             }
29             
30             [GKVoiceChatService defaultVoiceChatService].client = self;
31

  提示:有趣的是,如果你不启动音频播放器,语音聊天不能正常工作。

  然后检索GKVoiceChatService类的单一实例,调用它的startVoiceChatWithParticipantID:error:方法启动语音聊天。

1 if (![[GKVoiceChatService defaultVoiceChatService]
2                  startVoiceChatWithParticipantID:peerID error : & error ]) {
3                 NSLog(@ " Error starting startVoiceChatWithParticipantID: %@ " ,
4                     [ error userInfo]);
5             }
6

  调用startVoiceChatWithParticipantID:error:方法将会请求voiceChatService:sendData:toParticipantID:方法,它将会使用当前的蓝牙会话发送配置数据到其它设备。

1 - (void) voiceChatService:(GKVoiceChatService * ) voiceChatService
2                 sendData:(NSData * ) data
3          toParticipantID:(NSString * )participantID {
4
5     [currentSession sendData:data toPeers:
6         [NSArray arrayWithObject:participantID]
7         withDataMode:GKSendDataReliable error :nil];
8
9 }
10

  其它连接的设备接收到发来的配置数据后,通过调用receivedData:fromParticipantID:方法启动语音聊天服务。

  GKVoiceChatService使用两个设备之间交互的配置信息创建它自己的连接传输语音数据,还可以将microphoneMuted属性的值设为YES使麦克风静音。

1 [GKVoiceChatService defaultVoiceChatService].microphoneMuted = YES;

  测试应用程序

  在开始测试之前,先要把应用程序两台iPhone或iPod Touch上,对于iPod Touch,你需要使用一个外置麦克风,因为它默认是不带有麦克风的,一个好选择是Griffin iTalk Pro,如图3所示,它是iPod Touch麦克风及其零配件插入的基座,另外也支持苹果头戴式耳机及其配件。

  应用程序部署到设备上后,启动应用程序,按下Connect按钮使用蓝牙相互连接,当两个设备连接好后,就可以开始聊天了,如果要临时静音,按下Mute按钮一直不放即可,放开Mute按钮后,声音就又恢复了。

  在这篇文章中,你看到了如何使用Gamekit框架提供的GKVoiceChatService类在两个设备之间无缝地建立语音通信,关于两个设备之间的语音是如何传输的暂时没有必要知道,所有需要了解的就是要知道调用什么方法初始化语音聊天,另外你还要知道,语音聊天不仅可以通过蓝牙通信信道实现,在其它任何通信信道上都可以实现,实际上,如果使用TCP/IP连接两台设备,也可以实现语音聊天,在今后的文章中,我将会涉及。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值