diff -r 16e4b9007960 -r f5508c13dfe0 bluetoothappprofiles/avrcp/remconbeareravrcp/src/passthroughhelper.cpp --- a/bluetoothappprofiles/avrcp/remconbeareravrcp/src/passthroughhelper.cpp Wed Oct 13 13:15:31 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,443 +0,0 @@ -// Copyright (c) 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: -// - -#include "avrcplog.h" -#include "avrcprouter.h" -#include "avrcputils.h" -#include "controlcommand.h" -#include "passthroughhelper.h" -#include "controlbearer.h" - - -CPassthroughHelper* CPassthroughHelper::NewL(CRcpRouter& aRouter, MRemConControlCommandInterface& aCommandInterface, CDeltaTimer& aTimer) - { - CPassthroughHelper* helper = new(ELeave)CPassthroughHelper(aRouter, aCommandInterface, aTimer); - CleanupStack::PushL(helper); - helper->ConstructL(); - CleanupStack::Pop(helper); - return helper; - } - -CPassthroughHelper::~CPassthroughHelper() - { - } - -CPassthroughHelper::CPassthroughHelper(CRcpRouter& aRouter, MRemConControlCommandInterface& aCommandInterface, CDeltaTimer& aTimer) - : iRouter(aRouter) - , iCommandInterface(aCommandInterface) - , iTimer(aTimer) - { - } - -void CPassthroughHelper::ConstructL() - { - } - -void CPassthroughHelper::Disconnect() - { - LOG_FUNC - - // We handle the last command as a special case to ensure the presses and - // releases are balanced from a clients' point of view. - if(iPreviousPassthrough) - { - iRouter.RemoveFromSendQueue(*iPreviousPassthrough); - BalanceHandledCommand(*iPreviousPassthrough); - } - } - -/** Sends a response to the remote device. - -Because of the 100ms timeout for responses we send a response to -passthrough commands as soon as we receive them. This means the real -response from RemCon is currently ignored. A real response is -only sent if this is a vendor dependent command. - -@param aCommand The command to respond to. -@param aErr The result of handling the command. KErrNone if successful. - KErrNotSupported if this operation is not supported. -*/ -void CPassthroughHelper::Respond(CControlCommand& aCommand, TInt aErr) - { - LOG_FUNC - aCommand.SetResponseType(aErr); - iRouter.AddToSendQueue(aCommand); - } - -/** To be called on completion of command handling. - -This aggregates the handler's tidying up of a finished -command. - -@param aCommand The command to tidy up. -*/ -void CPassthroughHelper::HandledCommand(CControlCommand& aCommand) - { - LOG_FUNC - - // If this was the previous passthrough reset it to NULL - if(iPreviousPassthrough == &aCommand) - { - iPreviousPassthrough = NULL; - } - - aCommand.CancelTimer(iTimer); - aCommand.DecrementUsers(); - } - -/** Handles incoming passthrough command. - -How the command is handled is dependent on this and the previous command. - -Previous command This command Behaviour -Press_op1 Press_op1 discard -Press_op1 Release_op1 press_op1 hold timer not expired - generate click_op1 - press_op1 release timer not expired - generate release_op1 -Press_op1 Press_op2 generate release_op1, start hold timer for press_op2 -Press_op1 Release_op2 press_op1 hold timer not expired - generate click_op1, discard release_op2 - press_op1 release timer not expired - generate release_op1, discard release_op2 -Release_op1 Press_op1 start hold timer for press_op1 -Release_op1 Release_op1 discard -Release_op1 Press_op2 start hold timer for press_op2 -Release_op1 Release_op2 discard - -@param aCommand The command to handle. -@leave System wide error code. -*/ -void CPassthroughHelper::HandlePassthrough(CControlCommand& aCommand) - { - LOG_FUNC - - // We can't map Vendor Unique passthrough command to clicks as we do - // not know how the button action is conveyed to the API. All we can - // do is try and ensure that we try to generate a release if one is - // missing by asking the convert. We also need to consider them as - // part of the passthrough history for how other passthrough commands - // should be interpreted. - TUint8 thisOpId; - aCommand.Frame().OperationId(thisOpId); - if(!aCommand.IsAvrcpPassthrough()) - { - aCommand.SetClick(EFalse); - } - - // Behaviour depends on previous command - TUint8 prevOpId; - if(iPreviousPassthrough) - { - __ASSERT_ALWAYS(iPreviousPassthrough->ButtonAct() == AVCPanel::EButtonPress, - AvrcpUtils::Panic(EAvrcpPressNotPreviousPassthroughCommand)); - - iPreviousPassthrough->Frame().OperationId(prevOpId); - } - - if(aCommand.ButtonAct() == AVCPanel::EButtonPress) - { - // Respond now so we can decrement users of aCommand at will - Respond(aCommand, KErrNone); - - if(iPreviousPassthrough) - { - // previous is press, current is press - if(prevOpId == thisOpId) - { - // prevCommand is for same opId as this one. Drop this - // command and reset release timer for prevCommand. - aCommand.DecrementUsers(); - - iPreviousPassthrough->CancelTimer(iTimer); - // If still flagged as a click then the user won't have been notified - // of the press yet - so do it now. - if(iPreviousPassthrough->Click()) - { - iPreviousPassthrough->SetClick(EFalse); - iPreviousPassthrough->SetCoreButtonAction(ERemConCoreApiButtonPress, ETrue); - iCommandInterface.MrcciNewCommand(*iPreviousPassthrough, iPreviousPassthrough->ClientId()); - } - StartReleaseTimer(*iPreviousPassthrough); - } - else if(iPreviousPassthrough->Click()) - { - // prevCommand is click, Hold timer not expired. Generate click - // to RemCon then start waiting for click. - iPreviousPassthrough->CancelTimer(iTimer); - iPreviousPassthrough->SetCoreButtonAction(ERemConCoreApiButtonClick, ETrue); - iCommandInterface.MrcciNewCommand(*iPreviousPassthrough, iPreviousPassthrough->ClientId()); - - HandledCommand(*iPreviousPassthrough); - - // Start waiting for click (core api) or release (vendor unique) - NewPress(aCommand); - } - else - { - // prevCommand is not click, Release timer not expired. Generate - // release to RemCon then start waiting for click. - BalanceHandledCommand(*iPreviousPassthrough); - - // Start waiting for click (core api) or release (vendor unique) - NewPress(aCommand); - } - } - else - { - // No previous command, current is press - - // Start waiting for click (core api) or release (vendor unique) - NewPress(aCommand); - } - } - else if(iPreviousPassthrough) - { - // previous is press, current is release - if(prevOpId == thisOpId) - { - Respond(aCommand, KErrNone); - - if(iPreviousPassthrough->Click()) - { - // Button release for same opId with hold timeout - aCommand.DecrementUsers(); // Drop this command. - - // Cancel hold timer and send the previous command as a click. - iPreviousPassthrough->CancelTimer(iTimer); - iPreviousPassthrough->SetCoreButtonAction(ERemConCoreApiButtonClick, ETrue); - iCommandInterface.MrcciNewCommand(*iPreviousPassthrough, iPreviousPassthrough->ClientId()); - - HandledCommand(*iPreviousPassthrough); - } - else - { - // Button release for same opId, hold timeout expired - iPreviousPassthrough->CancelTimer(iTimer); - HandledCommand(*iPreviousPassthrough); - - if(aCommand.IsAvrcpPassthrough()) - { - aCommand.SetCoreButtonAction(ERemConCoreApiButtonRelease, ETrue); - } - iCommandInterface.MrcciNewCommand(aCommand, aCommand.ClientId()); - aCommand.DecrementUsers(); - } - } - else - { - // Drop this release and continue waiting for release to - // prevCommand. - Respond(aCommand, KErrNone); - aCommand.DecrementUsers(); - } - } - else - { - // No prevCommand, this is a release - // To get here either: - // - this is a spurious release - // - we've given up waiting for this - - // Because responses must be made within 100ms we respond before waiting - // to see what RemCon thinks. - Respond(aCommand, KErrNone); - aCommand.DecrementUsers(); - } - } - -void CPassthroughHelper::NewPress(CControlCommand& aCommand) - { - LOG_FUNC - __ASSERT_DEBUG(!iPreviousPassthrough, AVRCP_PANIC(EPreviousPassthroughNonNullReplacing)); - - iPreviousPassthrough = &aCommand; - - if(aCommand.IsAvrcpPassthrough()) - { - StartHoldTimer(aCommand); - } - else - { - iCommandInterface.MrcciNewCommand(aCommand, aCommand.ClientId()); - StartReleaseTimer(aCommand); - } - } - -/** To be called on completion of command handling for an unbalanced press. - -This is a special version of the HandledCommand which which assumes the -command has been notified to the user and so balances the notification -of a press with a generated release command. - -@param aCommand The command to tidy up. -*/ -void CPassthroughHelper::BalanceHandledCommand(CControlCommand& aCommand) - { - LOG_FUNC - // CancelTimer also frees the timer entries, so needs to be called - // here even though there's no pending entry. - aCommand.CancelTimer(iTimer); - - // If this was the previous passthrough reset it to NULL - if(iPreviousPassthrough == &aCommand) - { - iPreviousPassthrough = NULL; - } - - // Here we handle the case that a press has been informed but a release has yet - // to be reported, and if it hasn't we provide the notification. - if(aCommand.ButtonAct() == AVCPanel::EButtonPress && !aCommand.Click()) - { - if(aCommand.IsAvrcpPassthrough()) - { - // FIXME I think we might need a new transaction id here? - TRAPD(err, aCommand.ReSetCoreButtonActionL(ERemConCoreApiButtonRelease, ETrue)); - if (err == KErrNone) - { - iCommandInterface.MrcciNewCommand(aCommand, aCommand.ClientId()); - } - else - { - // just silently drop this command, do not send command to remconserv - } - } - else - { - // Need see if we can get a valid release from the converter. Pass - // it the same AVC Frame as the press, but with the button action - // flipped to release. If we can't do this then there's not a - // lot we can do. - // FIXME - } - } - aCommand.iHandlingLink.Deque(); - aCommand.DecrementUsers(); - } - - -//------------------------------------------------------------------------------------ -// Timer functions -//------------------------------------------------------------------------------------ - -/** Starts the hold timer (only applicable to press commands). - -This is the timer to determine whether a command will be passed to RemCon -as a click. If the timer expires before a matching release is received -the press and release will be sent separately. Otherwise, a click is -sent. - -@param aCommand The command to start the timer for. -*/ -void CPassthroughHelper::StartHoldTimer(CControlCommand& aCommand) - { - LOG_FUNC - - // These cannot fail as we use placement new - TAvrcpTimerExpiryInfo* timerInfo = new(aCommand.TimerExpiryInfo())TAvrcpTimerExpiryInfo(this, aCommand); - - TCallBack callback(HoldExpiry, timerInfo); - TDeltaTimerEntry* timerEntry = new(aCommand.TimerEntry())TDeltaTimerEntry(callback); - - iTimer.Queue(KRcpHoldThreshold, *timerEntry); - } - -/** Callback when hold timer expires. - -This is a static forwarding function. - -@param aExpiryInfo The information used by the real HoldExpiry to - deal with the timer expiry. -*/ -TInt CPassthroughHelper::HoldExpiry(TAny* aExpiryInfo) - { - LOG_STATIC_FUNC - TAvrcpTimerExpiryInfo *timerInfo = reinterpret_cast(aExpiryInfo); - (reinterpret_cast(timerInfo->iHandler))->HoldExpiry(timerInfo->iCommand); - - return KErrNone; - } - -/** Deals with expiry of hold timer. - -1) This is not a click. Set click to false for this command. -2) Inform RemCon of available press command -3) Start release timer. - -@param aCommand The CControlCommand that has expired. -*/ -void CPassthroughHelper::HoldExpiry(CControlCommand& aCommand) - { - LOG_FUNC - __ASSERT_DEBUG((aCommand.ButtonAct() == AVCPanel::EButtonPress), AvrcpUtils::Panic(EAvrcpHoldExpiryForRelease)); - - // We haven't received a release soon enough to treat this as - // a click. Send the press on to RemCon and wait for a release. - // CancelTimer also frees the timer entries, so needs to be called - // here even though there's no pending entry. - aCommand.CancelTimer(iTimer); - aCommand.SetClick(EFalse); - aCommand.SetCoreButtonAction(ERemConCoreApiButtonPress, ETrue); - iCommandInterface.MrcciNewCommand(aCommand, aCommand.ClientId()); - StartReleaseTimer(aCommand); - } - -/** Starts the release timer (only applicable to press commands). - -If a release is not received quickly enough to treat this press as -a click, the release timer is started. 2s after receiving a button -press we should assume the release if we haven't received one. - -@param aCommand The command to start the timer for. -*/ -void CPassthroughHelper::StartReleaseTimer(CControlCommand& aCommand) - { - TAvrcpTimerExpiryInfo* timerInfo = new(aCommand.TimerExpiryInfo())TAvrcpTimerExpiryInfo(this, aCommand); - - TCallBack callback(ReleaseExpiry, timerInfo); - TDeltaTimerEntry* timerEntry = new(aCommand.TimerEntry())TDeltaTimerEntry(callback); - - iTimer.Queue(KRcpIncomingButtonReleaseTimeout, *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 CPassthroughHelper::ReleaseExpiry(TAny* aExpiryInfo) - { - LOG_STATIC_FUNC - TAvrcpTimerExpiryInfo *timerInfo = reinterpret_cast(aExpiryInfo); - (reinterpret_cast(timerInfo->iHandler))->ReleaseExpiry(timerInfo->iCommand); - - return KErrNone; - } - -/** Deals with expiry of release timer. - -1) Generate release for this command. -2) Inform RemCon of available release command. - -@param aCommand The CControlCommand that has expired. -*/ -void CPassthroughHelper::ReleaseExpiry(CControlCommand& aCommand) - { - LOG_FUNC - __ASSERT_DEBUG((aCommand.ButtonAct() == AVCPanel::EButtonPress), AvrcpUtils::Panic(EAvrcpReleaseExpiryForRelease)); - __ASSERT_DEBUG(!aCommand.Click(), AvrcpUtils::Panic(EAvrcpReleaseExpiryForClick)); - - // We haven't received a release within the allotted time. Assume - // one and generate it to RemCon. - BalanceHandledCommand(aCommand); - }