Home | History | Annotate | Download | only in source
      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 
     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 
    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