Receive an Incoming Session When the Client is Behind a NAT

The following code example demonstrates how to receive an incoming session when the client is behind a NAT. The operations in the Initialize RTC code example must be performed before using this example.

Note  This example does not contain error checking or releases appropriate for real code.

C++ Code Example

//------------------------------------
//Incoming call to machine behind NAT
//------------------------------------

HRESULT  hr = S_OK;
BSTR     bstrLocalURI = NULL;
BSTR     bstrDestURI = NULL;
BSTR     bstrInternalLocalAddress = NULL;
long     lInternalLocalPort = 1234;

RTC_SESSION_TYPE  enSessionType;
IRTCSession       *pIRTCSession = NULL;
IRTCClient2       *pIRTCClient;

IRTCSessionPortManagement  *pSessionPortManagement;
IRTCPortManager            *pIRTCPortManager;
IRTCClientPortManagement   *pClientPortManagement;

enSessionType  =   // Specify session type 

// Get the URI to call; this can be a sip: or a tel: URI.

// CoCreate and initialize RTCClient. See the 
// Initialize RTC code example.
// Cocreate and initialize your implementation of the port manager.
// QueryInterface for pIRTCPortManager. 

bstrDestURI = ::SysAllocString(L"sip:someone@microsoft.com"); 

//CoCreateRTCClient and populate pIRTCClient
pIRTCClient->QueryInterface(__uuidof(IRTCClientPortManagement),
                            (PVOID *) &pClientPortManagement);

// The lInternalLocalPort and bstrInternalLocalAddress 
// is obtained when RTC calls into your implementation of 
// port manager's IRTCPortManager::GetMapping() method.

// Start the Client listening on a specified 
// local address and port.
hr = pClientPortManagement->StartListenAddressAndPort(bstrInternalLocalAddress, 
                                                      lInternalLocalPort);

// If (hr != S_OK), process the error here.

// Prepare to listen for an incoming session.
IRTCSessionStateChangeEvent  *pISessionState = NULL;
RTC_SESSION_STATE            enSessionState;

// Create the session state interface.
hr = pIDispatch->QueryInterface( IID_IRTCSessionStateChangeEvent,
                          reinterpret_cast<void**> (&plSessionState));

// If (hr != S_OK), process the error here.

// Get the current session state.
hr = pISessionState->get_State(&enSessionState);

// If (hr != S_OK), process the error here.

// Handle all the possible session states.
switch(enSessionState)
{
    ...
    // Handle the incoming call.
    case RTCSS_INCOMING:
    {
        // Play a ring on the local computer.
        pIRTCClient->PlayRing(RTCRT_PHONE, VARIANT_TRUE);

        hr = pISessionState->get_Session(&pIRTCSession);

        // If (hr != S_OK), process the error here.

        // Set the port manager on the incoming session.
        hr = pIRTCSession->QueryInterface(IID_IRTCSessionPortManagement),
                                             (void **) &pSessionPortManagement);

        // If (hr != S_OK), process the error here.

        hr = pSessionPortManagement->SetPortManager(pIRTCPortManager);

        // Release the pointer to the IRTCSessionPortManagement 
        // interface.
        pSessionPortManagement->Release();
        pSessionPortManagement=NULL;

        // Answer the incoming session.
        hr = pIRTCSession->Answer();

        // If (hr != S_OK), process the error here. 
        
        break;
    }
}

...

// Terminate the session when you are done. See the
// "Terminate a Call" code example. 

// Release all pointers.
if(pIRTCSession)
{
    pIRTCSession->Release();
    pIRTCSession=NULL;
}

if(pIRTCPortManager)
{
    pIRTCPortManager->Release();
    pIRTCPortManager=NULL;
}

...

// Have as many more sessions as you would like.
...

// If you are not expecting any more invites to this 
// machine, you can stop listening on the IP address
// and port.
hr = pClientPortManagement->StopListenAddressAndPort(bstrInternalLocalAddress, 
                                                     lInternalLocalPort);
...

// Free up the strings.

// Release all pointers.
if(pIRTCClient)
{
    pIRTCClient->Release();
    pIRTCClient=NULL;
}

if(pClientPortManagement)
{
pClientPortManagement->Release();
pClientPortManagement=NULL;
}

Visual Basic Code Example

'------------------------------------
'Incoming call to machine behind NAT
'------------------------------------
Dim bstrLocalURI As String '(for example, someone@microsoft.com)
Dim bstrDestURI As String '(for example, someone@microsoft.com)
Dim bstrInternalLocalAddress As String '(for example, 192.168.5.130)
Dim lInternalLocalPort As Long
Dim enSessionType As RTC_SESSION_TYPE
Dim objSession As IRTCSession
Dim objSessionPortManagement As IRTCSessionPortManagement
Dim objClientPortManagement As IRTCClientPortManagement
Dim objPortManager As IRTCPortManager
Dim objProfile As IRTCProfile
Dim objRTCClient As IRTCClient2

Dim objSessionState As IRTCSessionStateChangeEvent
Dim enSessionState As RTC_SESSION_STATE

lInternalLocalPort = 1234

'enSessionType  =   ' Specify the session type

' CoCreate and initialize the RTCClient.
' Cocreate and initialize your implementation of the 
' port manager.

Set objClientPortManagement = objSession

' lInternalLocalPort and bstrInternalLocalAddress are
' obtained when RTC calls into the port manager's
' implementation of GetMapping().

' Have the Client start listening on the local address and port.
Call objClientPortManagement.StartListenAddressAndPort(bstrInternalLocalAddress, lInternalLocalPort)

' If (Err.Number), process the error here.

' Prepare to listen for an incoming session.

' Initialize objSessionState from the Event object 
'when the Session State Change event fires.

' If (Err.Number), process the error here.

' Get the current session state.
Set enSessionState = objSessionState.get_State()

'If (Err.Number), process the error here.

' Handle all session states.
Select Case enSessionState
    
    ...
       
    ' Handle the incoming call.
    Case RTCSS_INCOMING:
        'Play a ring on the local computer.
        Call objIRTCClient.PlayRing(RTCRT_PHONE, True)

        Set objSession = objSessionState.get_Session()

        ' If (Err.Number), process the error here.

        Set objSessionPortManagement = objSession
        ' Set the port manager on the incoming session.
        Call objSessionPortManagement.SetPortManager(objPortManager)

        ' Answer the incoming session.
        Call objIRTCSession.Answer

        ' If (Err.Number), process the error here.
        
    ...
        
End Select

...

' Terminate the session when you are done.

' Create more sessions if you would like to.

...

' If the client does not expect any more session invites for this
' machine, the application can stop listening on the ip:port.

Call objClientPortManagement.StopListenAddressAndPort(bstrInternalLocalAddress, lInternalLocalPort)

' If (Err.Number), process the error here.