| /* |
| * 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. |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <time.h> |
| #include <cassert> |
| #if defined(_WIN32) |
| #include <conio.h> |
| #endif |
| |
| #include "voe_unit_test.h" |
| |
| #include "../../source/voice_engine_defines.h" |
| #include "thread_wrapper.h" |
| |
| using namespace webrtc; |
| |
| namespace voetest { |
| |
| #define CHECK(expr) \ |
| if (expr) \ |
| { \ |
| printf("Error at line: %i, %s \n", __LINE__, #expr); \ |
| printf("Error code: %i \n", base->LastError()); \ |
| PAUSE \ |
| return -1; \ |
| } |
| |
| extern char* GetFilename(char* filename); |
| extern const char* GetFilename(const char* filename); |
| extern int GetResource(char* resource, char* dest, int destLen); |
| extern char* GetResource(char* resource); |
| extern const char* GetResource(const char* resource); |
| |
| const char* VoEUnitTest::_key = "====YUtFWRAAAAADBtIHgAAAAAEAAAAcAAAAAQBHU0dsb2" |
| "JhbCBJUCBTb3VuZAAC\nAAAAIwAAAExpY2Vuc2VkIHRvIE5vcnRlbCBOZXR3cm9rcwAAAAAxA" |
| "AAAZxZ7/u0M\niFYyTwSwko5Uutf7mh8S0O4rYZYTFidbzQeuGonuL17F/2oD/2pfDp3jL4Rf" |
| "3z/A\nnlJsEJgEtASkDNFuwLILjGY0pzjjAYQp3pCl6z6k2MtE06AirdjGLYCjENpq/opX\nO" |
| "rs3sIuwdYK5va/aFcsjBDmlsGCUM48RDYG9s23bIHYafXUC4ofOaubbZPWiPTmL\nEVJ8WH4F" |
| "9pgNjALc14oJXfON7r/3\n=EsLx"; |
| |
| // ---------------------------------------------------------------------------- |
| // >>> R E A D M E F I R S T <<< |
| // ---------------------------------------------------------------------------- |
| |
| // 1) The user must ensure that the following codecs are included in VoE: |
| // |
| // - L16 |
| // - G.729 |
| // - G.722.1C |
| |
| // 2) It is also possible to modify the simulation time for each individual test |
| // |
| const int dTBetweenEachTest = 4000; |
| |
| // ---------------------------------------------------------------------------- |
| // Encrypt |
| // ---------------------------------------------------------------------------- |
| |
| void VoEUnitTest::encrypt(int channel_no, unsigned char * in_data, |
| unsigned char * out_data, int bytes_in, |
| int * bytes_out) { |
| int i; |
| |
| if (!_extOnOff) { |
| // no stereo emulation <=> pure bypass |
| for (i = 0; i < bytes_in; i++) |
| out_data[i] = in_data[i]; |
| *bytes_out = bytes_in; |
| } else if (_extOnOff && (_extBitsPerSample == 16)) { |
| // stereo emulation (sample based, 2 bytes per sample) |
| |
| const int nBytesPayload = bytes_in - 12; |
| |
| // RTP header (first 12 bytes) |
| memcpy(out_data, in_data, 12); |
| |
| // skip RTP header |
| short* ptrIn = (short*) &in_data[12]; |
| short* ptrOut = (short*) &out_data[12]; |
| |
| // network byte order |
| for (i = 0; i < nBytesPayload / 2; i++) { |
| // produce two output samples for each input sample |
| *ptrOut++ = *ptrIn; // left sample |
| *ptrOut++ = *ptrIn; // right sample |
| ptrIn++; |
| } |
| |
| *bytes_out = 12 + 2 * nBytesPayload; |
| } else if (_extOnOff && (_extBitsPerSample == 8)) { |
| // stereo emulation (sample based, 1 bytes per sample) |
| |
| const int nBytesPayload = bytes_in - 12; |
| |
| // RTP header (first 12 bytes) |
| memcpy(out_data, in_data, 12); |
| |
| // skip RTP header |
| unsigned char* ptrIn = (unsigned char*) &in_data[12]; |
| unsigned char* ptrOut = (unsigned char*) &out_data[12]; |
| |
| // network byte order |
| for (i = 0; i < nBytesPayload; i++) { |
| // produce two output samples for each input sample |
| *ptrOut++ = *ptrIn; // left sample |
| *ptrOut++ = *ptrIn; // right sample |
| ptrIn++; |
| } |
| |
| *bytes_out = 12 + 2 * nBytesPayload; |
| } else if (_extOnOff && (_extBitsPerSample == -1)) { |
| // stereo emulation (frame based) |
| |
| const int nBytesPayload = bytes_in - 12; |
| |
| // RTP header (first 12 bytes) |
| memcpy(out_data, in_data, 12); |
| |
| // skip RTP header |
| unsigned char* ptrIn = (unsigned char*) &in_data[12]; |
| unsigned char* ptrOut = (unsigned char*) &out_data[12]; |
| |
| // left channel |
| for (i = 0; i < nBytesPayload; i++) { |
| *ptrOut++ = *ptrIn++; |
| } |
| |
| ptrIn = (unsigned char*) &in_data[12]; |
| |
| // right channel |
| for (i = 0; i < nBytesPayload; i++) { |
| *ptrOut++ = *ptrIn++; |
| } |
| |
| *bytes_out = 12 + 2 * nBytesPayload; |
| } |
| } |
| |
| void VoEUnitTest::decrypt(int channel_no, unsigned char * in_data, |
| unsigned char * out_data, int bytes_in, |
| int * bytes_out) { |
| int i; |
| for (i = 0; i < bytes_in; i++) |
| out_data[i] = in_data[i]; |
| *bytes_out = bytes_in; |
| } |
| |
| void VoEUnitTest::encrypt_rtcp(int channel_no, unsigned char * in_data, |
| unsigned char * out_data, int bytes_in, |
| int * bytes_out) { |
| int i; |
| for (i = 0; i < bytes_in; i++) |
| out_data[i] = in_data[i]; |
| *bytes_out = bytes_in; |
| } |
| |
| void VoEUnitTest::decrypt_rtcp(int channel_no, unsigned char * in_data, |
| unsigned char * out_data, int bytes_in, |
| int * bytes_out) { |
| int i; |
| for (i = 0; i < bytes_in; i++) |
| out_data[i] = in_data[i]; |
| *bytes_out = bytes_in; |
| } |
| |
| void VoEUnitTest::SetStereoExternalEncryption(int channel, bool onOff, |
| int bitsPerSample) { |
| _extOnOff = onOff; |
| _extChannel = channel; |
| _extBitsPerSample = bitsPerSample; |
| } |
| |
| // VoEVEMediaProcess |
| MyMedia mpobj; |
| |
| // ---------------------------------------------------------------------------- |
| // VoEUnitTest |
| // ---------------------------------------------------------------------------- |
| |
| VoEUnitTest::VoEUnitTest(VoETestManager& mgr) : |
| _mgr(mgr), _extOnOff(false), _extBitsPerSample(-1) { |
| for (int i = 0; i < 32; i++) { |
| _listening[i] = false; |
| _playing[i] = false; |
| _sending[i] = false; |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // DoTest |
| // ---------------------------------------------------------------------------- |
| |
| int VoEUnitTest::DoTest() { |
| int test(-1); |
| int ret(0); |
| while ((test != 0) && (ret != -1)) { |
| test = MenuSelection(); |
| switch (test) { |
| case 0: |
| // Quit stress test |
| break; |
| case 1: |
| ret = MixerTest(); |
| break; |
| case 2: |
| ret = MixerTest(); |
| break; |
| default: |
| // Should not be possible |
| printf("Invalid selection! (Test code error)\n"); |
| assert(false); |
| } // switch |
| } // while |
| |
| return ret; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // MenuSelection |
| // ---------------------------------------------------------------------------- |
| |
| int VoEUnitTest::MenuSelection() { |
| printf("------------------------------------------------\n"); |
| printf("Select unit test\n\n"); |
| printf(" (0) Quit\n"); |
| printf(" (1) All\n"); |
| printf("- - - - - - - - - - - - - - - - - - - - - - - - \n"); |
| printf(" (2) Mixer\n"); |
| |
| const int maxMenuSelection = 2; |
| int selection(-1); |
| |
| while ((selection < 0) || (selection > maxMenuSelection)) { |
| printf("\n: "); |
| int retval = scanf("%d", &selection); |
| if ((retval != 1) || (selection < 0) || (selection > maxMenuSelection)) { |
| printf("Invalid selection!\n"); |
| } |
| } |
| |
| return selection; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // StartMedia |
| // ---------------------------------------------------------------------------- |
| |
| int VoEUnitTest::StartMedia(int channel, int rtpPort, bool listen, bool playout, |
| bool send, bool fileAsMic, bool localFile) { |
| VoEBase* base = _mgr.BasePtr(); |
| VoEFile* file = _mgr.FilePtr(); |
| |
| _listening[channel] = false; |
| _playing[channel] = false; |
| _sending[channel] = false; |
| |
| CHECK(base->SetLocalReceiver(channel, rtpPort)); |
| CHECK(base->SetSendDestination(channel, rtpPort, "127.0.0.1")); |
| if (listen) { |
| _listening[channel] = true; |
| CHECK(base->StartReceive(channel)); |
| } |
| if (playout) { |
| _playing[channel] = true; |
| CHECK(base->StartPlayout(channel)); |
| } |
| if (send) { |
| _sending[channel] = true; |
| CHECK(base->StartSend(channel)); |
| } |
| if (fileAsMic) { |
| // play mic as file, mix with microphone to ensure that SWB can be |
| //tested as well |
| const bool mixWithMic(true); |
| CHECK(file->StartPlayingFileAsMicrophone(channel, _mgr.AudioFilename(), |
| true, mixWithMic)); |
| } |
| if (localFile) { |
| CHECK(file->StartPlayingFileLocally(channel, |
| GetResource("audio_short16.pcm"), |
| false, |
| kFileFormatPcm16kHzFile)); |
| } |
| |
| return 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // StopMedia |
| // ---------------------------------------------------------------------------- |
| |
| int VoEUnitTest::StopMedia(int channel) { |
| VoEBase* base = _mgr.BasePtr(); |
| VoEFile* file = _mgr.FilePtr(); |
| |
| if (file->IsPlayingFileAsMicrophone(channel)) { |
| CHECK(file->StopPlayingFileAsMicrophone(channel)); |
| } |
| if (file->IsPlayingFileLocally(channel)) { |
| CHECK(file->StopPlayingFileLocally(channel)); |
| } |
| if (_listening[channel]) { |
| _listening[channel] = false; |
| CHECK(base->StopReceive(channel)); |
| } |
| if (_playing[channel]) { |
| _playing[channel] = false; |
| CHECK(base->StopPlayout(channel)); |
| } |
| if (_sending[channel]) { |
| _sending[channel] = false; |
| CHECK(base->StopSend(channel)); |
| } |
| |
| return 0; |
| } |
| |
| void VoEUnitTest::Sleep(unsigned int timeMillisec, bool addMarker) { |
| if (addMarker) { |
| float dtSec = (float) ((float) timeMillisec / 1000.0); |
| printf("[dT=%.1f]", dtSec); |
| fflush(NULL); |
| } |
| ::Sleep(timeMillisec); |
| } |
| |
| void VoEUnitTest::Wait() { |
| #if defined(_WIN32) |
| printf("\npress any key..."); fflush(NULL); |
| _getch(); |
| #endif |
| } |
| |
| void VoEUnitTest::Test(const char* msg) { |
| printf("%s", msg); |
| fflush(NULL); |
| printf("\n"); |
| fflush(NULL); |
| } |
| |
| int VoEUnitTest::MixerTest() { |
| // Set up test parameters first |
| // |
| const int testTime(dTBetweenEachTest); |
| |
| printf("\n\n================================================\n"); |
| printf(" Mixer Unit Test\n"); |
| printf("================================================\n\n"); |
| |
| // Get sub-API pointers |
| // |
| VoEBase* base = _mgr.BasePtr(); |
| VoECodec* codec = _mgr.CodecPtr(); |
| VoEFile* file = _mgr.FilePtr(); |
| VoEVolumeControl* volume = _mgr.VolumeControlPtr(); |
| VoEEncryption* encrypt = _mgr.EncryptionPtr(); |
| VoEDtmf* dtmf = _mgr.DtmfPtr(); |
| VoEExternalMedia* xmedia = _mgr.ExternalMediaPtr(); |
| |
| // Set trace |
| // |
| VoiceEngine::SetTraceFile(GetFilename("UnitTest_Mixer_trace.txt")); |
| VoiceEngine::SetTraceFilter(kTraceStateInfo | kTraceWarning | kTraceError | |
| kTraceCritical | kTraceApiCall | kTraceMemory | |
| kTraceInfo); |
| |
| // Init |
| // |
| CHECK(base->Init()); |
| |
| // 8 kHz |
| // CodecInst l16_8 = { 123, "L16", 8000, 160, 1, 128000 }; |
| CodecInst pcmu_8 = { 0, "pcmu", 8000, 160, 1, 64000 }; |
| // CodecInst g729_8 = { 18, "g729", 8000, 160, 1, 8000 }; |
| |
| // 16 kHz |
| CodecInst ipcmwb_16 = { 97, "ipcmwb", 16000, 320, 1, 80000 }; |
| CodecInst l16_16 = { 124, "L16", 16000, 320, 1, 256000 }; |
| |
| // 32 kHz |
| CodecInst l16_32 = { 125, "L16", 32000, 320, 1, 512000 }; |
| CodecInst g722_1c_32 = { 126, "G7221", 32000, 640, 1, 32000 };// 20ms@32kHz |
| |
| // ------------------------ |
| // Verify mixing frequency |
| // ------------------------ |
| |
| base->CreateChannel(); |
| |
| Test(">> Verify correct mixing frequency:\n"); |
| |
| Test("(ch 0) Sending file at 8kHz <=> mixing at 8kHz..."); |
| CHECK(StartMedia(0, 12345, true, true, true, true, false)); |
| Sleep(testTime); |
| |
| Test("(ch 0) Sending file at 16kHz <=> mixing at 16kHz..."); |
| CHECK(codec->SetSendCodec(0, ipcmwb_16)); |
| Sleep(testTime); |
| |
| Test("(ch 0) Sending speech at 32kHz <=> mixing at 32Hz..."); |
| CHECK(codec->SetSendCodec(0, l16_32)); |
| Sleep(testTime); |
| |
| Test("(ch 0) Sending file at 8kHz <=> mixing at 8kHz..."); |
| CHECK(codec->SetSendCodec(0, pcmu_8)); |
| Sleep(testTime); |
| |
| Test("(ch 0) Playing 16kHz file locally <=> mixing at 16kHz..."); |
| CHECK(file->StartPlayingFileLocally(0, GetResource("audio_long16.pcm"), |
| false, kFileFormatPcm16kHzFile)); |
| Sleep(testTime); |
| CHECK(file->StopPlayingFileLocally(0)); |
| |
| base->CreateChannel(); |
| |
| Test("(ch 0) Sending file at 8kHz <=> mixing at 8kHz..."); |
| CHECK(codec->SetSendCodec(0, pcmu_8)); |
| Sleep(testTime); |
| |
| Test("(ch 0) Sending speech at 32kHz <=> mixing at 32Hz..."); |
| CHECK(codec->SetSendCodec(0, l16_32)); |
| Sleep(testTime); |
| |
| Test("(ch 1) Playing 16kHz file locally <=> mixing at 32kHz..."); |
| CHECK(StartMedia(1, 54321, false, true, false, false, true)); |
| Sleep(testTime); |
| |
| CHECK(StopMedia(1)); |
| CHECK(StopMedia(0)); |
| |
| base->DeleteChannel(1); |
| base->DeleteChannel(0); |
| ANL(); |
| |
| // ------------------------- |
| // Verify stereo mode mixing |
| // ------------------------- |
| |
| base->CreateChannel(); |
| base->CreateChannel(); |
| |
| // SetOutputVolumePan |
| // |
| // Ensure that all cases sound OK and that the mixer changes state between |
| // mono and stereo as it should. A debugger is required to trace the state |
| // transitions. |
| |
| Test(">> Verify correct mixing in stereo using SetOutputVolumePan():\n"); |
| |
| Test("(ch 0) Playing 16kHz file locally <=> mixing in mono @ 16kHz..."); |
| CHECK(StartMedia(0, 12345, false, true, false, false, true)); |
| Sleep(testTime); |
| Test("Panning volume to the left <=> mixing in stereo @ 16kHz..."); |
| CHECK(volume->SetOutputVolumePan(-1, 1.0, 0.0)); |
| Sleep(testTime); |
| Test("Panning volume to the right <=> mixing in stereo @ 16kHz..."); |
| CHECK(volume->SetOutputVolumePan(-1, 0.0, 1.0)); |
| Sleep(testTime); |
| Test("Back to center volume again <=> mixing in mono @ 16kHz..."); |
| CHECK(volume->SetOutputVolumePan(-1, 1.0, 1.0)); |
| Sleep(testTime); |
| Test("(ch 1) Playing 16kHz file locally <=> mixing in mono @ 16kHz..."); |
| CHECK(StartMedia(1, 54321, false, true, false, false, true)); |
| Sleep(testTime); |
| Test("Panning volume to the left <=> mixing in stereo @ 16kHz..."); |
| CHECK(volume->SetOutputVolumePan(-1, 1.0, 0.0)); |
| Sleep(testTime); |
| Test("Back to center volume again <=> mixing in mono @ 16kHz..."); |
| CHECK(volume->SetOutputVolumePan(-1, 1.0, 1.0)); |
| Sleep(testTime); |
| Test("(ch 1) Stopped playing file <=> mixing in mono @ 16kHz..."); |
| CHECK(StopMedia(1)); |
| Sleep(testTime); |
| CHECK(StopMedia(0)); |
| Test("(ch 0) Sending file at 8kHz <=> mixing at 8kHz..."); |
| CHECK(StartMedia(0, 12345, true, true, true, true, false)); |
| Sleep(testTime); |
| Test("(ch 0) Sending speech at 32kHz <=> mixing at 32kHz..."); |
| CHECK(codec->SetSendCodec(0, l16_32)); |
| Sleep(testTime); |
| Test("Panning volume to the right <=> mixing in stereo @ 32kHz..."); |
| CHECK(volume->SetOutputVolumePan(-1, 0.0, 1.0)); |
| Sleep(testTime); |
| Test("Back to center volume again <=> mixing in mono @ 32kHz..."); |
| CHECK(volume->SetOutputVolumePan(-1, 1.0, 1.0)); |
| Sleep(testTime); |
| CHECK(StopMedia(0)); |
| ANL(); |
| |
| base->DeleteChannel(0); |
| base->DeleteChannel(1); |
| |
| // SetChannelOutputVolumePan |
| // |
| // Ensure that all cases sound OK and that the mixer changes state between |
| // mono and stereo as it should. A debugger is required to trace the state |
| // transitions. |
| |
| base->CreateChannel(); |
| base->CreateChannel(); |
| |
| Test(">> Verify correct mixing in stereo using" |
| " SetChannelOutputVolumePan():\n"); |
| |
| Test("(ch 0) Playing 16kHz file locally <=> mixing in mono @ 16kHz..."); |
| CHECK(StartMedia(0, 12345, false, true, false, false, true)); |
| Sleep(testTime); |
| Test("(ch 0) Panning channel volume to the left <=> mixing in stereo @ " |
| "16kHz..."); |
| CHECK(volume->SetOutputVolumePan(0, 1.0, 0.0)); |
| Sleep(testTime); |
| Test("(ch 0) Panning channel volume to the right <=> mixing in stereo" |
| " @ 16kHz..."); |
| CHECK(volume->SetOutputVolumePan(0, 0.0, 1.0)); |
| Sleep(testTime); |
| Test("(ch 0) Back to center volume again <=> mixing in mono @" |
| " 16kHz..."); |
| CHECK(volume->SetOutputVolumePan(0, 1.0, 1.0)); |
| Sleep(testTime); |
| Test("(ch 1) Playing 16kHz file locally <=> mixing in mono @ 16kHz..."); |
| CHECK(StartMedia(1, 54321, false, true, false, false, true)); |
| Sleep(testTime); |
| Test("(ch 1) Panning channel volume to the left <=> mixing in stereo " |
| "@ 16kHz..."); |
| CHECK(volume->SetOutputVolumePan(1, 1.0, 0.0)); |
| Sleep(testTime); |
| Test("(ch 1) Back to center volume again <=> mixing in mono @ 16kHz..."); |
| CHECK(volume->SetOutputVolumePan(1, 1.0, 1.0)); |
| Sleep(testTime); |
| Test("(ch 1) Stopped playing file <=> mixing in mono @ 16kHz..."); |
| CHECK(StopMedia(1)); |
| Sleep(testTime); |
| CHECK(StopMedia(0)); |
| ANL(); |
| |
| base->DeleteChannel(0); |
| base->DeleteChannel(1); |
| |
| // Emulate stereo-encoding using Encryption |
| // |
| // Modify the transmitted RTP stream by using external encryption. |
| // Supports frame based and sample based "stereo-encoding schemes". |
| |
| base->CreateChannel(); |
| |
| Test(">> Verify correct mixing in stereo using emulated stereo input:\n"); |
| |
| // enable external encryption |
| CHECK(encrypt->RegisterExternalEncryption(0, *this)); |
| Test("(ch 0) External Encryption is now enabled:"); |
| |
| Test("(ch 0) Sending file at 8kHz <=> mixing in mono @ 8kHz..."); |
| CHECK(StartMedia(0, 12345, true, true, true, true, false)); |
| Sleep(testTime); |
| |
| // switch to 16kHz (L16) sending codec |
| CHECK(codec->SetSendCodec(0, l16_16)); |
| Test("(ch 0) Sending file at 16kHz (L16) <=> mixing in mono @ 16kHz..."); |
| Sleep(testTime); |
| |
| // register L16 as 2-channel codec on receiving side => |
| // should sound bad since RTP module splits all received packets in half |
| // (sample based) |
| CHECK(base->StopPlayout(0)); |
| CHECK(base->StopReceive(0)); |
| l16_16.channels = 2; |
| CHECK(codec->SetRecPayloadType(0, l16_16)); |
| CHECK(base->StartReceive(0)); |
| CHECK(base->StartPlayout(0)); |
| Test("(ch 0) 16kHz L16 is now registered as 2-channel codec on RX side => " |
| "should sound bad..."); |
| Sleep(testTime); |
| |
| // emulate sample-based stereo encoding |
| Test("(ch 0) Emulate sample-based stereo encoding on sending side => " |
| "should sound OK..."); |
| SetStereoExternalEncryption(0, true, 16); |
| Sleep(testTime); |
| Test("(ch 0) Stop emulating sample-based stereo encoding on sending side =>" |
| " should sound bad..."); |
| SetStereoExternalEncryption(0, false, 16); |
| Sleep(testTime); |
| Test("(ch 0) Emulate sample-based stereo encoding on sending side => " |
| "should sound OK..."); |
| SetStereoExternalEncryption(0, true, 16); |
| Sleep(testTime); |
| |
| // switch to 32kHz (L16) sending codec and disable stereo encoding |
| CHECK(codec->SetSendCodec(0, l16_32)); |
| SetStereoExternalEncryption(0, false, 16); |
| Test("(ch 0) Sending file and spech at 32kHz (L16) <=> mixing in mono @ " |
| "32kHz..."); |
| Sleep(testTime); |
| |
| // register L16 32kHz as 2-channel codec on receiving side |
| CHECK(base->StopPlayout(0)); |
| CHECK(base->StopReceive(0)); |
| l16_32.channels = 2; |
| CHECK(codec->SetRecPayloadType(0, l16_32)); |
| CHECK(base->StartReceive(0)); |
| CHECK(base->StartPlayout(0)); |
| Test("(ch 0) 32kHz L16 is now registered as 2-channel codec on RX side =>" |
| " should sound bad..."); |
| Sleep(testTime); |
| |
| // emulate sample-based stereo encoding |
| Test("(ch 0) Emulate sample-based stereo encoding on sending side =>" |
| " should sound OK..."); |
| SetStereoExternalEncryption(0, true, 16); |
| Sleep(testTime); |
| |
| StopMedia(0); |
| l16_32.channels = 1; |
| |
| // disable external encryption |
| CHECK(encrypt->DeRegisterExternalEncryption(0)); |
| ANL(); |
| |
| base->DeleteChannel(0); |
| |
| // ------------------ |
| // Verify put-on-hold |
| // ------------------ |
| |
| base->CreateChannel(); |
| base->CreateChannel(); |
| |
| Test(">> Verify put-on-hold functionality:\n"); |
| |
| Test("(ch 0) Sending at 8kHz..."); |
| CHECK(StartMedia(0, 12345, true, true, true, true, false)); |
| Sleep(testTime); |
| |
| CHECK(base->SetOnHoldStatus(0, true, kHoldPlayOnly)); |
| Test("(ch 0) Playout is now on hold..."); |
| Sleep(testTime); |
| CHECK(base->SetOnHoldStatus(0, false, kHoldPlayOnly)); |
| Test("(ch 0) Playout is now enabled again..."); |
| Sleep(testTime); |
| |
| Test("(ch 0) Sending at 16kHz..."); |
| l16_16.channels = 1; |
| CHECK(codec->SetSendCodec(0, l16_16)); |
| Sleep(testTime); |
| |
| CHECK(base->SetOnHoldStatus(0, true, kHoldPlayOnly)); |
| Test("(ch 0) Playout is now on hold..."); |
| Sleep(testTime); |
| CHECK(base->SetOnHoldStatus(0, false, kHoldPlayOnly)); |
| Test("(ch 0) Playout is now enabled again..."); |
| Sleep(testTime); |
| |
| Test("(ch 0) Perform minor panning to the left to force mixing in" |
| " stereo..."); |
| CHECK(volume->SetOutputVolumePan(0, (float)1.0, (float)0.7)); |
| Sleep(testTime); |
| |
| CHECK(base->SetOnHoldStatus(0, true, kHoldPlayOnly)); |
| Test("(ch 0) Playout is now on hold..."); |
| Sleep(testTime); |
| CHECK(base->SetOnHoldStatus(0, false, kHoldPlayOnly)); |
| Test("(ch 0) Playout is now enabled again..."); |
| Sleep(testTime); |
| |
| Test("(ch 0) Back to center volume again..."); |
| CHECK(volume->SetOutputVolumePan(0, 1.0, 1.0)); |
| Sleep(testTime); |
| |
| Test("(ch 1) Add 16kHz local file to the mixer..."); |
| CHECK(StartMedia(1, 54321, false, true, false, false, true)); |
| Sleep(testTime); |
| |
| CHECK(base->SetOnHoldStatus(0, true, kHoldPlayOnly)); |
| Test("(ch 0) Playout is now on hold..."); |
| Sleep(testTime); |
| CHECK(base->SetOnHoldStatus(1, true, kHoldPlayOnly)); |
| Test("(ch 1) Playout is now on hold => should be silent..."); |
| Sleep(testTime); |
| CHECK(base->SetOnHoldStatus(0, false, kHoldPlayOnly)); |
| Test("(ch 0) Playout is now enabled again..."); |
| CHECK(base->SetOnHoldStatus(1, false, kHoldPlayOnly)); |
| Test("(ch 1) Playout is now enabled again..."); |
| Sleep(testTime); |
| StopMedia(1); |
| Test("(ch 1) Stopped playing file..."); |
| Sleep(testTime); |
| StopMedia(0); |
| ANL(); |
| |
| base->DeleteChannel(0); |
| base->DeleteChannel(1); |
| |
| // ----------------------------------- |
| // Verify recording of playout to file |
| // ----------------------------------- |
| |
| // StartRecordingPlayout |
| // |
| // Verify that the correct set of signals is recorded in the mixer. |
| // Record each channel and all channels (-1) to ensure that post and pre |
| // mixing recording works. |
| |
| base->CreateChannel(); |
| base->CreateChannel(); |
| |
| Test(">> Verify file-recording functionality:\n"); |
| |
| Test("(ch 0) Sending at 8kHz..."); |
| CHECK(StartMedia(0, 12345, true, true, true, true, false)); |
| Sleep(testTime); |
| |
| Test("(ch 0) Recording of playout to 16kHz PCM file..."); |
| CHECK(file->StartRecordingPlayout( |
| 0, GetFilename("RecordedPlayout16kHz.pcm"), NULL)); |
| Sleep(testTime); |
| CHECK(file->StopRecordingPlayout(0)); |
| |
| Test("(ch 0) Playing out the recorded file..."); |
| CHECK(volume->SetInputMute(0, true)); |
| CHECK(file->StartPlayingFileLocally( |
| 0, GetFilename("RecordedPlayout16kHz.pcm"))); |
| Sleep(testTime); |
| CHECK(file->StopPlayingFileLocally(0)); |
| CHECK(volume->SetInputMute(0, false)); |
| |
| CHECK(codec->SetSendCodec(0, l16_16)); |
| Test("(ch 0) Sending at 16kHz (L16)..."); |
| Sleep(testTime); |
| |
| Test("(ch 0) Recording of playout to 16kHz PCM file..."); |
| CHECK(file->StartRecordingPlayout( |
| 0, GetFilename("RecordedPlayout16kHz.pcm"), NULL)); |
| Sleep(testTime); |
| CHECK(file->StopRecordingPlayout(0)); |
| |
| Test("(ch 0) Playing out the recorded file..."); |
| CHECK(volume->SetInputMute(0, true)); |
| CHECK(file->StartPlayingFileLocally( |
| 0, GetFilename("RecordedPlayout16kHz.pcm"))); |
| Sleep(testTime); |
| CHECK(file->StopPlayingFileLocally(0)); |
| CHECK(volume->SetInputMute(0, false)); |
| |
| CHECK(codec->SetSendCodec(0, l16_32)); |
| Test("(ch 0) Sending at 32kHz (L16)..."); |
| Sleep(testTime); |
| |
| Test("(ch 0) Recording of playout to 16kHz PCM file..."); |
| CHECK(file->StartRecordingPlayout( |
| 0, GetFilename("RecordedPlayout16kHz.pcm"), NULL)); |
| Sleep(testTime); |
| CHECK(file->StopRecordingPlayout(0)); |
| |
| Test("(ch 0) Playing out the recorded file..."); |
| CHECK(volume->SetInputMute(0, true)); |
| CHECK(file->StartPlayingFileLocally( |
| 0, GetFilename("RecordedPlayout16kHz.pcm"))); |
| Sleep(testTime); |
| CHECK(file->StopPlayingFileLocally(0)); |
| CHECK(volume->SetInputMute(0, false)); |
| |
| Test("(ch 0) Sending at 16kHz without file as mic but file added on the" |
| " playout side instead..."); |
| CHECK(StopMedia(0)); |
| CHECK(StartMedia(0, 12345, false, true, false, false, true)); |
| CHECK(codec->SetSendCodec(0, l16_16)); |
| Sleep(testTime); |
| |
| Test("(ch 0) Recording of playout to 16kHz PCM file..."); |
| CHECK(file->StartRecordingPlayout( |
| 0, GetFilename("RecordedPlayout16kHz.pcm"), NULL)); |
| Sleep(testTime); |
| CHECK(file->StopRecordingPlayout(0)); |
| CHECK(file->StopPlayingFileLocally(0)); |
| |
| Test("(ch 0) Playing out the recorded file..."); |
| CHECK(file->StartPlayingFileLocally( |
| 0, GetFilename("RecordedPlayout16kHz.pcm"))); |
| Sleep(testTime); |
| CHECK(file->StopPlayingFileLocally(0)); |
| |
| CHECK(StopMedia(0)); |
| CHECK(StopMedia(1)); |
| |
| Test("(ch 0) Sending at 16kHz..."); |
| CHECK(StartMedia(0, 12345, true, true, true, false, false)); |
| CHECK(codec->SetSendCodec(0, l16_16)); |
| Test("(ch 1) Adding playout file..."); |
| CHECK(StartMedia(1, 33333, false, true, false, false, true)); |
| Sleep(testTime); |
| |
| Test("(ch -1) Speak while recording all channels to add mixer input on " |
| "channel 0..."); |
| CHECK(file->StartRecordingPlayout( |
| -1, GetFilename("RecordedPlayout16kHz.pcm"), NULL)); |
| Sleep(testTime); |
| CHECK(file->StopRecordingPlayout(-1)); |
| CHECK(file->StopPlayingFileLocally(1)); |
| |
| Test("(ch 0) Playing out the recorded file..."); |
| CHECK(volume->SetInputMute(0, true)); |
| CHECK(file->StartPlayingFileLocally( |
| 0, GetFilename("RecordedPlayout16kHz.pcm"))); |
| Sleep(testTime); |
| CHECK(file->StopPlayingFileLocally(0)); |
| CHECK(volume->SetInputMute(0, false)); |
| |
| CHECK(StopMedia(0)); |
| CHECK(StopMedia(1)); |
| ANL(); |
| |
| // StartRecordingPlayoutStereo |
| |
| Test(">> Verify recording of playout in stereo:\n"); |
| |
| Test("(ch 0) Sending at 32kHz..."); |
| CHECK(codec->SetSendCodec(0, l16_16)); |
| CHECK(StartMedia(0, 12345, true, true, true, true, false)); |
| Sleep(testTime); |
| |
| Test("Modified master balance (L=10%%, R=100%%) to force stereo mixing..."); |
| CHECK(volume->SetOutputVolumePan(-1, (float)0.1, (float)1.0)); |
| Sleep(testTime); |
| |
| /* |
| Test("Recording of left and right channel playout to two 16kHz PCM " |
| "files..."); |
| file->StartRecordingPlayoutStereo( |
| GetFilename("RecordedPlayout_Left_16kHz.pcm"), |
| GetFilename("RecordedPlayout_Right_16kHz.pcm"), StereoBoth); |
| Sleep(testTime); |
| Test("Back to center volume again..."); |
| CHECK(volume->SetOutputVolumePan(-1, (float)1.0, (float)1.0)); |
| */ |
| |
| Test("(ch 0) Playing out the recorded file for the left channel (10%%)..."); |
| CHECK(volume->SetInputMute(0, true)); |
| CHECK(file->StartPlayingFileLocally( |
| 0, GetFilename("RecordedPlayout_Left_16kHz.pcm"))); |
| Sleep(testTime); |
| CHECK(file->StopPlayingFileLocally(0)); |
| |
| Test("(ch 0) Playing out the recorded file for the right channel (100%%) =>" |
| " should sound louder than the left channel..."); |
| CHECK(file->StartPlayingFileLocally( |
| 0, GetFilename("RecordedPlayout_Right_16kHz.pcm"))); |
| Sleep(testTime); |
| CHECK(file->StopPlayingFileLocally(0)); |
| CHECK(volume->SetInputMute(0, false)); |
| |
| base->DeleteChannel(0); |
| base->DeleteChannel(1); |
| ANL(); |
| |
| // --------------------------- |
| // Verify inserted Dtmf tones |
| // --------------------------- |
| |
| Test(">> Verify Dtmf feedback functionality:\n"); |
| |
| base->CreateChannel(); |
| |
| for (int i = 0; i < 2; i++) { |
| if (i == 0) |
| Test("Dtmf direct feedback is now enabled..."); |
| else |
| Test("Dtmf direct feedback is now disabled..."); |
| |
| CHECK(dtmf->SetDtmfFeedbackStatus(true, (i==0))); |
| |
| Test("(ch 0) Sending at 32kHz using G.722.1C..."); |
| CHECK(codec->SetRecPayloadType(0, g722_1c_32)); |
| CHECK(codec->SetSendCodec(0, g722_1c_32)); |
| CHECK(StartMedia(0, 12345, true, true, true, false, false)); |
| Sleep(500); |
| |
| Test("(ch 0) Sending outband Dtmf events => ensure that they are added" |
| " to the mixer..."); |
| // ensure that receiver will not play out outband Dtmf |
| CHECK(dtmf->SetSendTelephoneEventPayloadType(0, 118)); |
| CHECK(dtmf->SendTelephoneEvent(0, 9, true, 390)); |
| Sleep(500); |
| CHECK(dtmf->SendTelephoneEvent(0, 1, true, 390)); |
| Sleep(500); |
| CHECK(dtmf->SendTelephoneEvent(0, 5, true, 390)); |
| Sleep(500); |
| Sleep(testTime - 1500); |
| |
| Test("(ch 0) Changing codec to 8kHz PCMU..."); |
| CHECK(codec->SetSendCodec(0, pcmu_8)); |
| Sleep(500); |
| |
| Test("(ch 0) Sending outband Dtmf events => ensure that they are added" |
| " to the mixer..."); |
| CHECK(dtmf->SendTelephoneEvent(0, 9, true, 390)); |
| Sleep(500); |
| CHECK(dtmf->SendTelephoneEvent(0, 1, true, 390)); |
| Sleep(500); |
| CHECK(dtmf->SendTelephoneEvent(0, 5, true, 390)); |
| Sleep(500); |
| Sleep(testTime - 1500); |
| |
| Test("(ch 0) Changing codec to 16kHz L16..."); |
| CHECK(codec->SetSendCodec(0, l16_16)); |
| Sleep(500); |
| |
| Test("(ch 0) Sending outband Dtmf events => ensure that they are added" |
| " to the mixer..."); |
| CHECK(dtmf->SendTelephoneEvent(0, 9, true, 390)); |
| Sleep(500); |
| CHECK(dtmf->SendTelephoneEvent(0, 1, true, 390)); |
| Sleep(500); |
| CHECK(dtmf->SendTelephoneEvent(0, 5, true, 390)); |
| Sleep(500); |
| Sleep(testTime - 1500); |
| |
| StopMedia(0); |
| ANL(); |
| } |
| |
| base->DeleteChannel(0); |
| |
| // --------------------------- |
| // Verify external processing |
| // -------------------------- |
| |
| base->CreateChannel(); |
| |
| Test(">> Verify external media processing:\n"); |
| |
| Test("(ch 0) Playing 16kHz file locally <=> mixing in mono @ 16kHz..."); |
| CHECK(StartMedia(0, 12345, false, true, false, false, true)); |
| Sleep(testTime); |
| Test("Enabling playout external media processing => played audio should " |
| "now be affected"); |
| CHECK(xmedia->RegisterExternalMediaProcessing( |
| 0, kPlaybackAllChannelsMixed, mpobj)); |
| Sleep(testTime); |
| Test("(ch 0) Sending speech at 32kHz <=> mixing at 32kHz..."); |
| CHECK(codec->SetSendCodec(0, l16_32)); |
| Sleep(testTime); |
| printf("Back to normal again\n"); |
| CHECK(xmedia->DeRegisterExternalMediaProcessing(0, |
| kPlaybackAllChannelsMixed)); |
| Sleep(testTime); |
| printf("Enabling playout external media processing on ch 0 => " |
| "played audio should now be affected\n"); |
| CHECK(xmedia->RegisterExternalMediaProcessing(0, kPlaybackPerChannel, |
| mpobj)); |
| Sleep(testTime); |
| Test("Panning volume to the right <=> mixing in stereo @ 32kHz..."); |
| CHECK(volume->SetOutputVolumePan(-1, 0.0, 1.0)); |
| Sleep(testTime); |
| Test("Back to center volume again <=> mixing in mono @ 32kHz..."); |
| CHECK(volume->SetOutputVolumePan(-1, 1.0, 1.0)); |
| Sleep(testTime); |
| printf("Back to normal again\n"); |
| CHECK(xmedia->DeRegisterExternalMediaProcessing(0, kPlaybackPerChannel)); |
| Sleep(testTime); |
| CHECK(StopMedia(0)); |
| ANL(); |
| |
| base->DeleteChannel(0); |
| |
| // -------------------------------------------------- |
| // Extended tests of emulated stereo encoding schemes |
| // -------------------------------------------------- |
| |
| CodecInst PCMU; |
| CodecInst G729; |
| CodecInst L16_8; |
| CodecInst L16_16; |
| CodecInst L16_32; |
| |
| base->CreateChannel(); |
| |
| Test(">> Verify emulated stereo encoding for differenct codecs:\n"); |
| |
| // enable external encryption |
| CHECK(encrypt->RegisterExternalEncryption(0, *this)); |
| Test("(ch 0) External Encryption is now enabled:"); |
| |
| // register all codecs on the receiving side |
| strcpy(PCMU.plname, "PCMU"); |
| PCMU.channels = 2; |
| PCMU.pacsize = 160; |
| PCMU.plfreq = 8000; |
| PCMU.pltype = 125; |
| PCMU.rate = 64000; |
| CHECK(codec->SetRecPayloadType(0, PCMU)); |
| |
| strcpy(G729.plname, "G729"); |
| G729.channels = 2; |
| G729.pacsize = 160; |
| G729.plfreq = 8000; |
| G729.pltype = 18; |
| G729.rate = 8000; |
| CHECK(codec->SetRecPayloadType(0, G729)); |
| |
| strcpy(L16_8.plname, "L16"); |
| L16_8.channels = 2; |
| L16_8.pacsize = 160; |
| L16_8.plfreq = 8000; |
| L16_8.pltype = 120; |
| L16_8.rate = 128000; |
| CHECK(codec->SetRecPayloadType(0, L16_8)); |
| |
| strcpy(L16_16.plname, "L16"); |
| L16_16.channels = 2; |
| L16_16.pacsize = 320; |
| L16_16.plfreq = 16000; |
| L16_16.pltype = 121; |
| L16_16.rate = 256000; |
| CHECK(codec->SetRecPayloadType(0, L16_16)); |
| |
| // NOTE - we cannot send larger than 1500 bytes per RTP packet |
| strcpy(L16_32.plname, "L16"); |
| L16_32.channels = 2; |
| L16_32.pacsize = 320; |
| L16_32.plfreq = 32000; |
| L16_32.pltype = 122; |
| L16_32.rate = 512000; |
| CHECK(codec->SetRecPayloadType(0, L16_32)); |
| |
| // sample-based, 8-bits per sample |
| |
| Test("(ch 0) Sending using G.711 (sample based, 8 bits/sample)..."); |
| PCMU.channels = 1; |
| CHECK(codec->SetSendCodec(0, PCMU)); |
| SetStereoExternalEncryption(0, true, 8); |
| CHECK(StartMedia(0, 12345, true, true, true, true, false)); |
| Sleep(testTime); |
| |
| // sample-based, 16-bits per sample |
| |
| Test("(ch 0) Sending using L16 8kHz (sample based, 16 bits/sample)..."); |
| L16_8.channels = 1; |
| CHECK(codec->SetSendCodec(0, L16_8)); |
| SetStereoExternalEncryption(0, true, 16); |
| Sleep(testTime); |
| |
| Test("(ch 0) Sending using L16 16kHz (sample based, 16 bits/sample)..."); |
| L16_16.channels = 1; |
| CHECK(codec->SetSendCodec(0, L16_16)); |
| Sleep(testTime); |
| |
| Test("(ch 0) Sending using L16 32kHz (sample based, 16 bits/sample)..."); |
| L16_32.channels = 1; |
| CHECK(codec->SetSendCodec(0, L16_32)); |
| Sleep(testTime); |
| |
| Test("(ch 0) Sending using G.729 (frame based)..."); |
| G729.channels = 1; |
| CHECK(codec->SetSendCodec(0, G729)); |
| Sleep(testTime); |
| |
| StopMedia(0); |
| |
| // disable external encryption |
| CHECK(encrypt->DeRegisterExternalEncryption(0)); |
| |
| base->DeleteChannel(0); |
| |
| // ------------------------------------------------------------------------ |
| CHECK(base->Terminate()); |
| |
| printf("\n\n------------------------------------------------\n"); |
| printf(" Test passed!\n"); |
| printf("------------------------------------------------\n\n"); |
| |
| return 0; |
| } |
| |
| } // namespace voetest |