--- a/bluetoothappprofiles/avrcp/remconbeareravrcp/src/avrcpoutgoingcommandhandler.cpp Wed Oct 13 13:15:31 2010 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,768 +0,0 @@
-// Copyright (c) 2004-2009 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:
-//
-
-
-
-/**
- @file
- @internalComponent
- @released
-*/
-
-#include <remconcoreapi.h>
-
-#include "avcpanel.h"
-#include "controlcommand.h"
-#include "avrcpoutgoingcommandhandler.h"
-#include "avrcplog.h"
-#include "avrcprouter.h"
-#include "avrcptimer.h"
-#include "avrcputils.h"
-#include "controlbearer.h"
-
-//---------------------------------------------------------------------
-// Construction/Destruction
-//---------------------------------------------------------------------
-
-/** Factory function.
-
-@param aBearer The CRemConBearerAvrcp this is to handle commands for.
-@param aObserver The observer of the bearer. Used to aquire converters.
-@param aRouter A CRcpRouter to use for communication with remote devices.
-@param aTimer CDeltaTimer to use for queuing timed events.
-@return A fully constructed CRcpOutgoingCommandHandler.
-@leave System wide error codes.
-*/
-CRcpOutgoingCommandHandler* CRcpOutgoingCommandHandler::NewL(MRemConControlCommandInterface& aCommandInterface,
- MRemConBearerObserver& aObserver,
- CRcpRouter& aRouter,
- CDeltaTimer& aTimer)
- {
- LOG_STATIC_FUNC
- CRcpOutgoingCommandHandler* handler = new(ELeave)CRcpOutgoingCommandHandler(aCommandInterface, aObserver, aRouter, aTimer);
- return handler;
- }
-
-/** Constructor.
-
-@param aBearer The CRemConBearerAvrcp this is to handle commands for.
-@param aObserver The observer of the bearer. Used to aquire converters.
-@param aRouter A CRcpRouter to use for communication with remote devices.
-@param aTimer CDeltaTimer to use for queuing timed events.
-@return A partially constructed CRcpIncomingCommandHandler.
-@leave System wide error codes.
-*/
-CRcpOutgoingCommandHandler::CRcpOutgoingCommandHandler(MRemConControlCommandInterface& aCommandInterface,
- MRemConBearerObserver& aObserver,
- CRcpRouter& aRouter,
- CDeltaTimer& aTimer) : iCommandQueue(_FOFF(CControlCommand, iHandlingLink)),
- iNotifyCommandQueue(_FOFF(CControlCommand, iHandlingLink)),
- iCommandInterface(aCommandInterface), iObserver(aObserver), iRouter(aRouter), iTimer(aTimer)
- {
- LOG_FUNC
- }
-
-/** Destructor.
-*/
-CRcpOutgoingCommandHandler::~CRcpOutgoingCommandHandler()
- {
- LOG_FUNC
-
- ClearQueue(iCommandQueue);
- ClearQueue(iNotifyCommandQueue);
- }
-
-void CRcpOutgoingCommandHandler::ClearQueue(TDblQue<CControlCommand>& aQue)
- {
- while(!aQue.IsEmpty())
- {
- CControlCommand* command = aQue.First();
- command->CancelTimer(iTimer);
- command->iHandlingLink.Deque();
- command->DecrementUsers();
- }
- }
-//---------------------------------------------------------------------
-// Called from the bearer
-//---------------------------------------------------------------------
-
-/** Tell the handler to gracefully shutdown.
-
-@param aClearQueue Whether to clear the queue without handling the things
- on it. If this is true the commands will be deleted.
- If this is false then pending commands will have responses
- generated to RemCon.
-*/
-void CRcpOutgoingCommandHandler::Disconnect(TBool aClearQueue)
- {
- LOG_FUNC
- ProcessDisconnect(iCommandQueue, aClearQueue);
- ProcessDisconnect(iNotifyCommandQueue, aClearQueue);
- }
-
-void CRcpOutgoingCommandHandler::ProcessDisconnect(TDblQue<CControlCommand>& aQue, TBool aClearQueue)
- {
- while(!aQue.IsEmpty())
- {
- CControlCommand* command = aQue.First();
- iRouter.RemoveFromSendQueue(*command);
- command->CancelTimer(iTimer);
-
- if(aClearQueue)
- {
- GenerateFailureResult(*command, KErrDisconnected);
- }
-
- command->iHandlingLink.Deque();
- command->DecrementUsers();
- }
- }
-/** Sends a new command.
-
-@param aInterfaceUid The RemCon client interface this command is from.
-@param aCommand The operation id within aInterfaceUid.
-@param aId A unique identifier provided by RemCon.
-@param aCommandData Data associated with this command.
-@param aAddr Bluetooth address of device to send this command to.
-@leave KErrNoMemory or system wide error code.
-@leave Command parsing error.
-*/
-void CRcpOutgoingCommandHandler::SendCommandL(TUid aInterfaceUid,
- TUint aCommand,
- TUint aId,
- RBuf8& aCommandData,
- const TBTDevAddr& aAddr)
- {
- LOG_FUNC
-
- if(aInterfaceUid.iUid == KRemConCoreApiUid)
- {
- // Passthrough commands are stateful, so we need to examine the
- // history - we can't just blindly wham it on the queue.
- HandleCoreApiCommandL(aCommand, aId, aCommandData, aAddr);
- }
- else
- {
- SendCommandL(aInterfaceUid, aCommand, aId, aCommandData, EFalse, aAddr, ETrue, EFalse);
- }
- }
-
-/** Sends a new notify command.
-
-@param aInterfaceUid The RemCon client interface this command is from.
-@param aCommand The operation id within aInterfaceUid.
-@param aId A unique identifier provided by RemCon, the transaction ID.
-@param aCommandData Data associated with this command.
-@param aAddr Bluetooth address of device to send this command to.
-@leave KErrNoMemory or system wide error code.
-@leave Command parsing error.
-*/
-void CRcpOutgoingCommandHandler::SendNotifyCommandL(TUid aInterfaceUid,
- TUint aCommand,
- TUint aId,
- RBuf8& aCommandData,
- const TBTDevAddr& aAddr)
- {
- LOG_FUNC
- SendCommandL(aInterfaceUid, aCommand, aId, aCommandData, EFalse, aAddr, ETrue, ETrue);
- }
-
-//---------------------------------------------------------------------
-// Data notifications from the router
-//---------------------------------------------------------------------
-
-/** Called by the router to provide a new response.
-
-@param aFrame The AV/C frame for this response. Ownership is taken.
-@param aTransLabel The AVCTP transaction id of this response. This is used
- to match it with its command.
-@param aAddr The remote from which this response originated
-*/
-void CRcpOutgoingCommandHandler::ReceiveResponse(const TDesC8& aMessageInformation,
- SymbianAvctp::TTransactionLabel aTransLabel,
- TBool aIpidBitSet)
- {
- LOG_FUNC
-
- CAVCFrame* frame = NULL;
- TInt err = KErrNone;
- if(!aIpidBitSet)
- {
- TRAP(err, frame = CAVCFrame::NewL(aMessageInformation, AVC::EResponse));
- }
-
- if(!err)
- {
- CControlCommand* command = NULL;
- command = FindInQueue(iCommandQueue, aTransLabel);
- if ( command != NULL )
- {
- //Found, so it is a normal command response.
- ProcessReceiveResponse(frame, aIpidBitSet, command, EFalse);
- }
- else
- {
- //Try to find in the notify command queue.
- command = FindInQueue(iNotifyCommandQueue, aTransLabel);
- if( command != NULL )
- {
- //Found, so it is a notify command response.
- ProcessReceiveResponse(frame, aIpidBitSet, command, ETrue);
- }
- }
-
- delete frame;
- }
- }
-
-CControlCommand* CRcpOutgoingCommandHandler::FindInQueue(TDblQue<CControlCommand>& aQue,
- SymbianAvctp::TTransactionLabel aTransLabel)
- {
- CControlCommand* command = NULL;
- TDblQueIter<CControlCommand> iter(aQue);
- while (iter)
- {
- command = iter++;
- if(command->TransactionLabel() == aTransLabel)
- {
- return command;
- }
- }
-
- return NULL;
- }
-
-void CRcpOutgoingCommandHandler::ProcessReceiveResponse(CAVCFrame* aFrame,
- TBool aIpidBitSet,
- CControlCommand* aCommand,
- TBool aNotify)
- {
- aCommand->CancelTimer(iTimer);
-
- TInt err = KErrNone;
- // Inform the bearer if this is something it knows about
- // ie not a click release
- if(aCommand->KnownToBearer())
- {
- if(!aIpidBitSet)
- {
- if(aFrame->Data().Length() < KAVCFrameHeaderLength)
- {
- // Drop corrupt frames
- return;
- }
-
- err = aCommand->ParseIncomingResponse(iObserver, *aFrame);
- }
- else
- {
- // If aIpidBitSet is true that means AVRCP is not supported
- // by the remote end. We handle this in the same way as not
- // supported commands, passing them up to RemCon as not
- // supported, so just map the ctype here, rather than setting
- // up another path for ipid handling, but we need pass as the
- // frame the original because we don't get one from AVCTP if
- // ipid is set.
- aCommand->SetResponseType(KErrNotSupported);
- err = aCommand->ParseIncomingResponse(iObserver, aCommand->Frame());
- }
-
- if ( aNotify )
- {//This is a notify command
- iCommandInterface.MrccciNewNotifyResponse(*aCommand);
- }
- else
- {
- iCommandInterface.MrccciNewResponse(*aCommand);
- }
- }
-
- TBool doDeque = ETrue;
- if ( (!aIpidBitSet) && (err == KErrNone) && (aNotify) && (aFrame->Type() == AVC::EInterim))
- {
- doDeque = EFalse;
- }
-
- // If this a passthrough press that hasn't yet been released, we need
- // to wait for a release before getting rid of this, otherwise we're done.
- if(aCommand == iUnreleasedCommand)
- {
- iUnreleasedHasResponse = ETrue;
- StartReleaseTimer(*iUnreleasedCommand);
- doDeque = EFalse;
- }
-
- if ( doDeque )
- {
- aCommand->iHandlingLink.Deque();
- aCommand->DecrementUsers();
- }
- }
-/** Called by the router to complete a send.
-
-@param aCommand The command which has been sent.
-@param aSendResult The result of the send. KErrNone if successful.
-*/
-void CRcpOutgoingCommandHandler::MessageSent(CAvrcpCommand& aCommand, TInt aSendResult)
- {
- LOG_FUNC
-
- if(aSendResult == KErrNone)
- {
- // Set off response timer
- StartResponseTimer(static_cast<CControlCommand&>(aCommand));
- }
- else
- {
- CControlCommand* command = FindInQueue(iNotifyCommandQueue, aCommand.TransactionLabel());
-
- if(command)
- {
- command->SetNotifyVolumeChangeResult(command->Frame());
- iCommandInterface.MrccciNewNotifyResponse(*command);
- }
- else
- {
- command = FindInQueue(iCommandQueue, aCommand.TransactionLabel());
-
- // Generate error response up to RemCon
- // if this is a core command we can set the result,
- // otherwise we just return it as we got it.
- if(command->Frame().Opcode() == AVC::EPassThrough)
- {
- // Need to insert before setting the button action so we have
- // long enough data
- if (!command->InsertCoreResult(aSendResult))
- {
- if(command->Click())
- {
- command->SetCoreButtonAction(ERemConCoreApiButtonClick, ETrue);
- }
- }
- }
-
- iCommandInterface.MrccciNewResponse(*command);
- }
-
- command->iHandlingLink.Deque();
- command->DecrementUsers();
- }
- }
-
-//---------------------------------------------------------------------
-// Internal Utility functions
-//---------------------------------------------------------------------
-
-void CRcpOutgoingCommandHandler::CleanupUnreleased()
- {
- iUnreleasedCommand->CancelTimer(iTimer);
- iUnreleasedCommand->iHandlingLink.Deque();
- iUnreleasedCommand->DecrementUsers();
- iUnreleasedHasResponse = EFalse;
- }
-
-/** Handle a command that is part of the Core API.
-
-@param aCommand The operation id within aInterfaceUid.
-@param aId A unique identifier provided by RemCon.
-@param aCommandData Data associated with this command.
-@param aAddr Bluetooth address of device to send this command to.
-@leave KErrNoMemory or system wide error code.
-@leave Command parsing error.
-*/
-void CRcpOutgoingCommandHandler::HandleCoreApiCommandL(TUint aCommand,
- TUint aId,
- RBuf8& aCommandData,
- const TBTDevAddr& aAddr)
- {
- if(aCommandData.Length() < KRemConCoreApiButtonDataLength)
- {
- User::Leave(KErrCorrupt);
- }
-
- TInt buttonData;
- AvrcpUtils::ReadCommandDataToInt(aCommandData,
- KRemConCoreApiButtonDataOffset, KRemConCoreApiButtonDataLength, buttonData);
-
- // First check if there's anything we need to do before sending this command,
- // mainly releasing a previous press.
- if(iUnreleasedCommand)
- {
- TUint prevOpId = iUnreleasedCommand->RemConOperationId();
-
- if(aCommand == prevOpId)
- {
- // Either we've received a release, or we've refreshed the press.
- // If the unreleased press has already been responded too we can
- // dispose of it now.
- // If the unreleased press has not been responded too we can
- // treat it like a normal command on reception of response, so just
- // set iUnreleased to NULL.
- if(iUnreleasedHasResponse)
- {
- CleanupUnreleased();
- }
-
- iUnreleasedCommand = NULL;
- }
- else
- {
- // A new operation!
- if(buttonData != ERemConCoreApiButtonRelease)
- {
- // Try and generate the release for the previous command, if
- // if fails then the remote will just have to assume it.
- // There's no point leaving this to the release timer, because
- // we want to send another command now, so even if we send the
- // release later the remote should ignore it.
- TRAP_IGNORE(GenerateCommandL(*iUnreleasedCommand, ERemConCoreApiButtonRelease));
-
- if(iUnreleasedHasResponse)
- {
- CleanupUnreleased();
- }
-
- iUnreleasedCommand = NULL;
- }
- else
- {
- // A release for a command other than iUnreleased. We can't
- // send this now.
- User::Leave(KErrNotReady);
- }
- }
- }
- else if(buttonData == ERemConCoreApiButtonRelease)
- {
- // We don't have an unreleased command. We must have already
- // released this, either via the timer, or because we've sent
- // another command in the meantime. We can't send this now.
- // Leaving synchronously means we don't need to worry about generating
- // a fake response, which may mislead the application.
- User::Leave(KErrNotReady);
- }
-
- if(buttonData == ERemConCoreApiButtonClick)
- {
- // aCommandData is still owned by RemCon until we return successfully.
- // If we try the operations with the new data first we won't end up
- // in a situation where the new CControlCommand thinks that it owns
- // aCommandData, then the release operation leaves, so RemCon also
- // thinks it owns aCommandData.
-
- RBuf8 pressBuf;
- pressBuf.CreateL(aCommandData);
- CleanupClosePushL(pressBuf);
-
- AvrcpUtils::SetCommandDataFromInt(pressBuf,
- KRemConCoreApiButtonDataOffset, KRemConCoreApiButtonDataLength, ERemConCoreApiButtonPress);
- SendCommandL(TUid::Uid(KRemConCoreApiUid), aCommand, aId, pressBuf, ETrue, aAddr, ETrue, EFalse);
-
- // Data has been taken ownership of by SendCommandL, so can just let
- // pressbuf go out of scope.
- CleanupStack::Pop(&pressBuf);
-
- AvrcpUtils::SetCommandDataFromInt(aCommandData,
- KRemConCoreApiButtonDataOffset, KRemConCoreApiButtonDataLength, ERemConCoreApiButtonRelease);
- SendCommandL(TUid::Uid(KRemConCoreApiUid), aCommand, aId, aCommandData, ETrue, aAddr, EFalse, EFalse);
- }
- else if(buttonData == ERemConCoreApiButtonPress)
- {
- iUnreleasedCommand = &SendCommandL(TUid::Uid(KRemConCoreApiUid), aCommand, aId, aCommandData, EFalse, aAddr, ETrue, EFalse);
- iReleaseTimerExpiryCount = 0;
- }
- else
- {
- // Must be release
- __ASSERT_DEBUG(buttonData == ERemConCoreApiButtonRelease, AvrcpUtils::Panic(EAvrcpUnknownButtonAction));
- SendCommandL(TUid::Uid(KRemConCoreApiUid), aCommand, aId, aCommandData, EFalse, aAddr, ETrue, EFalse);
- }
- }
-
-/** Creates a command from the RemCon data.
-
-This is an internal utility function.
-
-A CControlCommand will be created. Calling ProcessOutgoingCommandL on
-this creates a CAVCFrame from the provided data. If an AV/C frame
-can be created the command will be added to the outgoing queue to
-wait a response from the remote. Otherwise this function will
-leave.
-
-@param aInterfaceUid The RemCon client interface this command is from.
-@param aCommand The operation id within aInterfaceUid.
-@param aId A unique identifier provided by RemCon.
-@param aCommandData Data associated with this command.
-@param aIsClick Whether this is a button click.
-@param aAddr Bluetooth address of device to send this command to.
-@return The generated command.
-@leave KErrNoMemory or system wide error code.
-@leave Command parsing error.
-*/
-CControlCommand& CRcpOutgoingCommandHandler::SendCommandL(TUid aInterfaceUid,
- TUint aCommand,
- TUint aId,
- RBuf8& aCommandData,
- TBool aIsClick,
- const TBTDevAddr& aAddr,
- TBool aKnownToBearer,
- TBool aNotify)
- {
- LOG_FUNC
- // Create a command and wham it on our queue, so we can match it up with its response
- // CControlCommand::NewL takes ownership of the data in aCommandData then NULLs aCommandData
- // so a leave later in the function won't cause double deletion.
- CControlCommand* command = CControlCommand::NewL(aInterfaceUid, aCommand, aId, iCurrentTrans,
- aCommandData, aIsClick, aAddr, aKnownToBearer);
- CleanupStack::PushL(command);
-
- command->ProcessOutgoingCommandL(iObserver);
- CleanupStack::Pop(command);
- command->IncrementUsers();
-
- if ( aNotify )
- {
- iNotifyCommandQueue.AddLast(*command);
- }
- else
- {
- iCommandQueue.AddLast(*command);
- }
-
- // Increment our transaction id
- iCurrentTrans = (iCurrentTrans + 1) % SymbianAvctp::KMaxTransactionLabel;
-
- // Command stays on the queue till we've got the response
- iRouter.AddToSendQueue(*command);
-
- return *command;
- }
-
-/** Generate a failure response to RemCon.
-
-This sets the result for a passthrough command.
-It informs the bearer of the new response.
-
-@param aCommand The command to finish off.
-@param aResult The result (only valid for passthrough)
-*/
-void CRcpOutgoingCommandHandler::GenerateFailureResult(CControlCommand& aCommand, TInt aResult)
- {
- // Response is only necessary if the bearer knows about this command.
- if(aCommand.KnownToBearer() && (aCommand.Frame().Opcode() == AVC::EPassThrough))
- {
- if (aCommand.InsertCoreResult(aResult) == KErrNone)
- {
- if(aCommand.Click())
- {
- aCommand.SetCoreButtonAction(ERemConCoreApiButtonClick, ETrue);
- }
- else if(aCommand.ButtonAct() == AVCPanel::EButtonPress)
- {
- aCommand.SetCoreButtonAction(ERemConCoreApiButtonPress, ETrue);
- }
- else
- {
- aCommand.SetCoreButtonAction(ERemConCoreApiButtonRelease, ETrue);
- }
-
- iCommandInterface.MrccciNewResponse(aCommand);
- }
- }
- }
-
-/** Generate a command to the remote.
-
-This is needed in situations where the application has not met the avrcp
-button refresh requirements so we need to internally generate something
-to stop the remote getting a bad impression of us.
-
-@param aCommand The command to be issue again.
-*/
-void CRcpOutgoingCommandHandler::GenerateCommandL(CControlCommand& aCommand, TRemConCoreApiButtonAction aButtonAct)
- {
- LOG_FUNC
-
- RBuf8 commandData;
- commandData.CreateMaxL(KRemConCoreApiButtonDataLength);
-
- AvrcpUtils::SetCommandDataFromInt(commandData,
- KRemConCoreApiButtonDataOffset, KRemConCoreApiButtonDataLength, aButtonAct);
-
- // This will not leave before taking ownership of commandData.
- SendCommandL(aCommand.RemConInterfaceUid(), aCommand.RemConOperationId(), aCommand.RemConCommandId(), commandData, EFalse,
- aCommand.RemoteAddress(), EFalse, EFalse);
- }
-
-//------------------------------------------------------------------------------------
-// Timer functions
-//------------------------------------------------------------------------------------
-
-/** Starts the response timer.
-
-AVRCP mandates a remote respond within 100ms of receiving a command.
-This is the timer for that, and is started when a command has
-successfully been sent.
-
-@param aCommand The command to start the timer for.
-*/
-void CRcpOutgoingCommandHandler::StartResponseTimer(CControlCommand& aCommand)
- {
- LOG_FUNC
- // These use placement new, so cannot fail
- TAvrcpTimerExpiryInfo* timerInfo = new(aCommand.TimerExpiryInfo())TAvrcpTimerExpiryInfo(this, aCommand);
-
- TCallBack callback(ResponseExpiry, timerInfo);
- TDeltaTimerEntry* timerEntry = new(aCommand.TimerEntry())TDeltaTimerEntry(callback);
-
- iTimer.Queue(KRcpResponseTimeOut, *timerEntry);
- }
-
-/** Callback when response timer expires.
-
-This is a static forwarding function.
-
-@param aExpiryInfo The information used by the real ResponseExpiry to
- deal with the timer expiry.
-*/
-TInt CRcpOutgoingCommandHandler::ResponseExpiry(TAny* aExpiryInfo)
- {
- LOG_STATIC_FUNC
- TAvrcpTimerExpiryInfo *timerInfo = reinterpret_cast<TAvrcpTimerExpiryInfo*>(aExpiryInfo);
- (reinterpret_cast<CRcpOutgoingCommandHandler*>(timerInfo->iHandler))->ResponseExpiry(timerInfo->iCommand);
-
- return KErrNone;
- }
-
-/** Deals with response timeout.
-
-This sends a timeout response to RemCon.
-
-@param aCommand The CControlCommand that has expired.
-*/
-void CRcpOutgoingCommandHandler::ResponseExpiry(CControlCommand& aCommand)
- {
- LOG_FUNC
-
- GenerateFailureResult(aCommand, KErrTimedOut);
-
- // Failed to get a response to this, don't bother about trying
- // to release it.
- if(iUnreleasedCommand == &aCommand)
- {
- iUnreleasedCommand = NULL;
- __ASSERT_DEBUG(!iUnreleasedHasResponse, AvrcpUtils::Panic(EAvrcpPressHasPhantomResponse));
- }
-
- aCommand.iHandlingLink.Deque();
- aCommand.DecrementUsers();
- }
-
-/** Starts the release timer.
-
-AVRCP requires a press to be refreshed less than 2s after the first
-press, if it is not to be assumed to have been released. We pass
-this requirement on to RemCon clients as we don't know when they might
-go away and we don't want to keep buttons pressed forever. If the
-release timer expires we will assume a release, and generate it to
-the remote.
-
-@param aCommand The command to start the timer for.
-*/
-void CRcpOutgoingCommandHandler::StartReleaseTimer(CControlCommand& aCommand)
- {
- LOG_FUNC
-
- // These cannot fail as we use placement new
- TAvrcpTimerExpiryInfo* timerInfo = new(aCommand.TimerExpiryInfo())TAvrcpTimerExpiryInfo(this, aCommand);
-
- TCallBack callback(ReleaseExpiry, timerInfo);
- TDeltaTimerEntry* timerEntry = new(aCommand.TimerEntry())TDeltaTimerEntry(callback);
-
- iTimer.Queue(KRcpOutgoingButtonReleaseTimeout, *timerEntry);
- }
-
-/** Callback when release timer expires.
-
-This is a static forwarding function.
-
-@param aExpiryInfo The information used by the real ReleaseExpiry to
- deal with the timer expiry.
-*/
-TInt CRcpOutgoingCommandHandler::ReleaseExpiry(TAny* aExpiryInfo)
- {
- LOG_STATIC_FUNC
- TAvrcpTimerExpiryInfo *timerInfo = reinterpret_cast<TAvrcpTimerExpiryInfo*>(aExpiryInfo);
- (reinterpret_cast<CRcpOutgoingCommandHandler*>(timerInfo->iHandler))->ReleaseExpiry(timerInfo->iCommand);
-
- return KErrNone;
- }
-
-/** Deals with expiry of release timer.
-
-1) Generate release for this command.
-2) Send release to remote.
-
-@param aCommand The CControlCommand that has expired.
-*/
-void CRcpOutgoingCommandHandler::ReleaseExpiry(CControlCommand& aCommand)
- {
- LOG_FUNC
- __ASSERT_DEBUG((aCommand.ButtonAct() == AVCPanel::EButtonPress), AvrcpUtils::Panic(EAvrcpReleaseExpiryForRelease));
- __ASSERT_DEBUG(&aCommand == iUnreleasedCommand, AvrcpUtils::Panic(EAvrcpReleaseExpiryForOldCommand));
- __ASSERT_DEBUG(iUnreleasedHasResponse, AvrcpUtils::Panic(EAvrcpReleaseTimerStartedWithoutResponse));
-
- iReleaseTimerExpiryCount++;
-
- TBool commandCompleted = ETrue;
- // If the client is not yet obliged to refresh this, then send another press. Otherwise generate
- // the release for them.
- if((iReleaseTimerExpiryCount * KRcpOutgoingButtonReleaseTimeout) < KRemConCoreApiPressRefreshInterval)
- {
- // This will try and generate a press that is identical to the original
- // aCommand, but with a new AVCTP transaction id.
- TRAPD(err, GenerateCommandL(aCommand, ERemConCoreApiButtonPress));
-
- if(!err)
- {
- // Start the timer again on the original command
- StartReleaseTimer(aCommand);
- commandCompleted = EFalse;
- }
- }
- else
- {
- // Try an generate a release, but if it fails we just have to let the
- // remote assume it.
- TRAP_IGNORE(GenerateCommandL(aCommand, ERemConCoreApiButtonRelease));
- }
-
- // This condition may be true because
- // - we have failed to generate a press, in which case the remote is entitled
- // to assume this is released, so we just give up on it.
- // or
- // - the client has not met its press refresh obligation (whether we've
- // successfully generated a release or not.
- // In either case we won't do anything more with this command.
- if(commandCompleted)
- {
- aCommand.iHandlingLink.Deque();
- aCommand.DecrementUsers();
-
- iUnreleasedCommand = NULL;
- iUnreleasedHasResponse = EFalse;
- iReleaseTimerExpiryCount = 0;
- }
- }