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 <limits.h>
12#include <stdarg.h>
13#include <stdio.h>
14
15#include <algorithm>
16
17#include "gflags/gflags.h"
18#include "webrtc/system_wrappers/interface/scoped_ptr.h"
19#include "webrtc/test/channel_transport/include/channel_transport.h"
20#include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h"
21#include "webrtc/video_engine/test/auto_test/interface/vie_autotest_defines.h"
22#include "webrtc/video_engine/test/auto_test/primitives/choice_helpers.h"
23#include "webrtc/video_engine/test/auto_test/primitives/general_primitives.h"
24#include "webrtc/video_engine/test/auto_test/primitives/input_helpers.h"
25#include "webrtc/video_engine/test/libvietest/include/vie_to_file_renderer.h"
26#include "webrtc/voice_engine/include/voe_network.h"
27
28#define VCM_RED_PAYLOAD_TYPE                            96
29#define VCM_ULPFEC_PAYLOAD_TYPE                         97
30#define DEFAULT_SEND_IP                                 "127.0.0.1"
31#define DEFAULT_VIDEO_PORT                              "11111"
32#define DEFAULT_VIDEO_CODEC                             "VP8"
33#define DEFAULT_VIDEO_CODEC_WIDTH                       "640"
34#define DEFAULT_VIDEO_CODEC_HEIGHT                      "480"
35#define DEFAULT_VIDEO_CODEC_BITRATE                     "300"
36#define DEFAULT_VIDEO_CODEC_MIN_BITRATE                 "100"
37#define DEFAULT_VIDEO_CODEC_MAX_BITRATE                 "1000"
38#define DEFAULT_AUDIO_PORT                              "11113"
39#define DEFAULT_AUDIO_CODEC                             "ISAC"
40#define DEFAULT_VIDEO_CODEC_MAX_FRAMERATE               "30"
41#define DEFAULT_VIDEO_PROTECTION_METHOD                 "None"
42#define DEFAULT_TEMPORAL_LAYER                          "0"
43#define DEFAULT_BUFFERING_DELAY_MS                      "0"
44
45DEFINE_string(render_custom_call_remote_to, "", "Specify to render the remote "
46    "stream of a custom call to the provided filename instead of showing it in "
47    "window 2. The file will end up in the default output directory (out/).");
48
49enum StatisticsType {
50  kSendStatistic,
51  kReceivedStatistic
52};
53
54enum VideoProtectionMethod {
55  kProtectionMethodNone = 1,
56  kProtectionMethodFecOnly,
57  kProtectionMethodNackOnly,
58  kProtectionMethodHybridNackAndFec,
59};
60
61using webrtc::FromChoices;
62using webrtc::TypedInput;
63
64class ViEAutotestEncoderObserver : public webrtc::ViEEncoderObserver {
65 public:
66  ViEAutotestEncoderObserver() {}
67  ~ViEAutotestEncoderObserver() {}
68
69  void OutgoingRate(const int video_channel,
70                    const unsigned int framerate,
71                    const unsigned int bitrate) {
72    std::cout << "Send FR: " << framerate
73              << " BR: " << bitrate << std::endl;
74  }
75
76  virtual void SuspendChange(int video_channel, bool is_suspended) OVERRIDE {
77    std::cout << "SuspendChange: " << is_suspended << std::endl;
78  }
79};
80
81class ViEAutotestDecoderObserver : public webrtc::ViEDecoderObserver {
82 public:
83  ViEAutotestDecoderObserver() {}
84  ~ViEAutotestDecoderObserver() {}
85
86  void IncomingRate(const int video_channel,
87                    const unsigned int framerate,
88                    const unsigned int bitrate) {
89    std::cout << "Received FR: " << framerate
90              << " BR: " << bitrate << std::endl;
91  }
92
93  virtual void DecoderTiming(int decode_ms,
94                             int max_decode_ms,
95                             int current_delay_ms,
96                             int target_delay_ms,
97                             int jitter_buffer_ms,
98                             int min_playout_delay_ms,
99                             int render_delay_ms) {
100    std::cout << "Decoder timing: DecodeMS: " << decode_ms
101              << ", MaxDecodeMS: " << max_decode_ms
102              << ", CurrentDelayMS: " << current_delay_ms
103              << ", TargetDelayMS: " << target_delay_ms
104              << ", JitterBufferMS: " << jitter_buffer_ms
105              << ", MinPlayoutDelayMS: " << min_playout_delay_ms
106              << ", RenderDelayMS: " << render_delay_ms;
107  }
108
109  void IncomingCodecChanged(const int video_channel,
110                            const webrtc::VideoCodec& codec) {}
111  void RequestNewKeyFrame(const int video_channel) {
112    std::cout << "Decoder requesting a new key frame." << std::endl;
113  }
114};
115
116// The following are general helper functions.
117bool GetVideoDevice(webrtc::ViEBase* vie_base,
118                    webrtc::ViECapture* vie_capture,
119                    char* capture_device_name, char* capture_device_unique_id);
120std::string GetIPAddress();
121bool ValidateIP(std::string i_str);
122
123// The following are Print to stdout functions.
124void PrintCallInformation(const char* IP,
125                          const char* video_capture_device_name,
126                          const char* video_capture_unique_id,
127                          webrtc::VideoCodec video_codec,
128                          int video_tx_port,
129                          int video_rx_port,
130                          const char* audio_capture_device_name,
131                          const char* audio_playbackDeviceName,
132                          webrtc::CodecInst audio_codec,
133                          int audio_tx_port,
134                          int audio_rx_port,
135                          int protection_method);
136void PrintRTCCPStatistics(webrtc::ViERTP_RTCP* vie_rtp_rtcp,
137                          int video_channel,
138                          StatisticsType stat_type);
139void PrintRTPStatistics(webrtc::ViERTP_RTCP* vie_rtp_rtcp,
140                        int video_channel);
141void PrintBandwidthUsage(webrtc::ViERTP_RTCP* vie_rtp_rtcp,
142                         int video_channel);
143void PrintCodecStatistics(webrtc::ViECodec* vie_codec,
144                          int video_channel,
145                          StatisticsType stat_type);
146void PrintGetDiscardedPackets(webrtc::ViECodec* vie_codec,
147                              int video_channel);
148void PrintVideoStreamInformation(webrtc::ViECodec* vie_codec,
149                                 int video_channel);
150void PrintVideoCodec(webrtc::VideoCodec video_codec);
151
152// The following are video functions.
153void GetVideoPorts(int* tx_port, int* rx_port);
154void SetVideoCodecType(webrtc::ViECodec* vie_codec,
155                       webrtc::VideoCodec* video_codec);
156void SetVideoCodecResolution(webrtc::VideoCodec* video_codec);
157void SetVideoCodecSize(webrtc::VideoCodec* video_codec);
158void SetVideoCodecBitrate(webrtc::VideoCodec* video_codec);
159void SetVideoCodecMinBitrate(webrtc::VideoCodec* video_codec);
160void SetVideoCodecMaxBitrate(webrtc::VideoCodec* video_codec);
161void SetVideoCodecMaxFramerate(webrtc::VideoCodec* video_codec);
162void SetVideoCodecTemporalLayer(webrtc::VideoCodec* video_codec);
163VideoProtectionMethod GetVideoProtection();
164bool SetVideoProtection(webrtc::ViECodec* vie_codec,
165                        webrtc::ViERTP_RTCP* vie_rtp_rtcp,
166                        int video_channel,
167                        VideoProtectionMethod protection_method);
168bool GetBitrateSignaling();
169int GetBufferingDelay();
170
171// The following are audio helper functions.
172bool GetAudioDevices(webrtc::VoEBase* voe_base,
173                     webrtc::VoEHardware* voe_hardware,
174                     char* recording_device_name, int& recording_device_index,
175                     char* playback_device_name, int& playback_device_index);
176bool GetAudioDevices(webrtc::VoEBase* voe_base,
177                     webrtc::VoEHardware* voe_hardware,
178                     int& recording_device_index, int& playback_device_index);
179void GetAudioPorts(int* tx_port, int* rx_port);
180bool GetAudioCodec(webrtc::VoECodec* voe_codec,
181                   webrtc::CodecInst& audio_codec);
182
183int ViEAutoTest::ViECustomCall() {
184  ViETest::Log(" ");
185  ViETest::Log("========================================");
186  ViETest::Log(" Enter values to use custom settings\n");
187
188  int error = 0;
189  int number_of_errors = 0;
190  std::string str;
191
192  // Create the VoE and get the VoE interfaces.
193  webrtc::VoiceEngine* voe = webrtc::VoiceEngine::Create();
194  number_of_errors += ViETest::TestError(voe != NULL, "ERROR: %s at line %d",
195                                         __FUNCTION__, __LINE__);
196
197  webrtc::VoEBase* voe_base = webrtc::VoEBase::GetInterface(voe);
198  number_of_errors += ViETest::TestError(voe_base != NULL,
199                                         "ERROR: %s at line %d", __FUNCTION__,
200                                         __LINE__);
201
202  error = voe_base->Init();
203  number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
204                                         __FUNCTION__, __LINE__);
205
206  webrtc::VoECodec* voe_codec = webrtc::VoECodec::GetInterface(voe);
207  number_of_errors += ViETest::TestError(voe_codec != NULL,
208                                         "ERROR: %s at line %d", __FUNCTION__,
209                                         __LINE__);
210
211  webrtc::VoEHardware* voe_hardware =
212      webrtc::VoEHardware::GetInterface(voe);
213  number_of_errors += ViETest::TestError(voe_hardware != NULL,
214                                         "ERROR: %s at line %d", __FUNCTION__,
215                                         __LINE__);
216
217  webrtc::VoENetwork* voe_network=
218      webrtc::VoENetwork::GetInterface(voe);
219  number_of_errors += ViETest::TestError(voe_network != NULL,
220                                         "ERROR: %s at line %d", __FUNCTION__,
221                                         __LINE__);
222
223  webrtc::VoEAudioProcessing* voe_apm =
224      webrtc::VoEAudioProcessing::GetInterface(voe);
225  number_of_errors += ViETest::TestError(voe_apm != NULL,
226                                         "ERROR: %s at line %d", __FUNCTION__,
227                                         __LINE__);
228
229  // Create the ViE and get the ViE Interfaces.
230  webrtc::VideoEngine* vie = webrtc::VideoEngine::Create();
231  number_of_errors += ViETest::TestError(vie != NULL,
232                                         "ERROR: %s at line %d", __FUNCTION__,
233                                         __LINE__);
234
235  webrtc::ViEBase* vie_base = webrtc::ViEBase::GetInterface(vie);
236  number_of_errors += ViETest::TestError(vie_base != NULL,
237                                         "ERROR: %s at line %d", __FUNCTION__,
238                                         __LINE__);
239
240  error = vie_base->Init();
241  number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
242                                         __FUNCTION__, __LINE__);
243
244  webrtc::ViECapture* vie_capture =
245      webrtc::ViECapture::GetInterface(vie);
246  number_of_errors += ViETest::TestError(vie_capture != NULL,
247                                         "ERROR: %s at line %d", __FUNCTION__,
248                                         __LINE__);
249
250  webrtc::ViERender* vie_renderer = webrtc::ViERender::GetInterface(vie);
251  number_of_errors += ViETest::TestError(vie_renderer != NULL,
252                                         "ERROR: %s at line %d", __FUNCTION__,
253                                         __LINE__);
254
255  webrtc::ViECodec* vie_codec = webrtc::ViECodec::GetInterface(vie);
256  number_of_errors += ViETest::TestError(vie_codec != NULL,
257                                         "ERROR: %s at line %d", __FUNCTION__,
258                                         __LINE__);
259
260  webrtc::ViENetwork* vie_network = webrtc::ViENetwork::GetInterface(vie);
261  number_of_errors += ViETest::TestError(vie_network != NULL,
262                                         "ERROR: %s at line %d", __FUNCTION__,
263                                         __LINE__);
264
265  bool start_call = false;
266  std::string ip_address;
267  const unsigned int KMaxUniqueIdLength = 256;
268  char unique_id[KMaxUniqueIdLength] = "";
269  char device_name[KMaxUniqueIdLength] = "";
270  int video_tx_port = 0;
271  int video_rx_port = 0;
272  int video_channel = -1;
273  webrtc::VideoCodec video_send_codec;
274  char audio_capture_device_name[KMaxUniqueIdLength] = "";
275  char audio_playbackDeviceName[KMaxUniqueIdLength] = "";
276  int audio_capture_device_index = -1;
277  int audio_playback_device_index = -1;
278  int audio_tx_port = 0;
279  int audio_rx_port = 0;
280  webrtc::CodecInst audio_codec;
281  int audio_channel = -1;
282  VideoProtectionMethod protection_method = kProtectionMethodNone;
283  int buffer_delay_ms = 0;
284  bool is_image_scale_enabled = false;
285  bool remb = true;
286  webrtc::scoped_ptr<webrtc::test::VideoChannelTransport>
287      video_channel_transport;
288  webrtc::scoped_ptr<webrtc::test::VoiceChannelTransport>
289      voice_channel_transport;
290
291  while (!start_call) {
292    // Get the IP address to use from call.
293    ip_address = GetIPAddress();
294
295    // Get the video device to use for call.
296    memset(device_name, 0, KMaxUniqueIdLength);
297    memset(unique_id, 0, KMaxUniqueIdLength);
298    if (!GetVideoDevice(vie_base, vie_capture, device_name, unique_id))
299      return number_of_errors;
300
301    // Get and set the video ports for the call.
302    video_tx_port = 0;
303    video_rx_port = 0;
304    GetVideoPorts(&video_tx_port, &video_rx_port);
305
306    // Get and set the video codec parameters for the call.
307    memset(&video_send_codec, 0, sizeof(webrtc::VideoCodec));
308    SetVideoCodecType(vie_codec, &video_send_codec);
309    SetVideoCodecSize(&video_send_codec);
310    SetVideoCodecBitrate(&video_send_codec);
311    SetVideoCodecMinBitrate(&video_send_codec);
312    SetVideoCodecMaxBitrate(&video_send_codec);
313    SetVideoCodecMaxFramerate(&video_send_codec);
314    SetVideoCodecTemporalLayer(&video_send_codec);
315    remb = GetBitrateSignaling();
316
317    // Get the video protection method for the call.
318    protection_method = GetVideoProtection();
319
320    // Get the call mode (Real-Time/Buffered).
321    buffer_delay_ms = GetBufferingDelay();
322
323    // Get the audio device for the call.
324    memset(audio_capture_device_name, 0, KMaxUniqueIdLength);
325    memset(audio_playbackDeviceName, 0, KMaxUniqueIdLength);
326    GetAudioDevices(voe_base, voe_hardware, audio_capture_device_name,
327                    audio_capture_device_index, audio_playbackDeviceName,
328                    audio_playback_device_index);
329
330    // Get the audio port for the call.
331    audio_tx_port = 0;
332    audio_rx_port = 0;
333    GetAudioPorts(&audio_tx_port, &audio_rx_port);
334
335    // Get the audio codec for the call.
336    memset(static_cast<void*>(&audio_codec), 0, sizeof(audio_codec));
337    GetAudioCodec(voe_codec, audio_codec);
338
339    // Now ready to start the call.  Check user wants to continue.
340    PrintCallInformation(ip_address.c_str(), device_name, unique_id,
341                         video_send_codec, video_tx_port, video_rx_port,
342                         audio_capture_device_name, audio_playbackDeviceName,
343                         audio_codec, audio_tx_port, audio_rx_port,
344                         protection_method);
345
346    printf("\n");
347    int selection =
348        FromChoices("Ready to start:",
349                    "Start the call\n"
350                    "Reconfigure call settings\n")
351                        .WithDefault("Start the call").Choose();
352    start_call = (selection == 1);
353  }
354  /// **************************************************************
355  // Begin create/initialize WebRTC Video Engine for testing.
356  /// **************************************************************
357  if (start_call == true) {
358    // Configure audio channel first.
359    audio_channel = voe_base->CreateChannel();
360
361    voice_channel_transport.reset(
362        new webrtc::test::VoiceChannelTransport(voe_network, audio_channel));
363
364    error = voice_channel_transport->SetSendDestination(ip_address.c_str(),
365                                                        audio_tx_port);
366    number_of_errors += ViETest::TestError(error == 0,
367                                           "ERROR: %s at line %d",
368                                           __FUNCTION__, __LINE__);
369
370    error = voice_channel_transport->SetLocalReceiver(audio_rx_port);
371    number_of_errors += ViETest::TestError(error == 0,
372                                           "ERROR: %s at line %d",
373                                           __FUNCTION__, __LINE__);
374
375    error = voe_hardware->SetRecordingDevice(audio_capture_device_index);
376    number_of_errors += ViETest::TestError(error == 0,
377                                           "ERROR: %s at line %d",
378                                           __FUNCTION__, __LINE__);
379
380    error = voe_hardware->SetPlayoutDevice(audio_playback_device_index);
381    number_of_errors += ViETest::TestError(error == 0,
382                                           "ERROR: %s at line %d",
383                                           __FUNCTION__, __LINE__);
384
385    error = voe_codec->SetSendCodec(audio_channel, audio_codec);
386    number_of_errors += ViETest::TestError(error == 0,
387                                           "ERROR: %s at line %d",
388                                           __FUNCTION__, __LINE__);
389
390    error = voe_apm->SetAgcStatus(true, webrtc::kAgcDefault);
391    number_of_errors += ViETest::TestError(error == 0,
392                                           "ERROR: %s at line %d",
393                                           __FUNCTION__, __LINE__);
394
395    error = voe_apm->SetNsStatus(true, webrtc::kNsHighSuppression);
396    number_of_errors += ViETest::TestError(error == 0,
397                                           "ERROR: %s at line %d",
398                                           __FUNCTION__, __LINE__);
399    // Now configure the video channel.
400    error = vie->SetTraceFilter(webrtc::kTraceAll);
401    number_of_errors += ViETest::TestError(error == 0,
402                                           "ERROR: %s at line %d",
403                                           __FUNCTION__, __LINE__);
404
405    std::string trace_file =
406        ViETest::GetResultOutputPath() + "ViECustomCall_trace.txt";
407    error = vie->SetTraceFile(trace_file.c_str());
408    number_of_errors += ViETest::TestError(error == 0,
409                                           "ERROR: %s at line %d",
410                                           __FUNCTION__, __LINE__);
411
412    error = vie_base->SetVoiceEngine(voe);
413    number_of_errors += ViETest::TestError(error == 0,
414                                           "ERROR: %s at line %d",
415                                           __FUNCTION__, __LINE__);
416
417    error = vie_base->CreateChannel(video_channel);
418    number_of_errors += ViETest::TestError(error == 0,
419                                           "ERROR: %s at line %d",
420                                           __FUNCTION__, __LINE__);
421
422    error = vie_base->ConnectAudioChannel(video_channel, audio_channel);
423    number_of_errors += ViETest::TestError(error == 0,
424                                           "ERROR: %s at line %d",
425                                           __FUNCTION__, __LINE__);
426
427    int capture_id = 0;
428    error = vie_capture->AllocateCaptureDevice(unique_id,
429                                               KMaxUniqueIdLength,
430                                               capture_id);
431    number_of_errors += ViETest::TestError(error == 0,
432                                           "ERROR: %s at line %d",
433                                           __FUNCTION__, __LINE__);
434
435    error = vie_capture->ConnectCaptureDevice(capture_id, video_channel);
436    number_of_errors += ViETest::TestError(error == 0,
437                                           "ERROR: %s at line %d",
438                                           __FUNCTION__, __LINE__);
439
440    error = vie_capture->StartCapture(capture_id);
441    number_of_errors += ViETest::TestError(error == 0,
442                                           "ERROR: %s at line %d",
443                                           __FUNCTION__, __LINE__);
444
445    webrtc::ViERTP_RTCP* vie_rtp_rtcp =
446        webrtc::ViERTP_RTCP::GetInterface(vie);
447    number_of_errors += ViETest::TestError(vie != NULL,
448                                           "ERROR: %s at line %d",
449                                           __FUNCTION__, __LINE__);
450
451    error = vie_rtp_rtcp->SetRTCPStatus(video_channel,
452                                        webrtc::kRtcpCompound_RFC4585);
453    number_of_errors += ViETest::TestError(error == 0,
454                                           "ERROR: %s at line %d",
455                                           __FUNCTION__, __LINE__);
456
457    error = vie_rtp_rtcp->SetKeyFrameRequestMethod(
458        video_channel, webrtc::kViEKeyFrameRequestPliRtcp);
459    number_of_errors += ViETest::TestError(error == 0,
460                                           "ERROR: %s at line %d",
461                                           __FUNCTION__, __LINE__);
462
463    if (remb) {
464      error = vie_rtp_rtcp->SetRembStatus(video_channel, true, true);
465      number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
466                                             __FUNCTION__, __LINE__);
467    } else  {
468      error = vie_rtp_rtcp->SetTMMBRStatus(video_channel, true);
469      number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
470                                             __FUNCTION__, __LINE__);
471    }
472
473    error = vie_renderer->AddRenderer(capture_id, _window1, 0, 0.0, 0.0, 1.0,
474                                      1.0);
475    number_of_errors += ViETest::TestError(error == 0,
476                                           "ERROR: %s at line %d",
477                                           __FUNCTION__, __LINE__);
478
479
480    ViEToFileRenderer file_renderer;
481    if (FLAGS_render_custom_call_remote_to == "") {
482      error = vie_renderer->AddRenderer(video_channel, _window2, 1, 0.0, 0.0,
483                                        1.0, 1.0);
484      number_of_errors += ViETest::TestError(error == 0,
485                                             "ERROR: %s at line %d",
486                                             __FUNCTION__, __LINE__);
487    } else {
488      std::string output_path = ViETest::GetResultOutputPath();
489      std::string filename = FLAGS_render_custom_call_remote_to;
490      ViETest::Log("Rendering remote stream to %s: you will not see any output "
491          "in the second window.", (output_path + filename).c_str());
492
493      file_renderer.PrepareForRendering(output_path, filename);
494      RenderToFile(vie_renderer, video_channel, &file_renderer);
495    }
496
497    video_channel_transport.reset(
498        new webrtc::test::VideoChannelTransport(vie_network, video_channel));
499
500    error = video_channel_transport->SetSendDestination(ip_address.c_str(),
501                                                        video_tx_port);
502    number_of_errors += ViETest::TestError(error == 0,
503                                           "ERROR: %s at line %d",
504                                           __FUNCTION__, __LINE__);
505
506    error = video_channel_transport->SetLocalReceiver(video_rx_port);
507    number_of_errors += ViETest::TestError(error == 0,
508                                           "ERROR: %s at line %d",
509                                           __FUNCTION__, __LINE__);
510
511    error = vie_codec->SetSendCodec(video_channel, video_send_codec);
512    number_of_errors += ViETest::TestError(error == 0,
513                                           "ERROR: %s at line %d",
514                                           __FUNCTION__, __LINE__);
515
516    error = vie_codec->SetReceiveCodec(video_channel, video_send_codec);
517    number_of_errors += ViETest::TestError(error == 0,
518                                           "ERROR: %s at line %d",
519                                           __FUNCTION__, __LINE__);
520
521    // Set the call mode (conferencing/buffering)
522    error = vie_rtp_rtcp->SetSenderBufferingMode(video_channel,
523                                                    buffer_delay_ms);
524    number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
525                                           __FUNCTION__, __LINE__);
526    error = vie_rtp_rtcp->SetReceiverBufferingMode(video_channel,
527                                                      buffer_delay_ms);
528    number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
529                                           __FUNCTION__, __LINE__);
530    // Set the Video Protection before start send and receive.
531    SetVideoProtection(vie_codec, vie_rtp_rtcp,
532                       video_channel, protection_method);
533
534    // Start Voice Playout and Receive.
535    error = voe_base->StartReceive(audio_channel);
536    number_of_errors += ViETest::TestError(error == 0,
537                                           "ERROR: %s at line %d",
538                                           __FUNCTION__, __LINE__);
539
540    error = voe_base->StartPlayout(audio_channel);
541    number_of_errors += ViETest::TestError(error == 0,
542                                           "ERROR: %s at line %d",
543                                           __FUNCTION__, __LINE__);
544
545    error = voe_base->StartSend(audio_channel);
546    number_of_errors += ViETest::TestError(error == 0,
547                                           "ERROR: %s at line %d",
548                                           __FUNCTION__, __LINE__);
549
550    // Now start the Video Send & Receive.
551    error = vie_base->StartSend(video_channel);
552    number_of_errors += ViETest::TestError(error == 0,
553                                           "ERROR: %s at line %d",
554                                           __FUNCTION__, __LINE__);
555
556    error = vie_base->StartReceive(video_channel);
557    number_of_errors += ViETest::TestError(error == 0,
558                                           "ERROR: %s at line %d",
559                                           __FUNCTION__, __LINE__);
560
561    error = vie_renderer->StartRender(capture_id);
562    number_of_errors += ViETest::TestError(error == 0,
563                                           "ERROR: %s at line %d",
564                                           __FUNCTION__, __LINE__);
565
566    error = vie_renderer->StartRender(video_channel);
567    number_of_errors += ViETest::TestError(error == 0,
568                                           "ERROR: %s at line %d",
569                                           __FUNCTION__, __LINE__);
570
571    ViEAutotestEncoderObserver* codec_encoder_observer = NULL;
572    ViEAutotestDecoderObserver* codec_decoder_observer = NULL;
573
574    //  Engine ready, wait for input.
575
576    // Call started.
577    std::cout << std::endl;
578    std::cout << "Custom call started" << std::endl;
579
580    // Modify call or stop call.
581    printf("\n");
582    int selection = FromChoices(
583        "And now?",
584        "Stop the call\n"
585        "Modify the call\n"
586        "Keep the call running indefinitely\n")
587            .WithDefault("Keep the call running indefinitely").Choose();
588    if (selection == 3) {
589        AutoTestSleep(std::numeric_limits<int>::max());
590    }
591
592    while (selection == 2) {
593      // Keep on modifying the call until user stops the call.
594      int modify_selection = FromChoices(
595          "Modify the call:",
596          "Stop call\n"
597          "Change Video Send Codec\n"
598          "Change Video Send Size by Common Resolutions\n"
599          "Change Video Send Size by Width & Height\n"
600          "Change Video Capture Device\n"
601          "Change Video Protection Method\n"
602          "Toggle Encoder Observer\n"
603          "Toggle Decoder Observer\n"
604          "Print Call Information\n"
605          "Print Call Statistics\n"
606          "Toggle Image Scaling (Warning: high CPU usage when enabled)\n")
607              .WithDefault("Stop call")
608              .Choose();
609
610      switch (modify_selection) {
611        case 1:
612          selection = 1;
613          break;
614        case 2:
615          // Change video codec.
616          SetVideoCodecType(vie_codec, &video_send_codec);
617          SetVideoCodecSize(&video_send_codec);
618          SetVideoCodecBitrate(&video_send_codec);
619          SetVideoCodecMinBitrate(&video_send_codec);
620          SetVideoCodecMaxBitrate(&video_send_codec);
621          SetVideoCodecMaxFramerate(&video_send_codec);
622          SetVideoCodecTemporalLayer(&video_send_codec);
623          PrintCallInformation(ip_address.c_str(), device_name,
624                               unique_id, video_send_codec,
625                               video_tx_port, video_rx_port,
626                               audio_capture_device_name,
627                               audio_playbackDeviceName, audio_codec,
628                               audio_tx_port, audio_rx_port, protection_method);
629          error = vie_codec->SetSendCodec(video_channel, video_send_codec);
630          number_of_errors += ViETest::TestError(error == 0,
631                                                 "ERROR: %s at line %d",
632                                                 __FUNCTION__, __LINE__);
633          error = vie_codec->SetReceiveCodec(video_channel, video_send_codec);
634          number_of_errors += ViETest::TestError(error == 0,
635                                                 "ERROR: %s at line %d",
636                                                 __FUNCTION__, __LINE__);
637          break;
638        case 3:
639          // Change Video codec size by common resolution.
640          SetVideoCodecResolution(&video_send_codec);
641          PrintCallInformation(ip_address.c_str(), device_name,
642                               unique_id, video_send_codec,
643                               video_tx_port, video_rx_port,
644                               audio_capture_device_name,
645                               audio_playbackDeviceName, audio_codec,
646                               audio_tx_port, audio_rx_port, protection_method);
647          error = vie_codec->SetSendCodec(video_channel, video_send_codec);
648          number_of_errors += ViETest::TestError(error == 0,
649                                                 "ERROR: %s at line %d",
650                                                 __FUNCTION__, __LINE__);
651          error = vie_codec->SetReceiveCodec(video_channel, video_send_codec);
652          number_of_errors += ViETest::TestError(error == 0,
653                                                 "ERROR: %s at line %d",
654                                                 __FUNCTION__, __LINE__);
655          break;
656        case 4:
657          // Change video codec by size height and width.
658          SetVideoCodecSize(&video_send_codec);
659          PrintCallInformation(ip_address.c_str(), device_name,
660                               unique_id, video_send_codec,
661                               video_tx_port, video_rx_port,
662                               audio_capture_device_name,
663                               audio_playbackDeviceName, audio_codec,
664                               audio_tx_port, audio_rx_port, protection_method);
665          error = vie_codec->SetSendCodec(video_channel, video_send_codec);
666          number_of_errors += ViETest::TestError(error == 0,
667                                                 "ERROR: %s at line %d",
668                                                 __FUNCTION__, __LINE__);
669          error = vie_codec->SetReceiveCodec(video_channel, video_send_codec);
670          number_of_errors += ViETest::TestError(error == 0,
671                                                 "ERROR: %s at line %d",
672                                                 __FUNCTION__, __LINE__);
673          break;
674        case 5:
675          error = vie_renderer->StopRender(capture_id);
676          number_of_errors += ViETest::TestError(error == 0,
677                                                 "ERROR: %s at line %d",
678                                                 __FUNCTION__, __LINE__);
679          error = vie_renderer->RemoveRenderer(capture_id);
680          number_of_errors += ViETest::TestError(error == 0,
681                                                 "ERROR: %s at line %d",
682                                                 __FUNCTION__, __LINE__);
683          error = vie_capture->StopCapture(capture_id);
684          number_of_errors += ViETest::TestError(error == 0,
685                                                 "ERROR: %s at line %d",
686                                                 __FUNCTION__, __LINE__);
687          error = vie_capture->DisconnectCaptureDevice(video_channel);
688          number_of_errors += ViETest::TestError(error == 0,
689                                                 "ERROR: %s at line %d",
690                                                 __FUNCTION__, __LINE__);
691          error = vie_capture->ReleaseCaptureDevice(capture_id);
692          number_of_errors += ViETest::TestError(error == 0,
693                                                 "ERROR: %s at line %d",
694                                                 __FUNCTION__, __LINE__);
695          memset(device_name, 0, KMaxUniqueIdLength);
696          memset(unique_id, 0, KMaxUniqueIdLength);
697          if (!GetVideoDevice(vie_base, vie_capture, device_name, unique_id))
698            return number_of_errors;
699          capture_id = 0;
700          error = vie_capture->AllocateCaptureDevice(unique_id,
701                                                     KMaxUniqueIdLength,
702                                                     capture_id);
703          number_of_errors += ViETest::TestError(error == 0,
704                                                 "ERROR: %s at line %d",
705                                                 __FUNCTION__, __LINE__);
706          error = vie_capture->ConnectCaptureDevice(capture_id,
707                                                    video_channel);
708          number_of_errors += ViETest::TestError(error == 0,
709                                                 "ERROR: %s at line %d",
710                                                 __FUNCTION__, __LINE__);
711
712          assert(FLAGS_render_custom_call_remote_to == "" &&
713                 "Not implemented to change video capture device when "
714                 "rendering to file!");
715
716          error = vie_capture->StartCapture(capture_id);
717          number_of_errors += ViETest::TestError(error == 0,
718                                                 "ERROR: %s at line %d",
719                                                 __FUNCTION__, __LINE__);
720          error = vie_renderer->AddRenderer(capture_id, _window1, 0, 0.0, 0.0,
721                                            1.0, 1.0);
722          number_of_errors += ViETest::TestError(error == 0,
723                                                 "ERROR: %s at line %d",
724                                                 __FUNCTION__, __LINE__);
725          error = vie_renderer->StartRender(capture_id);
726          number_of_errors += ViETest::TestError(error == 0,
727                                                 "ERROR: %s at line %d",
728                                                 __FUNCTION__, __LINE__);
729          break;
730        case 6:
731          // Change the Video Protection.
732          protection_method = GetVideoProtection();
733          SetVideoProtection(vie_codec, vie_rtp_rtcp,
734                             video_channel, protection_method);
735          break;
736        case 7:
737          // Toggle Encoder Observer.
738          if (!codec_encoder_observer) {
739            std::cout << "Registering Encoder Observer" << std::endl;
740            codec_encoder_observer = new ViEAutotestEncoderObserver();
741            error = vie_codec->RegisterEncoderObserver(video_channel,
742                                                       *codec_encoder_observer);
743            number_of_errors += ViETest::TestError(error == 0,
744                                                   "ERROR: %s at line %d",
745                                                   __FUNCTION__, __LINE__);
746          } else {
747            std::cout << "Deregistering Encoder Observer" << std::endl;
748            error = vie_codec->DeregisterEncoderObserver(video_channel);
749            delete codec_encoder_observer;
750            codec_encoder_observer = NULL;
751            number_of_errors += ViETest::TestError(error == 0,
752                                                   "ERROR: %s at line %d",
753                                                   __FUNCTION__, __LINE__);
754          }
755          break;
756        case 8:
757          // Toggle Decoder Observer.
758          if (!codec_decoder_observer) {
759            std::cout << "Registering Decoder Observer" << std::endl;
760            codec_decoder_observer = new ViEAutotestDecoderObserver();
761            error = vie_codec->RegisterDecoderObserver(video_channel,
762                                                       *codec_decoder_observer);
763            number_of_errors += ViETest::TestError(error == 0,
764                                                   "ERROR: %s at line %d",
765                                                   __FUNCTION__, __LINE__);
766          } else {
767            std::cout << "Deregistering Decoder Observer" << std::endl;
768            error = vie_codec->DeregisterDecoderObserver(video_channel);
769            delete codec_decoder_observer;
770            codec_decoder_observer = NULL;
771            number_of_errors += ViETest::TestError(error == 0,
772                                                   "ERROR: %s at line %d",
773                                                   __FUNCTION__, __LINE__);
774          }
775          break;
776        case 9:
777          // Print Call information..
778          PrintCallInformation(ip_address.c_str(), device_name,
779                               unique_id, video_send_codec,
780                               video_tx_port, video_rx_port,
781                               audio_capture_device_name,
782                               audio_playbackDeviceName,
783                               audio_codec, audio_tx_port,
784                               audio_rx_port, protection_method);
785          PrintVideoStreamInformation(vie_codec,
786                                      video_channel);
787          break;
788        case 10:
789          // Print Call statistics.
790          PrintRTCCPStatistics(vie_rtp_rtcp, video_channel,
791                               kSendStatistic);
792          PrintRTCCPStatistics(vie_rtp_rtcp, video_channel,
793                               kReceivedStatistic);
794          PrintRTPStatistics(vie_rtp_rtcp, video_channel);
795          PrintBandwidthUsage(vie_rtp_rtcp, video_channel);
796          PrintCodecStatistics(vie_codec, video_channel,
797                               kSendStatistic);
798          PrintCodecStatistics(vie_codec, video_channel,
799                               kReceivedStatistic);
800          PrintGetDiscardedPackets(vie_codec, video_channel);
801          break;
802        case 11:
803          is_image_scale_enabled = !is_image_scale_enabled;
804          vie_codec->SetImageScaleStatus(video_channel, is_image_scale_enabled);
805          if (is_image_scale_enabled) {
806            std::cout << "Image Scale is now enabled" << std::endl;
807          } else {
808            std::cout << "Image Scale is now disabled" << std::endl;
809          }
810          break;
811        default:
812          assert(false);
813          break;
814      }
815    }
816
817    if (FLAGS_render_custom_call_remote_to != "")
818      file_renderer.StopRendering();
819
820    // Testing finished. Tear down Voice and Video Engine.
821    // Tear down the VoE first.
822    error = voe_base->StopReceive(audio_channel);
823    number_of_errors += ViETest::TestError(error == 0,
824                                           "ERROR: %s at line %d",
825                                           __FUNCTION__, __LINE__);
826
827    error = voe_base->StopPlayout(audio_channel);
828    number_of_errors += ViETest::TestError(error == 0,
829                                           "ERROR: %s at line %d",
830                                           __FUNCTION__, __LINE__);
831
832    error = voe_base->DeleteChannel(audio_channel);
833    number_of_errors += ViETest::TestError(error == 0,
834                                           "ERROR: %s at line %d",
835                                           __FUNCTION__, __LINE__);
836    // Now tear down the ViE engine.
837    error = vie_base->DisconnectAudioChannel(video_channel);
838
839    voice_channel_transport.reset(NULL);
840
841    // If Encoder/Decoder Observer is running, delete them.
842    if (codec_encoder_observer) {
843      error = vie_codec->DeregisterEncoderObserver(video_channel);
844      delete codec_encoder_observer;
845      number_of_errors += ViETest::TestError(error == 0,
846                                             "ERROR: %s at line %d",
847                                             __FUNCTION__, __LINE__);
848    }
849    if (codec_decoder_observer) {
850      error = vie_codec->DeregisterDecoderObserver(video_channel);
851      delete codec_decoder_observer;
852      number_of_errors += ViETest::TestError(error == 0,
853                                             "ERROR: %s at line %d",
854                                             __FUNCTION__, __LINE__);
855    }
856
857    error = vie_base->StopReceive(video_channel);
858    number_of_errors += ViETest::TestError(error == 0,
859                                           "ERROR: %s at line %d",
860                                           __FUNCTION__, __LINE__);
861
862    error = vie_base->StopSend(video_channel);
863    number_of_errors += ViETest::TestError(error == 0,
864                                           "ERROR: %s at line %d",
865                                           __FUNCTION__, __LINE__);
866
867    error = vie_renderer->StopRender(capture_id);
868    number_of_errors += ViETest::TestError(error == 0,
869                                           "ERROR: %s at line %d",
870                                           __FUNCTION__, __LINE__);
871
872    error = vie_renderer->StopRender(video_channel);
873    number_of_errors += ViETest::TestError(error == 0,
874                                           "ERROR: %s at line %d",
875                                           __FUNCTION__, __LINE__);
876
877    error = vie_renderer->RemoveRenderer(capture_id);
878    number_of_errors += ViETest::TestError(error == 0,
879                                           "ERROR: %s at line %d",
880                                           __FUNCTION__, __LINE__);
881
882    error = vie_renderer->RemoveRenderer(video_channel);
883    number_of_errors += ViETest::TestError(error == 0,
884                                           "ERROR: %s at line %d",
885                                           __FUNCTION__, __LINE__);
886
887    error = vie_capture->StopCapture(capture_id);
888    number_of_errors += ViETest::TestError(error == 0,
889                                           "ERROR: %s at line %d",
890                                           __FUNCTION__, __LINE__);
891
892    error = vie_capture->DisconnectCaptureDevice(video_channel);
893    number_of_errors += ViETest::TestError(error == 0,
894                                           "ERROR: %s at line %d",
895                                           __FUNCTION__, __LINE__);
896
897    error = vie_capture->ReleaseCaptureDevice(capture_id);
898    number_of_errors += ViETest::TestError(error == 0,
899                                           "ERROR: %s at line %d",
900                                           __FUNCTION__, __LINE__);
901
902    video_channel_transport.reset(NULL);
903
904    error = vie_base->DeleteChannel(video_channel);
905    number_of_errors += ViETest::TestError(error == 0,
906                                           "ERROR: %s at line %d",
907                                           __FUNCTION__, __LINE__);
908
909    int remaining_interfaces = 0;
910    remaining_interfaces = vie_codec->Release();
911    number_of_errors += ViETest::TestError(remaining_interfaces == 0,
912                                           "ERROR: %s at line %d",
913                                           __FUNCTION__, __LINE__);
914
915    remaining_interfaces = vie_capture->Release();
916    number_of_errors += ViETest::TestError(remaining_interfaces == 0,
917                                           "ERROR: %s at line %d",
918                                           __FUNCTION__, __LINE__);
919
920    remaining_interfaces = vie_rtp_rtcp->Release();
921    number_of_errors += ViETest::TestError(remaining_interfaces == 0,
922                                           "ERROR: %s at line %d",
923                                           __FUNCTION__, __LINE__);
924
925    remaining_interfaces = vie_renderer->Release();
926    number_of_errors += ViETest::TestError(remaining_interfaces == 0,
927                                           "ERROR: %s at line %d",
928                                           __FUNCTION__, __LINE__);
929
930    remaining_interfaces = vie_network->Release();
931    number_of_errors += ViETest::TestError(remaining_interfaces == 0,
932                                           "ERROR: %s at line %d",
933                                           __FUNCTION__, __LINE__);
934
935    remaining_interfaces = vie_base->Release();
936    number_of_errors += ViETest::TestError(remaining_interfaces == 0,
937                                           "ERROR: %s at line %d",
938                                           __FUNCTION__, __LINE__);
939
940    bool deleted = webrtc::VideoEngine::Delete(vie);
941    number_of_errors += ViETest::TestError(deleted == true,
942                                           "ERROR: %s at line %d",
943                                           __FUNCTION__, __LINE__);
944
945    ViETest::Log(" ");
946    ViETest::Log(" ViE Autotest Custom Call Started");
947    ViETest::Log("========================================");
948    ViETest::Log(" ");
949  }
950  return number_of_errors;
951}
952
953bool GetVideoDevice(webrtc::ViEBase* vie_base,
954                    webrtc::ViECapture* vie_capture,
955                    char* capture_device_name,
956                    char* capture_device_unique_id) {
957  int error = 0;
958  int number_of_errors = 0;
959
960  const unsigned int KMaxDeviceNameLength = 128;
961  const unsigned int KMaxUniqueIdLength = 256;
962  char device_name[KMaxDeviceNameLength];
963  char unique_id[KMaxUniqueIdLength];
964
965  if (vie_capture->NumberOfCaptureDevices() == 0) {
966    printf("You have no capture devices plugged into your system.\n");
967    return false;
968  }
969
970  std::string capture_choices;
971  std::string first_device;
972  for (int i = 0; i < vie_capture->NumberOfCaptureDevices(); i++) {
973    memset(device_name, 0, KMaxDeviceNameLength);
974    memset(unique_id, 0, KMaxUniqueIdLength);
975
976    error = vie_capture->GetCaptureDevice(i, device_name,
977        KMaxDeviceNameLength,
978        unique_id,
979        KMaxUniqueIdLength);
980    number_of_errors += ViETest::TestError(error == 0,
981        "ERROR: %s at line %d",
982        __FUNCTION__, __LINE__);
983    const int kCaptureLineLength =
984        KMaxDeviceNameLength + KMaxUniqueIdLength + 8;
985    char capture_line[kCaptureLineLength];
986    sprintf(capture_line, "%s (%s)", device_name, unique_id);
987    capture_choices += capture_line;
988    capture_choices += "\n";
989    if (first_device.empty())
990      first_device = capture_line;
991  }
992
993  int choice = FromChoices("Available Video Capture Devices", capture_choices)
994      .WithDefault(first_device)
995      .Choose();
996
997  error = vie_capture->GetCaptureDevice(
998      choice - 1, device_name, KMaxDeviceNameLength, unique_id,
999      KMaxUniqueIdLength);
1000  number_of_errors += ViETest::TestError(error == 0,
1001      "ERROR: %s at line %d",
1002      __FUNCTION__, __LINE__);
1003  strcpy(capture_device_unique_id, unique_id);
1004  strcpy(capture_device_name, device_name);
1005  return true;
1006}
1007
1008bool GetAudioDevices(webrtc::VoEBase* voe_base,
1009                     webrtc::VoEHardware* voe_hardware,
1010                     char* recording_device_name,
1011                     int& recording_device_index,
1012                     char* playback_device_name,
1013                     int& playback_device_index) {
1014  int error = 0;
1015  int number_of_errors = 0;
1016
1017  const unsigned int KMaxDeviceNameLength = 128;
1018  const unsigned int KMaxUniqueIdLength = 128;
1019  char recording_device_unique_name[KMaxDeviceNameLength];
1020  char playback_device_unique_name[KMaxUniqueIdLength];
1021
1022  int number_of_recording_devices = -1;
1023  error = voe_hardware->GetNumOfRecordingDevices(number_of_recording_devices);
1024  number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
1025                                         __FUNCTION__, __LINE__);
1026
1027  recording_device_index = -1;
1028  playback_device_index = -1;
1029
1030  std::string device_choices;
1031  std::string default_recording_line;
1032  for (int i = 0; i < number_of_recording_devices; ++i) {
1033    error = voe_hardware->GetRecordingDeviceName(
1034        i, recording_device_name, recording_device_unique_name);
1035    number_of_errors += ViETest::TestError(error == 0,
1036        "ERROR: %s at line %d",
1037        __FUNCTION__, __LINE__);
1038
1039    device_choices += recording_device_name;
1040    device_choices += "\n";
1041    if (default_recording_line.empty())
1042      default_recording_line = recording_device_name;
1043  }
1044
1045  int choice = FromChoices("Available audio capture devices:", device_choices)
1046      .WithDefault(default_recording_line)
1047      .Choose();
1048
1049  recording_device_index = choice - 1;
1050  error = voe_hardware->GetRecordingDeviceName(
1051      recording_device_index, recording_device_name,
1052      recording_device_unique_name);
1053  number_of_errors += ViETest::TestError(
1054      error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__);
1055
1056  int number_of_playback_devices = -1;
1057  error = voe_hardware->GetNumOfPlayoutDevices(number_of_playback_devices);
1058  number_of_errors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
1059                                         __FUNCTION__, __LINE__);
1060
1061
1062  std::string playback_choices;
1063  std::string default_playback_line;
1064  for (int i = 0; i < number_of_playback_devices; i++) {
1065    error = voe_hardware->GetPlayoutDeviceName(i,
1066        playback_device_name,
1067        playback_device_unique_name);
1068    number_of_errors += ViETest::TestError(
1069        error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__);
1070    playback_choices += playback_device_name;
1071    playback_choices += "\n";
1072    if (default_playback_line.empty())
1073      default_playback_line = playback_device_name;
1074  }
1075
1076  choice = FromChoices("Available audio playout devices:", playback_choices)
1077      .WithDefault(default_playback_line)
1078      .Choose();
1079
1080  playback_device_index = choice - 1;
1081  error = voe_hardware->GetPlayoutDeviceName(playback_device_index,
1082      playback_device_name,
1083      playback_device_unique_name);
1084  number_of_errors += ViETest::TestError(error == 0,
1085      "ERROR: %s at line %d",
1086      __FUNCTION__, __LINE__);
1087  return true;
1088}
1089
1090// General helper functions.
1091
1092std::string GetIPAddress() {
1093  class IpValidator : public webrtc::InputValidator {
1094   public:
1095    bool InputOk(const std::string& input) const {
1096      // Just check quickly that it's on the form x.y.z.w
1097      return std::count(input.begin(), input.end(), '.') == 3;
1098    }
1099  };
1100  return TypedInput("Enter destination IP.")
1101      .WithDefault(DEFAULT_SEND_IP)
1102      .WithInputValidator(new IpValidator())
1103      .AskForInput();
1104}
1105
1106// Video settings functions.
1107
1108void GetVideoPorts(int* tx_port, int* rx_port) {
1109  std::string tx_input = TypedInput("Enter video send port.")
1110      .WithDefault(DEFAULT_VIDEO_PORT)
1111      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, 65536))
1112      .AskForInput();
1113  *tx_port = atoi(tx_input.c_str());
1114
1115  std::string rx_input = TypedInput("Enter video receive port.")
1116      .WithDefault(DEFAULT_VIDEO_PORT)
1117      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, 65536))
1118      .AskForInput();
1119  *rx_port = atoi(rx_input.c_str());
1120}
1121
1122// Audio settings functions.
1123
1124void GetAudioPorts(int* tx_port, int* rx_port) {
1125  std::string tx_input = TypedInput("Enter audio send port.")
1126      .WithDefault(DEFAULT_AUDIO_PORT)
1127      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, 65536))
1128      .AskForInput();
1129  *tx_port = atoi(tx_input.c_str());
1130
1131  std::string rx_input = TypedInput("Enter audio receive port.")
1132      .WithDefault(DEFAULT_AUDIO_PORT)
1133      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, 65536))
1134      .AskForInput();
1135  *rx_port = atoi(rx_input.c_str());
1136}
1137
1138bool GetAudioCodec(webrtc::VoECodec* voe_codec,
1139                   webrtc::CodecInst& audio_codec) {
1140  int error = 0;
1141  memset(&audio_codec, 0, sizeof(webrtc::CodecInst));
1142
1143  std::string default_codec_line;
1144  std::string codec_choices;
1145  for (int codec_idx = 0; codec_idx < voe_codec->NumOfCodecs(); codec_idx++) {
1146    error = voe_codec->GetCodec(codec_idx, audio_codec);
1147    ViETest::TestError(error == 0,
1148        "ERROR: %s at line %d",
1149        __FUNCTION__, __LINE__);
1150
1151    char codec_line[128];
1152    sprintf(codec_line, "%s type: %d freq: %d chan: %d",
1153        audio_codec.plname, audio_codec.pltype, audio_codec.plfreq,
1154        audio_codec.channels);
1155    codec_choices += codec_line;
1156    codec_choices += "\n";
1157
1158    if (strcmp(audio_codec.plname, DEFAULT_AUDIO_CODEC) == 0) {
1159      default_codec_line = codec_line;
1160    }
1161  }
1162  assert(!default_codec_line.empty() && "Default codec doesn't exist.");
1163
1164  int codec_selection = FromChoices("Available Audio Codecs:", codec_choices)
1165            .WithDefault(default_codec_line)
1166            .Choose();
1167
1168  error = voe_codec->GetCodec(codec_selection - 1, audio_codec);
1169  ViETest::TestError(error == 0,
1170      "ERROR: %s at line %d",
1171      __FUNCTION__, __LINE__);
1172  return true;
1173}
1174
1175void PrintCallInformation(const char* IP, const char* video_capture_device_name,
1176                          const char* video_capture_unique_id,
1177                          webrtc::VideoCodec video_codec,
1178                          int video_tx_port, int video_rx_port,
1179                          const char* audio_capture_device_name,
1180                          const char* audio_playbackDeviceName,
1181                          webrtc::CodecInst audio_codec,
1182                          int audio_tx_port, int audio_rx_port,
1183                          int protection_method) {
1184  std::string str;
1185
1186  std::cout << "************************************************"
1187            << std::endl;
1188  std::cout << "The call has the following settings: " << std::endl;
1189  std::cout << "\tIP: " << IP << std::endl;
1190  std::cout << "\tVideo Capture Device: " << video_capture_device_name
1191            << std::endl;
1192  std::cout << "\t\tName: " << video_capture_device_name << std::endl;
1193  std::cout << "\t\tUniqueId: " << video_capture_unique_id << std::endl;
1194  PrintVideoCodec(video_codec);
1195  std::cout << "\t Video Tx Port: " << video_tx_port << std::endl;
1196  std::cout << "\t Video Rx Port: " << video_rx_port << std::endl;
1197  std::cout << "\t Video Protection Method (NOTE: Starts at 1 now): "
1198            << protection_method  << std::endl;
1199  std::cout << "\tAudio Capture Device: " << audio_capture_device_name
1200            << std::endl;
1201  std::cout << "\tAudio Playback Device: " << audio_playbackDeviceName
1202            << std::endl;
1203  std::cout << "\tAudio Codec: " << std::endl;
1204  std::cout << "\t\tplname: " << audio_codec.plname << std::endl;
1205  std::cout << "\t\tpltype: " << static_cast<int>(audio_codec.pltype)
1206            << std::endl;
1207  std::cout << "\t Audio Tx Port: " << audio_tx_port << std::endl;
1208  std::cout << "\t Audio Rx Port: " << audio_rx_port << std::endl;
1209  std::cout << "************************************************"
1210            << std::endl;
1211}
1212
1213void SetVideoCodecType(webrtc::ViECodec* vie_codec,
1214                       webrtc::VideoCodec* video_codec) {
1215  int error = 0;
1216  int number_of_errors = 0;
1217  memset(video_codec, 0, sizeof(webrtc::VideoCodec));
1218
1219  std::string codec_choices;
1220  std::string default_codec_line;
1221  for (int i = 0; i < vie_codec->NumberOfCodecs(); i++) {
1222    error = vie_codec->GetCodec(i, *video_codec);
1223    number_of_errors += ViETest::TestError(
1224        error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__);
1225
1226    codec_choices += video_codec->plName;
1227    codec_choices += "\n";
1228    if (strcmp(video_codec->plName, DEFAULT_VIDEO_CODEC) == 0)
1229      default_codec_line = video_codec->plName;
1230  }
1231  assert(!default_codec_line.empty() && "Default does not exist.");
1232
1233  int choice = FromChoices("Available Video Codecs", codec_choices)
1234      .WithDefault(default_codec_line)
1235      .Choose();
1236  error = vie_codec->GetCodec(choice - 1, *video_codec);
1237  number_of_errors += ViETest::TestError(
1238      error == 0, "ERROR: %s at line %d", __FUNCTION__, __LINE__);
1239
1240  if (video_codec->codecType == webrtc::kVideoCodecI420) {
1241    video_codec->width = 176;
1242    video_codec->height = 144;
1243  }
1244}
1245
1246void SetVideoCodecResolution(webrtc::VideoCodec* video_codec) {
1247  if (video_codec->codecType != webrtc::kVideoCodecVP8) {
1248    printf("Can only change codec size if it's VP8\n");
1249    return;
1250  }
1251
1252  int choice = FromChoices(
1253      "Available Common Resolutions:",
1254      "SQCIF (128X96)\n"
1255      "QQVGA (160X120)\n"
1256      "QCIF  (176X144)\n"
1257      "CIF   (352X288)\n"
1258      "VGA   (640X480)\n"
1259      "WVGA  (800x480)\n"
1260      "4CIF  (704X576)\n"
1261      "SVGA  (800X600)\n"
1262      "HD    (1280X720)\n"
1263      "XGA   (1024x768)\n")
1264          .Choose();
1265
1266  switch (choice) {
1267    case 1:
1268      video_codec->width = 128;
1269      video_codec->height = 96;
1270      break;
1271    case 2:
1272      video_codec->width = 160;
1273      video_codec->height = 120;
1274      break;
1275    case 3:
1276      video_codec->width = 176;
1277      video_codec->height = 144;
1278      break;
1279    case 4:
1280      video_codec->width = 352;
1281      video_codec->height = 288;
1282      break;
1283    case 5:
1284      video_codec->width = 640;
1285      video_codec->height = 480;
1286      break;
1287    case 6:
1288      video_codec->width = 800;
1289      video_codec->height = 480;
1290      break;
1291    case 7:
1292      video_codec->width = 704;
1293      video_codec->height = 576;
1294      break;
1295    case 8:
1296      video_codec->width = 800;
1297      video_codec->height = 600;
1298      break;
1299    case 9:
1300      video_codec->width = 1280;
1301      video_codec->height = 720;
1302      break;
1303    case 10:
1304      video_codec->width = 1024;
1305      video_codec->height = 768;
1306      break;
1307  }
1308}
1309
1310void SetVideoCodecSize(webrtc::VideoCodec* video_codec) {
1311  if (video_codec->codecType != webrtc::kVideoCodecVP8) {
1312    printf("Can only change codec size if it's VP8\n");
1313    return;
1314  }
1315
1316  std::string input = TypedInput("Choose video width.")
1317      .WithDefault(DEFAULT_VIDEO_CODEC_WIDTH)
1318      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, INT_MAX))
1319      .AskForInput();
1320  video_codec->width = atoi(input.c_str());
1321
1322  input = TypedInput("Choose video height.")
1323      .WithDefault(DEFAULT_VIDEO_CODEC_HEIGHT)
1324      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, INT_MAX))
1325      .AskForInput();
1326  video_codec->height = atoi(input.c_str());
1327}
1328
1329void SetVideoCodecBitrate(webrtc::VideoCodec* video_codec) {
1330  std::string input = TypedInput("Choose start rate (in kbps).")
1331      .WithDefault(DEFAULT_VIDEO_CODEC_BITRATE)
1332      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, INT_MAX))
1333      .AskForInput();
1334
1335  video_codec->startBitrate = atoi(input.c_str());
1336}
1337
1338void SetVideoCodecMaxBitrate(webrtc::VideoCodec* video_codec) {
1339  std::string input = TypedInput("Choose max bitrate (in kbps).")
1340      .WithDefault(DEFAULT_VIDEO_CODEC_MAX_BITRATE)
1341      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, INT_MAX))
1342      .AskForInput();
1343
1344  video_codec->maxBitrate = atoi(input.c_str());
1345}
1346
1347void SetVideoCodecMinBitrate(webrtc::VideoCodec* video_codec) {
1348  std::string input = TypedInput("Choose min bitrate (in kbps).")
1349      .WithDefault(DEFAULT_VIDEO_CODEC_MIN_BITRATE)
1350      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, INT_MAX))
1351      .AskForInput();
1352
1353  video_codec->minBitrate = atoi(input.c_str());
1354}
1355
1356void SetVideoCodecMaxFramerate(webrtc::VideoCodec* video_codec) {
1357  std::string input = TypedInput("Choose max framerate (in fps).")
1358      .WithDefault(DEFAULT_VIDEO_CODEC_MAX_FRAMERATE)
1359      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(1, INT_MAX))
1360      .AskForInput();
1361  video_codec->maxFramerate = atoi(input.c_str());
1362}
1363
1364void SetVideoCodecTemporalLayer(webrtc::VideoCodec* video_codec) {
1365  if (video_codec->codecType != webrtc::kVideoCodecVP8)
1366    return;
1367
1368  std::string input = TypedInput("Choose number of temporal layers (0 to 4).")
1369      .WithDefault(DEFAULT_TEMPORAL_LAYER)
1370      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(0, 4))
1371      .AskForInput();
1372  video_codec->codecSpecific.VP8.numberOfTemporalLayers = atoi(input.c_str());
1373}
1374
1375// GetVideoProtection only prints the prompt to get a number
1376// that SetVideoProtection method uses.
1377VideoProtectionMethod GetVideoProtection() {
1378  int choice = FromChoices(
1379      "Available Video Protection Methods:",
1380      "None\n"
1381      "FEC\n"
1382      "NACK\n"
1383      "NACK+FEC\n")
1384          .WithDefault(DEFAULT_VIDEO_PROTECTION_METHOD)
1385          .Choose();
1386
1387  assert(choice >= kProtectionMethodNone &&
1388         choice <= kProtectionMethodHybridNackAndFec);
1389  return static_cast<VideoProtectionMethod>(choice);
1390}
1391
1392bool SetVideoProtection(webrtc::ViECodec* vie_codec,
1393                        webrtc::ViERTP_RTCP* vie_rtp_rtcp,
1394                        int video_channel,
1395                        VideoProtectionMethod protection_method) {
1396  int error = 0;
1397  int number_of_errors = 0;
1398  webrtc::VideoCodec video_codec;
1399
1400  memset(&video_codec, 0, sizeof(webrtc::VideoCodec));
1401
1402  // Set all video protection to false initially
1403  error = vie_rtp_rtcp->SetHybridNACKFECStatus(video_channel, false,
1404                                               VCM_RED_PAYLOAD_TYPE,
1405                                               VCM_ULPFEC_PAYLOAD_TYPE);
1406  number_of_errors += ViETest::TestError(error == 0,
1407                                         "ERROR: %s at line %d",
1408                                         __FUNCTION__, __LINE__);
1409  error = vie_rtp_rtcp->SetFECStatus(video_channel, false,
1410                                     VCM_RED_PAYLOAD_TYPE,
1411                                     VCM_ULPFEC_PAYLOAD_TYPE);
1412  number_of_errors += ViETest::TestError(error == 0,
1413                                         "ERROR: %s at line %d",
1414                                         __FUNCTION__, __LINE__);
1415  error = vie_rtp_rtcp->SetNACKStatus(video_channel, false);
1416  number_of_errors += ViETest::TestError(error == 0,
1417                                         "ERROR: %s at line %d",
1418                                         __FUNCTION__, __LINE__);
1419  // Set video protection for FEC, NACK or Hybrid.
1420  switch (protection_method) {
1421    case kProtectionMethodNone:
1422      // No protection selected, all protection already at false.
1423      std::cout << "Call using None protection Method" << std::endl;
1424      break;
1425    case kProtectionMethodFecOnly:
1426      std::cout << "Call using FEC protection Method" << std::endl;
1427      error = vie_rtp_rtcp->SetFECStatus(video_channel, true,
1428                                         VCM_RED_PAYLOAD_TYPE,
1429                                         VCM_ULPFEC_PAYLOAD_TYPE);
1430      number_of_errors += ViETest::TestError(error == 0,
1431                                             "ERROR: %s at line %d",
1432                                             __FUNCTION__, __LINE__);
1433      break;
1434    case kProtectionMethodNackOnly:
1435      std::cout << "Call using NACK protection Method" << std::endl;
1436      error = vie_rtp_rtcp->SetNACKStatus(video_channel, true);
1437      number_of_errors += ViETest::TestError(error == 0,
1438                                             "ERROR: %s at line %d",
1439                                             __FUNCTION__, __LINE__);
1440      break;
1441    case kProtectionMethodHybridNackAndFec:
1442      std::cout << "Call using Hybrid NACK and FEC protection Method"
1443                << std::endl;
1444      error = vie_rtp_rtcp->SetHybridNACKFECStatus(video_channel, true,
1445                                                   VCM_RED_PAYLOAD_TYPE,
1446                                                   VCM_ULPFEC_PAYLOAD_TYPE);
1447      number_of_errors += ViETest::TestError(error == 0,
1448                                             "ERROR: %s at line %d",
1449                                             __FUNCTION__, __LINE__);
1450      break;
1451  }
1452
1453  // Set receive codecs for FEC and hybrid NACK/FEC.
1454  if (protection_method == kProtectionMethodFecOnly ||
1455      protection_method == kProtectionMethodHybridNackAndFec) {
1456    // RED.
1457    error = vie_codec->GetCodec(vie_codec->NumberOfCodecs() - 2,
1458                                video_codec);
1459    number_of_errors += ViETest::TestError(error == 0,
1460                                           "ERROR: %s at line %d",
1461                                           __FUNCTION__, __LINE__);
1462    video_codec.plType = VCM_RED_PAYLOAD_TYPE;
1463    error = vie_codec->SetReceiveCodec(video_channel, video_codec);
1464    number_of_errors += ViETest::TestError(error == 0,
1465                                           "ERROR: %s at line %d",
1466                                           __FUNCTION__, __LINE__);
1467    std::cout << "RED Codec Information:" << std::endl;
1468    PrintVideoCodec(video_codec);
1469    // ULPFEC.
1470    error = vie_codec->GetCodec(vie_codec->NumberOfCodecs() - 1,
1471                                video_codec);
1472    number_of_errors += ViETest::TestError(error == 0,
1473                                           "ERROR: %s at line %d",
1474                                           __FUNCTION__, __LINE__);
1475    video_codec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
1476    error = vie_codec->SetReceiveCodec(video_channel, video_codec);
1477    number_of_errors += ViETest::TestError(error == 0,
1478                                           "ERROR: %s at line %d",
1479                                           __FUNCTION__, __LINE__);
1480    std::cout << "ULPFEC Codec Information:" << std::endl;
1481    PrintVideoCodec(video_codec);
1482  }
1483
1484  return true;
1485}
1486
1487// Returns true if REMB, false if TMMBR.
1488bool GetBitrateSignaling() {
1489  int choice = FromChoices(
1490      "Available Bitrate Signaling Methods:",
1491      "REMB\n"
1492      "TMMBR\n")
1493          .WithDefault("REMB")
1494          .Choose();
1495  return choice == 1;
1496}
1497
1498int GetBufferingDelay() {
1499  std::string input = TypedInput("Choose buffering delay (mS).")
1500      .WithDefault(DEFAULT_BUFFERING_DELAY_MS)
1501      .WithInputValidator(new webrtc::IntegerWithinRangeValidator(0, 10000))
1502      .AskForInput();
1503  std::string delay_ms = input;
1504  return atoi(delay_ms.c_str());
1505}
1506
1507void PrintRTCCPStatistics(webrtc::ViERTP_RTCP* vie_rtp_rtcp,
1508                          int video_channel,
1509                          StatisticsType stat_type) {
1510  int error = 0;
1511  int number_of_errors = 0;
1512  webrtc::RtcpStatistics rtcp_stats;
1513  int rtt_ms = 0;
1514
1515  switch (stat_type) {
1516    case kReceivedStatistic:
1517      std::cout << "RTCP Received statistics"
1518                << std::endl;
1519      // Get and print the Received RTCP Statistics
1520      error = vie_rtp_rtcp->GetReceiveChannelRtcpStatistics(video_channel,
1521                                                      rtcp_stats,
1522                                                      rtt_ms);
1523      number_of_errors += ViETest::TestError(error == 0,
1524                                             "ERROR: %s at line %d",
1525                                             __FUNCTION__, __LINE__);
1526      break;
1527    case kSendStatistic:
1528      std::cout << "RTCP Sent statistics"
1529                << std::endl;
1530      // Get and print the Sent RTCP Statistics
1531      error = vie_rtp_rtcp->GetSendChannelRtcpStatistics(video_channel,
1532                                                  rtcp_stats,
1533                                                  rtt_ms);
1534      number_of_errors += ViETest::TestError(error == 0,
1535                                             "ERROR: %s at line %d",
1536                                             __FUNCTION__, __LINE__);
1537      break;
1538  }
1539  std::cout << "\tRTCP fraction of lost packets: "
1540            << rtcp_stats.fraction_lost << std::endl;
1541  std::cout << "\tRTCP cumulative number of lost packets: "
1542            << rtcp_stats.cumulative_lost << std::endl;
1543  std::cout << "\tRTCP max received sequence number "
1544            << rtcp_stats.extended_max_sequence_number << std::endl;
1545  std::cout << "\tRTCP jitter: "
1546            << rtcp_stats.jitter << std::endl;
1547  std::cout << "\tRTCP round trip (ms): "
1548            << rtt_ms << std::endl;
1549}
1550
1551void PrintRTPStatistics(webrtc::ViERTP_RTCP* vie_rtp_rtcp,
1552                        int video_channel) {
1553  int error = 0;
1554  int number_of_errors = 0;
1555  webrtc::StreamDataCounters sent;
1556  webrtc::StreamDataCounters received;
1557
1558  std::cout << "RTP statistics"
1559            << std::endl;
1560
1561  // Get and print the RTP Statistics
1562  error = vie_rtp_rtcp->GetRtpStatistics(video_channel, sent, received);
1563  number_of_errors += ViETest::TestError(error == 0,
1564                                         "ERROR: %s at line %d",
1565                                         __FUNCTION__, __LINE__);
1566  std::cout << "\tRTP bytes sent: "
1567            << sent.bytes << std::endl;
1568  std::cout << "\tRTP packets sent: "
1569            << sent.packets << std::endl;
1570  std::cout << "\tRTP bytes received: "
1571            << received.bytes << std::endl;
1572  std::cout << "\tRTP packets received: "
1573            << received.packets << std::endl;
1574}
1575
1576void PrintBandwidthUsage(webrtc::ViERTP_RTCP* vie_rtp_rtcp,
1577                         int video_channel) {
1578  int error = 0;
1579  int number_of_errors = 0;
1580  unsigned int total_bitrate_sent = 0;
1581  unsigned int video_bitrate_sent = 0;
1582  unsigned int fec_bitrate_sent = 0;
1583  unsigned int nack_bitrate_sent = 0;
1584  double percentage_fec = 0;
1585  double percentage_nack = 0;
1586
1587  std::cout << "Bandwidth Usage" << std::endl;
1588
1589  // Get and print Bandwidth usage
1590  error = vie_rtp_rtcp->GetBandwidthUsage(video_channel, total_bitrate_sent,
1591                                          video_bitrate_sent, fec_bitrate_sent,
1592                                          nack_bitrate_sent);
1593  number_of_errors += ViETest::TestError(error == 0,
1594                                         "ERROR: %s at line %d",
1595                                         __FUNCTION__, __LINE__);
1596  std::cout << "\tTotal bitrate sent (Kbit/s): "
1597            << total_bitrate_sent << std::endl;
1598  std::cout << "\tVideo bitrate sent (Kbit/s): "
1599            << video_bitrate_sent << std::endl;
1600  std::cout << "\tFEC bitrate sent (Kbit/s): "
1601            << fec_bitrate_sent << std::endl;
1602  percentage_fec =
1603      (static_cast<double>(fec_bitrate_sent) /
1604      static_cast<double>(total_bitrate_sent)) * 100;
1605  std::cout << "\tPercentage FEC bitrate sent from total bitrate: "
1606            << percentage_fec << std::endl;
1607  std::cout << "\tNACK bitrate sent (Kbit/s): "
1608            << nack_bitrate_sent << std::endl;
1609  percentage_nack =
1610      (static_cast<double>(nack_bitrate_sent) /
1611      static_cast<double>(total_bitrate_sent)) * 100;
1612  std::cout << "\tPercentage NACK bitrate sent from total bitrate: "
1613            << percentage_nack << std::endl;
1614}
1615
1616void PrintCodecStatistics(webrtc::ViECodec* vie_codec,
1617                          int video_channel,
1618                          StatisticsType stat_type) {
1619  int error = 0;
1620  int number_of_errors = 0;
1621  unsigned int key_frames = 0;
1622  unsigned int delta_frames = 0;
1623  switch (stat_type) {
1624    case kReceivedStatistic:
1625      std::cout << "Codec Receive statistics"
1626                << std::endl;
1627      // Get and print the Receive Codec Statistics
1628      error = vie_codec->GetReceiveCodecStastistics(video_channel, key_frames,
1629                                                    delta_frames);
1630      number_of_errors += ViETest::TestError(error == 0,
1631                                             "ERROR: %s at line %d",
1632                                             __FUNCTION__, __LINE__);
1633      break;
1634    case kSendStatistic:
1635      std::cout << "Codec Send statistics"
1636                << std::endl;
1637      // Get and print the Send Codec Statistics
1638      error = vie_codec->GetSendCodecStastistics(video_channel, key_frames,
1639                                                 delta_frames);
1640      number_of_errors += ViETest::TestError(error == 0,
1641                                             "ERROR: %s at line %d",
1642                                             __FUNCTION__, __LINE__);
1643      break;
1644  }
1645  std::cout << "\tNumber of encoded key frames: "
1646            << key_frames << std::endl;
1647  std::cout << "\tNumber of encoded delta frames: "
1648            << delta_frames << std::endl;
1649}
1650
1651void PrintGetDiscardedPackets(webrtc::ViECodec* vie_codec, int video_channel) {
1652  std::cout << "Discarded Packets" << std::endl;
1653  int discarded_packets = 0;
1654  discarded_packets = vie_codec->GetDiscardedPackets(video_channel);
1655  std::cout << "\tNumber of discarded packets: "
1656            << discarded_packets << std::endl;
1657}
1658
1659void PrintVideoStreamInformation(webrtc::ViECodec* vie_codec,
1660                                 int video_channel) {
1661  webrtc::VideoCodec outgoing_codec;
1662  webrtc::VideoCodec incoming_codec;
1663
1664  memset(&outgoing_codec, 0, sizeof(webrtc::VideoCodec));
1665  memset(&incoming_codec, 0, sizeof(webrtc::VideoCodec));
1666
1667  vie_codec->GetSendCodec(video_channel, outgoing_codec);
1668  vie_codec->GetReceiveCodec(video_channel, incoming_codec);
1669
1670  std::cout << "************************************************"
1671            << std::endl;
1672  std::cout << "ChannelId: " << video_channel << std::endl;
1673  std::cout << "Outgoing Stream information:" << std::endl;
1674  PrintVideoCodec(outgoing_codec);
1675  std::cout << "Incoming Stream information:" << std::endl;
1676  PrintVideoCodec(incoming_codec);
1677  std::cout << "************************************************"
1678            << std::endl;
1679}
1680
1681void PrintVideoCodec(webrtc::VideoCodec video_codec) {
1682  std::cout << "\t\tplName: " << video_codec.plName << std::endl;
1683  std::cout << "\t\tplType: " << static_cast<int>(video_codec.plType)
1684            << std::endl;
1685  std::cout << "\t\twidth: " << video_codec.width << std::endl;
1686  std::cout << "\t\theight: " << video_codec.height << std::endl;
1687  std::cout << "\t\tstartBitrate: " << video_codec.startBitrate
1688            << std::endl;
1689  std::cout << "\t\tminBitrate: " << video_codec.minBitrate
1690            << std::endl;
1691  std::cout << "\t\tmaxBitrate: " << video_codec.maxBitrate
1692            << std::endl;
1693  std::cout << "\t\tmaxFramerate: "
1694            << static_cast<int>(video_codec.maxFramerate) << std::endl;
1695  if (video_codec.codecType == webrtc::kVideoCodecVP8) {
1696    int number_of_layers =
1697        static_cast<int>(video_codec.codecSpecific.VP8.numberOfTemporalLayers);
1698    std::cout << "\t\tVP8 Temporal Layer: " << number_of_layers << std::endl;
1699  }
1700}
1701