这篇文章主要介绍ios webrtcdemo的实现及相关注意事项,转载请说明出处(博客园RTC.Blacker)
前面很多人问webrtc android下有webrtcdemo,ios上怎么找不到,放在哪里呢?
答案:webrtcdemo在ios上没有实现,如果要实现也很简单,既然安卓都有了,依葫芦画瓢即可移植到ios上,不过可能要求您熟悉android语法,这里给出ios上的参考代码:
1 -(BOOL)initWebrtcObjects
2 {
//转载请说明出处: RTC_Blacker http://www.cnblogs.com/lingyunhu
3 if ((voE = webrtc::VoiceEngine::Create()) == NULL) {
4 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
5 return FALSE;
6 }
7 if ((voeBase = webrtc::VoEBase::GetInterface(voE)) == NULL) {
8 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
9 return FALSE;
10 }
11 if ((voeCodec = webrtc::VoECodec::GetInterface(voE)) == NULL) {
12 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
13 return FALSE;
14 }
15 if ((voeFile=webrtc::VoEFile::GetInterface(voE))==NULL) {
16 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
17 }
18 if ((voeHardware = webrtc::VoEHardware::GetInterface(voE)) == NULL) {
19 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
20 return FALSE;
21 }
22 if ((voeNetwork = webrtc::VoENetwork::GetInterface(voE)) == NULL) {
23 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
24 return FALSE;
25 }
26 if ((voeAudioProccessing = webrtc::VoEAudioProcessing::GetInterface(voE)) == NULL) {
27 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
28 return FALSE;
29 }
30 if ((voeRtpRtcp = webrtc::VoERTP_RTCP::GetInterface(voE)) == NULL) {
31 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
32 return FALSE;
33 }
34
35 if(voeBase->Init()!=0){
36 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
37 }
38
39 if ((viE = webrtc::VideoEngine::Create()) == NULL) {
40 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
41 return FALSE;
42 }
43 if ((vieBase = webrtc::ViEBase::GetInterface(viE)) == NULL) {
44 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
45 return FALSE;
46 }
47 if ((vieCapture = webrtc::ViECapture::GetInterface(viE)) == NULL) {
48 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
49 return FALSE;
50 }
51 if ((vieRender = webrtc::ViERender::GetInterface(viE)) == NULL) {
52 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
53 return FALSE;
54 }
55 if ((vieCodec = webrtc::ViECodec::GetInterface(viE)) == NULL) {
56 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
57 return FALSE;
58 }
59 if ((vieNetwork = webrtc::ViENetwork::GetInterface(viE)) == NULL) {
60 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
61 return FALSE;
62 }
63 if ((vieRtpRtcp = webrtc::ViERTP_RTCP::GetInterface(viE)) == NULL) {
64 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
65 return FALSE;
66 }
67
68 if (vieBase->Init() != 0) {
69 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
70 return FALSE;
71 }
72
73 [self initAudioCodec];
74 [self initVideoCodec];
75
76 captureID = 0;
77 videoChannel = -1;
78
79 return TRUE;
80 }
81
82 -(void)initAudioCodec
83 {
84 memset(&voeCodecInst, 0, sizeof(webrtc::CodecInst));
85
86 if (voeCodec != NULL) {
87 for (int index=0; index < voeCodec->NumOfCodecs(); index++) {
88 webrtc::CodecInst ci;
89 voeCodec->GetCodec(index, ci);
90 if (strncmp(ci.plname, "ISAC", 4) == 0) {
91 memcpy(&voeCodecInst, &ci, sizeof(webrtc::CodecInst));
92 break;
93 }
94 }
95 //voeCodecInst.channels = 1;
96 //voeCodecInst.rate = -1;
97 }
98 }
99
100 -(BOOL)start
101 {
102 f ((audioChannel = voeBase->CreateChannel())!=0) {
103 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
104 return FALSE;
105 }
106 if (vieBase->CreateChannel(videoChannel) != 0) {
107 DebugLog(@"AVErr: %d %s at line %d", vieBase->LastError(),__FUNCTION__, __LINE__);
108 return FALSE;
109 }
110 DebugLog(@"AVInfo: CreateChannel success! %d, %d",videoChannel,audioChannel);
111
112 //vieCodec->SetReceiveCodec(videoChannel,videoCodec);
113
114 if(voeAudioProccessing->SetAecmMode()!=0){
115 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
116 return FALSE;
117 }
118 voeAudioProccessing->SetAgcStatus(TRUE, webrtc::kAgcDefault);
119 voeAudioProccessing->SetNsStatus(TRUE, webrtc::kNsHighSuppression);
120 _voice_capture_device_index = -1;
121 voeHardware->SetRecordingDevice(_voice_capture_device_index);
122 voeHardware->SetPlayoutDevice(_voice_playback_device_index);
123 if(voeHardware->SetLoudspeakerStatus(true)!=0){
124 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
125 }
126 voeCodec->SetSendCodec(audioChannel, voeCodecInst);
127
128 RtpRtcpStreamStruct streamStruct=[self createRtpStreamStruct];
129 voeChannelTransport=new webrtc::test::VoiceChannelTransport(voeNetwork, audioChannel);
130 voeChannelTransport->SetLocalReceiver2(localARtpPort.rtp,streamStruct );
131 voeChannelTransport->SetSendDestination2([remoteIPAddress UTF8String], remoteARtpPort.rtp, remoteARtpPort.rtcp);
132
133 if(vieCodec->SetSendCodec(videoChannel, videoCodec) != 0)
134 {
135 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
136 return FALSE;
137 }
138 vieRtpRtcp->SetNACKStatus(videoChannel, TRUE);
139 vieRtpRtcp->SetRTCPStatus(videoChannel, webrtc::kRtcpNonCompound_RFC5506);
140 vieRtpRtcp->SetKeyFrameRequestMethod(videoChannel, webrtc::kViEKeyFrameRequestPliRtcp);
141
142 vieBase->SetVoiceEngine(voE);
143 if (vieBase->ConnectAudioChannel(videoChannel, audioChannel)) {
144 DebugLog(@"AVErr:%s at line %d",__FUNCTION__,__LINE__);
145 return FALSE;
146 }
147
148 if (deviceUniqueID == nil) {
149 DebugLog(@"AVInfo NumberOfCaptureDevices is %d", vieCapture->NumberOfCaptureDevices());
150 int list_count=vieCapture->NumberOfCaptureDevices();
151 if ( list_count> 0) {
152 int list_number=0;
153 if (list_count>1) {
154 list_number=1;//[[AVShareData instance] isUseFrontCamera]?0:1;
155 }
156 char device_name[KMaxDeviceNameLength];
157 char unique_id[KMaxUniqueIdLength];
158 memset(unique_id, 0, KMaxUniqueIdLength);
159 vieCapture->GetCaptureDevice(list_number, device_name, KMaxDeviceNameLength, unique_id, KMaxUniqueIdLength);
160 deviceUniqueID = [NSString stringWithFormat:@"%s", unique_id];
161 }
162 }
163 DebugLog(@"AVInfo deviceUniqueID is %@", deviceUniqueID);
164
165 if ((vieCapture->AllocateCaptureDevice([deviceUniqueID UTF8String], deviceUniqueID.length, captureID)) != 0) {
166 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
167 return FALSE;
168 }
169
170 DebugLog(@"AVInfo captureID is %d", captureID);
171
172 if (vieCapture->ConnectCaptureDevice(captureID, videoChannel) != 0) {
173 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
174 return FALSE;
175 }
176
177 webrtc::CaptureCapability captureCapability;
178 captureCapability.width=352;
179 captureCapability.height=288;
180 captureCapability.codecType=webrtc::kVideoCodecVP8;
181 captureCapability.maxFPS=DEFAULT_VIDEO_CODEC_MAX_FRAMERATE;
182 //vieCapture->SetRotateCapturedFrames(captureID, <#const webrtc::RotateCapturedFrame rotation#>)
183 if (vieCapture->StartCapture(captureID,captureCapability) != 0) {
184 //if (vieCapture->StartCapture(captureID) != 0) {
185 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
186 return FALSE;
187 }
188 if((vieRender->AddRenderer(captureID, [self localRenderView], 0, 0.0, 0.0, 1.0, 1.0)) != 0){
189 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
190 return FALSE;
191 }
192 /*
193 if((vieRender->AddRenderer(captureID, [self localRenderView2], 0, 0.0, 0.0, 1.0, 1.0)) != 0){
194 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
195 return FALSE;
196 }
197 */
198
199 if (vieRender->StartRender(captureID) != 0) {
200 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
201 return FALSE;
202 }
203 if(vieRender->AddRenderer(videoChannel, [self remoteRenderView], 1, 0.0f, 0.0f, 1.0f, 1.0f)!=0){
204 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
205 return FALSE;
206 }
207 if(vieRender->StartRender(videoChannel)!=0){
208 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
209 return FALSE;
210 }
211
212 if (vieBase->StartReceive(videoChannel)!=0) {
213 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
214 return FALSE;
215 }
216 if (vieBase->StartSend(videoChannel)!=0) {
217 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
218 return FALSE;
219 }
220 if(voeBase->StartReceive(audioChannel) != 0)
221 {
222 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
223 return FALSE;
224 }
225 if(voeBase->StartPlayout(audioChannel) != 0)
226 {
227 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
228 return FALSE;
229 }
230 if(voeBase->StartSend(audioChannel) != 0)
231 {
232 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
233 return FALSE;
234 }
235
236 //webrtc::CodecInst ci;
237 //voeFile->StartRecordingMicrophone(@"a.avi",ci,1000);
238
239 DebugLog(@"AVInfo: %s at line %d success!", __FUNCTION__, __LINE__);
240 return TRUE;
241 }
242
243 -(BOOL)stop
244 {
245 if(voeBase->StopSend(audioChannel)!=0){
246 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
247 return FALSE;
248 }
249 if(voeBase->StopReceive(audioChannel)!=0){
250 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
251 return FALSE;
252 }
253 if(voeBase->StopPlayout(audioChannel)!=0){
254 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
255 return FALSE;
256 }
257
258 if(vieBase->StopSend(videoChannel)!=0){
259 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
260 return FALSE;
261 }
262 if(vieBase->StopReceive(videoChannel)!=0){
263 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
264 return FALSE;
265 }
266 if(vieCapture->StopCapture(captureID)!=0){
267 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
268 return FALSE;
269 }
270 if(vieCapture->ReleaseCaptureDevice(captureID)!=0){
271 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
272 return FALSE;
273 }
274 if(vieRender->StopRender(videoChannel)!=0){
275 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
276 return FALSE;
277 }
278 if(vieRender->RemoveRenderer(videoChannel)!=0){
279 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
280 return FALSE;
281 }
282
283 if(voeBase->DeleteChannel(audioChannel)!=0){
284 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
285 return FALSE;
286 }
287 if(vieBase->DeleteChannel(videoChannel)!=0){
288 DebugLog(@"AVErr: %s at line %d", __FUNCTION__, __LINE__);
289 return FALSE;
290 }
291
292 DebugLog(@"AVInfo: %s at line %d success", __FUNCTION__, __LINE__);
293
294 return TRUE;
295 }
相关说明:
1,声音处理:
1.1. webrtc支持很多种音频编码,ilbc. isac. G711. G722. opus等等,不能编码适用不同场景,可根据自己需求调整.
1.2. 声音处理最大的难题就是噪声,回声,抖动,自动增益的处理,这也是最有价值的部分,webrtc和系统里面都有相应的处理,不过因为安卓机型众多,加上厂商DIY所以不同机器问题不一样,有些问题还得自己去处理,如webrtc团队基本上就不会用小米,酷派啥的测试.
1.3. AECM目前在安卓上都是通过软件在处理,看资料说后面一些厂商会直接集成到硬件上,具体效果拭目以待.
2,视频处理:
2.1. webrtc默认使用vp8编码,这也是Google力推的一种编码格式,后面会推VP9.
2.2. 如果需兼容H264,则需要自己去集成,实际上有人已经这么做了,不过WebRTC后面也会支持H264.
2.3. vp8与和h264孰优孰劣,最好自己去比较测试,不要道听途书,我相信Google力推的东西不会差到哪去.
2.4. NACK,字面解释就是协商确认包,实际就是起到丢包重传的作用,网络不好时因为丢包造成花屏,通过这个可解决,但会带来一定的延迟.
2.5. FEC,字面解释就是向前纠错编码,与NACK不同,包里面已经携带了纠错码,即时前一包未正确接收,也可根据他的信息正确计算出来.

浙公网安备 33010602011771号