1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/signaling/test/mediaconduit_unittests.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,917 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include <iostream> 1.9 +#include <string> 1.10 +#include <fstream> 1.11 +#include <unistd.h> 1.12 +#include <vector> 1.13 +#include <math.h> 1.14 + 1.15 +using namespace std; 1.16 + 1.17 +#include "mozilla/Scoped.h" 1.18 +#include <MediaConduitInterface.h> 1.19 +#include "nsIEventTarget.h" 1.20 +#include "FakeMediaStreamsImpl.h" 1.21 + 1.22 +#define GTEST_HAS_RTTI 0 1.23 +#include "gtest/gtest.h" 1.24 +#include "gtest_utils.h" 1.25 + 1.26 +#include "mtransport_test_utils.h" 1.27 +MtransportTestUtils *test_utils; 1.28 + 1.29 +//Video Frame Color 1.30 +const int COLOR = 0x80; //Gray 1.31 + 1.32 +//MWC RNG of George Marsaglia 1.33 +//taken from xiph.org 1.34 +static int32_t Rz, Rw; 1.35 +static inline int32_t fast_rand(void) 1.36 +{ 1.37 + Rz=36969*(Rz&65535)+(Rz>>16); 1.38 + Rw=18000*(Rw&65535)+(Rw>>16); 1.39 + return (Rz<<16)+Rw; 1.40 +} 1.41 + 1.42 +/** 1.43 + * Global structure to store video test results. 1.44 + */ 1.45 +struct VideoTestStats 1.46 +{ 1.47 + int numRawFramesInserted; 1.48 + int numFramesRenderedSuccessfully; 1.49 + int numFramesRenderedWrongly; 1.50 +}; 1.51 + 1.52 +VideoTestStats vidStatsGlobal={0,0,0}; 1.53 + 1.54 + 1.55 +/** 1.56 + * A Dummy Video Conduit Tester. 1.57 + * The test-case inserts a 640*480 grey imagerevery 33 milliseconds 1.58 + * to the video-conduit for encoding and transporting. 1.59 + */ 1.60 + 1.61 +class VideoSendAndReceive 1.62 +{ 1.63 +public: 1.64 + VideoSendAndReceive():width(640), 1.65 + height(480) 1.66 + { 1.67 + } 1.68 + 1.69 + ~VideoSendAndReceive() 1.70 + { 1.71 + } 1.72 + 1.73 + void Init(mozilla::RefPtr<mozilla::VideoSessionConduit> aSession) 1.74 + { 1.75 + mSession = aSession; 1.76 + } 1.77 + void GenerateAndReadSamples() 1.78 + { 1.79 + 1.80 + int len = ((width * height) * 3 / 2); 1.81 + uint8_t* frame = (uint8_t*) PR_MALLOC(len); 1.82 + int numFrames = 121; 1.83 + memset(frame, COLOR, len); 1.84 + 1.85 + do 1.86 + { 1.87 + mSession->SendVideoFrame((unsigned char*)frame, 1.88 + len, 1.89 + width, 1.90 + height, 1.91 + mozilla::kVideoI420, 1.92 + 0); 1.93 + PR_Sleep(PR_MillisecondsToInterval(33)); 1.94 + vidStatsGlobal.numRawFramesInserted++; 1.95 + numFrames--; 1.96 + } while(numFrames >= 0); 1.97 + PR_Free(frame); 1.98 + } 1.99 + 1.100 +private: 1.101 +mozilla::RefPtr<mozilla::VideoSessionConduit> mSession; 1.102 +int width, height; 1.103 +}; 1.104 + 1.105 + 1.106 + 1.107 +/** 1.108 + * A Dummy AudioConduit Tester 1.109 + * The test reads PCM samples of a standard test file and 1.110 + * passws to audio-conduit for encoding, RTPfication and 1.111 + * decoding ebery 10 milliseconds. 1.112 + * This decoded samples are read-off the conduit for writing 1.113 + * into output audio file in PCM format. 1.114 + */ 1.115 +class AudioSendAndReceive 1.116 +{ 1.117 +public: 1.118 + static const unsigned int PLAYOUT_SAMPLE_FREQUENCY; //default is 16000 1.119 + static const unsigned int PLAYOUT_SAMPLE_LENGTH; //default is 160000 1.120 + 1.121 + AudioSendAndReceive() 1.122 + { 1.123 + } 1.124 + 1.125 + ~AudioSendAndReceive() 1.126 + { 1.127 + } 1.128 + 1.129 + void Init(mozilla::RefPtr<mozilla::AudioSessionConduit> aSession, 1.130 + mozilla::RefPtr<mozilla::AudioSessionConduit> aOtherSession, 1.131 + std::string fileIn, std::string fileOut) 1.132 + { 1.133 + 1.134 + mSession = aSession; 1.135 + mOtherSession = aOtherSession; 1.136 + iFile = fileIn; 1.137 + oFile = fileOut; 1.138 + } 1.139 + 1.140 + //Kick start the test 1.141 + void GenerateAndReadSamples(); 1.142 + 1.143 +private: 1.144 + 1.145 + mozilla::RefPtr<mozilla::AudioSessionConduit> mSession; 1.146 + mozilla::RefPtr<mozilla::AudioSessionConduit> mOtherSession; 1.147 + std::string iFile; 1.148 + std::string oFile; 1.149 + 1.150 + int WriteWaveHeader(int rate, int channels, FILE* outFile); 1.151 + int FinishWaveHeader(FILE* outFile); 1.152 + void GenerateMusic(int16_t* buf, int len); 1.153 +}; 1.154 + 1.155 +const unsigned int AudioSendAndReceive::PLAYOUT_SAMPLE_FREQUENCY = 16000; 1.156 +const unsigned int AudioSendAndReceive::PLAYOUT_SAMPLE_LENGTH = 160000; 1.157 + 1.158 +int AudioSendAndReceive::WriteWaveHeader(int rate, int channels, FILE* outFile) 1.159 +{ 1.160 + //Hardcoded for 16 bit samples 1.161 + unsigned char header[] = { 1.162 + // File header 1.163 + 0x52, 0x49, 0x46, 0x46, // 'RIFF' 1.164 + 0x00, 0x00, 0x00, 0x00, // chunk size 1.165 + 0x57, 0x41, 0x56, 0x45, // 'WAVE' 1.166 + // fmt chunk. We always write 16-bit samples. 1.167 + 0x66, 0x6d, 0x74, 0x20, // 'fmt ' 1.168 + 0x10, 0x00, 0x00, 0x00, // chunk size 1.169 + 0x01, 0x00, // WAVE_FORMAT_PCM 1.170 + 0xFF, 0xFF, // channels 1.171 + 0xFF, 0xFF, 0xFF, 0xFF, // sample rate 1.172 + 0x00, 0x00, 0x00, 0x00, // data rate 1.173 + 0xFF, 0xFF, // frame size in bytes 1.174 + 0x10, 0x00, // bits per sample 1.175 + // data chunk 1.176 + 0x64, 0x61, 0x74, 0x61, // 'data' 1.177 + 0xFE, 0xFF, 0xFF, 0x7F // chunk size 1.178 + }; 1.179 + 1.180 +#define set_uint16le(buffer, value) \ 1.181 + (buffer)[0] = (value) & 0xff; \ 1.182 + (buffer)[1] = (value) >> 8; 1.183 +#define set_uint32le(buffer, value) \ 1.184 + set_uint16le( (buffer), (value) & 0xffff ); \ 1.185 + set_uint16le( (buffer) + 2, (value) >> 16 ); 1.186 + 1.187 + // set dynamic header fields 1.188 + set_uint16le(header + 22, channels); 1.189 + set_uint32le(header + 24, rate); 1.190 + set_uint16le(header + 32, channels*2); 1.191 + 1.192 + size_t written = fwrite(header, 1, sizeof(header), outFile); 1.193 + if (written != sizeof(header)) { 1.194 + cerr << "Writing WAV header failed" << endl; 1.195 + return -1; 1.196 + } 1.197 + 1.198 + return 0; 1.199 +} 1.200 + 1.201 +// Update the WAVE file header with the written length 1.202 +int AudioSendAndReceive::FinishWaveHeader(FILE* outFile) 1.203 +{ 1.204 + // Measure how much data we've written 1.205 + long end = ftell(outFile); 1.206 + if (end < 16) { 1.207 + cerr << "Couldn't get output file length" << endl; 1.208 + return (end < 0) ? end : -1; 1.209 + } 1.210 + 1.211 + // Update the header 1.212 + unsigned char size[4]; 1.213 + int err = fseek(outFile, 40, SEEK_SET); 1.214 + if (err < 0) { 1.215 + cerr << "Couldn't seek to WAV file header." << endl; 1.216 + return err; 1.217 + } 1.218 + set_uint32le(size, (end - 44) & 0xffffffff); 1.219 + size_t written = fwrite(size, 1, sizeof(size), outFile); 1.220 + if (written != sizeof(size)) { 1.221 + cerr << "Couldn't write data size to WAV header" << endl; 1.222 + return -1; 1.223 + } 1.224 + 1.225 + // Return to the end 1.226 + err = fseek(outFile, 0, SEEK_END); 1.227 + if (err < 0) { 1.228 + cerr << "Couldn't seek to WAV file end." << endl; 1.229 + return err; 1.230 + } 1.231 + 1.232 + return 0; 1.233 +} 1.234 + 1.235 +//Code from xiph.org to generate music of predefined length 1.236 +void AudioSendAndReceive::GenerateMusic(short* buf, int len) 1.237 +{ 1.238 + cerr <<" Generating Input Music " << endl; 1.239 + int32_t a1,a2,b1,b2; 1.240 + int32_t c1,c2,d1,d2; 1.241 + int32_t i,j; 1.242 + a1=b1=a2=b2=0; 1.243 + c1=c2=d1=d2=0; 1.244 + j=0; 1.245 + /*60ms silence */ 1.246 + for(i=0;i<2880;i++) 1.247 + { 1.248 + buf[i*2]=buf[(i*2)+1]=0; 1.249 + } 1.250 + for(i=2880;i<len-1;i+=2) 1.251 + { 1.252 + int32_t r; 1.253 + int32_t v1,v2; 1.254 + v1=v2=(((j*((j>>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15; 1.255 + r=fast_rand();v1+=r&65535;v1-=r>>16; 1.256 + r=fast_rand();v2+=r&65535;v2-=r>>16; 1.257 + b1=v1-a1+((b1*61+32)>>6);a1=v1; 1.258 + b2=v2-a2+((b2*61+32)>>6);a2=v2; 1.259 + c1=(30*(c1+b1+d1)+32)>>6;d1=b1; 1.260 + c2=(30*(c2+b2+d2)+32)>>6;d2=b2; 1.261 + v1=(c1+128)>>8; 1.262 + v2=(c2+128)>>8; 1.263 + buf[i]=v1>32767?32767:(v1<-32768?-32768:v1); 1.264 + buf[i+1]=v2>32767?32767:(v2<-32768?-32768:v2); 1.265 + if(i%6==0)j++; 1.266 + } 1.267 + cerr << "Generating Input Music Done " << endl; 1.268 +} 1.269 + 1.270 +//Hardcoded for 16 bit samples for now 1.271 +void AudioSendAndReceive::GenerateAndReadSamples() 1.272 +{ 1.273 + int16_t audioInput[PLAYOUT_SAMPLE_LENGTH]; 1.274 + int16_t audioOutput[PLAYOUT_SAMPLE_LENGTH]; 1.275 + short* inbuf; 1.276 + int sampleLengthDecoded = 0; 1.277 + unsigned int SAMPLES = (PLAYOUT_SAMPLE_FREQUENCY * 10); //10 seconds 1.278 + int CHANNELS = 1; //mono audio 1.279 + int sampleLengthInBytes = sizeof(audioInput); 1.280 + //generated audio buffer 1.281 + inbuf = (short *)moz_xmalloc(sizeof(short)*SAMPLES*CHANNELS); 1.282 + memset(audioInput,0,sampleLengthInBytes); 1.283 + memset(audioOutput,0,sampleLengthInBytes); 1.284 + MOZ_ASSERT(SAMPLES <= PLAYOUT_SAMPLE_LENGTH); 1.285 + 1.286 + FILE* inFile = fopen( iFile.c_str(), "wb+"); 1.287 + if(!inFile) { 1.288 + cerr << "Input File Creation Failed " << endl; 1.289 + return; 1.290 + } 1.291 + 1.292 + FILE* outFile = fopen( oFile.c_str(), "wb+"); 1.293 + if(!outFile) { 1.294 + cerr << "Output File Creation Failed " << endl; 1.295 + return; 1.296 + } 1.297 + 1.298 + //Create input file with the music 1.299 + WriteWaveHeader(PLAYOUT_SAMPLE_FREQUENCY, 1, inFile); 1.300 + GenerateMusic(inbuf, SAMPLES); 1.301 + fwrite(inbuf,1,SAMPLES*sizeof(inbuf[0])*CHANNELS,inFile); 1.302 + FinishWaveHeader(inFile); 1.303 + fclose(inFile); 1.304 + 1.305 + WriteWaveHeader(PLAYOUT_SAMPLE_FREQUENCY, 1, outFile); 1.306 + unsigned int numSamplesReadFromInput = 0; 1.307 + do 1.308 + { 1.309 + if(!memcpy(audioInput, inbuf, sampleLengthInBytes)) 1.310 + { 1.311 + return; 1.312 + } 1.313 + 1.314 + numSamplesReadFromInput += PLAYOUT_SAMPLE_LENGTH; 1.315 + inbuf += PLAYOUT_SAMPLE_LENGTH; 1.316 + 1.317 + mSession->SendAudioFrame(audioInput, 1.318 + PLAYOUT_SAMPLE_LENGTH, 1.319 + PLAYOUT_SAMPLE_FREQUENCY,10); 1.320 + 1.321 + PR_Sleep(PR_MillisecondsToInterval(10)); 1.322 + mOtherSession->GetAudioFrame(audioOutput, PLAYOUT_SAMPLE_FREQUENCY, 1.323 + 10, sampleLengthDecoded); 1.324 + if(sampleLengthDecoded == 0) 1.325 + { 1.326 + cerr << " Zero length Sample " << endl; 1.327 + } 1.328 + 1.329 + int wrote_ = fwrite (audioOutput, 1 , sampleLengthInBytes, outFile); 1.330 + if(wrote_ != sampleLengthInBytes) 1.331 + { 1.332 + cerr << "Couldn't Write " << sampleLengthInBytes << "bytes" << endl; 1.333 + break; 1.334 + } 1.335 + }while(numSamplesReadFromInput < SAMPLES); 1.336 + 1.337 + FinishWaveHeader(outFile); 1.338 + fclose(outFile); 1.339 +} 1.340 + 1.341 +/** 1.342 + * Dummy Video Target for the conduit 1.343 + * This class acts as renderer attached to the video conuit 1.344 + * As of today we just verify if the frames rendered are exactly 1.345 + * the same as frame inserted at the first place 1.346 + */ 1.347 +class DummyVideoTarget: public mozilla::VideoRenderer 1.348 +{ 1.349 +public: 1.350 + DummyVideoTarget() 1.351 + { 1.352 + } 1.353 + 1.354 + virtual ~DummyVideoTarget() 1.355 + { 1.356 + } 1.357 + 1.358 + 1.359 + void RenderVideoFrame(const unsigned char* buffer, 1.360 + unsigned int buffer_size, 1.361 + uint32_t time_stamp, 1.362 + int64_t render_time, 1.363 + const mozilla::ImageHandle& handle) 1.364 + { 1.365 + //write the frame to the file 1.366 + if(VerifyFrame(buffer, buffer_size) == 0) 1.367 + { 1.368 + vidStatsGlobal.numFramesRenderedSuccessfully++; 1.369 + } else 1.370 + { 1.371 + vidStatsGlobal.numFramesRenderedWrongly++; 1.372 + } 1.373 + } 1.374 + 1.375 + void FrameSizeChange(unsigned int, unsigned int, unsigned int) 1.376 + { 1.377 + //do nothing 1.378 + } 1.379 + 1.380 + //This is hardcoded to check if the contents of frame is COLOR 1.381 + // as we set while sending. 1.382 + int VerifyFrame(const unsigned char* buffer, unsigned int buffer_size) 1.383 + { 1.384 + int good = 0; 1.385 + for(int i=0; i < (int) buffer_size; i++) 1.386 + { 1.387 + if(buffer[i] == COLOR) 1.388 + { 1.389 + ++good; 1.390 + } 1.391 + else 1.392 + { 1.393 + --good; 1.394 + } 1.395 + } 1.396 + return 0; 1.397 + } 1.398 + 1.399 +}; 1.400 + 1.401 +/** 1.402 + * Fake Audio and Video External Transport Class 1.403 + * The functions in this class will be invoked by the conduit 1.404 + * when it has RTP/RTCP frame to transmit. 1.405 + * For everty RTP/RTCP frame we receive, we pass it back 1.406 + * to the conduit for eventual decoding and rendering. 1.407 + */ 1.408 +class FakeMediaTransport : public mozilla::TransportInterface 1.409 +{ 1.410 +public: 1.411 + FakeMediaTransport():numPkts(0), 1.412 + mAudio(false), 1.413 + mVideo(false) 1.414 + { 1.415 + } 1.416 + 1.417 + ~FakeMediaTransport() 1.418 + { 1.419 + } 1.420 + 1.421 + virtual nsresult SendRtpPacket(const void* data, int len) 1.422 + { 1.423 + ++numPkts; 1.424 + if(mAudio) 1.425 + { 1.426 + mOtherAudioSession->ReceivedRTPPacket(data,len); 1.427 + } else 1.428 + { 1.429 + mOtherVideoSession->ReceivedRTPPacket(data,len); 1.430 + } 1.431 + return NS_OK; 1.432 + } 1.433 + 1.434 + virtual nsresult SendRtcpPacket(const void* data, int len) 1.435 + { 1.436 + if(mAudio) 1.437 + { 1.438 + mOtherAudioSession->ReceivedRTCPPacket(data,len); 1.439 + } else 1.440 + { 1.441 + mOtherVideoSession->ReceivedRTCPPacket(data,len); 1.442 + } 1.443 + return NS_OK; 1.444 + } 1.445 + 1.446 + //Treat this object as Audio Transport 1.447 + void SetAudioSession(mozilla::RefPtr<mozilla::AudioSessionConduit> aSession, 1.448 + mozilla::RefPtr<mozilla::AudioSessionConduit> 1.449 + aOtherSession) 1.450 + { 1.451 + mAudioSession = aSession; 1.452 + mOtherAudioSession = aOtherSession; 1.453 + mAudio = true; 1.454 + } 1.455 + 1.456 + // Treat this object as Video Transport 1.457 + void SetVideoSession(mozilla::RefPtr<mozilla::VideoSessionConduit> aSession, 1.458 + mozilla::RefPtr<mozilla::VideoSessionConduit> 1.459 + aOtherSession) 1.460 + { 1.461 + mVideoSession = aSession; 1.462 + mOtherVideoSession = aOtherSession; 1.463 + mVideo = true; 1.464 + } 1.465 + 1.466 +private: 1.467 + mozilla::RefPtr<mozilla::AudioSessionConduit> mAudioSession; 1.468 + mozilla::RefPtr<mozilla::VideoSessionConduit> mVideoSession; 1.469 + mozilla::RefPtr<mozilla::VideoSessionConduit> mOtherVideoSession; 1.470 + mozilla::RefPtr<mozilla::AudioSessionConduit> mOtherAudioSession; 1.471 + int numPkts; 1.472 + bool mAudio, mVideo; 1.473 +}; 1.474 + 1.475 + 1.476 +namespace { 1.477 + 1.478 +class TransportConduitTest : public ::testing::Test 1.479 +{ 1.480 + public: 1.481 + TransportConduitTest() 1.482 + { 1.483 + //input and output file names 1.484 + iAudiofilename = "input.wav"; 1.485 + oAudiofilename = "recorded.wav"; 1.486 + } 1.487 + 1.488 + ~TransportConduitTest() 1.489 + { 1.490 + } 1.491 + 1.492 + //1. Dump audio samples to dummy external transport 1.493 + void TestDummyAudioAndTransport() 1.494 + { 1.495 + //get pointer to AudioSessionConduit 1.496 + int err=0; 1.497 + mAudioSession = mozilla::AudioSessionConduit::Create(nullptr); 1.498 + if( !mAudioSession ) 1.499 + ASSERT_NE(mAudioSession, (void*)nullptr); 1.500 + 1.501 + mAudioSession2 = mozilla::AudioSessionConduit::Create(nullptr); 1.502 + if( !mAudioSession2 ) 1.503 + ASSERT_NE(mAudioSession2, (void*)nullptr); 1.504 + 1.505 + FakeMediaTransport* xport = new FakeMediaTransport(); 1.506 + ASSERT_NE(xport, (void*)nullptr); 1.507 + xport->SetAudioSession(mAudioSession, mAudioSession2); 1.508 + mAudioTransport = xport; 1.509 + 1.510 + // attach the transport to audio-conduit 1.511 + err = mAudioSession->AttachTransport(mAudioTransport); 1.512 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.513 + err = mAudioSession2->AttachTransport(mAudioTransport); 1.514 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.515 + 1.516 + //configure send and recv codecs on the audio-conduit 1.517 + //mozilla::AudioCodecConfig cinst1(124,"PCMU",8000,80,1,64000); 1.518 + mozilla::AudioCodecConfig cinst1(124,"opus",48000,960,1,64000); 1.519 + mozilla::AudioCodecConfig cinst2(125,"L16",16000,320,1,256000); 1.520 + 1.521 + 1.522 + std::vector<mozilla::AudioCodecConfig*> rcvCodecList; 1.523 + rcvCodecList.push_back(&cinst1); 1.524 + rcvCodecList.push_back(&cinst2); 1.525 + 1.526 + err = mAudioSession->ConfigureSendMediaCodec(&cinst1); 1.527 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.528 + err = mAudioSession->ConfigureRecvMediaCodecs(rcvCodecList); 1.529 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.530 + 1.531 + err = mAudioSession2->ConfigureSendMediaCodec(&cinst1); 1.532 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.533 + err = mAudioSession2->ConfigureRecvMediaCodecs(rcvCodecList); 1.534 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.535 + 1.536 + //start generating samples 1.537 + audioTester.Init(mAudioSession,mAudioSession2, iAudiofilename,oAudiofilename); 1.538 + cerr << " ******************************************************** " << endl; 1.539 + cerr << " Generating Audio Samples " << endl; 1.540 + cerr << " ******************************************************** " << endl; 1.541 + PR_Sleep(PR_SecondsToInterval(2)); 1.542 + audioTester.GenerateAndReadSamples(); 1.543 + PR_Sleep(PR_SecondsToInterval(2)); 1.544 + cerr << " ******************************************************** " << endl; 1.545 + cerr << " Input Audio File " << iAudiofilename << endl; 1.546 + cerr << " Output Audio File " << oAudiofilename << endl; 1.547 + cerr << " ******************************************************** " << endl; 1.548 + } 1.549 + 1.550 + //2. Dump audio samples to dummy external transport 1.551 + void TestDummyVideoAndTransport() 1.552 + { 1.553 + int err = 0; 1.554 + //get pointer to VideoSessionConduit 1.555 + mVideoSession = mozilla::VideoSessionConduit::Create(nullptr); 1.556 + if( !mVideoSession ) 1.557 + ASSERT_NE(mVideoSession, (void*)nullptr); 1.558 + 1.559 + // This session is for other one 1.560 + mVideoSession2 = mozilla::VideoSessionConduit::Create(nullptr); 1.561 + if( !mVideoSession2 ) 1.562 + ASSERT_NE(mVideoSession2,(void*)nullptr); 1.563 + 1.564 + mVideoRenderer = new DummyVideoTarget(); 1.565 + ASSERT_NE(mVideoRenderer, (void*)nullptr); 1.566 + 1.567 + FakeMediaTransport* xport = new FakeMediaTransport(); 1.568 + ASSERT_NE(xport, (void*)nullptr); 1.569 + xport->SetVideoSession(mVideoSession,mVideoSession2); 1.570 + mVideoTransport = xport; 1.571 + 1.572 + // attach the transport and renderer to video-conduit 1.573 + err = mVideoSession2->AttachRenderer(mVideoRenderer); 1.574 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.575 + err = mVideoSession->AttachTransport(mVideoTransport); 1.576 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.577 + err = mVideoSession2->AttachTransport(mVideoTransport); 1.578 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.579 + 1.580 + //configure send and recv codecs on theconduit 1.581 + mozilla::VideoCodecConfig cinst1(120, "VP8", 0); 1.582 + mozilla::VideoCodecConfig cinst2(124, "I420", 0); 1.583 + 1.584 + 1.585 + std::vector<mozilla::VideoCodecConfig* > rcvCodecList; 1.586 + rcvCodecList.push_back(&cinst1); 1.587 + rcvCodecList.push_back(&cinst2); 1.588 + 1.589 + err = mVideoSession->ConfigureSendMediaCodec(&cinst1); 1.590 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.591 + 1.592 + err = mVideoSession2->ConfigureRecvMediaCodecs(rcvCodecList); 1.593 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.594 + 1.595 + //start generating samples 1.596 + cerr << " *************************************************" << endl; 1.597 + cerr << " Starting the Video Sample Generation " << endl; 1.598 + cerr << " *************************************************" << endl; 1.599 + PR_Sleep(PR_SecondsToInterval(2)); 1.600 + videoTester.Init(mVideoSession); 1.601 + videoTester.GenerateAndReadSamples(); 1.602 + PR_Sleep(PR_SecondsToInterval(2)); 1.603 + cerr << " **************************************************" << endl; 1.604 + cerr << " Done With The Testing " << endl; 1.605 + cerr << " VIDEO TEST STATS " << endl; 1.606 + cerr << " Num Raw Frames Inserted: "<< 1.607 + vidStatsGlobal.numRawFramesInserted << endl; 1.608 + cerr << " Num Frames Successfully Rendered: "<< 1.609 + vidStatsGlobal.numFramesRenderedSuccessfully << endl; 1.610 + cerr << " Num Frames Wrongly Rendered: "<< 1.611 + vidStatsGlobal.numFramesRenderedWrongly << endl; 1.612 + 1.613 + cerr << " Done With The Testing " << endl; 1.614 + 1.615 + cerr << " **************************************************" << endl; 1.616 + ASSERT_EQ(0, vidStatsGlobal.numFramesRenderedWrongly); 1.617 + ASSERT_EQ(vidStatsGlobal.numRawFramesInserted, 1.618 + vidStatsGlobal.numFramesRenderedSuccessfully); 1.619 + } 1.620 + 1.621 + void TestVideoConduitCodecAPI() 1.622 + { 1.623 + int err = 0; 1.624 + mozilla::RefPtr<mozilla::VideoSessionConduit> mVideoSession; 1.625 + //get pointer to VideoSessionConduit 1.626 + mVideoSession = mozilla::VideoSessionConduit::Create(nullptr); 1.627 + if( !mVideoSession ) 1.628 + ASSERT_NE(mVideoSession, (void*)nullptr); 1.629 + 1.630 + //Test Configure Recv Codec APIS 1.631 + cerr << " *************************************************" << endl; 1.632 + cerr << " Test Receive Codec Configuration API Now " << endl; 1.633 + cerr << " *************************************************" << endl; 1.634 + 1.635 + std::vector<mozilla::VideoCodecConfig* > rcvCodecList; 1.636 + 1.637 + //Same APIs 1.638 + cerr << " *************************************************" << endl; 1.639 + cerr << " 1. Same Codec (VP8) Repeated Twice " << endl; 1.640 + cerr << " *************************************************" << endl; 1.641 + 1.642 + mozilla::VideoCodecConfig cinst1(120, "VP8", 0); 1.643 + mozilla::VideoCodecConfig cinst2(120, "VP8", 0); 1.644 + rcvCodecList.push_back(&cinst1); 1.645 + rcvCodecList.push_back(&cinst2); 1.646 + err = mVideoSession->ConfigureRecvMediaCodecs(rcvCodecList); 1.647 + EXPECT_NE(err,mozilla::kMediaConduitNoError); 1.648 + rcvCodecList.pop_back(); 1.649 + rcvCodecList.pop_back(); 1.650 + 1.651 + 1.652 + PR_Sleep(PR_SecondsToInterval(2)); 1.653 + cerr << " *************************************************" << endl; 1.654 + cerr << " 2. Codec With Invalid Payload Names " << endl; 1.655 + cerr << " *************************************************" << endl; 1.656 + cerr << " Setting payload 1 with name: I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676" << endl; 1.657 + cerr << " Setting payload 2 with name of zero length" << endl; 1.658 + 1.659 + mozilla::VideoCodecConfig cinst3(124, "I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676", 0); 1.660 + mozilla::VideoCodecConfig cinst4(124, "", 0); 1.661 + 1.662 + rcvCodecList.push_back(&cinst3); 1.663 + rcvCodecList.push_back(&cinst4); 1.664 + 1.665 + err = mVideoSession->ConfigureRecvMediaCodecs(rcvCodecList); 1.666 + EXPECT_TRUE(err != mozilla::kMediaConduitNoError); 1.667 + rcvCodecList.pop_back(); 1.668 + rcvCodecList.pop_back(); 1.669 + 1.670 + 1.671 + PR_Sleep(PR_SecondsToInterval(2)); 1.672 + cerr << " *************************************************" << endl; 1.673 + cerr << " 3. Null Codec Parameter " << endl; 1.674 + cerr << " *************************************************" << endl; 1.675 + 1.676 + rcvCodecList.push_back(0); 1.677 + 1.678 + err = mVideoSession->ConfigureRecvMediaCodecs(rcvCodecList); 1.679 + EXPECT_TRUE(err != mozilla::kMediaConduitNoError); 1.680 + rcvCodecList.pop_back(); 1.681 + 1.682 + cerr << " *************************************************" << endl; 1.683 + cerr << " Test Send Codec Configuration API Now " << endl; 1.684 + cerr << " *************************************************" << endl; 1.685 + 1.686 + cerr << " *************************************************" << endl; 1.687 + cerr << " 1. Same Codec (VP8) Repeated Twice " << endl; 1.688 + cerr << " *************************************************" << endl; 1.689 + 1.690 + 1.691 + err = mVideoSession->ConfigureSendMediaCodec(&cinst1); 1.692 + EXPECT_EQ(mozilla::kMediaConduitNoError, err); 1.693 + err = mVideoSession->ConfigureSendMediaCodec(&cinst1); 1.694 + EXPECT_EQ(mozilla::kMediaConduitCodecInUse, err); 1.695 + 1.696 + 1.697 + cerr << " *************************************************" << endl; 1.698 + cerr << " 2. Codec With Invalid Payload Names " << endl; 1.699 + cerr << " *************************************************" << endl; 1.700 + cerr << " Setting payload with name: I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676" << endl; 1.701 + 1.702 + err = mVideoSession->ConfigureSendMediaCodec(&cinst3); 1.703 + EXPECT_TRUE(err != mozilla::kMediaConduitNoError); 1.704 + 1.705 + cerr << " *************************************************" << endl; 1.706 + cerr << " 3. Null Codec Parameter " << endl; 1.707 + cerr << " *************************************************" << endl; 1.708 + 1.709 + err = mVideoSession->ConfigureSendMediaCodec(nullptr); 1.710 + EXPECT_TRUE(err != mozilla::kMediaConduitNoError); 1.711 + 1.712 + } 1.713 + 1.714 + void DumpMaxFs(int orig_width, int orig_height, int max_fs, 1.715 + int new_width, int new_height) 1.716 + { 1.717 + cerr << "Applying max_fs=" << max_fs << " to input resolution " << 1.718 + orig_width << "x" << orig_height << endl; 1.719 + cerr << "New resolution: " << new_width << "x" << new_height << endl; 1.720 + cerr << endl; 1.721 + } 1.722 + 1.723 + // Calculate new resolution for sending video by applying max-fs constraint. 1.724 + void GetVideoResolutionWithMaxFs(int orig_width, int orig_height, int max_fs, 1.725 + int *new_width, int *new_height) 1.726 + { 1.727 + int err = 0; 1.728 + 1.729 + // Get pointer to VideoSessionConduit. 1.730 + mVideoSession = mozilla::VideoSessionConduit::Create(nullptr); 1.731 + if( !mVideoSession ) 1.732 + ASSERT_NE(mVideoSession, (void*)nullptr); 1.733 + 1.734 + // Configure send codecs on the conduit. 1.735 + mozilla::VideoCodecConfig cinst1(120, "VP8", 0, max_fs, 0); 1.736 + 1.737 + err = mVideoSession->ConfigureSendMediaCodec(&cinst1); 1.738 + ASSERT_EQ(mozilla::kMediaConduitNoError, err); 1.739 + 1.740 + // Send one frame. 1.741 + MOZ_ASSERT(!(orig_width & 1)); 1.742 + MOZ_ASSERT(!(orig_height & 1)); 1.743 + int len = ((orig_width * orig_height) * 3 / 2); 1.744 + uint8_t* frame = (uint8_t*) PR_MALLOC(len); 1.745 + 1.746 + memset(frame, COLOR, len); 1.747 + mVideoSession->SendVideoFrame((unsigned char*)frame, 1.748 + len, 1.749 + orig_width, 1.750 + orig_height, 1.751 + mozilla::kVideoI420, 1.752 + 0); 1.753 + PR_Free(frame); 1.754 + 1.755 + // Get the new resolution as adjusted by the max-fs constraint. 1.756 + *new_width = mVideoSession->SendingWidth(); 1.757 + *new_height = mVideoSession->SendingHeight(); 1.758 + } 1.759 + 1.760 + void TestVideoConduitMaxFs() 1.761 + { 1.762 + int orig_width, orig_height, width, height, max_fs; 1.763 + 1.764 + // No limitation. 1.765 + cerr << "Test no max-fs limition" << endl; 1.766 + orig_width = 640; 1.767 + orig_height = 480; 1.768 + max_fs = 0; 1.769 + GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height); 1.770 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.771 + ASSERT_EQ(width, 640); 1.772 + ASSERT_EQ(height, 480); 1.773 + 1.774 + // VGA to QVGA. 1.775 + cerr << "Test resizing from VGA to QVGA" << endl; 1.776 + orig_width = 640; 1.777 + orig_height = 480; 1.778 + max_fs = 300; 1.779 + GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height); 1.780 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.781 + ASSERT_EQ(width, 320); 1.782 + ASSERT_EQ(height, 240); 1.783 + 1.784 + // Extreme input resolution. 1.785 + cerr << "Test extreme input resolution" << endl; 1.786 + orig_width = 3072; 1.787 + orig_height = 100; 1.788 + max_fs = 300; 1.789 + GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height); 1.790 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.791 + ASSERT_EQ(width, 768); 1.792 + ASSERT_EQ(height, 26); 1.793 + 1.794 + // Small max-fs. 1.795 + cerr << "Test small max-fs (case 1)" << endl; 1.796 + orig_width = 8; 1.797 + orig_height = 32; 1.798 + max_fs = 1; 1.799 + GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height); 1.800 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.801 + ASSERT_EQ(width, 4); 1.802 + ASSERT_EQ(height, 16); 1.803 + 1.804 + // Small max-fs. 1.805 + cerr << "Test small max-fs (case 2)" << endl; 1.806 + orig_width = 4; 1.807 + orig_height = 50; 1.808 + max_fs = 1; 1.809 + GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height); 1.810 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.811 + ASSERT_EQ(width, 2); 1.812 + ASSERT_EQ(height, 16); 1.813 + 1.814 + // Small max-fs. 1.815 + cerr << "Test small max-fs (case 3)" << endl; 1.816 + orig_width = 872; 1.817 + orig_height = 136; 1.818 + max_fs = 3; 1.819 + GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height); 1.820 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.821 + ASSERT_EQ(width, 48); 1.822 + ASSERT_EQ(height, 8); 1.823 + 1.824 + // Small max-fs. 1.825 + cerr << "Test small max-fs (case 4)" << endl; 1.826 + orig_width = 160; 1.827 + orig_height = 8; 1.828 + max_fs = 5; 1.829 + GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height); 1.830 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.831 + ASSERT_EQ(width, 80); 1.832 + ASSERT_EQ(height, 4); 1.833 + 1.834 + // Extremely small width and height(see bug 919979). 1.835 + cerr << "Test with extremely small width and height" << endl; 1.836 + orig_width = 2; 1.837 + orig_height = 2; 1.838 + max_fs = 5; 1.839 + GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height); 1.840 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.841 + ASSERT_EQ(width, 2); 1.842 + ASSERT_EQ(height, 2); 1.843 + 1.844 + // Random values. 1.845 + cerr << "Test with random values" << endl; 1.846 + for (int i = 0; i < 30; i++) { 1.847 + cerr << "."; 1.848 + max_fs = rand() % 1000; 1.849 + orig_width = ((rand() % 2000) & ~1) + 2; 1.850 + orig_height = ((rand() % 2000) & ~1) + 2; 1.851 + 1.852 + GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, 1.853 + &width, &height); 1.854 + if (max_fs > 0 && 1.855 + ceil(width / 16.) * ceil(height / 16.) > max_fs) { 1.856 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.857 + ADD_FAILURE(); 1.858 + } 1.859 + if ((width & 1) || (height & 1)) { 1.860 + DumpMaxFs(orig_width, orig_height, max_fs, width, height); 1.861 + ADD_FAILURE(); 1.862 + } 1.863 + } 1.864 + cerr << endl; 1.865 + } 1.866 + 1.867 +private: 1.868 + //Audio Conduit Test Objects 1.869 + mozilla::RefPtr<mozilla::AudioSessionConduit> mAudioSession; 1.870 + mozilla::RefPtr<mozilla::AudioSessionConduit> mAudioSession2; 1.871 + mozilla::RefPtr<mozilla::TransportInterface> mAudioTransport; 1.872 + AudioSendAndReceive audioTester; 1.873 + 1.874 + //Video Conduit Test Objects 1.875 + mozilla::RefPtr<mozilla::VideoSessionConduit> mVideoSession; 1.876 + mozilla::RefPtr<mozilla::VideoSessionConduit> mVideoSession2; 1.877 + mozilla::RefPtr<mozilla::VideoRenderer> mVideoRenderer; 1.878 + mozilla::RefPtr<mozilla::TransportInterface> mVideoTransport; 1.879 + VideoSendAndReceive videoTester; 1.880 + 1.881 + std::string fileToPlay; 1.882 + std::string fileToRecord; 1.883 + std::string iAudiofilename; 1.884 + std::string oAudiofilename; 1.885 +}; 1.886 + 1.887 + 1.888 +// Test 1: Test Dummy External Xport 1.889 +TEST_F(TransportConduitTest, TestDummyAudioWithTransport) { 1.890 + TestDummyAudioAndTransport(); 1.891 +} 1.892 + 1.893 +// Test 2: Test Dummy External Xport 1.894 +TEST_F(TransportConduitTest, TestDummyVideoWithTransport) { 1.895 + TestDummyVideoAndTransport(); 1.896 + } 1.897 + 1.898 +TEST_F(TransportConduitTest, TestVideoConduitCodecAPI) { 1.899 + TestVideoConduitCodecAPI(); 1.900 + } 1.901 + 1.902 +TEST_F(TransportConduitTest, TestVideoConduitMaxFs) { 1.903 + TestVideoConduitMaxFs(); 1.904 + } 1.905 + 1.906 +} // end namespace 1.907 + 1.908 +int main(int argc, char **argv) 1.909 +{ 1.910 + // This test can cause intermittent oranges on the builders 1.911 + CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_MEDIACONDUIT_TESTS") 1.912 + 1.913 + test_utils = new MtransportTestUtils(); 1.914 + ::testing::InitGoogleTest(&argc, argv); 1.915 + int rv = RUN_ALL_TESTS(); 1.916 + delete test_utils; 1.917 + return rv; 1.918 +} 1.919 + 1.920 +