/* * 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. */ // testAPI.cpp : Defines the entry point for the console application. // #define _CRTDBG_MAP_ALLOC #include #include #include #include #include #include #include "rtp_rtcp.h" #include "common_types.h" #include "process_thread.h" #include "trace.h" #include "../source/ModuleRtpRtcpImpl.h" #define TEST_AUDIO #define TEST_VIDEO WebRtc_UWord8 _payloadDataFile[65000]; WebRtc_UWord16 _payloadDataFileLength; #define VIDEO_NACK_LIST_SIZE 30 class LoopBackTransport : public webrtc::Transport { public: LoopBackTransport(RtpRtcp* rtpRtcpModule) : _rtpRtcpModule(rtpRtcpModule) { _sendCount = 0; } virtual int SendPacket(int channel, const void *data, int len) { _sendCount++; if(_sendCount > 500 && _sendCount <= 510) { // drop 10 packets printf("\tDrop packet\n"); return len; } if(_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) { return len; } return -1; } virtual int SendRTCPPacket(int channel, const void *data, int len) { if(_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) { return len; } return -1; } WebRtc_UWord32 _sendCount; RtpRtcp* _rtpRtcpModule; }; class DataRelayReceiverVideo : public RtpData { public: DataRelayReceiverVideo(RtpRtcp* rtpRtcpModule) : _rtpRtcpModule(rtpRtcpModule) {} virtual WebRtc_Word32 OnReceivedPayloadData(const WebRtc_UWord8* payloadData, const WebRtc_UWord16 payloadSize, const webrtc::WebRtcRTPHeader* rtpHeader, const WebRtc_UWord8* rtpPacket, const WebRtc_UWord16 rtpPacketSize) { if(rtpPacketSize == 0) { // we relay only one packet once, but this function in called for each NALU return 0; } if(_rtpRtcpModule->SendRTPPacket(rtpHeader, rtpPacket, rtpPacketSize) == 0) { return 0; } return -1; } RtpRtcp* _rtpRtcpModule; }; // Dummy comment, shall be removed class LoopBackTransportVideo : public webrtc::Transport { public: LoopBackTransportVideo(RtpRtcp* rtpRtcpModule) : _count(0), _packetLoss(0), _rtpRtcpModule(rtpRtcpModule) { } virtual int SendPacket(int channel, const void *data, int len) { if(static_cast(data)[0] == 0) { // printf("\t\tReceived pad data length:%d\n", len); return len; } _count++; if(_packetLoss > 0) { if(_count%_packetLoss == 0) { // printf("Drop video packet: %u\n", static_cast(data)[3]); return len; } // printf("video packet: %u\n", static_cast(data)[3]); } else { // printf("video packet: %u\n", static_cast(data)[3]); } if(_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) { return len; } return -1; } virtual int SendRTCPPacket(int channel, const void *data, int len) { if(_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) { return len; } return -1; } WebRtc_UWord32 _packetLoss; WebRtc_UWord32 _count; WebRtc_UWord32 _time; RtpRtcp* _rtpRtcpModule; }; class DataReceiver : public RtpData { public: DataReceiver(RtpRtcp* rtpRtcpModule) : _rtpRtcpModule(rtpRtcpModule) { } virtual WebRtc_Word32 OnReceivedPayloadData(const WebRtc_UWord8* payloadData, const WebRtc_UWord16 payloadSize, const webrtc::WebRtcRTPHeader* rtpHeader, const WebRtc_UWord8* rtpPacket, const WebRtc_UWord16 rtpPacketSize) { // printf("\tReceived packet:%d payload type:%d length:%d\n", rtpHeader->header.sequenceNumber, rtpHeader->header.payloadType, payloadSize); if(rtpHeader->header.payloadType == 98 || rtpHeader->header.payloadType == 99) { if(strncmp("test", (const char*)payloadData, 4) == 0) { return 0; } assert(false); return -1; } if(rtpHeader->header.payloadType == 100 || rtpHeader->header.payloadType == 101 || rtpHeader->header.payloadType == 102) { if(rtpHeader->type.Audio.channel == 1) { if(payloadData[0] == 0xff) { return 0; } }else if(rtpHeader->type.Audio.channel == 2) { if(payloadData[0] == 0x0) { return 0; } }else if(rtpHeader->type.Audio.channel == 3) { if(payloadData[0] == 0xaa) { return 0; } } assert(false); return -1; } if(payloadSize == 10) { if(strncmp("testEnergy", (const char*)payloadData, 10) == 0) { if(rtpHeader->type.Audio.numEnergy == 2) { if( rtpHeader->type.Audio.arrOfEnergy[0] == 7 && rtpHeader->type.Audio.arrOfEnergy[1] == 9) { return 0; } } assert(false); return -1; } } return 0; } RtpRtcp* _rtpRtcpModule; }; class DataReceiverVideo : public RtpData { public: DataReceiverVideo() : _packetLoss(false), _curLength(0) { } void CheckRecivedFrame(bool nack) { printf("\t\tCheckRecivedFrame\n"); { assert(_curLength == _payloadDataFileLength); _curLength = 0; if(!nack) { for (int i = 0; i < _payloadDataFileLength; i++) { assert(_receiveBuffer[i] == _payloadDataFile[i]); } } } } virtual WebRtc_Word32 OnReceivedPayloadData(const WebRtc_UWord8* payloadData, const WebRtc_UWord16 payloadSize, const webrtc::WebRtcRTPHeader* rtpHeader, const WebRtc_UWord8* rtpPacket, const WebRtc_UWord16 rtpPacketSize) { if(rtpHeader->frameType == webrtc::kFrameEmpty && payloadSize == 0) { return 0; } // store received payload data int sByte = 0; if (rtpHeader->type.Video.codec == VideoH263 && rtpHeader->type.Video.codecHeader.H263.bits) { // "or" the first bits assert(_curLength > 0); _receiveBuffer[_curLength - 1] |= payloadData[0]; sByte = 1; } memcpy(&_receiveBuffer[_curLength], &payloadData[sByte], payloadSize - sByte); _curLength += payloadSize - sByte; if(!_packetLoss) { if (rtpHeader->header.markerBit && payloadSize) { // last packet, compare send and received data stream CheckRecivedFrame(false); } } else { for(int i = 0; i < VIDEO_NACK_LIST_SIZE; i++) { if(_nackList[i] == rtpHeader->header.sequenceNumber) { _nackList[i] = -1; break; } } } return 0; } bool _packetLoss; WebRtc_Word32 _nackList[VIDEO_NACK_LIST_SIZE]; WebRtc_UWord8 _receiveBuffer[100000]; WebRtc_UWord32 _curLength; }; class VideoFeedback : public RtpVideoFeedback { virtual void OnReceivedIntraFrameRequest(const WebRtc_Word32 id, const WebRtc_UWord8 message) { printf("\tReceived video IntraFrameRequest message:%d \n", message); }; virtual void OnNetworkChanged(const WebRtc_Word32 id, const WebRtc_UWord32 bitrateTarget, const WebRtc_UWord8 fractionLost, const WebRtc_UWord16 roundTripTimeMs, const WebRtc_UWord32 jitterMS, const WebRtc_UWord16 bwEstimateKbitMin, const WebRtc_UWord16 bwEstimateKbitMax) { static int count = 0; count++; const WebRtc_UWord32 bitrateTargetKbit = bitrateTarget/1000; // todo jitter is not valid due to send rate if(count == 1) { assert(3667 >= bwEstimateKbitMax); assert(fractionLost >= 80 && fractionLost < 150); assert(300 == bitrateTargetKbit); // no inc due to no fraction loss } else if(count == 2) { assert(1517 == bwEstimateKbitMax); assert(0 == fractionLost); assert(300 == bitrateTargetKbit); // no inc due to no actual bitrate } else if(count == 3) { assert(1517 == bwEstimateKbitMax); assert(0 == fractionLost); assert(220 == bitrateTargetKbit); } else if(count == 4) { assert(0 == fractionLost); assert(243 == bitrateTargetKbit); } else { assert(10 == jitterMS); assert(4 == fractionLost); } printf("\tReceived video OnNetworkChanged bitrateTargetKbit:%d RTT:%d Loss:%d\n", bitrateTargetKbit, roundTripTimeMs, fractionLost); }; }; class AudioFeedback : public RtpAudioFeedback { virtual void OnReceivedTelephoneEvent(const WebRtc_Word32 id, const WebRtc_UWord8 event, const bool end) { static WebRtc_UWord8 expectedEvent = 0; if(end) { WebRtc_UWord8 oldEvent = expectedEvent-1; if(expectedEvent == 32) { oldEvent = 15; } #if 0 // test of multiple events else if(expectedEvent == 34) { oldEvent = 32; expectedEvent = 33; }else if(expectedEvent == 33) { oldEvent = 33; expectedEvent = 34; } #endif assert(oldEvent == event); }else { assert(expectedEvent == event); expectedEvent++; } if(expectedEvent == 16) { expectedEvent = 32; } if(end) { printf("\tReceived End of DTMF event:%d with id:%d\n", event, id); }else { printf("\tReceived Start of DTMF event:%d with id:%d\n", event, id); } } virtual void OnPlayTelephoneEvent(const WebRtc_Word32 id, const WebRtc_UWord8 event, const WebRtc_UWord16 lengthMs, const WebRtc_UWord8 volume) { printf("\tPlayout DTMF event:%d time:%d ms volume:%d with id:%d\n", event, lengthMs,volume, id); }; }; class RtcpFeedback : public RtcpFeedback { public: RtcpFeedback() { _rtpRtcpModule = NULL; _rtpRtcpModuleRelay = NULL; }; virtual void OnRTCPPacketTimeout(const WebRtc_Word32 id) { printf("\tReceived OnPacketTimeout for RTCP id:%d\n", id); } // if audioVideoOffset > 0 video is behind audio virtual void OnLipSyncUpdate(const WebRtc_Word32 id, const WebRtc_Word32 audioVideoOffset) { // printf("\tReceived OnLipSyncUpdate:%d with id:%d\n", audioVideoOffset, id); }; virtual void OnTMMBRReceived(const WebRtc_Word32 id, const WebRtc_UWord16 bwEstimateKbit) { printf("\tReceived OnTMMBRReceived:%d with id:%d\n", bwEstimateKbit, id); }; virtual void OnXRVoIPMetricReceived(const WebRtc_Word32 id, const RTCPVoIPMetric* metric, const WebRtc_Word8 VoIPmetricBuffer[28]) { printf("\tOnXRVoIPMetricReceived:%d with id:%d\n", metric->burstDensity, id); }; virtual void OnSLIReceived(const WebRtc_Word32 id, const WebRtc_UWord8 pictureId) { printf("\tReceived OnSLIReceived:%d with id:%d\n", pictureId, id); assert(pictureId == 28); }; virtual void OnRPSIReceived(const WebRtc_Word32 id, const WebRtc_UWord64 pictureId) { printf("\tReceived OnRPSIReceived:%d with id:%d\n", pictureId, id); assert(pictureId == 12345678); }; virtual void OnApplicationDataReceived(const WebRtc_Word32 id, const WebRtc_UWord8 subType, const WebRtc_UWord32 name, const WebRtc_UWord16 length, const WebRtc_UWord8* data) { WebRtc_Word8 printName[5]; printName[0] = (WebRtc_Word8)(name >> 24); printName[1] = (WebRtc_Word8)(name >> 16); printName[2] = (WebRtc_Word8)(name >> 8); printName[3] = (WebRtc_Word8)name; printName[4] = 0; WebRtc_Word8* printData = new WebRtc_Word8[length+1]; memcpy(printData, data, length); printData[length] = 0; printf("\tOnApplicationDataReceived subtype:%d name:%s data:%s with id:%d\n", subType, printName, printData, id); assert(strncmp("test",printName, 5) == 0); delete [] printData; }; virtual void OnSendReportReceived(const WebRtc_Word32 id, const WebRtc_UWord32 senderSSRC, const WebRtc_UWord8* incomingPacket, const WebRtc_UWord16 packetLength) { printf("\tOnSendReportReceived RTCP id:%d\n", id); if(_rtpRtcpModule) { RTCPSenderInfo senderInfo; assert(_rtpRtcpModule->RemoteRTCPStat(&senderInfo) == 0); senderInfo.sendOctetCount; senderInfo.sendPacketCount; } if(_rtpRtcpModuleRelay) { // relay packet _rtpRtcpModuleRelay->SendRTCPPacket(incomingPacket, packetLength); } }; // for relay conferencing virtual void OnReceiveReportReceived(const WebRtc_Word32 id, const WebRtc_UWord32 senderSSRC, const WebRtc_UWord8* incomingPacket, const WebRtc_UWord16 packetLength) { WebRtc_UWord16 RTT = 0; WebRtc_UWord32 remoteSSRC; switch(id) { case 123: remoteSSRC = 124; break; case 124: remoteSSRC = 123; break; case 125: remoteSSRC = 126; break; case 126: remoteSSRC = 125; break; default: assert(false); } _rtpRtcpModule->RTT(remoteSSRC, &RTT,NULL,NULL,NULL); printf("\tOnReceiveReportReceived RTT:%d RTCP id:%d\n", RTT, id); if(_rtpRtcpModuleRelay) { // relay packet _rtpRtcpModuleRelay->SendRTCPPacket(incomingPacket, packetLength); } }; RtpRtcp* _rtpRtcpModule; RtpRtcp* _rtpRtcpModuleRelay; }; class RTPCallback : public RtpFeedback { public: virtual WebRtc_Word32 OnInitializeDecoder(const WebRtc_Word32 id, const WebRtc_Word8 payloadType, const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE], const WebRtc_UWord32 frequency, const WebRtc_UWord8 channels, const WebRtc_UWord32 rate) { if(payloadType == 96) { assert(rate == 64000); } printf("\tReceived OnInitializeDecoder \n\t\tpayloadName:%s \n\t\tpayloadType:%d \n\t\tfrequency:%d \n\t\tchannels:%d \n\t\trate:%d \n\t\twith id:%d\n", payloadName,payloadType,frequency, channels, rate, id); return 0; } virtual void OnPacketTimeout(const WebRtc_Word32 id) { printf("\tReceived OnPacketTimeout\n"); } virtual void OnReceivedPacket(const WebRtc_Word32 id, const RtpRtcpPacketType packetType) { printf("\tReceived OnReceivedPacket\n"); } virtual void OnPeriodicDeadOrAlive(const WebRtc_Word32 id, const RTPAliveType alive) { printf("\tReceived OnPeriodicDeadOrAlive\n"); } virtual void OnIncomingSSRCChanged( const WebRtc_Word32 id, const WebRtc_UWord32 SSRC) { printf("\tReceived OnIncomingSSRCChanged\n"); } virtual void OnIncomingCSRCChanged( const WebRtc_Word32 id, const WebRtc_UWord32 CSRC, const bool added) { printf("\tReceived OnIncomingCSRCChanged\n"); } }; // todo look at VE 3.0 test app int _tmain(int argc, _TCHAR* argv[]) { // _crtBreakAlloc = 17967; WebRtc_Word8 fileName[1024] = "testTrace.txt"; Trace::CreateTrace(); Trace::SetTraceFile(fileName); memcpy(fileName, "testTraceDebug.txt", 19); Trace::SetEncryptedTraceFile(fileName); Trace::SetLevelFilter(webrtc::kTraceAll); int myId = 123; ProcessThread* processThread = ProcessThread::CreateProcessThread(); processThread->Start(); #ifdef TEST_AUDIO // test all APIs in RTP/RTCP module RtpRtcp* rtpRtcpModule1 = RtpRtcp::CreateRtpRtcp(myId, true); // audio RtpRtcp* rtpRtcpModule2 = RtpRtcp::CreateRtpRtcp(myId+1, true); // audio processThread->RegisterModule(rtpRtcpModule1); processThread->RegisterModule(rtpRtcpModule2); printf("Welcome to API test of RTP/RTCP module\n"); WebRtc_Word8 version[256]; WebRtc_UWord32 remainingBufferInBytes = 256; WebRtc_UWord32 position = 0; assert( 0 == rtpRtcpModule1->Version(version, remainingBufferInBytes, position)); assert(-1 == rtpRtcpModule1->Version(NULL, remainingBufferInBytes, position)); printf("\nVersion\n\t%s\n\n", version); assert( 0 == rtpRtcpModule1->InitReceiver()); assert( 0 == rtpRtcpModule1->InitSender()); assert( 0 == rtpRtcpModule2->InitReceiver()); assert( 0 == rtpRtcpModule2->InitSender()); printf("\tInitialization done\n"); assert(-1 == rtpRtcpModule1->SetMaxTransferUnit(10)); assert(-1 == rtpRtcpModule1->SetMaxTransferUnit(IP_PACKET_SIZE + 1)); assert( 0 == rtpRtcpModule1->SetMaxTransferUnit(1234)); assert(1234-20-8 == rtpRtcpModule1->MaxPayloadLength()); assert( 0 == rtpRtcpModule1->SetTransportOverhead(true, true, 12)); assert(1234 - 20- 20 -20 - 12 == rtpRtcpModule1->MaxPayloadLength()); assert( 0 == rtpRtcpModule1->SetTransportOverhead(false, false, 0)); assert(1234 - 20 - 8== rtpRtcpModule1->MaxPayloadLength()); assert( 0 == rtpRtcpModule1->SetSequenceNumber(2345)); assert(2345 == rtpRtcpModule1->SequenceNumber()); assert( 0 == rtpRtcpModule1->SetSSRC(3456)); assert(3456 == rtpRtcpModule1->SSRC()); assert( 0 == rtpRtcpModule1->SetStartTimestamp(4567)); assert(4567 == rtpRtcpModule1->StartTimestamp()); assert(0 == rtpRtcpModule1->SetAudioEnergy(NULL,0)); WebRtc_UWord32 arrOfCSRC[webrtc::kRtpCsrcSize] = {1234,2345}; WebRtc_UWord32 testOfCSRC[webrtc::kRtpCsrcSize] = {0,0,0}; assert( 0 == rtpRtcpModule1->SetCSRCs(arrOfCSRC,2)); assert( 2 == rtpRtcpModule1->CSRCs(testOfCSRC)); assert(arrOfCSRC[0] == testOfCSRC[0]); assert(arrOfCSRC[1] == testOfCSRC[1]); assert( kRtcpOff == rtpRtcpModule1->RTCP()); assert(0 == rtpRtcpModule1->SetRTCPStatus(kRtcpCompound)); assert( kRtcpCompound == rtpRtcpModule1->RTCP()); assert( kRtcpOff == rtpRtcpModule2->RTCP()); assert(0 == rtpRtcpModule2->SetRTCPStatus(kRtcpCompound)); assert( kRtcpCompound == rtpRtcpModule2->RTCP()); assert( 0 == rtpRtcpModule1->SetCNAME("john.doe@test.test")); assert( 0 == rtpRtcpModule2->SetCNAME("jane.doe@test.test")); assert(-1 == rtpRtcpModule1->SetCNAME(NULL)); WebRtc_Word8 cName[RTCP_CNAME_SIZE]; assert(0 == rtpRtcpModule1->CNAME(cName)); assert(0 == strncmp(cName, "john.doe@test.test", RTCP_CNAME_SIZE)); assert(-1 == rtpRtcpModule1->CNAME(NULL)); assert( false == rtpRtcpModule1->TMMBR()); assert(0 == rtpRtcpModule1->SetTMMBRStatus(true)); assert( true == rtpRtcpModule1->TMMBR()); assert(0 == rtpRtcpModule1->SetTMMBRStatus(false)); assert( false == rtpRtcpModule1->TMMBR()); assert( kNackOff == rtpRtcpModule1->NACK()); assert(0 == rtpRtcpModule1->SetNACKStatus(kNackRtcp)); assert( kNackRtcp == rtpRtcpModule1->NACK()); assert( false == rtpRtcpModule1->Sending()); assert(0 == rtpRtcpModule1->SetSendingStatus(true)); assert( true == rtpRtcpModule1->Sending()); assert(0 == rtpRtcpModule2->SetSendingStatus(true)); // audio specific assert( false == rtpRtcpModule1->TelephoneEvent()); assert(0 == rtpRtcpModule2->SetTelephoneEventStatus(true, true, true)); // to test detection at the end of a DTMF tone assert( true == rtpRtcpModule2->TelephoneEvent()); printf("Basic set/get test done\n"); // test setup DataReceiver* myDataReceiver1 = new DataReceiver(rtpRtcpModule1); assert(0 == rtpRtcpModule1->RegisterIncomingDataCallback(myDataReceiver1)); DataReceiver* myDataReceiver2 = new DataReceiver(rtpRtcpModule2); assert(0 == rtpRtcpModule2->RegisterIncomingDataCallback(myDataReceiver2)); LoopBackTransport* myLoopBackTransport1 = new LoopBackTransport(rtpRtcpModule2); assert(0 == rtpRtcpModule1->RegisterSendTransport(myLoopBackTransport1)); LoopBackTransport* myLoopBackTransport2 = new LoopBackTransport(rtpRtcpModule1); assert(0 == rtpRtcpModule2->RegisterSendTransport(myLoopBackTransport2)); RTPCallback* myRTPCallback = new RTPCallback(); assert(0 == rtpRtcpModule2->RegisterIncomingRTPCallback(myRTPCallback)); RtcpFeedback* myRTCPFeedback1 = new RtcpFeedback(); RtcpFeedback* myRTCPFeedback2 = new RtcpFeedback(); myRTCPFeedback1->_rtpRtcpModule = rtpRtcpModule1; myRTCPFeedback2->_rtpRtcpModule = rtpRtcpModule2; assert(0 == rtpRtcpModule1->RegisterIncomingRTCPCallback(myRTCPFeedback1)); assert(0 == rtpRtcpModule2->RegisterIncomingRTCPCallback(myRTCPFeedback2)); assert(0 == rtpRtcpModule1->SetSendingStatus(true)); // start basic RTP test // send an empty RTP packet, should fail since we have not registerd the payload type assert(-1 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96, 0, NULL, 0)); WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE] = "PCMU"; assert(0 == rtpRtcpModule1->RegisterSendPayload( payloadName, 96, 8000)); assert(0 == rtpRtcpModule1->RegisterReceivePayload(payloadName, 96, 8000)); assert(0 == rtpRtcpModule2->RegisterSendPayload( payloadName, 96, 8000)); assert(0 == rtpRtcpModule2->RegisterReceivePayload( payloadName, 96, 8000, 1, 64000)); WebRtc_Word8 testPayloadName[RTP_PAYLOAD_NAME_SIZE]; WebRtc_UWord32 testFrequency = 0; WebRtc_Word8 testPayloadType= 0; WebRtc_UWord8 testChannels= 0; assert(0 == rtpRtcpModule1->ReceivePayload( 96,testPayloadName, &testFrequency, &testChannels)); assert(0 == strncmp(testPayloadName, payloadName, 4)); assert(1 == testChannels); assert(0 == rtpRtcpModule1->ReceivePayloadType( payloadName,8000,1,&testPayloadType)); assert(testPayloadType == 96); // energy test const WebRtc_UWord8 energy[3] = {7,9,3}; assert(-1 == rtpRtcpModule1->SetAudioEnergy(energy,3)); //should fails since we only have 2 CSRCs assert(0 == rtpRtcpModule1->SetAudioEnergy(energy,2)); // send RTP packet with the data "testtest" const WebRtc_UWord8 test[9] = "testtest"; const WebRtc_UWord8 testEnergy[11] = "testEnergy"; assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,96, 0, testEnergy, 10)); assert(0 == rtpRtcpModule2->SendOutgoingData(webrtc::kAudioFrameSpeech,96, 0, test, 8)); // assert(-1 == rtpRtcpModule->SendOutgoingData(96, 0, NULL, 4)); assert(3456 == rtpRtcpModule2->RemoteSSRC()); assert(4567 == rtpRtcpModule2->RemoteTimestamp()); assert(0 == rtpRtcpModule1->SetStorePacketsStatus(true, 100)); assert(-1 == rtpRtcpModule1->SetTFRCStatus(true)); assert(0 == rtpRtcpModule1->SetAudioEnergy(NULL,0)); assert(0 == rtpRtcpModule1->SetTFRCStatus(true)); memcpy(payloadName, "RED",4); // Test RED assert(0 == rtpRtcpModule1->SetSendREDPayloadType(127)); WebRtc_Word8 red = 0; assert(0 == rtpRtcpModule1->SendREDPayloadType(red)); assert(127 == red); assert(0 == rtpRtcpModule1->RegisterReceivePayload( payloadName, 127)); assert(0 == rtpRtcpModule2->RegisterReceivePayload( payloadName, 127)); { RTPFragmentationHeader fragmentation; fragmentation.fragmentationVectorSize = 2; fragmentation.fragmentationLength = new WebRtc_UWord32[2]; fragmentation.fragmentationLength[0] = 4; fragmentation.fragmentationLength[1] = 4; fragmentation.fragmentationOffset = new WebRtc_UWord32[2]; fragmentation.fragmentationOffset[0] = 0; fragmentation.fragmentationOffset[1] = 4; fragmentation.fragmentationTimeDiff = new WebRtc_UWord16[2]; fragmentation.fragmentationTimeDiff[0] = 0; fragmentation.fragmentationTimeDiff[1] = 0; fragmentation.fragmentationPlType = new WebRtc_UWord8[2]; fragmentation.fragmentationPlType[0] = 96; fragmentation.fragmentationPlType[1] = 96; // send a RTP packet assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,96, 160, test,8, &fragmentation)); } assert(0 == rtpRtcpModule1->SetSendREDPayloadType(-1)); assert(-1 == rtpRtcpModule1->SendREDPayloadType(red)); assert(0 == rtpRtcpModule1->SetStorePacketsStatus(false)); assert(0 == rtpRtcpModule1->SetTFRCStatus(false)); printf("Basic RTP test done\n"); // todo CNG AudioFeedback* audioFeedback = new AudioFeedback(); assert(0 == rtpRtcpModule2->RegisterAudioCallback(audioFeedback)); // prepare for DTMF memcpy(payloadName, "telephone-event",16); assert(0 == rtpRtcpModule1->RegisterSendPayload( payloadName, 97, 8000)); assert(0 == rtpRtcpModule2->RegisterReceivePayload( payloadName, 97)); // prepare for 3 channel audio 8 bits per sample memcpy(payloadName, "PCMA",5); assert(0 == rtpRtcpModule1->RegisterSendPayload( payloadName, 98, 8000, 3)); assert(0 == rtpRtcpModule2->RegisterReceivePayload( payloadName, 98,8000, 3)); // prepare for 3 channel audio 16 bits per sample memcpy(payloadName, "L16",4); assert(0 == rtpRtcpModule1->RegisterSendPayload( payloadName, 99, 8000, 3)); assert(0 == rtpRtcpModule2->RegisterReceivePayload( payloadName, 99, 8000, 3)); // prepare for 3 channel audio 5 bits per sample memcpy(payloadName, "G726-40",8); assert(0 == rtpRtcpModule1->RegisterSendPayload( payloadName, 100, 8000, 3)); assert(0 == rtpRtcpModule2->RegisterReceivePayload( payloadName, 100, 8000, 3)); // prepare for 3 channel audio 3 bits per sample memcpy(payloadName, "G726-24",8); assert(0 == rtpRtcpModule1->RegisterSendPayload( payloadName, 101, 8000, 3)); assert(0 == rtpRtcpModule2->RegisterReceivePayload( payloadName, 101, 8000, 3)); // prepare for 3 channel audio 2 bits per sample memcpy(payloadName, "G726-16",8); assert(0 == rtpRtcpModule1->RegisterSendPayload( payloadName, 102, 8000, 3)); assert(0 == rtpRtcpModule2->RegisterReceivePayload( payloadName, 102, 8000, 3)); // Start DTMF test // Send a DTMF tone using RFC 2833 (4733) for(int i = 0; i < 16; i++) { printf("\tSending tone: %d\n", i); assert(0 == rtpRtcpModule1->SendTelephoneEventOutband(i, 160, 10)); } // send RTP packets for 16 tones a 160 ms + 100ms pause between = 2560ms + 1600ms = 4160ms int j = 2; for(;j <= 250;j++) { assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,96, 160*j, test,8)); Sleep(20); } printf("Basic DTMF test done\n"); assert(0 == rtpRtcpModule1->SendTelephoneEventOutband(32, 9000, 10)); for(;j <= 740;j++) { assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,96, 160*j, test,8)); Sleep(20); } printf("Start Stereo test\n"); // test sample based multi channel codec, 3 channels 8 bits WebRtc_UWord8 test3channels[15] = "ttteeesssttt"; assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,98, 160*j, test3channels,12)); Sleep(20); j++; // test sample based multi channel codec, 3 channels 16 bits const WebRtc_UWord8 test3channels16[13] = "teteteststst"; assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,99, 160*j, test3channels16,12)); Sleep(20); j++; // test sample based multi channel codec, 3 channels 5 bits test3channels[0] = 0xf8; // 5 ones 3 zeros test3channels[1] = 0x2b; // 2 zeros 5 10 1 one test3channels[2] = 0xf0; // 4 ones 4 zeros test3channels[3] = 0x2b; // 1 zero 5 01 2 ones test3channels[4] = 0xe0; // 3 ones 5 zeros test3channels[5] = 0x0; test3channels[6] = 0x0; test3channels[7] = 0x0; test3channels[8] = 0x0; test3channels[9] = 0x0; test3channels[10] = 0x0; test3channels[11] = 0x0; test3channels[12] = 0x0; test3channels[13] = 0x0; test3channels[14] = 0x0; assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,100, 160*j, test3channels,15)); Sleep(20); j++; // test sample based multi channel codec, 3 channels 3 bits test3channels[0] = 0xe2; // 3 ones 3 zeros 2 10 test3channels[1] = 0xf0; // 1 1 3 ones 3 zeros 1 0 test3channels[2] = 0xb8; // 2 10 3 ones 3 zeros test3channels[3] = 0xa0; // 3 101 5 zeros test3channels[4] = 0x0; assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,101, 160*j, test3channels,15)); Sleep(20); j++; // test sample based multi channel codec, 3 channels 2 bits test3channels[0] = 0xcb; // 2 ones 2 zeros 2 10 2 ones test3channels[1] = 0x2c; // 2 zeros 2 10 2 ones 2 zeros test3channels[2] = 0xb2; // 2 10 2 ones 2 zeros 2 10 test3channels[3] = 0xcb; // 2 ones 2 zeros 2 10 2 ones test3channels[4] = 0x2c; // 2 zeros 2 10 2 ones 2 zeros assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,102, 160*j, test3channels,15)); Sleep(20); j++; for(;j <= 750;j++) { assert(0 == rtpRtcpModule1->SendOutgoingData(webrtc::kAudioFrameSpeech,96, 160*j, test,8)); Sleep(20); } printf("Long tone DTMF test done\n"); // start basic RTCP test assert(0 == rtpRtcpModule1->SendRTCPReferencePictureSelection(12345678)); assert(0 == rtpRtcpModule1->SendRTCPSliceLossIndication(156)); testOfCSRC[0] = 0; testOfCSRC[1] = 0; assert( 2 == rtpRtcpModule2->RemoteCSRCs(testOfCSRC)); assert(arrOfCSRC[0] == testOfCSRC[0]); assert(arrOfCSRC[1] == testOfCSRC[1]); // set cname of mixed assert( 0 == rtpRtcpModule1->AddMixedCNAME(arrOfCSRC[0], "john@192.168.0.1")); assert( 0 == rtpRtcpModule1->AddMixedCNAME(arrOfCSRC[1], "jane@192.168.0.2")); assert(-1 == rtpRtcpModule1->AddMixedCNAME(arrOfCSRC[0], NULL)); assert(-1 == rtpRtcpModule1->RemoveMixedCNAME(arrOfCSRC[0] + 1)); // not added assert( 0 == rtpRtcpModule1->RemoveMixedCNAME(arrOfCSRC[1])); assert( 0 == rtpRtcpModule1->AddMixedCNAME(arrOfCSRC[1], "jane@192.168.0.2")); RTCPReportBlock reportBlock; reportBlock.cumulativeLost = 1; reportBlock.delaySinceLastSR = 2; reportBlock.extendedHighSeqNum= 3; reportBlock.fractionLost= 4; reportBlock.jitter= 5; reportBlock.lastSR= 6; // set report blocks assert(-1 == rtpRtcpModule1->AddRTCPReportBlock(arrOfCSRC[0], NULL)); assert( 0 == rtpRtcpModule1->AddRTCPReportBlock(arrOfCSRC[0], &reportBlock)); reportBlock.lastSR= 7; assert(0 == rtpRtcpModule1->AddRTCPReportBlock(arrOfCSRC[1], &reportBlock)); WebRtc_UWord32 name = 't'<<24; name += 'e'<<16; name += 's'<<8; name += 't'; assert(0 == rtpRtcpModule1->SetRTCPApplicationSpecificData(3,name,(const WebRtc_UWord8 *)"test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test ",300)); // send RTCP packet, triggered by timer Sleep(8000); WebRtc_UWord32 receivedNTPsecs = 0; WebRtc_UWord32 receivedNTPfrac = 0; WebRtc_UWord32 RTCPArrivalTimeSecs = 0; WebRtc_UWord32 RTCPArrivalTimeFrac = 0; assert(0 == rtpRtcpModule2->RemoteNTP(&receivedNTPsecs, &receivedNTPfrac, &RTCPArrivalTimeSecs, &RTCPArrivalTimeFrac)); assert(-1 == rtpRtcpModule2->RemoteCNAME(rtpRtcpModule2->RemoteSSRC() + 1, cName)); // not received assert(-1 == rtpRtcpModule2->RemoteCNAME(rtpRtcpModule2->RemoteSSRC(), NULL)); // check multiple CNAME assert(0 == rtpRtcpModule2->RemoteCNAME(rtpRtcpModule2->RemoteSSRC(), cName)); assert(0 == strncmp(cName, "john.doe@test.test", RTCP_CNAME_SIZE)); assert(0 == rtpRtcpModule2->RemoteCNAME(arrOfCSRC[0], cName)); assert(0 == strncmp(cName, "john@192.168.0.1", RTCP_CNAME_SIZE)); assert(0 == rtpRtcpModule2->RemoteCNAME(arrOfCSRC[1], cName)); assert(0 == strncmp(cName, "jane@192.168.0.2", RTCP_CNAME_SIZE)); // get all report blocks RTCPReportBlock reportBlockReceived; assert(-1 == rtpRtcpModule1->RemoteRTCPStat(rtpRtcpModule1->RemoteSSRC() + 1, &reportBlockReceived)); // not received assert(-1 == rtpRtcpModule1->RemoteRTCPStat(rtpRtcpModule1->RemoteSSRC(), NULL)); assert(0 == rtpRtcpModule1->RemoteRTCPStat(rtpRtcpModule1->RemoteSSRC(), &reportBlockReceived)); float secSinceLastReport = (float)reportBlockReceived.delaySinceLastSR/65536.0f; assert( secSinceLastReport > 0.0f && secSinceLastReport < 7.5f); // audio RTCP max 7.5 sec // startSeqNum + number of sent + number of extra due to DTMF assert(2345+750+2+16 == reportBlockReceived.extendedHighSeqNum); assert(0 == reportBlockReceived.fractionLost); // we have dropped 10 packets but since we change codec it's reset assert(0 == reportBlockReceived.cumulativeLost); WebRtc_UWord8 fraction_lost = 0; // scale 0 to 255 WebRtc_UWord32 cum_lost = 0; // number of lost packets WebRtc_UWord32 ext_max = 0; // highest sequence number received WebRtc_UWord32 jitter = 0; WebRtc_UWord32 max_jitter = 0; assert(0 == rtpRtcpModule2->StatisticsRTP(&fraction_lost, &cum_lost, &ext_max, &jitter, &max_jitter)); assert(0 == fraction_lost); assert(0 == cum_lost); assert(2345+750+16+2 == ext_max); assert(reportBlockReceived.jitter == jitter); WebRtc_UWord16 RTT; WebRtc_UWord16 avgRTT; WebRtc_UWord16 minRTT; WebRtc_UWord16 maxRTT; // Get RoundTripTime assert(0 == rtpRtcpModule1->RTT(rtpRtcpModule1->RemoteSSRC(),&RTT, &avgRTT, &minRTT, &maxRTT)); assert(RTT < 10); assert(avgRTT < 10); assert(minRTT < 10); assert(minRTT > 0); assert(maxRTT < 10); /* since we filter out this in the receiver we can't get it assert(0 == rtpRtcpModule2->RemoteRTCPStat(arrOfCSRC[0], &reportBlockReceived)); assert(reportBlock.cumulativeLost == reportBlockReceived.cumulativeLost); assert(reportBlock.delaySinceLastSR == reportBlockReceived.delaySinceLastSR); assert(reportBlock.extendedHighSeqNum == reportBlockReceived.extendedHighSeqNum); assert(reportBlock.fractionLost == reportBlockReceived.fractionLost); assert(reportBlock.jitter == reportBlockReceived.jitter); assert(6 == reportBlockReceived.lastSR); assert(0 == rtpRtcpModule2->RemoteRTCPStat(arrOfCSRC[1], &reportBlockReceived)); assert(reportBlock.cumulativeLost == reportBlockReceived.cumulativeLost); assert(reportBlock.delaySinceLastSR == reportBlockReceived.delaySinceLastSR); assert(reportBlock.extendedHighSeqNum == reportBlockReceived.extendedHighSeqNum); assert(reportBlock.fractionLost == reportBlockReceived.fractionLost); assert(reportBlock.jitter == reportBlockReceived.jitter); assert(reportBlock.lastSR == reportBlockReceived.lastSR); */ // set report blocks assert(0 == rtpRtcpModule1->AddRTCPReportBlock(arrOfCSRC[0], &reportBlock)); // test receive report assert(0 == rtpRtcpModule1->SetSendingStatus(false)); // test that BYE clears the CNAME assert(-1 == rtpRtcpModule2->RemoteCNAME(rtpRtcpModule2->RemoteSSRC(), cName)); // send RTCP packet, triggered by timer Sleep(5000); printf("\tBasic RTCP test done\n"); processThread->DeRegisterModule(rtpRtcpModule1); processThread->DeRegisterModule(rtpRtcpModule2); RtpRtcp::DestroyRtpRtcp(rtpRtcpModule1); RtpRtcp::DestroyRtpRtcp(rtpRtcpModule2); #endif // TEST_AUDIO #ifdef TEST_VIDEO // Test video RtpRtcp* rtpRtcpModuleVideo = RtpRtcp::CreateRtpRtcp(myId, false); // video assert( 0 == rtpRtcpModuleVideo->InitReceiver()); assert( 0 == rtpRtcpModuleVideo->InitSender()); LoopBackTransportVideo* myLoopBackTransportVideo = new LoopBackTransportVideo(rtpRtcpModuleVideo); assert(0 == rtpRtcpModuleVideo->RegisterSendTransport(myLoopBackTransportVideo)); DataReceiverVideo* myDataReceiverVideo = new DataReceiverVideo(); assert(0 == rtpRtcpModuleVideo->RegisterIncomingDataCallback(myDataReceiverVideo)); VideoFeedback* myVideoFeedback = new VideoFeedback(); assert(0 == rtpRtcpModuleVideo->RegisterIncomingVideoCallback(myVideoFeedback)); printf("Start video test\n"); WebRtc_UWord32 timestamp = 3000; WebRtc_Word8 payloadNameVideo[RTP_PAYLOAD_NAME_SIZE] = "I420"; assert(0 == rtpRtcpModuleVideo->RegisterSendPayload(payloadNameVideo, 123)); assert(0 == rtpRtcpModuleVideo->RegisterReceivePayload(payloadNameVideo, 123)); _payloadDataFileLength = (WebRtc_UWord16)sizeof(_payloadDataFile); for(int n = 0; n< _payloadDataFileLength; n++) { _payloadDataFile[n] = n%10; } printf("\tSending I420 frame. Length: %d\n", _payloadDataFileLength); assert(0 == rtpRtcpModuleVideo->SendOutgoingData(webrtc::kVideoFrameDelta,123, timestamp, _payloadDataFile, _payloadDataFileLength)); memcpy(payloadNameVideo, "MP4V-ES", 8); assert(0 == rtpRtcpModuleVideo->RegisterSendPayload(payloadNameVideo, 122)); assert(0 == rtpRtcpModuleVideo->RegisterReceivePayload(payloadNameVideo, 122)); // fake a MPEG-4 coded stream for (int m = 500; m< _payloadDataFileLength; m+= 500) { // start codes _payloadDataFile[m] = 0; _payloadDataFile[m+1] = 0; } printf("\tSending MPEG-4 frame. Length: %d\n", _payloadDataFileLength); assert(0 == rtpRtcpModuleVideo->SendOutgoingData(webrtc::kVideoFrameDelta,122, timestamp, _payloadDataFile, _payloadDataFileLength)); memcpy(payloadNameVideo, "H263-1998", 10); assert(0 == rtpRtcpModuleVideo->RegisterSendPayload(payloadNameVideo, 124)); assert(0 == rtpRtcpModuleVideo->RegisterReceivePayload(payloadNameVideo, 124)); // Test send H.263 frame FILE* openFile = fopen("H263_CIF_IFRAME.bin", "rb"); assert(openFile != NULL); fseek(openFile, 0, SEEK_END); _payloadDataFileLength = (WebRtc_Word16)(ftell(openFile)); rewind(openFile); assert(_payloadDataFileLength > 0); fread(_payloadDataFile, 1, _payloadDataFileLength, openFile); fclose(openFile); // send frame (1998/2000) printf("\tSending H263(1998) frame. Length: %d\n", _payloadDataFileLength); assert(0 == rtpRtcpModuleVideo->SendOutgoingData(webrtc::kVideoFrameDelta,124, timestamp, _payloadDataFile, _payloadDataFileLength)); memcpy(payloadNameVideo, "H263",5); assert(0 == rtpRtcpModuleVideo->RegisterSendPayload(payloadNameVideo, 34)); assert(0 == rtpRtcpModuleVideo->RegisterReceivePayload(payloadNameVideo, 34)); timestamp += 3000; // send frame printf("\tSending H263 frame. Length: %d\n", _payloadDataFileLength); assert(0 == rtpRtcpModuleVideo->SendOutgoingData(webrtc::kVideoFrameDelta,34, timestamp, _payloadDataFile, _payloadDataFileLength)); timestamp += 3000; // lower MTU -> mode B printf("\tSending H263 frame (MTU 300). Length: %d\n", _payloadDataFileLength); assert(0 == rtpRtcpModuleVideo->SetMaxTransferUnit(300)); assert(0 == rtpRtcpModuleVideo->SendOutgoingData(webrtc::kVideoFrameDelta,34, timestamp, _payloadDataFile, _payloadDataFileLength)); timestamp += 3000; // get frame w/ non-byte aligned GOB headers openFile = fopen("H263_QCIF_IFRAME.bin", "rb"); assert(openFile != NULL); fseek(openFile, 0, SEEK_END); _payloadDataFileLength = (WebRtc_Word16)(ftell(openFile)); rewind(openFile); assert(_payloadDataFileLength > 0); fread(_payloadDataFile, 1, _payloadDataFileLength, openFile); fclose(openFile); // send frame printf("\tSending H263 frame (MTU 1500). Length: %d\n", _payloadDataFileLength); assert(0 == rtpRtcpModuleVideo->SetMaxTransferUnit(1500)); assert(0 == rtpRtcpModuleVideo->SendOutgoingData(webrtc::kVideoFrameKey,34, timestamp, _payloadDataFile, _payloadDataFileLength)); timestamp += 3000; // lower MTU -> mode B printf("\tSending H263 frame (MTU 300). Length: %d\n", _payloadDataFileLength); assert(0 == rtpRtcpModuleVideo->SetMaxTransferUnit(300)); assert(0 == rtpRtcpModuleVideo->SendOutgoingData(webrtc::kVideoFrameKey,34, timestamp, _payloadDataFile, _payloadDataFileLength)); timestamp += 3000; openFile = fopen("H263_CIF_PFRAME.bin", "rb"); assert(openFile != NULL); fseek(openFile, 0, SEEK_END); _payloadDataFileLength = (WebRtc_Word16)(ftell(openFile)); rewind(openFile); assert(_payloadDataFileLength > 0); fread(_payloadDataFile, 1, _payloadDataFileLength, openFile); fclose(openFile); // test H.263 without all GOBs assert(0 == rtpRtcpModuleVideo->SetMaxTransferUnit(1500)); printf("\tSending H263 frame without all GOBs (MTU 1500). Length: %d\n", _payloadDataFileLength); assert(0 == rtpRtcpModuleVideo->SendOutgoingData(webrtc::kVideoFrameDelta,34, timestamp, _payloadDataFile, _payloadDataFileLength)); timestamp += 3000; // test H.263 without all GOBs small MTU assert(0 == rtpRtcpModuleVideo->SetMaxTransferUnit(500)); printf("\tSending H263 frame without all GOBs (MTU 500). Length: %d\n", _payloadDataFileLength); assert(0 == rtpRtcpModuleVideo->SendOutgoingData(webrtc::kVideoFrameDelta,34, timestamp, _payloadDataFile, _payloadDataFileLength)); // test PLI with relay assert(0 == rtpRtcpModuleVideo->RegisterIncomingVideoCallback(myVideoFeedback)); assert(0 == rtpRtcpModuleVideoReceiver->SetKeyFrameRequestMethod(kKeyFrameReqPliRtcp)); assert(0 == rtpRtcpModuleVideoReceiver->RequestKeyFrame()); processThread->DeRegisterModule(rtpRtcpModuleVideo); processThread->DeRegisterModule(rtpRtcpModuleVideoReceiver); processThread->Stop(); ProcessThread::DestroyProcessThread(processThread); RtpRtcp::DestroyRtpRtcp(rtpRtcpModuleVideoReceiver); RtpRtcp::DestroyRtpRtcp(rtpRtcpModuleVideoRelay); RtpRtcp::DestroyRtpRtcp(rtpRtcpModuleVideoRelay2); RtpRtcp::DestroyRtpRtcp(rtpRtcpModuleVideo); #endif // TEST_VIDEO printf("\nAPI test of RTP/RTCP module done\n"); #ifdef TEST_AUDIO delete myLoopBackTransport1; delete myLoopBackTransport2; delete myDataReceiver1; delete myDataReceiver2; delete myRTCPFeedback1; delete myRTCPFeedback2; delete audioFeedback; delete myRTPCallback; #endif #ifdef TEST_VIDEO delete myLoopBackTransportVideo; delete myVideoFeedback; delete myDataReceiverVideo; delete myRelayDataReceiver; delete myRelaySender; delete myRelayReceiver; delete myRelaySender2; delete myRelayReceiver2; delete myRelayDataReceiver2; delete myDataReceive2; delete myRTCPFeedbackVideo; delete myRTCPFeedbackRealy; delete myRTCPFeedbackReceiver; delete myRTCPFeedbackRealy2; #endif // TEST_VIDEO ::Sleep(5000); Trace::ReturnTrace(); return 0; }