/*
* Copyright (c) 2002-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:  Server-side sub-session of Accessory Audio Control
*
*/



// INCLUDE FILES
#include "AccSrvSubAudioControl.h"
#include "acc_debug.h"

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES

// CONSTANTS

// MACROS

// LOCAL CONSTANTS AND MACROS

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

// ============================= LOCAL FUNCTIONS ===============================

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::CAccSrvSubAudioControl
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CAccSrvSubAudioControl::CAccSrvSubAudioControl(
    CASYProxyAPI* aProxy,
    CAccSrvConnectionController* aConnectionController,
    CAccSrvServerModel* aServerModel,
    TUint aCallerThreadID )
    : CAccSrvSubControl ( aProxy, aConnectionController, aServerModel ),
      iCallerThreadID( aCallerThreadID )
    {
    }
// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::ConstructL()
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::ConstructL()" );

    CAccSrvSubControl::ConstructL();

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::ConstructL() - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//

CAccSrvSubAudioControl* CAccSrvSubAudioControl::NewL(
    CASYProxyAPI* aProxy,
    CAccSrvConnectionController* aConnectionController,
    CAccSrvServerModel* aServerModel,
    TUint aCallerThreadID )
    {
    if ( !aProxy )
        {
        User::Leave( KErrArgument );
        }

    CAccSrvSubAudioControl* self = new (ELeave) CAccSrvSubAudioControl( aProxy,
                                                                        aConnectionController,
                                                                        aServerModel,
                                                                        aCallerThreadID );

    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    return self;
    }

// Destructor
CAccSrvSubAudioControl::~CAccSrvSubAudioControl()
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::~CAccSrvSubAudioControl()" );

    RMessage2 dummy;

    CAccSrvSubAudioControl::CancelAccessoryAudioLinkOpen( dummy );//For iAccessoryAudioLinkOpenMsg
    CAccSrvSubAudioControl::CancelAccessoryAudioLinkClose( dummy );//For iAccessoryAudioLinkCloseMsg
    CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkOpened( dummy );//For iNotifyAccessoryAudioLinkOpenedMsg
    CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkClosed( dummy );//For iNotifyAccessoryAudioLinkClosedMsg
    
    if ( iServerModel )
        {       
        iServerModel->SetAudioLinkOpenCancelled( EFalse );
        iServerModel->SetAudioLinkCloseCancelled( EFalse );
        }

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::~CAccSrvSubAudioControl - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::NotifyAccessoryAudioLinkOpened
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::NotifyAccessoryAudioLinkOpened( const RMessage2& aMessage )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::NotifyAccessoryAudioLinkOpened()" );

    iConnectionController->NotificationQueue().RegisterControlMessage( EAccessoryAudioLinkOpened,
                                                                       this );

    iNotifyAccessoryAudioLinkOpenedMsg = aMessage;//Store RMessage2 for future completion

    // If message is null, there is no pending request and no filtering needed
    if ( !iAccessoryAudioLinkOpenMsg.IsNull() )
        {
        //NotifyAccessoryAudioLinkOpened() notification is filtered
        //for AccessoryAudioLinkOpen() caller thread.
        //In this case NotifyAccessoryAudioLinkOpened() notification
        //is ordered after AccessoryAudioLinkOpen() is sent.
        iConnectionController->ServerModel().SetMsgThreadIDFilter( iCallerThreadID,
                                                                   EAccessoryAudioLinkOpened );
        }

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::NotifyAccessoryAudioLinkOpened - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::NotifyAccessoryAudioLinkClosed
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::NotifyAccessoryAudioLinkClosed( const RMessage2& aMessage )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::NotifyAccessoryAudioLinkClosed()" );

    iConnectionController->NotificationQueue().RegisterControlMessage( EAccessoryAudioLinkClosed,
                                                                       this );
    iNotifyAccessoryAudioLinkClosedMsg = aMessage;//Store RMessage2 for future completion

    // If message is null, there is no pending request and no filtering needed
    if ( !iAccessoryAudioLinkCloseMsg.IsNull() )
        {
        //NotifyAccessoryAudioLinkClosed() notification is filtered
        //for AccessoryAudioLinkClose() caller thread.
        //In this case NotifyAccessoryAudioLinkClosed() notification
        //is ordered after AccessoryAudioLinkClose() is sent.
        iConnectionController->ServerModel().SetMsgThreadIDFilter( iCallerThreadID,
                                                                   EAccessoryAudioLinkClosed );
        }

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::NotifyAccessoryAudioLinkClosed - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::AccessoryAudioLinkOpenL
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::AccessoryAudioLinkOpenL( const RMessage2& aMessage )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::AccessoryAudioLinkOpenL()" );

    TAccPolGenericID     genericID;
    TAccSrvGenericIDPckg genericIDPckg( genericID );
    TAccAudioType        audioType( EAccMonoAudio ); // Initialization value
    TAccSrvAudioTypePckg audioTypePckg( audioType );

    aMessage.ReadL( KAccServParamPosFirst, genericIDPckg );
    aMessage.ReadL( KAccServParamPosSecond, audioTypePckg );
    
    //Precondition
    iServerModel->IsConnectedL( genericID );//Leaves with KErrArgument if the accessory is not connected

    iServerModel->SetAudioType( audioType );//Notice, This works for single client (Server model can store only one value)

    iConnectionController->NotificationQueue().RegisterControlMessage( EAccessoryAudioLinkOpen,
                                                                       this );
    
    TInt bluetoothAudioLinkOpenReqs( iConnectionController->NotificationQueue().ControlMessagesWaiting( EBluetoothAudioLinkOpenReq ) );
    if ( bluetoothAudioLinkOpenReqs > 0 )
        {
        //Send bluetooth audio link notification now.
        iServerModel->SetBluetoothAudioLinkOpenReqPostponed( EFalse );
        iConnectionController->NotificationQueue().CompleteControlMessageL( EBluetoothAudioLinkOpenReq,
                                                                            KErrNone,
                                                                            genericID.UniqueID() );
        }
    else
        {
        //There was not any bluetooth audio link notification waiting at the moment.
        //Bluetooth audio link will be opened immediately when bluetooth audio link notification is set.
        //See EAccSrvNotifyBluetoothAudioLinkOpenReq handling from the control.
        iServerModel->SetBluetoothAudioLinkOpenReqPostponed( ETrue );
        }
    
    iAccessoryAudioLinkOpenMsg = aMessage;//Store RMessage2 for future completion
    
    // If message is null, there is no pending request and no filtering needed
    if ( !iNotifyAccessoryAudioLinkOpenedMsg.IsNull() )
        {
        //NotifyAccessoryAudioLinkOpened notification() is filtered
        //for AccessoryAudioLinkOpen() caller thread
        iConnectionController->ServerModel().SetMsgThreadIDFilter( iCallerThreadID,
                                                                   EAccessoryAudioLinkOpened );
        }

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::AccessoryAudioLinkOpenL - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::AccessoryAudioLinkCloseL
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::AccessoryAudioLinkCloseL( const RMessage2& aMessage )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubBaseConnection::AccessoryAudioLinkCloseL()" );

    TAccPolGenericID     genericID;
    TAccSrvGenericIDPckg genericIDPckg( genericID );
    TAccAudioType        audioType( EAccMonoAudio ); // Initialization value
    TAccSrvAudioTypePckg audioTypePckg( audioType );

    aMessage.ReadL( KAccServParamPosFirst, genericIDPckg );
    aMessage.ReadL( KAccServParamPosSecond, audioTypePckg );

    //Precondition
    iServerModel->IsConnectedL( genericID );//Leaves with KErrArgument if the accessory is not connected

    iServerModel->SetAudioType( audioType );//Notice, This works for single client (Server model can store only one value)

    iConnectionController->NotificationQueue().RegisterControlMessage( 
                                                    EAccessoryAudioLinkClose,
                                                    this );

    iConnectionController->NotificationQueue().CompleteControlMessageL( 
                                                    EBluetoothAudioLinkCloseReq,
                                                    KErrNone,
                                                    genericID.UniqueID() );

    iAccessoryAudioLinkCloseMsg = aMessage;//Store RMessage2 for future completion

    // If message is null, there is no pending request and no filtering needed
    if ( !iNotifyAccessoryAudioLinkClosedMsg.IsNull() )
        {
        //NotifyAccessoryAudioLinkClosed() notification is filtered
        //for AccessoryAudioLinkClose() caller thread
        iConnectionController->ServerModel().SetMsgThreadIDFilter( 
                                                    iCallerThreadID,
                                                    EAccessoryAudioLinkClosed );
        }

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubBaseConnection::AccessoryAudioLinkCloseL - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::AudioRoutingStatusNotifyL
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::AudioRoutingStatusNotifyL( const RMessage2& aMessage )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::AudioRoutingStatusNotifyL()" );

    TAccPolGenericID genericID;
    TPckgBuf<TBool> activeAudioPckgBuf;
    TAccSrvGenericIDPckg genericIDPckg( genericID );

    aMessage.ReadL( KAccServParamPosFirst, activeAudioPckgBuf );
    aMessage.ReadL( KAccServParamPosSecond, genericIDPckg );

    iConnectionController->HandleAccessoryModeChangedL( genericID.UniqueID(), 
                                                        activeAudioPckgBuf() );

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::AudioRoutingStatusNotifyL - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::CancelAccessoryAudioLinkOpen
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::CancelAccessoryAudioLinkOpen( 
    const RMessage2& /*aMessage*/ )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::CancelAccessoryAudioLinkOpen()" );

    // If message is null, there is nothing to cancel
    if ( !iAccessoryAudioLinkOpenMsg.IsNull() )
        {
        iConnectionController->NotificationQueue().CancelControlMessage( 
                                                    EAccessoryAudioLinkOpen,
                                                    this );

        //AccessoryAudioLinkOpen() request is cancelled
        //-> NO filtering needed for NotifyAccessoryAudioLinkOpened()
        iConnectionController->ServerModel().FindAndDeleteMsgThreadIDFilter( 
                                                    iCallerThreadID, 
                                                    EAccessoryAudioLinkOpened );

        Write( iAccessoryAudioLinkOpenMsg, KAccSrvAccessoryAudioLinkOpenBit );
        iAccessoryAudioLinkOpenMsg.Complete( KErrCancel );
        iServerModel->SetAudioLinkOpenCancelled( ETrue );
        }

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::CancelAccessoryAudioLinkOpen - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::CancelAccessoryAudioLinkClose
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::CancelAccessoryAudioLinkClose(
    const RMessage2& /*aMessage*/ )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::CancelAccessoryAudioLinkClose()" );

    // If message is null, there is nothing to cancel
    if ( !iAccessoryAudioLinkCloseMsg.IsNull() )
        {
        iConnectionController->NotificationQueue().CancelControlMessage( EAccessoryAudioLinkClose,
                                                                         this );

        //AccessoryAudioLinkClose() request is cancelled
        //-> NO filtering needed for NotifyAccessoryAudioLinkClosed()
        iConnectionController->ServerModel().FindAndDeleteMsgThreadIDFilter(
            iCallerThreadID, EAccessoryAudioLinkClosed );

        Write( iAccessoryAudioLinkCloseMsg, KAccSrvAccessoryAudioLinkCloseBit );
        iAccessoryAudioLinkCloseMsg.Complete( KErrCancel );
        iServerModel->SetAudioLinkCloseCancelled( ETrue );
        }

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::CancelAccessoryAudioLinkClose - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkOpened
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkOpened(
    const RMessage2& /*aMessage*/ )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkOpened()" );

    // If message is null, there is nothing to cancel
    if( !iNotifyAccessoryAudioLinkOpenedMsg.IsNull() )
        {
        iConnectionController->NotificationQueue().CancelControlMessage( 
            EAccessoryAudioLinkOpened, this );

        //NotifyAccessoryAudioLinkOpened() notification order is cancelled
        //-> NO filtering needed for that message
        iConnectionController->ServerModel().FindAndDeleteMsgThreadIDFilter( 
            iCallerThreadID, EAccessoryAudioLinkOpened );

        Write( iNotifyAccessoryAudioLinkOpenedMsg, KAccSrvNotifyAccessoryAudioLinkOpenedBit );
        iNotifyAccessoryAudioLinkOpenedMsg.Complete( KErrCancel );
        }

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkOpened - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkClosed
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkClosed( 
    const RMessage2& /*aMessage*/ )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkClosed()" );

    // If message is null, there is nothing to cancel
    if( !iNotifyAccessoryAudioLinkClosedMsg.IsNull() )
        {
        iConnectionController->NotificationQueue().CancelControlMessage( 
            EAccessoryAudioLinkClosed, this );

        //NotifyAccessoryAudioLinkClosed() notification order is cancelled
        //-> NO filtering needed for that message
        iConnectionController->ServerModel().FindAndDeleteMsgThreadIDFilter(
            iCallerThreadID, EAccessoryAudioLinkClosed );
    
        Write( iNotifyAccessoryAudioLinkClosedMsg, KAccSrvNotifyAccessoryAudioLinkClosedBit );
        iNotifyAccessoryAudioLinkClosedMsg.Complete( KErrCancel );
        }

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::CancelNotifyAccessoryAudioLinkClosed - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::DispatchMessageL
// Handles client request. If request is not handled here, it is passed to 
// parent class for handling
// -----------------------------------------------------------------------------
//
void CAccSrvSubAudioControl::DispatchMessageL( const RMessage2& aMessage )
    {
    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::DispatchMessageL()" );

    TInt function = aMessage.Function();

    switch ( function )
        {
        case EAccSrvNotifyAccessoryAudioLinkOpened:
            {
            NotifyAccessoryAudioLinkOpened( aMessage );
            break;
            }
        case EAccSrvNotifyAccessoryAudioLinkClosed:
            {
            NotifyAccessoryAudioLinkClosed( aMessage );
            break;
            }
        case EAccSrvAccessoryAudioLinkOpen:
            {
            AccessoryAudioLinkOpenL( aMessage );
            break;
            }
        case EAccSrvAccessoryAudioLinkClose:
            {
            AccessoryAudioLinkCloseL( aMessage );
            break;
            }
        case EAccSrvAudioRoutingStatusNotify:
            {
            AudioRoutingStatusNotifyL( aMessage );
            break;
            }
        case EAccSrvCancelAccessoryAudioLinkOpen:
            {
            CancelAccessoryAudioLinkOpen( aMessage );
            break;
            }
        case EAccSrvCancelAccessoryAudioLinkClose:
            {
            CancelAccessoryAudioLinkClose( aMessage );
            break;
            }
        case EAccSrvCancelNotifyAccessoryAudioLinkOpened:
            {
            CancelNotifyAccessoryAudioLinkOpened( aMessage );
            break;
            }
        case EAccSrvCancelNotifyAccessoryAudioLinkClosed:
            {
            CancelNotifyAccessoryAudioLinkClosed( aMessage );
            break;
            }
        default:
            {
            // Not handled here, pass to base class
            CAccSrvSubControl::DispatchMessageL( aMessage );
            break;
            }
        } // switch( function )

    COM_TRACE_( "[AccFW:AccServer] CAccSrvSubAudioControl::DispatchMessageL - return void" );
    }

// -----------------------------------------------------------------------------
// CAccSrvSubAudioControl::CompleteMessageL
// -----------------------------------------------------------------------------
//
TBool CAccSrvSubAudioControl::CompleteMessageL( TMsgID aMsgID,
                                                TInt aErrorCode,
                                                TInt aUniqueID )
    {
    COM_TRACE_3( "[AccFW:AccServer] CAccSrvSubAudioControl::CompleteMessageL(MsgID=%d Err=%d UniqueID=%d)", aMsgID, aErrorCode, aUniqueID );

    TBool messageConsumption( EFalse );// Return value tells should this subsession be removed from the queue

    switch ( aMsgID )
        {
        case EAccessoryAudioLinkOpen:
            {
            if( KErrNone != aErrorCode )
                {
                //Release NotifyAccessoryAudioLinkOpened() filtering in error case.
                //BluetoothAudioLinkOpenedNotify() message is never sent in error case
                iConnectionController->ServerModel().FindAndDeleteMsgThreadIDFilter(
                                                                    iCallerThreadID,
                                                                    EAccessoryAudioLinkOpened );
                }  
            //Complete outstanding AccessoryAudioLinkOpen request
            Write( iAccessoryAudioLinkOpenMsg, KAccSrvAccessoryAudioLinkOpenBit );
            iAccessoryAudioLinkOpenMsg.Complete( aErrorCode );
            messageConsumption = ETrue;
            }
            break;

        case EAccessoryAudioLinkClose:
            {
            if( KErrNone != aErrorCode )
                {
                //Release NotifyAccessoryAudioLinkClosed() filtering in error case.
                //BluetoothAudioLinkClosedNotify() message is never sent in error case
                iConnectionController->ServerModel().FindAndDeleteMsgThreadIDFilter(
                                                                    iCallerThreadID,
                                                                    EAccessoryAudioLinkClosed );
                }                
            //Complete outstanding AccessoryAudioLinkClose request
            Write( iAccessoryAudioLinkCloseMsg, KAccSrvAccessoryAudioLinkCloseBit );
            iAccessoryAudioLinkCloseMsg.Complete( aErrorCode );
            messageConsumption = ETrue;
            }
            break;

        case EAccessoryAudioLinkOpened:
            {
            // Nothing is done here if filter is set, i.e. NotifyAccessoryAudioLinkOpened()
            // notification was ordered from the same thread that AccessoryAudioLinkOpen() was called
            if ( !iConnectionController->ServerModel().FindAndDeleteMsgThreadIDFilter( 
                                                                    iCallerThreadID, 
                                                                    EAccessoryAudioLinkOpened ) )
                {
                //Complete outstanding NotifyAccessoryAudioLinkOpened request
                //Notice, This works for single client (Server model can store only one value)
                TAccAudioType    audioType( iConnectionController->ServerModel().AudioType() );
                TAccPolGenericID genericID;
                iConnectionController->ServerModel().FindWithUniqueIDL( aUniqueID, genericID );
                TAccSrvGenericIDPckg genericIDPckg( genericID );
                TAccSrvAudioTypePckg audioTypePckg( audioType );
                
                COM_TRACE_1( "[AccFW:AccServer] CAccSrvSubAudioControl::CompleteMessageL - Opened AudioType=%d)", audioType );

                iNotifyAccessoryAudioLinkOpenedMsg.WriteL( KAccServParamPosFirst, genericIDPckg );
                iNotifyAccessoryAudioLinkOpenedMsg.WriteL( KAccServParamPosSecond, audioTypePckg );
                Write( iNotifyAccessoryAudioLinkOpenedMsg, 
                       KAccSrvNotifyAccessoryAudioLinkOpenedBit );

                iNotifyAccessoryAudioLinkOpenedMsg.Complete( aErrorCode );
                messageConsumption = ETrue;
                }
            }
            break;

        case EAccessoryAudioLinkClosed:
            {
            // Nothing is done here if filter is set, i.e. NotifyAccessoryAudioLinkClosed() 
            // notification was ordered from the same thread that AccessoryAudioLinkClose() was called
            if ( !iConnectionController->ServerModel().FindAndDeleteMsgThreadIDFilter(
                                                                    iCallerThreadID,
                                                                    EAccessoryAudioLinkClosed ) )
                {
                //Complete outstanding NotifyAccessoryAudioLinkClosed request
                //Notice, This works for single client (Server model can store only one value)
                TAccAudioType    audioType( iConnectionController->ServerModel().AudioType() );
                TAccPolGenericID genericID;
                iConnectionController->ServerModel().FindWithUniqueIDL( aUniqueID, genericID );
                TAccSrvGenericIDPckg genericIDPckg( genericID );
                TAccSrvAudioTypePckg audioTypePckg( audioType );

                COM_TRACE_1( "[AccFW:AccServer] CAccSrvSubAudioControl::CompleteMessageL - Closed AudioType=%d)", audioType );

                iNotifyAccessoryAudioLinkClosedMsg.WriteL( KAccServParamPosFirst, genericIDPckg );
                iNotifyAccessoryAudioLinkClosedMsg.WriteL( KAccServParamPosSecond, audioTypePckg );
                Write( iNotifyAccessoryAudioLinkClosedMsg, 
                       KAccSrvNotifyAccessoryAudioLinkClosedBit );

                iNotifyAccessoryAudioLinkClosedMsg.Complete( aErrorCode );
                messageConsumption = ETrue;
                }
            }
            break;

        default:
            {
            //Pass handling to parent class
            messageConsumption = CAccSrvSubControl::CompleteMessageL( aMsgID,
                                                                      aErrorCode,
                                                                      aUniqueID );
            }
        }

    COM_TRACE_1( "[AccFW:AccServer] CAccSrvSubAudioControl::CompleteMessageL - return 0x%x", messageConsumption );

    return messageConsumption;
    }

// ========================== OTHER EXPORTED FUNCTIONS =========================

//  End of File
