/webrtc/video_engine/test/auto_test/source/vie_autotest_loopback.cc
C++ | 691 lines | 544 code | 79 blank | 68 comment | 121 complexity | 8485972d800135b8492e8b90751b3818 MD5 | raw file
1/* 2 * Copyright (c) 2011 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// 12// vie_autotest_loopback.cc 13// 14// This code is also used as sample code for ViE 3.0 15// 16 17// =================================================================== 18// 19// BEGIN: VideoEngine 3.0 Sample Code 20// 21 22#include <iostream> 23 24#include "common_types.h" 25#include "tb_external_transport.h" 26#include "voe_base.h" 27#include "vie_autotest_defines.h" 28#include "vie_autotest.h" 29#include "vie_base.h" 30#include "vie_capture.h" 31#include "vie_codec.h" 32#include "vie_network.h" 33#include "vie_render.h" 34#include "vie_rtp_rtcp.h" 35 36#define VCM_RED_PAYLOAD_TYPE 96 37#define VCM_ULPFEC_PAYLOAD_TYPE 97 38 39int VideoEngineSampleCode(void* window1, void* window2) 40{ 41 //******************************************************** 42 // Begin create/initialize Video Engine for testing 43 //******************************************************** 44 45 int error = 0; 46 47 // 48 // Create a VideoEngine instance 49 // 50 webrtc::VideoEngine* ptrViE = NULL; 51 ptrViE = webrtc::VideoEngine::Create(); 52 if (ptrViE == NULL) 53 { 54 printf("ERROR in VideoEngine::Create\n"); 55 return -1; 56 } 57 58 error = ptrViE->SetTraceFilter(webrtc::kTraceAll); 59 if (error == -1) 60 { 61 printf("ERROR in VideoEngine::SetTraceLevel\n"); 62 return -1; 63 } 64 65 std::string trace_file = 66 ViETest::GetResultOutputPath() + "ViELoopbackCall_trace.txt"; 67 error = ptrViE->SetTraceFile(trace_file.c_str()); 68 if (error == -1) 69 { 70 printf("ERROR in VideoEngine::SetTraceFile\n"); 71 return -1; 72 } 73 74 // 75 // Init VideoEngine and create a channel 76 // 77 webrtc::ViEBase* ptrViEBase = webrtc::ViEBase::GetInterface(ptrViE); 78 if (ptrViEBase == NULL) 79 { 80 printf("ERROR in ViEBase::GetInterface\n"); 81 return -1; 82 } 83 84 error = ptrViEBase->Init(); 85 if (error == -1) 86 { 87 printf("ERROR in ViEBase::Init\n"); 88 return -1; 89 } 90 91 webrtc::ViERTP_RTCP* ptrViERtpRtcp = 92 webrtc::ViERTP_RTCP::GetInterface(ptrViE); 93 if (ptrViERtpRtcp == NULL) 94 { 95 printf("ERROR in ViERTP_RTCP::GetInterface\n"); 96 return -1; 97 } 98 99 printf("Bandwidth estimation modes:\n"); 100 printf("1. Multi-stream bandwidth estimation\n"); 101 printf("2. Single-stream bandwidth estimation\n"); 102 printf("Choose bandwidth estimation mode (default is 1): "); 103 std::string str; 104 std::getline(std::cin, str); 105 int bwe_mode_choice = atoi(str.c_str()); 106 webrtc::BandwidthEstimationMode bwe_mode; 107 switch (bwe_mode_choice) { 108 case 1: 109 bwe_mode = webrtc::kViEMultiStreamEstimation; 110 break; 111 case 2: 112 bwe_mode = webrtc::kViESingleStreamEstimation; 113 break; 114 default: 115 bwe_mode = webrtc::kViEMultiStreamEstimation; 116 break; 117 } 118 119 error = ptrViERtpRtcp->SetBandwidthEstimationMode(bwe_mode); 120 if (error == -1) 121 { 122 printf("ERROR in ViERTP_RTCP::SetBandwidthEstimationMode\n"); 123 return -1; 124 } 125 126 int videoChannel = -1; 127 error = ptrViEBase->CreateChannel(videoChannel); 128 if (error == -1) 129 { 130 printf("ERROR in ViEBase::CreateChannel\n"); 131 return -1; 132 } 133 134 // 135 // List available capture devices, allocate and connect. 136 // 137 webrtc::ViECapture* ptrViECapture = 138 webrtc::ViECapture::GetInterface(ptrViE); 139 if (ptrViEBase == NULL) 140 { 141 printf("ERROR in ViECapture::GetInterface\n"); 142 return -1; 143 } 144 145 const unsigned int KMaxDeviceNameLength = 128; 146 const unsigned int KMaxUniqueIdLength = 256; 147 char deviceName[KMaxDeviceNameLength]; 148 memset(deviceName, 0, KMaxDeviceNameLength); 149 char uniqueId[KMaxUniqueIdLength]; 150 memset(uniqueId, 0, KMaxUniqueIdLength); 151 152 printf("Available capture devices:\n"); 153 int captureIdx = 0; 154 for (captureIdx = 0; 155 captureIdx < ptrViECapture->NumberOfCaptureDevices(); 156 captureIdx++) 157 { 158 memset(deviceName, 0, KMaxDeviceNameLength); 159 memset(uniqueId, 0, KMaxUniqueIdLength); 160 161 error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, 162 KMaxDeviceNameLength, uniqueId, 163 KMaxUniqueIdLength); 164 if (error == -1) 165 { 166 printf("ERROR in ViECapture::GetCaptureDevice\n"); 167 return -1; 168 } 169 printf("\t %d. %s\n", captureIdx + 1, deviceName); 170 } 171 printf("\nChoose capture device: "); 172#ifdef WEBRTC_ANDROID 173 captureIdx = 0; 174 printf("0\n"); 175#else 176 if (scanf("%d", &captureIdx) != 1) 177 { 178 printf("Error in scanf()\n"); 179 return -1; 180 } 181 getchar(); 182 captureIdx = captureIdx - 1; // Compensate for idx start at 1. 183#endif 184 error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName, 185 KMaxDeviceNameLength, uniqueId, 186 KMaxUniqueIdLength); 187 if (error == -1) 188 { 189 printf("ERROR in ViECapture::GetCaptureDevice\n"); 190 return -1; 191 } 192 193 int captureId = 0; 194 error = ptrViECapture->AllocateCaptureDevice(uniqueId, KMaxUniqueIdLength, 195 captureId); 196 if (error == -1) 197 { 198 printf("ERROR in ViECapture::AllocateCaptureDevice\n"); 199 return -1; 200 } 201 202 error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel); 203 if (error == -1) 204 { 205 printf("ERROR in ViECapture::ConnectCaptureDevice\n"); 206 return -1; 207 } 208 209 error = ptrViECapture->StartCapture(captureId); 210 if (error == -1) 211 { 212 printf("ERROR in ViECapture::StartCapture\n"); 213 return -1; 214 } 215 216 // 217 // RTP/RTCP settings 218 // 219 220 error = ptrViERtpRtcp->SetRTCPStatus(videoChannel, 221 webrtc::kRtcpCompound_RFC4585); 222 if (error == -1) 223 { 224 printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n"); 225 return -1; 226 } 227 228 error = ptrViERtpRtcp->SetKeyFrameRequestMethod( 229 videoChannel, webrtc::kViEKeyFrameRequestPliRtcp); 230 if (error == -1) 231 { 232 printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n"); 233 return -1; 234 } 235 236 error = ptrViERtpRtcp->SetRembStatus(videoChannel, true, true); 237 if (error == -1) 238 { 239 printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n"); 240 return -1; 241 } 242 243 // 244 // Set up rendering 245 // 246 webrtc::ViERender* ptrViERender = webrtc::ViERender::GetInterface(ptrViE); 247 if (ptrViERender == NULL) 248 { 249 printf("ERROR in ViERender::GetInterface\n"); 250 return -1; 251 } 252 253 error 254 = ptrViERender->AddRenderer(captureId, window1, 0, 0.0, 0.0, 1.0, 1.0); 255 if (error == -1) 256 { 257 printf("ERROR in ViERender::AddRenderer\n"); 258 return -1; 259 } 260 261 error = ptrViERender->StartRender(captureId); 262 if (error == -1) 263 { 264 printf("ERROR in ViERender::StartRender\n"); 265 return -1; 266 } 267 268 error = ptrViERender->AddRenderer(videoChannel, window2, 1, 0.0, 0.0, 1.0, 269 1.0); 270 if (error == -1) 271 { 272 printf("ERROR in ViERender::AddRenderer\n"); 273 return -1; 274 } 275 276 error = ptrViERender->StartRender(videoChannel); 277 if (error == -1) 278 { 279 printf("ERROR in ViERender::StartRender\n"); 280 return -1; 281 } 282 283 // 284 // Setup codecs 285 // 286 webrtc::ViECodec* ptrViECodec = webrtc::ViECodec::GetInterface(ptrViE); 287 if (ptrViECodec == NULL) 288 { 289 printf("ERROR in ViECodec::GetInterface\n"); 290 return -1; 291 } 292 293 // Check available codecs and prepare receive codecs 294 printf("\nAvailable codecs:\n"); 295 webrtc::VideoCodec videoCodec; 296 memset(&videoCodec, 0, sizeof(webrtc::VideoCodec)); 297 int codecIdx = 0; 298 for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); codecIdx++) 299 { 300 error = ptrViECodec->GetCodec(codecIdx, videoCodec); 301 if (error == -1) 302 { 303 printf("ERROR in ViECodec::GetCodec\n"); 304 return -1; 305 } 306 307 // try to keep the test frame size small when I420 308 if (videoCodec.codecType == webrtc::kVideoCodecI420) 309 { 310 videoCodec.width = 176; 311 videoCodec.height = 144; 312 } 313 314 error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec); 315 if (error == -1) 316 { 317 printf("ERROR in ViECodec::SetReceiveCodec\n"); 318 return -1; 319 } 320 if (videoCodec.codecType != webrtc::kVideoCodecRED 321 && videoCodec.codecType != webrtc::kVideoCodecULPFEC) 322 { 323 printf("\t %d. %s\n", codecIdx + 1, videoCodec.plName); 324 } 325 } 326 printf("Choose codec: "); 327#ifdef WEBRTC_ANDROID 328 codecIdx = 0; 329 printf("0\n"); 330#else 331 if (scanf("%d", &codecIdx) != 1) 332 { 333 printf("Error in scanf()\n"); 334 return -1; 335 } 336 getchar(); 337 codecIdx = codecIdx - 1; // Compensate for idx start at 1. 338#endif 339 340 error = ptrViECodec->GetCodec(codecIdx, videoCodec); 341 if (error == -1) 342 { 343 printf("ERROR in ViECodec::GetCodec\n"); 344 return -1; 345 } 346 347 // Set spatial resolution option 348 std::cout << std::endl; 349 std::cout << "Enter frame size option (default is CIF):" << std::endl; 350 std::cout << "1. QCIF (176X144) " << std::endl; 351 std::cout << "2. CIF (352X288) " << std::endl; 352 std::cout << "3. VGA (640X480) " << std::endl; 353 std::cout << "4. 4CIF (704X576) " << std::endl; 354 std::cout << "5. WHD (1280X720) " << std::endl; 355 std::getline(std::cin, str); 356 int resolnOption = atoi(str.c_str()); 357 // Try to keep the test frame size small when I420 358 if (videoCodec.codecType == webrtc::kVideoCodecI420) 359 { 360 resolnOption = 1; 361 } 362 switch (resolnOption) 363 { 364 case 1: 365 videoCodec.width = 176; 366 videoCodec.height = 144; 367 break; 368 case 2: 369 videoCodec.width = 352; 370 videoCodec.height = 288; 371 break; 372 case 3: 373 videoCodec.width = 640; 374 videoCodec.height = 480; 375 break; 376 case 4: 377 videoCodec.width = 704; 378 videoCodec.height = 576; 379 break; 380 case 5: 381 videoCodec.width = 1280; 382 videoCodec.height = 720; 383 break; 384 } 385 386 // Set number of temporal layers. 387 std::cout << std::endl; 388 std::cout << "Choose number of temporal layers (1 to 4)."; 389 std::cout << "Press enter for default: \n"; 390 std::getline(std::cin, str); 391 int numTemporalLayers = atoi(str.c_str()); 392 if(numTemporalLayers != 0) 393 { 394 videoCodec.codecSpecific.VP8.numberOfTemporalLayers = numTemporalLayers; 395 } 396 397 // Set start bit rate 398 std::cout << std::endl; 399 std::cout << "Choose start rate (in kbps). Press enter for default: "; 400 std::getline(std::cin, str); 401 int startRate = atoi(str.c_str()); 402 if(startRate != 0) 403 { 404 videoCodec.startBitrate=startRate; 405 } 406 407 error = ptrViECodec->SetSendCodec(videoChannel, videoCodec); 408 if (error == -1) 409 { 410 printf("ERROR in ViECodec::SetSendCodec\n"); 411 return -1; 412 } 413 414 // 415 // Choose Protection Mode 416 // 417 std::cout << std::endl; 418 std::cout << "Enter Protection Method:" << std::endl; 419 std::cout << "0. None" << std::endl; 420 std::cout << "1. FEC" << std::endl; 421 std::cout << "2. NACK" << std::endl; 422 std::cout << "3. NACK+FEC" << std::endl; 423 std::getline(std::cin, str); 424 int protectionMethod = atoi(str.c_str()); 425 error = 0; 426 bool temporalToggling = true; 427 switch (protectionMethod) 428 { 429 case 0: // None: default is no protection 430 break; 431 432 case 1: // FEC only 433 error = ptrViERtpRtcp->SetFECStatus(videoChannel, 434 true, 435 VCM_RED_PAYLOAD_TYPE, 436 VCM_ULPFEC_PAYLOAD_TYPE); 437 temporalToggling = false; 438 break; 439 440 case 2: // Nack only 441 error = ptrViERtpRtcp->SetNACKStatus(videoChannel, true); 442 443 break; 444 445 case 3: // Hybrid NAck and FEC 446 error = ptrViERtpRtcp->SetHybridNACKFECStatus( 447 videoChannel, 448 true, 449 VCM_RED_PAYLOAD_TYPE, 450 VCM_ULPFEC_PAYLOAD_TYPE); 451 temporalToggling = false; 452 break; 453 } 454 455 if (error < 0) 456 { 457 printf("ERROR in ViERTP_RTCP::SetProtectionStatus\n"); 458 } 459 460 461 // 462 // Address settings 463 // 464 webrtc::ViENetwork* ptrViENetwork = 465 webrtc::ViENetwork::GetInterface(ptrViE); 466 if (ptrViENetwork == NULL) 467 { 468 printf("ERROR in ViENetwork::GetInterface\n"); 469 return -1; 470 } 471 472 // Setting External transport 473 TbExternalTransport extTransport(*(ptrViENetwork), videoChannel, NULL); 474 475 int testMode = 0; 476 std::cout << std::endl; 477 std::cout << "Enter 1 for testing packet loss and delay with " 478 "external transport: "; 479 std::string test_str; 480 std::getline(std::cin, test_str); 481 testMode = atoi(test_str.c_str()); 482 if (testMode == 1) 483 { 484 // Avoid changing SSRC due to collision. 485 error = ptrViERtpRtcp->SetLocalSSRC(videoChannel, 1); 486 487 error = ptrViENetwork->RegisterSendTransport(videoChannel, 488 extTransport); 489 if (error == -1) 490 { 491 printf("ERROR in ViECodec::RegisterSendTransport \n"); 492 return -1; 493 } 494 495 // Setting uniform loss. Actual values will be set by user. 496 NetworkParameters network; 497 network.loss_model = kUniformLoss; 498 // Set up packet loss value 499 std::cout << "Enter Packet Loss Percentage" << std::endl; 500 std::string rate_str; 501 std::getline(std::cin, rate_str); 502 network.packet_loss_rate = atoi(rate_str.c_str()); 503 if (network.packet_loss_rate > 0) { 504 temporalToggling = false; 505 } 506 507 // Set network delay value 508 std::cout << "Enter network delay value [mS]" << std::endl; 509 std::string delay_str; 510 std::getline(std::cin, delay_str); 511 network.mean_one_way_delay = atoi(delay_str.c_str()); 512 extTransport.SetNetworkParameters(network); 513 if (numTemporalLayers > 1 && temporalToggling) { 514 extTransport.SetTemporalToggle(numTemporalLayers); 515 } else { 516 // Disabled 517 extTransport.SetTemporalToggle(0); 518 } 519 } 520 else 521 { 522 const char* ipAddress = "127.0.0.1"; 523 const unsigned short rtpPort = 6000; 524 std::cout << std::endl; 525 std::cout << "Using rtp port: " << rtpPort << std::endl; 526 std::cout << std::endl; 527 error = ptrViENetwork->SetLocalReceiver(videoChannel, rtpPort); 528 if (error == -1) 529 { 530 printf("ERROR in ViENetwork::SetLocalReceiver\n"); 531 return -1; 532 } 533 error = ptrViENetwork->SetSendDestination(videoChannel, 534 ipAddress, rtpPort); 535 if (error == -1) 536 { 537 printf("ERROR in ViENetwork::SetSendDestination\n"); 538 return -1; 539 } 540 } 541 542 error = ptrViEBase->StartReceive(videoChannel); 543 if (error == -1) 544 { 545 printf("ERROR in ViENetwork::StartReceive\n"); 546 return -1; 547 } 548 549 error = ptrViEBase->StartSend(videoChannel); 550 if (error == -1) 551 { 552 printf("ERROR in ViENetwork::StartSend\n"); 553 return -1; 554 } 555 556 //******************************************************** 557 // Engine started 558 //******************************************************** 559 560 561 // Call started 562 printf("\nLoopback call started\n\n"); 563 printf("Press enter to stop..."); 564 while ((getchar()) != '\n') 565 ; 566 567 //******************************************************** 568 // Testing finished. Tear down Video Engine 569 //******************************************************** 570 571 error = ptrViEBase->StopReceive(videoChannel); 572 if (error == -1) 573 { 574 printf("ERROR in ViEBase::StopReceive\n"); 575 return -1; 576 } 577 578 error = ptrViEBase->StopSend(videoChannel); 579 if (error == -1) 580 { 581 printf("ERROR in ViEBase::StopSend\n"); 582 return -1; 583 } 584 585 error = ptrViERender->StopRender(captureId); 586 if (error == -1) 587 { 588 printf("ERROR in ViERender::StopRender\n"); 589 return -1; 590 } 591 592 error = ptrViERender->RemoveRenderer(captureId); 593 if (error == -1) 594 { 595 printf("ERROR in ViERender::RemoveRenderer\n"); 596 return -1; 597 } 598 599 error = ptrViERender->StopRender(videoChannel); 600 if (error == -1) 601 { 602 printf("ERROR in ViERender::StopRender\n"); 603 return -1; 604 } 605 606 error = ptrViERender->RemoveRenderer(videoChannel); 607 if (error == -1) 608 { 609 printf("ERROR in ViERender::RemoveRenderer\n"); 610 return -1; 611 } 612 613 error = ptrViECapture->StopCapture(captureId); 614 if (error == -1) 615 { 616 printf("ERROR in ViECapture::StopCapture\n"); 617 return -1; 618 } 619 620 error = ptrViECapture->DisconnectCaptureDevice(videoChannel); 621 if (error == -1) 622 { 623 printf("ERROR in ViECapture::DisconnectCaptureDevice\n"); 624 return -1; 625 } 626 627 error = ptrViECapture->ReleaseCaptureDevice(captureId); 628 if (error == -1) 629 { 630 printf("ERROR in ViECapture::ReleaseCaptureDevice\n"); 631 return -1; 632 } 633 634 error = ptrViEBase->DeleteChannel(videoChannel); 635 if (error == -1) 636 { 637 printf("ERROR in ViEBase::DeleteChannel\n"); 638 return -1; 639 } 640 641 int remainingInterfaces = 0; 642 remainingInterfaces = ptrViECodec->Release(); 643 remainingInterfaces += ptrViECapture->Release(); 644 remainingInterfaces += ptrViERtpRtcp->Release(); 645 remainingInterfaces += ptrViERender->Release(); 646 remainingInterfaces += ptrViENetwork->Release(); 647 remainingInterfaces += ptrViEBase->Release(); 648 if (remainingInterfaces > 0) 649 { 650 printf("ERROR: Could not release all interfaces\n"); 651 return -1; 652 } 653 654 bool deleted = webrtc::VideoEngine::Delete(ptrViE); 655 if (deleted == false) 656 { 657 printf("ERROR in VideoEngine::Delete\n"); 658 return -1; 659 } 660 661 return 0; 662 663 // 664 // END: VideoEngine 3.0 Sample Code 665 // 666 // =================================================================== 667} 668 669int ViEAutoTest::ViELoopbackCall() 670{ 671 ViETest::Log(" "); 672 ViETest::Log("========================================"); 673 ViETest::Log(" ViE Autotest Loopback Call\n"); 674 675 if (VideoEngineSampleCode(_window1, _window2) == 0) 676 { 677 ViETest::Log(" "); 678 ViETest::Log(" ViE Autotest Loopback Call Done"); 679 ViETest::Log("========================================"); 680 ViETest::Log(" "); 681 682 return 0; 683 } 684 685 ViETest::Log(" "); 686 ViETest::Log(" ViE Autotest Loopback Call Failed"); 687 ViETest::Log("========================================"); 688 ViETest::Log(" "); 689 return 1; 690 691}