blob: d6607457a75b4cfaafa304e17391075d79596f86 [file] [log] [blame]
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
//
// vie_autotest_loopback.cc
//
// This code is also used as sample code for ViE 3.0
//
// ===================================================================
//
// BEGIN: VideoEngine 3.0 Sample Code
//
#include <iostream>
#include "common_types.h"
#include "tb_external_transport.h"
#include "voe_base.h"
#include "vie_autotest_defines.h"
#include "vie_autotest.h"
#include "vie_base.h"
#include "vie_capture.h"
#include "vie_codec.h"
#include "vie_network.h"
#include "vie_render.h"
#include "vie_rtp_rtcp.h"
#define VCM_RED_PAYLOAD_TYPE 96
#define VCM_ULPFEC_PAYLOAD_TYPE 97
int VideoEngineSampleCode(void* window1, void* window2)
{
//********************************************************
// Begin create/initialize Video Engine for testing
//********************************************************
int error = 0;
//
// Create a VideoEngine instance
//
webrtc::VideoEngine* ptrViE = NULL;
ptrViE = webrtc::VideoEngine::Create();
if (ptrViE == NULL)
{
printf("ERROR in VideoEngine::Create\n");
return -1;
}
error = ptrViE->SetTraceFilter(webrtc::kTraceAll);
if (error == -1)
{
printf("ERROR in VideoEngine::SetTraceLevel\n");
return -1;
}
std::string trace_file =
ViETest::GetResultOutputPath() + "ViELoopbackCall_trace.txt";
error = ptrViE->SetTraceFile(trace_file.c_str());
if (error == -1)
{
printf("ERROR in VideoEngine::SetTraceFile\n");
return -1;
}
//
// Init VideoEngine and create a channel
//
webrtc::ViEBase* ptrViEBase = webrtc::ViEBase::GetInterface(ptrViE);
if (ptrViEBase == NULL)
{
printf("ERROR in ViEBase::GetInterface\n");
return -1;
}
error = ptrViEBase->Init();
if (error == -1)
{
printf("ERROR in ViEBase::Init\n");
return -1;
}
int videoChannel = -1;
error = ptrViEBase->CreateChannel(videoChannel);
if (error == -1)
{
printf("ERROR in ViEBase::CreateChannel\n");
return -1;
}
//
// List available capture devices, allocate and connect.
//
webrtc::ViECapture* ptrViECapture =
webrtc::ViECapture::GetInterface(ptrViE);
if (ptrViEBase == NULL)
{
printf("ERROR in ViECapture::GetInterface\n");
return -1;
}
const unsigned int KMaxDeviceNameLength = 128;
const unsigned int KMaxUniqueIdLength = 256;
char deviceName[KMaxDeviceNameLength];
memset(deviceName, 0, KMaxDeviceNameLength);
char uniqueId[KMaxUniqueIdLength];
memset(uniqueId, 0, KMaxUniqueIdLength);
printf("Available capture devices:\n");
int captureIdx = 0;
for (captureIdx = 0;
captureIdx < ptrViECapture->NumberOfCaptureDevices();
captureIdx++)
{
memset(deviceName, 0, KMaxDeviceNameLength);
memset(uniqueId, 0, KMaxUniqueIdLength);
error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName,
KMaxDeviceNameLength, uniqueId,
KMaxUniqueIdLength);
if (error == -1)
{
printf("ERROR in ViECapture::GetCaptureDevice\n");
return -1;
}
printf("\t %d. %s\n", captureIdx + 1, deviceName);
}
printf("\nChoose capture device: ");
#ifdef WEBRTC_ANDROID
captureIdx = 0;
printf("0\n");
#else
if (scanf("%d", &captureIdx) != 1)
{
printf("Error in scanf()\n");
return -1;
}
getchar();
captureIdx = captureIdx - 1; // Compensate for idx start at 1.
#endif
error = ptrViECapture->GetCaptureDevice(captureIdx, deviceName,
KMaxDeviceNameLength, uniqueId,
KMaxUniqueIdLength);
if (error == -1)
{
printf("ERROR in ViECapture::GetCaptureDevice\n");
return -1;
}
int captureId = 0;
error = ptrViECapture->AllocateCaptureDevice(uniqueId, KMaxUniqueIdLength,
captureId);
if (error == -1)
{
printf("ERROR in ViECapture::AllocateCaptureDevice\n");
return -1;
}
error = ptrViECapture->ConnectCaptureDevice(captureId, videoChannel);
if (error == -1)
{
printf("ERROR in ViECapture::ConnectCaptureDevice\n");
return -1;
}
error = ptrViECapture->StartCapture(captureId);
if (error == -1)
{
printf("ERROR in ViECapture::StartCapture\n");
return -1;
}
//
// RTP/RTCP settings
//
webrtc::ViERTP_RTCP* ptrViERtpRtcp =
webrtc::ViERTP_RTCP::GetInterface(ptrViE);
if (ptrViERtpRtcp == NULL)
{
printf("ERROR in ViERTP_RTCP::GetInterface\n");
return -1;
}
error = ptrViERtpRtcp->SetRTCPStatus(videoChannel,
webrtc::kRtcpCompound_RFC4585);
if (error == -1)
{
printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n");
return -1;
}
error = ptrViERtpRtcp->SetKeyFrameRequestMethod(
videoChannel, webrtc::kViEKeyFrameRequestPliRtcp);
if (error == -1)
{
printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n");
return -1;
}
error = ptrViERtpRtcp->SetRembStatus(videoChannel, true, true);
if (error == -1)
{
printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n");
return -1;
}
//
// Set up rendering
//
webrtc::ViERender* ptrViERender = webrtc::ViERender::GetInterface(ptrViE);
if (ptrViERender == NULL)
{
printf("ERROR in ViERender::GetInterface\n");
return -1;
}
error
= ptrViERender->AddRenderer(captureId, window1, 0, 0.0, 0.0, 1.0, 1.0);
if (error == -1)
{
printf("ERROR in ViERender::AddRenderer\n");
return -1;
}
error = ptrViERender->StartRender(captureId);
if (error == -1)
{
printf("ERROR in ViERender::StartRender\n");
return -1;
}
error = ptrViERender->AddRenderer(videoChannel, window2, 1, 0.0, 0.0, 1.0,
1.0);
if (error == -1)
{
printf("ERROR in ViERender::AddRenderer\n");
return -1;
}
error = ptrViERender->StartRender(videoChannel);
if (error == -1)
{
printf("ERROR in ViERender::StartRender\n");
return -1;
}
//
// Setup codecs
//
webrtc::ViECodec* ptrViECodec = webrtc::ViECodec::GetInterface(ptrViE);
if (ptrViECodec == NULL)
{
printf("ERROR in ViECodec::GetInterface\n");
return -1;
}
// Check available codecs and prepare receive codecs
printf("\nAvailable codecs:\n");
webrtc::VideoCodec videoCodec;
memset(&videoCodec, 0, sizeof(webrtc::VideoCodec));
int codecIdx = 0;
for (codecIdx = 0; codecIdx < ptrViECodec->NumberOfCodecs(); codecIdx++)
{
error = ptrViECodec->GetCodec(codecIdx, videoCodec);
if (error == -1)
{
printf("ERROR in ViECodec::GetCodec\n");
return -1;
}
// try to keep the test frame size small when I420
if (videoCodec.codecType == webrtc::kVideoCodecI420)
{
videoCodec.width = 176;
videoCodec.height = 144;
}
error = ptrViECodec->SetReceiveCodec(videoChannel, videoCodec);
if (error == -1)
{
printf("ERROR in ViECodec::SetReceiveCodec\n");
return -1;
}
if (videoCodec.codecType != webrtc::kVideoCodecRED
&& videoCodec.codecType != webrtc::kVideoCodecULPFEC)
{
printf("\t %d. %s\n", codecIdx + 1, videoCodec.plName);
}
}
printf("Choose codec: ");
#ifdef WEBRTC_ANDROID
codecIdx = 0;
printf("0\n");
#else
if (scanf("%d", &codecIdx) != 1)
{
printf("Error in scanf()\n");
return -1;
}
getchar();
codecIdx = codecIdx - 1; // Compensate for idx start at 1.
#endif
error = ptrViECodec->GetCodec(codecIdx, videoCodec);
if (error == -1)
{
printf("ERROR in ViECodec::GetCodec\n");
return -1;
}
// Set spatial resolution option
std::string str;
std::cout << std::endl;
std::cout << "Enter frame size option (default is CIF):" << std::endl;
std::cout << "1. QCIF (176X144) " << std::endl;
std::cout << "2. CIF (352X288) " << std::endl;
std::cout << "3. VGA (640X480) " << std::endl;
std::cout << "4. 4CIF (704X576) " << std::endl;
std::cout << "5. WHD (1280X720) " << std::endl;
std::getline(std::cin, str);
int resolnOption = atoi(str.c_str());
// Try to keep the test frame size small when I420
if (videoCodec.codecType == webrtc::kVideoCodecI420)
{
resolnOption = 1;
}
switch (resolnOption)
{
case 1:
videoCodec.width = 176;
videoCodec.height = 144;
break;
case 2:
videoCodec.width = 352;
videoCodec.height = 288;
break;
case 3:
videoCodec.width = 640;
videoCodec.height = 480;
break;
case 4:
videoCodec.width = 704;
videoCodec.height = 576;
break;
case 5:
videoCodec.width = 1280;
videoCodec.height = 720;
break;
}
// Set number of temporal layers.
std::cout << std::endl;
std::cout << "Choose number of temporal layers (1 to 4).";
std::cout << "Press enter for default: \n";
std::getline(std::cin, str);
int numTemporalLayers = atoi(str.c_str());
if(numTemporalLayers != 0)
{
videoCodec.codecSpecific.VP8.numberOfTemporalLayers = numTemporalLayers;
}
// Set start bit rate
std::cout << std::endl;
std::cout << "Choose start rate (in kbps). Press enter for default: ";
std::getline(std::cin, str);
int startRate = atoi(str.c_str());
if(startRate != 0)
{
videoCodec.startBitrate=startRate;
}
error = ptrViECodec->SetSendCodec(videoChannel, videoCodec);
if (error == -1)
{
printf("ERROR in ViECodec::SetSendCodec\n");
return -1;
}
//
// Choose Protection Mode
//
std::cout << std::endl;
std::cout << "Enter Protection Method:" << std::endl;
std::cout << "0. None" << std::endl;
std::cout << "1. FEC" << std::endl;
std::cout << "2. NACK" << std::endl;
std::cout << "3. NACK+FEC" << std::endl;
std::getline(std::cin, str);
int protectionMethod = atoi(str.c_str());
error = 0;
bool temporalToggling = true;
switch (protectionMethod)
{
case 0: // None: default is no protection
break;
case 1: // FEC only
error = ptrViERtpRtcp->SetFECStatus(videoChannel,
true,
VCM_RED_PAYLOAD_TYPE,
VCM_ULPFEC_PAYLOAD_TYPE);
temporalToggling = false;
break;
case 2: // Nack only
error = ptrViERtpRtcp->SetNACKStatus(videoChannel, true);
break;
case 3: // Hybrid NAck and FEC
error = ptrViERtpRtcp->SetHybridNACKFECStatus(
videoChannel,
true,
VCM_RED_PAYLOAD_TYPE,
VCM_ULPFEC_PAYLOAD_TYPE);
temporalToggling = false;
break;
}
if (error < 0)
{
printf("ERROR in ViERTP_RTCP::SetProtectionStatus\n");
}
//
// Address settings
//
webrtc::ViENetwork* ptrViENetwork =
webrtc::ViENetwork::GetInterface(ptrViE);
if (ptrViENetwork == NULL)
{
printf("ERROR in ViENetwork::GetInterface\n");
return -1;
}
// Setting External transport
TbExternalTransport extTransport(*(ptrViENetwork));
int testMode = 0;
std::cout << std::endl;
std::cout << "Enter 1 for testing packet loss and delay with "
"external transport: ";
std::string test_str;
std::getline(std::cin, test_str);
testMode = atoi(test_str.c_str());
if (testMode == 1)
{
// Avoid changing SSRC due to collision.
error = ptrViERtpRtcp->SetLocalSSRC(videoChannel, 1);
error = ptrViENetwork->RegisterSendTransport(videoChannel,
extTransport);
if (error == -1)
{
printf("ERROR in ViECodec::RegisterSendTransport \n");
return -1;
}
// Set up packet loss value
std::cout << "Enter Packet Loss Percentage" << std::endl;
std::string rate_str;
std::getline(std::cin, rate_str);
int rate = atoi(rate_str.c_str());
extTransport.SetPacketLoss(rate);
if (rate) {
temporalToggling = false;
}
// Set network delay value
std::cout << "Enter network delay value [mS]" << std::endl;
std::string delay_str;
std::getline(std::cin, delay_str);
int delayMs = atoi(delay_str.c_str());
extTransport.SetNetworkDelay(delayMs);
if (numTemporalLayers > 1 && temporalToggling) {
extTransport.SetTemporalToggle(numTemporalLayers);
} else {
// Disabled
extTransport.SetTemporalToggle(0);
}
}
else
{
const char* ipAddress = "127.0.0.1";
const unsigned short rtpPort = 6000;
std::cout << std::endl;
std::cout << "Using rtp port: " << rtpPort << std::endl;
std::cout << std::endl;
error = ptrViENetwork->SetLocalReceiver(videoChannel, rtpPort);
if (error == -1)
{
printf("ERROR in ViENetwork::SetLocalReceiver\n");
return -1;
}
error = ptrViENetwork->SetSendDestination(videoChannel,
ipAddress, rtpPort);
if (error == -1)
{
printf("ERROR in ViENetwork::SetSendDestination\n");
return -1;
}
}
error = ptrViEBase->StartReceive(videoChannel);
if (error == -1)
{
printf("ERROR in ViENetwork::StartReceive\n");
return -1;
}
error = ptrViEBase->StartSend(videoChannel);
if (error == -1)
{
printf("ERROR in ViENetwork::StartSend\n");
return -1;
}
//********************************************************
// Engine started
//********************************************************
// Call started
printf("\nLoopback call started\n\n");
printf("Press enter to stop...");
while ((getchar()) != '\n')
;
//********************************************************
// Testing finished. Tear down Video Engine
//********************************************************
error = ptrViEBase->StopReceive(videoChannel);
if (error == -1)
{
printf("ERROR in ViEBase::StopReceive\n");
return -1;
}
error = ptrViEBase->StopSend(videoChannel);
if (error == -1)
{
printf("ERROR in ViEBase::StopSend\n");
return -1;
}
error = ptrViERender->StopRender(captureId);
if (error == -1)
{
printf("ERROR in ViERender::StopRender\n");
return -1;
}
error = ptrViERender->RemoveRenderer(captureId);
if (error == -1)
{
printf("ERROR in ViERender::RemoveRenderer\n");
return -1;
}
error = ptrViERender->StopRender(videoChannel);
if (error == -1)
{
printf("ERROR in ViERender::StopRender\n");
return -1;
}
error = ptrViERender->RemoveRenderer(videoChannel);
if (error == -1)
{
printf("ERROR in ViERender::RemoveRenderer\n");
return -1;
}
error = ptrViECapture->StopCapture(captureId);
if (error == -1)
{
printf("ERROR in ViECapture::StopCapture\n");
return -1;
}
error = ptrViECapture->DisconnectCaptureDevice(videoChannel);
if (error == -1)
{
printf("ERROR in ViECapture::DisconnectCaptureDevice\n");
return -1;
}
error = ptrViECapture->ReleaseCaptureDevice(captureId);
if (error == -1)
{
printf("ERROR in ViECapture::ReleaseCaptureDevice\n");
return -1;
}
error = ptrViEBase->DeleteChannel(videoChannel);
if (error == -1)
{
printf("ERROR in ViEBase::DeleteChannel\n");
return -1;
}
int remainingInterfaces = 0;
remainingInterfaces = ptrViECodec->Release();
remainingInterfaces += ptrViECapture->Release();
remainingInterfaces += ptrViERtpRtcp->Release();
remainingInterfaces += ptrViERender->Release();
remainingInterfaces += ptrViENetwork->Release();
remainingInterfaces += ptrViEBase->Release();
if (remainingInterfaces > 0)
{
printf("ERROR: Could not release all interfaces\n");
return -1;
}
bool deleted = webrtc::VideoEngine::Delete(ptrViE);
if (deleted == false)
{
printf("ERROR in VideoEngine::Delete\n");
return -1;
}
return 0;
//
// END: VideoEngine 3.0 Sample Code
//
// ===================================================================
}
int ViEAutoTest::ViELoopbackCall()
{
ViETest::Log(" ");
ViETest::Log("========================================");
ViETest::Log(" ViE Autotest Loopback Call\n");
if (VideoEngineSampleCode(_window1, _window2) == 0)
{
ViETest::Log(" ");
ViETest::Log(" ViE Autotest Loopback Call Done");
ViETest::Log("========================================");
ViETest::Log(" ");
return 0;
}
ViETest::Log(" ");
ViETest::Log(" ViE Autotest Loopback Call Failed");
ViETest::Log("========================================");
ViETest::Log(" ");
return 1;
}