--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothappprofiles/avrcp/remconbeareravrcp/src/remconbeareravrcp.cpp Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,1155 @@
+// 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 <avctpservices.h>
+#include <bttypes.h>
+#include <e32base.h>
+#include <remconaddress.h>
+#include <remconbeareravrcp.h>
+#include <remcon/remconbearerobserver.h>
+#include "controlcommand.h"
+#include "browsecommand.h"
+#include "avrcpbrowsingcommandhandler.h"
+#include "avrcpincomingcommandhandler.h"
+#include "avrcpoutgoingcommandhandler.h"
+#include "avrcpremotedevice.h"
+#include "avrcprouter.h"
+#include "avrcputils.h"
+#include "avrcpplayerinfomanager.h"
+#include "bulkbearer.h"
+#include "controlbearer.h"
+#include "mediabrowse.h"
+#include "nowplaying.h"
+
+#include "avrcplog.h"
+
+
+
+/** Allocates and constructs a new CRemConBearerAvrcp object.
+
+@param aParams Bearer construction params used for base class construction.
+@return A new CRemConBearerAvrcp object.
+@leave System wide error code
+*/
+CRemConBearerAvrcp* CRemConBearerAvrcp::NewL(TBearerParams& aParams)
+ {
+ LOG_STATIC_FUNC
+ CRemConBearerAvrcp* bearer = new(ELeave) CRemConBearerAvrcp(aParams);
+ CleanupStack::PushL(bearer);
+
+ TRAPD(err, bearer->ConstructL());
+
+ if(err == KErrNoMemory)
+ {
+ User::Leave(err);
+ }
+ // else KErrNone or some other error -- swallow it.
+
+ CleanupStack::Pop(bearer);
+ return bearer;
+ }
+
+/** Constructor.
+
+@param aParams Bearer construction params used for base class construction.
+*/
+CRemConBearerAvrcp::CRemConBearerAvrcp(TBearerParams& aParams) :
+ CRemConBearerPlugin(aParams), iRemotes(_FOFF(CRcpRemoteDevice, iLink)),
+ iReadyCommands(_FOFF(CAvrcpCommand, iReadyLink)), iReadyResponses(_FOFF(CAvrcpCommand, iReadyLink)),
+ iReadyNotifyResponses(_FOFF(CControlCommand, iReadyLink)),
+ iReadyNotifyCommands(_FOFF(CAvrcpCommand, iReadyLink))
+ {
+ LOG_FUNC
+ }
+
+/** Second phase construction.
+
+@leave System wide error code
+*/
+void CRemConBearerAvrcp::ConstructL()
+ {
+ LOG_FUNC
+
+ // Set-up TLS
+ LEAVEIFERRORL(Dll::SetTls(reinterpret_cast<TAny*>(EControlThread)));
+
+ // New up a router. This opens and uses the RAvctp.
+ // On initialisation it should begin listening.
+ iRouter = CControlRouter::NewL(iAvctp, *this);
+ iTimer = CDeltaTimer::NewL(CActive::EPriorityStandard);
+ iPlayerInfoManager = CAvrcpPlayerInfoManager::NewL(Observer(), *this);
+ iInternalHandler = &iPlayerInfoManager->InternalCommandHandler();
+
+ // Create the bulk bearer - actual usage occurs in the bulk thread.
+ iBulkBearer = CAvrcpBulkBearer::NewL(iAvctp, *iPlayerInfoManager);
+ iConstructionComplete = ETrue;
+ }
+
+/** Destructor.
+*/
+CRemConBearerAvrcp::~CRemConBearerAvrcp()
+ {
+ LOG_FUNC
+
+ while (!iRemotes.IsEmpty())
+ {
+ CRcpRemoteDevice* remote = iRemotes.First();
+ remote->iLink.Deque();
+ remote->Disconnect(EFalse);
+ delete remote;
+ }
+
+ delete iRouter;
+
+ delete iBulkBearer;
+
+ // Delete the timer last as pending events
+ // are cancelled in remote->Disconnect
+
+ delete iTimer;
+
+ delete iPlayerInfoManager;
+
+ Dll::FreeTls();
+ }
+
+//---------------------------------------------------------------------
+// RemConBearer control functions
+//---------------------------------------------------------------------
+
+/** Called by RemCon to retrieve a response on a connection.
+
+This must only be called as a result of a NewResponse upcall.
+
+@param aInterfaceUid The UID of the outer-layer client API specifying the response.
+@param aId The command identifier used as a cookie for command/response matching.
+@param aOperationId The ID of the response operation in the outer-layer client API.
+@param aData API-specific message data. On success, ownership is returned.
+@param aAddr The connection.
+*/
+TInt CRemConBearerAvrcp::GetResponse(TUid& aInterfaceUid,
+ TUint& aId,
+ TUint& aOperationId,
+ RBuf8& aCommandData,
+ TRemConAddress& aAddr)
+ {
+ LOG_FUNC
+
+ // If object only partially constructed, swallow the request
+ __ASSERT_DEBUG(iConstructionComplete, AVRCP_PANIC(EAvrcpNoResponsesAvailable));
+
+
+ TInt result = KErrNotFound;
+
+ if(!iReadyResponses.IsEmpty())
+ {
+ CAvrcpCommand* command = iReadyResponses.First();
+ TBTDevAddr btAddr;
+ command->GetCommandInfo(aInterfaceUid, aId, aOperationId, aCommandData, btAddr);
+ AvrcpUtils::BTToRemConAddr(btAddr, aAddr);
+
+ // Remove command from queue first because calling
+ // DecrementUsers() may delete command
+ command->iReadyLink.Deque();
+ command->DecrementUsers();
+ result = KErrNone;
+ }
+ else
+ {
+ // RemCon is trying to pick up a response we don't think we have
+ __ASSERT_DEBUG(EFalse, AVRCP_PANIC(EAvrcpNoResponsesAvailable));
+ }
+
+ return result;
+ }
+
+/** Called by RemCon to retrieve a response on a connection.
+
+This must only be called as a result of a NewResponse upcall.
+
+@param aInterfaceUid The UID of the outer-layer client API specifying the response.
+@param aId The command identifier used as a cookie for command/response matching.
+@param aOperationId The ID of the response operation in the outer-layer client API.
+@param aData API-specific message data. On success, ownership is returned.
+@param aAddr The connection.
+*/
+TInt CRemConBearerAvrcp::GetNotifyResponse(TUid& aInterfaceUid,
+ TUint& aId,
+ TUint& aOperationId,
+ RBuf8& aCommandData,
+ TRemConAddress& aAddr,
+ TRemConMessageSubType& aSubMessageType)
+ {
+ LOG_FUNC
+
+ // If object only partially constructed, swallow the request
+ __ASSERT_DEBUG(iConstructionComplete, AVRCP_PANIC(EAvrcpNoResponsesAvailable));
+
+
+ TInt result = KErrNotFound;
+
+ if(!iReadyNotifyResponses.IsEmpty())
+ {
+ CControlCommand* command = iReadyNotifyResponses.First();
+ TBTDevAddr btAddr;
+ command->GetCommandInfo(aInterfaceUid, aId, aOperationId, aCommandData, btAddr);
+ AvrcpUtils::BTToRemConAddr(btAddr, aAddr);
+
+ switch ( command->Frame().Type() )
+ {
+ case AVC::EInterim:
+ aSubMessageType = ERemConNotifyResponseInterim;
+ break;
+ case AVC::EChanged:
+ aSubMessageType = ERemConNotifyResponseChanged;
+ break;
+ case AVC::ERejected: // fall into default
+ case AVC::ENotImplemented:// fall into default
+ default:
+ aSubMessageType = ERemConMessageDefault;
+ break;
+ }
+
+ // Remove command from queue first because calling
+ // DecrementUsers() may delete command
+ command->iReadyLink.Deque();
+ command->DecrementUsers();
+ result = KErrNone;
+ }
+ else
+ {
+ // RemCon is trying to pick up a response we don't think we have
+ __ASSERT_DEBUG(EFalse, AVRCP_PANIC(EAvrcpNoResponsesAvailable));
+ }
+
+ return result;
+ }
+
+/** Called by RemCon to send a command on a connection.
+
+@param aInterfaceUid The UID of the outer-layer client API specifying the command.
+@param aOperationId The ID of the command operation in the outer-layer client API.
+@param aId The command identifier used as a cookie for command/response matching.
+@param aData API-specific message data. On success, ownership is passed.
+@param aAddr The connection.
+@return Error. This request is synchronous. It returns KErrNone when AVRCP has
+taken responsibility for sending the message. This involves checking that the message
+is well-formed and adding it to the send queue.
+*/
+TInt CRemConBearerAvrcp::SendCommand(TUid aInterfaceUid,
+ TUint aOperationId,
+ TUint aId,
+ RBuf8& aData,
+ const TRemConAddress& aAddr)
+ {
+ LOG_FUNC
+ // RemCon retains ownership of the data in aData until
+ // this function returns KErrNone.
+
+ if (!iConstructionComplete)
+ {
+ // Object only partially constructed, swallow the request
+ return KErrNotSupported;
+ }
+
+
+ TBTDevAddr btAddr;
+ TInt err = AvrcpUtils::RemConToBTAddr(aAddr, btAddr);
+
+ if(err == KErrNone)
+ {
+ CRcpRemoteDevice* remote = RemoteDevice(btAddr);
+ __ASSERT_ALWAYS(remote, AVRCP_PANIC(EAvrcpNotConnected));
+
+ TRAP(err, remote->OutgoingHandler().SendCommandL(aInterfaceUid,
+ aOperationId,
+ aId,
+ aData,
+ btAddr));
+ }
+
+ return err;
+ }
+
+
+/** Called by RemCon to retrieve a command on a connection.
+
+This must only be called as a result of a NewCommand upcall.
+
+@param aInterfaceUid The UID of the outer-layer client API specifying the command.
+@param aId The command identifier used as a cookie for command/response matching.
+@param aOperationId The ID of the command operation in the outer-layer client API.
+@param aData API-specific message data. On success, ownership is returned.
+@param aAddr The connection.
+*/
+TInt CRemConBearerAvrcp::GetCommand(TUid& aInterfaceUid,
+ TUint& aId,
+ TUint& aOperationId,
+ RBuf8& aCommandData,
+ TRemConAddress& aAddr)
+ {
+ TInt result = KErrNotFound;
+
+ if(!iReadyCommands.IsEmpty())
+ {
+ CAvrcpCommand* command = GetFirstCommand(iReadyCommands, aInterfaceUid, aId, aOperationId, aCommandData, aAddr);
+ if(command)
+ {
+ // Remove command from queue first because calling
+ // DecrementUsers() may delete command
+ command->iReadyLink.Deque();
+ command->DecrementUsers();
+ result = KErrNone;
+ }
+ }
+ else
+ {
+ __DEBUGGER();
+ }
+
+ return result;
+ }
+
+/** Called by RemCon to retrieve a notify command on a connection.
+
+This must only be called as a result of a NewNotifyCommand upcall.
+
+@param aInterfaceUid The UID of the outer-layer client API specifying the command.
+@param aId The command identifier used as a cookie for command/response matching.
+@param aOperationId The ID of the command operation in the outer-layer client API.
+@param aData API-specific message data. On success, ownership is returned.
+@param aAddr The connection.
+*/
+TInt CRemConBearerAvrcp::GetNotifyCommand(TUid& aInterfaceUid,
+ TUint& aId,
+ TUint& aOperationId,
+ RBuf8& aCommandData,
+ TRemConAddress& aAddr)
+ {
+ TInt result = KErrNotFound;
+
+ CAvrcpCommand* command = GetFirstCommand(iReadyNotifyCommands, aInterfaceUid, aId, aOperationId, aCommandData, aAddr);
+ if(command)
+ {
+ // Remove command from queue first because calling
+ // DecrementUsers() may delete command
+ command->iReadyLink.Deque();
+ command->DecrementUsers();
+ result = KErrNone;
+ }
+
+ return result;
+ }
+
+/**
+Internal method, called by GetCommand() and GetNotifyCommand()
+
+@return The first command from the Queue. NULL if the queue is empty. The command remains
+ on the queue.
+*/
+CAvrcpCommand* CRemConBearerAvrcp::GetFirstCommand(TDblQue<CAvrcpCommand>& aQue, TUid& aInterfaceUid,
+ TUint& aId,
+ TUint& aOperationId,
+ RBuf8& aCommandData,
+ TRemConAddress& aAddr)
+ {
+ LOG_FUNC
+
+ // If object only partially constructed, swallow the request
+ __ASSERT_DEBUG(iConstructionComplete, AVRCP_PANIC(EAvrcpNoResponsesAvailable));
+
+ CAvrcpCommand* command = NULL;
+
+ if(! aQue.IsEmpty())
+ {
+ command = aQue.First();
+
+ // Calling GetCommandInfo transfers the command data to RemCon. This means
+ // once we have called it we are committed to returning KErrNone.
+ TBTDevAddr btAddr;
+ command->GetCommandInfo(aInterfaceUid, aId, aOperationId, aCommandData, btAddr);
+ AvrcpUtils::BTToRemConAddr(btAddr, aAddr);
+ }
+ else
+ {
+ // RemCon is trying to pick up a command we don't think we have
+ __ASSERT_DEBUG(EFalse, AVRCP_PANIC(EAvrcpNoResponsesAvailable));
+ }
+
+ return command;
+ }
+/** Called by RemCon to send a response on a connection.
+
+@param aInterfaceUid The UID of the outer-layer client API specifying the response.
+@param aOperationId The ID of the response operation in the outer-layer client API.
+@param aId The command identifier used as a cookie for command/response matching
+@param aData API-specific message data. On success, ownership is passed.
+@param aAddr The connection.
+@return Error. This request is synchronous. It is completed by AVRCP when it has
+taken responsibility for sending the message. This involves checking that the message
+is well-formed and adding it to the send queue.
+*/
+TInt CRemConBearerAvrcp::SendResponse(TUid aInterfaceUid,
+ TUint /*aOperationId*/,
+ TUint aId,
+ RBuf8& aData,
+ const TRemConAddress& aAddr)
+ {
+ LOG_FUNC
+ // RemCon retains ownership of the data in aData until
+ // this function returns KErrNone.
+
+ if (!iConstructionComplete)
+ {
+ // Object only partially constructed, swallow the request
+ return KErrNotSupported;
+ }
+
+
+ TBTDevAddr btAddr;
+ TInt err = AvrcpUtils::RemConToBTAddr(aAddr, btAddr);
+ __ASSERT_DEBUG(err == KErrNone, AVRCP_PANIC(EInvalidBtAddrInResponse));
+
+ if(btAddr != TBTDevAddr(0))
+ {
+ CRcpRemoteDevice* remote = RemoteDevice(btAddr);
+ __ASSERT_ALWAYS(remote, AVRCP_PANIC(EAvrcpNotConnected));
+
+ err = remote->IncomingHandler().SendRemConResponse(aInterfaceUid, aId, aData);
+ }
+ else
+ {
+ err = iInternalHandler->SendRemConResponse(aInterfaceUid, aId, aData);
+ }
+
+ return err;
+ }
+
+/** Called by RemCon when either
+ a) The TSP does not address a command to any clients
+ b) The TSP does not permit the response from any commands
+ c) All the clients disconnect from remcon before the response is sent
+ to send a null response on a connection. The connection must already
+ exist
+ @param aInterfaceUid The UID of the outer-layer client API that the command
+ was sent to
+ @param aOperationId The ID of the command operation sent to remcon
+ @param aId The command identifier used as a cookie for command/response
+ matching.
+ @param aAddr The connection.
+ */
+
+void CRemConBearerAvrcp::SendReject(TUid aInterfaceUid,
+ TUint /* aOperationId */,
+ TUint aTransactionId,
+ const TRemConAddress& aAddr)
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(iConstructionComplete, AVRCP_PANIC(EAvrcpNotFullyConstructed));
+
+ TBTDevAddr btAddr;
+ __DEBUG_ONLY(TInt err = )AvrcpUtils::RemConToBTAddr(aAddr, btAddr);
+ __ASSERT_DEBUG(err == KErrNone, AVRCP_PANIC(EInvalidBtAddrInResponse));
+
+ if(btAddr != TBTDevAddr(0))
+ {
+ CRcpRemoteDevice* remote = RemoteDevice(btAddr);
+ __ASSERT_ALWAYS(remote, AVRCP_PANIC(EAvrcpNotConnected));
+
+ remote->IncomingHandler().SendReject(aInterfaceUid, aTransactionId);
+ }
+ else
+ {
+ iInternalHandler->SendReject(aInterfaceUid, aTransactionId);
+ }
+
+ }
+
+/** Called by RemCon to establish a bearer-level connection to another party.
+
+Completion is signalled back in ConnectConfirm.
+
+@param aAddr The RemCon address to connect to.
+*/
+void CRemConBearerAvrcp::ConnectRequest(const TRemConAddress& aAddr)
+ {
+ LOG_FUNC
+
+ if (!iConstructionComplete)
+ {
+ // Object only partially constructed, error the request
+ Observer().ConnectConfirm(aAddr, KErrNotSupported);
+ return;
+ }
+
+
+ // Get a bluetooth address from the TRemConAddr
+ TBTDevAddr btAddr;
+ TInt convErr = AvrcpUtils::RemConToBTAddr(aAddr, btAddr);
+ if(convErr != KErrNone)
+ {
+ Observer().ConnectConfirm(aAddr, convErr);
+ return;
+ }
+
+ // Address for internal commands
+ if(btAddr == TBTDevAddr(0))
+ {
+ Observer().ConnectConfirm(aAddr, KErrNone);
+ return;
+ }
+
+ CRcpRemoteDevice* remote = RemoteDevice(btAddr);
+ if(remote)
+ {
+ // Already have a connection to this address
+ Observer().ConnectConfirm(aAddr, KErrNone);
+ return;
+ }
+
+ TRAPD(devErr, remote = CRcpRemoteDevice::NewL(btAddr, *iRouter, *this, Observer(), *iTimer, *iPlayerInfoManager));
+ if(devErr)
+ {
+ Observer().ConnectConfirm(aAddr, devErr);
+ return;
+ }
+
+ iRemotes.AddLast(*remote);
+ devErr = iRouter->ConnectRequest(btAddr);
+ if(devErr != KErrNone)
+ {
+ remote->iLink.Deque();
+ delete remote;
+
+ // Error with connect, generate errored ConnectConfirm.
+ Observer().ConnectConfirm(aAddr, devErr);
+ return;
+ }
+
+ return;
+ }
+
+/** Called by RemCon to destroy a bearer-level connection to another party.
+
+Completion is signalled back in DisconnectConfirm.
+
+@param aAddr The RemCon address to disconnect from.
+*/
+void CRemConBearerAvrcp::DisconnectRequest(const TRemConAddress& aAddr)
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(iConstructionComplete, AVRCP_PANIC(EAvrcpDisconnectRequestWhilePartiallyConstructed));
+
+ TBTDevAddr btAddr;
+ TInt err = AvrcpUtils::RemConToBTAddr(aAddr, btAddr);
+
+ if(!err)
+ {
+ // Address for internal commands
+ if(btAddr == TBTDevAddr(0))
+ {
+ Observer().DisconnectConfirm(aAddr, KErrNone);
+ }
+ else
+ {
+ CRcpRemoteDevice *remote = RemoteDevice(btAddr);
+ if(remote)
+ {
+ // calling disconnect gives the remote the opportunity
+ // to do anything necessary to commands still on its
+ // queue before we delete it.
+ remote->Disconnect(ETrue);
+ remote->iLink.Deque();
+ delete remote;
+
+ err = iRouter->DisconnectRequest(btAddr);
+ // If this failed generate an errored DisconnectConfirm now,
+ // otherwise we'll be prodded with a DisconnectConfirm from
+ // the router at a later date.
+ if(err != KErrNone)
+ {
+ Observer().DisconnectConfirm(aAddr, err);
+ }
+ }
+ else
+ {
+ __ASSERT_DEBUG(EFalse, AVRCP_PANIC(EAvrcpMismatchedConnectDisconnect));
+ Observer().DisconnectConfirm(aAddr, KErrNotFound);
+ }
+ }
+ }
+ else
+ {
+ Observer().DisconnectConfirm(aAddr, err);
+ }
+ }
+
+/** Called by RemCon to get the security policy.
+
+This is the list of capabilities required to make/destroy connections
+over the bearer, and to send and receive messages over the bearer.
+
+@return The bearer's security policy.
+*/
+TSecurityPolicy CRemConBearerAvrcp::SecurityPolicy() const
+ {
+ LOG_FUNC
+ return TSecurityPolicy(ECapabilityLocalServices);
+ }
+
+/** Called by RemCon when either (a) the number of controller clients changes
+from 0 to 1 or from 1 to 0, or (b) the number of target clients changes
+from 0 to 1 or from 1 to 0.
+
+@param aControllerPresent Whether there are any controller clients connected.
+@param aTargetPresent Whether there are any target clients connected.
+*/
+void CRemConBearerAvrcp::ClientStatus(TBool aControllerPresent, TBool aTargetPresent)
+ {
+ LOG_FUNC
+
+ if (!iConstructionComplete)
+ {
+ // Object only partially constructed, swallow the request
+ return;
+ }
+
+ iPlayerInfoManager->ClientStatus(aControllerPresent, aTargetPresent);
+ }
+
+/**
+Called by RemCon when a client has become available for addressing. Once this
+call has been made the bearer may use the provided TRemConClientId to address
+incoming commands and notifys to this client until RemCon calls ClientNotAvailable
+with this TRemConClientId.
+
+@param aId A unique identifier for this client, that can be used when addressing
+incoming commands.
+@param aClientType The basic type of this client
+@param aClientSubType More detailed type information on this client
+@param aName The name of this client in UTF-8.
+*/
+void CRemConBearerAvrcp::ClientAvailable(TRemConClientId& aId, TPlayerType aClientType, TPlayerSubType aClientSubType, const TDesC8& aName)
+ {
+ LOG_FUNC
+
+ if (!iConstructionComplete)
+ {
+ // Object only partially constructed, swallow the request
+ return;
+ }
+
+ iPlayerInfoManager->ClientAvailable(aId, aClientType, aClientSubType, aName);
+ }
+
+/**
+Called by RemCon when a client is no longer available for addressing. Once this
+call has been made the bearer shall not use this client id when addressing incoming
+commands and notifys until informed that the client is available again via
+ClientAvailable.
+
+@param aId The client that has ceased to be available.
+*/
+void CRemConBearerAvrcp::ClientNotAvailable(TRemConClientId& aId)
+ {
+ LOG_FUNC
+
+ if (!iConstructionComplete)
+ {
+ // Object only partially constructed, swallow the request
+ return;
+ }
+
+ iPlayerInfoManager->ClientNotAvailable(aId);
+ }
+
+TInt CRemConBearerAvrcp::SetLocalAddressedClient(TRemConClientId& aId)
+ {
+ LOG_FUNC
+
+ if (!iConstructionComplete)
+ {
+ // Object only partially constructed, swallow the request
+ return KErrNotSupported;
+ }
+
+ return iPlayerInfoManager->SetLocalAddressedClient(aId);
+ }
+
+void CRemConBearerAvrcp::ControllerFeaturesUpdated(RArray<TUid>& aSupportedInterfaces)
+ {
+ LOG_FUNC
+
+ if(!iConstructionComplete)
+ {
+ // Object only partially constructed, swallow the request
+ return;
+ }
+
+ // This is a best effort attempt at keeping the sdp record accurate. If we
+ // failed to update it then just live with it.
+ TRAP_IGNORE(iPlayerInfoManager->ControllerFeaturesUpdatedL(aSupportedInterfaces));
+ }
+
+//---------------------------------------------------------------------
+// Data notifications from the command handlers
+//---------------------------------------------------------------------
+
+/** Called from incoming handlers to notify that a command
+is ready for Remcon.
+
+@param aCommand The command that is ready.
+*/
+void CRemConBearerAvrcp::MrcciNewCommand(CAvrcpCommand& aCommand)
+ {
+ LOG_FUNC
+
+ // Need to put the command on the queue straight
+ // away in case RemCon collects it synchronously
+ iReadyCommands.AddLast(aCommand);
+ aCommand.IncrementUsers();
+
+ TRemConAddress remAddr;
+ AvrcpUtils::BTToRemConAddr(aCommand.RemoteAddress(), remAddr);
+
+ // Unaddressed variant
+ TInt err = Observer().NewCommand(remAddr);
+
+ if(err != KErrNone)
+ {
+ HandleUndeliveredCommand(aCommand, remAddr);
+ }
+ }
+
+/** Called from incoming handlers to notify that a command
+is ready for Remcon.
+
+@param aCommand The command that is ready.
+*/
+void CRemConBearerAvrcp::MrcciNewCommand(CAvrcpCommand& aCommand, const TRemConClientId& aClientId)
+ {
+ LOG_FUNC
+
+ // Need to put the command on the queue straight
+ // away in case RemCon collects it synchronously
+ iReadyCommands.AddLast(aCommand);
+ aCommand.IncrementUsers();
+
+ TRemConAddress remAddr;
+ AvrcpUtils::BTToRemConAddr(aCommand.RemoteAddress(), remAddr);
+
+ // if this is the null client id then RemCon will address it
+ TInt err = Observer().NewCommand(remAddr, aClientId);
+
+ if(err != KErrNone)
+ {
+ HandleUndeliveredCommand(aCommand, remAddr);
+ }
+ }
+
+/** Called from incoming handlers to notify that a notify command
+is ready for Remcon.
+
+@param aCommand The command that is ready.
+*/
+void CRemConBearerAvrcp::MrccciNewNotifyCommand(CAvrcpCommand& aCommand)
+ {
+ LOG_FUNC
+
+ // Need to put the command on the queue straight
+ // away in case RemCon collects it synchronously
+ iReadyNotifyCommands.AddLast(aCommand);
+ aCommand.IncrementUsers();
+
+ TRemConAddress remAddr;
+ AvrcpUtils::BTToRemConAddr(aCommand.RemoteAddress(), remAddr);
+
+ // Will be addressed by RemCon
+ TInt err = Observer().NewNotifyCommand(remAddr);
+
+ if(err != KErrNone)
+ {
+ HandleUndeliveredCommand(aCommand, remAddr);
+ }
+ }
+
+/** Called from incoming handlers to notify that a notify command
+is ready for Remcon.
+
+@param aCommand The command that is ready.
+*/
+void CRemConBearerAvrcp::MrccciNewNotifyCommand(CAvrcpCommand& aCommand, const TRemConClientId& aClientId)
+ {
+ LOG_FUNC
+
+ // Need to put the command on the queue straight
+ // away in case RemCon collects it synchronously
+ iReadyNotifyCommands.AddLast(aCommand);
+ aCommand.IncrementUsers();
+
+ TRemConAddress remAddr;
+ AvrcpUtils::BTToRemConAddr(aCommand.RemoteAddress(), remAddr);
+
+ // if this is the null client id then RemCon will address it
+ TInt err = Observer().NewNotifyCommand(remAddr, aClientId);
+
+ if(err != KErrNone)
+ {
+ HandleUndeliveredCommand(aCommand, remAddr);
+ }
+ }
+
+
+/** Called from outgoing handlers to notify that a response
+is ready for RemCon.
+
+@param aCommand The response that is ready.
+*/
+void CRemConBearerAvrcp::MrccciNewResponse(CAvrcpCommand& aCommand)
+ {
+ LOG_FUNC
+
+ // Need to put the response on the queue straight
+ // away in case RemCon collects it synchronously
+ iReadyResponses.AddLast(aCommand);
+ aCommand.IncrementUsers();
+
+ TRemConAddress remAddr;
+ AvrcpUtils::BTToRemConAddr(aCommand.RemoteAddress(), remAddr);
+ TInt err = Observer().NewResponse(remAddr);
+
+ if(err != KErrNone)
+ {
+ // RemCon is not going to pick this response up
+ aCommand.iReadyLink.Deque();
+ aCommand.DecrementUsers();
+ }
+ }
+
+/** Get a new transaction id for an incoming command.
+
+@return The new command id.
+*/
+TUint CRemConBearerAvrcp::MrcciNewTransactionId()
+ {
+ LOG_FUNC
+ return Observer().NewTransactionId();
+ }
+
+void CRemConBearerAvrcp::MrccciSetAddressedClient(const TRemConClientId& aClientId)
+ {
+ LOG_FUNC
+
+ Observer().SetRemoteAddressedClient(TUid::Uid(KRemConBearerAvrcpImplementationUid), aClientId);
+ }
+
+/** Called from outgoing handlers to notify that a response
+for a notify command is ready for RemCon.
+
+@param aCommand The response that is ready.
+*/
+void CRemConBearerAvrcp::MrccciNewNotifyResponse(CControlCommand& aCommand)
+ {
+ LOG_FUNC
+
+ // Need to put the response on the queue straight
+ // away in case RemCon collects it synchronously
+ iReadyNotifyResponses.AddLast(aCommand);
+ aCommand.IncrementUsers();
+
+ TRemConAddress remAddr;
+ AvrcpUtils::BTToRemConAddr(aCommand.RemoteAddress(), remAddr);
+ TInt err = Observer().NewNotifyResponse(remAddr);
+
+ if(err != KErrNone)
+ {
+ // RemCon is not going to pick this response up
+ aCommand.iReadyLink.Deque();
+ aCommand.DecrementUsers();
+ }
+ }
+
+/** Called by RemCon to send a notify command on a connection.
+
+@param aInterfaceUid The UID of the outer-layer client API specifying the command.
+@param aOperationId The ID of the command operation in the outer-layer client API.
+@param aId The command identifier used as a cookie for command/response matching, the transaction ID.
+@param aData API-specific message data. On success, ownership is passed.
+@param aAddr The connection.
+@return Error. This request is synchronous. It returns KErrNone when AVRCP has
+taken responsibility for sending the message. This involves checking that the message
+is well-formed and adding it to the send queue.
+*/
+TInt CRemConBearerAvrcp::SendNotifyCommand(TUid aInterfaceUid,
+ TUint aOperationId,
+ TUint aId,
+ RBuf8& aData,
+ const TRemConAddress& aAddr)
+ {
+ LOG_FUNC
+ // RemCon retains ownership of the data in aData until
+ // this function returns KErrNone.
+
+ if (!iConstructionComplete)
+ {
+ // Object only partially constructed, swallow the request
+ return KErrNotSupported;
+ }
+
+
+ TBTDevAddr btAddr;
+ TInt err = AvrcpUtils::RemConToBTAddr(aAddr, btAddr);
+
+ if(err == KErrNone)
+ {
+ CRcpRemoteDevice* remote = RemoteDevice(btAddr);
+ __ASSERT_ALWAYS(remote, AVRCP_PANIC(EAvrcpNotConnected));
+
+ TRAP(err, remote->OutgoingHandler().SendNotifyCommandL(aInterfaceUid,
+ aOperationId,
+ aId,
+ aData,
+ btAddr));
+ }
+
+ return err;
+ }
+
+//---------------------------------------------------------------------
+// Control notifications from the router
+//---------------------------------------------------------------------
+
+/** Called when a connection comes in from a remote.
+
+@param aBTDevice The address of the device initiating the connection.
+*/
+void CRemConBearerAvrcp::ConnectIndicate(const TBTDevAddr& aBTDevice)
+ {
+ LOG_FUNC
+ CRcpRemoteDevice *remote = NULL;
+ // We new up the device here even though we may end up deleting it
+ // later in the function because we need to know if we've successfully
+ // got a remote before we can tell RemCon. RemCon may optionally
+ // drop the connection in which case we delete remote straight away.
+ TRAPD(devErr, remote = CRcpRemoteDevice::NewL(aBTDevice, *iRouter, *this, Observer(), *iTimer, *iPlayerInfoManager));
+ if(!devErr)
+ {
+ iRemotes.AddLast(*remote);
+
+ TRemConAddress remoteAddr;
+ AvrcpUtils::BTToRemConAddr(aBTDevice, remoteAddr);
+
+ TInt err = Observer().ConnectIndicate(remoteAddr);
+ if(err)
+ {
+ // We need to drop this connection. Disconnect and delete
+ // the remote NOW. When we get the disconnect confirm we
+ // will then know that we shouldn't tell RemCon.
+ remote->Disconnect(ETrue);
+ remote->iLink.Deque();
+ delete remote;
+
+ err = iRouter->DisconnectRequest(aBTDevice);
+ }
+ }
+ }
+
+/** Called to confirm an outgoing connection.
+
+@param aBTDevice The device the outgoing connection is to.
+@param aError The result of the connection attempt.
+*/
+void CRemConBearerAvrcp::ConnectConfirm(const TBTDevAddr& aBTDevice, TInt aError)
+ {
+ LOG_FUNC
+ TRemConAddress remoteAddr;
+ AvrcpUtils::BTToRemConAddr(aBTDevice, remoteAddr);
+
+ if(aError != KErrNone)
+ {
+ CRcpRemoteDevice *remote = RemoteDevice(aBTDevice);
+ if(remote)
+ {
+ // calling disconnect gives the remote the opportunity
+ // to do anything necessary to commands still on its
+ // queue before we delete it.
+ remote->Disconnect(ETrue);
+ remote->iLink.Deque();
+ delete remote;
+ }
+ }
+
+ Observer().ConnectConfirm(remoteAddr, aError);
+ }
+
+/** Called when a remote disconnects.
+
+@param aBTDevice The address of the remote that has disconnected.
+*/
+void CRemConBearerAvrcp::DisconnectIndicate(const TBTDevAddr& aBTDevice)
+ {
+ LOG_FUNC
+ TRemConAddress remoteAddr;
+ AvrcpUtils::BTToRemConAddr(aBTDevice, remoteAddr);
+
+ CRcpRemoteDevice *remote = RemoteDevice(aBTDevice);
+ if(remote)
+ {
+ // calling disconnect gives the remote the opportunity
+ // to do anything necessary to commands still on its
+ // queue before we delete it.
+ remote->Disconnect(ETrue);
+ remote->iLink.Deque();
+ delete remote;
+ }
+
+ Observer().DisconnectIndicate(remoteAddr);
+ }
+
+/** Called to confirm a locally initiated disconnect.
+
+@param aBTDevice The address of the disconnected remote.
+@param aError The result of the disconnect attempt.
+*/
+void CRemConBearerAvrcp::DisconnectConfirm(const TBTDevAddr& aBTDevice, TInt aError)
+ {
+ LOG_FUNC
+ TRemConAddress remoteAddr;
+ AvrcpUtils::BTToRemConAddr(aBTDevice, remoteAddr);
+
+ Observer().DisconnectConfirm(remoteAddr, aError);
+ }
+
+/** Called to get a bearer interface.
+
+@param aUid The uid of the desired interface.
+@return An instance of the desired interface, NULL if
+ one could not be found.
+*/
+TAny* CRemConBearerAvrcp::GetInterface(TUid aUid)
+ {
+ LOG_FUNC
+
+ TAny* ret = NULL;
+ if ( aUid == TUid::Uid(KRemConBearerInterface1) )
+ {
+ ret = reinterpret_cast<TAny*>(
+ static_cast<MRemConBearerInterface*>(this)
+ );
+ }
+ else if ( aUid == TUid::Uid(KRemConBearerInterface2) )
+ {
+ ret = reinterpret_cast<TAny*>(
+ static_cast<MRemConBearerInterfaceV2*>(this)
+ );
+ }
+ else if ( aUid == TUid::Uid(KRemConBearerInterface3) )
+ {
+ ret = reinterpret_cast<TAny*>(
+ static_cast<MRemConBearerInterfaceV3*>(this)
+ );
+ }
+ else if ( aUid == TUid::Uid(KRemConBearerBulkInterface1) )
+ {
+ ret = reinterpret_cast<TAny*>(
+ static_cast<MRemConBearerBulkInterface*>(iBulkBearer)
+ );
+ }
+
+ return ret;
+ }
+
+//---------------------------------------------------------------------
+// Utility functions
+//---------------------------------------------------------------------
+
+MIncomingCommandHandler* CRemConBearerAvrcp::IncomingHandler(const TBTDevAddr& aAddr)
+ {
+ CRcpRemoteDevice* remote = RemoteDevice(aAddr);
+ if(remote)
+ {
+ return &remote->IncomingHandler();
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+MOutgoingCommandHandler* CRemConBearerAvrcp::OutgoingHandler(const TBTDevAddr& aAddr)
+ {
+ CRcpRemoteDevice* remote = RemoteDevice(aAddr);
+ if(remote)
+ {
+ return &remote->OutgoingHandler();
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+/** Utility function to get the CRcpRemoteDevice that
+handles a given BT address.
+
+@param aAddr The address to get the CRcpRemoteDevice for.
+@return A pointer to a remote device, or NULL if not found.
+*/
+CRcpRemoteDevice* CRemConBearerAvrcp::RemoteDevice(const TBTDevAddr& aAddr)
+ {
+ LOG_FUNC
+
+ CRcpRemoteDevice* remote = NULL;
+
+ TDblQueIter<CRcpRemoteDevice> iter(iRemotes);
+ while (iter)
+ {
+ remote = iter++;
+ if(remote->RemoteAddress() == aAddr)
+ {
+ break;
+ }
+ remote = NULL;
+ }
+
+ return remote;
+ }
+
+void CRemConBearerAvrcp::HandleUndeliveredCommand(CAvrcpCommand& aCommand, const TRemConAddress& aAddr)
+ {
+ TUid interfaceUid;
+ TUint remconId, operationId;
+ RBuf8 commandData;
+ TBTDevAddr btAddr;
+
+ // Calling GetCommandInfo transfers the command data to us.
+ aCommand.GetCommandInfo(interfaceUid, remconId, operationId, commandData, btAddr);
+ SendReject(interfaceUid, operationId, remconId, aAddr);
+ commandData.Close();
+
+ // RemCon is not going to pick this command up
+ aCommand.iReadyLink.Deque();
+ aCommand.DecrementUsers();
+ }