• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 //
12 // vie_autotest_record.cc
13 //
14 // This code is also used as sample code for ViE 3.0
15 //
16 
17 #include <fstream>
18 #include <stdio.h>
19 
20 #include "webrtc/common_types.h"
21 #include "webrtc/system_wrappers/interface/tick_util.h"
22 #include "webrtc/test/channel_transport/include/channel_transport.h"
23 #include "webrtc/video_engine/include/vie_base.h"
24 #include "webrtc/video_engine/include/vie_capture.h"
25 #include "webrtc/video_engine/include/vie_codec.h"
26 #include "webrtc/video_engine/include/vie_network.h"
27 #include "webrtc/video_engine/include/vie_render.h"
28 #include "webrtc/video_engine/include/vie_rtp_rtcp.h"
29 #include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h"
30 #include "webrtc/video_engine/test/auto_test/interface/vie_autotest_defines.h"
31 #include "webrtc/video_engine/test/libvietest/include/tb_external_transport.h"
32 #include "webrtc/voice_engine/include/voe_base.h"
33 #include "webrtc/voice_engine/include/voe_network.h"
34 #include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
35 
36 #define VCM_RED_PAYLOAD_TYPE            96
37 #define VCM_ULPFEC_PAYLOAD_TYPE         97
38 #define DEFAULT_AUDIO_PORT              11113
39 #define DEFAULT_AUDIO_CODEC             "ISAC"
40 #define DEFAULT_VIDEO_CODEC_WIDTH       640
41 #define DEFAULT_VIDEO_CODEC_HEIGHT      480
42 #define DEFAULT_VIDEO_CODEC_START_RATE  1000
43 #define DEFAULT_RECORDING_FOLDER        "RECORDING"
44 #define DEFAULT_RECORDING_AUDIO         "/audio_debug.aec"
45 #define DEFAULT_RECORDING_VIDEO         "/video_debug.yuv"
46 #define DEFAULT_RECORDING_AUDIO_RTP     "/audio_rtpdump.rtp"
47 #define DEFAULT_RECORDING_VIDEO_RTP     "/video_rtpdump.rtp"
48 
49 bool GetAudioDevices(webrtc::VoEBase* voe_base,
50                      webrtc::VoEHardware* voe_hardware,
51                      char* recording_device_name,
52                      int& recording_device_index,
53                      char* playbackDeviceName,
54                      int& playback_device_index);
55 bool GetAudioCodecRecord(webrtc::VoECodec* voe_codec,
56                          webrtc::CodecInst& audio_codec);
57 
VideoEngineSampleRecordCode(void * window1,void * window2)58 int VideoEngineSampleRecordCode(void* window1, void* window2) {
59   int error = 0;
60   // Audio settings.
61   int audio_tx_port = DEFAULT_AUDIO_PORT;
62   int audio_rx_port = DEFAULT_AUDIO_PORT;
63   webrtc::CodecInst audio_codec;
64   int audio_channel = -1;
65   int audio_capture_device_index = -1;
66   int audio_playback_device_index = -1;
67   const unsigned int KMaxDeviceNameLength = 128;
68   const unsigned int KMaxUniqueIdLength = 256;
69   char deviceName[KMaxDeviceNameLength];
70   char audio_capture_device_name[KMaxUniqueIdLength] = "";
71   char audio_playbackDeviceName[KMaxUniqueIdLength] = "";
72 
73   // Network settings.
74   const char* ipAddress = "127.0.0.1";
75   const int rtpPort = 6000;
76 
77   //
78   // Create a VideoEngine instance
79   //
80   webrtc::VideoEngine* ptrViE = NULL;
81   ptrViE = webrtc::VideoEngine::Create();
82   if (ptrViE == NULL) {
83     printf("ERROR in VideoEngine::Create\n");
84     return -1;
85   }
86 
87   error = ptrViE->SetTraceFilter(webrtc::kTraceAll);
88   if (error == -1) {
89     printf("ERROR in VideoEngine::SetTraceLevel\n");
90     return -1;
91   }
92 
93   std::string trace_file =
94     ViETest::GetResultOutputPath() + "ViERecordCall_trace.txt";
95   error = ptrViE->SetTraceFile(trace_file.c_str());
96   if (error == -1) {
97     printf("ERROR in VideoEngine::SetTraceFile\n");
98     return -1;
99   }
100 
101   //
102   // Create a VoE instance
103   //
104   webrtc::VoiceEngine* voe = webrtc::VoiceEngine::Create();
105   //
106   // Init VideoEngine and create a channel
107   //
108   webrtc::ViEBase* ptrViEBase = webrtc::ViEBase::GetInterface(ptrViE);
109   if (ptrViEBase == NULL) {
110     printf("ERROR in ViEBase::GetInterface\n");
111     return -1;
112   }
113 
114   error = ptrViEBase->Init();
115   if (error == -1) {
116     printf("ERROR in ViEBase::Init\n");
117     return -1;
118   }
119 
120   webrtc::VoEBase* voe_base = webrtc::VoEBase::GetInterface(voe);
121   if (voe_base == NULL) {
122     printf("ERROR in VoEBase::GetInterface\n");
123     return -1;
124   }
125   error = voe_base->Init();
126   if (error == -1) {
127     printf("ERROR in VoEBase::Init\n");
128     return -1;
129   }
130 
131   int videoChannel = -1;
132   error = ptrViEBase->CreateChannel(videoChannel);
133   if (error == -1) {
134     printf("ERROR in ViEBase::CreateChannel\n");
135     return -1;
136   }
137 
138   webrtc::VoEHardware* voe_hardware =
139     webrtc::VoEHardware::GetInterface(voe);
140   webrtc::VoECodec* voe_codec = webrtc::VoECodec::GetInterface(voe);
141   webrtc::VoEAudioProcessing* voe_apm =
142        webrtc::VoEAudioProcessing::GetInterface(voe);
143   webrtc::VoENetwork* voe_network =
144     webrtc::VoENetwork::GetInterface(voe);
145 
146   // Get the audio device for the call.
147   memset(audio_capture_device_name, 0, KMaxUniqueIdLength);
148   memset(audio_playbackDeviceName, 0, KMaxUniqueIdLength);
149   GetAudioDevices(voe_base, voe_hardware, audio_capture_device_name,
150                   audio_capture_device_index, audio_playbackDeviceName,
151                   audio_playback_device_index);
152 
153   // Get the audio codec for the call.
154   memset(static_cast<void*>(&audio_codec), 0, sizeof(audio_codec));
155   GetAudioCodecRecord(voe_codec, audio_codec);
156 
157   audio_channel = voe_base->CreateChannel();
158 
159   webrtc::scoped_ptr<webrtc::test::VoiceChannelTransport>
160       voice_channel_transport(
161           new webrtc::test::VoiceChannelTransport(voe_network, audio_channel));
162 
163   voice_channel_transport->SetSendDestination(ipAddress, audio_tx_port);
164   voice_channel_transport->SetLocalReceiver(audio_rx_port);
165 
166   voe_hardware->SetRecordingDevice(audio_capture_device_index);
167   voe_hardware->SetPlayoutDevice(audio_playback_device_index);
168   voe_codec->SetSendCodec(audio_channel, audio_codec);
169   voe_apm->SetAgcStatus(true, webrtc::kAgcDefault);
170   voe_apm->SetNsStatus(true, webrtc::kNsHighSuppression);
171 
172   //
173   // List available capture devices, allocate and connect.
174   //
175   webrtc::ViECapture* ptrViECapture =
176       webrtc::ViECapture::GetInterface(ptrViE);
177   if (ptrViECapture == NULL) {
178     printf("ERROR in ViECapture::GetInterface\n");
179     return -1;
180   }
181 
182   webrtc::VoERTP_RTCP* ptrVoERtpRtcp =
183     webrtc::VoERTP_RTCP::GetInterface(voe);
184   if (ptrVoERtpRtcp == NULL) {
185     printf("ERROR in VoERTP_RTCP::GetInterface\n");
186     return -1;
187   }
188 
189   memset(deviceName, 0, KMaxDeviceNameLength);
190   char uniqueId[KMaxUniqueIdLength];
191   memset(uniqueId, 0, KMaxUniqueIdLength);
192 
193   printf("Available capture devices:\n");
194   int captureIdx = 0;
195   for (captureIdx = 0;
196        captureIdx < ptrViECapture->NumberOfCaptureDevices();
197        captureIdx++) {
198     memset(deviceName, 0, KMaxDeviceNameLength);
199     memset(uniqueId, 0, KMaxUniqueIdLength);
200 
201     error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName,
202                                             KMaxDeviceNameLength, uniqueId,
203                                             KMaxUniqueIdLength);
204     if (error == -1) {
205       printf("ERROR in ViECapture::GetCaptureDevice\n");
206       return -1;
207     }
208     printf("\t %d. %s\n", captureIdx + 1, deviceName);
209   }
210   printf("\nChoose capture device: ");
211 #ifdef WEBRTC_ANDROID
212   captureIdx = 0;
213   printf("0\n");
214 #else
215   if (scanf("%d", &captureIdx) != 1) {
216     printf("Error in scanf()\n");
217     return -1;
218   }
219   getchar();
220   captureIdx = captureIdx - 1;  // Compensate for idx start at 1.
221 #endif
222   error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName,
223                                           KMaxDeviceNameLength, uniqueId,
224                                           KMaxUniqueIdLength);
225   if (error == -1) {
226     printf("ERROR in ViECapture::GetCaptureDevice\n");
227     return -1;
228   }
229 
230   int captureId = 0;
231   error = ptrViECapture->AllocateCaptureDevice(uniqueId, KMaxUniqueIdLength,
232                                                captureId);
233   if (error == -1) {
234     printf("ERROR in ViECapture::AllocateCaptureDevice\n");
235     return -1;
236   }
237 
238   error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel);
239   if (error == -1) {
240     printf("ERROR in ViECapture::ConnectCaptureDevice\n");
241     return -1;
242   }
243 
244   error = ptrViECapture->StartCapture(captureId);
245   if (error == -1) {
246     printf("ERROR in ViECapture::StartCapture\n");
247     return -1;
248   }
249 
250   //
251   // RTP/RTCP settings
252   //
253   webrtc::ViERTP_RTCP* ptrViERtpRtcp =
254       webrtc::ViERTP_RTCP::GetInterface(ptrViE);
255   if (ptrViERtpRtcp == NULL) {
256     printf("ERROR in ViERTP_RTCP::GetInterface\n");
257     return -1;
258   }
259 
260   error = ptrViERtpRtcp->SetRTCPStatus(videoChannel,
261                                        webrtc::kRtcpCompound_RFC4585);
262   if (error == -1) {
263     printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n");
264     return -1;
265   }
266 
267   error = ptrViERtpRtcp->SetKeyFrameRequestMethod(
268       videoChannel, webrtc::kViEKeyFrameRequestPliRtcp);
269   if (error == -1) {
270     printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n");
271     return -1;
272   }
273 
274   error = ptrViERtpRtcp->SetRembStatus(videoChannel, true, true);
275   if (error == -1) {
276     printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n");
277     return -1;
278   }
279 
280   //
281   // Set up rendering
282   //
283   webrtc::ViERender* ptrViERender = webrtc::ViERender::GetInterface(ptrViE);
284   if (ptrViERender == NULL) {
285     printf("ERROR in ViERender::GetInterface\n");
286     return -1;
287   }
288 
289   error = ptrViERender->AddRenderer(captureId, window1, 0, 0.0, 0.0, 1.0, 1.0);
290   if (error == -1) {
291     printf("ERROR in ViERender::AddRenderer\n");
292     return -1;
293   }
294 
295   error = ptrViERender->StartRender(captureId);
296   if (error == -1) {
297     printf("ERROR in ViERender::StartRender\n");
298     return -1;
299   }
300 
301   error = ptrViERender->AddRenderer(videoChannel, window2, 1, 0.0, 0.0, 1.0,
302                                     1.0);
303   if (error == -1) {
304     printf("ERROR in ViERender::AddRenderer\n");
305     return -1;
306   }
307 
308   error = ptrViERender->StartRender(videoChannel);
309   if (error == -1) {
310     printf("ERROR in ViERender::StartRender\n");
311     return -1;
312   }
313 
314   //
315   // Setup codecs
316   //
317   webrtc::ViECodec* ptrViECodec = webrtc::ViECodec::GetInterface(ptrViE);
318   if (ptrViECodec == NULL) {
319     printf("ERROR in ViECodec::GetInterface\n");
320     return -1;
321   }
322 
323   webrtc::VideoCodec videoCodec;
324   memset(&videoCodec, 0, sizeof(webrtc::VideoCodec));
325   int codecIdx = 0;
326 
327 #ifdef WEBRTC_ANDROID
328   codecIdx = 0;
329   printf("0\n");
330 #else
331   codecIdx = 0;  // Compensate for idx start at 1.
332 #endif
333 
334   error = ptrViECodec->GetCodec(codecIdx, videoCodec);
335   if (error == -1) {
336      printf("ERROR in ViECodec::GetCodec\n");
337      return -1;
338   }
339 
340   // Set spatial resolution option
341   videoCodec.width = DEFAULT_VIDEO_CODEC_WIDTH;
342   videoCodec.height = DEFAULT_VIDEO_CODEC_HEIGHT;
343 
344   // Set start bit rate
345   videoCodec.startBitrate = DEFAULT_VIDEO_CODEC_START_RATE;
346 
347   error = ptrViECodec->SetSendCodec(videoChannel, videoCodec);
348   if (error == -1) {
349     printf("ERROR in ViECodec::SetSendCodec\n");
350     return -1;
351   }
352 
353   //
354   // Address settings
355   //
356   webrtc::ViENetwork* ptrViENetwork =
357       webrtc::ViENetwork::GetInterface(ptrViE);
358   if (ptrViENetwork == NULL) {
359     printf("ERROR in ViENetwork::GetInterface\n");
360     return -1;
361   }
362   webrtc::test::VideoChannelTransport* video_channel_transport =
363       new webrtc::test::VideoChannelTransport(ptrViENetwork, videoChannel);
364 
365   error = video_channel_transport->SetSendDestination(ipAddress, rtpPort);
366   if (error == -1) {
367     printf("ERROR in SetSendDestination\n");
368     return -1;
369   }
370   error = video_channel_transport->SetLocalReceiver(rtpPort);
371   if (error == -1) {
372     printf("ERROR in SetLocalReceiver\n");
373     return -1;
374   }
375 
376   std::string str;
377   int enable_labeling = 0;
378   std::cout << std::endl;
379   std::cout << "Do you want to label this recording?" << std::endl;
380   std::cout << "0. No (default)." << std::endl;
381   std::cout << "1. This call will be labeled on the fly." << std::endl;
382   std::getline(std::cin, str);
383   enable_labeling = atoi(str.c_str());
384 
385   uint32_t folder_time = static_cast<uint32_t>
386     (webrtc::TickTime::MillisecondTimestamp());
387   std::stringstream folder_time_str;
388   folder_time_str <<  folder_time;
389   const std::string folder_name = "recording" + folder_time_str.str();
390   printf("recording name = %s\n", folder_name.c_str());
391   // TODO(mikhal): use file_utils.
392 #ifdef WIN32
393   _mkdir(folder_name.c_str());
394 #else
395   mkdir(folder_name.c_str(), 0777);
396 #endif
397   const std::string audio_filename =  folder_name + DEFAULT_RECORDING_AUDIO;
398   const std::string video_filename =  folder_name + DEFAULT_RECORDING_VIDEO;
399   const std::string audio_rtp_filename = folder_name +
400     DEFAULT_RECORDING_AUDIO_RTP;
401   const std::string video_rtp_filename = folder_name +
402     DEFAULT_RECORDING_VIDEO_RTP;
403   std::fstream timing;
404   if (enable_labeling == 1) {
405     std::cout << "Press enter to stamp current time."<< std::endl;
406     std::string timing_file = folder_name + "/labeling.txt";
407     timing.open(timing_file.c_str(), std::fstream::out | std::fstream::app);
408   }
409   printf("\nPress enter to start recording\n");
410   std::getline(std::cin, str);
411   printf("\nRecording started\n\n");
412 
413   error = ptrViEBase->StartReceive(videoChannel);
414   if (error == -1) {
415     printf("ERROR in ViENetwork::StartReceive\n");
416     return -1;
417   }
418 
419   error = ptrViEBase->StartSend(videoChannel);
420   if (error == -1) {
421     printf("ERROR in ViENetwork::StartSend\n");
422     return -1;
423   }
424   error = voe_base->StartSend(audio_channel);
425   if (error == -1) {
426     printf("ERROR in VoENetwork::StartSend\n");
427     return -1;
428   }
429 
430   //  Engine started
431 
432   voe_apm->StartDebugRecording(audio_filename.c_str());
433   ptrViECodec->StartDebugRecording(videoChannel, video_filename.c_str());
434   ptrViERtpRtcp->StartRTPDump(videoChannel,
435                               video_rtp_filename.c_str(), webrtc::kRtpOutgoing);
436   ptrVoERtpRtcp->StartRTPDump(audio_channel,
437                               audio_rtp_filename.c_str(), webrtc::kRtpOutgoing);
438   printf("Press s + enter to stop...");
439   int64_t clock_time;
440   if (enable_labeling == 1) {
441     clock_time = webrtc::TickTime::MillisecondTimestamp();
442     timing << clock_time << std::endl;
443   }
444   char c = getchar();
445   fflush(stdin);
446   while (c != 's') {
447     if (c == '\n' && enable_labeling == 1) {
448       clock_time = webrtc::TickTime::MillisecondTimestamp();
449       timing << clock_time << std::endl;
450     }
451     c = getchar();
452   }
453   if (enable_labeling == 1) {
454     clock_time = webrtc::TickTime::MillisecondTimestamp();
455     timing << clock_time << std::endl;
456   }
457 
458   ptrViERtpRtcp->StopRTPDump(videoChannel, webrtc::kRtpOutgoing);
459   ptrVoERtpRtcp->StopRTPDump(audio_channel, webrtc::kRtpOutgoing);
460   voe_apm->StopDebugRecording();
461   ptrViECodec->StopDebugRecording(videoChannel);
462   if (enable_labeling == 1)
463     timing.close();
464 
465   //  Recording finished. Tear down Video Engine.
466 
467   error = ptrViEBase->StopReceive(videoChannel);
468   if (error == -1) {
469     printf("ERROR in ViEBase::StopReceive\n");
470     return -1;
471   }
472 
473   error = ptrViEBase->StopSend(videoChannel);
474   if (error == -1) {
475     printf("ERROR in ViEBase::StopSend\n");
476     return -1;
477   }
478   error = voe_base->StopSend(audio_channel);
479 
480   error = ptrViERender->StopRender(captureId);
481   if (error == -1) {
482     printf("ERROR in ViERender::StopRender\n");
483     return -1;
484   }
485 
486   error = ptrViERender->RemoveRenderer(captureId);
487   if (error == -1) {
488     printf("ERROR in ViERender::RemoveRenderer\n");
489     return -1;
490   }
491 
492   error = ptrViERender->StopRender(videoChannel);
493   if (error == -1) {
494     printf("ERROR in ViERender::StopRender\n");
495     return -1;
496   }
497 
498   error = ptrViERender->RemoveRenderer(videoChannel);
499   if (error == -1) {
500     printf("ERROR in ViERender::RemoveRenderer\n");
501     return -1;
502   }
503 
504   error = ptrViECapture->StopCapture(captureId);
505   if (error == -1) {
506     printf("ERROR in ViECapture::StopCapture\n");
507     return -1;
508   }
509 
510   error = ptrViECapture->DisconnectCaptureDevice(videoChannel);
511   if (error == -1) {
512     printf("ERROR in ViECapture::DisconnectCaptureDevice\n");
513     return -1;
514   }
515 
516   error = ptrViECapture->ReleaseCaptureDevice(captureId);
517   if (error == -1) {
518     printf("ERROR in ViECapture::ReleaseCaptureDevice\n");
519     return -1;
520   }
521 
522   error = ptrViEBase->DeleteChannel(videoChannel);
523   if (error == -1) {
524     printf("ERROR in ViEBase::DeleteChannel\n");
525     return -1;
526   }
527   delete video_channel_transport;
528 
529   int remainingInterfaces = 0;
530   remainingInterfaces = ptrViECodec->Release();
531   remainingInterfaces += ptrViECapture->Release();
532   remainingInterfaces += ptrViERtpRtcp->Release();
533   remainingInterfaces += ptrViERender->Release();
534   remainingInterfaces += ptrViENetwork->Release();
535   remainingInterfaces += ptrViEBase->Release();
536   if (remainingInterfaces > 0) {
537     printf("ERROR: Could not release all interfaces\n");
538     return -1;
539   }
540   bool deleted = webrtc::VideoEngine::Delete(ptrViE);
541   if (deleted == false) {
542     printf("ERROR in VideoEngine::Delete\n");
543     return -1;
544   }
545   return 0;
546 }
547 
548 
549 // TODO(mikhal): Place above functionality under this class.
ViERecordCall()550 int ViEAutoTest::ViERecordCall() {
551   ViETest::Log(" ");
552   ViETest::Log("========================================");
553   ViETest::Log(" ViE Record Call\n");
554 
555   if (VideoEngineSampleRecordCode(_window1, _window2) == 0) {
556     ViETest::Log(" ");
557     ViETest::Log(" ViE Autotest Record Call Done");
558     ViETest::Log("========================================");
559     ViETest::Log(" ");
560     return 0;
561   }
562 
563   ViETest::Log(" ");
564   ViETest::Log(" ViE Autotest Record Call Failed");
565   ViETest::Log("========================================");
566   ViETest::Log(" ");
567   return 1;
568 }
569 
GetAudioCodecRecord(webrtc::VoECodec * voe_codec,webrtc::CodecInst & audio_codec)570 bool GetAudioCodecRecord(webrtc::VoECodec* voe_codec,
571                          webrtc::CodecInst& audio_codec) {
572   int error = 0;
573   int number_of_errors = 0;
574   memset(&audio_codec, 0, sizeof(webrtc::CodecInst));
575 
576   while (1) {
577     int codec_idx = 0;
578     int default_codec_idx = 0;
579     for (codec_idx = 0; codec_idx < voe_codec->NumOfCodecs(); codec_idx++) {
580       error = voe_codec->GetCodec(codec_idx, audio_codec);
581       number_of_errors += ViETest::TestError(error == 0,
582                                              "ERROR: %s at line %d",
583                                              __FUNCTION__, __LINE__);
584 
585       // Test for default codec index.
586       if (strcmp(audio_codec.plname, DEFAULT_AUDIO_CODEC) == 0) {
587         default_codec_idx = codec_idx;
588       }
589     }
590     error = voe_codec->GetCodec(default_codec_idx, audio_codec);
591     number_of_errors += ViETest::TestError(error == 0,
592                                            "ERROR: %s at line %d",
593                                            __FUNCTION__, __LINE__);
594     return true;
595   }
596   assert(false);
597   return false;
598 }
599