Sample code for local audio mixing to achieve 3 way/N way calling.

In CE 6.0 R2 release, RTC 1.5 started supporting local audio mixing. Local audio mixing can be enabled by using the flag RTCIF_ENABLE_GLOBAL_MEDIA_MIXING during RTCClient object initialization. Here is the code example (ignoring error handling):

Initialize RTC to enable local media mixing:

    hr =  CoInitializeEx(NULL, COINIT_MULTITHREADED);

    hr = CoCreateInstance(CLSID_RTCClient,

 NULL,

 CLSCTX_INPROC_SERVER,

 IID_IRTCClient,

 (LPVOID *)&gpRTCClient );

        IRTCClient2 *piRTC2 = NULL;

       

        hr = gpRTCClient->QueryInterface(IID_IRTCClient2, (void**)&piRTC2);

        hr = piRTC2->InitializeEx(RTCIF_ENABLE_GLOBAL_MEDIA_MIXING);

 

 Once media mixing is enabled, audio for all calls will be locally mixed. Consider the following example to see how 3-way /N way calling can be achieved:

Consider two audio calls between a caller (Endpoint 1) and two other callers (Endpoint 2 and 3). Without local media mixing, 2 and 3 can talk to 1, but not to each other on the existing calls. When local audio mixing is enabled on endpoint 1, endpoint 1 mixes the audio stream as described below, which will enable 3-way conferencing, and all three can talk to each other.

·        Endpoint 1 mixes its own audio (1) with the audio that it receives from endpoint 3 (3) and sends it to endpoint 2. Similarly,

·        Endpoint 1 mixes its own audio (1) with the audio that it receives from endpoint 2 (2) and send it to endpoint 3.

This way, endpoint 2 can listen to endpoint 3, and endpoint 3 can also listen to endpoint 2.

Since Endpoint 1 is the mixer, the conferencing is dependent on endpoint 1. If endpoint 1 disconnects any of the calls, then Endpoint 2& 3 won’t be able to talk to each other.

Here is a code example (ignoring error conditions for simplicity)

Establishing a 3 way call:

Step 1: Endpoint 1 Calling Endpoint 2

    hr = gpRTCClient->CreateSession(RTCST_PC_TO_PC, NULL, NULL, 0, &pSessionEndpoint2);

    if (SUCCEEDED(hr))

    {

 

            hr = pSessionEndpoint2->AddParticipant(bstrEndpoint2URI, bstrEndpoint2Name, NULL);

   }

After this, RTC will post a session connected event, once the call has been established between endpoin1 and endpoint 3.

Step 2: Endpoint 1 putting Endpoint 2 on Hold, before calling Endpoint 3

    IRTCSessionCallControl* pSessionEndpoint2CallCtrl = NULL;

 

    // Query for the IRTCSessionCallControl interface.

    HRESULT hr = pSessionEndpoint2->QueryInterface (IID_IRTCSessionCallControl,

                                   (void**) & pSessionEndpoint2CallCtrl);

 

    hr = pSessionEndpoint2->get_State(&enState);

 

        if(enState != RTCSS_CONNECTED)

        {

            ASSERT(0);

           // Handle error!!

        }

        

    pSessionEndpoint2CallCtrl->Hold(lCookie);

Step 3: Endpoint 1 Calling Endpoint 3

    hr = gpRTCClient->CreateSession(RTCST_PC_TO_PC, NULL, NULL, 0, &pSessionEndpoint3);

    if (SUCCEEDED(hr))

    {

 

            hr = pSessionEndpoint3->AddParticipant(bstrEndpoint3URI, bstrEndpoint3Name, NULL);

   }

Step 4: Endpoint 1 Unholds Endpoint 2 to establish 3 way conference

    IRTCSessionCallControl* pSessionEndpoint2CallCtrl = NULL;

 

    // Query for the IRTCSessionCallControl interface.

    HRESULT hr = pSessionEndpoint2->QueryInterface (IID_IRTCSessionCallControl,

                                   (void**) & pSessionEndpoint2CallCtrl);

 

    hr = pSessionEndpoint2->get_State(&enState);

 

        if(enState != RTCSS_HOLD)

        {

            ASSERT(0);

           // Handle error!!

        }

        

    pSessionEndpoint2CallCtrl->UnHold(lCookie);

 

After Step 4, all 3 endpoints can talk to each other. Please note that Step 2 and Step 4 (putting Endpoint 1 call on Hold and then UnHold) are optional steps. RTC 1.5 will allow making call to Endpoint 3 while call to Endpoint 2 is active. But this kind of calling is not normal in the telephony world.

 

If Endpoint 1 wants to talk to Endpoint 2 exclusively, it can simply put Endpoint 3 call on Hold, and similarly it can put Endpoint 1 call on Hold if it wants to talk to Endpoint 3 exclusively.

 

Also note that even though media is mixed for both calls, All APIs related to each call (like RTCSession and RTCParticipant APIs) will only act on the respective individual calls. For e.g.

Example 1: pSessionEndpoint2->Terminate(RTC_TERMINATE_REASON) will just disconnect Endpoint 2 and not Endpoint 3.

Example 2: pPartEndpoint2->SendDTMF(RTC_DTMF) will send DTMF tones only to Endpoint 2, and not to Endpoint 3,

etc.

 

However, APIs like CRTCClient::put_Volume(RTC_AUDIO_DEVICE enDevice, long lVolume) will affect both calls.

 

Thanks and happy coding!!