diff -r 22de2e391156 -r 20ac952a623c remotecontrol/avrcp/remconbeareravrcp/src/avrcputils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remotecontrol/avrcp/remconbeareravrcp/src/avrcputils.cpp Wed Oct 13 16:20:29 2010 +0300 @@ -0,0 +1,360 @@ +// 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: +// + +#include +#include +#include +#include +#include +#include "avrcplog.h" +#include "avrcputils.h" + +/** +@file +@internalComponent +@released +*/ + +/** Utility AVRCP panic function. + +@param aPanic The panic number. +*/ +void AvrcpUtils::Panic(TAvrcpPanic aPanic) + { + User::Panic(KAvrcpPanicName, aPanic); + } + + +/** Set the command data. This overwrites the current +contents of the data buffer. + +@param aCommandData The buffer in which to set the data. +@param aOffset The offset within aCommandData to set the data. +@param aLength The length of data to replace. +@param aValue The new value for the replaced data. +*/ +void AvrcpUtils::SetCommandDataFromInt(RBuf8& aCommandData, + TInt aOffset, TInt aLength, TInt aValue) + { + LOG_STATIC_FUNC + __ASSERT_DEBUG(aLength <= 4, Panic(EAvrcpCommandDataTooLong)); + + for(TInt i = 0; i < aLength; i++) + { + aCommandData[aOffset+i] = aValue >> (8*i); + } + } + +/** Reads command data from the buffer to an int. + +@param aCommandData The buffer from which to read the data. +@param aOffset The offset within aCommandData read from. +@param aLength The length of data to read. This must not be + more than 4. +@param aValue On return, the value of the specified data section. +*/ +void AvrcpUtils::ReadCommandDataToInt(const RBuf8& aCommandData, + TInt aOffset, TInt aLength, TInt& aValue) + { + LOG_STATIC_FUNC + __ASSERT_DEBUG(aLength <= 4, Panic(EAvrcpCommandDataTooLong)); + + aValue = 0; + + for(TInt i = 0 ; i < aLength; i++) + { + aValue |= aCommandData[aOffset+i]<<(8*i); + } + } + +/** Convert from a RemCon address to a bluetooth device address. + +@param aRemoteAddress The RemCon format address to convert. +@param aBTAddr On return, the bluetooth device address. +@return Whether the conversion could be performed successfully. +*/ +TInt AvrcpUtils::RemConToBTAddr(const TRemConAddress& aRemoteAddress, TBTDevAddr& aBTAddr) + { + LOG_STATIC_FUNC + TInt err = KErrArgument; + + // Check client has provided us a valid address + if(aRemoteAddress.Addr().Length() == KBTDevAddrSize) + { + aBTAddr = TBTDevAddr(aRemoteAddress.Addr()); + err = KErrNone; + } + else + { + __ASSERT_DEBUG(EFalse, AvrcpUtils::Panic(EAvrcpBadBTAddr)); + } + + return err; + } + +/** Convert from a bluetooth device address to a RemCon address. + +We assume this cannot fail, as bluetooth addresses are generated +internally rather than by a client, so they should always be +valid, and so convertible. + +@param aBTAddr The bluetooth device address to convert. +@param aRemoteAddress On return, the RemCon format address. +*/ +void AvrcpUtils::BTToRemConAddr(const TBTDevAddr& aBTAddr, TRemConAddress& aRemConAddress) + { + LOG_STATIC_FUNC + aRemConAddress.Addr() = aBTAddr.Des(); + aRemConAddress.BearerUid() = TUid::Uid(KRemConBearerAvrcpImplementationUid); + } + +NONSHARABLE_CLASS(CSpecificThreadCallBackBody) + : public CActive + { +public: + static CSpecificThreadCallBackBody* NewL(const TCallBack& aCallBack, TInt aPriority); + ~CSpecificThreadCallBackBody(); + + TInt Start(); + TInt CallBack(); + void HandleCancel(); + +private: + CSpecificThreadCallBackBody(const TCallBack& aCallBack, TInt aPriority); + void ConstructL(); + + TInt AsyncMessage(TInt aParam); + +private: // from CActive + void RunL(); + void DoCancel(); + +private: + TCallBack iCallBack; + + RThread iLocalThread; + + RMsgQueue iInbound; + RMsgQueue iOutbound; + }; + +RSpecificThreadCallBack::RSpecificThreadCallBack() + : iBody(NULL) + { + LOG_FUNC + } + +TInt RSpecificThreadCallBack::Create(const TCallBack& aCallBack, TInt aPriority) + { + TRAPD(err, iBody = CSpecificThreadCallBackBody::NewL(aCallBack, aPriority)); + return err; + } + +void RSpecificThreadCallBack::Close() + { + LOG_FUNC + delete iBody; + iBody = NULL; + } + +TInt RSpecificThreadCallBack::Start() + { + return iBody->Start(); + } + +TInt RSpecificThreadCallBack::CallBack() + { + return iBody->CallBack(); + } + +void RSpecificThreadCallBack::Cancel() + { + return iBody->HandleCancel(); + } + +CSpecificThreadCallBackBody* CSpecificThreadCallBackBody::NewL(const TCallBack& aCallBack, TInt aPriority) + { + CSpecificThreadCallBackBody* self = new(ELeave) CSpecificThreadCallBackBody(aCallBack, aPriority); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CSpecificThreadCallBackBody::CSpecificThreadCallBackBody(const TCallBack& aCallBack, TInt aPriority) + : CActive(aPriority) + , iCallBack(aCallBack) + { + LOG_FUNC + } + +void CSpecificThreadCallBackBody::ConstructL() + { + User::LeaveIfError(iInbound.CreateLocal(1)); + User::LeaveIfError(iOutbound.CreateLocal(1)); + } + +CSpecificThreadCallBackBody::~CSpecificThreadCallBackBody() + { + LOG_FUNC + HandleCancel(); + iInbound.Close(); + iOutbound.Close(); + iLocalThread.Close(); + } + +TInt CSpecificThreadCallBackBody::Start() + { + TInt err = KErrNone; + if(!IsAdded()) + { + err = iLocalThread.Duplicate(RThread()); + if(err == KErrNone) + { + CActiveScheduler::Add(this); + iInbound.NotifyDataAvailable(iStatus); + SetActive(); + } + } + return err; + } + +TInt CSpecificThreadCallBackBody::CallBack() + { + TInt err = KErrUnknown; + if(iLocalThread.Id() == RThread().Id()) + { + // Simple synchronous case. + err = iCallBack.CallBack(); + } + else + { + RThread thisThread; + err = thisThread.Duplicate(RThread()); + if(err == KErrNone) + { + err = AsyncMessage(thisThread.Handle()); + } + } + return err; + } + +TInt CSpecificThreadCallBackBody::AsyncMessage(TInt aParam) + { + TInt err = KErrNone; + TRequestStatus logonStatus; + iLocalThread.Logon(logonStatus); + if(logonStatus == KErrNoMemory) + { + // This seems kludgy, but I think it is the most reliable way. + User::WaitForRequest(logonStatus); // Ensure the all requests are correct... + err = KErrNoMemory; + } + else + { + iInbound.SendBlocking(aParam); + TRequestStatus status; + iOutbound.NotifyDataAvailable(status); + User::WaitForRequest(status, logonStatus); + if(status == KRequestPending) + { + // Remote thread is dead + iOutbound.CancelDataAvailable(); + User::WaitForRequest(status); + err = KErrDied; + } + else + { + // Success (the thread may have subsequently died, but we are only concerned with this call). + iLocalThread.LogonCancel(logonStatus); + User::WaitForRequest(logonStatus); + err = status.Int(); + if(err == KErrNone) + { + iOutbound.ReceiveBlocking(err); + } + } + } + return err; + } + + +void CSpecificThreadCallBackBody::RunL() + { + TInt threadHandle; + iInbound.ReceiveBlocking(threadHandle); + if(threadHandle == 0) + { + // 0 is a cancel message + // therefore don't do anything + iOutbound.SendBlocking(KErrNone); + } + else + { + RThread remoteThread; + remoteThread.SetHandleNC(threadHandle); + + TInt result = iCallBack.CallBack(); + + // There doesn't seem to be a safe way of handling when the other thread + // dies...... + iOutbound.SendBlocking(result); + + remoteThread.Close(); + + iInbound.NotifyDataAvailable(iStatus); + SetActive(); + } + } + +void CSpecificThreadCallBackBody::DoCancel() + { + if(RThread().Id() == iLocalThread.Id()) + { + iInbound.CancelDataAvailable(); + } + else + { + // other thread cancelling - so just complete the + // request + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrCancel); + } + } + +void CSpecificThreadCallBackBody::HandleCancel() + { + if(IsAdded()) + { + if(RThread().Id() == iLocalThread.Id()) + { + Cancel(); // synchronous cancel is fine in same thread... + } + else + { + // In a different thread - this is more interesting... + TInt err = AsyncMessage(0); // 0 is special as it means cancel. + if(err == KErrDied && IsActive()) + { + // Remote thread has already died so we need to tidy up the + // active object ourselves. + Cancel(); + } + } + } + // else shouldn't be active... + } + +