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 <iostream> // NOLINT 12 13 #include "webrtc/common_types.h" 14 #include "webrtc/video_engine/include/vie_base.h" 15 #include "webrtc/video_engine/include/vie_capture.h" 16 #include "webrtc/video_engine/include/vie_codec.h" 17 #include "webrtc/video_engine/include/vie_network.h" 18 #include "webrtc/video_engine/include/vie_render.h" 19 #include "webrtc/video_engine/include/vie_rtp_rtcp.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/libvietest/include/tb_external_transport.h" 23 #include "webrtc/voice_engine/include/voe_base.h" 24 25 enum RelayMode { 26 kRelayOneStream = 1, 27 kRelayAllStreams = 2 28 }; 29 30 #define VCM_RED_PAYLOAD_TYPE 96 31 #define VCM_ULPFEC_PAYLOAD_TYPE 97 32 33 const int kNumStreams = 3; 34 35 void InitialSingleStreamSettings(webrtc::VideoCodec* video_codec) { 36 video_codec->numberOfSimulcastStreams = 0; 37 video_codec->width = 1200; 38 video_codec->height = 800; 39 } 40 41 void SetSimulcastSettings(webrtc::VideoCodec* video_codec) { 42 video_codec->width = 1280; 43 video_codec->height = 720; 44 45 // Simulcast settings. 46 video_codec->numberOfSimulcastStreams = kNumStreams; 47 video_codec->simulcastStream[0].width = 320; 48 video_codec->simulcastStream[0].height = 180; 49 video_codec->simulcastStream[0].numberOfTemporalLayers = 0; 50 video_codec->simulcastStream[0].maxBitrate = 100; 51 video_codec->simulcastStream[0].targetBitrate = 100; 52 video_codec->simulcastStream[0].minBitrate = 0; 53 video_codec->simulcastStream[0].qpMax = video_codec->qpMax; 54 55 video_codec->simulcastStream[1].width = 640; 56 video_codec->simulcastStream[1].height = 360; 57 video_codec->simulcastStream[1].numberOfTemporalLayers = 0; 58 video_codec->simulcastStream[1].maxBitrate = 500; 59 video_codec->simulcastStream[1].targetBitrate = 500; 60 video_codec->simulcastStream[1].minBitrate = 200; 61 video_codec->simulcastStream[1].qpMax = video_codec->qpMax; 62 63 video_codec->simulcastStream[2].width = 1280; 64 video_codec->simulcastStream[2].height = 720; 65 video_codec->simulcastStream[2].numberOfTemporalLayers = 0; 66 video_codec->simulcastStream[2].maxBitrate = 1200; 67 video_codec->simulcastStream[2].targetBitrate = 1200; 68 video_codec->simulcastStream[2].minBitrate = 900; 69 video_codec->simulcastStream[2].qpMax = video_codec->qpMax; 70 } 71 72 void RuntimeSingleStreamSettings(webrtc::VideoCodec* video_codec) { 73 SetSimulcastSettings(video_codec); 74 video_codec->width = 1200; 75 video_codec->height = 800; 76 video_codec->numberOfSimulcastStreams = kNumStreams; 77 video_codec->simulcastStream[0].maxBitrate = 0; 78 video_codec->simulcastStream[0].targetBitrate = 0; 79 video_codec->simulcastStream[0].minBitrate = 0; 80 video_codec->simulcastStream[1].maxBitrate = 0; 81 video_codec->simulcastStream[1].targetBitrate = 0; 82 video_codec->simulcastStream[1].minBitrate = 0; 83 video_codec->simulcastStream[2].maxBitrate = 0; 84 video_codec->simulcastStream[2].targetBitrate = 0; 85 video_codec->simulcastStream[2].minBitrate = 0; 86 } 87 88 int VideoEngineSimulcastTest(void* window1, void* window2) { 89 // ******************************************************* 90 // Begin create/initialize Video Engine for testing 91 // ******************************************************* 92 93 int error = 0; 94 int receive_channels[kNumStreams]; 95 96 // Create a VideoEngine instance. 97 webrtc::VideoEngine* video_engine = NULL; 98 video_engine = webrtc::VideoEngine::Create(); 99 if (video_engine == NULL) { 100 printf("ERROR in VideoEngine::Create\n"); 101 return -1; 102 } 103 104 error = video_engine->SetTraceFilter(webrtc::kTraceAll); 105 if (error == -1) { 106 printf("ERROR in VideoEngine::SetTraceLevel\n"); 107 return -1; 108 } 109 110 std::string trace_file = 111 ViETest::GetResultOutputPath() + "ViESimulcast_trace.txt"; 112 error = video_engine->SetTraceFile(trace_file.c_str()); 113 if (error == -1) { 114 printf("ERROR in VideoEngine::SetTraceFile\n"); 115 return -1; 116 } 117 118 // Init VideoEngine and create a channel. 119 webrtc::ViEBase* vie_base = webrtc::ViEBase::GetInterface(video_engine); 120 if (vie_base == NULL) { 121 printf("ERROR in ViEBase::GetInterface\n"); 122 return -1; 123 } 124 125 error = vie_base->Init(); 126 if (error == -1) { 127 printf("ERROR in ViEBase::Init\n"); 128 return -1; 129 } 130 131 RelayMode relay_mode = kRelayOneStream; 132 printf("Select relay mode:\n"); 133 printf("\t1. Relay one stream\n"); 134 printf("\t2. Relay all streams\n"); 135 if (scanf("%d", reinterpret_cast<int*>(&relay_mode)) != 1) { 136 printf("Error in scanf()\n"); 137 return -1; 138 } 139 getchar(); 140 141 webrtc::ViERTP_RTCP* vie_rtp_rtcp = 142 webrtc::ViERTP_RTCP::GetInterface(video_engine); 143 if (vie_rtp_rtcp == NULL) { 144 printf("ERROR in ViERTP_RTCP::GetInterface\n"); 145 return -1; 146 } 147 148 int video_channel = -1; 149 error = vie_base->CreateChannel(video_channel); 150 if (error == -1) { 151 printf("ERROR in ViEBase::CreateChannel\n"); 152 return -1; 153 } 154 155 for (int i = 0; i < kNumStreams; ++i) { 156 receive_channels[i] = -1; 157 error = vie_base->CreateReceiveChannel(receive_channels[i], video_channel); 158 if (error == -1) { 159 printf("ERROR in ViEBase::CreateChannel\n"); 160 return -1; 161 } 162 } 163 164 // List available capture devices, allocate and connect. 165 webrtc::ViECapture* vie_capture = 166 webrtc::ViECapture::GetInterface(video_engine); 167 if (vie_base == NULL) { 168 printf("ERROR in ViECapture::GetInterface\n"); 169 return -1; 170 } 171 172 const unsigned int KMaxDeviceNameLength = 128; 173 const unsigned int KMaxUniqueIdLength = 256; 174 char device_name[KMaxDeviceNameLength]; 175 memset(device_name, 0, KMaxDeviceNameLength); 176 char unique_id[KMaxUniqueIdLength]; 177 memset(unique_id, 0, KMaxUniqueIdLength); 178 179 printf("Available capture devices:\n"); 180 int capture_idx = 0; 181 for (capture_idx = 0; capture_idx < vie_capture->NumberOfCaptureDevices(); 182 capture_idx++) { 183 memset(device_name, 0, KMaxDeviceNameLength); 184 memset(unique_id, 0, KMaxUniqueIdLength); 185 186 error = vie_capture->GetCaptureDevice(capture_idx, device_name, 187 KMaxDeviceNameLength, unique_id, 188 KMaxUniqueIdLength); 189 if (error == -1) { 190 printf("ERROR in ViECapture::GetCaptureDevice\n"); 191 return -1; 192 } 193 printf("\t %d. %s\n", capture_idx + 1, device_name); 194 } 195 printf("\nChoose capture device: "); 196 #ifdef WEBRTC_ANDROID 197 capture_idx = 0; 198 printf("0\n"); 199 #else 200 if (scanf("%d", &capture_idx) != 1) { 201 printf("Error in scanf()\n"); 202 return -1; 203 } 204 getchar(); 205 // Compensate for idx start at 1. 206 capture_idx = capture_idx - 1; 207 #endif 208 error = vie_capture->GetCaptureDevice(capture_idx, device_name, 209 KMaxDeviceNameLength, unique_id, 210 KMaxUniqueIdLength); 211 if (error == -1) { 212 printf("ERROR in ViECapture::GetCaptureDevice\n"); 213 return -1; 214 } 215 216 int capture_id = 0; 217 error = vie_capture->AllocateCaptureDevice(unique_id, KMaxUniqueIdLength, 218 capture_id); 219 if (error == -1) { 220 printf("ERROR in ViECapture::AllocateCaptureDevice\n"); 221 return -1; 222 } 223 224 error = vie_capture->ConnectCaptureDevice(capture_id, video_channel); 225 if (error == -1) { 226 printf("ERROR in ViECapture::ConnectCaptureDevice\n"); 227 return -1; 228 } 229 230 error = vie_capture->StartCapture(capture_id); 231 if (error == -1) { 232 printf("ERROR in ViECapture::StartCapture\n"); 233 return -1; 234 } 235 236 // RTP/RTCP settings. 237 error = vie_rtp_rtcp->SetRTCPStatus(video_channel, 238 webrtc::kRtcpCompound_RFC4585); 239 if (error == -1) { 240 printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); 241 return -1; 242 } 243 244 vie_rtp_rtcp->SetRembStatus(video_channel, true, false); 245 if (error == -1) { 246 printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); 247 return -1; 248 } 249 250 error = vie_rtp_rtcp->SetKeyFrameRequestMethod( 251 video_channel, webrtc::kViEKeyFrameRequestPliRtcp); 252 if (error == -1) { 253 printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n"); 254 return -1; 255 } 256 257 for (int i = 0; i < kNumStreams; ++i) { 258 error = vie_rtp_rtcp->SetRTCPStatus(receive_channels[i], 259 webrtc::kRtcpCompound_RFC4585); 260 if (error == -1) { 261 printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); 262 return -1; 263 } 264 265 vie_rtp_rtcp->SetRembStatus(receive_channels[i], false, true); 266 if (error == -1) { 267 printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); 268 return -1; 269 } 270 271 error = vie_rtp_rtcp->SetKeyFrameRequestMethod( 272 receive_channels[i], webrtc::kViEKeyFrameRequestPliRtcp); 273 if (error == -1) { 274 printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n"); 275 return -1; 276 } 277 } 278 279 // Set up rendering. 280 webrtc::ViERender* vie_render = webrtc::ViERender::GetInterface(video_engine); 281 if (vie_render == NULL) { 282 printf("ERROR in ViERender::GetInterface\n"); 283 return -1; 284 } 285 286 error = vie_render->AddRenderer(capture_id, window1, 0, 0.0, 0.0, 1.0, 1.0); 287 if (error == -1) { 288 printf("ERROR in ViERender::AddRenderer\n"); 289 return -1; 290 } 291 292 error = vie_render->StartRender(capture_id); 293 if (error == -1) { 294 printf("ERROR in ViERender::StartRender\n"); 295 return -1; 296 } 297 298 // Only rendering the thumbnail. 299 int channel_to_render = video_channel; 300 if (relay_mode == kRelayAllStreams) { 301 channel_to_render = receive_channels[0]; 302 } 303 error = vie_render->AddRenderer(channel_to_render, window2, 1, 0.0, 0.0, 1.0, 304 1.0); 305 if (error == -1) { 306 printf("ERROR in ViERender::AddRenderer\n"); 307 return -1; 308 } 309 310 error = vie_render->StartRender(channel_to_render); 311 if (error == -1) { 312 printf("ERROR in ViERender::StartRender\n"); 313 return -1; 314 } 315 316 // Setup codecs. 317 webrtc::ViECodec* vie_codec = webrtc::ViECodec::GetInterface(video_engine); 318 if (vie_codec == NULL) { 319 printf("ERROR in ViECodec::GetInterface\n"); 320 return -1; 321 } 322 323 // Check available codecs and prepare receive codecs. 324 printf("\nAvailable codecs:\n"); 325 webrtc::VideoCodec video_codec; 326 memset(&video_codec, 0, sizeof(webrtc::VideoCodec)); 327 int codec_idx = 0; 328 for (codec_idx = 0; codec_idx < vie_codec->NumberOfCodecs(); codec_idx++) { 329 error = vie_codec->GetCodec(codec_idx, video_codec); 330 if (error == -1) { 331 printf("ERROR in ViECodec::GetCodec\n"); 332 return -1; 333 } 334 // Try to keep the test frame size small when I420. 335 if (video_codec.codecType != webrtc::kVideoCodecVP8) { 336 continue; 337 } 338 for (int i = 0; i < kNumStreams; ++i) { 339 error = vie_codec->SetReceiveCodec(receive_channels[i], video_codec); 340 if (error == -1) { 341 printf("ERROR in ViECodec::SetReceiveCodec\n"); 342 return -1; 343 } 344 } 345 if (video_codec.codecType != webrtc::kVideoCodecRED && 346 video_codec.codecType != webrtc::kVideoCodecULPFEC) { 347 printf("\t %d. %s\n", codec_idx + 1, video_codec.plName); 348 } 349 break; 350 } 351 error = vie_codec->GetCodec(codec_idx, video_codec); 352 if (error == -1) { 353 printf("ERROR in ViECodec::GetCodec\n"); 354 return -1; 355 } 356 357 bool simulcast_mode = true; 358 int num_streams = 1; 359 // Set spatial resolution option. 360 if (simulcast_mode) { 361 SetSimulcastSettings(&video_codec); 362 num_streams = video_codec.numberOfSimulcastStreams; 363 } else { 364 InitialSingleStreamSettings(&video_codec); 365 num_streams = 1; 366 } 367 368 // Set start bit rate. 369 std::string str; 370 std::cout << std::endl; 371 std::cout << "Choose start rate (in kbps). Press enter for default: "; 372 std::getline(std::cin, str); 373 int start_rate = atoi(str.c_str()); 374 if (start_rate != 0) { 375 video_codec.startBitrate = start_rate; 376 } 377 378 error = vie_codec->SetSendCodec(video_channel, video_codec); 379 if (error == -1) { 380 printf("ERROR in ViECodec::SetSendCodec\n"); 381 return -1; 382 } 383 384 // Address settings. 385 webrtc::ViENetwork* vie_network = 386 webrtc::ViENetwork::GetInterface(video_engine); 387 if (vie_network == NULL) { 388 printf("ERROR in ViENetwork::GetInterface\n"); 389 return -1; 390 } 391 392 TbExternalTransport::SsrcChannelMap ssrc_channel_map; 393 for (int idx = 0; idx < num_streams; idx++) { 394 error = vie_rtp_rtcp->SetLocalSSRC(video_channel, idx + 1, // SSRC 395 webrtc::kViEStreamTypeNormal, idx); 396 ssrc_channel_map[idx + 1] = receive_channels[idx]; 397 if (error == -1) { 398 printf("ERROR in ViERTP_RTCP::SetLocalSSRC(idx:%d)\n", 399 idx); 400 return -1; 401 } 402 } 403 404 TbExternalTransport::SsrcChannelMap* channel_map = &ssrc_channel_map; 405 if (relay_mode == kRelayOneStream) { 406 channel_map = NULL; 407 } 408 409 // Setting External transport. 410 TbExternalTransport ext_transport(*vie_network, video_channel, channel_map); 411 412 error = vie_network->RegisterSendTransport(video_channel, ext_transport); 413 if (error == -1) { 414 printf("ERROR in ViECodec::RegisterSendTransport \n"); 415 return -1; 416 } 417 418 for (int i = 0; i < kNumStreams; ++i) { 419 error = vie_network->RegisterSendTransport(receive_channels[i], 420 ext_transport); 421 if (error == -1) { 422 printf("ERROR in ViECodec::RegisterSendTransport \n"); 423 return -1; 424 } 425 } 426 427 // Set network one-way delay value. 428 // 10 ms one-way delay. 429 NetworkParameters network; 430 network.loss_model = kUniformLoss; 431 network.mean_one_way_delay = 10; 432 ext_transport.SetNetworkParameters(network); 433 434 if (relay_mode == kRelayOneStream) { 435 ext_transport.SetSSRCFilter(num_streams); 436 } 437 438 error = vie_base->StartSend(video_channel); 439 if (error == -1) { 440 printf("ERROR in ViENetwork::StartSend\n"); 441 return -1; 442 } 443 error = vie_base->StartReceive(video_channel); 444 if (error == -1) { 445 printf("ERROR in ViENetwork::StartReceive\n"); 446 return -1; 447 } 448 449 for (int i = 0; i < kNumStreams; ++i) { 450 error = vie_base->StartReceive(receive_channels[i]); 451 if (error == -1) { 452 printf("ERROR in ViENetwork::StartReceive\n"); 453 return -1; 454 } 455 } 456 457 // Create a receive channel to verify that it doesn't mess up toggling 458 // between single stream and simulcast. 459 int video_channel2 = -1; 460 error = vie_base->CreateReceiveChannel(video_channel2, video_channel); 461 if (error == -1) { 462 printf("ERROR in ViEBase::CreateReceiveChannel\n"); 463 return -1; 464 } 465 466 // ******************************************************* 467 // Engine started 468 // ******************************************************* 469 470 printf("\nSimulcast call started\n\n"); 471 do { 472 printf("Enter new SSRC filter 1,2 or 3\n"); 473 printf("... or 0 to switch between simulcast and a single stream\n"); 474 printf("Press enter to stop..."); 475 str.clear(); 476 std::getline(std::cin, str); 477 if (!str.empty()) { 478 int ssrc = atoi(str.c_str()); 479 if (ssrc == 0) { 480 // Toggle between simulcast and a single stream with different 481 // resolution. 482 if (simulcast_mode) { 483 RuntimeSingleStreamSettings(&video_codec); 484 num_streams = 1; 485 printf("Disabling simulcast\n"); 486 } else { 487 SetSimulcastSettings(&video_codec); 488 num_streams = video_codec.numberOfSimulcastStreams; 489 printf("Enabling simulcast\n"); 490 } 491 simulcast_mode = !simulcast_mode; 492 if (vie_codec->SetSendCodec(video_channel, video_codec) != 0) { 493 printf("ERROR switching between simulcast and single stream\n"); 494 return -1; 495 } 496 for (int idx = 0; idx < num_streams; idx++) { 497 error = vie_rtp_rtcp->SetLocalSSRC(video_channel, idx + 1, // SSRC 498 webrtc::kViEStreamTypeNormal, idx); 499 if (error == -1) { 500 printf("ERROR in ViERTP_RTCP::SetLocalSSRC(idx:%d)\n", idx); 501 return -1; 502 } 503 } 504 if (relay_mode == kRelayOneStream) { 505 ext_transport.SetSSRCFilter(num_streams); 506 } 507 } else if (ssrc > 0 && ssrc < 4) { 508 if (relay_mode == kRelayOneStream) { 509 ext_transport.SetSSRCFilter(ssrc); 510 } 511 } else { 512 printf("Invalid SSRC\n"); 513 } 514 } else { 515 break; 516 } 517 } while (true); 518 519 // ******************************************************* 520 // Testing finished. Tear down Video Engine 521 // ******************************************************* 522 error = vie_base->DeleteChannel(video_channel2); 523 if (error == -1) { 524 printf("ERROR in ViEBase::DeleteChannel\n"); 525 return -1; 526 } 527 528 for (int i = 0; i < kNumStreams; ++i) { 529 error = vie_base->StopReceive(receive_channels[i]); 530 if (error == -1) { 531 printf("ERROR in ViEBase::StopReceive\n"); 532 return -1; 533 } 534 } 535 536 error = vie_base->StopReceive(video_channel); 537 if (error == -1) { 538 printf("ERROR in ViEBase::StopReceive\n"); 539 return -1; 540 } 541 542 error = vie_base->StopSend(video_channel); 543 if (error == -1) { 544 printf("ERROR in ViEBase::StopSend\n"); 545 return -1; 546 } 547 548 error = vie_render->StopRender(capture_id); 549 if (error == -1) { 550 printf("ERROR in ViERender::StopRender\n"); 551 return -1; 552 } 553 554 error = vie_render->RemoveRenderer(capture_id); 555 if (error == -1) { 556 printf("ERROR in ViERender::RemoveRenderer\n"); 557 return -1; 558 } 559 560 error = vie_render->StopRender(channel_to_render); 561 if (error == -1) { 562 printf("ERROR in ViERender::StopRender\n"); 563 return -1; 564 } 565 566 error = vie_render->RemoveRenderer(channel_to_render); 567 if (error == -1) { 568 printf("ERROR in ViERender::RemoveRenderer\n"); 569 return -1; 570 } 571 572 error = vie_capture->StopCapture(capture_id); 573 if (error == -1) { 574 printf("ERROR in ViECapture::StopCapture\n"); 575 return -1; 576 } 577 578 error = vie_capture->DisconnectCaptureDevice(video_channel); 579 if (error == -1) { 580 printf("ERROR in ViECapture::DisconnectCaptureDevice\n"); 581 return -1; 582 } 583 584 error = vie_capture->ReleaseCaptureDevice(capture_id); 585 if (error == -1) { 586 printf("ERROR in ViECapture::ReleaseCaptureDevice\n"); 587 return -1; 588 } 589 590 for (int i = 0; i < kNumStreams; ++i) { 591 error = vie_base->DeleteChannel(receive_channels[i]); 592 if (error == -1) { 593 printf("ERROR in ViEBase::DeleteChannel\n"); 594 return -1; 595 } 596 } 597 598 error = vie_base->DeleteChannel(video_channel); 599 if (error == -1) { 600 printf("ERROR in ViEBase::DeleteChannel\n"); 601 return -1; 602 } 603 604 int remaining_interfaces = 0; 605 remaining_interfaces = vie_codec->Release(); 606 remaining_interfaces += vie_capture->Release(); 607 remaining_interfaces += vie_rtp_rtcp->Release(); 608 remaining_interfaces += vie_render->Release(); 609 remaining_interfaces += vie_network->Release(); 610 remaining_interfaces += vie_base->Release(); 611 if (remaining_interfaces > 0) { 612 printf("ERROR: Could not release all interfaces\n"); 613 return -1; 614 } 615 616 bool deleted = webrtc::VideoEngine::Delete(video_engine); 617 if (deleted == false) { 618 printf("ERROR in VideoEngine::Delete\n"); 619 return -1; 620 } 621 return 0; 622 } 623 624 int ViEAutoTest::ViESimulcastCall() { 625 ViETest::Log(" "); 626 ViETest::Log("========================================"); 627 ViETest::Log(" ViE Autotest Simulcast Call\n"); 628 629 if (VideoEngineSimulcastTest(_window1, _window2) == 0) { 630 ViETest::Log(" "); 631 ViETest::Log(" ViE Autotest Simulcast Call Done"); 632 ViETest::Log("========================================"); 633 ViETest::Log(" "); 634 635 return 0; 636 } 637 ViETest::Log(" "); 638 ViETest::Log(" ViE Autotest Simulcast Call Failed"); 639 ViETest::Log("========================================"); 640 ViETest::Log(" "); 641 return 1; 642 } 643