media/webrtc/signaling/test/mediaconduit_unittests.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include <iostream>
michael@0 6 #include <string>
michael@0 7 #include <fstream>
michael@0 8 #include <unistd.h>
michael@0 9 #include <vector>
michael@0 10 #include <math.h>
michael@0 11
michael@0 12 using namespace std;
michael@0 13
michael@0 14 #include "mozilla/Scoped.h"
michael@0 15 #include <MediaConduitInterface.h>
michael@0 16 #include "nsIEventTarget.h"
michael@0 17 #include "FakeMediaStreamsImpl.h"
michael@0 18
michael@0 19 #define GTEST_HAS_RTTI 0
michael@0 20 #include "gtest/gtest.h"
michael@0 21 #include "gtest_utils.h"
michael@0 22
michael@0 23 #include "mtransport_test_utils.h"
michael@0 24 MtransportTestUtils *test_utils;
michael@0 25
michael@0 26 //Video Frame Color
michael@0 27 const int COLOR = 0x80; //Gray
michael@0 28
michael@0 29 //MWC RNG of George Marsaglia
michael@0 30 //taken from xiph.org
michael@0 31 static int32_t Rz, Rw;
michael@0 32 static inline int32_t fast_rand(void)
michael@0 33 {
michael@0 34 Rz=36969*(Rz&65535)+(Rz>>16);
michael@0 35 Rw=18000*(Rw&65535)+(Rw>>16);
michael@0 36 return (Rz<<16)+Rw;
michael@0 37 }
michael@0 38
michael@0 39 /**
michael@0 40 * Global structure to store video test results.
michael@0 41 */
michael@0 42 struct VideoTestStats
michael@0 43 {
michael@0 44 int numRawFramesInserted;
michael@0 45 int numFramesRenderedSuccessfully;
michael@0 46 int numFramesRenderedWrongly;
michael@0 47 };
michael@0 48
michael@0 49 VideoTestStats vidStatsGlobal={0,0,0};
michael@0 50
michael@0 51
michael@0 52 /**
michael@0 53 * A Dummy Video Conduit Tester.
michael@0 54 * The test-case inserts a 640*480 grey imagerevery 33 milliseconds
michael@0 55 * to the video-conduit for encoding and transporting.
michael@0 56 */
michael@0 57
michael@0 58 class VideoSendAndReceive
michael@0 59 {
michael@0 60 public:
michael@0 61 VideoSendAndReceive():width(640),
michael@0 62 height(480)
michael@0 63 {
michael@0 64 }
michael@0 65
michael@0 66 ~VideoSendAndReceive()
michael@0 67 {
michael@0 68 }
michael@0 69
michael@0 70 void Init(mozilla::RefPtr<mozilla::VideoSessionConduit> aSession)
michael@0 71 {
michael@0 72 mSession = aSession;
michael@0 73 }
michael@0 74 void GenerateAndReadSamples()
michael@0 75 {
michael@0 76
michael@0 77 int len = ((width * height) * 3 / 2);
michael@0 78 uint8_t* frame = (uint8_t*) PR_MALLOC(len);
michael@0 79 int numFrames = 121;
michael@0 80 memset(frame, COLOR, len);
michael@0 81
michael@0 82 do
michael@0 83 {
michael@0 84 mSession->SendVideoFrame((unsigned char*)frame,
michael@0 85 len,
michael@0 86 width,
michael@0 87 height,
michael@0 88 mozilla::kVideoI420,
michael@0 89 0);
michael@0 90 PR_Sleep(PR_MillisecondsToInterval(33));
michael@0 91 vidStatsGlobal.numRawFramesInserted++;
michael@0 92 numFrames--;
michael@0 93 } while(numFrames >= 0);
michael@0 94 PR_Free(frame);
michael@0 95 }
michael@0 96
michael@0 97 private:
michael@0 98 mozilla::RefPtr<mozilla::VideoSessionConduit> mSession;
michael@0 99 int width, height;
michael@0 100 };
michael@0 101
michael@0 102
michael@0 103
michael@0 104 /**
michael@0 105 * A Dummy AudioConduit Tester
michael@0 106 * The test reads PCM samples of a standard test file and
michael@0 107 * passws to audio-conduit for encoding, RTPfication and
michael@0 108 * decoding ebery 10 milliseconds.
michael@0 109 * This decoded samples are read-off the conduit for writing
michael@0 110 * into output audio file in PCM format.
michael@0 111 */
michael@0 112 class AudioSendAndReceive
michael@0 113 {
michael@0 114 public:
michael@0 115 static const unsigned int PLAYOUT_SAMPLE_FREQUENCY; //default is 16000
michael@0 116 static const unsigned int PLAYOUT_SAMPLE_LENGTH; //default is 160000
michael@0 117
michael@0 118 AudioSendAndReceive()
michael@0 119 {
michael@0 120 }
michael@0 121
michael@0 122 ~AudioSendAndReceive()
michael@0 123 {
michael@0 124 }
michael@0 125
michael@0 126 void Init(mozilla::RefPtr<mozilla::AudioSessionConduit> aSession,
michael@0 127 mozilla::RefPtr<mozilla::AudioSessionConduit> aOtherSession,
michael@0 128 std::string fileIn, std::string fileOut)
michael@0 129 {
michael@0 130
michael@0 131 mSession = aSession;
michael@0 132 mOtherSession = aOtherSession;
michael@0 133 iFile = fileIn;
michael@0 134 oFile = fileOut;
michael@0 135 }
michael@0 136
michael@0 137 //Kick start the test
michael@0 138 void GenerateAndReadSamples();
michael@0 139
michael@0 140 private:
michael@0 141
michael@0 142 mozilla::RefPtr<mozilla::AudioSessionConduit> mSession;
michael@0 143 mozilla::RefPtr<mozilla::AudioSessionConduit> mOtherSession;
michael@0 144 std::string iFile;
michael@0 145 std::string oFile;
michael@0 146
michael@0 147 int WriteWaveHeader(int rate, int channels, FILE* outFile);
michael@0 148 int FinishWaveHeader(FILE* outFile);
michael@0 149 void GenerateMusic(int16_t* buf, int len);
michael@0 150 };
michael@0 151
michael@0 152 const unsigned int AudioSendAndReceive::PLAYOUT_SAMPLE_FREQUENCY = 16000;
michael@0 153 const unsigned int AudioSendAndReceive::PLAYOUT_SAMPLE_LENGTH = 160000;
michael@0 154
michael@0 155 int AudioSendAndReceive::WriteWaveHeader(int rate, int channels, FILE* outFile)
michael@0 156 {
michael@0 157 //Hardcoded for 16 bit samples
michael@0 158 unsigned char header[] = {
michael@0 159 // File header
michael@0 160 0x52, 0x49, 0x46, 0x46, // 'RIFF'
michael@0 161 0x00, 0x00, 0x00, 0x00, // chunk size
michael@0 162 0x57, 0x41, 0x56, 0x45, // 'WAVE'
michael@0 163 // fmt chunk. We always write 16-bit samples.
michael@0 164 0x66, 0x6d, 0x74, 0x20, // 'fmt '
michael@0 165 0x10, 0x00, 0x00, 0x00, // chunk size
michael@0 166 0x01, 0x00, // WAVE_FORMAT_PCM
michael@0 167 0xFF, 0xFF, // channels
michael@0 168 0xFF, 0xFF, 0xFF, 0xFF, // sample rate
michael@0 169 0x00, 0x00, 0x00, 0x00, // data rate
michael@0 170 0xFF, 0xFF, // frame size in bytes
michael@0 171 0x10, 0x00, // bits per sample
michael@0 172 // data chunk
michael@0 173 0x64, 0x61, 0x74, 0x61, // 'data'
michael@0 174 0xFE, 0xFF, 0xFF, 0x7F // chunk size
michael@0 175 };
michael@0 176
michael@0 177 #define set_uint16le(buffer, value) \
michael@0 178 (buffer)[0] = (value) & 0xff; \
michael@0 179 (buffer)[1] = (value) >> 8;
michael@0 180 #define set_uint32le(buffer, value) \
michael@0 181 set_uint16le( (buffer), (value) & 0xffff ); \
michael@0 182 set_uint16le( (buffer) + 2, (value) >> 16 );
michael@0 183
michael@0 184 // set dynamic header fields
michael@0 185 set_uint16le(header + 22, channels);
michael@0 186 set_uint32le(header + 24, rate);
michael@0 187 set_uint16le(header + 32, channels*2);
michael@0 188
michael@0 189 size_t written = fwrite(header, 1, sizeof(header), outFile);
michael@0 190 if (written != sizeof(header)) {
michael@0 191 cerr << "Writing WAV header failed" << endl;
michael@0 192 return -1;
michael@0 193 }
michael@0 194
michael@0 195 return 0;
michael@0 196 }
michael@0 197
michael@0 198 // Update the WAVE file header with the written length
michael@0 199 int AudioSendAndReceive::FinishWaveHeader(FILE* outFile)
michael@0 200 {
michael@0 201 // Measure how much data we've written
michael@0 202 long end = ftell(outFile);
michael@0 203 if (end < 16) {
michael@0 204 cerr << "Couldn't get output file length" << endl;
michael@0 205 return (end < 0) ? end : -1;
michael@0 206 }
michael@0 207
michael@0 208 // Update the header
michael@0 209 unsigned char size[4];
michael@0 210 int err = fseek(outFile, 40, SEEK_SET);
michael@0 211 if (err < 0) {
michael@0 212 cerr << "Couldn't seek to WAV file header." << endl;
michael@0 213 return err;
michael@0 214 }
michael@0 215 set_uint32le(size, (end - 44) & 0xffffffff);
michael@0 216 size_t written = fwrite(size, 1, sizeof(size), outFile);
michael@0 217 if (written != sizeof(size)) {
michael@0 218 cerr << "Couldn't write data size to WAV header" << endl;
michael@0 219 return -1;
michael@0 220 }
michael@0 221
michael@0 222 // Return to the end
michael@0 223 err = fseek(outFile, 0, SEEK_END);
michael@0 224 if (err < 0) {
michael@0 225 cerr << "Couldn't seek to WAV file end." << endl;
michael@0 226 return err;
michael@0 227 }
michael@0 228
michael@0 229 return 0;
michael@0 230 }
michael@0 231
michael@0 232 //Code from xiph.org to generate music of predefined length
michael@0 233 void AudioSendAndReceive::GenerateMusic(short* buf, int len)
michael@0 234 {
michael@0 235 cerr <<" Generating Input Music " << endl;
michael@0 236 int32_t a1,a2,b1,b2;
michael@0 237 int32_t c1,c2,d1,d2;
michael@0 238 int32_t i,j;
michael@0 239 a1=b1=a2=b2=0;
michael@0 240 c1=c2=d1=d2=0;
michael@0 241 j=0;
michael@0 242 /*60ms silence */
michael@0 243 for(i=0;i<2880;i++)
michael@0 244 {
michael@0 245 buf[i*2]=buf[(i*2)+1]=0;
michael@0 246 }
michael@0 247 for(i=2880;i<len-1;i+=2)
michael@0 248 {
michael@0 249 int32_t r;
michael@0 250 int32_t v1,v2;
michael@0 251 v1=v2=(((j*((j>>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15;
michael@0 252 r=fast_rand();v1+=r&65535;v1-=r>>16;
michael@0 253 r=fast_rand();v2+=r&65535;v2-=r>>16;
michael@0 254 b1=v1-a1+((b1*61+32)>>6);a1=v1;
michael@0 255 b2=v2-a2+((b2*61+32)>>6);a2=v2;
michael@0 256 c1=(30*(c1+b1+d1)+32)>>6;d1=b1;
michael@0 257 c2=(30*(c2+b2+d2)+32)>>6;d2=b2;
michael@0 258 v1=(c1+128)>>8;
michael@0 259 v2=(c2+128)>>8;
michael@0 260 buf[i]=v1>32767?32767:(v1<-32768?-32768:v1);
michael@0 261 buf[i+1]=v2>32767?32767:(v2<-32768?-32768:v2);
michael@0 262 if(i%6==0)j++;
michael@0 263 }
michael@0 264 cerr << "Generating Input Music Done " << endl;
michael@0 265 }
michael@0 266
michael@0 267 //Hardcoded for 16 bit samples for now
michael@0 268 void AudioSendAndReceive::GenerateAndReadSamples()
michael@0 269 {
michael@0 270 int16_t audioInput[PLAYOUT_SAMPLE_LENGTH];
michael@0 271 int16_t audioOutput[PLAYOUT_SAMPLE_LENGTH];
michael@0 272 short* inbuf;
michael@0 273 int sampleLengthDecoded = 0;
michael@0 274 unsigned int SAMPLES = (PLAYOUT_SAMPLE_FREQUENCY * 10); //10 seconds
michael@0 275 int CHANNELS = 1; //mono audio
michael@0 276 int sampleLengthInBytes = sizeof(audioInput);
michael@0 277 //generated audio buffer
michael@0 278 inbuf = (short *)moz_xmalloc(sizeof(short)*SAMPLES*CHANNELS);
michael@0 279 memset(audioInput,0,sampleLengthInBytes);
michael@0 280 memset(audioOutput,0,sampleLengthInBytes);
michael@0 281 MOZ_ASSERT(SAMPLES <= PLAYOUT_SAMPLE_LENGTH);
michael@0 282
michael@0 283 FILE* inFile = fopen( iFile.c_str(), "wb+");
michael@0 284 if(!inFile) {
michael@0 285 cerr << "Input File Creation Failed " << endl;
michael@0 286 return;
michael@0 287 }
michael@0 288
michael@0 289 FILE* outFile = fopen( oFile.c_str(), "wb+");
michael@0 290 if(!outFile) {
michael@0 291 cerr << "Output File Creation Failed " << endl;
michael@0 292 return;
michael@0 293 }
michael@0 294
michael@0 295 //Create input file with the music
michael@0 296 WriteWaveHeader(PLAYOUT_SAMPLE_FREQUENCY, 1, inFile);
michael@0 297 GenerateMusic(inbuf, SAMPLES);
michael@0 298 fwrite(inbuf,1,SAMPLES*sizeof(inbuf[0])*CHANNELS,inFile);
michael@0 299 FinishWaveHeader(inFile);
michael@0 300 fclose(inFile);
michael@0 301
michael@0 302 WriteWaveHeader(PLAYOUT_SAMPLE_FREQUENCY, 1, outFile);
michael@0 303 unsigned int numSamplesReadFromInput = 0;
michael@0 304 do
michael@0 305 {
michael@0 306 if(!memcpy(audioInput, inbuf, sampleLengthInBytes))
michael@0 307 {
michael@0 308 return;
michael@0 309 }
michael@0 310
michael@0 311 numSamplesReadFromInput += PLAYOUT_SAMPLE_LENGTH;
michael@0 312 inbuf += PLAYOUT_SAMPLE_LENGTH;
michael@0 313
michael@0 314 mSession->SendAudioFrame(audioInput,
michael@0 315 PLAYOUT_SAMPLE_LENGTH,
michael@0 316 PLAYOUT_SAMPLE_FREQUENCY,10);
michael@0 317
michael@0 318 PR_Sleep(PR_MillisecondsToInterval(10));
michael@0 319 mOtherSession->GetAudioFrame(audioOutput, PLAYOUT_SAMPLE_FREQUENCY,
michael@0 320 10, sampleLengthDecoded);
michael@0 321 if(sampleLengthDecoded == 0)
michael@0 322 {
michael@0 323 cerr << " Zero length Sample " << endl;
michael@0 324 }
michael@0 325
michael@0 326 int wrote_ = fwrite (audioOutput, 1 , sampleLengthInBytes, outFile);
michael@0 327 if(wrote_ != sampleLengthInBytes)
michael@0 328 {
michael@0 329 cerr << "Couldn't Write " << sampleLengthInBytes << "bytes" << endl;
michael@0 330 break;
michael@0 331 }
michael@0 332 }while(numSamplesReadFromInput < SAMPLES);
michael@0 333
michael@0 334 FinishWaveHeader(outFile);
michael@0 335 fclose(outFile);
michael@0 336 }
michael@0 337
michael@0 338 /**
michael@0 339 * Dummy Video Target for the conduit
michael@0 340 * This class acts as renderer attached to the video conuit
michael@0 341 * As of today we just verify if the frames rendered are exactly
michael@0 342 * the same as frame inserted at the first place
michael@0 343 */
michael@0 344 class DummyVideoTarget: public mozilla::VideoRenderer
michael@0 345 {
michael@0 346 public:
michael@0 347 DummyVideoTarget()
michael@0 348 {
michael@0 349 }
michael@0 350
michael@0 351 virtual ~DummyVideoTarget()
michael@0 352 {
michael@0 353 }
michael@0 354
michael@0 355
michael@0 356 void RenderVideoFrame(const unsigned char* buffer,
michael@0 357 unsigned int buffer_size,
michael@0 358 uint32_t time_stamp,
michael@0 359 int64_t render_time,
michael@0 360 const mozilla::ImageHandle& handle)
michael@0 361 {
michael@0 362 //write the frame to the file
michael@0 363 if(VerifyFrame(buffer, buffer_size) == 0)
michael@0 364 {
michael@0 365 vidStatsGlobal.numFramesRenderedSuccessfully++;
michael@0 366 } else
michael@0 367 {
michael@0 368 vidStatsGlobal.numFramesRenderedWrongly++;
michael@0 369 }
michael@0 370 }
michael@0 371
michael@0 372 void FrameSizeChange(unsigned int, unsigned int, unsigned int)
michael@0 373 {
michael@0 374 //do nothing
michael@0 375 }
michael@0 376
michael@0 377 //This is hardcoded to check if the contents of frame is COLOR
michael@0 378 // as we set while sending.
michael@0 379 int VerifyFrame(const unsigned char* buffer, unsigned int buffer_size)
michael@0 380 {
michael@0 381 int good = 0;
michael@0 382 for(int i=0; i < (int) buffer_size; i++)
michael@0 383 {
michael@0 384 if(buffer[i] == COLOR)
michael@0 385 {
michael@0 386 ++good;
michael@0 387 }
michael@0 388 else
michael@0 389 {
michael@0 390 --good;
michael@0 391 }
michael@0 392 }
michael@0 393 return 0;
michael@0 394 }
michael@0 395
michael@0 396 };
michael@0 397
michael@0 398 /**
michael@0 399 * Fake Audio and Video External Transport Class
michael@0 400 * The functions in this class will be invoked by the conduit
michael@0 401 * when it has RTP/RTCP frame to transmit.
michael@0 402 * For everty RTP/RTCP frame we receive, we pass it back
michael@0 403 * to the conduit for eventual decoding and rendering.
michael@0 404 */
michael@0 405 class FakeMediaTransport : public mozilla::TransportInterface
michael@0 406 {
michael@0 407 public:
michael@0 408 FakeMediaTransport():numPkts(0),
michael@0 409 mAudio(false),
michael@0 410 mVideo(false)
michael@0 411 {
michael@0 412 }
michael@0 413
michael@0 414 ~FakeMediaTransport()
michael@0 415 {
michael@0 416 }
michael@0 417
michael@0 418 virtual nsresult SendRtpPacket(const void* data, int len)
michael@0 419 {
michael@0 420 ++numPkts;
michael@0 421 if(mAudio)
michael@0 422 {
michael@0 423 mOtherAudioSession->ReceivedRTPPacket(data,len);
michael@0 424 } else
michael@0 425 {
michael@0 426 mOtherVideoSession->ReceivedRTPPacket(data,len);
michael@0 427 }
michael@0 428 return NS_OK;
michael@0 429 }
michael@0 430
michael@0 431 virtual nsresult SendRtcpPacket(const void* data, int len)
michael@0 432 {
michael@0 433 if(mAudio)
michael@0 434 {
michael@0 435 mOtherAudioSession->ReceivedRTCPPacket(data,len);
michael@0 436 } else
michael@0 437 {
michael@0 438 mOtherVideoSession->ReceivedRTCPPacket(data,len);
michael@0 439 }
michael@0 440 return NS_OK;
michael@0 441 }
michael@0 442
michael@0 443 //Treat this object as Audio Transport
michael@0 444 void SetAudioSession(mozilla::RefPtr<mozilla::AudioSessionConduit> aSession,
michael@0 445 mozilla::RefPtr<mozilla::AudioSessionConduit>
michael@0 446 aOtherSession)
michael@0 447 {
michael@0 448 mAudioSession = aSession;
michael@0 449 mOtherAudioSession = aOtherSession;
michael@0 450 mAudio = true;
michael@0 451 }
michael@0 452
michael@0 453 // Treat this object as Video Transport
michael@0 454 void SetVideoSession(mozilla::RefPtr<mozilla::VideoSessionConduit> aSession,
michael@0 455 mozilla::RefPtr<mozilla::VideoSessionConduit>
michael@0 456 aOtherSession)
michael@0 457 {
michael@0 458 mVideoSession = aSession;
michael@0 459 mOtherVideoSession = aOtherSession;
michael@0 460 mVideo = true;
michael@0 461 }
michael@0 462
michael@0 463 private:
michael@0 464 mozilla::RefPtr<mozilla::AudioSessionConduit> mAudioSession;
michael@0 465 mozilla::RefPtr<mozilla::VideoSessionConduit> mVideoSession;
michael@0 466 mozilla::RefPtr<mozilla::VideoSessionConduit> mOtherVideoSession;
michael@0 467 mozilla::RefPtr<mozilla::AudioSessionConduit> mOtherAudioSession;
michael@0 468 int numPkts;
michael@0 469 bool mAudio, mVideo;
michael@0 470 };
michael@0 471
michael@0 472
michael@0 473 namespace {
michael@0 474
michael@0 475 class TransportConduitTest : public ::testing::Test
michael@0 476 {
michael@0 477 public:
michael@0 478 TransportConduitTest()
michael@0 479 {
michael@0 480 //input and output file names
michael@0 481 iAudiofilename = "input.wav";
michael@0 482 oAudiofilename = "recorded.wav";
michael@0 483 }
michael@0 484
michael@0 485 ~TransportConduitTest()
michael@0 486 {
michael@0 487 }
michael@0 488
michael@0 489 //1. Dump audio samples to dummy external transport
michael@0 490 void TestDummyAudioAndTransport()
michael@0 491 {
michael@0 492 //get pointer to AudioSessionConduit
michael@0 493 int err=0;
michael@0 494 mAudioSession = mozilla::AudioSessionConduit::Create(nullptr);
michael@0 495 if( !mAudioSession )
michael@0 496 ASSERT_NE(mAudioSession, (void*)nullptr);
michael@0 497
michael@0 498 mAudioSession2 = mozilla::AudioSessionConduit::Create(nullptr);
michael@0 499 if( !mAudioSession2 )
michael@0 500 ASSERT_NE(mAudioSession2, (void*)nullptr);
michael@0 501
michael@0 502 FakeMediaTransport* xport = new FakeMediaTransport();
michael@0 503 ASSERT_NE(xport, (void*)nullptr);
michael@0 504 xport->SetAudioSession(mAudioSession, mAudioSession2);
michael@0 505 mAudioTransport = xport;
michael@0 506
michael@0 507 // attach the transport to audio-conduit
michael@0 508 err = mAudioSession->AttachTransport(mAudioTransport);
michael@0 509 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 510 err = mAudioSession2->AttachTransport(mAudioTransport);
michael@0 511 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 512
michael@0 513 //configure send and recv codecs on the audio-conduit
michael@0 514 //mozilla::AudioCodecConfig cinst1(124,"PCMU",8000,80,1,64000);
michael@0 515 mozilla::AudioCodecConfig cinst1(124,"opus",48000,960,1,64000);
michael@0 516 mozilla::AudioCodecConfig cinst2(125,"L16",16000,320,1,256000);
michael@0 517
michael@0 518
michael@0 519 std::vector<mozilla::AudioCodecConfig*> rcvCodecList;
michael@0 520 rcvCodecList.push_back(&cinst1);
michael@0 521 rcvCodecList.push_back(&cinst2);
michael@0 522
michael@0 523 err = mAudioSession->ConfigureSendMediaCodec(&cinst1);
michael@0 524 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 525 err = mAudioSession->ConfigureRecvMediaCodecs(rcvCodecList);
michael@0 526 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 527
michael@0 528 err = mAudioSession2->ConfigureSendMediaCodec(&cinst1);
michael@0 529 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 530 err = mAudioSession2->ConfigureRecvMediaCodecs(rcvCodecList);
michael@0 531 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 532
michael@0 533 //start generating samples
michael@0 534 audioTester.Init(mAudioSession,mAudioSession2, iAudiofilename,oAudiofilename);
michael@0 535 cerr << " ******************************************************** " << endl;
michael@0 536 cerr << " Generating Audio Samples " << endl;
michael@0 537 cerr << " ******************************************************** " << endl;
michael@0 538 PR_Sleep(PR_SecondsToInterval(2));
michael@0 539 audioTester.GenerateAndReadSamples();
michael@0 540 PR_Sleep(PR_SecondsToInterval(2));
michael@0 541 cerr << " ******************************************************** " << endl;
michael@0 542 cerr << " Input Audio File " << iAudiofilename << endl;
michael@0 543 cerr << " Output Audio File " << oAudiofilename << endl;
michael@0 544 cerr << " ******************************************************** " << endl;
michael@0 545 }
michael@0 546
michael@0 547 //2. Dump audio samples to dummy external transport
michael@0 548 void TestDummyVideoAndTransport()
michael@0 549 {
michael@0 550 int err = 0;
michael@0 551 //get pointer to VideoSessionConduit
michael@0 552 mVideoSession = mozilla::VideoSessionConduit::Create(nullptr);
michael@0 553 if( !mVideoSession )
michael@0 554 ASSERT_NE(mVideoSession, (void*)nullptr);
michael@0 555
michael@0 556 // This session is for other one
michael@0 557 mVideoSession2 = mozilla::VideoSessionConduit::Create(nullptr);
michael@0 558 if( !mVideoSession2 )
michael@0 559 ASSERT_NE(mVideoSession2,(void*)nullptr);
michael@0 560
michael@0 561 mVideoRenderer = new DummyVideoTarget();
michael@0 562 ASSERT_NE(mVideoRenderer, (void*)nullptr);
michael@0 563
michael@0 564 FakeMediaTransport* xport = new FakeMediaTransport();
michael@0 565 ASSERT_NE(xport, (void*)nullptr);
michael@0 566 xport->SetVideoSession(mVideoSession,mVideoSession2);
michael@0 567 mVideoTransport = xport;
michael@0 568
michael@0 569 // attach the transport and renderer to video-conduit
michael@0 570 err = mVideoSession2->AttachRenderer(mVideoRenderer);
michael@0 571 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 572 err = mVideoSession->AttachTransport(mVideoTransport);
michael@0 573 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 574 err = mVideoSession2->AttachTransport(mVideoTransport);
michael@0 575 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 576
michael@0 577 //configure send and recv codecs on theconduit
michael@0 578 mozilla::VideoCodecConfig cinst1(120, "VP8", 0);
michael@0 579 mozilla::VideoCodecConfig cinst2(124, "I420", 0);
michael@0 580
michael@0 581
michael@0 582 std::vector<mozilla::VideoCodecConfig* > rcvCodecList;
michael@0 583 rcvCodecList.push_back(&cinst1);
michael@0 584 rcvCodecList.push_back(&cinst2);
michael@0 585
michael@0 586 err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
michael@0 587 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 588
michael@0 589 err = mVideoSession2->ConfigureRecvMediaCodecs(rcvCodecList);
michael@0 590 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 591
michael@0 592 //start generating samples
michael@0 593 cerr << " *************************************************" << endl;
michael@0 594 cerr << " Starting the Video Sample Generation " << endl;
michael@0 595 cerr << " *************************************************" << endl;
michael@0 596 PR_Sleep(PR_SecondsToInterval(2));
michael@0 597 videoTester.Init(mVideoSession);
michael@0 598 videoTester.GenerateAndReadSamples();
michael@0 599 PR_Sleep(PR_SecondsToInterval(2));
michael@0 600 cerr << " **************************************************" << endl;
michael@0 601 cerr << " Done With The Testing " << endl;
michael@0 602 cerr << " VIDEO TEST STATS " << endl;
michael@0 603 cerr << " Num Raw Frames Inserted: "<<
michael@0 604 vidStatsGlobal.numRawFramesInserted << endl;
michael@0 605 cerr << " Num Frames Successfully Rendered: "<<
michael@0 606 vidStatsGlobal.numFramesRenderedSuccessfully << endl;
michael@0 607 cerr << " Num Frames Wrongly Rendered: "<<
michael@0 608 vidStatsGlobal.numFramesRenderedWrongly << endl;
michael@0 609
michael@0 610 cerr << " Done With The Testing " << endl;
michael@0 611
michael@0 612 cerr << " **************************************************" << endl;
michael@0 613 ASSERT_EQ(0, vidStatsGlobal.numFramesRenderedWrongly);
michael@0 614 ASSERT_EQ(vidStatsGlobal.numRawFramesInserted,
michael@0 615 vidStatsGlobal.numFramesRenderedSuccessfully);
michael@0 616 }
michael@0 617
michael@0 618 void TestVideoConduitCodecAPI()
michael@0 619 {
michael@0 620 int err = 0;
michael@0 621 mozilla::RefPtr<mozilla::VideoSessionConduit> mVideoSession;
michael@0 622 //get pointer to VideoSessionConduit
michael@0 623 mVideoSession = mozilla::VideoSessionConduit::Create(nullptr);
michael@0 624 if( !mVideoSession )
michael@0 625 ASSERT_NE(mVideoSession, (void*)nullptr);
michael@0 626
michael@0 627 //Test Configure Recv Codec APIS
michael@0 628 cerr << " *************************************************" << endl;
michael@0 629 cerr << " Test Receive Codec Configuration API Now " << endl;
michael@0 630 cerr << " *************************************************" << endl;
michael@0 631
michael@0 632 std::vector<mozilla::VideoCodecConfig* > rcvCodecList;
michael@0 633
michael@0 634 //Same APIs
michael@0 635 cerr << " *************************************************" << endl;
michael@0 636 cerr << " 1. Same Codec (VP8) Repeated Twice " << endl;
michael@0 637 cerr << " *************************************************" << endl;
michael@0 638
michael@0 639 mozilla::VideoCodecConfig cinst1(120, "VP8", 0);
michael@0 640 mozilla::VideoCodecConfig cinst2(120, "VP8", 0);
michael@0 641 rcvCodecList.push_back(&cinst1);
michael@0 642 rcvCodecList.push_back(&cinst2);
michael@0 643 err = mVideoSession->ConfigureRecvMediaCodecs(rcvCodecList);
michael@0 644 EXPECT_NE(err,mozilla::kMediaConduitNoError);
michael@0 645 rcvCodecList.pop_back();
michael@0 646 rcvCodecList.pop_back();
michael@0 647
michael@0 648
michael@0 649 PR_Sleep(PR_SecondsToInterval(2));
michael@0 650 cerr << " *************************************************" << endl;
michael@0 651 cerr << " 2. Codec With Invalid Payload Names " << endl;
michael@0 652 cerr << " *************************************************" << endl;
michael@0 653 cerr << " Setting payload 1 with name: I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676" << endl;
michael@0 654 cerr << " Setting payload 2 with name of zero length" << endl;
michael@0 655
michael@0 656 mozilla::VideoCodecConfig cinst3(124, "I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676", 0);
michael@0 657 mozilla::VideoCodecConfig cinst4(124, "", 0);
michael@0 658
michael@0 659 rcvCodecList.push_back(&cinst3);
michael@0 660 rcvCodecList.push_back(&cinst4);
michael@0 661
michael@0 662 err = mVideoSession->ConfigureRecvMediaCodecs(rcvCodecList);
michael@0 663 EXPECT_TRUE(err != mozilla::kMediaConduitNoError);
michael@0 664 rcvCodecList.pop_back();
michael@0 665 rcvCodecList.pop_back();
michael@0 666
michael@0 667
michael@0 668 PR_Sleep(PR_SecondsToInterval(2));
michael@0 669 cerr << " *************************************************" << endl;
michael@0 670 cerr << " 3. Null Codec Parameter " << endl;
michael@0 671 cerr << " *************************************************" << endl;
michael@0 672
michael@0 673 rcvCodecList.push_back(0);
michael@0 674
michael@0 675 err = mVideoSession->ConfigureRecvMediaCodecs(rcvCodecList);
michael@0 676 EXPECT_TRUE(err != mozilla::kMediaConduitNoError);
michael@0 677 rcvCodecList.pop_back();
michael@0 678
michael@0 679 cerr << " *************************************************" << endl;
michael@0 680 cerr << " Test Send Codec Configuration API Now " << endl;
michael@0 681 cerr << " *************************************************" << endl;
michael@0 682
michael@0 683 cerr << " *************************************************" << endl;
michael@0 684 cerr << " 1. Same Codec (VP8) Repeated Twice " << endl;
michael@0 685 cerr << " *************************************************" << endl;
michael@0 686
michael@0 687
michael@0 688 err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
michael@0 689 EXPECT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 690 err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
michael@0 691 EXPECT_EQ(mozilla::kMediaConduitCodecInUse, err);
michael@0 692
michael@0 693
michael@0 694 cerr << " *************************************************" << endl;
michael@0 695 cerr << " 2. Codec With Invalid Payload Names " << endl;
michael@0 696 cerr << " *************************************************" << endl;
michael@0 697 cerr << " Setting payload with name: I4201234tttttthhhyyyy89087987y76t567r7756765rr6u6676" << endl;
michael@0 698
michael@0 699 err = mVideoSession->ConfigureSendMediaCodec(&cinst3);
michael@0 700 EXPECT_TRUE(err != mozilla::kMediaConduitNoError);
michael@0 701
michael@0 702 cerr << " *************************************************" << endl;
michael@0 703 cerr << " 3. Null Codec Parameter " << endl;
michael@0 704 cerr << " *************************************************" << endl;
michael@0 705
michael@0 706 err = mVideoSession->ConfigureSendMediaCodec(nullptr);
michael@0 707 EXPECT_TRUE(err != mozilla::kMediaConduitNoError);
michael@0 708
michael@0 709 }
michael@0 710
michael@0 711 void DumpMaxFs(int orig_width, int orig_height, int max_fs,
michael@0 712 int new_width, int new_height)
michael@0 713 {
michael@0 714 cerr << "Applying max_fs=" << max_fs << " to input resolution " <<
michael@0 715 orig_width << "x" << orig_height << endl;
michael@0 716 cerr << "New resolution: " << new_width << "x" << new_height << endl;
michael@0 717 cerr << endl;
michael@0 718 }
michael@0 719
michael@0 720 // Calculate new resolution for sending video by applying max-fs constraint.
michael@0 721 void GetVideoResolutionWithMaxFs(int orig_width, int orig_height, int max_fs,
michael@0 722 int *new_width, int *new_height)
michael@0 723 {
michael@0 724 int err = 0;
michael@0 725
michael@0 726 // Get pointer to VideoSessionConduit.
michael@0 727 mVideoSession = mozilla::VideoSessionConduit::Create(nullptr);
michael@0 728 if( !mVideoSession )
michael@0 729 ASSERT_NE(mVideoSession, (void*)nullptr);
michael@0 730
michael@0 731 // Configure send codecs on the conduit.
michael@0 732 mozilla::VideoCodecConfig cinst1(120, "VP8", 0, max_fs, 0);
michael@0 733
michael@0 734 err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
michael@0 735 ASSERT_EQ(mozilla::kMediaConduitNoError, err);
michael@0 736
michael@0 737 // Send one frame.
michael@0 738 MOZ_ASSERT(!(orig_width & 1));
michael@0 739 MOZ_ASSERT(!(orig_height & 1));
michael@0 740 int len = ((orig_width * orig_height) * 3 / 2);
michael@0 741 uint8_t* frame = (uint8_t*) PR_MALLOC(len);
michael@0 742
michael@0 743 memset(frame, COLOR, len);
michael@0 744 mVideoSession->SendVideoFrame((unsigned char*)frame,
michael@0 745 len,
michael@0 746 orig_width,
michael@0 747 orig_height,
michael@0 748 mozilla::kVideoI420,
michael@0 749 0);
michael@0 750 PR_Free(frame);
michael@0 751
michael@0 752 // Get the new resolution as adjusted by the max-fs constraint.
michael@0 753 *new_width = mVideoSession->SendingWidth();
michael@0 754 *new_height = mVideoSession->SendingHeight();
michael@0 755 }
michael@0 756
michael@0 757 void TestVideoConduitMaxFs()
michael@0 758 {
michael@0 759 int orig_width, orig_height, width, height, max_fs;
michael@0 760
michael@0 761 // No limitation.
michael@0 762 cerr << "Test no max-fs limition" << endl;
michael@0 763 orig_width = 640;
michael@0 764 orig_height = 480;
michael@0 765 max_fs = 0;
michael@0 766 GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
michael@0 767 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 768 ASSERT_EQ(width, 640);
michael@0 769 ASSERT_EQ(height, 480);
michael@0 770
michael@0 771 // VGA to QVGA.
michael@0 772 cerr << "Test resizing from VGA to QVGA" << endl;
michael@0 773 orig_width = 640;
michael@0 774 orig_height = 480;
michael@0 775 max_fs = 300;
michael@0 776 GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
michael@0 777 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 778 ASSERT_EQ(width, 320);
michael@0 779 ASSERT_EQ(height, 240);
michael@0 780
michael@0 781 // Extreme input resolution.
michael@0 782 cerr << "Test extreme input resolution" << endl;
michael@0 783 orig_width = 3072;
michael@0 784 orig_height = 100;
michael@0 785 max_fs = 300;
michael@0 786 GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
michael@0 787 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 788 ASSERT_EQ(width, 768);
michael@0 789 ASSERT_EQ(height, 26);
michael@0 790
michael@0 791 // Small max-fs.
michael@0 792 cerr << "Test small max-fs (case 1)" << endl;
michael@0 793 orig_width = 8;
michael@0 794 orig_height = 32;
michael@0 795 max_fs = 1;
michael@0 796 GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
michael@0 797 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 798 ASSERT_EQ(width, 4);
michael@0 799 ASSERT_EQ(height, 16);
michael@0 800
michael@0 801 // Small max-fs.
michael@0 802 cerr << "Test small max-fs (case 2)" << endl;
michael@0 803 orig_width = 4;
michael@0 804 orig_height = 50;
michael@0 805 max_fs = 1;
michael@0 806 GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
michael@0 807 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 808 ASSERT_EQ(width, 2);
michael@0 809 ASSERT_EQ(height, 16);
michael@0 810
michael@0 811 // Small max-fs.
michael@0 812 cerr << "Test small max-fs (case 3)" << endl;
michael@0 813 orig_width = 872;
michael@0 814 orig_height = 136;
michael@0 815 max_fs = 3;
michael@0 816 GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
michael@0 817 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 818 ASSERT_EQ(width, 48);
michael@0 819 ASSERT_EQ(height, 8);
michael@0 820
michael@0 821 // Small max-fs.
michael@0 822 cerr << "Test small max-fs (case 4)" << endl;
michael@0 823 orig_width = 160;
michael@0 824 orig_height = 8;
michael@0 825 max_fs = 5;
michael@0 826 GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
michael@0 827 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 828 ASSERT_EQ(width, 80);
michael@0 829 ASSERT_EQ(height, 4);
michael@0 830
michael@0 831 // Extremely small width and height(see bug 919979).
michael@0 832 cerr << "Test with extremely small width and height" << endl;
michael@0 833 orig_width = 2;
michael@0 834 orig_height = 2;
michael@0 835 max_fs = 5;
michael@0 836 GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs, &width, &height);
michael@0 837 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 838 ASSERT_EQ(width, 2);
michael@0 839 ASSERT_EQ(height, 2);
michael@0 840
michael@0 841 // Random values.
michael@0 842 cerr << "Test with random values" << endl;
michael@0 843 for (int i = 0; i < 30; i++) {
michael@0 844 cerr << ".";
michael@0 845 max_fs = rand() % 1000;
michael@0 846 orig_width = ((rand() % 2000) & ~1) + 2;
michael@0 847 orig_height = ((rand() % 2000) & ~1) + 2;
michael@0 848
michael@0 849 GetVideoResolutionWithMaxFs(orig_width, orig_height, max_fs,
michael@0 850 &width, &height);
michael@0 851 if (max_fs > 0 &&
michael@0 852 ceil(width / 16.) * ceil(height / 16.) > max_fs) {
michael@0 853 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 854 ADD_FAILURE();
michael@0 855 }
michael@0 856 if ((width & 1) || (height & 1)) {
michael@0 857 DumpMaxFs(orig_width, orig_height, max_fs, width, height);
michael@0 858 ADD_FAILURE();
michael@0 859 }
michael@0 860 }
michael@0 861 cerr << endl;
michael@0 862 }
michael@0 863
michael@0 864 private:
michael@0 865 //Audio Conduit Test Objects
michael@0 866 mozilla::RefPtr<mozilla::AudioSessionConduit> mAudioSession;
michael@0 867 mozilla::RefPtr<mozilla::AudioSessionConduit> mAudioSession2;
michael@0 868 mozilla::RefPtr<mozilla::TransportInterface> mAudioTransport;
michael@0 869 AudioSendAndReceive audioTester;
michael@0 870
michael@0 871 //Video Conduit Test Objects
michael@0 872 mozilla::RefPtr<mozilla::VideoSessionConduit> mVideoSession;
michael@0 873 mozilla::RefPtr<mozilla::VideoSessionConduit> mVideoSession2;
michael@0 874 mozilla::RefPtr<mozilla::VideoRenderer> mVideoRenderer;
michael@0 875 mozilla::RefPtr<mozilla::TransportInterface> mVideoTransport;
michael@0 876 VideoSendAndReceive videoTester;
michael@0 877
michael@0 878 std::string fileToPlay;
michael@0 879 std::string fileToRecord;
michael@0 880 std::string iAudiofilename;
michael@0 881 std::string oAudiofilename;
michael@0 882 };
michael@0 883
michael@0 884
michael@0 885 // Test 1: Test Dummy External Xport
michael@0 886 TEST_F(TransportConduitTest, TestDummyAudioWithTransport) {
michael@0 887 TestDummyAudioAndTransport();
michael@0 888 }
michael@0 889
michael@0 890 // Test 2: Test Dummy External Xport
michael@0 891 TEST_F(TransportConduitTest, TestDummyVideoWithTransport) {
michael@0 892 TestDummyVideoAndTransport();
michael@0 893 }
michael@0 894
michael@0 895 TEST_F(TransportConduitTest, TestVideoConduitCodecAPI) {
michael@0 896 TestVideoConduitCodecAPI();
michael@0 897 }
michael@0 898
michael@0 899 TEST_F(TransportConduitTest, TestVideoConduitMaxFs) {
michael@0 900 TestVideoConduitMaxFs();
michael@0 901 }
michael@0 902
michael@0 903 } // end namespace
michael@0 904
michael@0 905 int main(int argc, char **argv)
michael@0 906 {
michael@0 907 // This test can cause intermittent oranges on the builders
michael@0 908 CHECK_ENVIRONMENT_FLAG("MOZ_WEBRTC_MEDIACONDUIT_TESTS")
michael@0 909
michael@0 910 test_utils = new MtransportTestUtils();
michael@0 911 ::testing::InitGoogleTest(&argc, argv);
michael@0 912 int rv = RUN_ALL_TESTS();
michael@0 913 delete test_utils;
michael@0 914 return rv;
michael@0 915 }
michael@0 916
michael@0 917

mercurial