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