diff -r 000000000000 -r f63038272f30 bluetoothappprofiles/avrcp/remconbeareravrcp/src/avrcprouter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothappprofiles/avrcp/remconbeareravrcp/src/avrcprouter.cpp Mon Jan 18 20:28:57 2010 +0200 @@ -0,0 +1,499 @@ +// 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 + +#include "avrcpcommand.h" +#include "avrcplog.h" +#include "avrcprouter.h" +#include "avrcputils.h" +#include "commandhandlerinterface.h" + +using namespace SymbianAvctp; + +/** Constructor. + +@param aRemotes The list of remote devices known to AVRCP. +@param aBearer The bearer. +@return A partially constructed CRcpRouter. +*/ +CRcpRouter::CRcpRouter(MAvrcpBearer& aBearer) + : iChannel(NULL) + , iBearer(aBearer) + , iSendQueue(_FOFF(CAvrcpCommand, iSendLink)) + , iState(EAvrcpRouterCanSend) + { + LOG_FUNC + } + +/** Destructor. +*/ +CRcpRouter::~CRcpRouter() + { + LOG_FUNC + // The lifetime of the Router is the same as that of the bearer plugin. + // This means that there is no point worrying about the stuff on our + // send queue as we won't be around to pass the results up to RemCon. + while (!iSendQueue.IsEmpty()) + { + CAvrcpCommand *command = iSendQueue.First(); + command->iSendLink.Deque(); + command->DecrementUsers(); + } + } + +//------------------------------------------------------------------ +// Data functions called from command handlers +//------------------------------------------------------------------ + +/** Adds command to send queue. + +This message will be sent as soon as the iAvcp becomes +free for sending, unless the command is removed before +then. + +@param aCommand The command to send. +@see CRcpRouter::RemoveFromSendQueue +*/ +void CRcpRouter::AddToSendQueue(CAvrcpCommand& aCommand) + { + LOG_FUNC + + __ASSERT_ALWAYS(!aCommand.iSendLink.IsQueued(), AVRCP_PANIC(ECommandAlreadyQueuedForSending)); + + iSendQueue.AddLast(aCommand); + aCommand.IncrementUsers(); + + if(iState == EAvrcpRouterCanSend) + { + Send(); + } + } + +/** Remove command from send queue. + +@param aCommand The command that is not to be sent. +*/ +void CRcpRouter::RemoveFromSendQueue(CAvrcpCommand& aCommand) + { + LOG_FUNC + + if(iSendQueue.IsFirst(&aCommand)) + { + // If this is at the front of the queue it's currently being + // sent. Cancel that and start off the next thing. + iChannel->MacCancelSend(); + aCommand.iSendLink.Deque(); + iState = EAvrcpRouterCanSend; + if(!iSendQueue.IsEmpty()) + { + Send(); + } + } + else + { + // Still waiting to be sent so we can just sneak it out of + // the queue. + aCommand.iSendLink.Deque(); + } + } + +//------------------------------------------------------------------ +// Control functions called from bearer +//------------------------------------------------------------------ + +/** Try to bring up an explicit connection to a remote. + +@param aAddr The address of the remote. +@return System wide error. KErrNone if this request will be + attempted, and generate a ConnectConfirm. +*/ +TInt CRcpRouter::ConnectRequest(const TBTDevAddr& aAddr) + { + LOG_FUNC + return iChannel->MacAttachRequest(aAddr); + } + +/** Try to bring down an explicit connection to a remote. + +@param aAddr The address of the remote. +@return System wide error. KErrNone if the disconnect will be + attempted, and generate a DisconnectConfirm. +*/ +TInt CRcpRouter::DisconnectRequest(const TBTDevAddr& aAddr) + { + LOG_FUNC + return iChannel->MacDetachRequest(aAddr); + } + +//------------------------------------------------------------------ +// MAvctpEventNotify functions called from RAvctp +//------------------------------------------------------------------ + +/** AVCTP Connection Indicate. + +This is called when a remote device has connected +to us. NB we don't return the configuration status as +in Appendix A - AVCTP Upper Interface of [R2]. If aAccept +is not changed the connection will be refused however +this may not result in the actual disconnection of the +device if another RAvctp client did accept the connection. + +@param aBTDevice the address of the device connected to +@param aAccept this parameter is provided so that the client + of RAvctp can indicate whether they want to accept the + connection. The meaning of a refusal is that you don't + care whether or not the connection is there or not. +@see RAvctp +*/ +void CRcpRouter::MaenAttachIndicate(const TBTDevAddr& aBTDevice, TInt aMtu, TBool& aAccept) + { + LOG_FUNC + aAccept = ETrue; + + // if we have already received data from this device we will have + // informed RemCon about it already, so don't pass up the connection + // now + if(!iBearer.IncomingHandler(aBTDevice)) + { + iBearer.ConnectIndicate(aBTDevice); + } + + MIncomingCommandHandler* handler = iBearer.IncomingHandler(aBTDevice); + if(handler) + { + handler->MaxPacketSize(aMtu); + aAccept = ETrue; + } + else + { + aAccept = EFalse; + } + } + +/** AVCTP Connection Confirm. + +This is a response to RAvctp::ConnectRequest and passes on the +result of the Connection attempt. NB we don't return the +configuration status as in Appendix A - AVCTP Upper +Interface of [R2]. If the aConnectResult is KErrNone +then iAvctp is now connected. + +@param aBTDevice the address of the device connected to +@param aConnectResult connection result - one of the + system-wide error codes. +@see RAvctp +*/ +void CRcpRouter::MaenAttachConfirm(const TBTDevAddr& aBTDevice, TInt aMtu, TInt aConnectResult) + { + LOG_FUNC + iBearer.ConnectConfirm(aBTDevice, aConnectResult); + + MIncomingCommandHandler* handler = iBearer.IncomingHandler(aBTDevice); + if(handler) + { + handler->MaxPacketSize(aMtu); + } + } + +/** AVCTP Disconnection Indication. + +Indicates that a remote device has disconnected from us. +It is only called if the device had been explicitly Connected to. + +@param aBTDevice the address of the disconnecting device +@see RAvctp +*/ +void CRcpRouter::MaenDetachIndicate(const TBTDevAddr& aBTDevice) + { + LOG_FUNC + iBearer.DisconnectIndicate(aBTDevice); + } + +/** AVCTP Disconnection Confirm. + +@param aBTDevice the address of the disconnected device +@param aDisconnectResult will be one of the system-wide + error codes. If KErrTimedOut is + returned then the RAvctp will be + disconnected. +@see RAvctp +*/ +void CRcpRouter::MaenDetachConfirm(const TBTDevAddr& aBTDevice, TInt aDisconnectResult) + { + LOG_FUNC + iBearer.DisconnectConfirm(aBTDevice, aDisconnectResult); + } + +/** AVCTP Message received indication. + +This method is called when a message has been received from +the given device on the RAvctp's PID. + +Note that because AVCTP is a connectionless protocol, it is +perfectly possible to get a MaenMessageReceivedIndicate event +from a device that you have not either explicitly connected to. +For instance even if you don't accept a MaenConnectIndicate +you may still receive messages from that remote device. + +@param aBTDevice address of the device sending us an AVCTP message +@param aTransactionLabel message transaction label +@param aType type of message +@param aIpidBitSet this will be set to true only if a message has been received indicating + that the profile corresponding to the originally sent message is not valid. + If RAvctp was used to send the message then this response will have come from + the remote device aBTDevice. +@param aMessageInformation contains only the AVCTP Command / Response Message Information and not the whole packet. + Ownership transferred to client. +@see RAvctp +*/ +void CRcpRouter::MaenMessageReceivedIndicate(const TBTDevAddr& aBTDevice, + SymbianAvctp::TTransactionLabel aTransactionLabel, + SymbianAvctp::TMessageType aType, + TBool aIpidBitSet, + const TDesC8& aMessageInformation) + { + LOG_FUNC + AVRCPLOG(aMessageInformation) + + // Find the right handler + if(aType == ECommand) + { + MIncomingCommandHandler* handler = iBearer.IncomingHandler(aBTDevice); + + if(!handler) + { + iBearer.ConnectIndicate(aBTDevice); + + handler = iBearer.IncomingHandler(aBTDevice); + } + + if(handler) + { + // If this leaves the handler is rejecting handling this command, just + // ignore it. + TRAP_IGNORE(handler->ReceiveCommandL(aMessageInformation, aTransactionLabel, aBTDevice)); + } + } + else + { + MOutgoingCommandHandler* handler = iBearer.OutgoingHandler(aBTDevice); + if(handler) + { + handler->ReceiveResponse(aMessageInformation, aTransactionLabel, aIpidBitSet); + } + } + } + +/** AVCTP Message send complete. + +This method is called when a RAvctp has attempted to send +the message defined by aTransactionLabel and aBTDevice. +@param aTransactionLabel The transaction label of the message + that has been sent +@param aBTDevice the device to which the send has completed +@param aSendResult KErrNone if the send was successful or one + of the system-wide error codes +@see RAvctp +*/ +void CRcpRouter::MaenMessageSendComplete(const TBTDevAddr& aBTDevice, + SymbianAvctp::TTransactionLabel aTransactionLabel, + TInt aSendResult) + { + LOG_FUNC + __ASSERT_ALWAYS(!iSendQueue.IsEmpty(), AvrcpUtils::Panic(EAvrcpNoOutstandingSend)); + + CAvrcpCommand* command = iSendQueue.First(); + + __ASSERT_ALWAYS(command->TransactionLabel() == aTransactionLabel, AvrcpUtils::Panic(EAvrcpUnknownAvctpTransId)); + + MAvrcpCommandHandler* handler = NULL; + if(command->MessageType() == ECommand) + { + handler = iBearer.OutgoingHandler(aBTDevice); + } + else + { + handler = iBearer.IncomingHandler(aBTDevice); + } + + if(handler) + { + handler->MessageSent(*command, aSendResult); + } + + // Deque before calling Decrement because Decrement handling may involve + // deleting command + command->iSendLink.Deque(); + command->DecrementUsers(); + + // Now able to do another send. Toggle our state and check if there + // are any commands waiting. + iState = EAvrcpRouterCanSend; + if(!iSendQueue.IsEmpty()) + { + Send(); + } + } + +/** AVCTP Close Complete. + +This is the response to the CloseGracefully() that has been +called on a RAvctp object. It is the last event that will be +called until the RAvctp object is Open()'d again. +@see RAvctp +*/ +void CRcpRouter::MaenCloseComplete() + { + LOG_FUNC + } + +/** AVCTP error notification. + +Note an errored device does not indicate that the device has +been disconnected. If it has then a MaenDisconnectIndicate +event will be used to indicate this. + +@param aBTDevice the remote device associated with the error or TBTDevAddr(0) for a general error +@param aError system wide error +@see RAvctp +*/ +void CRcpRouter::MaenErrorNotify(const TBTDevAddr& /*aBTDevice*/, TInt /*aError*/) + { + LOG_FUNC + } + +/** +Returns a null aObject if the extension is not implemented, +or a pointer to another interface if it is. + +@param aInterface UID of the interface to return +@param aObject system wide error +@see RAvctp +*/ +void CRcpRouter::MaenExtensionInterfaceL(TUid /*aInterface*/, void*& aObject) + { + LOG_FUNC + aObject = NULL; + } + +//------------------------------------------------------------------ +// Utility functions +//------------------------------------------------------------------ + +/** Issue a send to AVCTP. + +This sends the first message on the command queue. +*/ +void CRcpRouter::Send() + { + LOG_FUNC + __ASSERT_ALWAYS(!iSendQueue.IsEmpty(), AvrcpUtils::Panic(EAvrcpNoOutstandingSend)); + + CAvrcpCommand* command = iSendQueue.First(); + +#ifdef _DEBUG + TInt err = +#endif // _DEBUG + iChannel->MacSendMessage(command->RemoteAddress(), + command->TransactionLabel(), + command->MessageType(), + command->Data()); + + __ASSERT_DEBUG(err == KErrNone, AvrcpUtils::Panic(EAvrcpSendingMessageFailed)); + + iState = EAvrcpRouterSending; + } + +/** Factory funtion. + +@param aAvctp An open RAvctp instance. +@param aBearer The bearer. +@return A fully constructed CRcpRouter. +@leave System wide error codes. +*/ +CControlRouter* CControlRouter::NewL(RAvctp& aAvctp, MAvrcpBearer& aBearer) + { + LOG_STATIC_FUNC + CControlRouter* router = new(ELeave) CControlRouter(aAvctp, aBearer); + CleanupStack::PushL(router); + router->ConstructL(); + CleanupStack::Pop(router); + return router; + } + +CControlRouter::~CControlRouter() + { + LOG_FUNC + iAvctp.Close(RAvctp::ENormal); + } + +CControlRouter::CControlRouter(RAvctp& aAvctp, MAvrcpBearer& aBearer) + : CRcpRouter(aBearer) + , iAvctp(aAvctp) + { + LOG_FUNC + } + +void CControlRouter::ConstructL() + { + LOG_FUNC + LEAVEIFERRORL(iAvctp.Open(*this, KAvrcpPid, iChannel)); + } + +/** Factory funtion. + +@param aAvctp An open RAvctp instance. +@param aBearer The bearer. +@return A fully constructed CRcpRouter. +@leave System wide error codes. +*/ +CBulkRouter* CBulkRouter::NewL(RAvctp& aAvctp, MAvrcpBearer& aBearer) + { + LOG_STATIC_FUNC + CBulkRouter* router = new(ELeave) CBulkRouter(aAvctp, aBearer); + CleanupStack::PushL(router); + router->ConstructL(); + CleanupStack::Pop(router); + return router; + } + +CBulkRouter::~CBulkRouter() + { + LOG_FUNC + iAvctp.UninstallSecondaryChannel(); + } + +CBulkRouter::CBulkRouter(RAvctp& aAvctp, MAvrcpBearer& aBearer) + : CRcpRouter(aBearer) + , iAvctp(aAvctp) + { + LOG_FUNC + } + +void CBulkRouter::ConstructL() + { + LOG_FUNC + LEAVEIFERRORL(iAvctp.InstallSecondaryChannel(*this, iChannel)); + } +