Beispiel #1
0
   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
   }
Beispiel #2
0
   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(&notfDisp);

         // 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
   }
Beispiel #3
0
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 ;
    };