Home | History | Annotate | Download | only in cmd_test
      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 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #ifndef _WIN32
     15 #include <unistd.h>
     16 #endif
     17 
     18 #include <vector>
     19 
     20 #include "gflags/gflags.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 #include "webrtc/base/format_macros.h"
     23 #include "webrtc/base/scoped_ptr.h"
     24 #include "webrtc/call/rtc_event_log.h"
     25 #include "webrtc/engine_configurations.h"
     26 #include "webrtc/modules/audio_processing/include/audio_processing.h"
     27 #include "webrtc/test/channel_transport/channel_transport.h"
     28 #include "webrtc/test/testsupport/fileutils.h"
     29 #include "webrtc/test/testsupport/trace_to_stderr.h"
     30 #include "webrtc/voice_engine/include/voe_audio_processing.h"
     31 #include "webrtc/voice_engine/include/voe_base.h"
     32 #include "webrtc/voice_engine/include/voe_codec.h"
     33 #include "webrtc/voice_engine/include/voe_dtmf.h"
     34 #include "webrtc/voice_engine/include/voe_errors.h"
     35 #include "webrtc/voice_engine/include/voe_external_media.h"
     36 #include "webrtc/voice_engine/include/voe_file.h"
     37 #include "webrtc/voice_engine/include/voe_hardware.h"
     38 #include "webrtc/voice_engine/include/voe_neteq_stats.h"
     39 #include "webrtc/voice_engine/include/voe_network.h"
     40 #include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
     41 #include "webrtc/voice_engine/include/voe_video_sync.h"
     42 #include "webrtc/voice_engine/include/voe_volume_control.h"
     43 
     44 DEFINE_bool(use_log_file, false,
     45     "Output logs to a file; by default they will be printed to stderr.");
     46 
     47 using namespace webrtc;
     48 using namespace test;
     49 
     50 #define VALIDATE                                           \
     51   if (res != 0) {                                          \
     52     printf("*** Error at line %i \n", __LINE__);           \
     53     printf("*** Error code = %i \n", base1->LastError());  \
     54   }
     55 
     56 VoiceEngine* m_voe = NULL;
     57 VoEBase* base1 = NULL;
     58 VoECodec* codec = NULL;
     59 VoEVolumeControl* volume = NULL;
     60 VoEDtmf* dtmf = NULL;
     61 VoERTP_RTCP* rtp_rtcp = NULL;
     62 VoEAudioProcessing* apm = NULL;
     63 VoENetwork* netw = NULL;
     64 VoEFile* file = NULL;
     65 VoEVideoSync* vsync = NULL;
     66 VoEHardware* hardware = NULL;
     67 VoEExternalMedia* xmedia = NULL;
     68 VoENetEqStats* neteqst = NULL;
     69 
     70 void RunTest(std::string out_path);
     71 
     72 class MyObserver : public VoiceEngineObserver {
     73  public:
     74    virtual void CallbackOnError(int channel, int err_code);
     75 };
     76 
     77 void MyObserver::CallbackOnError(int channel, int err_code) {
     78   // Add printf for other error codes here
     79   if (err_code == VE_TYPING_NOISE_WARNING) {
     80     printf("  TYPING NOISE DETECTED \n");
     81   } else if (err_code == VE_TYPING_NOISE_OFF_WARNING) {
     82     printf("  TYPING NOISE OFF DETECTED \n");
     83   } else if (err_code == VE_RECEIVE_PACKET_TIMEOUT) {
     84     printf("  RECEIVE PACKET TIMEOUT \n");
     85   } else if (err_code == VE_PACKET_RECEIPT_RESTARTED) {
     86     printf("  PACKET RECEIPT RESTARTED \n");
     87   } else if (err_code == VE_RUNTIME_PLAY_WARNING) {
     88     printf("  RUNTIME PLAY WARNING \n");
     89   } else if (err_code == VE_RUNTIME_REC_WARNING) {
     90     printf("  RUNTIME RECORD WARNING \n");
     91   } else if (err_code == VE_SATURATION_WARNING) {
     92     printf("  SATURATION WARNING \n");
     93   } else if (err_code == VE_RUNTIME_PLAY_ERROR) {
     94     printf("  RUNTIME PLAY ERROR \n");
     95   } else if (err_code == VE_RUNTIME_REC_ERROR) {
     96     printf("  RUNTIME RECORD ERROR \n");
     97   } else if (err_code == VE_REC_DEVICE_REMOVED) {
     98     printf("  RECORD DEVICE REMOVED \n");
     99   }
    100 }
    101 
    102 void SetStereoIfOpus(bool use_stereo, CodecInst* codec_params) {
    103   if (strncmp(codec_params->plname, "opus", 4) == 0) {
    104     if (use_stereo)
    105       codec_params->channels = 2;
    106     else
    107       codec_params->channels = 1;
    108   }
    109 }
    110 
    111 void PrintCodecs(bool opus_stereo) {
    112   CodecInst codec_params;
    113   for (int i = 0; i < codec->NumOfCodecs(); ++i) {
    114     int res = codec->GetCodec(i, codec_params);
    115     VALIDATE;
    116     SetStereoIfOpus(opus_stereo, &codec_params);
    117     printf("%2d. %3d  %s/%d/%" PRIuS " \n", i, codec_params.pltype,
    118            codec_params.plname, codec_params.plfreq, codec_params.channels);
    119   }
    120 }
    121 
    122 int main(int argc, char** argv) {
    123   google::ParseCommandLineFlags(&argc, &argv, true);
    124 
    125   int res = 0;
    126 
    127   printf("Test started \n");
    128 
    129   m_voe = VoiceEngine::Create();
    130   base1 = VoEBase::GetInterface(m_voe);
    131   codec = VoECodec::GetInterface(m_voe);
    132   apm = VoEAudioProcessing::GetInterface(m_voe);
    133   volume = VoEVolumeControl::GetInterface(m_voe);
    134   dtmf = VoEDtmf::GetInterface(m_voe);
    135   rtp_rtcp = VoERTP_RTCP::GetInterface(m_voe);
    136   netw = VoENetwork::GetInterface(m_voe);
    137   file = VoEFile::GetInterface(m_voe);
    138   vsync = VoEVideoSync::GetInterface(m_voe);
    139   hardware = VoEHardware::GetInterface(m_voe);
    140   xmedia = VoEExternalMedia::GetInterface(m_voe);
    141   neteqst = VoENetEqStats::GetInterface(m_voe);
    142 
    143   MyObserver my_observer;
    144 
    145   rtc::scoped_ptr<test::TraceToStderr> trace_to_stderr;
    146   if (!FLAGS_use_log_file) {
    147     trace_to_stderr.reset(new test::TraceToStderr);
    148   } else {
    149     const std::string trace_filename = test::OutputPath() + "webrtc_trace.txt";
    150     VoiceEngine::SetTraceFilter(kTraceAll);
    151     res = VoiceEngine::SetTraceFile(trace_filename.c_str());
    152     VALIDATE;
    153     res = VoiceEngine::SetTraceCallback(NULL);
    154     VALIDATE;
    155     printf("Outputting logs to file: %s\n", trace_filename.c_str());
    156   }
    157 
    158   printf("Init\n");
    159   res = base1->Init();
    160   if (res != 0) {
    161     printf("\nError calling Init: %d\n", base1->LastError());
    162     fflush(NULL);
    163     exit(1);
    164   }
    165 
    166   res = base1->RegisterVoiceEngineObserver(my_observer);
    167   VALIDATE;
    168 
    169   printf("Version\n");
    170   char tmp[1024];
    171   res = base1->GetVersion(tmp);
    172   VALIDATE;
    173   printf("%s\n", tmp);
    174 
    175   RunTest(test::OutputPath());
    176 
    177   printf("Terminate \n");
    178 
    179   base1->DeRegisterVoiceEngineObserver();
    180 
    181   res = base1->Terminate();
    182   VALIDATE;
    183 
    184   if (base1)
    185     base1->Release();
    186 
    187   if (codec)
    188     codec->Release();
    189 
    190   if (volume)
    191     volume->Release();
    192 
    193   if (dtmf)
    194     dtmf->Release();
    195 
    196   if (rtp_rtcp)
    197     rtp_rtcp->Release();
    198 
    199   if (apm)
    200     apm->Release();
    201 
    202   if (netw)
    203     netw->Release();
    204 
    205   if (file)
    206     file->Release();
    207 
    208   if (vsync)
    209     vsync->Release();
    210 
    211   if (hardware)
    212     hardware->Release();
    213 
    214   if (xmedia)
    215     xmedia->Release();
    216 
    217   if (neteqst)
    218     neteqst->Release();
    219 
    220   VoiceEngine::Delete(m_voe);
    221 
    222   return 0;
    223 }
    224 
    225 void RunTest(std::string out_path) {
    226   int chan, res;
    227   CodecInst cinst;
    228   bool enable_aec = false;
    229   bool enable_agc = false;
    230   bool enable_rx_agc = false;
    231   bool enable_cng = false;
    232   bool enable_ns = false;
    233   bool enable_rx_ns = false;
    234   bool typing_detection = false;
    235   bool muted = false;
    236   bool opus_stereo = false;
    237   bool opus_dtx = false;
    238   bool experimental_ns_enabled = false;
    239   bool debug_recording_started = false;
    240 
    241 #if defined(WEBRTC_ANDROID)
    242   std::string resource_path = "/sdcard/";
    243 #else
    244   std::string resource_path = webrtc::test::ProjectRootPath();
    245   if (resource_path == webrtc::test::kCannotFindProjectRootDir) {
    246     printf("*** Unable to get project root directory. "
    247            "File playing may fail. ***\n");
    248     // Fall back to the current directory.
    249     resource_path = "./";
    250   } else {
    251     resource_path += "data/voice_engine/";
    252   }
    253 #endif
    254   const std::string audio_filename = resource_path + "audio_long16.pcm";
    255 
    256   const std::string play_filename = out_path + "recorded_playout.pcm";
    257   const std::string mic_filename = out_path + "recorded_mic.pcm";
    258 
    259   chan = base1->CreateChannel();
    260   if (chan < 0) {
    261     printf("************ Error code = %i\n", base1->LastError());
    262     fflush(NULL);
    263   }
    264 
    265   VoiceChannelTransport* voice_channel_transport(
    266       new VoiceChannelTransport(netw, chan));
    267 
    268   char ip[64];
    269   printf("1. 127.0.0.1 \n");
    270   printf("2. Specify IP \n");
    271   int ip_selection;
    272   ASSERT_EQ(1, scanf("%i", &ip_selection));
    273 
    274   if (ip_selection == 1) {
    275     strcpy(ip, "127.0.0.1");
    276   } else {
    277     printf("Specify remote IP: ");
    278     ASSERT_EQ(1, scanf("%s", ip));
    279   }
    280 
    281   int rPort;
    282   printf("Specify remote port (1=1234): ");
    283   ASSERT_EQ(1, scanf("%i", &rPort));
    284   if (1 == rPort)
    285     rPort = 1234;
    286   printf("Set Send port \n");
    287 
    288   printf("Set Send IP \n");
    289   res = voice_channel_transport->SetSendDestination(ip, rPort);
    290   VALIDATE;
    291 
    292   int lPort;
    293   printf("Specify local port (1=1234): ");
    294   ASSERT_EQ(1, scanf("%i", &lPort));
    295   if (1 == lPort)
    296     lPort = 1234;
    297   printf("Set Rec Port \n");
    298 
    299   res = voice_channel_transport->SetLocalReceiver(lPort);
    300   VALIDATE;
    301 
    302   printf("\n");
    303   PrintCodecs(opus_stereo);
    304   printf("Select send codec: ");
    305   int codec_selection;
    306   ASSERT_EQ(1, scanf("%i", &codec_selection));
    307   codec->GetCodec(codec_selection, cinst);
    308 
    309   printf("Set primary codec\n");
    310   SetStereoIfOpus(opus_stereo, &cinst);
    311   res = codec->SetSendCodec(chan, cinst);
    312   VALIDATE;
    313 
    314   const int kMaxNumChannels = 8;
    315   int channel_index = 0;
    316   std::vector<int> channels(kMaxNumChannels);
    317   std::vector<VoiceChannelTransport*> voice_channel_transports(kMaxNumChannels);
    318 
    319   for (int i = 0; i < kMaxNumChannels; ++i) {
    320     channels[i] = base1->CreateChannel();
    321     int port = rPort + (i + 1) * 2;
    322 
    323     voice_channel_transports[i] = new VoiceChannelTransport(netw, channels[i]);
    324 
    325     res = voice_channel_transports[i]->SetSendDestination(ip, port);
    326     VALIDATE;
    327     res = voice_channel_transports[i]->SetLocalReceiver(port);
    328     VALIDATE;
    329     res = codec->SetSendCodec(channels[i], cinst);
    330     VALIDATE;
    331   }
    332 
    333   // Call loop
    334   bool newcall = true;
    335   while (newcall) {
    336     int rd(-1), pd(-1);
    337     res = hardware->GetNumOfRecordingDevices(rd);
    338     VALIDATE;
    339     res = hardware->GetNumOfPlayoutDevices(pd);
    340     VALIDATE;
    341 
    342     char dn[128] = { 0 };
    343     char guid[128] = { 0 };
    344     printf("\nPlayout devices (%d): \n", pd);
    345     for (int j = 0; j < pd; ++j) {
    346       res = hardware->GetPlayoutDeviceName(j, dn, guid);
    347       VALIDATE;
    348       printf("  %d: %s \n", j, dn);
    349     }
    350 
    351     printf("Recording devices (%d): \n", rd);
    352     for (int j = 0; j < rd; ++j) {
    353       res = hardware->GetRecordingDeviceName(j, dn, guid);
    354       VALIDATE;
    355       printf("  %d: %s \n", j, dn);
    356     }
    357 
    358     printf("Select playout device: ");
    359     ASSERT_EQ(1, scanf("%d", &pd));
    360     res = hardware->SetPlayoutDevice(pd);
    361     VALIDATE;
    362     printf("Select recording device: ");
    363     ASSERT_EQ(1, scanf("%d", &rd));
    364     printf("Setting sound devices \n");
    365     res = hardware->SetRecordingDevice(rd);
    366     VALIDATE;
    367 
    368     res = codec->SetVADStatus(0, enable_cng);
    369     VALIDATE;
    370 
    371     res = apm->SetAgcStatus(enable_agc);
    372     VALIDATE;
    373 
    374     res = apm->SetEcStatus(enable_aec);
    375     VALIDATE;
    376 
    377     res = apm->SetNsStatus(enable_ns);
    378     VALIDATE;
    379 
    380     printf("\n1. Send, listen and playout \n");
    381     printf("2. Send only \n");
    382     printf("3. Listen and playout only \n");
    383     printf("Select transfer mode: ");
    384     int call_selection;
    385     ASSERT_EQ(1, scanf("%i", &call_selection));
    386     const bool send = !(call_selection == 3);
    387     const bool receive = !(call_selection == 2);
    388 
    389     if (receive) {
    390 #ifndef EXTERNAL_TRANSPORT
    391       printf("Start Listen \n");
    392       res = base1->StartReceive(chan);
    393       VALIDATE;
    394 #endif
    395 
    396       printf("Start Playout \n");
    397       res = base1->StartPlayout(chan);
    398       VALIDATE;
    399     }
    400 
    401     if (send) {
    402       printf("Start Send \n");
    403       res = base1->StartSend(chan);
    404       VALIDATE;
    405     }
    406 
    407     printf("Getting mic volume \n");
    408     unsigned int vol = 999;
    409     res = volume->GetMicVolume(vol);
    410     VALIDATE;
    411     if ((vol > 255) || (vol < 1)) {
    412       printf("\n****ERROR in GetMicVolume");
    413     }
    414 
    415     int forever = 1;
    416     while (forever) {
    417       printf("\nSelect codec\n");
    418       PrintCodecs(opus_stereo);
    419       printf("\nOther actions\n");
    420       const int num_codecs = codec->NumOfCodecs();
    421       int option_index = num_codecs;
    422       printf("%i. Toggle CNG\n", option_index++);
    423       printf("%i. Toggle AGC\n", option_index++);
    424       printf("%i. Toggle NS\n", option_index++);
    425       printf("%i. Toggle experimental NS\n", option_index++);
    426       printf("%i. Toggle EC\n", option_index++);
    427       printf("%i. Select AEC\n", option_index++);
    428       printf("%i. Select AECM\n", option_index++);
    429       printf("%i. Get speaker volume\n", option_index++);
    430       printf("%i. Set speaker volume\n", option_index++);
    431       printf("%i. Get microphone volume\n", option_index++);
    432       printf("%i. Set microphone volume\n", option_index++);
    433       printf("%i. Play local file (audio_long16.pcm) \n", option_index++);
    434       printf("%i. Change playout device \n", option_index++);
    435       printf("%i. Change recording device \n", option_index++);
    436       printf("%i. Toggle receive-side AGC \n", option_index++);
    437       printf("%i. Toggle receive-side NS \n", option_index++);
    438       printf("%i. AGC status \n", option_index++);
    439       printf("%i. Toggle microphone mute \n", option_index++);
    440       printf("%i. Get last error code \n", option_index++);
    441       printf("%i. Toggle typing detection \n",
    442              option_index++);
    443       printf("%i. Record a PCM file \n", option_index++);
    444       printf("%i. Play a previously recorded PCM file locally \n",
    445              option_index++);
    446       printf("%i. Play a previously recorded PCM file as microphone \n",
    447              option_index++);
    448       printf("%i. Add an additional file-playing channel \n", option_index++);
    449       printf("%i. Remove a file-playing channel \n", option_index++);
    450       printf("%i. Toggle Opus stereo (Opus must be selected again to apply "
    451              "the setting) \n", option_index++);
    452       printf("%i. Set Opus maximum playback rate \n", option_index++);
    453       printf("%i. Toggle Opus DTX \n", option_index++);
    454       printf("%i. Set bit rate (only take effect on codecs that allow the "
    455              "change) \n", option_index++);
    456       printf("%i. Toggle AECdump recording \n", option_index++);
    457       printf("%i. Record RtcEventLog file of 30 seconds \n", option_index++);
    458 
    459       printf("Select action or %i to stop the call: ", option_index);
    460       int option_selection;
    461       ASSERT_EQ(1, scanf("%i", &option_selection));
    462 
    463       option_index = num_codecs;
    464       if (option_selection < option_index) {
    465         res = codec->GetCodec(option_selection, cinst);
    466         VALIDATE;
    467         if (strcmp(cinst.plname, "red") == 0) {
    468           printf("Enabling RED\n");
    469           res = rtp_rtcp->SetREDStatus(chan, true, cinst.pltype);
    470         } else {
    471           SetStereoIfOpus(opus_stereo, &cinst);
    472           printf("Set primary codec\n");
    473           res = codec->SetSendCodec(chan, cinst);
    474         }
    475         VALIDATE;
    476       } else if (option_selection == option_index++) {
    477         enable_cng = !enable_cng;
    478         res = codec->SetVADStatus(0, enable_cng);
    479         VALIDATE;
    480         if (enable_cng)
    481           printf("\n CNG is now on! \n");
    482         else
    483           printf("\n CNG is now off! \n");
    484       } else if (option_selection == option_index++) {
    485         enable_agc = !enable_agc;
    486         res = apm->SetAgcStatus(enable_agc);
    487         VALIDATE;
    488         if (enable_agc)
    489           printf("\n AGC is now on! \n");
    490         else
    491           printf("\n AGC is now off! \n");
    492       } else if (option_selection == option_index++) {
    493         enable_ns = !enable_ns;
    494         res = apm->SetNsStatus(enable_ns);
    495         VALIDATE;
    496         if (enable_ns)
    497           printf("\n NS is now on! \n");
    498         else
    499           printf("\n NS is now off! \n");
    500       } else if (option_selection == option_index++) {
    501         experimental_ns_enabled = !experimental_ns_enabled;
    502         Config config;
    503         config.Set<ExperimentalNs>(new ExperimentalNs(experimental_ns_enabled));
    504         base1->audio_processing()->SetExtraOptions(config);
    505         if (experimental_ns_enabled) {
    506           printf("\n Experimental NS is now on!\n");
    507         } else {
    508           printf("\n Experimental NS is now off!\n");
    509         }
    510       } else if (option_selection == option_index++) {
    511         enable_aec = !enable_aec;
    512         res = apm->SetEcStatus(enable_aec, kEcUnchanged);
    513         VALIDATE;
    514         if (enable_aec)
    515           printf("\n Echo control is now on! \n");
    516         else
    517           printf("\n Echo control is now off! \n");
    518       } else if (option_selection == option_index++) {
    519         res = apm->SetEcStatus(enable_aec, kEcAec);
    520         VALIDATE;
    521         printf("\n AEC selected! \n");
    522         if (enable_aec)
    523           printf(" (Echo control is on)\n");
    524         else
    525           printf(" (Echo control is off)\n");
    526       } else if (option_selection == option_index++) {
    527         res = apm->SetEcStatus(enable_aec, kEcAecm);
    528         VALIDATE;
    529         printf("\n AECM selected! \n");
    530         if (enable_aec)
    531           printf(" (Echo control is on)\n");
    532         else
    533           printf(" (Echo control is off)\n");
    534       } else if (option_selection == option_index++) {
    535         unsigned vol(0);
    536         res = volume->GetSpeakerVolume(vol);
    537         VALIDATE;
    538         printf("\n Speaker Volume is %d \n", vol);
    539       } else if (option_selection == option_index++) {
    540         printf("Level: ");
    541         int level;
    542         ASSERT_EQ(1, scanf("%i", &level));
    543         res = volume->SetSpeakerVolume(level);
    544         VALIDATE;
    545       } else if (option_selection == option_index++) {
    546         unsigned vol(0);
    547         res = volume->GetMicVolume(vol);
    548         VALIDATE;
    549         printf("\n Microphone Volume is %d \n", vol);
    550       } else if (option_selection == option_index++) {
    551         printf("Level: ");
    552         int level;
    553         ASSERT_EQ(1, scanf("%i", &level));
    554         res = volume->SetMicVolume(level);
    555         VALIDATE;
    556       } else if (option_selection == option_index++) {
    557         res = file->StartPlayingFileLocally(0, audio_filename.c_str());
    558         VALIDATE;
    559       } else if (option_selection == option_index++) {
    560         // change the playout device with current call
    561         int num_pd(-1);
    562         res = hardware->GetNumOfPlayoutDevices(num_pd);
    563         VALIDATE;
    564 
    565         char dn[128] = { 0 };
    566         char guid[128] = { 0 };
    567 
    568         printf("\nPlayout devices (%d): \n", num_pd);
    569         for (int i = 0; i < num_pd; ++i) {
    570           res = hardware->GetPlayoutDeviceName(i, dn, guid);
    571           VALIDATE;
    572           printf("  %d: %s \n", i, dn);
    573         }
    574         printf("Select playout device: ");
    575         ASSERT_EQ(1, scanf("%d", &num_pd));
    576         // Will use plughw for hardware devices
    577         res = hardware->SetPlayoutDevice(num_pd);
    578         VALIDATE;
    579       } else if (option_selection == option_index++) {
    580         // change the recording device with current call
    581         int num_rd(-1);
    582 
    583         res = hardware->GetNumOfRecordingDevices(num_rd);
    584         VALIDATE;
    585 
    586         char dn[128] = { 0 };
    587         char guid[128] = { 0 };
    588 
    589         printf("Recording devices (%d): \n", num_rd);
    590         for (int i = 0; i < num_rd; ++i) {
    591           res = hardware->GetRecordingDeviceName(i, dn, guid);
    592           VALIDATE;
    593           printf("  %d: %s \n", i, dn);
    594         }
    595 
    596         printf("Select recording device: ");
    597         ASSERT_EQ(1, scanf("%d", &num_rd));
    598         printf("Setting sound devices \n");
    599         // Will use plughw for hardware devices
    600         res = hardware->SetRecordingDevice(num_rd);
    601         VALIDATE;
    602       } else if (option_selection == option_index++) {
    603         // Remote AGC
    604         enable_rx_agc = !enable_rx_agc;
    605         res = apm->SetRxAgcStatus(chan, enable_rx_agc);
    606         VALIDATE;
    607         if (enable_rx_agc)
    608           printf("\n Receive-side AGC is now on! \n");
    609         else
    610           printf("\n Receive-side AGC is now off! \n");
    611       } else if (option_selection == option_index++) {
    612         // Remote NS
    613         enable_rx_ns = !enable_rx_ns;
    614         res = apm->SetRxNsStatus(chan, enable_rx_ns);
    615         VALIDATE;
    616         if (enable_rx_ns)
    617           printf("\n Receive-side NS is now on! \n");
    618         else
    619           printf("\n Receive-side NS is now off! \n");
    620       } else if (option_selection == option_index++) {
    621         AgcModes agcmode;
    622         bool enable;
    623         res = apm->GetAgcStatus(enable, agcmode);
    624         VALIDATE
    625             printf("\n AGC enable is %d, mode is %d \n", enable, agcmode);
    626       } else if (option_selection == option_index++) {
    627         // Toggle Mute on Microphone
    628         res = volume->GetInputMute(chan, muted);
    629         VALIDATE;
    630         muted = !muted;
    631         res = volume->SetInputMute(chan, muted);
    632         VALIDATE;
    633         if (muted)
    634           printf("\n Microphone is now on mute! \n");
    635         else
    636           printf("\n Microphone is no longer on mute! \n");
    637       } else if (option_selection == option_index++) {
    638         // Get the last error code and print to screen
    639         int err_code = 0;
    640         err_code = base1->LastError();
    641         if (err_code != -1)
    642           printf("\n The last error code was %i.\n", err_code);
    643       } else if (option_selection == option_index++) {
    644         typing_detection= !typing_detection;
    645         res = apm->SetTypingDetectionStatus(typing_detection);
    646         VALIDATE;
    647         if (typing_detection)
    648           printf("\n Typing detection is now on!\n");
    649         else
    650           printf("\n Typing detection is now off!\n");
    651       } else if (option_selection == option_index++) {
    652         int stop_record = 1;
    653         int file_source = 1;
    654         printf("\n Select source of recorded file. ");
    655         printf("\n 1. Record from microphone to file ");
    656         printf("\n 2. Record from playout to file ");
    657         printf("\n Enter your selection: \n");
    658         ASSERT_EQ(1, scanf("%i", &file_source));
    659         if (file_source == 1) {
    660           printf("\n Start recording microphone as %s \n",
    661                  mic_filename.c_str());
    662           res = file->StartRecordingMicrophone(mic_filename.c_str());
    663           VALIDATE;
    664         } else {
    665           printf("\n Start recording playout as %s \n", play_filename.c_str());
    666           res = file->StartRecordingPlayout(chan, play_filename.c_str());
    667           VALIDATE;
    668         }
    669         while (stop_record != 0) {
    670           printf("\n Type 0 to stop recording file \n");
    671           ASSERT_EQ(1, scanf("%i", &stop_record));
    672         }
    673         if (file_source == 1) {
    674           res = file->StopRecordingMicrophone();
    675           VALIDATE;
    676         } else {
    677           res = file->StopRecordingPlayout(chan);
    678           VALIDATE;
    679         }
    680         printf("\n File finished recording \n");
    681       } else if (option_selection == option_index++) {
    682         int file_type = 1;
    683         int stop_play = 1;
    684         printf("\n Select a file to play locally in a loop.");
    685         printf("\n 1. Play %s", mic_filename.c_str());
    686         printf("\n 2. Play %s", play_filename.c_str());
    687         printf("\n Enter your selection\n");
    688         ASSERT_EQ(1, scanf("%i", &file_type));
    689         if (file_type == 1)  {
    690           printf("\n Start playing %s locally in a loop\n",
    691                  mic_filename.c_str());
    692           res = file->StartPlayingFileLocally(chan, mic_filename.c_str(), true);
    693           VALIDATE;
    694         } else {
    695           printf("\n Start playing %s locally in a loop\n",
    696                  play_filename.c_str());
    697           res = file->StartPlayingFileLocally(chan, play_filename.c_str(),
    698                                               true);
    699           VALIDATE;
    700         }
    701         while (stop_play != 0) {
    702           printf("\n Type 0 to stop playing file\n");
    703           ASSERT_EQ(1, scanf("%i", &stop_play));
    704         }
    705         res = file->StopPlayingFileLocally(chan);
    706         VALIDATE;
    707       } else if (option_selection == option_index++) {
    708         int file_type = 1;
    709         int stop_play = 1;
    710         printf("\n Select a file to play as microphone in a loop.");
    711         printf("\n 1. Play %s", mic_filename.c_str());
    712         printf("\n 2. Play %s", play_filename.c_str());
    713         printf("\n Enter your selection\n");
    714         ASSERT_EQ(1, scanf("%i", &file_type));
    715         if (file_type == 1)  {
    716           printf("\n Start playing %s as mic in a loop\n",
    717                  mic_filename.c_str());
    718           res = file->StartPlayingFileAsMicrophone(chan, mic_filename.c_str(),
    719                                                    true);
    720           VALIDATE;
    721         } else {
    722           printf("\n Start playing %s as mic in a loop\n",
    723                  play_filename.c_str());
    724           res = file->StartPlayingFileAsMicrophone(chan, play_filename.c_str(),
    725                                                    true);
    726           VALIDATE;
    727         }
    728         while (stop_play != 0) {
    729           printf("\n Type 0 to stop playing file\n");
    730           ASSERT_EQ(1, scanf("%i", &stop_play));
    731         }
    732         res = file->StopPlayingFileAsMicrophone(chan);
    733         VALIDATE;
    734       } else if (option_selection == option_index++) {
    735         if (channel_index < kMaxNumChannels) {
    736           res = base1->StartReceive(channels[channel_index]);
    737           VALIDATE;
    738           res = base1->StartPlayout(channels[channel_index]);
    739           VALIDATE;
    740           res = base1->StartSend(channels[channel_index]);
    741           VALIDATE;
    742           res = file->StartPlayingFileAsMicrophone(channels[channel_index],
    743                                                    audio_filename.c_str(),
    744                                                    true,
    745                                                    false);
    746           VALIDATE;
    747           channel_index++;
    748           printf("Using %d additional channels\n", channel_index);
    749         } else {
    750           printf("Max number of channels reached\n");
    751         }
    752       } else if (option_selection == option_index++) {
    753         if (channel_index > 0) {
    754           channel_index--;
    755           res = file->StopPlayingFileAsMicrophone(channels[channel_index]);
    756           VALIDATE;
    757           res = base1->StopSend(channels[channel_index]);
    758           VALIDATE;
    759           res = base1->StopPlayout(channels[channel_index]);
    760           VALIDATE;
    761           res = base1->StopReceive(channels[channel_index]);
    762           VALIDATE;
    763           printf("Using %d additional channels\n", channel_index);
    764         } else {
    765           printf("All additional channels stopped\n");
    766         }
    767       } else if (option_selection == option_index++) {
    768         opus_stereo = !opus_stereo;
    769         if (opus_stereo)
    770           printf("\n Opus stereo enabled (select Opus again to apply the "
    771                  "setting). \n");
    772         else
    773           printf("\n Opus mono enabled (select Opus again to apply the "
    774                  "setting). \n");
    775       } else if (option_selection == option_index++) {
    776         printf("\n Input maxium playback rate in Hz: ");
    777         int max_playback_rate;
    778         ASSERT_EQ(1, scanf("%i", &max_playback_rate));
    779         res = codec->SetOpusMaxPlaybackRate(chan, max_playback_rate);
    780         VALIDATE;
    781       } else if (option_selection == option_index++) {
    782         opus_dtx = !opus_dtx;
    783         res = codec->SetOpusDtx(chan, opus_dtx);
    784         VALIDATE;
    785         printf("Opus DTX %s.\n", opus_dtx ? "enabled" : "disabled");
    786       } else if (option_selection == option_index++) {
    787         res = codec->GetSendCodec(chan, cinst);
    788         VALIDATE;
    789         printf("Current bit rate is %i bps, set to: ", cinst.rate);
    790         int new_bitrate_bps;
    791         ASSERT_EQ(1, scanf("%i", &new_bitrate_bps));
    792         res = codec->SetBitRate(chan, new_bitrate_bps);
    793         VALIDATE;
    794       } else if (option_selection == option_index++) {
    795         const char* kDebugFileName = "audio.aecdump";
    796         if (debug_recording_started) {
    797           apm->StopDebugRecording();
    798           printf("Debug recording named %s stopped\n", kDebugFileName);
    799         } else {
    800           apm->StartDebugRecording(kDebugFileName);
    801           printf("Debug recording named %s started\n", kDebugFileName);
    802         }
    803         debug_recording_started = !debug_recording_started;
    804       } else if (option_selection == option_index++) {
    805         const char* kDebugFileName = "eventlog.rel";
    806         codec->GetEventLog()->StartLogging(kDebugFileName, 30000);
    807       } else {
    808         break;
    809       }
    810     }
    811 
    812     if (debug_recording_started) {
    813       apm->StopDebugRecording();
    814     }
    815 
    816     if (send) {
    817       printf("Stop Send \n");
    818       res = base1->StopSend(chan);
    819       VALIDATE;
    820     }
    821 
    822     if (receive) {
    823       printf("Stop Playout \n");
    824       res = base1->StopPlayout(chan);
    825       VALIDATE;
    826 
    827 #ifndef EXTERNAL_TRANSPORT
    828       printf("Stop Listen \n");
    829       res = base1->StopReceive(chan);
    830       VALIDATE;
    831 #endif
    832     }
    833 
    834     while (channel_index > 0) {
    835       --channel_index;
    836       res = file->StopPlayingFileAsMicrophone(channels[channel_index]);
    837       VALIDATE;
    838       res = base1->StopSend(channels[channel_index]);
    839       VALIDATE;
    840       res = base1->StopPlayout(channels[channel_index]);
    841       VALIDATE;
    842       res = base1->StopReceive(channels[channel_index]);
    843       VALIDATE;
    844     }
    845 
    846     printf("\n1. New call \n");
    847     printf("2. Quit \n");
    848     printf("Select action: ");
    849     int end_option;
    850     ASSERT_EQ(1, scanf("%i", &end_option));
    851     newcall = (end_option == 1);
    852     // Call loop
    853   }
    854 
    855   // Transports should be deleted before channel deletion.
    856   delete voice_channel_transport;
    857   for (int i = 0; i < kMaxNumChannels; ++i) {
    858     delete voice_channel_transports[i];
    859     voice_channel_transports[i] = NULL;
    860   }
    861 
    862   printf("Delete channels \n");
    863   res = base1->DeleteChannel(chan);
    864   VALIDATE;
    865 
    866   for (int i = 0; i < kMaxNumChannels; ++i) {
    867     res = base1->DeleteChannel(channels[i]);
    868     VALIDATE;
    869   }
    870 }
    871