CTBCAFBridge hpp 和 cpp 文件分析

hpp 文件

 

typedef class CTBCAFBridge *PCTBCAFBridge;
class TBCAF_API CTBCAFBridge : public CTBCAFCallFlow
{
public:
/*--------------------------------------------------------------------------------------------------------------------------------
 |  Constructor/Destructor
 *------------------------------------------------------------------------------------------------------------------------------*/
    /*!
     * \brief   This constructor is used to create a call between two legs.
     *
     * \param    in_pFreeListener    Free call listener that the leg will use when it is ready to be freed.
     *
     */
    CTBCAFBridge
    (
        IN    ITBCMCFreeListener<ITBCAFCallFlow> *    in_pFreeListener
    );

    /*!
     * \brief   This constructor is used to sync a call between two legs.
     *
     * \param    in_pFreeListener        Free call listener that the leg will use when it is ready to be freed.
     * \param    in_LinkId                Synced link identifier.
     * \param   in_JoinAttribute        Synced bridge information.
     * \param    in_ptrSourceLeg            Source leg.
     * \param    in_ptrDestinationLeg    Destination leg.
     *
     */
    CTBCAFBridge
    ( 
        IN        ITBCMCFreeListener<ITBCAFCallFlow> *    in_pFreeListener,
        IN        TBCMC_LINK_ID                            in_LinkId,
        IN        CTBCMC_JOIN_ATTRIBUTE &                    in_JoinAttribute,
        IN        PTRCTBCAFCallLeg                        in_ptrSourceLeg,
        IN        PTRCTBCAFCallLeg                        in_ptrDestinationLeg
    );

    /*!
     * \brief   Clear all local resources.
     *
     */
    virtual ~CTBCAFBridge();

/*--------------------------------------------------------------------------------------------------------------------------------
 |  Public API Definition
 *------------------------------------------------------------------------------------------------------------------------------*/

    /*! \ref ITBCAFCallFlow::GetAccountId */
    virtual TBX_UINT32 GetAccountId();

    /*!
     * \brief   Set the options used when calls are joined.
     *
     * \remarks    This function must be called before OnCallLegAnswered is called
     *            (generally done immediately after constructing the object),
     *            as the "join" between the two legs is done at that moment, and
     *            options set later will be ignored.
     *
     */
    virtual TBX_RESULT SetOptions( const CTBCAFBridgeOptions& in_Options );

/*--------------------------------------------------------------------------------------------------------------------------------
 |  Events Definition
 *------------------------------------------------------------------------------------------------------------------------------*/
    /*******************************************************************************************************************
     * Call Leg Interface
     ******************************************************************************************************************/

    /*! \ref ITBCAFCallFlow::OnCallLegAlerting */
    virtual TBX_RESULT OnCallLegAlerting( PCTBCAFCallLeg in_pCallLeg, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute );

    /*! \ref ITBCAFCallFlow::OnCallLegAnswered */
    virtual TBX_RESULT OnCallLegAnswered( PCTBCAFCallLeg in_pCallLeg, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute );

    /*! \ref ITBCAFCallFlow::OnCallLegTerminatingIndication */
    virtual TBX_RESULT OnCallLegTerminatingIndication( PCTBCAFCallLeg in_pCallLeg, TBCMC_CALL_REASON & in_Reason, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute );

    /*! \ref ITBCAFCallFlow::OnCallLegTerminated */
    virtual TBX_RESULT OnCallLegTerminated( PCTBCAFCallLeg in_pCallLeg, TBCMC_CALL_REASON & in_Reason, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute );
    
    /*******************************************************************************************************************
     * Leg Interface
     ******************************************************************************************************************/

    /*! \ref ITBCAFCallFlow::OnLegEvent */
    virtual TBX_RESULT OnLegEvent( PCTBCAFCallLeg in_pCallLeg, PITBCMCEvent in_pEvent );

    /*! \ref ITBCAFCallFlow::OnLegError */
    virtual TBX_RESULT OnLegError( PCTBCAFCallLeg in_pCallLeg, CTBCMCLegError & in_Error );

    /*! \ref ITBCAFCallFlow::OnSyncDone */
    virtual TBX_RESULT OnSyncDone( PCTBCAFCallLeg in_pCallLeg );

    /*! \ref ITBCAFCallFlow::OnLegProfileChanged */
    virtual TBX_RESULT OnLegProfileChanged( PCTBCAFCallLeg in_pCallLeg, CTBCMC_MEDIA_PROFILE & in_MediaProfile, TBCMC_MEDIA_REASON_CODE in_Reason, TBCMC_CALL_REASON_CODE in_RefusedReason );

    /*******************************************************************************************************************
     * Tone Interface
     ******************************************************************************************************************/

    /*! \ref ITBCAFCallFlow::OnEventCollected */
    virtual TBX_RESULT OnEventCollected
    (
        PCTBCAFCallLeg                                in_pCallLeg,
        const CTBCAFString&                            in_strEvent,
        const CTBCMC_EVENT_COLLECTED_ATTRIBUTE&        in_EventAttr
    );

/*--------------------------------------------------------------------------------------------------------------------------------
 |  Protected API Definition
 *------------------------------------------------------------------------------------------------------------------------------*/
protected:

    /*! \ref CTBCAFCallFlow::OnSuppInfoApplicationTransport */
    virtual TBX_RESULT OnSuppInfoApplicationTransport( PCTBCAFCallLeg in_pCallLeg, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute );

    /*! \ref CTBCAFCallFlow::OnSuppInfoCallProgress */
    virtual TBX_RESULT OnSuppInfoCallProgress( PCTBCAFCallLeg in_pCallLeg, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute );

    /*! \ref CTBCAFCallFlow::OnSuppInfoSuspend */
    virtual TBX_RESULT OnSuppInfoSuspend
    (
      IN    PCTBCAFCallLeg                    in_pCallLeg,
      IN    TBCMC_SUPP_INFO_MSG_TYPE         in_SuppInfoType,
      IN    CTBCMC_PROTOCOL_ATTRIBUTE &     in_ProtocolAttribute
    );

    /*! \ref CTBCAFCallFlow::OnSuppInfoResume */
    virtual TBX_RESULT OnSuppInfoResume
    (
      IN    PCTBCAFCallLeg                    in_pCallLeg,
      IN    TBCMC_SUPP_INFO_MSG_TYPE         in_SuppInfoType,
      IN    CTBCMC_PROTOCOL_ATTRIBUTE &     in_ProtocolAttribute
    );

    /*! \ref CTBCAFCallFlow::OnSuppInfoChargeUnit */
    virtual TBX_RESULT OnSuppInfoChargeUnit
    (
      IN    PCTBCAFCallLeg                    in_pCallLeg,
      IN    TBCMC_SUPP_INFO_MSG_TYPE         in_SuppInfoType,
      IN    CTBCMC_PROTOCOL_ATTRIBUTE &     in_ProtocolAttribute
    );

    /*! \ref CTBCAFCallFlow::OnSuppInfoSS7Charge */
    virtual TBX_RESULT OnSuppInfoSS7Charge
    (
      IN    PCTBCAFCallLeg                    in_pCallLeg,
      IN    CTBCMC_PROTOCOL_ATTRIBUTE &     in_ProtocolAttribute
    );

    /*! \ref CTBCAFCallFlow::OnSuppInfoUnrecognizedMSU */
    virtual TBX_RESULT OnSuppInfoUnrecognizedMSU( PCTBCAFCallLeg in_pCallLeg, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute );

    /*! \ref CTBCAFCallFlow::OnSuppInfoConfusion */
    virtual TBX_RESULT OnSuppInfoConfusion
    ( 
      IN        PCTBCAFCallLeg                 in_pCallLeg, 
      IN        CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute 
    );

    /*! \ref CTBCAFCallFlow::OnSuppInfoDefault */
    virtual TBX_RESULT OnSuppInfoDefault
    ( 
      IN        PCTBCAFCallLeg                 in_pCallLeg, 
      IN        TBCMC_SUPP_INFO_MSG_TYPE     in_SuppInfoType, 
      IN        CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute 
    );
/*--------------------------------------------------------------------------------------------------------------------------------
 |  Private API Definition
 *------------------------------------------------------------------------------------------------------------------------------*/
private:
    /*!
     * \brief   Check if both active legs (incoming and outgoing) are terminating/terminated, in which case
     *            this function also terminates all other legs and mixers.
     *
     * \param    Reason to use to terminate other legs
     */
    TBX_VOID CheckTerminateRemainingLegsAndMixers
    (
      IN    TBCMC_CALL_REASON &                 in_Reason
    );

    /*!
     * \brief   Get the appropriate reason code to use on a bridged leg according to the termination reason of the other leg.
     *
     * \param    in_Reason                Reason used to terminate the first leg
     * \param    out_ReasonForBridgedLeg    On output, will contain the reason to use when terminating the bridged leg.
     */
    TBX_VOID GetBridgedLegTermReason
    (
      IN    TBCMC_CALL_REASON &                 in_Reason,
      OUT    TBCMC_CALL_REASON &                 out_ReasonForBridgedLeg
    );


/*--------------------------------------------------------------------------------------------------------------------------------
 |  Disable copy constructor and assignment operator
 *------------------------------------------------------------------------------------------------------------------------------*/
    TBCAF_DISABLE_DEFAULT_COPY_CONSTRUCTOR( CTBCAFBridge  );
    TBCAF_DISABLE_DEFAULT_ASSIGNEMENT_OPERATOR( CTBCAFBridge  );

/*--------------------------------------------------------------------------------------------------------------------------------
|  Protected Definition
*------------------------------------------------------------------------------------------------------------------------------*/
protected:
    CTBCAFBridgeOptions                        mOptions;

/*--------------------------------------------------------------------------------------------------------------------------------
 |  Private Definition
 *------------------------------------------------------------------------------------------------------------------------------*/
private:
    PITBCAFGwParamsDao                        mpGwParamsDao;
    TBX_UINT32                                mun32TerminatingLegId;
    TBX_BOOLEAN                                mfSuspended;
};

 

cpp 文件

 

/*--------------------------------------------------------------------------------------------------------------------------------
 |
 |    Project:        CAF Gateway
 |
 |    Filename:       CTBCAFBridge.cpp
 |
 |    Copyright:      TelcoBridges 2002-2012, All Rights Reserved
 |
 |    Description:    This file contains the Gateway module.
 |
 |    Notes:          Tabs = 4
 |
 *-------------------------------------------------------------------------------------------------------------------------------
 |
 |    Revision:       $Revision: 157514 $
 |
 *------------------------------------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------------------------------------
 |  Includes
 *------------------------------------------------------------------------------------------------------------------------------*/

/* System includes */
#include <tbcaf_includes.hh>
#include <CTBCAFString.hpp>
#include <CTBCAFBridge.hpp>
#include <CTBCAFCallUtil.hpp>
#include <CTBCMCLegError.hpp>
#include <ITBCMCEvent.hpp>

/*--------------------------------------------------------------------------------------------------------------------------------
 |  Namespace declaration
 *------------------------------------------------------------------------------------------------------------------------------*/
namespace TBCAF
{

/*--------------------------------------------------------------------------------------------------------------------------------
 |  Defines
 *------------------------------------------------------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------------------------------------------------------
 |  Types
 *------------------------------------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------------------------------------
 |  Global variables
 *------------------------------------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------------------------------------
 |  Macros
 *------------------------------------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------------------------------------
 |  Function Prototypes
 *------------------------------------------------------------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------------------------------------------------------------
 |  Implementation
 *------------------------------------------------------------------------------------------------------------------------------*/


CTBCAFBridge::CTBCAFBridge
(
  IN    ITBCMCFreeListener<ITBCAFCallFlow> *    in_pFreeListener
) : CTBCAFCallFlow( in_pFreeListener )
{
    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::CTBCAFBridge )
    {
        mun32TerminatingLegId            = 0;
        mfSuspended                        = TBX_FALSE;

        LogTrace( TBCAF_TRACE_LEVEL_0, "CTBCAFBridge::CTBCAFBridge\n" );

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
    }

    RETURN_VOID;
}


CTBCAFBridge::CTBCAFBridge
(
  IN    ITBCMCFreeListener<ITBCAFCallFlow> *    in_pFreeListener,
  IN    TBCMC_LINK_ID                            in_LinkId,
  IN    CTBCMC_JOIN_ATTRIBUTE &                 in_JoinAttribute,
  IN    PTRCTBCAFCallLeg                        in_ptrSourceLeg,
  IN    PTRCTBCAFCallLeg                        in_ptrDestinationLeg
) : CTBCAFCallFlow( in_pFreeListener, in_LinkId, in_JoinAttribute, in_ptrSourceLeg, in_ptrDestinationLeg )
{
    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::CTBCAFBridge )
    {
        mun32TerminatingLegId            = 0;
        mfSuspended                        = TBX_FALSE;

        LogTrace( TBCAF_TRACE_LEVEL_0, "CTBCAFBridge::CTBCAFBridge" );

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
    }

    RETURN_VOID;
}


CTBCAFBridge::~CTBCAFBridge()
{
    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::~CTBCAFBridge )
    {
        LogTrace( TBCAF_TRACE_LEVEL_0,    "CTBCAFBridge::~CTBCAFBridge\n" );

        /* Clear remaining legs and mixers */
        Clear();

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
    }

    RETURN_VOID;
}




TBX_UINT32 CTBCAFBridge::GetAccountId()
{
    return 0;
}



TBX_UINT32 CTBCAFBridge::SetOptions( const CTBCAFBridgeOptions& in_Options )
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )
    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::SetOptions )
    {
        mOptions = in_Options;

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
    }

    RETURN;
TBCAF_MUTEX_GET_SCOPE_END( &mMutex )
}


/*******************************************************************************************************************
 * Call Leg Interface
 ******************************************************************************************************************/



TBX_RESULT CTBCAFBridge::OnCallLegAlerting
(
  IN    PCTBCAFCallLeg                        in_pCallLeg,
  IN    CTBCMC_PROTOCOL_ATTRIBUTE &         in_ProtocolAttribute
)
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )
    PTRCTBCAFCallLeg    ptrCallLeg;

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::OnCallLegAlerting )
    {
        LogTrace( TBCAF_TRACE_LEVEL_1, "CTBCAFBridge::OnCallLegAlerting for Leg 0x%08X\n", in_pCallLeg->GetLegId() );

        ptrCallLeg = GetIncomingActiveLeg();
        if( ptrCallLeg != NULL)
        {
            /* Copy Charge information into incoming leg */
            ptrCallLeg->GetAttributes().GetChargeIndicator() = in_pCallLeg->GetAttributes().GetChargeIndicator();

            /* Copy echo canceler flag into incoming leg */
            ptrCallLeg->GetAttributes().GetEchoCanceller() = in_pCallLeg->GetAttributes().GetEchoCanceller();

            if( !ptrCallLeg->IsAlerted() )
                ptrCallLeg->AlertCall();
#if 0
            /* Try sending CPG with event alerting */
            {
                CTBCMC_PROTOCOL_ATTRIBUTE    ExtraProtInfo;
                TBCMC_CALL_PROTOCOL_TYPE     ProtocolType = ptrCallLeg->GetAttributes().GetProtocolType();

                if (ProtocolType == TBCMC_CALL_PROTOCOL_TYPE_SS7)
                {
                    TBX_UINT16        un16BufferSize = 0;
                    TBX_UINT8        aun8Buffer [250];

                    TB640_SS7_ISUP_WRITE_EVENT_INFORMATION (
                        aun8Buffer,
                        &un16BufferSize,
                        0,
                        1, /*  (Event Indicator) -> 1 = Alerting (refer to Q.763) */
                        0); /* (Event Presentation Restriction Indicator) -> 0 = No indication (refer to Q.763) */

                    ExtraProtInfo.SetSS7Ie(un16BufferSize, aun8Buffer );
                    ptrCallLeg->SendCallSuppInfo( TBCMC_SUPP_INFO_MSG_TYPE_CALL_PROGRESS, &ExtraProtInfo);
                }
            }
#endif
        }

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
    }

    RETURN;
TBCAF_MUTEX_GET_SCOPE_END( &mMutex )
}


TBX_RESULT CTBCAFBridge::OnCallLegAnswered
(
  IN    PCTBCAFCallLeg                        in_pCallLeg,
  IN    CTBCMC_PROTOCOL_ATTRIBUTE &         in_ProtocolAttribute
)
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )
    PTRCTBCAFCallLeg    ptrIncomingCallLeg;

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::OnCallLegAnswered )
    {
        LogTrace( TBCAF_TRACE_LEVEL_2, "Bridge::Answered for Leg 0x%08X\n", in_pCallLeg->GetLegId() );

        ptrIncomingCallLeg = GetIncomingActiveLeg();
        if( ptrIncomingCallLeg != NULL )
        {
            TBX_BOOL    fNeedToJoin = TBX_TRUE;

            /* Copy echo canceler flag into incoming leg */
            ptrIncomingCallLeg->GetAttributes().GetEchoCanceller() = in_pCallLeg->GetAttributes().GetEchoCanceller();

            /* Check if already full-duplex joined with incoming call leg */
            CTBCMC_JOIN_ATTRIBUTE    JoinAttributes;
            if( in_pCallLeg->GetJoinedLegAttributes( ptrIncomingCallLeg->GetLegId(), &JoinAttributes ) )
            {
                if( JoinAttributes.IsFullDuplex() )
                {
                    /* Already full-duplex joined. No need to re-join */
                    fNeedToJoin = TBX_FALSE;
                }
            }

            if( fNeedToJoin )
            {
                in_pCallLeg->Join( ptrIncomingCallLeg.Get(), NULL, mOptions.mfWarnIfToneDetectionEnabled );
            }
            if (ptrIncomingCallLeg->IsAnswered() == TBX_FALSE)
            {
                LogTrace( TBCAF_TRACE_LEVEL_1, "Bridge::AnswerCall, Answering bridged Leg 0x%08X",
                    ptrIncomingCallLeg->GetLegId());

                ptrIncomingCallLeg->AnswerCall();
            }
        }

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
    }

    RETURN;
TBCAF_MUTEX_GET_SCOPE_END( &mMutex )
}


TBX_RESULT CTBCAFBridge::OnCallLegTerminatingIndication
(
  IN    PCTBCAFCallLeg                    in_pCallLeg,
  IN    TBCMC_CALL_REASON &                 in_Reason,
  IN    CTBCMC_PROTOCOL_ATTRIBUTE &     in_ProtocolAttribute
)
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )
    TBCMC_CALL_REASON                    Reason;
    PTRCTBCAFCallLeg                    ptrOtherCallLeg;
    TBCAF_TRACE_LEVEL                    TraceLevel = TBCAF_TRACE_LEVEL_3;
    PTBX_CHAR                            pszColor = "";

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::OnCallLegTerminatingIndication )
    {
        ptrOtherCallLeg = NULL;


        if
        (
            in_Reason.Reason == TBCMC_CALL_REASON_CODE_TOOLPACK_SYNC_DROP ||
            in_Reason.Reason == TBCMC_CALL_REASON_CODE_TOOLPACK_RESOURCE_NO_MORE_AVAILABLE
        )
        {
            TraceLevel = TBCAF_TRACE_LEVEL_3;
            pszColor = FYELLOW;
        }
        else if (in_Reason.Reason > TBCMC_CALL_REASON_CODE_TOOLPACK_NORMAL &&
            in_Reason.Reason <= TBCMC_CALL_REASON_CODE_TOOLPACK_LAST)
        {
            TraceLevel = TBCAF_TRACE_LEVEL_3;
            pszColor = FRED;
        }

        mun32TerminatingLegId = in_pCallLeg->GetLegId();

        LogTrace( TraceLevel, "EndCall: Leg=0x%08X (%s) %sReason=%u (%s)",
            in_pCallLeg->GetLegId(),
            in_pCallLeg->GetAttributes().GetNetworkAccessPoint().c_str(),
            pszColor,
            (unsigned int)in_Reason.Reason,
            TBCMC_CALL_REASON_CODE_TO_STRING( in_Reason.Reason ));

        memcpy (&Reason, &in_Reason, sizeof (Reason));

#if 0    /* Bug #10617: No more required to unjoin, TerminateCall() will implicitly do that. */
        // Unjoin legs
        if( in_pCallLeg->IsJoined() )
        {
            in_pCallLeg->Unjoin();
        }
#endif

        // Terminate other leg
        ptrOtherCallLeg = GetOtherLegSmartPtr( in_pCallLeg );
        if( ptrOtherCallLeg != NULL )
        {
            TBCMC_CALL_REASON        ReasonForBridgedLeg;
            GetBridgedLegTermReason( Reason, ReasonForBridgedLeg );

            LogTrace( TBCAF_TRACE_LEVEL_1, "Bridge::OnCallLegTerminatingIndication, Terminating bridged Leg: 0x%08X",
                ptrOtherCallLeg->GetLegId());
            ptrOtherCallLeg->TerminateCall( ReasonForBridgedLeg );
        }

        // Terminate leg
        in_pCallLeg->TerminateCall( Reason );

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
    }

    RETURN;
TBCAF_MUTEX_GET_SCOPE_END( &mMutex )
}



TBX_RESULT CTBCAFBridge::OnCallLegTerminated
(
  IN    PCTBCAFCallLeg                    in_pCallLeg,
  IN    TBCMC_CALL_REASON &                 in_Reason,
  IN    CTBCMC_PROTOCOL_ATTRIBUTE &     in_ProtocolAttribute
)
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )
    TBCMC_CALL_REASON                    Reason;
    PTRCTBCAFCallLeg                    ptrOtherCallLeg;
    TBCAF_TRACE_LEVEL                    TraceLevel = TBCAF_TRACE_LEVEL_3;
    PTBX_CHAR                            pszColor = "";
    
    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::OnCallLegTerminated )
    {
        ptrOtherCallLeg = NULL;

        if
        (
            in_Reason.Reason == TBCMC_CALL_REASON_CODE_TOOLPACK_SYNC_DROP ||
            in_Reason.Reason == TBCMC_CALL_REASON_CODE_TOOLPACK_RESOURCE_NO_MORE_AVAILABLE
        )
        {
            TraceLevel = TBCAF_TRACE_LEVEL_3;
            pszColor = FYELLOW;
        }
        else if (in_Reason.Reason > TBCMC_CALL_REASON_CODE_TOOLPACK_NORMAL &&
            in_Reason.Reason <= TBCMC_CALL_REASON_CODE_TOOLPACK_LAST)
        {
            TraceLevel = TBCAF_TRACE_LEVEL_3;
            pszColor = FRED;
        }
        if (mun32TerminatingLegId == in_pCallLeg->GetLegId())
        {
            TraceLevel = TBCAF_TRACE_LEVEL_2;
        }

        LogTrace( TraceLevel, "LegTerminated: Leg=0x%08X %sReason=%u (%s)",
            in_pCallLeg->GetLegId(),
            pszColor,
            (unsigned int)in_Reason.Reason,
            TBCMC_CALL_REASON_CODE_TO_STRING( in_Reason.Reason ));

        memcpy (&Reason, &in_Reason, sizeof (Reason));

        // Terminate other leg
        ptrOtherCallLeg = GetOtherLegSmartPtr( in_pCallLeg );
        if( ptrOtherCallLeg != NULL )
        {
            TBCMC_CALL_REASON        ReasonForBridgedLeg;
            GetBridgedLegTermReason( Reason, ReasonForBridgedLeg );

            ptrOtherCallLeg->TerminateCall( ReasonForBridgedLeg );
        }

        /* Check if other legs/mixers also need to be terminated */
        CheckTerminateRemainingLegsAndMixers( in_Reason );

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
        /* Call base class' handler */
        CTBCAFCallFlow::OnCallLegTerminated (in_pCallLeg, in_Reason, in_ProtocolAttribute);
    }

    RETURN;
TBCAF_MUTEX_GET_SCOPE_END( &mMutex )
}

TBX_VOID CTBCAFBridge::CheckTerminateRemainingLegsAndMixers
(
  IN    TBCMC_CALL_REASON &                 in_Reason
)
{
    TBX_BOOL    fActiveInTerminating    = TBX_FALSE;
    TBX_BOOL    fActiveOutTerminating    = TBX_FALSE;

    /* As soon as one of the last active leg is terminating, drop all other legs */
    if( mptrActiveCallLegIn == NULL || mptrActiveCallLegIn->IsTerminating() )
    {
        fActiveInTerminating = TBX_TRUE;
    }
    if( mptrActiveCallLegOut == NULL || mptrActiveCallLegOut->IsTerminating() )
    {
        fActiveOutTerminating = TBX_TRUE;
    }

    if( fActiveInTerminating && fActiveOutTerminating )
    {
        LogTrace( TBCAF_TRACE_LEVEL_3, "CheckTerminateRemainingLegsAndMixers: All active legs terminating\n" );

        std::vector< PTRCTBCAFCallLeg >                aLegs;
        std::vector< PTRCTBCAFCallLeg >::iterator    itLeg;
        GetLegs( &aLegs );
        for( itLeg = aLegs.begin(); itLeg != aLegs.end(); ++itLeg )
        {
            if( !(*itLeg)->IsTerminating() )
            {
                LogTrace( TBCAF_TRACE_LEVEL_3, "CheckTerminateRemainingLegsAndMixers:: Also terminating non-active leg Leg 0x%08X", (*itLeg)->GetLegId() );
                (*itLeg)->TerminateCall( in_Reason );
            }
        }

        std::vector< PTRCTBCAFMixer >                aMixers;
        std::vector< PTRCTBCAFMixer >::iterator        itMixer;
        GetMixers( &aMixers );
        for( itMixer = aMixers.begin(); itMixer != aMixers.end(); ++itMixer )
        {
            if( !(*itMixer)->IsTerminating() )
            {
                LogTrace( TBCAF_TRACE_LEVEL_3, "CheckTerminateRemainingLegsAndMixers:: Also terminating mixer 0x%08X", (*itMixer)->GetMixerId() );
                (*itMixer)->MixerTerminate();
            }
        }
    }
}


TBX_RESULT CTBCAFBridge::OnSuppInfoApplicationTransport( PCTBCAFCallLeg in_pCallLeg, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute )
{
    /* Forward this message */
    PTRCTBCAFCallLeg    ptrOtherLeg;
    ptrOtherLeg = GetOtherLegSmartPtr( in_pCallLeg );
    if( ptrOtherLeg != NULL )
    {
        TBCMC_CALL_PROTOCOL_TYPE     OtherProtocolType = ptrOtherLeg->GetAttributes().GetProtocolType();

        LogTrace( TBCAF_TRACE_LEVEL_2, "OnSuppInfoApplicationTransport: Leg 0x%08X APM received forward to %s\n",
            ptrOtherLeg->GetLegId(),
            TBCMC_CALL_TYPE_TO_STRING(OtherProtocolType) );

        if( OtherProtocolType == TBCMC_CALL_PROTOCOL_TYPE_SS7 )
        {
            /* Forward to other leg */
            ptrOtherLeg->SendCallSuppInfo( TBCMC_SUPP_INFO_MSG_TYPE_SS7_APP_TRANSPORT );
        }
        else if ( OtherProtocolType == TBCMC_CALL_PROTOCOL_TYPE_SIP )
        {
            CTBCMC_PROTOCOL_ATTRIBUTE    ExtraProtInfo;
            ExtraProtInfo.SetSipStatusCode (SIP_STATUS_183_SESSION_PROGRESS);
            ptrOtherLeg->SendCallSuppInfo( TBCMC_SUPP_INFO_MSG_TYPE_CALL_PROGRESS, &ExtraProtInfo );
        }
    }

    return TBX_RESULT_OK;
}


TBX_RESULT CTBCAFBridge::OnSuppInfoCallProgress( PCTBCAFCallLeg in_pCallLeg, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute )
{
    TBX_BOOLEAN                        fSendMsg = TBX_TRUE;
    TBCMC_SUPP_INFO_MSG_TYPE        SupInfoMsgType = TBCMC_SUPP_INFO_MSG_TYPE_NOT_USED;
    TBCMC_CALL_PROTOCOL_TYPE        ProtocolType = TBCMC_CALL_PROTOCOL_TYPE_UNSPECIFIED;
    CTBCMC_PROTOCOL_ATTRIBUTE        ProtocolAttribute;
    CTBCAFPtr<CTBCAFCallLeg>        pLegToSendCallProgress;

    (void)in_ProtocolAttribute; /* Argument not used in this function */

    if( in_ProtocolAttribute.GetPtr()->Cmn.Type == TBCMC_CALL_PROTOCOL_TYPE_SS7 &&
        in_ProtocolAttribute.GetPtr()->Ss7Attribute.ProtocolVariant == TBCMC_SS7_ISUP_PROTOCOL_VARIANT_SPIROU )
    {
        //In SPIROU, always forward CPG to the other leg
        pLegToSendCallProgress = GetOtherLegSmartPtr( in_pCallLeg );
    }
    else
    {
        /* 
         * Depending on the incoming call type, we need to send the proper call progress.  We'll let the
         * engine to insert the proper "default" IE until we are able to completely convert all protocols
         * and variants amongst them
         */
        pLegToSendCallProgress = GetIncomingActiveLeg();
        if ( pLegToSendCallProgress!= NULL && pLegToSendCallProgress->IsAnswered() )
        {
            fSendMsg = TBX_FALSE;        /* Never forward PROGRESS when the call is answered, unless for SPIROU */
        }
    }

    if( pLegToSendCallProgress != NULL )
    {

        ProtocolType = pLegToSendCallProgress->GetAttributes().GetCallLegAttribute()->GetProtocolType();

        /* 
         * Check which message type we need to send (different for SS7 or ISDN)
         * Note that we don't propagate the "CallProgress" toward SIP network.  We only do this for the
         * EarlyMedia case (which is handled by another behavior).
         */
        if ( ProtocolType == TBCMC_CALL_PROTOCOL_TYPE_SS7 )
            SupInfoMsgType = TBCMC_SUPP_INFO_MSG_TYPE_SS7_CALL_PROGRESS;
        else if ( ProtocolType == TBCMC_CALL_PROTOCOL_TYPE_ISDN )
            SupInfoMsgType = TBCMC_SUPP_INFO_MSG_TYPE_ISDN_CALL_PROGRESS;
        else
            fSendMsg = TBX_FALSE;

        /* Send the progress message */
        if (fSendMsg)
        {
            pLegToSendCallProgress->SendCallSuppInfo
            (
                SupInfoMsgType,
                &ProtocolAttribute
            );                
        }
    }

    return TBX_RESULT_OK;
}



TBX_RESULT CTBCAFBridge::OnSuppInfoSuspend
(
  IN    PCTBCAFCallLeg                    in_pCallLeg,
  IN    TBCMC_SUPP_INFO_MSG_TYPE         in_SuppInfoType,
  IN    CTBCMC_PROTOCOL_ATTRIBUTE &     in_ProtocolAttribute
)
{
    TBX_BOOL            fJoinPending;
    TBX_BOOL            fJoined            = in_pCallLeg->IsJoined( NULL, &fJoinPending );
    PTRCTBCAFCallLeg    ptrOtherCallLeg    = GetOtherLegSmartPtr( in_pCallLeg );

    LogTrace
    (
        TBCAF_TRACE_LEVEL_1,
        "CTBCAFBridge::OnSuppInfoSuspend (%s) for Leg 0x%08X Joined=%u",
        TBCMC_SUPP_INFO_MSG_TYPE_TO_STRING( in_SuppInfoType ),
        in_pCallLeg->GetLegId(),
        fJoined 
    );

    if( ptrOtherCallLeg != NULL && !ptrOtherCallLeg->IsTerminating() )
    {
        // Forward suspend info to next leg
        ptrOtherCallLeg->SendCallSuppInfo( in_SuppInfoType );
    }

    if( fJoined || fJoinPending )
    {
        /* Temporary unjoin legs */
        if( in_SuppInfoType == TBCMC_SUPP_INFO_MSG_TYPE_SUSPEND )
        {
            /* When suspended, we unjoin completely */
            in_pCallLeg->Unjoin();
        }
        else if( ptrOtherCallLeg != NULL )
        {
            /* When in_pCallLeg is 'on hold', we join half-duplex from in_pCallLeg --> Other leg */
            CTBCMC_JOIN_ATTRIBUTE    JoinAttr;
            JoinAttr.IsFullDuplex() = TBX_FALSE;
            in_pCallLeg->Join( ptrOtherCallLeg.Get(), NULL, TBX_TRUE, &JoinAttr );
        }
        mfSuspended = TBX_TRUE;
    }

    return TBX_RESULT_OK;
}


TBX_RESULT CTBCAFBridge::OnSuppInfoResume
(
  IN    PCTBCAFCallLeg                    in_pCallLeg,
  IN    TBCMC_SUPP_INFO_MSG_TYPE         in_SuppInfoType,
  IN    CTBCMC_PROTOCOL_ATTRIBUTE &     in_ProtocolAttribute
)
{
    TBX_BOOL            fJoinPending;
    TBX_BOOL            fUnjoinPending;
    TBX_BOOL            fJoined            = in_pCallLeg->IsJoined( NULL, &fJoinPending, &fUnjoinPending );
    PTRCTBCAFCallLeg    ptrOtherCallLeg    = GetOtherLegSmartPtr( in_pCallLeg );
    
    (void)in_ProtocolAttribute; /* Argument not used in this function */

    LogTrace( TBCAF_TRACE_LEVEL_1, "CTBCAFBridge::OnSuppInfoResume (%s) for Leg 0x%08X Joined=%u%s%s Suspend=%u",
        TBCMC_SUPP_INFO_MSG_TYPE_TO_STRING( in_SuppInfoType ),
        in_pCallLeg->GetLegId(),
        fJoined,
        fJoinPending ? " (join pending)" : "",
        fUnjoinPending ? " (unjoin pending)" : "",
        (unsigned int)mfSuspended);

    if( ptrOtherCallLeg != NULL && !ptrOtherCallLeg->IsTerminating() )
    {
        // Forward suspend info to next leg
        ptrOtherCallLeg->SendCallSuppInfo( in_SuppInfoType );
    }

    if( mfSuspended )
    {
        if( ptrOtherCallLeg != NULL )
        {
            /* Re-join legs */
            ptrOtherCallLeg->Join( in_pCallLeg, NULL, mOptions.mfWarnIfToneDetectionEnabled );
        }
        mfSuspended = TBX_FALSE;
    }

    return TBX_RESULT_OK;
}


TBX_RESULT CTBCAFBridge::OnSuppInfoChargeUnit
(
  IN    PCTBCAFCallLeg                    in_pCallLeg,
  IN    TBCMC_SUPP_INFO_MSG_TYPE         in_SuppInfoType,
  IN    CTBCMC_PROTOCOL_ATTRIBUTE &     in_ProtocolAttribute
)
{
    TBX_RESULT            Result = TBX_RESULT_INVALID_STATE;
    PTRCTBCAFCallLeg    ptrOtherCallLeg;
    ptrOtherCallLeg = GetOtherLegSmartPtr( in_pCallLeg );

    if( in_SuppInfoType == TBCMC_SUPP_INFO_MSG_TYPE_CHARGE_UNIT )
    {
        if( ptrOtherCallLeg != NULL && !ptrOtherCallLeg->IsTerminating() )
        {
            CTBCMC_PROTOCOL_ATTRIBUTE ProtocolAttribute;
            TBX_UINT8 in_un8ChargeUnitNumber;
            TBX_UINT8 in_un8MessageNumber;

            LogTrace( TBCAF_TRACE_LEVEL_1, "CTBCAFBridge::OnSuppInfoChargeUnit (ITX) for Leg 0x%08X: Forwarding to leg 0x%08X",
                in_pCallLeg->GetLegId(),
                ptrOtherCallLeg->GetLegId() );
            
            switch( ptrOtherCallLeg->GetAttributes().GetCallLegAttribute()->GetProtocolType() )
            {
                case TBCMC_CALL_PROTOCOL_TYPE_SS7: /* Only supported on ISUP and SIP */
                case TBCMC_CALL_PROTOCOL_TYPE_SIP:
                    in_ProtocolAttribute.GetChargeNumber( in_un8ChargeUnitNumber, in_un8MessageNumber );
                    ProtocolAttribute.SetChargeNumber( in_un8ChargeUnitNumber, in_un8MessageNumber );
                    ProtocolAttribute.GetPtr()->Cmn.Type = ptrOtherCallLeg->GetAttributes().GetCallLegAttribute()->GetProtocolType();

                    ptrOtherCallLeg->SendCallSuppInfo(
                        TBCMC_SUPP_INFO_MSG_TYPE_CHARGE_UNIT, 
                        &ProtocolAttribute );
                    break;
                default:
                    break;
            }
            Result = TBX_RESULT_OK;
        }

        LogTrace( TBCAF_TRACE_LEVEL_1, "CTBCAFBridge::OnSuppInfoChargeUnit (ITX) for Leg 0x%08X: Acknowledging (TXA)",
            in_pCallLeg->GetLegId() );

        /* Acknowledge (TXA) */
        in_pCallLeg->SendCallSuppInfo( TBCMC_SUPP_INFO_MSG_TYPE_CHARGING_ACK, NULL );
    }
    else if( in_SuppInfoType == TBCMC_SUPP_INFO_MSG_TYPE_CHARGING_ACK )
    {
        LogTrace( TBCAF_TRACE_LEVEL_1, "CTBCAFBridge::OnSuppInfoChargeUnit (TXA) for Leg 0x%08X: Received acknowledge",
            in_pCallLeg->GetLegId() );
        /* Don't forward this, this ack belongs to us. In fact, the specs says that:
           - Incoming ITX received => Forward to other leg, and return ack (TXA) to current leg
           - Then we expect a ack (TXA) from other leg in response to our forwarded ITX (here, we just got that ack) */
        /* Make sure we did not store SS7 raw data in the other leg, else it could cause problem for the next message we transmit*/ 
        if( ptrOtherCallLeg != NULL && !ptrOtherCallLeg->IsTerminating() )
        {
            ptrOtherCallLeg->EmptySs7RawDataToTransmit();
        }
    }
    else
    {
        LogTrace( TBCAF_TRACE_LEVEL_ERROR, "OnSuppInfoChargeUnit: Unexpected supp info type %u", (unsigned int)in_SuppInfoType );
    }

    return Result;
}

TBX_RESULT CTBCAFBridge::OnSuppInfoSS7Charge( PCTBCAFCallLeg in_pCallLeg, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute )
{
    /* Forward this message */
    PTRCTBCAFCallLeg    ptrOtherCallLeg;
    ptrOtherCallLeg = GetOtherLegSmartPtr( in_pCallLeg );
    if( ptrOtherCallLeg != NULL )
    {
        CTBCMC_PROTOCOL_ATTRIBUTE    ExtraProtInfo;
        TBCMC_CALL_PROTOCOL_TYPE     OtherProtocolType = ptrOtherCallLeg->GetAttributes().GetProtocolType();

        LogTrace( TBCAF_TRACE_LEVEL_2, "OnSuppInfoSS7Charge: Leg 0x%08X CHG received forward to %s\n",
            ptrOtherCallLeg->GetLegId(),
            TBCMC_CALL_TYPE_TO_STRING(OtherProtocolType) );

        if( OtherProtocolType == TBCMC_CALL_PROTOCOL_TYPE_SS7 )
        {
            /* Forward to other leg */
            CTBCAFPtr<CTBCMCSs7RawData>    ptrSs7RawData;
            in_ProtocolAttribute.GetSs7RawData( &ptrSs7RawData );

            if ( ptrSs7RawData != NULL )
            {
                TBCMC_SS7_ISUP_PROTOCOL_VARIANT        ProtocolVariant;
                CTBCAFString                        strData;
                PSS7_ISUP_MSG_CHG_STRUCT            pChgMsg;
                TBX_BYTE                            abyIeBuffer [250];
                TBX_UINT16                            un16IeBufferSize = 0;

                ptrSs7RawData->GetSs7RawDataBuf( ProtocolVariant, strData );
                pChgMsg = (PSS7_ISUP_MSG_CHG_STRUCT)strData.c_str();

                if ( strData.Length() > SS7_ISUP_MSG_CHG_MIN_SIZE && 
                    pChgMsg->un8MsgId == SS7_ISUP_MESSAGE_CHG &&
                    pChgMsg->un8MandatoryOff == 0x02 &&                                            /* Pointer of mandatory IE */
                    (TBX_UINT32)pChgMsg->un8ChargeInfoSize + SS7_ISUP_MSG_CHG_MIN_SIZE <= strData.Length()    /* Charge information IE length */
                   )
                {
                    /* Basic validation successful, we can use this ss7 raw data to write mandatory IEs */
                    /* Insert the 2 mandatory IEs */
                    TB640_SS7_ISUP_WRITE_CHARGE_INFO_TYPE
                    (
                        abyIeBuffer,
                        &un16IeBufferSize,
                        0,
                        pChgMsg->un8ChargeType                                /* Charge info type value */
                    );

                    TB640_SS7_ISUP_WRITE_CHARGE_INFO
                    (
                        abyIeBuffer,
                        &un16IeBufferSize,
                        0,
                        pChgMsg->un8ChargeInfoSize,
                        pChgMsg->aun8ChargeInfo                             /* Charge info array of bytes */
                    );

                    ExtraProtInfo.SetSS7Ie( un16IeBufferSize, abyIeBuffer );

                    ptrOtherCallLeg->SendCallSuppInfo
                    (
                        TBCMC_SUPP_INFO_MSG_TYPE_SS7_CHARGE,
                        &ExtraProtInfo
                    );
                }
            }
        }
        else if ( OtherProtocolType == TBCMC_CALL_PROTOCOL_TYPE_SIP )
        {
            ExtraProtInfo.SetSipStatusCode (SIP_STATUS_183_SESSION_PROGRESS);
            ptrOtherCallLeg->SendCallSuppInfo
            (
                TBCMC_SUPP_INFO_MSG_TYPE_CALL_PROGRESS,
                &ExtraProtInfo
            );
        }
    }

    return TBX_RESULT_OK;
}


TBX_RESULT CTBCAFBridge::OnSuppInfoUnrecognizedMSU( PCTBCAFCallLeg in_pCallLeg, CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute )
{
    TBX_RESULT            Result = TBX_RESULT_INVALID_STATE;
    PTRCTBCAFCallLeg    ptrOtherCallLeg;

    LogTrace( TBCAF_TRACE_LEVEL_2, "CTBCAFBridge::for Leg 0x%08X",
        in_pCallLeg->GetLegId() );

    ptrOtherCallLeg = GetOtherLegSmartPtr( in_pCallLeg );
    if( ptrOtherCallLeg != NULL && !ptrOtherCallLeg->IsTerminating() )
    {
        TBCMC_CALL_PROTOCOL_TYPE     ProtocolType = ptrOtherCallLeg->GetAttributes().GetProtocolType();
        
        if( ProtocolType == TBCMC_CALL_PROTOCOL_TYPE_SS7 ||
            ProtocolType == TBCMC_CALL_PROTOCOL_TYPE_SIP )        /* For SIP-I, the message will be dropped in case of normal SIP */
        {
            /* Forward to other leg, using the raw buffer copied in CTBCAFCallBehaviorHeaderForward */
            ptrOtherCallLeg->SendCallSuppInfo( TBCMC_SUPP_INFO_MSG_TYPE_SS7_UNRECOGNIZED_MSU );
            
        }
        /*else
        {
            ptrOtherCallLeg->SetSs7RawDataToTransmit(NULL);
        }*/
        Result = TBX_RESULT_OK;
    }

    return Result;
}

TBX_RESULT CTBCAFBridge::OnSuppInfoConfusion
( 
    IN        PCTBCAFCallLeg in_pCallLeg, 
    IN        CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute 
)
{
    LogTrace( TBCAF_TRACE_LEVEL_2, "CTBCAFBridge::OnSuppInfoConfusion for Leg 0x%08X",
        in_pCallLeg->GetLegId() );

    /* On confusion, we never forward to other call leg, so if SS7 raw data was forwarded, we want to remove it */
    PTRCTBCAFCallLeg    ptrOtherCallLeg;
    ptrOtherCallLeg = GetOtherLegSmartPtr( in_pCallLeg );
    if( ptrOtherCallLeg != NULL && !ptrOtherCallLeg->IsTerminating() )
    {
        CTBCAFPtr<CTBCMCSs7RawData> ptrNull; 
        ptrNull = NULL;
        ptrOtherCallLeg->EmptySs7RawDataToTransmit();
    }

    return TBX_RESULT_INVALID_STATE;
}

TBX_RESULT CTBCAFBridge::OnSuppInfoDefault
( 
    IN        PCTBCAFCallLeg in_pCallLeg, 
    IN        TBCMC_SUPP_INFO_MSG_TYPE     in_SuppInfoType, 
    IN        CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute 
)
{
    TBX_RESULT            Result = TBX_RESULT_INVALID_STATE;

    LogTrace( TBCAF_TRACE_LEVEL_2, "CTBCAFBridge::OnSuppInfoDefault for Leg 0x%08X",
        in_pCallLeg->GetLegId() );

    //For SPIROU, forward message to other leg by default
    if (in_ProtocolAttribute.GetPtr()->Cmn.Type == TBCMC_CALL_PROTOCOL_TYPE_SS7 &&
        in_ProtocolAttribute.GetPtr()->Ss7Attribute.ProtocolVariant == TBCMC_SS7_ISUP_PROTOCOL_VARIANT_SPIROU )
    {
        PTRCTBCAFCallLeg    ptrOtherCallLeg;
        ptrOtherCallLeg = GetOtherLegSmartPtr( in_pCallLeg );
        if( ptrOtherCallLeg != NULL && !ptrOtherCallLeg->IsTerminating() )
        {
            if( ptrOtherCallLeg->GetAttributes().GetProtocolType() == TBCMC_CALL_PROTOCOL_TYPE_SS7 )
            {
                /* Forward to other leg */
                ptrOtherCallLeg->SendCallSuppInfo( in_SuppInfoType, &in_ProtocolAttribute );
            }
            Result = TBX_RESULT_OK;
        }
    }
    return Result;
}

TBX_RESULT CTBCAFBridge::OnLegEvent
(
  IN    PCTBCAFCallLeg                in_pCallLeg,
  IN    PITBCMCEvent                in_pEvent
)
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )
    CTBCMCLegError            LegError;

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::OnLegEvent )
    {
        LogTrace( TBCAF_TRACE_LEVEL_0, "CTBCAFBridge::OnLegEvent: 0x%08X\n", in_pCallLeg->GetLegId() );

        switch( in_pEvent->GetType() )
        {
            case TBCMC_EVENT_TYPE_TIMEOUT:
            {
                LogTrace( TBCAF_TRACE_LEVEL_ERROR, "CTBCAFBridge::OnLegEvent: Received unhandled timeout. A behavior should have catched it, but did not!\n" );
            } break;

            case TBCMC_EVENT_TYPE_TERMINATE:
            {
                in_pCallLeg->TerminateCall( TBCMC_CALL_REASON_CODE_TOOLPACK_NORMAL );
            } break;

            default:
                LogTrace( TBCAF_TRACE_LEVEL_2, "CTBCAFBridge::OnLegEvent: Unhandled event %u for leg 0x%08X\n",
                    in_pEvent->GetType(),
                    in_pCallLeg->GetLegId() );
        }

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
        delete in_pEvent;
    }

    RETURN;
TBCAF_MUTEX_GET_SCOPE_END( &mMutex )
}


TBX_RESULT CTBCAFBridge::OnLegError
(
  IN    PCTBCAFCallLeg                in_pCallLeg,
  IN    CTBCMCLegError &             in_Error
)
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::OnLegError )
    {
        if( in_Error.mMsgId == TBCMC_MSG_ID_CMD_CALL_LEG_TERMINATE )
        {
            LogTrace( TBCAF_TRACE_LEVEL_ERROR, "CTBCAFBridge::OnLegError for Leg 0x%08X Error(%s 0x%08x)\n",
                in_pCallLeg->GetLegId(), in_Error.what(), in_Error.mResult );

            /* Error upon call termination. Free leg immediately */
            if( in_pCallLeg->IsJoined() )
            {
                in_pCallLeg->TerminateCall( TBCMC_CALL_REASON_CODE_TOOLPACK_RESOURCE_ERROR );
            }
            else
            {
                in_pCallLeg->FreeLeg();
            }
        }
        else if( in_Error.IsDataPathErrors() )
        {
            TBCAF_TRACE_LEVEL        TraceLevel = TBCAF_TRACE_LEVEL_2;
            if( in_Error.mLegErrors.FromNetwork.fExcessiveIpPortChanges )
            {
                /* This error is considered fatal */
                TraceLevel = TBCAF_TRACE_LEVEL_ERROR;
            }
            LogTrace( TraceLevel, FRED "CTBCAFBridge::OnLegError for Leg 0x%08X Data path error(%s)\n",
                in_pCallLeg->GetLegId(), in_Error.GetDatapathErrorsStr().c_str() );
            if( TraceLevel == TBCAF_TRACE_LEVEL_ERROR)
            {
                // Kick leg termination
                in_pCallLeg->TerminateCall( TBCMC_CALL_REASON_CODE_TOOLPACK_RESOURCE_ERROR );
            }
        }
        else
        {
            TBCAF_TRACE_LEVEL    TraceLevel = TBCAF_TRACE_LEVEL_ERROR;

            if( in_pCallLeg->IsTerminating() )    TraceLevel = TBCAF_TRACE_LEVEL_0;

            LogTrace( TraceLevel, "CTBCAFBridge::OnLegError for Leg 0x%08X on MsgId 0x%08X Error(%s 0x%08x)\n",
                in_pCallLeg->GetLegId(), (unsigned int)in_Error.mMsgId, in_Error.what(), in_Error.mResult );

            #if 0    /* We no more drop the leg, here is not the right place to determine if an error is fatal to a leg or not
                       (for example, is it fatal that a call to PlayEvent has failed?  Behavior that made the operation can decide
                       but we can't take a generic decision here in the call flow class) */
            // Kick leg termination
            in_pCallLeg->TerminateCall( TBCMC_CALL_REASON_CODE_TOOLPACK_RESOURCE_ERROR );
            #endif
        }

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
    }

    RETURN;
TBCAF_MUTEX_GET_SCOPE_END( &mMutex )
}

/*******************************************************************************************************************
 * Leg Interface
 ******************************************************************************************************************/



TBX_RESULT CTBCAFBridge::OnSyncDone
(
  IN    PCTBCAFCallLeg                            in_pCallLeg
)
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )

    PTRCTBCAFCallLeg    ptrOtherLeg;

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAFCODE( CTBCAFBridge::OnSyncDone )
    {
        TBCAFPrintCallLegInfo
        (
            TBCAF_TRACE_LEVEL_1,
            in_pCallLeg->GetLegId(),
            &in_pCallLeg->GetAttributes(),
            "CTBCAFBridge::OnSyncDone",
            this
        );

        /* Test that we have one active incoming and outgoing leg */
        if( mptrActiveCallLegIn == NULL || mptrActiveCallLegOut == NULL )
        {
            std::vector< PTRCTBCAFCallLeg >                aLegs;
            std::vector< PTRCTBCAFCallLeg >::iterator    itLeg;

            GetLegs( &aLegs );

            LogTrace( TBCAF_TRACE_LEVEL_3, "CTBCAFBridge::OnSyncDone Missing active leg => Terminating %u call legs\n", aLegs.size() );

            for( itLeg = aLegs.begin(); itLeg != aLegs.end(); ++itLeg )
            {
                (*itLeg)->TerminateCall( TBCMC_CALL_REASON_CODE_TOOLPACK_SYNC_DROP );
            }
        }

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Exception handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_EXCEPTION_HANDLING

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_ERROR_HANDLING( CAF_VERBOSE )
    {
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CAF_CLEANUP
    {
    }

    RETURN;
TBCAF_MUTEX_GET_SCOPE_END( &mMutex )
}


TBX_RESULT CTBCAFBridge::OnEventCollected
(
    PCTBCAFCallLeg                                in_pCallLeg,
    const CTBCAFString&                            in_strEvent,
    const CTBCMC_EVENT_COLLECTED_ATTRIBUTE&        in_EventAttr
)
{
    LogTrace( TBCAF_TRACE_LEVEL_1, "CTBCAFBridge::OnEventCollected for LegId 0x%08x: %s (duration %ums)\n", in_pCallLeg->GetLegId(), in_strEvent.c_str(), in_EventAttr.un32EventDurationMs );

    /* Don't pass to base class CTBCAFCallFlow, not necessary */
    return TBX_RESULT_OK;
}



TBX_RESULT CTBCAFBridge::OnLegProfileChanged
(
  IN    PCTBCAFCallLeg                in_pCallLeg,
  IN    CTBCMC_MEDIA_PROFILE &         in_MediaProfile,
  IN    TBCMC_MEDIA_REASON_CODE        in_Reason,
  IN    TBCMC_CALL_REASON_CODE        in_RefusedReason
)
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )
    /*---------------------------------------------------------------------------------------------------------------------------
     |  Code section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CODE
    {
        TBCAFPrintCallLegInfo
        (
            TBCAF_TRACE_LEVEL_1,
            in_pCallLeg->GetLegId(),
            &in_pCallLeg->GetAttributes(),
            "CTBCAFBridge::OnLegProfileChanged",
            this
        );

        TBX_EXIT_SUCCESS( TBX_RESULT_OK );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Error handling section
     *--------------------------------------------------------------------------------------------------------------------------*/
    ERROR_HANDLING
    {
        LogTrace( TBCMC_TRACE_LEVEL_ERROR,
            "CTBCAFBridge::OnLegProfileChanged: %s (0x%08X) 0x%08X %s:%d",
            TBX_ERROR_DESCRIPTION,
            TBX_ERROR_LEVEL,
            (int)TBX_ERROR_RESULT,
            TBX_ERROR_FILE,
            TBX_ERROR_LINE );
    }

    /*---------------------------------------------------------------------------------------------------------------------------
     |  Cleanup section
     *--------------------------------------------------------------------------------------------------------------------------*/
    CLEANUP
    {
    }

    RETURN;
TBCAF_MUTEX_GET_SCOPE_END( &mMutex )
}

TBX_VOID CTBCAFBridge::GetBridgedLegTermReason
(
  IN    TBCMC_CALL_REASON &                 in_Reason,
  OUT    TBCMC_CALL_REASON &                 out_ReasonForBridgedLeg
)
{
    memcpy (&out_ReasonForBridgedLeg, &in_Reason, sizeof (out_ReasonForBridgedLeg));
    /* By default, the bridged leg should be terminated with the same reason as the other leg.
       However, some reason code with special signification must be remapped */
    switch( in_Reason.Reason )
    {
        case TBCMC_CALL_REASON_CODE_401_UNAUTHORIZED:
        case TBCMC_CALL_REASON_CODE_407_PROXY_AUTH_REQD:
            out_ReasonForBridgedLeg.Reason = TBCMC_CALL_REASON_CODE_403_FORBIDDEN;
            break;
        default:
            /* Already copied by the memcpy above */
            break;
    }
}

CTBCAFBridgeOptions::CTBCAFBridgeOptions()
 : mfWarnIfToneDetectionEnabled( TBX_TRUE )
{
    
}


CTBCAFBridgeOptions::CTBCAFBridgeOptions( const CTBCAFBridgeOptions& in_Copy )
{
    *this = in_Copy;
}

    
CTBCAFBridgeOptions::~CTBCAFBridgeOptions()
{
}


const CTBCAFBridgeOptions & CTBCAFBridgeOptions::operator=( const CTBCAFBridgeOptions& in_Copy )
{
    mfWarnIfToneDetectionEnabled     = in_Copy.mfWarnIfToneDetectionEnabled;
    return *this;
}

/*--------------------------------------------------------------------------------------------------------------------------------
 |  Namespace declaration
 *------------------------------------------------------------------------------------------------------------------------------*/
} /* namespace TBCAF */

 

posted on 2015-12-29 10:30  齐文宣  阅读(316)  评论(0)    收藏  举报

导航