• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2011 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_loopback.cc
13 //
14 // This code is also used as sample code for ViE 3.0
15 //
16 
17 // ===================================================================
18 //
19 // BEGIN: VideoEngine 3.0 Sample Code
20 //
21 
22 #include <iostream>
23 
24 #include "webrtc/common_types.h"
25 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
26 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
27 #include "webrtc/test/channel_transport/include/channel_transport.h"
28 #include "webrtc/video_engine/include/vie_base.h"
29 #include "webrtc/video_engine/include/vie_capture.h"
30 #include "webrtc/video_engine/include/vie_codec.h"
31 #include "webrtc/video_engine/include/vie_external_codec.h"
32 #include "webrtc/video_engine/include/vie_network.h"
33 #include "webrtc/video_engine/include/vie_render.h"
34 #include "webrtc/video_engine/include/vie_rtp_rtcp.h"
35 #include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h"
36 #include "webrtc/video_engine/test/auto_test/interface/vie_autotest_defines.h"
37 #include "webrtc/video_engine/test/libvietest/include/tb_external_transport.h"
38 #include "webrtc/voice_engine/include/voe_base.h"
39 
40 const uint32_t kSsrc = 0x01234567;
41 const uint32_t kRtxSsrc = 0x01234568;
42 const int kRtxPayloadType = 98;
43 #define VCM_RED_PAYLOAD_TYPE        96
44 #define VCM_ULPFEC_PAYLOAD_TYPE     97
45 
VideoEngineSampleCode(void * window1,void * window2)46 int VideoEngineSampleCode(void* window1, void* window2)
47 {
48     //********************************************************
49     //  Begin create/initialize Video Engine for testing
50     //********************************************************
51 
52     int error = 0;
53 
54     //
55     // Create a VideoEngine instance
56     //
57     webrtc::VideoEngine* ptrViE = NULL;
58     ptrViE = webrtc::VideoEngine::Create();
59     if (ptrViE == NULL)
60     {
61         printf("ERROR in VideoEngine::Create\n");
62         return -1;
63     }
64 
65     error = ptrViE->SetTraceFilter(webrtc::kTraceAll);
66     if (error == -1)
67     {
68         printf("ERROR in VideoEngine::SetTraceFilter\n");
69         return -1;
70     }
71 
72     std::string trace_file =
73         ViETest::GetResultOutputPath() + "ViELoopbackCall_trace.txt";
74     error = ptrViE->SetTraceFile(trace_file.c_str());
75     if (error == -1)
76     {
77         printf("ERROR in VideoEngine::SetTraceFile\n");
78         return -1;
79     }
80 
81     //
82     // Init VideoEngine and create a channel
83     //
84     webrtc::ViEBase* ptrViEBase = webrtc::ViEBase::GetInterface(ptrViE);
85     if (ptrViEBase == NULL)
86     {
87         printf("ERROR in ViEBase::GetInterface\n");
88         return -1;
89     }
90 
91     error = ptrViEBase->Init();
92     if (error == -1)
93     {
94         printf("ERROR in ViEBase::Init\n");
95         return -1;
96     }
97 
98     webrtc::ViERTP_RTCP* ptrViERtpRtcp =
99         webrtc::ViERTP_RTCP::GetInterface(ptrViE);
100     if (ptrViERtpRtcp == NULL)
101     {
102         printf("ERROR in ViERTP_RTCP::GetInterface\n");
103         return -1;
104     }
105 
106     int videoChannel = -1;
107     error = ptrViEBase->CreateChannel(videoChannel);
108     if (error == -1)
109     {
110         printf("ERROR in ViEBase::CreateChannel\n");
111         return -1;
112     }
113 
114     //
115     // List available capture devices, allocate and connect.
116     //
117     webrtc::ViECapture* ptrViECapture =
118         webrtc::ViECapture::GetInterface(ptrViE);
119     if (ptrViEBase == NULL)
120     {
121         printf("ERROR in ViECapture::GetInterface\n");
122         return -1;
123     }
124 
125     const unsigned int KMaxDeviceNameLength = 128;
126     const unsigned int KMaxUniqueIdLength = 256;
127     char deviceName[KMaxDeviceNameLength];
128     memset(deviceName, 0, KMaxDeviceNameLength);
129     char uniqueId[KMaxUniqueIdLength];
130     memset(uniqueId, 0, KMaxUniqueIdLength);
131 
132     printf("Available capture devices:\n");
133     int captureIdx = 0;
134     for (captureIdx = 0;
135          captureIdx < ptrViECapture->NumberOfCaptureDevices();
136          captureIdx++)
137     {
138         memset(deviceName, 0, KMaxDeviceNameLength);
139         memset(uniqueId, 0, KMaxUniqueIdLength);
140 
141         error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName,
142                                                 KMaxDeviceNameLength, uniqueId,
143                                                 KMaxUniqueIdLength);
144         if (error == -1)
145         {
146             printf("ERROR in ViECapture::GetCaptureDevice\n");
147             return -1;
148         }
149         printf("\t %d. %s\n", captureIdx + 1, deviceName);
150     }
151     printf("\nChoose capture device: ");
152 #ifdef WEBRTC_ANDROID
153     captureIdx = 0;
154     printf("0\n");
155 #else
156     if (scanf("%d", &captureIdx) != 1)
157     {
158         printf("Error in scanf()\n");
159         return -1;
160     }
161     getchar();
162     captureIdx = captureIdx - 1; // Compensate for idx start at 1.
163 #endif
164     error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName,
165                                             KMaxDeviceNameLength, uniqueId,
166                                             KMaxUniqueIdLength);
167     if (error == -1)
168     {
169         printf("ERROR in ViECapture::GetCaptureDevice\n");
170         return -1;
171     }
172 
173     int captureId = 0;
174     error = ptrViECapture->AllocateCaptureDevice(uniqueId, KMaxUniqueIdLength,
175                                                  captureId);
176     if (error == -1)
177     {
178         printf("ERROR in ViECapture::AllocateCaptureDevice\n");
179         return -1;
180     }
181 
182     error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel);
183     if (error == -1)
184     {
185         printf("ERROR in ViECapture::ConnectCaptureDevice\n");
186         return -1;
187     }
188 
189     error = ptrViECapture->StartCapture(captureId);
190     if (error == -1)
191     {
192         printf("ERROR in ViECapture::StartCapture\n");
193         return -1;
194     }
195 
196     //
197     // RTP/RTCP settings
198     //
199 
200     error = ptrViERtpRtcp->SetRTCPStatus(videoChannel,
201                                          webrtc::kRtcpCompound_RFC4585);
202     if (error == -1)
203     {
204         printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n");
205         return -1;
206     }
207 
208     error = ptrViERtpRtcp->SetKeyFrameRequestMethod(
209         videoChannel, webrtc::kViEKeyFrameRequestPliRtcp);
210     if (error == -1)
211     {
212         printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n");
213         return -1;
214     }
215 
216     error = ptrViERtpRtcp->SetRembStatus(videoChannel, true, true);
217     if (error == -1)
218     {
219         printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n");
220         return -1;
221     }
222 
223     // Setting SSRC manually (arbitrary value), as otherwise we will get a clash
224     // (loopback), and a new SSRC will be set, which will reset the receiver.
225     error = ptrViERtpRtcp->SetLocalSSRC(videoChannel, kSsrc);
226     if (error == -1) {
227       printf("ERROR in ViERTP_RTCP::SetLocalSSRC\n");
228       return -1;
229     }
230 
231     error = ptrViERtpRtcp->SetLocalSSRC(videoChannel, kRtxSsrc,
232                                         webrtc::kViEStreamTypeRtx, 0);
233     if (error == -1) {
234       printf("ERROR in ViERTP_RTCP::SetLocalSSRC\n");
235       return -1;
236     }
237 
238     error = ptrViERtpRtcp->SetRemoteSSRCType(videoChannel,
239                                              webrtc::kViEStreamTypeRtx,
240                                              kRtxSsrc);
241 
242     if (error == -1) {
243       printf("ERROR in ViERTP_RTCP::SetRtxReceivePayloadType\n");
244       return -1;
245     }
246 
247     error = ptrViERtpRtcp->SetRtxSendPayloadType(videoChannel, kRtxPayloadType);
248     if (error == -1) {
249       printf("ERROR in ViERTP_RTCP::SetRtxSendPayloadType\n");
250       return -1;
251     }
252 
253     error = ptrViERtpRtcp->SetRtxReceivePayloadType(videoChannel,
254                                                     kRtxPayloadType);
255     if (error == -1) {
256       printf("ERROR in ViERTP_RTCP::SetRtxReceivePayloadType\n");
257       return -1;
258     }
259     //
260     // Set up rendering
261     //
262     webrtc::ViERender* ptrViERender = webrtc::ViERender::GetInterface(ptrViE);
263     if (ptrViERender == NULL) {
264       printf("ERROR in ViERender::GetInterface\n");
265       return -1;
266     }
267 
268     error
269         = ptrViERender->AddRenderer(captureId, window1, 0, 0.0, 0.0, 1.0, 1.0);
270     if (error == -1)
271     {
272         printf("ERROR in ViERender::AddRenderer\n");
273         return -1;
274     }
275 
276     error = ptrViERender->StartRender(captureId);
277     if (error == -1)
278     {
279         printf("ERROR in ViERender::StartRender\n");
280         return -1;
281     }
282 
283     error = ptrViERender->AddRenderer(videoChannel, window2, 1, 0.0, 0.0, 1.0,
284                                       1.0);
285     if (error == -1)
286     {
287         printf("ERROR in ViERender::AddRenderer\n");
288         return -1;
289     }
290 
291     error = ptrViERender->StartRender(videoChannel);
292     if (error == -1)
293     {
294         printf("ERROR in ViERender::StartRender\n");
295         return -1;
296     }
297 
298     //
299     // Setup codecs
300     //
301     webrtc::ViECodec* ptrViECodec = webrtc::ViECodec::GetInterface(ptrViE);
302     if (ptrViECodec == NULL)
303     {
304         printf("ERROR in ViECodec::GetInterface\n");
305         return -1;
306     }
307 
308     // Check available codecs and prepare receive codecs
309     printf("\nAvailable codecs:\n");
310     webrtc::VideoCodec videoCodec;
311     memset(&videoCodec, 0, sizeof(webrtc::VideoCodec));
312     int codecIdx = 0;
313     for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); codecIdx++)
314     {
315         error = ptrViECodec->GetCodec(codecIdx, videoCodec);
316         if (error == -1)
317         {
318             printf("ERROR in ViECodec::GetCodec\n");
319             return -1;
320         }
321 
322         // try to keep the test frame size small when I420
323         if (videoCodec.codecType == webrtc::kVideoCodecI420)
324         {
325             videoCodec.width = 176;
326             videoCodec.height = 144;
327         }
328 
329         error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec);
330         if (error == -1)
331         {
332             printf("ERROR in ViECodec::SetReceiveCodec\n");
333             return -1;
334         }
335         if (videoCodec.codecType != webrtc::kVideoCodecRED
336             && videoCodec.codecType != webrtc::kVideoCodecULPFEC)
337         {
338             printf("\t %d. %s\n", codecIdx + 1, videoCodec.plName);
339         }
340     }
341     printf("%d. VP8 over Generic.\n", ptrViECodec->NumberOfCodecs() + 1);
342 
343     printf("Choose codec: ");
344 #ifdef WEBRTC_ANDROID
345     codecIdx = 0;
346     printf("0\n");
347 #else
348     if (scanf("%d", &codecIdx) != 1)
349     {
350         printf("Error in scanf()\n");
351         return -1;
352     }
353     getchar();
354     codecIdx = codecIdx - 1; // Compensate for idx start at 1.
355 #endif
356     // VP8 over generic transport gets this special one.
357     if (codecIdx == ptrViECodec->NumberOfCodecs()) {
358       for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); ++codecIdx) {
359         error = ptrViECodec->GetCodec(codecIdx, videoCodec);
360         assert(error != -1);
361         if (videoCodec.codecType == webrtc::kVideoCodecVP8)
362           break;
363       }
364       assert(videoCodec.codecType == webrtc::kVideoCodecVP8);
365       videoCodec.codecType = webrtc::kVideoCodecGeneric;
366 
367       // Any plName should work with generic
368       strcpy(videoCodec.plName, "VP8-GENERIC");
369       uint8_t pl_type = 127;
370       videoCodec.plType = pl_type;
371       webrtc::ViEExternalCodec* external_codec = webrtc::ViEExternalCodec
372           ::GetInterface(ptrViE);
373       assert(external_codec != NULL);
374       error = external_codec->RegisterExternalSendCodec(videoChannel, pl_type,
375           webrtc::VP8Encoder::Create(), false);
376       assert(error != -1);
377       error = external_codec->RegisterExternalReceiveCodec(videoChannel,
378           pl_type, webrtc::VP8Decoder::Create(), false);
379       assert(error != -1);
380     } else {
381       error = ptrViECodec->GetCodec(codecIdx, videoCodec);
382       if (error == -1) {
383         printf("ERROR in ViECodec::GetCodec\n");
384         return -1;
385       }
386     }
387 
388     // Set spatial resolution option
389     std::string str;
390     std::cout << std::endl;
391     std::cout << "Enter frame size option (default is CIF):" << std::endl;
392     std::cout << "1. QCIF (176X144) " << std::endl;
393     std::cout << "2. CIF  (352X288) " << std::endl;
394     std::cout << "3. VGA  (640X480) " << std::endl;
395     std::cout << "4. 4CIF (704X576) " << std::endl;
396     std::cout << "5. WHD  (1280X720) " << std::endl;
397     std::cout << "6. FHD  (1920X1080) " << std::endl;
398     std::getline(std::cin, str);
399     int resolnOption = atoi(str.c_str());
400     switch (resolnOption)
401     {
402         case 1:
403             videoCodec.width = 176;
404             videoCodec.height = 144;
405             break;
406         case 2:
407             videoCodec.width = 352;
408             videoCodec.height = 288;
409             break;
410         case 3:
411             videoCodec.width = 640;
412             videoCodec.height = 480;
413             break;
414         case 4:
415             videoCodec.width = 704;
416             videoCodec.height = 576;
417             break;
418         case 5:
419             videoCodec.width = 1280;
420             videoCodec.height = 720;
421             break;
422         case 6:
423             videoCodec.width = 1920;
424             videoCodec.height = 1080;
425             break;
426     }
427 
428     // Set number of temporal layers.
429     std::cout << std::endl;
430     std::cout << "Choose number of temporal layers (1 to 4).";
431     std::cout << "Press enter for default: \n";
432     std::getline(std::cin, str);
433     int numTemporalLayers = atoi(str.c_str());
434     if(numTemporalLayers != 0)
435     {
436         videoCodec.codecSpecific.VP8.numberOfTemporalLayers = numTemporalLayers;
437     }
438 
439     // Set start bit rate
440     std::cout << std::endl;
441     std::cout << "Choose start rate (in kbps). Press enter for default:  ";
442     std::getline(std::cin, str);
443     int startRate = atoi(str.c_str());
444     if(startRate != 0)
445     {
446         videoCodec.startBitrate=startRate;
447     }
448 
449     error = ptrViECodec->SetSendCodec(videoChannel, videoCodec);
450     assert(error != -1);
451     error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec);
452     assert(error != -1);
453 
454     //
455     // Choose Protection Mode
456     //
457     std::cout << std::endl;
458     std::cout << "Enter Protection Method:" << std::endl;
459     std::cout << "0. None" << std::endl;
460     std::cout << "1. FEC" << std::endl;
461     std::cout << "2. NACK" << std::endl;
462     std::cout << "3. NACK+FEC" << std::endl;
463     std::getline(std::cin, str);
464     int protectionMethod = atoi(str.c_str());
465     error = 0;
466     bool temporalToggling = true;
467     switch (protectionMethod)
468     {
469         case 0: // None: default is no protection
470             break;
471 
472         case 1: // FEC only
473             error = ptrViERtpRtcp->SetFECStatus(videoChannel,
474                                                 true,
475                                                 VCM_RED_PAYLOAD_TYPE,
476                                                 VCM_ULPFEC_PAYLOAD_TYPE);
477             temporalToggling = false;
478             break;
479 
480         case 2: // Nack only
481             error = ptrViERtpRtcp->SetNACKStatus(videoChannel, true);
482 
483             break;
484 
485         case 3: // Hybrid NAck and FEC
486             error = ptrViERtpRtcp->SetHybridNACKFECStatus(
487                 videoChannel,
488                 true,
489                 VCM_RED_PAYLOAD_TYPE,
490                 VCM_ULPFEC_PAYLOAD_TYPE);
491             temporalToggling = false;
492             break;
493      }
494 
495     if (error < 0)
496     {
497         printf("ERROR in ViERTP_RTCP::SetProtectionStatus\n");
498     }
499 
500     // Set up buffering delay.
501     std::cout << std::endl;
502     std::cout << "Set buffering delay (mS). Press enter for default(0mS):  ";
503     std::getline(std::cin, str);
504     int buffering_delay = atoi(str.c_str());
505     if (buffering_delay != 0) {
506       error = ptrViERtpRtcp->SetSenderBufferingMode(videoChannel,
507                                                     buffering_delay);
508       if (error < 0)
509         printf("ERROR in ViERTP_RTCP::SetSenderBufferingMode\n");
510 
511       error = ptrViERtpRtcp->SetReceiverBufferingMode(videoChannel,
512                                                       buffering_delay);
513       if (error < 0)
514         printf("ERROR in ViERTP_RTCP::SetReceiverBufferingMode\n");
515     }
516 
517     //
518     // Address settings
519     //
520     webrtc::ViENetwork* ptrViENetwork =
521         webrtc::ViENetwork::GetInterface(ptrViE);
522     if (ptrViENetwork == NULL)
523     {
524         printf("ERROR in ViENetwork::GetInterface\n");
525         return -1;
526     }
527 
528     // Setup transport.
529     TbExternalTransport* extTransport = NULL;
530     webrtc::test::VideoChannelTransport* video_channel_transport = NULL;
531 
532     int testMode = 0;
533     std::cout << std::endl;
534     std::cout << "Enter 1 for testing packet loss and delay with "
535         "external transport: ";
536     std::string test_str;
537     std::getline(std::cin, test_str);
538     testMode = atoi(test_str.c_str());
539     if (testMode == 1)
540     {
541         // Avoid changing SSRC due to collision.
542         error = ptrViERtpRtcp->SetLocalSSRC(videoChannel, 1);
543 
544         extTransport = new TbExternalTransport(*ptrViENetwork, videoChannel,
545                                                NULL);
546 
547         error = ptrViENetwork->RegisterSendTransport(videoChannel,
548                                                      *extTransport);
549         if (error == -1)
550         {
551             printf("ERROR in ViECodec::RegisterSendTransport \n");
552             return -1;
553         }
554 
555         // Setting uniform loss. Actual values will be set by user.
556         NetworkParameters network;
557         network.loss_model = kUniformLoss;
558         // Set up packet loss value
559         std::cout << "Enter Packet Loss Percentage" << std::endl;
560         std::string rate_str;
561         std::getline(std::cin, rate_str);
562         network.packet_loss_rate = atoi(rate_str.c_str());
563         if (network.packet_loss_rate > 0) {
564           temporalToggling = false;
565         }
566 
567         // Set network delay value
568         std::cout << "Enter network delay value [mS]" << std::endl;
569         std::string delay_str;
570         std::getline(std::cin, delay_str);
571         network.mean_one_way_delay = atoi(delay_str.c_str());
572         extTransport->SetNetworkParameters(network);
573         if (numTemporalLayers > 1 && temporalToggling) {
574           extTransport->SetTemporalToggle(numTemporalLayers);
575         } else {
576           // Disabled
577           extTransport->SetTemporalToggle(0);
578         }
579     }
580     else
581     {
582         video_channel_transport = new webrtc::test::VideoChannelTransport(
583             ptrViENetwork, videoChannel);
584 
585         const char* ipAddress = "127.0.0.1";
586         const unsigned short rtpPort = 6000;
587         std::cout << std::endl;
588         std::cout << "Using rtp port: " << rtpPort << std::endl;
589         std::cout << std::endl;
590 
591         error = video_channel_transport->SetLocalReceiver(rtpPort);
592         if (error == -1)
593         {
594             printf("ERROR in SetLocalReceiver\n");
595             return -1;
596         }
597         error = video_channel_transport->SetSendDestination(ipAddress, rtpPort);
598         if (error == -1)
599         {
600             printf("ERROR in SetSendDestination\n");
601             return -1;
602         }
603     }
604 
605     error = ptrViEBase->StartReceive(videoChannel);
606     if (error == -1)
607     {
608         printf("ERROR in ViENetwork::StartReceive\n");
609         return -1;
610     }
611 
612     error = ptrViEBase->StartSend(videoChannel);
613     if (error == -1)
614     {
615         printf("ERROR in ViENetwork::StartSend\n");
616         return -1;
617     }
618 
619     //********************************************************
620     //  Engine started
621     //********************************************************
622 
623 
624     // Call started
625     printf("\nLoopback call started\n\n");
626     printf("Press enter to stop...");
627     while ((getchar()) != '\n')
628         ;
629 
630     //********************************************************
631     //  Testing finished. Tear down Video Engine
632     //********************************************************
633 
634     error = ptrViEBase->StopReceive(videoChannel);
635     if (error == -1)
636     {
637         printf("ERROR in ViEBase::StopReceive\n");
638         return -1;
639     }
640 
641     error = ptrViEBase->StopSend(videoChannel);
642     if (error == -1)
643     {
644         printf("ERROR in ViEBase::StopSend\n");
645         return -1;
646     }
647 
648     error = ptrViERender->StopRender(captureId);
649     if (error == -1)
650     {
651         printf("ERROR in ViERender::StopRender\n");
652         return -1;
653     }
654 
655     error = ptrViERender->RemoveRenderer(captureId);
656     if (error == -1)
657     {
658         printf("ERROR in ViERender::RemoveRenderer\n");
659         return -1;
660     }
661 
662     error = ptrViERender->StopRender(videoChannel);
663     if (error == -1)
664     {
665         printf("ERROR in ViERender::StopRender\n");
666         return -1;
667     }
668 
669     error = ptrViERender->RemoveRenderer(videoChannel);
670     if (error == -1)
671     {
672         printf("ERROR in ViERender::RemoveRenderer\n");
673         return -1;
674     }
675 
676     error = ptrViECapture->StopCapture(captureId);
677     if (error == -1)
678     {
679         printf("ERROR in ViECapture::StopCapture\n");
680         return -1;
681     }
682 
683     error = ptrViECapture->DisconnectCaptureDevice(videoChannel);
684     if (error == -1)
685     {
686         printf("ERROR in ViECapture::DisconnectCaptureDevice\n");
687         return -1;
688     }
689 
690     error = ptrViECapture->ReleaseCaptureDevice(captureId);
691     if (error == -1)
692     {
693         printf("ERROR in ViECapture::ReleaseCaptureDevice\n");
694         return -1;
695     }
696 
697     error = ptrViEBase->DeleteChannel(videoChannel);
698     if (error == -1)
699     {
700         printf("ERROR in ViEBase::DeleteChannel\n");
701         return -1;
702     }
703 
704     delete video_channel_transport;
705     delete extTransport;
706 
707     int remainingInterfaces = 0;
708     remainingInterfaces = ptrViECodec->Release();
709     remainingInterfaces += ptrViECapture->Release();
710     remainingInterfaces += ptrViERtpRtcp->Release();
711     remainingInterfaces += ptrViERender->Release();
712     remainingInterfaces += ptrViENetwork->Release();
713     remainingInterfaces += ptrViEBase->Release();
714     if (remainingInterfaces > 0)
715     {
716         printf("ERROR: Could not release all interfaces\n");
717         return -1;
718     }
719 
720     bool deleted = webrtc::VideoEngine::Delete(ptrViE);
721     if (deleted == false)
722     {
723         printf("ERROR in VideoEngine::Delete\n");
724         return -1;
725     }
726 
727     return 0;
728 
729     //
730     // END:  VideoEngine 3.0 Sample Code
731     //
732     // ===================================================================
733 }
734 
ViELoopbackCall()735 int ViEAutoTest::ViELoopbackCall()
736 {
737     ViETest::Log(" ");
738     ViETest::Log("========================================");
739     ViETest::Log(" ViE Autotest Loopback Call\n");
740 
741     if (VideoEngineSampleCode(_window1, _window2) == 0)
742     {
743         ViETest::Log(" ");
744         ViETest::Log(" ViE Autotest Loopback Call Done");
745         ViETest::Log("========================================");
746         ViETest::Log(" ");
747 
748         return 0;
749     }
750 
751     ViETest::Log(" ");
752     ViETest::Log(" ViE Autotest Loopback Call Failed");
753     ViETest::Log("========================================");
754     ViETest::Log(" ");
755     return 1;
756 
757 }
758