[objc] view plain copy

  1. <span style="white-space:pre">    </span>语音技术近来可是出遍了风头,从iphone4s的siri,到微信的语音聊天等等,极大地方便了人们的社交生活,也体现了当今移动科技发展的迅猛。当然,作为一位移动开发的从业人员怎能落伍呢!今天我们就来简单的实现一下语音聊天的功能。  

[objc] view plain copy

  1. <span style="white-space:pre">    </span>这次Demo使用的是Speex对录制的声音进行语音压缩,并且进行ogg的封装。由于本人水平有限,尝试了几次对ogg库的编译都不成功,于是终于在Code4App上找到了一个Demo,把它的speex和封装好的ogg拿了过来,如果大家对ios支持的语音格式不太了解

首先上图,聊天界面:

YYText 在iOS17中报错_#import

 

源码如下:

聊天界面头文件:

[objc] view plain copy

1. #import <UIKit/UIKit.h>  
2. #import "RecorderManager.h"  
3. #import "PlayerManager.h"  
4.   
5. @interface MainViewController : UIViewController<UITableViewDataSource, UITableViewDelegate, RecordingDelegate, PlayingDelegate, UIGestureRecognizerDelegate>  
6.   
7. - (IBAction)talk:(id)sender;  
8.   
9. @property (strong, nonatomic) IBOutlet UITableView *vTableView;  
10.   
11. @property (strong, nonatomic) IBOutlet UIButton *speekBtb;  
12.   
13. @property (assign) BOOL isSpeak;  
14.   
15. @property (strong, nonatomic) NSMutableArray *voiceArray;  
16.   
17. @property (strong, nonatomic) NSString *fileName;  
18.   
19. @property (assign) BOOL isPlaying;  
20.   
21. @end  
 
实现:
 
[objc] view plain copy

1. #import "MainViewController.h"  
2.   
3. @interface MainViewController()  
4.   
5. @end  
6.   
7. @implementation MainViewController  
8. @synthesize isSpeak = _isSpeak;  
9. @synthesize voiceArray = _voiceArray;  
10. @synthesize fileName = _fileName;  
11. @synthesize isPlaying = _isPlaying;  
12.   
13. - (id)initWithNibName:(NSString *)nibNameOrNilNSBundle *)nibBundleOrNil  
14. {  
15. self = [super bundle:nibBundleOrNil];  
16. if (self) {  
17. // Custom initialization  
18.     }  
19. return self;  
20. }  
21.   
22. - (void)viewDidLoad  
23. {  
24. super viewDidLoad];  
25. // Do any additional setup after loading the view from its nib.  
26.       
27. self.vTableView.delegate = self;  
28. self.voiceArray = [[NSMutableArray init];  
29.       
30. UILongPressGestureRecognizer *guesture = [[UILongPressGestureRecognizerself@selector(handSpeakBtnPressed:)];  
31. .delegate = self;  
32. .minimumPressDuration = 0.01f;  
33.       
34. //录音按钮添加手势操作  
35.  addGestureRecognizer:guesture];  
36. }  
37.   
38. - (void)didReceiveMemoryWarning  
39. {  
40. super didReceiveMemoryWarning];  
41. // Dispose of any resources that can be recreated.  
42. }  
43.   
44. #pragma mark tableView+++++++++++++++++++++++++++++++++++++++  
45. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{  
46. return 1;  
47. }  
48.   
49. - (void)tableView:(UITableView *)tableViewNSIndexPath *)indexPath{  
50. UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];  
51.       
52. //cell选中属性修改为无  
53.  setSelectionStyle:UITableViewCellSelectionStyleNone];  
54. }  
55.   
56. - (UITableViewCell *)tableView:(UITableView *)tableViewNSIndexPath *)indexPath{  
57.       
58. static NSString *identifid = @"simpleCell";  
59. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifid];  
60. if(!cell){  
61.  init];  
62.     }  
63.       
64. NSMutableDictionary *dic = [self.voiceArray.row];  
65.       
66. //加载聊天内容  
67. UIButton *chatView = [dic@"view"];  
68. if([[dic@"from"]@"SELF"]){  
69. //添加录音时长显示  
70. UILabel *label = [[UILabel120, 25, 30, 30)];  
71. int time = [[dic@"time"] intValue];  
72. @"%d'", time]];  
73.  addSubview:label];  
74.           
75. //添加头像  
76. float offset = (chatView.frame.size.height - 48)>0?(chatView.frame.size.height - 48)/2:10;  
77. UIImageView *headIcon = [[UIImageViewself.view.frame.size.width - 48 -5, offset, 48, 48)];  
78. @"h2.jpg"]];  
79.  addSubview:headIcon];  
80. @"点击播放" forState:UIControlStateNormal];  
81.           
82. .tag = 100 + indexPath.row;  
83. self@selector(playVoice:) forControlEvents:UIControlEventTouchUpInside];  
84.           
85. else if([[dic@"from"]@"OTHER"]){  
86. //系统自动回复部分  
87. float offset = (chatView.frame.size.height - 48)>0?(chatView.frame.size.height - 48)/2:10;  
88. UIImageView *headIcon = [[UIImageView5, offset, 48, 48)];  
89. @"h1.jpg"]];  
90.  addSubview:headIcon];  
91. @"hello world" forState:UIControlStateNormal];  
92.     }  
93.   
94.  addSubview:chatView];  
95.       
96. return cell;  
97. }  
98.   
99. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{  
100. return [_voiceArray count];  
101. }  
102.   
103. - (CGFloat)tableView:(UITableView *)tableViewNSIndexPath *)indexPath{  
104. UIView *chatView = [[_voiceArray@"view"];  
105. return chatView.frame.size.height+30;  
106. }  
107.   
108. //添加手势操作,长按按钮  
109. - (void)handSpeakBtnPressed:(UILongPressGestureRecognizer *)gestureRecognizer {  
110. if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {  
111. @"UIGestureRecognizerStateBegan");  
112.           
113. self.speekBtb@"松开结束" forState:UIControlStateNormal];  
114. self:nil];  
115.     }  
116. if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {  
117. @"UIGestureRecognizerStateChanged");  
118.     }  
119.       
120. if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {  
121. @"UIGestureRecognizerStateEnded");  
122.           
123. self.speekBtb@"按住说话" forState:UIControlStateNormal];  
124. self stopRecordVoice];  
125.     }  
126. }  
127.   
128. //开始录音  
129. - (IBAction)talk:(id)sender {  
130. //若正在播放则立即返回  
131. if(self.isPlaying){  
132. return;  
133.     }  
134.       
135. if(!self.isSpeak){  
136. self.isSpeak = YES;  
137. .delegate = self;  
138.  startRecording];  
139.     }  
140. }  
141.   
142. //结束录音  
143. - (void)stopRecordVoice{  
144. self.isSpeak = NO;  
145.  stopRecording];  
146. }  
147.   
148. //播放录音  
149. - (void)playVoice:(id)sender{  
150. if(self.isSpeak){  
151. return;  
152.     }  
153.       
154. if(!self.isPlaying){  
155. UIButton *btn = (UIButton *)sender;  
156. .tag;  
157.           
158. NSMutableDictionary *dic = [_voiceArray100)];  
159. self.fileName = [dic@"voice"];  
160.           
161. .delegate = nil;  
162.           
163. self.isPlaying = YES;  
164. self.fileNameself];  
165. else{  
166. self.isPlaying = NO;  
167.  stopPlaying];  
168.     }  
169. }  
170.   
171. - (void)recordingFinishedWithFileName:(NSString *)filePath time:(NSTimeInterval)interval{  
172. //录音保存的文件地址  
173. self.fileName = filePath;  
174. UIButton *view = [self@"点击播放"YES];  
175. //时长  
176. NSNumber *num = [[NSNumber initWithDouble:interval];  
177.       
178. NSMutableDictionary *dic = [[NSMutableDictionary@"SELF", @"from", view, @"view", self.fileName, @"voice", num, @"time", nil];  
179. self.voiceArray addObject:dic];  
180.       
181. //系统默认回复消息  
182. UIButton *otherView = [self@"你好!"NO];  
183. NSMutableDictionary *m_dic = [[NSMutableDictionary@"OTHER", @"from", otherView, @"view", @"", @"voice", 0, @"time",nil];  
184.       
185. self.voiceArray addObject:m_dic];  
186.       
187.  reloadData];  
188. }  
189.   
190. //超时操作  
191. - (void)recordingTimeout{  
192. self.isSpeak = NO;  
193. }  
194.   
195. //录音机停止采集声音  
196. - (void)recordingStopped{  
197. self.isSpeak = NO;  
198. }  
199.   
200. //录制失败操作  
201. - (void)recordingFailed:(NSString *)failureInfoString{  
202. self.isSpeak = NO;  
203. }  
204.   
205. //播放停止  
206. - (void)playingStoped{  
207. self.isPlaying = NO;  
208. }  
209.   
210. //聊天气泡按钮生成  
211. - (UIButton*)bubbleView:(NSString *)messageBOOL)isFromSelf  
212. {  
213. UIView *returnView = [self from:isFromSelf];  
214. UIButton *cellView = [[UIButton initWithFrame:CGRectZero];  
215. .backgroundColor = [UIColor clearColor];  
216.  clearColor]];  
217.       
218. NSString *picName = [NSString@"%@.png", isFromSelf?@"bubble2":@"bubble1"];  
219. UIImage *bubble = [UIImage imageNamed:picName];  
220.       
221. UIImageView *bubbleView = [[UIImageView353]];  
222. if(isFromSelf)  
223.     {  
224. .frame = CGRectMake(9.0f, 20.0f, returnView.frame.size.width, returnView.frame.size.height);  
225. .frame = CGRectMake(0.0f, 14.0f, returnView.frame.size.width+45.0f, returnView.frame.size.height + 20.0f);  
226. .frame = CGRectMake(self.view.frame.size.width - bubbleView.frame.size.width - 60, 20.0f, bubbleView.frame.size.width, bubbleView.frame.size.height + 20.0f);  
227.     }  
228. else  
229.     {  
230. .frame = CGRectMake(88.0f, 20.0f, returnView.frame.size.width, returnView.frame.size.height);  
231. .frame = CGRectMake(55.0f, 14.0f, returnView.frame.size.width + 45.0f, returnView.frame.size.height + 20.0f);  
232. .frame = CGRectMake(50.0f, 20.0f, bubbleView.frame.size.width + 50.0f, bubbleView.frame.size.height + 20.0f);  
233.     }  
234.       
235.  forState:UIControlStateNormal];  
236. 13.0f]];  
237. return cellView;  
238. }  
239.   
240. #pragma mark -  
241. #pragma mark assemble message at index  
242. #define BUBBLEWIDTH 18  
243. #define BUBBLEHEIGHT 18  
244. #define MAX_WIDTH 140  
245. - (UIView *)assembleMessageAtIndex:(NSString *)messageBOOL)fromself  
246. {  
247.  init];  
248. self _array:array];  
249.       
250. UIView *returnView = [[UIView initWithFrame:CGRectZero];  
251. 0;  
252. 0;  
253. 0;  
254. 0;  
255.       
256. if(array)  
257.     {  
258. for(int i = 0; i < [array count]; i++)  
259.         {  
260. NSString *msg = [array objectAtIndex:i];  
261.               
262. for (int index = 0; index < msg.length; index++)  
263.             {  
264. NSString *m_ch = [msg1)];  
265. if(upX >= MAX_WIDTH)  
266.                 {  
267.                     upY = upY + BUBBLEHEIGHT;  
268. 0;  
269. 140;  
270.                     y = upY;  
271.                 }  
272.                   
273. UIFont *font = [UIFont13.0f];  
274. 140, 40)];  
275. UILabel *m_label = [[UILabel.width, m_size.height)];  
276.  addSubview:m_label];  
277. .font = font;  
278. .text = m_ch;  
279. .backgroundColor = [UIColor clearColor];  
280. .width;  
281. if(x < 140)  
282.                 {  
283.                     x = upX;  
284.                 }  
285.             }  
286.         }  
287.     }  
288.       
289. .frame = CGRectMake(15.0f, 1.0f, x, y);  
290. return returnView;  
291. }  
292.   
293. - (void)NSString *)messageNSMutableArray *)array  
294. {  
295. if(message != nil)  
296.     {  
297.  message];  
298.     }  
299. }  
300.   
301.   
302. - (void)dealloc{  
303.   
304. selfself@"isSpeak"];  
305. self.fileName = nil;  
306. }  
307.   
308. @end

好了一个简单的语音聊天程序就好了,是不是很简单,其中最重要的就是 RecorderManager以及PlayerManager两个类了,一个负责录音,一个负责播放,这两个类我准备放到下一篇博客中讲解一下,大家不妨通过去下载我的Demo自己动手试一试,下载地址:。

 

注意点:

1.在将Demo程序中的Classes以及Libs文件加入到工程中去的时候,请将echo_diagnostic.m文件以及以test开头的文件删掉,否则工程会报错。

2.在工程中将Preprocessor Macros选项中的内容删除。