• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #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 
CallbackOnError(int channel,int err_code)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 
SetStereoIfOpus(bool use_stereo,CodecInst * codec_params)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 
PrintCodecs(bool opus_stereo)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 
main(int argc,char ** argv)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 
RunTest(std::string out_path)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