void testTickerNotification() { CallbackUserData userData; RTL_START(1000000); calculateSampleData(); OUTPUT_DRIVER driver(OUTPUT_DRIVER_CONSTRUCTOR_PARAMS); userData.mDriver = &driver; OsCallback notificationCallback((intptr_t)&userData, &driverCallback); frameTime = 0; sampleDataSz = TEST_SAMPLE_DATA_SIZE; driver.enableDevice(TEST_SAMPLES_PER_FRAME_SIZE, TEST_SAMPLES_PER_SECOND, 0, notificationCallback); // Wait defined amount of time. OsTask::delay(TEST_SAMPLE_DATA_LENGTH_SEC*1000); driver.disableDevice(); CPPUNIT_ASSERT(!driver.isEnabled()); CPPUNIT_ASSERT(frameInCallback > TEST_SAMPLE_DATA_LENGTH_SEC*TEST_FRAME_RATE); RTL_WRITE("testTickerNotification.rtl"); RTL_STOP }
void testMprDelay() { RTL_START(10000000); int i; // Create source (input) and sink (output) resources. MpTestResource sourceResource("TestSource", 0, 0, 1, 1); sourceResource.setGenOutBufMask(1); sourceResource.setOutSignalType(MpTestResource::MP_SINE_SAW); sourceResource.setSignalAmplitude(0, 16000); sourceResource.setSpeechType(0, MP_SPEECH_SILENT); MpTestResource sinkResource("TestSink", 1, 1, 0, 0); UtlString buffer; MprDelay delayResource("TestDelay", TEST_DELAY_FRAMES); try { // Add source and sink resources to flowgraph and link them together. CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->addResource(sourceResource)); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->addResource(sinkResource)); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->addResource(delayResource)); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->addLink(sourceResource, 0, delayResource, 0)); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->addLink(delayResource, 0, sinkResource, 0)); // Create a queue.. OsMsg* pMsg; OsMsgDispatcher notfDisp; // Now we enable the flowgraph.. Which should enable resources. CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->enable()); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->start()); mpFlowGraph->setNotificationDispatcher(¬fDisp); // TESTING BEGINS // Generate NULL frames for (i = 0; i < 2*TEST_DELAY_FRAMES; i++) { mpFlowGraph->processNextFrame(); CPPUNIT_ASSERT_EQUAL(0, notfDisp.numMsgs()); } CPPUNIT_ASSERT_EQUAL(0, delayResource.getDelayMs()); // Generate inactive frames sourceResource.setGenOutBufMask(1); sourceResource.setSpeechType(0, MP_SPEECH_SILENT); for (i = 0; i < 2*TEST_DELAY_FRAMES; i++) { mpFlowGraph->processNextFrame(); CPPUNIT_ASSERT_EQUAL(0, notfDisp.numMsgs()); } CPPUNIT_ASSERT_EQUAL(0, delayResource.getDelayMs()); // Generate first active frame sourceResource.setGenOutBufMask(1); sourceResource.setSpeechType(0, MP_SPEECH_ACTIVE); mpFlowGraph->processNextFrame(); CPPUNIT_ASSERT_EQUAL(1, notfDisp.numMsgs()); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, notfDisp.receive((OsMsg*&)pMsg, OsTime(10))); CPPUNIT_ASSERT_EQUAL(MpResNotificationMsg::MPRNM_DELAY_SPEECH_STARTED, (MpResNotificationMsg::RNMsgType)((MpResNotificationMsg*)pMsg)->getMsg()); // Add few frames to check getDelayFrames() correctness. for (i = 0; i < TEST_DELAY_FRAMES/2-1; i++) { if (i%2 == 1) sourceResource.setGenOutBufMask(0); else sourceResource.setGenOutBufMask(1); mpFlowGraph->processNextFrame(); CPPUNIT_ASSERT_EQUAL(0, notfDisp.numMsgs()); } sourceResource.setGenOutBufMask(1); CPPUNIT_ASSERT_EQUAL(TEST_DELAY_FRAMES/2, delayResource.getDelayFrames()); // Start Play MprDelay::startPlay("TestDelay", *mpFlowGraph->getMsgQ()); // Push frames to test behaviour during the play. for (i = 0; i < TEST_DELAY_FRAMES; i++) { if (i%2 == 1) sourceResource.setGenOutBufMask(0); else sourceResource.setGenOutBufMask(1); mpFlowGraph->processNextFrame(); CPPUNIT_ASSERT_EQUAL(0, notfDisp.numMsgs()); } CPPUNIT_ASSERT_EQUAL(TEST_DELAY_FRAMES/2, delayResource.getDelayFrames()); // Test quiescent state during the play. sourceResource.setGenOutBufMask(1); sourceResource.setSpeechType(0, MP_SPEECH_ACTIVE); for (i = 0; i < TEST_DELAY_FRAMES; i++) { mpFlowGraph->processNextFrame(); CPPUNIT_ASSERT_EQUAL(0, notfDisp.numMsgs()); } sourceResource.setSpeechType(0, MP_SPEECH_SILENT); int delay = delayResource.getDelayFrames(); for (i = 0; i < delay; i++) { CPPUNIT_ASSERT_EQUAL(0, notfDisp.numMsgs()); mpFlowGraph->processNextFrame(); } CPPUNIT_ASSERT_EQUAL(1, notfDisp.numMsgs()); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, notfDisp.receive((OsMsg*&)pMsg, OsTime(10))); CPPUNIT_ASSERT_EQUAL(MpResNotificationMsg::MPRNM_DELAY_QUIESCENCE, (MpResNotificationMsg::RNMsgType)((MpResNotificationMsg*)pMsg)->getMsg()); // Stop Play MprDelay::stopPlay("TestDelay", *mpFlowGraph->getMsgQ()); // Generate first active frame sourceResource.setGenOutBufMask(1); sourceResource.setSpeechType(0, MP_SPEECH_ACTIVE); mpFlowGraph->processNextFrame(); CPPUNIT_ASSERT_EQUAL(1, notfDisp.numMsgs()); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, notfDisp.receive((OsMsg*&)pMsg, OsTime(10))); CPPUNIT_ASSERT_EQUAL(MpResNotificationMsg::MPRNM_DELAY_SPEECH_STARTED, (MpResNotificationMsg::RNMsgType)((MpResNotificationMsg*)pMsg)->getMsg()); // Add more frames to cause MprDelay's overflow. for (i = 0; i < 2*TEST_DELAY_FRAMES; i++) { if (i%2 == 1) sourceResource.setGenOutBufMask(0); else sourceResource.setGenOutBufMask(1); mpFlowGraph->processNextFrame(); CPPUNIT_ASSERT_EQUAL(0, notfDisp.numMsgs()); } CPPUNIT_ASSERT_EQUAL(TEST_DELAY_FRAMES, delayResource.getDelayFrames()); // TESTING END mpFlowGraph->processNextFrame(); // Remove resources from flowgraph. We should remove them explicitly // here, because they are stored on the stack and will be destroyed. CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->removeResource(sinkResource)); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->removeResource(sourceResource)); CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->removeResource(delayResource)); mpFlowGraph->processNextFrame(); } catch (CppUnit::Exception& e) { // Remove resources from flowgraph. We should remove them explicitly // here, because they are stored on the stack and will be destroyed. // If we will not catch this assert we'll have this resources destroyed // while still referenced in flowgraph, causing crash. if (sinkResource.getFlowGraph() != NULL) { CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->removeResource(sinkResource)); } if (sourceResource.getFlowGraph() != NULL) { CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->removeResource(sourceResource)); } if (delayResource.getFlowGraph() != NULL) { CPPUNIT_ASSERT_EQUAL(OS_SUCCESS, mpFlowGraph->removeResource(delayResource)); } mpFlowGraph->processNextFrame(); // Rethrow exception. throw(e); } RTL_WRITE("testMprDelay.rtl"); RTL_STOP }
OsStatus mpStartUp(int sampleRate, int samplesPerFrame, int numAudioBuffers, OsConfigDb* pConfigDb, const size_t numCodecPaths, const UtlString codecPaths[]) { // TODO: // This should be broken down into separate arguments for: // Max number of flowgraphs // Max number of calls // Max calls/streams per flowgraph // Buffers used/stream or used/flowgraph // Approximate based upon current media interface initialization int maxCalls = numAudioBuffers / 16; #ifdef _VXWORKS int defSilenceSuppressLevel = 10000; #else int defSilenceSuppressLevel = 0; #endif OsStatus resCode; UtlBoolean silenceSuppressFlag; UtlString silenceSuppressEnable; int silenceSuppressLevel; assert(samplesPerFrame >= 8); showMpMisc(TRUE); RTL_START(100000000); setExternalRtlCollector(sRealtimeLogCollector); // First initialize static codecs mpStaticCodecInitializer(); MpCodecFactory* pcf = MpCodecFactory::getMpCodecFactory(); if(numCodecPaths != 0) { size_t i; for(i = 0; i < numCodecPaths; i++) { pcf->loadAllDynCodecs(codecPaths[i].data(), CODEC_PLUGINS_FILTER); } } else { pcf->loadAllDynCodecs(CODEC_PLUGIN_PATH, CODEC_PLUGINS_FILTER); } #ifdef _VXWORKS /* [ */ /* Rashly assumes page size is a power of two */ MpMisc.mem_page_size = goGetThePageSize(); MpMisc.mem_page_mask = MpMisc.mem_page_size - 1; #endif /* _VXWORKS ] */ MpMisc.sampleBytes = sizeof(MpAudioSample); MpMisc.frameSamples = samplesPerFrame; MpMisc.frameBytes = MpMisc.sampleBytes * MpMisc.frameSamples; MpMisc.rtpMaxBytes = /* sizeof(struct RtpHeader) */ 12 + (((sampleRate + 24) / 25) * MpMisc.sampleBytes); // Create buffer for audio data in mediagraph MpMisc.RawAudioPool = new MpBufPool( samplesPerFrame*sizeof(MpAudioSample) + MpArrayBuf::getHeaderSize(), numAudioBuffers, "RawAudioPool"); Nprintf( "mpStartUp: MpMisc.RawAudioPool = 0x%X\n" , (int) MpMisc.RawAudioPool, 0,0,0,0,0); if (NULL == MpMisc.RawAudioPool) { return OS_NO_MEMORY; } // Create buffer for audio headers int audioBuffers = MpMisc.RawAudioPool->getNumBlocks(); MpMisc.AudioHeadersPool = new MpBufPool(sizeof(MpAudioBuf), audioBuffers, "AudioHeadersPool"); Nprintf( "mpStartUp: MpMisc.AudioHeadersPool = 0x%X\n" , (int) MpMisc.AudioHeadersPool, 0,0,0,0,0); if (NULL == MpMisc.AudioHeadersPool) { // TODO:: Think about proper resource deallocation on fail in mpStartUp() return OS_NO_MEMORY; } MpAudioBuf::smpDefaultPool = MpMisc.AudioHeadersPool; /* * Go get a buffer and fill with silence. We will use this for muting * either or both of input and output, and whenever we are starved for * audio data. */ { MpAudioBufPtr sb = MpMisc.RawAudioPool->getBuffer(); if (!sb.isValid()) { Zprintf("\n\mpStartUp:" " MpBufPool::getBuffer() failed, quitting!\n\n\n", 0,0,0,0,0,0); delete MpMisc.RawAudioPool; MpMisc.RawAudioPool = NULL; return OS_LIMIT_REACHED; } sb->setSamplesNumber(samplesPerFrame); memset(sb->getSamplesWritePtr(), 0, sb->getSamplesNumber()*sizeof(MpAudioSample)); sb->setSpeechType(MP_SPEECH_SILENT); MpMisc.mpFgSilence = sb; Zprintf("mpStartUp: MpMisc.silence = 0x%X\n", (int) MpMisc.mpFgSilence, 0,0,0,0,0); }
void testTones() { RTL_START(1600000); CPPUNIT_ASSERT(mpMediaFactory); SdpCodecList* sdpCodecList = new SdpCodecList(); CPPUNIT_ASSERT(sdpCodecList); UtlSList utlCodecList; sdpCodecList->getCodecs(utlCodecList); UtlString localRtpInterfaceAddress("127.0.0.1"); UtlString locale; int tosOptions = 0; UtlString stunServerAddress; int stunOptions = 0; int stunKeepAlivePeriodSecs = 25; UtlString turnServerAddress; int turnPort = 0 ; UtlString turnUser; UtlString turnPassword; int turnKeepAlivePeriodSecs = 25; bool enableIce = false ; CpMediaInterface* mediaInterface = mpMediaFactory->createMediaInterface(NULL, sdpCodecList, NULL, // public mapped RTP IP address localRtpInterfaceAddress, locale, tosOptions, stunServerAddress, stunOptions, stunKeepAlivePeriodSecs, turnServerAddress, turnPort, turnUser, turnPassword, turnKeepAlivePeriodSecs, enableIce); // Record the entire "call" - all connections. mediaInterface->recordAudio("testTones_call_recording.wav"); mediaInterface->giveFocus() ; RTL_EVENT("Tone set", 0); printf("first tone set\n"); RTL_EVENT("Tone set", 1); mediaInterface->startTone(6, true, false) ;OsTask::delay(500) ; RTL_EVENT("Tone set", 2); mediaInterface->startTone(8, true, false) ;OsTask::delay(500) ; RTL_EVENT("Tone set", 3); mediaInterface->startTone(4, true, false) ;OsTask::delay(500) ; RTL_EVENT("Tone set", 0); printf("second tone set\n"); OsTask::delay(500) ; RTL_EVENT("Tone set", 1); mediaInterface->startTone(6, true, false) ;OsTask::delay(500) ; RTL_EVENT("Tone set", 2); mediaInterface->startTone(8, true, false) ;OsTask::delay(500) ; RTL_EVENT("Tone set", 3); mediaInterface->startTone(4, true, false) ;OsTask::delay(500) ; RTL_EVENT("Tone set", 0); printf("third tone set\n"); OsTask::delay(500) ; RTL_EVENT("Tone set", 1); mediaInterface->startTone(9, true, false) ;OsTask::delay(500) ; mediaInterface->startTone(5, true, false) ;OsTask::delay(500) ; mediaInterface->startTone(5, true, false) ;OsTask::delay(500) ; mediaInterface->startTone(4, true, false) ;OsTask::delay(500) ; RTL_EVENT("Tone set", 0); printf("fourth tone set\n"); OsTask::delay(500) ; RTL_EVENT("Tone set", 1); mediaInterface->startTone(9, true, false) ;OsTask::delay(500) ; mediaInterface->startTone(5, true, false) ;OsTask::delay(500) ; mediaInterface->startTone(5, true, false) ;OsTask::delay(500) ; mediaInterface->startTone(4, true, false) ;OsTask::delay(500) ; RTL_EVENT("Tone set", 0); printf("tone set done\n"); OsTask::delay(1000) ; // Stop recording the "call" -- all connections. mediaInterface->stopRecording(); RTL_WRITE("testTones.rtl"); RTL_STOP; // delete interface mediaInterface->release(); OsTask::delay(500) ; delete sdpCodecList ; };
void testTwoTones() { RTL_START(2400000); // This test creates three flowgraphs. It streams RTP with tones // from the 2nd and 3rd to be received and mixed in the first flowgraph // So we test RTP and we test that we can generate 2 different tones in // to different flowgraphs to ensure that the ToneGen has no global // interactions or dependencies. CPPUNIT_ASSERT(mpMediaFactory); SdpCodecList* pSdpCodecList = new SdpCodecList(); CPPUNIT_ASSERT(pSdpCodecList); UtlSList utlCodecList; pSdpCodecList->getCodecs(utlCodecList); UtlString localRtpInterfaceAddress("127.0.0.1"); OsSocket::getHostIp(&localRtpInterfaceAddress); UtlString locale; int tosOptions = 0; UtlString stunServerAddress; int stunOptions = 0; int stunKeepAlivePeriodSecs = 25; UtlString turnServerAddress; int turnPort = 0 ; UtlString turnUser; UtlString turnPassword; int turnKeepAlivePeriodSecs = 25; bool enableIce = false ; // Create a flowgraph (sink) to receive and mix 2 sources CpMediaInterface* mixedInterface = mpMediaFactory->createMediaInterface(NULL, pSdpCodecList, NULL, // public mapped RTP IP address localRtpInterfaceAddress, locale, tosOptions, stunServerAddress, stunOptions, stunKeepAlivePeriodSecs, turnServerAddress, turnPort, turnUser, turnPassword, turnKeepAlivePeriodSecs, enableIce); // Create connections for mixed(sink) flowgraph int mixedConnection1Id = -1; CPPUNIT_ASSERT(mixedInterface->createConnection(mixedConnection1Id, NULL) == OS_SUCCESS); CPPUNIT_ASSERT(mixedConnection1Id > 0); int mixedConnection2Id = -1; CPPUNIT_ASSERT(mixedInterface->createConnection(mixedConnection2Id, NULL) == OS_SUCCESS); CPPUNIT_ASSERT(mixedConnection2Id > 0); // Get the address of the connections so we can send RTP to them // capabilities of first connection on mixed(sink) flowgraph const int maxAddresses = 1; UtlString rtpHostAddresses1[maxAddresses]; int rtpAudioPorts1[maxAddresses]; int rtcpAudioPorts1[maxAddresses]; int rtpVideoPorts1[maxAddresses]; int rtcpVideoPorts1[maxAddresses]; RTP_TRANSPORT transportTypes1[maxAddresses]; int numActualAddresses1; SdpCodecList supportedCodecs1; SdpSrtpParameters srtpParameters1; int videoBandwidth1; int videoFramerate1; CPPUNIT_ASSERT_EQUAL( mixedInterface->getCapabilitiesEx(mixedConnection1Id, maxAddresses, rtpHostAddresses1, rtpAudioPorts1, rtcpAudioPorts1, rtpVideoPorts1, rtcpVideoPorts1, transportTypes1, numActualAddresses1, supportedCodecs1, srtpParameters1, videoBandwidth1, videoFramerate1), OS_SUCCESS); // capabilities of second connection on mixed(sink) flowgraph UtlString rtpHostAddresses2[maxAddresses]; int rtpAudioPorts2[maxAddresses]; int rtcpAudioPorts2[maxAddresses]; int rtpVideoPorts2[maxAddresses]; int rtcpVideoPorts2[maxAddresses]; RTP_TRANSPORT transportTypes2[maxAddresses]; int numActualAddresses2; SdpCodecList supportedCodecs2; SdpSrtpParameters srtpParameters2; int videoBandwidth2; int videoFramerate2; CPPUNIT_ASSERT_EQUAL( mixedInterface->getCapabilitiesEx(mixedConnection2Id, maxAddresses, rtpHostAddresses2, rtpAudioPorts2, rtcpAudioPorts2, rtpVideoPorts2, rtcpVideoPorts2, transportTypes2, numActualAddresses2, supportedCodecs2, srtpParameters2, videoBandwidth2, videoFramerate2), OS_SUCCESS); // Prep the sink connections to receive RTP UtlSList codec1List; supportedCodecs1.getCodecs(codec1List); CPPUNIT_ASSERT_EQUAL( mixedInterface->startRtpReceive(mixedConnection1Id, codec1List), OS_SUCCESS); // Want to hear what is on the mixed flowgraph mixedInterface->giveFocus(); UtlSList codec2List; supportedCodecs2.getCodecs(codec2List); CPPUNIT_ASSERT_EQUAL( mixedInterface->startRtpReceive(mixedConnection2Id, codec2List), OS_SUCCESS); // Second flowgraph to be one of two sources CpMediaInterface* source1Interface = mpMediaFactory->createMediaInterface(NULL, pSdpCodecList, NULL, // public mapped RTP IP address localRtpInterfaceAddress, locale, tosOptions, stunServerAddress, stunOptions, stunKeepAlivePeriodSecs, turnServerAddress, turnPort, turnUser, turnPassword, turnKeepAlivePeriodSecs, enableIce); // Create connection for source 1 flowgraph int source1ConnectionId = -1; CPPUNIT_ASSERT(source1Interface->createConnection(source1ConnectionId, NULL) == OS_SUCCESS); CPPUNIT_ASSERT(source1ConnectionId > 0); // Set the destination for sending RTP from source 1 to connection 1 on // the mix flowgraph printf("rtpHostAddresses1: \"%s\"\nrtpAudioPorts1: %d\nrtcpAudioPorts1: %d\nrtpVideoPorts1: %d\nrtcpVideoPorts1: %d\n", rtpHostAddresses1->data(), *rtpAudioPorts1, *rtcpAudioPorts1, *rtpVideoPorts1, *rtcpVideoPorts1); CPPUNIT_ASSERT_EQUAL( source1Interface->setConnectionDestination(source1ConnectionId, rtpHostAddresses1->data(), *rtpAudioPorts1, *rtcpAudioPorts1, *rtpVideoPorts1, *rtcpVideoPorts1), OS_SUCCESS); // Start sending RTP from source 1 to the mix flowgraph CPPUNIT_ASSERT_EQUAL( source1Interface->startRtpSend(source1ConnectionId, codec1List), OS_SUCCESS); // Second flowgraph to be one of two sources CpMediaInterface* source2Interface = mpMediaFactory->createMediaInterface(NULL, pSdpCodecList, NULL, // public mapped RTP IP address localRtpInterfaceAddress, locale, tosOptions, stunServerAddress, stunOptions, stunKeepAlivePeriodSecs, turnServerAddress, turnPort, turnUser, turnPassword, turnKeepAlivePeriodSecs, enableIce); // Create connection for source 2 flowgraph int source2ConnectionId = -1; CPPUNIT_ASSERT(source2Interface->createConnection(source2ConnectionId, NULL) == OS_SUCCESS); CPPUNIT_ASSERT(source2ConnectionId > 0); // Set the destination for sending RTP from source 2 to connection 2 on // the mix flowgraph CPPUNIT_ASSERT_EQUAL( source2Interface->setConnectionDestination(source2ConnectionId, *rtpHostAddresses2, *rtpAudioPorts2, *rtcpAudioPorts2, *rtpVideoPorts2, *rtcpVideoPorts2), OS_SUCCESS); RTL_EVENT("Tone count", 0); // Record the entire "call" - all connections. mixedInterface->recordAudio("testTwoTones_call_recording.wav"); // Start sending RTP from source 2 to the mix flowgraph CPPUNIT_ASSERT_EQUAL( source2Interface->startRtpSend(source2ConnectionId, codec2List), OS_SUCCESS); RTL_EVENT("Tone count", 1); printf("generate tones in source 1\n"); source1Interface->startTone(1, true, true); OsTask::delay(1000); RTL_EVENT("Tone count", 2); printf("generate tones in source 2 as well\n"); source2Interface->startTone(2, true, true); OsTask::delay(1000); RTL_EVENT("Tone count", 1); printf("stop tones in source 1\n"); OsTask::delay(1000); RTL_EVENT("Tone count", 0); OsTask::delay(1000); printf("two tones done\n"); // Stop recording the "call" -- all connections. mixedInterface->stopRecording(); // Delete connections mixedInterface->deleteConnection(mixedConnection1Id); mixedInterface->deleteConnection(mixedConnection2Id); source1Interface->deleteConnection(source1ConnectionId); source2Interface->deleteConnection(source2ConnectionId); // delete interfaces mixedInterface->release(); source1Interface->release(); source2Interface->release(); OsTask::delay(500) ; RTL_WRITE("testTwoTones.rtl"); RTL_STOP; delete pSdpCodecList ; };