sipvoipprovider/src/svpaudioutility.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 20:12:36 +0200
changeset 0 a4daefaec16c
permissions -rw-r--r--
Revision: 201001 Kit: 201003

/*
* Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Provides static utility functions for SVP
*
*/


#include <mceaudiostream.h>
#include <mcertpsource.h>
#include <mceaudiocodec.h>
#include <mcespeakersink.h>
#include <mcemicsource.h>
#include <AudioPreference.h>
#include "svpaudioutility.h"
#include "svplogger.h"
#include "svpconsts.h"
#include "svpsessionbase.h"
#include "svpemergencysession.h"
#include "svpholdcontext.h"
#include "svpholdcontroller.h"

// LOCAL CONSTANTS
// Constants for VoIP uplink audio preferences, renamed for better
// readability and to clarify between IB/OB DTMF's. 
// See <audiopreference.h> for more information.
// Inband signalling uplink preference (i.e inband DTMF)
const TUint KSVPAudioPrefUplinkIbDtmf = KAudioPrefVoipAudioUplinkNonSignal;
// Outband signalling uplink preference (i.e outband DTMF)
const TUint KSVPAudioPrefUplinkOobDtmf = KAudioPrefVoipAudioUplink;


// ---------------------------------------------------------------------------
// SVPAudioUtility::IsDownlinkStream
// ---------------------------------------------------------------------------
//
TBool SVPAudioUtility::IsDownlinkStream( CMceAudioStream& aStream )
    {
    SVPDEBUG2( "SVPAudioUtility::IsDownlinkStream source: 0x%x", aStream.Source() );
    
    if ( aStream.Source() && KMceRTPSource == aStream.Source()->Type() )
        {
        SVPDEBUG1( "SVPAudioUtility::IsDownlinkStream RTP SOURCE => DOWNLINK" );
        return ETrue;
        }
    else
        {
        SVPDEBUG1( "SVPAudioUtility::IsDownlinkStream EFalse" );
        
        return EFalse;
        }
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::SetPriorityCodecValuesL
// ---------------------------------------------------------------------------
//
TBool SVPAudioUtility::SetPriorityCodecValuesL(
    CMceAudioStream& aAudioInStream,
    CMceAudioStream& aAudioOutStream )
    {
    SVPDEBUG1("SVPAudioUtility::SetPriorityCodecValuesL In");
    
    // set MMF codec priorities  for all codecs in both streams
    const TInt inCodecCount = aAudioInStream.Codecs().Count();
    SVPDEBUG2(
        "SVPAudioUtility::SetPriorityCodecValuesL codeccount IN: %d",
            inCodecCount )
     
    const TInt outCodecCount = aAudioOutStream.Codecs().Count();
    SVPDEBUG2(
        "SVPAudioUtility::SetPriorityCodecValuesL codeccount OUT: %d",
            outCodecCount )
    
    const TBool inDtmf = SVPAudioUtility::SetDtmfPriorityL( aAudioInStream );
    const TBool outDtmf = SVPAudioUtility::SetDtmfPriorityL( aAudioOutStream );
    
    // inDtmf and outDtmf _must_ match. Either inband (both EFalse) or outband
    // (both ETrue).
    if ( inDtmf != outDtmf )
        {
        SVPDEBUG1("SVPAudioUtility::SetPriorityCodecValuesL KErrNotFound");
        User::Leave( KErrNotFound );
        }
    
    SVPDEBUG1( "SVPAudioUtility::SetPriorityCodecValuesL set IN priorities" );
    
    SetAudioCodecPrioritiesL( aAudioInStream, KAudioPrefVoipAudioDownlink );
    
    // Check which version of DTMF's are we using, inband or outband.
    TBool outband( EFalse );
    TUint uplinkPreference = KSVPAudioPrefUplinkIbDtmf;
    if ( inDtmf && outDtmf )
        {
        SVPDEBUG1(
            "SVPAudioUtility::SetPriorityCodecValuesL change to OOB DTMF" );
        
        uplinkPreference = KSVPAudioPrefUplinkOobDtmf;
        outband = ETrue;
        }
    // else inband used.
    
    SVPDEBUG1( "SVPAudioUtility::SetPriorityCodecValuesL set OUT priorities" );
    
    SetAudioCodecPrioritiesL( aAudioOutStream, uplinkPreference );
    
    SVPDEBUG1( "SVPAudioUtility::SetPriorityCodecValuesL Out" );
    
    return outband;
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::SetDtmfPriorityL
// ---------------------------------------------------------------------------
//
TBool SVPAudioUtility::SetDtmfPriorityL( CMceAudioStream& aAudioStream )
    {
    SVPDEBUG1( "SVPAudioUtility::SetDtmfPriorityL In" );
    
    const RPointerArray<CMceAudioCodec>& codecs = aAudioStream.Codecs();
    TInt codCount( codecs.Count() );
    
    // loop through codecs in in stream
    while ( codCount )
        {
        codCount--;
        
        SVPDEBUG2( "SVPAudioUtility::SetDtmfPriorityL, round: %d", codCount );
        
        // Check if codec is DTMF, note the return values of CompareF
        if( !codecs[ codCount ]->SdpName().CompareF( KTELEVENT ) )
            {
            SVPDEBUG1( "SVPAudioUtility::SetDtmfPriorityL ETrue" );
            
            SVPDEBUG2( "SVPAudioUtility::SetDtmfPriorityL curr.prio: %d",
                codecs[codCount]->MMFPriority() )
            SVPDEBUG2( "SVPAudioUtility::SetDtmfPriorityL curr.pref: 0x%x",
                codecs[codCount]->MMFPriorityPreference() )
            
            // Set the priorities.
            codecs[ codCount ]->SetMMFPriorityL( KAudioPriorityDTMFString );
            codecs[ codCount ]->SetMMFPriorityPreferenceL( KAudioDTMFString );
            return ETrue;
            }
        }
    
    SVPDEBUG1( "SVPAudioUtility::SetDtmfPriorityL EFalse" );
    return EFalse;
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::SetAudioCodecPrioritiesL
// ---------------------------------------------------------------------------
//
void SVPAudioUtility::SetAudioCodecPrioritiesL(
    CMceAudioStream& aAudioStream,
    TUint aAudioPref )
    {
    SVPDEBUG2( "SVPAudioUtility::SetAudioCodecPrioritiesL aAudioPref: 0x%x",
        aAudioPref );
    
    const RPointerArray<CMceAudioCodec>& codecs = aAudioStream.Codecs();
    TInt codCount( codecs.Count() );
    
    // loop through codecs in in stream
    while ( codCount )
        {
        codCount--;
        
        SVPDEBUG2( "SVPAudioUtility::SetAudioCodecPrioritiesL, round: %d",
            codCount );
        
        // Handle only real audio codecs.
        if( codecs[ codCount ]->SdpName().CompareF( KTELEVENT ) )
            {
            SVPDEBUG2( "SVPAudioUtility::SetAudioCodecPrioritiesL curr.prio: %d",
                codecs[codCount]->MMFPriority() )
            SVPDEBUG2( "SVPAudioUtility::SetAudioCodecPrioritiesL curr.pref: 0x%x",
                codecs[codCount]->MMFPriorityPreference() )
                
            // Priority is always the same for VoIP.
            codecs[ codCount ]->SetMMFPriorityL( KAudioPriorityPhoneCall );
            codecs[ codCount ]->SetMMFPriorityPreferenceL( aAudioPref );
            }
        } 
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::SetAudioCodecPrioritiesL
// ---------------------------------------------------------------------------
//
void SVPAudioUtility::SetAudioStreamPrioritiesL(
    CMceMediaStream& aMediaStream,
    CMceMediaStream& aBoundStream )
    {
    SVPDEBUG1( "SVPAudioUtility::SetAudioStreamPrioritiesL In" );
    
    if ( KMceAudio != aMediaStream.Type() ||
         KMceAudio != aBoundStream.Type() )
        {
        SVPDEBUG1( "SVPAudioUtility::SetAudioStreamPrioritiesL KErrArgument" );
        SVPDEBUG2( "SVPAudioUtility::SetAudioStreamPrioritiesL media.Type: %u",
            aMediaStream.Type() );
        SVPDEBUG2( "SVPAudioUtility::SetAudioStreamPrioritiesL bound.Type: %u",
            aBoundStream.Type() );
        
        User::Leave( KErrArgument );
        }
    // else stream types are OK, thus we proceed.
    
    // Set the codec MMF priorities here, first get the audiostreams.
    CMceAudioStream& stream = static_cast<CMceAudioStream&>( aMediaStream );
    CMceAudioStream& bound = static_cast<CMceAudioStream&>( aBoundStream );
    
    if ( SVPAudioUtility::IsDownlinkStream( stream ) )
        {
        SVPAudioUtility::SetPriorityCodecValuesL( stream, bound );
        }
    else
        {
        SVPAudioUtility::SetPriorityCodecValuesL( bound, stream );
        }
    
    SVPDEBUG1( "SVPAudioUtility::SetAudioStreamPrioritiesL Out" );
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::EnableSpeakerSinkL
// ---------------------------------------------------------------------------
//
void SVPAudioUtility::EnableSpeakerSinkL( 
    const RPointerArray< CMceMediaSink >& aSink )
    {
    TInt snkCount( aSink.Count() );
    while ( snkCount )
        {
        snkCount--;
        if ( KMceSpeakerSink == aSink[ snkCount ]->Type() && 
             !aSink[ snkCount ]->IsEnabled() )
            {
            SVPDEBUG1( "SVPAudioUtility::EnableSpeakerSinkL Speaker found" );
            
            aSink[ snkCount ]->EnableL();
            
            SVPDEBUG1( "SVPAudioUtility::EnableSpeakerSinkL Speaker ENABLED" );
            }
        } 
    }
    
// ---------------------------------------------------------------------------
// SVPAudioUtility::DisableSpeakerSinkL
// ---------------------------------------------------------------------------
//
void SVPAudioUtility::DisableSpeakerSinkL( 
    const RPointerArray< CMceMediaSink >& aSink )
    {
    TInt snkCount( aSink.Count() );
    while ( snkCount )
        {
        snkCount--;
        if ( KMceSpeakerSink == aSink[ snkCount ]->Type() &&
             aSink[ snkCount ]->IsEnabled() )
            {
            SVPDEBUG1( "SVPAudioUtility::DisableSpeakerSinkL Speaker found" );
            
            aSink[ snkCount ]->DisableL();
            
            SVPDEBUG1( "SVPAudioUtility::DisableSpeakerSinkL Speaker DISABLED" );
            }
        } 
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::EnableMicSourceL
// ---------------------------------------------------------------------------
//
void SVPAudioUtility::EnableMicSourceL( CMceMediaSource& aMicSource )
    {            
    if ( KMceMicSource == aMicSource.Type() && !aMicSource.IsEnabled() )
        {
        SVPDEBUG1("SVPAudioUtility::EnableMicSourceL Mic found");
        
        aMicSource.EnableL();
        
        SVPDEBUG1("SVPAudioUtility::EnableMicSourceL Mic ENABLED");
        }
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::DisableMicSourceL
// ---------------------------------------------------------------------------
//
void SVPAudioUtility::DisableMicSourceL( CMceMediaSource& aMicSource )
    {
    if ( KMceMicSource == aMicSource.Type() && aMicSource.IsEnabled() )
        {
        SVPDEBUG1( "SVPAudioUtility::DisableMicSourceL Mic found" );
        
        aMicSource.DisableL();
        
        SVPDEBUG1( "SVPAudioUtility::DisableMicSourceL Mic DISABLED" );
        }
    }
    
// ---------------------------------------------------------------------------
// SVPAudioUtility::EnableSpeakerSinksL
// ---------------------------------------------------------------------------
//
void SVPAudioUtility::EnableSpeakerSinksL(
    const RPointerArray< CMceMediaStream >& aStreams )
    {
    SVPDEBUG1("SVPAudioUtility::EnableSpeakerSinksL In");
    
    TInt index( aStreams.Count() );
    while( index-- )
        {
        if ( KMceAudio == aStreams[ index ]->Type() )
            {
            EnableSpeakerSinkL( aStreams[ index ]->Sinks() );
            }
        
        if ( KMceAudio == aStreams[ index ]->BoundStreamL().Type() )
            {
            EnableSpeakerSinkL( aStreams[ index ]->BoundStreamL().Sinks() );
            }
        }
    
    SVPDEBUG1("SVPAudioUtility::EnableSpeakerSinksL Out");
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::DisableMicSourceL
// ---------------------------------------------------------------------------
//
void SVPAudioUtility::DisableMicSourceL( CMceMediaStream& aStream )
    {
    SVPDEBUG1("SVPAudioUtility::DisableMicSourceL CMceMediaStream In");
    
    CMceMediaSource* source = NULL;
    source = aStream.Source();
    if ( source )
        {
        SVPDEBUG1("SVPAudioUtility::DisableMicSourceL aStream");
        
        DisableMicSourceL( *source );
        }
    
    if ( aStream.BoundStream() )
        {
        source = aStream.BoundStreamL().Source();
        if ( source )
            {
            SVPDEBUG1("SVPAudioUtility::DisableMicSourceL BoundStream");
            
            DisableMicSourceL( *source );
            }
        }
        
    SVPDEBUG1("SVPAudioUtility::DisableMicSourceL CMceMediaStream Out");
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::FindCodec
// ---------------------------------------------------------------------------
//
CMceAudioCodec* SVPAudioUtility::FindCodec( CMceAudioStream& aAudiostream,
    const TDesC8& aCodecname )
    {
    SVPDEBUG1("SVPAudioUtility::FindCodec In");
    
    const RPointerArray<CMceAudioCodec>& codecs = aAudiostream.Codecs();
    TInt codecCount = codecs.Count();
    while ( codecCount )
        {
        codecCount--;
        if ( !codecs[codecCount]->SdpName().CompareF( aCodecname ) )
            {
            SVPDEBUG1("SVPAudioUtility::SVPAudioUtility Codec found");
            
            return codecs[codecCount];
            }
        }
    
    SVPDEBUG1("SVPAudioUtility::FindCodec Out NULL");
    return NULL;
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::RemoveCodecL
// ---------------------------------------------------------------------------
//
void SVPAudioUtility::RemoveCodecL( CMceAudioStream& aAudiostream,
    const TDesC8& aCodecname )
    {
    SVPDEBUG1("SVPAudioUtility::RemoveCodecL In");
    
    CMceAudioCodec* codec = SVPAudioUtility::FindCodec( aAudiostream,
        aCodecname );
    
    while ( codec )
        {
        SVPDEBUG1("SVPAudioUtility::RemoveCodecL Removing");
        
        aAudiostream.RemoveCodecL( *codec );
        codec = SVPAudioUtility::FindCodec( aAudiostream, aCodecname );
        }
    
    SVPDEBUG1("SVPAudioUtility::RemoveCodecL Out");
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::MmfPriorityUpdateNeededL
// ---------------------------------------------------------------------------
//
TBool SVPAudioUtility::MmfPriorityUpdateNeededL(
    const RPointerArray<CMceMediaStream>& aStreams )
    {
    SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL In" )
    
    // We need to check if DTMF codec is found and then check uplink stream
    // MMF priorities.
    // 1) If DTMF codec is found and uplink stream codecs have preference
    //    KSVPAudioPrefAudioUplinkOobDtmf no update is needed.
    // 2) If DTMF codec is not found and uplink stream codecs have preference
    //    KSVPAudioPrefAudioUplinkIbDtmf no update is needed.
    // 3) In other cases we need to do MMF preference/priority update.
    
    // In order to do this we need to find uplink audio streams, check whether
    // the stream has DTMF codec and then check which MMF preference the codec
    // codec has. We may have multiple streams, but for simplicity sake if
    // we find just one stream needing priority/preference update, we return
    // ETrue as update need.
    TInt strmCount( aStreams.Count() );
    
    SVPDEBUG2( "SVPAudioUtility::MmfPriorityUpdateNeededL strmCount: %d",
        strmCount )
    
    while ( strmCount )
        {
        SVPDEBUG2( "SVPAudioUtility::MmfPriorityUpdateNeededL tb checked",
            strmCount )
        
        strmCount--;
        
        // Basic assertions. Streams have to be KMceAudio and 'main' stream
        // must have a bound stream.
        __ASSERT_ALWAYS( KMceAudio == aStreams[strmCount]->Type(),
            User::Leave( KErrArgument ) );
        __ASSERT_ALWAYS( aStreams[strmCount]->BoundStream(),
            User::Leave( KErrArgument ) );
        __ASSERT_ALWAYS( KMceAudio == aStreams[strmCount]->BoundStreamL().Type(),
            User::Leave( KErrArgument ) );
        
        // Now that we are clear from the asserts, we can safely do the casts
        // and find the uplink stream for priority/preference checking.
        CMceAudioStream* audioStream =
            static_cast<CMceAudioStream*>( aStreams[strmCount] );
        CMceAudioStream& boundStream =
            static_cast<CMceAudioStream&>( audioStream->BoundStreamL() );
        
        CMceAudioStream* uplinkStream = NULL;
        
        if ( !IsDownlinkStream( *audioStream ) )
            {
            SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL main is uplink" )
            
            uplinkStream = audioStream;
            }
        else if ( !IsDownlinkStream( boundStream ) )
            {
            SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL bound is uplink" )
            
            uplinkStream = &boundStream;
            }
        
        // Next assert handles the missing else branch.
        __ASSERT_ALWAYS( uplinkStream, User::Leave( KErrNotFound ) );
        
        TBool res = MmfPriorityUpdateNeededL( *uplinkStream );
        if ( res )
            {
            SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL ETrue" )
            return ETrue;
            }
        }
    
    SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL EFalse" )
    return EFalse;
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::MmfPriorityUpdateNeededL
// ---------------------------------------------------------------------------
//
TBool SVPAudioUtility::MmfPriorityUpdateNeededL(
    CMceAudioStream& aUplinkStream )
    {
    SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL (stream) In" )
    
    // Check which uplink preference we need to have based whether DTMF codec
    // is part of the codec list.
    TUint uplinkPreference = 0;
    if ( FindCodec( aUplinkStream, KTELEVENT ) )
        {
        SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL (stream) DTMF OB" )
        
        uplinkPreference = KSVPAudioPrefUplinkOobDtmf;
        }
    else
        {
        SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL (stream) DTMF IB" )
        
        uplinkPreference = KSVPAudioPrefUplinkIbDtmf;
        }
    
    // Given stream must have at least one codec in order to do the priority /
    // preference check. This function is private and called inside, thus this
    // assertion just adds to the checks done in caller.
    const RPointerArray<CMceAudioCodec>& codecs = aUplinkStream.Codecs();
    TInt codecCount = codecs.Count();
    
    SVPDEBUG2( "SVPAudioUtility::MmfPriorityUpdateNeededL (stream) codecCount: %d",
        codecCount )
    
    __ASSERT_ALWAYS( codecCount, User::Leave( KErrArgument ) );
    
    while( codecCount )
        {
        SVPDEBUG2( "SVPAudioUtility::MmfPriorityUpdateNeededL (stream) tb checked: %d",
            codecCount )
        
        codecCount--;
        
        SVPDEBUG2( "SVPAudioUtility::MmfPriorityUpdateNeededL curr.prio: %d",
                codecs[codecCount]->MMFPriority() )
        SVPDEBUG2( "SVPAudioUtility::MmfPriorityUpdateNeededL curr.pref: 0x%x",
                codecs[codecCount]->MMFPriorityPreference() )
        
        // Do not include DTMF codec into the preference check. Note CompareF
        // return value also, 0 means match.
        if ( codecs[codecCount]->SdpName().CompareF( KTELEVENT ) &&
            uplinkPreference != codecs[codecCount]->MMFPriorityPreference() )
            {
            SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL (stream) ETrue" )
            
            return ETrue;
            }
        
        // else preferences match, ne-ext please!!!
        }
    
    SVPDEBUG1( "SVPAudioUtility::MmfPriorityUpdateNeededL (stream) EFalse" )
    return EFalse;
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::DtmfActionCapableSession
// ---------------------------------------------------------------------------
//
TBool SVPAudioUtility::DtmfActionCapableSession(
    const CSVPSessionBase& aSession )
    {
    if ( aSession.HasHoldController() &&
         ESVPConnected == aSession.HoldController().HoldState() )
        {
        SVPDEBUG1( "SVPAudioUtility::DtmfActionCapableSession ETrue 1" )
        
        return ETrue;
        }
    else if ( !aSession.HasHoldController() )
        {
        SVPDEBUG1( "SVPAudioUtility::DtmfActionCapableSession ETrue 2" )
        
        return ETrue;
        }
    else
        {
        SVPDEBUG1( "SVPAudioUtility::DtmfActionCapableSession EFalse" )
        
        return EFalse;
        }
    }

// ---------------------------------------------------------------------------
// Check DTMF capability of emergency session
// ---------------------------------------------------------------------------
//
TBool SVPAudioUtility::DtmfActionCapableSession(
    const CSVPEmergencySession& aSession )
    {
    if ( aSession.HasHoldController() &&
         ESVPConnected == aSession.HoldController().HoldState() )
        {
        SVPDEBUG1( "SVPAudioUtility::DtmfActionCapableSession ETrue 1" )
        
        return ETrue;
        }
    else if ( !aSession.HasHoldController() )
        {
        SVPDEBUG1( "SVPAudioUtility::DtmfActionCapableSession ETrue 2" )
        
        return ETrue;
        }
    else
        {
        SVPDEBUG1( "SVPAudioUtility::DtmfActionCapableSession EFalse" )
        
        return EFalse;
        }
    }

// ---------------------------------------------------------------------------
// SVPAudioUtility::DtmfActionCapableStream
// ---------------------------------------------------------------------------
//
TBool SVPAudioUtility::DtmfActionCapableStream(
    const CMceMediaStream& aStream )
    {
    // We used to check for source's DtmfAvailable and DtmfActive attributes,
    // but those are IPC calls which are not preferred for DTMF's real-time
    // nature. Thus leaving those out and letting the server return us a
    // error code if those attributes are not correct for DTMF sending
    // actually does the same thing but improves performance.
    // Thus what once was three IPC calls is now just one.
    TBool ret = EFalse;
    CMceMediaSource* source = aStream.Source();
    
#ifdef _DEBUG
    SVPDEBUG2( "SVPAudioUtility::DtmfActionCapableStream type: %d", aStream.Type() )
    SVPDEBUG2( "SVPAudioUtility::DtmfActionCapableStream source: 0x%x", source )
    if ( source )
        {
        SVPDEBUG2( "SVPAudioUtility::DtmfActionCapableStream enabled: %d", source->IsEnabled() )
        }
#endif
    
    if ( KMceAudio == aStream.Type() && source && source->IsEnabled() )
        {
        ret = ETrue;
        }
    
    SVPDEBUG2( "SVPAudioUtility::DtmfActionCapableStream ret: %d", ret )
    
    return ret;
    }