Receiving Media

The following code example shows how to receive audio packets from a channel.


The method Select is used to wait for network events. This method works in the same way as the function select known from the socket API, but works with channels instead of socket descriptors.


while (m_dwAudioThreadID != 0)
{
  // Set events of interest for an audio channel that was created earlier:
  aChannels[0] = m_iControlChannel;
  aChannels[1] = m_iAudioChannelRTP;
  aChannels[2] = m_iAudioChannelRTCP;
  aChannels[3] = m_iSession;
  aInputEvents[0]  = AF_SELECT_READ;
  aInputEvents[1]  = AF_SELECT_READ;
  aInputEvents[2]  = AF_SELECT_READ;
  aInputEvents[3]  = AF_SELECT_READ;
  aOutputEvents[0] = AF_SELECT_NOEVENT;
  aOutputEvents[1] = AF_SELECT_NOEVENT;
  aOutputEvents[2] = AF_SELECT_NOEVENT;
  aOutputEvents[3] = AF_SELECT_NOEVENT;
  int iRet = m_pAFEngine->Select(4,
                                aChannels,
                                aInputEvents,
                                aOutputEvents,
                                AF_TIMEOUT_INFINITE
                          );
  if (iRet <= 0)
  {
        continue;
  }
  //Handle audio channel
  if (aOutputEvents[1])
  {
        if (aOutputEvents[1] & AF_SELECT_READ)
        {
              int iRet = m_pAFEngine->Recv(m_iAudioChannelRTP,
              pBuff, 2048, AF_NON_BLOCKING);
              if (iRet > 0)
              {
                    m_pAudio->HandleAudioPacket(pBuff, iRet);
              }
        }
        if (aOutputEvents[1] & AF_SELECT_ERROR)
        {
              if (m_iAudioChannelRTP >= 0)
              {
                    EndCall();
                    HangUp();
              }
        }
  }// end handle audio channel
  //Handle control channel
  if (aOutputEvents[0])
  {
        if (aOutputEvents[0] & AF_SELECT_READ)
        {
              char dummy;
              m_pAFEngine->Recv(m_iControlChannel, &dummy, 1,
                                         AF_NON_BLOCKING);
        }
        if (aOutputEvents[0] & AF_SELECT_ERROR)
        {
              //handle error
        }
  }
  // Handle Session event
  if (aOutputEvents[3])
  {
        if (aOutputEvents[3] & AF_SELECT_READ)
        {
            unsignedlong ulEvent;
            int iRet = m_pAFEngine->Recv(m_iSession,
                                        (char*)&ulEvent,
                                        4,
                                        AF_NON_BLOCKING
                                    );
            if (iRet > 0)
            {
                 switch (ulEvent)
                 {
                    case EAfEventICECheckCompleted:
                    //Ring after the Ice Checks complete
                    if (!m_bCaller)
                    {
                        m_pAudio->PlayWavFile(sWavFile);
                    }
                    break;
                    case EAfEventICENeedUpdatedOffer:
                    SendReinvite();
                    break;
                    default:
                    break;
                } //switch
            } //if iRet
        }
        if (aOutputEvents[3] & AF_SELECT_ERROR)
        {
              //handle error
        }
  }// end handle session level event channel
} // end while


The above example assumes a separate audio engine (object m_pAudio) is used to process the packets received via the AnyFirewallâ„¢ Engine. The method Select uses an infinite timeout (AF_TIMEOUT_INFINITE). The predefined value AF_SELECT_READ is used to determine which event is of interest to the application. In addition, it is possible that the Select call returns an event of type AF_SELECT_ERROR. In the Select call, we include two additional channels along with the audio channels. One is the control channel (AF_CHANNEL_LOOPBACK), which can be used for resuming the execution blocked by the Select call, and the other is the session level event channel, used for receiving session related events fired from the AFE. Channel types are discussed in 6.1. Channels.

As an alternative to using Select, it is possible to provide a callback function that is called by AnyFirewall Engine whenever data is available for reading on a channel. The callback is provided by implementing an abstract base class IAfCallbackHandler, which defines the actual callback function HandleCallback. The callback class is set using the API function SetCallbackHandler.

Do not mix Select and Callback functions.

The following code snippet shows an actual implementation of the callback and how to register the callback with a channel in AnyFirewall Engine.

// callback class
class CAudioReceiver : IAfCallbackHandler
{
    public:
    virtual void _cdecl HandleCallback(int iChannel, char *pData,
                                    int iLen,
                                    const CAfStdString& sSrcAddress,
                                    int iSrcPort,
                                    const void *pContext
                            );
}
// the actual callback implementation
void CAudioReceiver::HandleCallback(int iChannel, char *pData,
                                    int iLen,
                                    const CAfStdString& sSrcAddress,
                                    int iSrcPort,
                                    const void *pContext))
{
    // received an audio packet on channel iChannel
    m_pAudio->HandleAudioPacket(pData, iLen);
}
// registering the callback with AnyFirewall Engine for an audio channel
CAudioReceiver *pAudioReceiver = new CAudioReceiver;
pAFEngine->SetCallbackHandler(m_iAudioChannelRTP, pAudioReceiver);


For more details, please refer to 7.3. Channel Management and Data Transfer.