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 45 DEFINE_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 49 enum StatisticsType { 50 kSendStatistic, 51 kReceivedStatistic 52 }; 53 54 enum VideoProtectionMethod { 55 kProtectionMethodNone = 1, 56 kProtectionMethodFecOnly, 57 kProtectionMethodNackOnly, 58 kProtectionMethodHybridNackAndFec, 59 }; 60 61 using webrtc::FromChoices; 62 using webrtc::TypedInput; 63 64 class 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 81 class 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. 117 bool GetVideoDevice(webrtc::ViEBase* vie_base, 118 webrtc::ViECapture* vie_capture, 119 char* capture_device_name, char* capture_device_unique_id); 120 std::string GetIPAddress(); 121 bool ValidateIP(std::string i_str); 122 123 // The following are Print to stdout functions. 124 void 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); 136 void PrintRTCCPStatistics(webrtc::ViERTP_RTCP* vie_rtp_rtcp, 137 int video_channel, 138 StatisticsType stat_type); 139 void PrintRTPStatistics(webrtc::ViERTP_RTCP* vie_rtp_rtcp, 140 int video_channel); 141 void PrintBandwidthUsage(webrtc::ViERTP_RTCP* vie_rtp_rtcp, 142 int video_channel); 143 void PrintCodecStatistics(webrtc::ViECodec* vie_codec, 144 int video_channel, 145 StatisticsType stat_type); 146 void PrintGetDiscardedPackets(webrtc::ViECodec* vie_codec, 147 int video_channel); 148 void PrintVideoStreamInformation(webrtc::ViECodec* vie_codec, 149 int video_channel); 150 void PrintVideoCodec(webrtc::VideoCodec video_codec); 151 152 // The following are video functions. 153 void GetVideoPorts(int* tx_port, int* rx_port); 154 void SetVideoCodecType(webrtc::ViECodec* vie_codec, 155 webrtc::VideoCodec* video_codec); 156 void SetVideoCodecResolution(webrtc::VideoCodec* video_codec); 157 void SetVideoCodecSize(webrtc::VideoCodec* video_codec); 158 void SetVideoCodecBitrate(webrtc::VideoCodec* video_codec); 159 void SetVideoCodecMinBitrate(webrtc::VideoCodec* video_codec); 160 void SetVideoCodecMaxBitrate(webrtc::VideoCodec* video_codec); 161 void SetVideoCodecMaxFramerate(webrtc::VideoCodec* video_codec); 162 void SetVideoCodecTemporalLayer(webrtc::VideoCodec* video_codec); 163 VideoProtectionMethod GetVideoProtection(); 164 bool SetVideoProtection(webrtc::ViECodec* vie_codec, 165 webrtc::ViERTP_RTCP* vie_rtp_rtcp, 166 int video_channel, 167 VideoProtectionMethod protection_method); 168 bool GetBitrateSignaling(); 169 int GetBufferingDelay(); 170 171 // The following are audio helper functions. 172 bool 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); 176 bool GetAudioDevices(webrtc::VoEBase* voe_base, 177 webrtc::VoEHardware* voe_hardware, 178 int& recording_device_index, int& playback_device_index); 179 void GetAudioPorts(int* tx_port, int* rx_port); 180 bool GetAudioCodec(webrtc::VoECodec* voe_codec, 181 webrtc::CodecInst& audio_codec); 182 183 int 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 953 bool 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 1008 bool 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 1092 std::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 1108 void 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 1124 void 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 1138 bool 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 1175 void 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 1213 void 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 1246 void 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 1310 void 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 1329 void 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 1338 void 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 1347 void 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 1356 void 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 1364 void 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. 1377 VideoProtectionMethod 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 1392 bool 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. 1488 bool 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 1498 int 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 1507 void 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 1551 void 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 1576 void 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 1616 void 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 1651 void 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->GetNumDiscardedPackets(video_channel); 1655 std::cout << "\tNumber of discarded packets: " 1656 << discarded_packets << std::endl; 1657 } 1658 1659 void 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 1681 void 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