--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothmgmt/bluetoothclientlib/btlib/btsynclink.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1488 @@
+// Copyright (c) 2003-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:
+// Generic functions associated with all Bluetooth socket addresses
+//
+//
+
+#include "bt_sock.h"
+#include "internaltypes.h"
+#include "btsocketpanic.h"
+#include "btsynclinkhelpers.h"
+#include <bluetooth/logger.h>
+
+
+EXPORT_C TBTSyncPackets::TBTSyncPackets(TBTSyncPacketTypes aPacketTypes)
+ : iPacketTypes(aPacketTypes)
+ {}
+
+
+EXPORT_C TBTSyncPacketTypes TBTSyncPackets::operator()() const
+ {
+ return iPacketTypes;
+ }
+
+EXPORT_C TBTSyncBandwidth::TBTSyncBandwidth()
+ {}
+
+EXPORT_C TBTSyncBandwidth::TBTSyncBandwidth(TUint aBandwidth)
+ : iTransmit(aBandwidth), iReceive(aBandwidth)
+ {}
+
+TBTeSCOLinkParams::TBTeSCOLinkParams(TUint aBandwidth, TUint16 aCoding, TUint16 aLatency, TUint8 aRetransmission)
+ : iBandwidth(aBandwidth), iCoding(aCoding), iLatency(aLatency), iRetransmissionEffort(aRetransmission)
+ {}
+
+/** Allocate and open a socket sub-session for Bluetooth SCO
+
+@param aNotifier Notifier object which will receive callbacks after asynchronous requests
+@param aServer Handle to a currently connected session on the socket server
+@return Newly allocated CBluetoothSynchronousLink object
+@capability LocalServices
+*/
+EXPORT_C CBluetoothSynchronousLink* CBluetoothSynchronousLink::NewL(MBluetoothSynchronousLinkNotifier& aNotifier,
+ RSocketServ& aServer)
+ {
+ CBluetoothSynchronousLink* self = NewLC(aNotifier, aServer);
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+/** Allocate and open a socket sub-session for Bluetooth SCO
+
+@param aNotifier Notifier object which will receive callbacks after asynchronous requests
+@param aServer Handle to a currently connected session on the socket server
+@return Newly allocated CBluetoothSynchronousLink object
+@capability LocalServices
+*/
+EXPORT_C CBluetoothSynchronousLink* CBluetoothSynchronousLink::NewLC(MBluetoothSynchronousLinkNotifier& aNotifier,
+ RSocketServ& aServer)
+ {
+ CBluetoothSynchronousLink* self=new (ELeave) CBluetoothSynchronousLink(aNotifier, aServer);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+
+/**
+Destructor
+*/
+EXPORT_C CBluetoothSynchronousLink::~CBluetoothSynchronousLink()
+ {
+ FTRACE(FPrint(_L("Destroying CBTSyncLink 0x%08x"), this));
+ delete iBTSynchronousLinkSenderSCO;
+ delete iBTSynchronousLinkSenderESCO;
+ delete iBTSynchronousLinkReceiverSCO;
+ delete iBTSynchronousLinkReceiverESCO;
+ delete iBTSynchronousLinkAccepterSCO;
+ delete iBTSynchronousLinkAccepterESCO;
+ delete iBTSynchronousLinkAttacherSCO;
+ delete iBTSynchronousLinkAttacherESCO;
+ delete iBTSynchronousLinkDetacherSCO;
+ delete iBTSynchronousLinkDetacherESCO;
+ delete iBTSynchronousLinkBaseband;
+
+ FLOG(_L("Closing sockets"));
+ ListeningSCOSocket().Close();
+ ListeningESCOSocket().Close();
+ SCOSocket().Close();
+ ESCOSocket().Close();
+ }
+
+
+void CBluetoothSynchronousLink::ConstructL()
+ {
+ iBTSynchronousLinkSenderSCO = CBTSynchronousLinkSender::NewL(*this,ESCO);
+ iBTSynchronousLinkSenderESCO = CBTSynchronousLinkSender::NewL(*this,EeSCO);
+ iBTSynchronousLinkReceiverSCO = CBTSynchronousLinkReceiver::NewL(*this,ESCO);
+ iBTSynchronousLinkReceiverESCO = CBTSynchronousLinkReceiver::NewL(*this,EeSCO);
+ iBTSynchronousLinkAccepterSCO = CBTSynchronousLinkAccepter::NewL(*this,ESCO);
+ iBTSynchronousLinkAccepterESCO = CBTSynchronousLinkAccepter::NewL(*this,EeSCO);
+ iBTSynchronousLinkAttacherSCO = CBTSynchronousLinkAttacher::NewL(*this,ESCO);
+ iBTSynchronousLinkAttacherESCO = CBTSynchronousLinkAttacher::NewL(*this,EeSCO);
+ iBTSynchronousLinkDetacherSCO = CBTSynchronousLinkDetacher::NewL(*this,ESCO);
+ iBTSynchronousLinkDetacherESCO = CBTSynchronousLinkDetacher::NewL(*this,EeSCO);
+ iBTSynchronousLinkBaseband = CBTSynchronousLinkBaseband::NewL(*this);
+ }
+
+
+CBluetoothSynchronousLink::CBluetoothSynchronousLink(MBluetoothSynchronousLinkNotifier& aNotifier,
+ RSocketServ& aServer)
+ : iNotifier(&aNotifier), iSockServer(aServer),
+ iRequestedLink(KBTSync64KBit, 0, 25, EeSCORetransmitDontCare),
+ iNegotiatedLink(0, 0, 0, 0)
+ {
+ FTRACE(FPrint(_L("Constructing CBTSyncLink 0x%08x"), this));
+ }
+
+
+/**
+Create a synchronous link (e.g. voice) on an EXISTING physical link.
+
+@param aBDAddr Bluetooth address of remote device (specifying existing physical link)
+@return Error code
+*/
+EXPORT_C TInt CBluetoothSynchronousLink::SetupConnection(const TBTDevAddr& aBDAddr)
+ {
+ return SetupConnection(aBDAddr, TBTSyncPackets(TBTSyncPackets::ESyncAnySCOPacket));
+ }
+
+
+/**
+Create a synchronous link (e.g. voice) on an EXISTING physical link.
+@see TBTPacketType
+@param aBDAddr Bluetooth address of remote device (specifying existing physical link)
+@param aPacketTypes Bitmask of the SCO packet types required on this connection
+Use only the three SCO specific packet type enums
+E.g. EPacketsHV1|EPacketsHV2|EPacketsHV3 (EAnySCOPacket) specifies all the three packet
+types are allowed.
+OR if ESCO is supported
+three ESCO specific packet type enums
+@return Error code
+*/
+EXPORT_C TInt CBluetoothSynchronousLink::SetupConnection(const TBTDevAddr& aBDAddr, const TUint16 aPacketTypes)
+ {
+ return SetupConnection(aBDAddr, TBTSyncPackets((aPacketTypes & EAnySCOPacket) >> KSCOvsSyncHVOffset));
+ }
+
+
+// This needs to be a macro or the 'return' won't return properly
+#define CLOSE_RETURN_IF_ERROR(error) if (error) { LinkDown(); SCOSocket().Close(); ESCOSocket().Close(); return error; }
+#define CLOSE_LISTENER_RETURN_IF_ERROR(error) if (error) { ListeningSCOSocket().Close(); ListeningESCOSocket().Close(); return error; }
+
+EXPORT_C TInt CBluetoothSynchronousLink::SetupConnection(const TBTDevAddr& aBDAddr, const TBTSyncPackets& aPacketTypes)
+ {
+ TBool openSCO = EFalse;
+ TBool openESCO = EFalse;
+
+ FTRACE(FPrint(_L("SetupConnection on CBTSyncLink 0x%08x"), this));
+
+ TBTSyncPacketTypes packets = aPacketTypes();
+
+ __ASSERT_ALWAYS(packets, Panic(EBadSyncPacketTypes));
+
+ packets &= (TBTSyncPackets::ESyncAnySCOPacket | TBTSyncPackets::ESyncAnyESCOPacket);
+ if (!packets)
+ {
+ FLOG(_L("Bad packets specified at initial mask"));
+ return KErrNotSupported;
+ }
+
+ TBTSyncPacketTypes packetsSCO = packets & TBTSyncPackets::ESyncAnySCOPacket;
+ if (packetsSCO)
+ {
+ iSCOTypes |= ESCO;
+ openSCO = ETrue;
+ }
+
+ TBTSyncPacketTypes packetsESCO = packets & TBTSyncPackets::ESyncAnyESCOPacket;
+ if (packetsESCO)
+ {
+ iSCOTypes |= EeSCO;
+ openESCO = ETrue;
+ }
+
+ // but must be one
+ __ASSERT_ALWAYS(packetsSCO || packetsESCO, Panic(EBadSyncPacketTypes));
+
+ if (iBTSynchronousLinkAttacherSCO->IsActive())
+ {
+ FLOG(_L("Link attacher already active"));
+ return KErrInUse;
+ }
+
+ if (iBTSynchronousLinkAttacherESCO->IsActive())
+ {
+ FLOG(_L("Link attacher already active"));
+ return KErrInUse;
+ }
+
+ TInt linkState = LinkUp(aBDAddr);
+ if (linkState != KErrNone)
+ {
+ FLOG(_L("Baseband link not available"));
+ return KErrDisconnected;
+ }
+
+ TInt err = KErrNone;
+
+ if (openSCO && openESCO)
+ {
+ /* open both socket types */
+ /* first try ESCO */
+ err = ESCOSocket().Open(iSockServer,
+ KBTAddrFamily,
+ KSockBluetoothTypeESCO,
+ KBTLinkManager);
+ if(!err)
+ {
+ err = ESCOSocket().SetOpt(ESyncUserPacketTypes, KSolBtSCO, packets);
+
+ if (!err)
+ {
+ TPckgBuf<TBTeSCOLinkParams> options;
+ options() = iRequestedLink;
+ err = ESCOSocket().SetOpt(EeSCOExtOptions, KSolBtESCO, options);
+ }
+ }
+ if (err)
+ { // ESCO failed so try only SCO
+ ESCOSocket().Close();
+ openESCO = EFalse;
+ }
+
+ err = SCOSocket().Open(iSockServer,
+ KBTAddrFamily,
+ KSockBluetoothTypeSCO,
+ KBTLinkManager);
+ if(!err)
+ {
+ err = SCOSocket().SetOpt(ESyncUserPacketTypes, KSolBtSCO, packetsSCO);
+ }
+ else
+ {// SCO failed
+ openSCO = EFalse;
+ }
+
+ CLOSE_RETURN_IF_ERROR(err); // this will sort out if both have failed
+ }
+ else if (openSCO)
+ {
+ err = SCOSocket().Open(iSockServer,
+ KBTAddrFamily,
+ KSockBluetoothTypeSCO,
+ KBTLinkManager);
+ if(err)
+ {
+ return err;
+ }
+ err = SCOSocket().SetOpt(ESyncUserPacketTypes, KSolBtSCO, packetsSCO);
+ CLOSE_RETURN_IF_ERROR(err);
+ }
+ else if (openESCO)
+ {
+ err = ESCOSocket().Open(iSockServer,
+ KBTAddrFamily,
+ KSockBluetoothTypeESCO,
+ KBTLinkManager);
+ if(err)
+ {
+ SCOSocket().Close();
+ return err;
+ }
+ err = ESCOSocket().SetOpt(ESyncUserPacketTypes, KSolBtSCO, packetsESCO);
+
+ TPckgBuf<TBTeSCOLinkParams> options;
+ options() = iRequestedLink;
+ err = ESCOSocket().SetOpt(EeSCOExtOptions, KSolBtESCO, options);
+ CLOSE_RETURN_IF_ERROR(err);
+ }
+
+ iSockAddr.SetBTAddr(aBDAddr);
+
+ iBTSynchronousLinkBaseband->PreventPark();
+
+ if(openESCO)
+ {
+ iOpeningESCO = ETrue;
+ iBTSynchronousLinkAttacherESCO->AttachSCOLink(iSockAddr);
+ iBTSynchronousLinkBaseband->CatchEvents();
+ }
+
+ if(openSCO)
+ {
+ iOpeningSCO = ETrue;
+ iBTSynchronousLinkAttacherSCO->AttachSCOLink(iSockAddr);
+ iBTSynchronousLinkBaseband->CatchEvents();
+ }
+
+ return KErrNone;
+ }
+
+
+/**
+Cancel creating a synchronous link.
+This cancels the asynchronous request to prevent the callback reaching the client.
+It makes no claims about the resultant state of the CBluetoothSynchronousLink. If
+a client wishes to continue using the CBluetoothSynchronousLink it is strongly
+recommended to follow a call to CancelSetup with a call to Disconnect, which will
+ensure that any established connection is tidied up.
+@see CBluetoothSynchronousLink::Disconnect
+*/
+EXPORT_C void CBluetoothSynchronousLink::CancelSetup()
+ {
+ iBTSynchronousLinkAttacherSCO->Cancel();
+ iBTSynchronousLinkAttacherESCO->Cancel();
+ iBTSynchronousLinkBaseband->StopAll();
+ }
+
+
+/**
+Disconnect a synchronous link.
+
+The physical link will remain unless no other services are running on it.
+@return Error code
+*/
+EXPORT_C TInt CBluetoothSynchronousLink::Disconnect()
+ {
+ if (!SCOSocket().SubSessionHandle())
+ {
+ if(!ESCOSocket().SubSessionHandle())
+ {
+ return KErrDisconnected;
+ }
+ }
+
+ if (iBTSynchronousLinkDetacherSCO->IsActive() ||
+ iBTSynchronousLinkDetacherESCO->IsActive())
+ {
+ return KErrInUse;
+ }
+
+ __ASSERT_ALWAYS(iSCOTypes, Panic(EBadSyncPacketTypes));
+ if (iSCOTypes & ESCO)
+ {
+ iBTSynchronousLinkDetacherSCO->DetachSCOLink(iDummySCOShutdownDescriptor, iDummySCOShutdownDescriptor);
+ }
+
+ if (iSCOTypes & EeSCO)
+ {
+ iBTSynchronousLinkDetacherESCO->DetachSCOLink(iDummySCOShutdownDescriptor, iDummySCOShutdownDescriptor);
+ }
+
+ return KErrNone;
+ }
+
+
+/**
+Send data over synchronous link. It is worth noting that Bluetooth hardware
+may have dedicated pins to supply synchronous data, and the RSocket interface
+cannot provide the synchronous requirements of the SCO link. As a result of
+this, the CBluetoothSynchronousLink class may only provide the control plane of
+a SCO connection. In this situation, Receive returns KErrNotSupported via the
+MBluetoothSynchronousLinkNotifier::HandleSendCompleteL callback.
+
+@param const aData Data to be sent.
+@return Error code
+*/
+EXPORT_C TInt CBluetoothSynchronousLink::Send(const TDesC8& aData)
+ {
+ __ASSERT_ALWAYS(SCOSocket().SubSessionHandle() || ESCOSocket().SubSessionHandle(), Panic(EInvalidSubSession));
+ if (!SCOSocket().SubSessionHandle())
+ {
+ if(!ESCOSocket().SubSessionHandle())
+ {
+ return KErrDisconnected;
+ }
+ }
+
+ if (iBTSynchronousLinkSenderSCO->IsActive() ||
+ iBTSynchronousLinkSenderESCO->IsActive())
+ {
+ return KErrInUse;
+ }
+
+ __ASSERT_ALWAYS(iSCOTypes, Panic(EBadSyncPacketTypes));
+ if (iSCOTypes & ESCO)
+ {
+ iBTSynchronousLinkSenderSCO->SendSCOData(aData);
+ }
+
+ if (iSCOTypes & EeSCO)
+ {
+ iBTSynchronousLinkSenderESCO->SendSCOData(aData);
+ }
+
+ return KErrNone;
+ }
+
+
+/**
+Cancel sending data.
+*/
+EXPORT_C void CBluetoothSynchronousLink::CancelSend()
+ {
+ iBTSynchronousLinkSenderSCO->Cancel();
+ iBTSynchronousLinkSenderESCO->Cancel();
+ }
+
+
+/**
+Receive data over synchronous link. It is worth noting that Bluetooth hardware
+may have dedicated pins to supply synchronous data, and the RSocket interface
+cannot provide the synchronous requirements of the SCO link. As a result of
+this, the CBluetoothSynchronousLink class may only provide the control plane of
+a SCO connection. In this situation, Receive returns KErrNotSupported via the
+MBluetoothSynchronousLinkNotifier::HandleReceiveCompleteL callback.
+
+@param const aData Buffer for data to be received.
+@return Error code
+*/
+EXPORT_C TInt CBluetoothSynchronousLink::Receive(TDes8& aData)
+ {
+ __ASSERT_ALWAYS(SCOSocket().SubSessionHandle() || ESCOSocket().SubSessionHandle(), Panic(EInvalidSubSession));
+ if (!SCOSocket().SubSessionHandle())
+ {
+ if(!ESCOSocket().SubSessionHandle())
+ {
+ return KErrDisconnected;
+ }
+ }
+
+ if (iBTSynchronousLinkSenderSCO->IsActive() ||
+ iBTSynchronousLinkSenderESCO->IsActive())
+ {
+ return KErrInUse;
+ }
+
+ __ASSERT_ALWAYS(iSCOTypes, Panic(EBadSyncPacketTypes));
+ if (iSCOTypes & ESCO)
+ {
+ iBTSynchronousLinkReceiverSCO->ReadSCOData(aData);
+ }
+
+ if (iSCOTypes & EeSCO)
+ {
+ iBTSynchronousLinkReceiverESCO->ReadSCOData(aData);
+ }
+
+ return KErrNone;
+ }
+
+
+/**
+Cancel receiving data.
+*/
+EXPORT_C void CBluetoothSynchronousLink::CancelReceive()
+ {
+ iBTSynchronousLinkReceiverSCO->Cancel();
+ iBTSynchronousLinkReceiverESCO->Cancel();
+ }
+
+
+/**
+Prepare for a remote device to set up a synchronous link on the local device.
+
+Whilst this facility is set, a response can be sent to a remote device trying to
+set up a synchronous link, allowing that synchronous link to be brought up.
+This object will represent that synchronous link locally when/if it does come up.
+@return Error code
+*/
+EXPORT_C TInt CBluetoothSynchronousLink::AcceptConnection()
+ {
+ return AcceptConnection(TBTSyncPackets(TBTSyncPackets::ESyncAnySCOPacket));
+ }
+
+
+/**
+Prepare for a remote device to set up a synchronous link on the local device.
+
+Whilst this facility is set, a response can be sent to a remote device trying to
+set up a synchronous link, allowing that synchronous link to be brought up.
+This object will represent that synchronous link locally when/if it does come up.
+
+@see TBTPacketType
+@param aPacketTypes Bitmask of supported packets.
+@return Error code
+*/
+EXPORT_C TInt CBluetoothSynchronousLink::AcceptConnection(const TBTSyncPackets& aPacketTypes)
+ {
+ TBool listenForSCO = EFalse;
+ TBool listenForESCO = EFalse;
+
+ FTRACE(FPrint(_L("AcceptConnection on CBTSyncLink 0x%08x"), this));
+
+ TBTSyncPacketTypes packets = aPacketTypes();
+
+
+ __ASSERT_ALWAYS(packets, Panic(EBadSyncPacketTypes));
+ packets &= (TBTSyncPackets::ESyncAnySCOPacket | TBTSyncPackets::ESyncAnyESCOPacket);
+ if (!packets)
+ {
+ return KErrNotSupported;
+ }
+
+ if (iBTSynchronousLinkAccepterSCO->IsActive())
+ {
+ return KErrInUse;
+ }
+
+ if (iBTSynchronousLinkAccepterESCO->IsActive())
+ {
+ return KErrInUse;
+ }
+
+ TInt err = ListeningSCOSocket().Open(iSockServer, KBTAddrFamily, KSockBluetoothTypeSCO, KBTLinkManager);
+ if(err)
+ {
+ return err;
+ }
+
+ err = ListeningESCOSocket().Open(iSockServer, KBTAddrFamily, KSockBluetoothTypeESCO, KBTLinkManager);
+ if(err)
+ {
+ ListeningSCOSocket().Close();
+ return err;
+ }
+
+ TBTSyncPacketTypes packetsSCO = packets & TBTSyncPackets::ESyncAnySCOPacket;
+ if (packetsSCO)
+ {
+ err = ListeningSCOSocket().SetOpt(ESyncUserPacketTypes, KSolBtSCO, packetsSCO);
+ if(!err)
+ {
+ iSCOTypes |= ESCO;
+ listenForSCO = ETrue;
+ }
+ }
+
+ TBTSyncPacketTypes packetsESCO = packets & TBTSyncPackets::ESyncAnyESCOPacket;
+ if (packetsESCO)
+ {
+ err = ListeningESCOSocket().SetOpt(ESyncUserPacketTypes, KSolBtSCO, packetsESCO);
+ if (!err)
+ {
+ iSCOTypes |= EeSCO;
+ listenForESCO = ETrue;
+ }
+
+ TPckgBuf<TBTeSCOLinkParams> options;
+ options() = iRequestedLink;
+ err = ListeningESCOSocket().SetOpt(EeSCOExtOptions, KSolBtESCO, options);
+ CLOSE_LISTENER_RETURN_IF_ERROR(err);
+ }
+
+ __ASSERT_ALWAYS(listenForSCO || listenForESCO, Panic(EBadSyncPacketTypes));
+
+ TBTSockAddr sa;
+ TBTServiceSecurity sec;
+
+ //security settings
+ sec.SetAuthentication(EMitmNotRequired);
+ sec.SetEncryption(EFalse);
+ sec.SetAuthorisation(EFalse);
+ sec.SetDenied(EFalse);
+
+ sa.SetBTAddr(TBTDevAddr()); // I don't think this matters which address is being used
+ sa.SetSecurity(sec);
+
+ if (listenForSCO)
+ {
+ err = ListeningSCOSocket().Bind(sa);
+ CLOSE_LISTENER_RETURN_IF_ERROR(err);
+
+ err = ListeningSCOSocket().Listen(KSCOListenQueSize);
+ CLOSE_LISTENER_RETURN_IF_ERROR(err);
+
+ err = SCOSocket().Open(SocketServer());
+ if(err)
+ {
+ return err;
+ }
+ }
+
+ if(listenForESCO)
+ {
+ err = ListeningESCOSocket().Bind(sa);
+ CLOSE_LISTENER_RETURN_IF_ERROR(err);
+
+ err = ListeningESCOSocket().Listen(KSCOListenQueSize);
+ CLOSE_LISTENER_RETURN_IF_ERROR(err);
+
+ err = ESCOSocket().Open(SocketServer());
+ if(err)
+ {
+ return err;
+ }
+ }
+
+ if (listenForSCO)
+ {
+ iBTSynchronousLinkAccepterSCO->Accept(ListeningSCOSocket());
+ }
+
+ if(listenForESCO)
+ {
+ iBTSynchronousLinkAccepterESCO->Accept(ListeningESCOSocket());
+ }
+
+ return err;
+ }
+
+
+/**
+Cancel ability to respond to a remote request to set up a synchronous link.
+It is possible for a race condition to mean that a connection has been established,
+but as this call consumes the callback, for this fact not to reach the caller.
+For this reason, it may be desirable to follow a call to CancelAccept with a call
+to Disconnect.
+@see CBluetoothSynchronousLink::Disconnect
+*/
+EXPORT_C void CBluetoothSynchronousLink::CancelAccept()
+ {
+ iBTSynchronousLinkAccepterSCO->Cancel();
+ iBTSynchronousLinkAccepterESCO->Cancel();
+ iBTSynchronousLinkBaseband->StopAll();
+
+ ListeningSCOSocket().Close();
+ ListeningESCOSocket().Close();
+ SCOSocket().Close();
+ ESCOSocket().Close();
+ }
+
+
+/**
+ * Specify Voice Setting.
+ * See section 6.12 in Bluetooth Core Specification v1.2, Vol. 2, Part E.
+ */
+EXPORT_C void CBluetoothSynchronousLink::SetCoding(TUint16 aVoiceCoding)
+ {
+ iRequestedLink.iCoding = aVoiceCoding;
+ }
+
+
+/**
+ * Specify maximum bandwidths in octets/second.
+ */
+EXPORT_C void CBluetoothSynchronousLink::SetMaxBandwidth(TBTSyncBandwidth aBandwidth)
+ {
+ iRequestedLink.iBandwidth = aBandwidth;
+ }
+
+
+/**
+ * Specify maximum acceptable latency in milliseconds.
+ */
+EXPORT_C void CBluetoothSynchronousLink::SetMaxLatency(TUint16 aLatency)
+ {
+ iRequestedLink.iLatency = Max(aLatency, KMinESCOLatency);
+ }
+
+
+/**
+ * Specify link retransmission policy.
+ */
+EXPORT_C void CBluetoothSynchronousLink::SetRetransmissionEffort(TBTeSCORetransmissionTypes aRetransmissionEffort)
+ {
+ iRequestedLink.iRetransmissionEffort = static_cast<TUint8>(aRetransmissionEffort);
+ }
+
+
+/**
+ * Return the air coding portion only of the coding specified on the link.
+ * See section 6.12 in Bluetooth Core Specification v1.2, Vol. 2, Part E.
+ */
+EXPORT_C TUint16 CBluetoothSynchronousLink::Coding()
+ {
+ return iNegotiatedLink.iCoding & KAirCodingFormatBits;
+ }
+
+
+/**
+ * Return the negotiated bandwidth.
+ */
+EXPORT_C TBTSyncBandwidth CBluetoothSynchronousLink::Bandwidth()
+ {
+ return iNegotiatedLink.iBandwidth;
+ }
+
+
+
+/**
+ * Return the negotiated latency in miliseconds (rounded up if non-integer on the link).
+ */
+EXPORT_C TUint16 CBluetoothSynchronousLink::Latency()
+ {
+ return iNegotiatedLink.iLatency;
+ }
+
+
+/**
+ * Return an estimate of the retransmission policy on the link.
+ * Estimate is calculated by taking the size of the retransmission window,
+ * estimating the packet type based on packet length and calculating the
+ * number of packet retransmissions which are possible. This number is
+ * then returned by this function.
+ */
+EXPORT_C TUint8 CBluetoothSynchronousLink::RetransmissionEffort()
+ {
+ return iNegotiatedLink.iRetransmissionEffort;
+ }
+
+
+/** Gets the socket address of the remote Bluetooth device.
+@panic ESock_client 17 Raised when the link is not connected so there is no valid remote name to return.
+@param aAddr The socket address.
+*/
+EXPORT_C void CBluetoothSynchronousLink::RemoteName(TSockAddr& aAddr)
+ {
+ __ASSERT_ALWAYS(iSCOTypes, Panic(EBadSyncPacketTypes));
+ if (iSCOTypes & ESCO)
+ {
+ SCOSocket().RemoteName(aAddr);
+ }
+
+ if (iSCOTypes & EeSCO)
+ {
+ ESCOSocket().RemoteName(aAddr);
+ }
+ }
+
+/**
+Set the object to be notified of synchronous link events. This does
+not take ownership. This notifier will replace the current one.
+
+@param aNotifer The new object to inform of synchronous link events.
+*/
+EXPORT_C void CBluetoothSynchronousLink::SetNotifier(MBluetoothSynchronousLinkNotifier& aNotifier)
+ {
+ iNotifier = &aNotifier;
+ }
+
+void CBluetoothSynchronousLink::HandleSetupConnectionCompleteL(TInt aErr, TSCOType aSCOType)
+ {
+ TBool notify = EFalse;
+ FTRACE(FPrint(_L("CBluetoothSynchronousLink::HandleSetupConnectionCompleteL(aErr %d)"), aErr));
+
+ /* we can be in a situation where we are trying:
+ SCO connection only
+ ESCO connection only
+ either SCO or ESCO
+
+ If the connection is successful and we are trying one type then we accept it
+ If the connection isn't successful and we are trying one type then clean up
+
+ If we are trying both and
+ a) only one is successful then clean up the other one
+ b) neither are successful then clean up
+ c) ESCO and SCO are both successful take the ESCO one and close SCO.
+
+
+ What ever case we are dealing with only notify when we are sure of a finished
+ result
+ */
+ if (aErr==KErrNone)
+ {
+ iSCOTypes = (TUint8)aSCOType;
+ if (EeSCO == aSCOType)
+ {
+ if (iOpeningSCO)
+ {
+ // if we are trying both then close the SCO Socket
+ // we only want one open
+ SCOSocket().Close();
+ iOpeningSCO = EFalse;
+ iOpenedSCO = EFalse;
+ }
+ else //we can update and notify as we are only trying ESCO
+ {
+ UpdateLinkParams(aSCOType);
+ }
+ notify = ETrue;
+ }
+ if (ESCO == aSCOType)
+ {
+ if (!iOpeningESCO)
+ {// we are only trying SCO so we can update and notify
+ UpdateLinkParams(aSCOType);
+ notify = ETrue;
+ }
+ else
+ {
+ iOpenedSCO = ETrue; // if the ESCO is rejected then we need to notify SCO was opened
+ }
+ }
+ }
+ else
+ {
+ if (EeSCO == aSCOType)
+ {
+ if (!iOpeningSCO)
+ {
+ // if we are trying both and the other socket might be accepted (or has
+ // been) we don't want to close this all down, but if we're not trying
+ // to open SCO then close it all down and tell the user
+ iNegotiatedLink = TBTeSCOLinkParams(0, 0, 0, 0);
+ iBTSynchronousLinkBaseband->StopAll();
+ LinkDown();
+ notify = ETrue;
+ }
+ else if (iOpenedSCO)
+ {
+ // successfully opened SCO connection, ESCO failed so tell the user
+ // about the SCO
+ notify = ETrue;
+ }
+ // no longer trying to open ESCO
+ iOpeningESCO = EFalse;
+ ESCOSocket().Close();
+ }
+ else // ESCO = aSCOType - plain SCO
+ {
+ if (!iOpeningESCO)
+ {
+ // if we are trying both and the other socket might be accepted (or has
+ // been) we don't want to close this all down but if we're not trying
+ // to open ESCO then close it all down and tell the called
+ iNegotiatedLink = TBTeSCOLinkParams(0, 0, 0, 0);
+ iBTSynchronousLinkBaseband->StopAll();
+ LinkDown();
+ notify = ETrue;
+ }
+ else
+ {// no longer trying to open SCO
+ iOpeningSCO = EFalse;
+ }
+ SCOSocket().Close();
+ }
+ }
+
+ if (notify)
+ {
+#ifdef __FLOGGING__
+ TRAPD(err, Notifier().HandleSetupConnectionCompleteL(aErr));
+ FTRACE(FPrint(_L("Setup upcall to link owner returned %d"), err));
+ User::LeaveIfError(err);
+#else
+ Notifier().HandleSetupConnectionCompleteL(aErr);
+#endif
+ }
+ }
+
+
+void CBluetoothSynchronousLink::HandleDisconnectionCompleteL(TInt aErr)
+ {
+ FTRACE(FPrint(_L("CBluetoothSynchronousLink::HandleDisconnectionCompleteL(aErr %d)"), aErr));
+
+ iNegotiatedLink = TBTeSCOLinkParams(0, 0, 0, 0);
+
+ iBTSynchronousLinkBaseband->StopAll();
+ LinkDown();
+ SCOSocket().Close();
+ ESCOSocket().Close();
+
+#ifdef __FLOGGING__
+ TRAPD(err, Notifier().HandleDisconnectionCompleteL(aErr));
+ FTRACE(FPrint(_L("Disconnect upcall to link owner returned %d"), err));
+ User::LeaveIfError(err);
+#else
+ Notifier().HandleDisconnectionCompleteL(aErr);
+#endif
+
+ }
+
+
+void CBluetoothSynchronousLink::HandleAcceptConnectionCompleteL(TInt aErr, TSCOType aSCOType)
+ {
+ FTRACE(FPrint(_L("CBluetoothSynchronousLink::HandleAcceptConnectionCompleteL(aErr %d)"), aErr));
+
+ if (aErr==KErrNone)
+ {
+ iSCOTypes = (TUint8)aSCOType;
+
+ TSockAddr sockAddr;
+ if (aSCOType & ESCO)
+ {
+ iBTSynchronousLinkAccepterESCO->Cancel();
+ SCOSocket().RemoteName(sockAddr);
+ }
+ else
+ {
+ iBTSynchronousLinkAccepterSCO->Cancel();
+ ESCOSocket().RemoteName(sockAddr);
+ }
+
+ if(sockAddr.Family() == KBTAddrFamily)
+ {
+ TBTSockAddr& btSockAddr = static_cast<TBTSockAddr&>(sockAddr); // subclasses of TSockAddr are forbidden to add members
+ TBTDevAddr da = btSockAddr.BTAddr();
+ TInt linkState = LinkUp(da);
+
+ __ASSERT_ALWAYS((linkState == KErrNone), Panic(EBasebandFailedConnect));
+
+ iBTSynchronousLinkBaseband->PreventPark();
+ iBTSynchronousLinkBaseband->CatchEvents();
+ UpdateLinkParams(aSCOType);
+ }
+ else
+ {
+ // reading RemoteName has failed, probably socket state is already closed
+ // for example after quick disconnection initiated from remote side
+ aErr = KErrDisconnected;
+ }
+ }
+ else
+ {
+ iNegotiatedLink = TBTeSCOLinkParams(0, 0, 0, 0);
+ }
+
+#ifdef __FLOGGING__
+ TRAPD(err, Notifier().HandleAcceptConnectionCompleteL(aErr));
+ FTRACE(FPrint(_L("Accept upcall to link owner returned %d"), err));
+ User::LeaveIfError(err);
+#else
+ Notifier().HandleAcceptConnectionCompleteL(aErr);
+#endif
+
+ ListeningSCOSocket().Close();
+ ListeningESCOSocket().Close();
+ }
+
+
+void CBluetoothSynchronousLink::HandleSendCompleteL(TInt aErr)
+ {
+ Notifier().HandleSendCompleteL(aErr);
+ }
+
+
+void CBluetoothSynchronousLink::HandleReceiveCompleteL(TInt aErr)
+ {
+ Notifier().HandleReceiveCompleteL(aErr);
+ }
+
+
+MBluetoothSynchronousLinkNotifier& CBluetoothSynchronousLink::Notifier()
+ {
+ return *iNotifier;
+ }
+
+
+RSocket& CBluetoothSynchronousLink::ListeningSCOSocket()
+ {
+ return iListeningSCOSocket;
+ }
+
+
+RSocket& CBluetoothSynchronousLink::ListeningESCOSocket()
+ {
+ return iListeningESCOSocket;
+ }
+
+RSocket& CBluetoothSynchronousLink::SCOSocket()
+ {
+ return iSCOSocket;
+ }
+
+RSocket& CBluetoothSynchronousLink::ESCOSocket()
+ {
+ return iESCOSocket;
+ }
+
+RSocketServ& CBluetoothSynchronousLink::SocketServer()
+ {
+ return iSockServer;
+ }
+
+
+RBTBaseband& CBluetoothSynchronousLink::Baseband()
+ {
+ return iBaseband;
+ }
+
+
+void CBluetoothSynchronousLink::UpdateLinkParams(TSCOType aSCOType)
+ {
+ TPckgBuf<TBTeSCOLinkParams> options;
+
+ TInt err = KErrNotSupported;
+ if(aSCOType == EeSCO)
+ {
+ err = ESCOSocket().GetOpt(EeSCOExtOptions, KSolBtESCO, options);
+ }
+ if (err) return;
+
+ iNegotiatedLink.iLatency = options().iLatency;
+ iNegotiatedLink.iBandwidth = options().iBandwidth;
+ iNegotiatedLink.iRetransmissionEffort = options().iRetransmissionEffort;
+ iNegotiatedLink.iCoding = options().iCoding;
+ }
+
+
+TInt CBluetoothSynchronousLink::LinkUp(TBTDevAddr aAddr)
+ {
+ __ASSERT_ALWAYS((iBaseband.SubSessionHandle() == 0), Panic(EBasebandAlreadyConnected));
+ return iBaseband.Open(SocketServer(), aAddr);
+ }
+
+
+void CBluetoothSynchronousLink::LinkDown()
+ {
+ iBaseband.Close();
+ __ASSERT_ALWAYS((iBaseband.SubSessionHandle() == 0), Panic(EBasebandFailedDisconnect));
+ }
+
+
+//==========================================================
+//Active Object Helpers
+//
+
+//
+//for CBluetoothSynchronousLink
+//
+CBTSynchronousLinkBaseband* CBTSynchronousLinkBaseband::NewL(CBluetoothSynchronousLink& aParent)
+ {
+ CBTSynchronousLinkBaseband* self = new(ELeave) CBTSynchronousLinkBaseband(aParent);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CBTSynchronousLinkBaseband::CBTSynchronousLinkBaseband(CBluetoothSynchronousLink& aParent)
+ : CActive(CActive::EPriorityStandard), iParent(aParent)
+ {}
+
+
+void CBTSynchronousLinkBaseband::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+ }
+
+
+CBTSynchronousLinkBaseband::~CBTSynchronousLinkBaseband()
+ {
+ StopAll();
+ }
+
+void CBTSynchronousLinkBaseband::PreventPark()
+ {
+ iParent.Baseband().PreventLowPowerModes(EParkMode);
+ }
+
+
+void CBTSynchronousLinkBaseband::CatchEvents()
+ {
+ if (!IsActive())
+ {
+ iParent.Baseband().ActivateNotifierForOneShot(iEvent, iStatus, ENotifySCOLinkDown|ENotifyPhysicalLinkDown);
+ SetActive();
+ }
+ }
+
+
+void CBTSynchronousLinkBaseband::RunL()
+ {
+ FLOG(_L("CBTSynchronousLinkBaseband caught disconnection event"));
+ iParent.HandleDisconnectionCompleteL(iStatus.Int());
+ }
+
+
+TInt CBTSynchronousLinkBaseband::RunError(TInt /*aError*/)
+ {
+ // Swallow the error
+ return KErrNone;
+ }
+
+
+void CBTSynchronousLinkBaseband::StopAll()
+ {
+ iParent.Baseband().AllowLowPowerModes(EParkMode);
+ Cancel();
+ }
+
+
+void CBTSynchronousLinkBaseband::DoCancel()
+ {
+ iParent.Baseband().CancelNextBasebandChangeEventNotifier();
+ }
+
+
+//--
+CBTSynchronousLinkAttacher* CBTSynchronousLinkAttacher::NewL(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ {
+ CBTSynchronousLinkAttacher* self = new (ELeave) CBTSynchronousLinkAttacher(aParent, aSCOType);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CBTSynchronousLinkAttacher::CBTSynchronousLinkAttacher(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ : CActive(CActive::EPriorityStandard), iParent(aParent), iSCOType(aSCOType)
+ {
+ }
+
+void CBTSynchronousLinkAttacher::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CBTSynchronousLinkAttacher::~CBTSynchronousLinkAttacher()
+ {
+ Cancel();
+ }
+
+void CBTSynchronousLinkAttacher::AttachSCOLink(TBTSockAddr& aSockAddr)
+ {
+ __ASSERT_ALWAYS(!IsActive(), Panic(EUnfinishedBusiness));
+
+ FLOG(_L("CBTSynchronousLinkAttacher attaching sync link"));
+
+ if(iSCOType == ESCO)
+ {
+ iParent.SCOSocket().Connect(aSockAddr, iStatus);
+ }
+ else
+ {
+ iParent.ESCOSocket().Connect(aSockAddr, iStatus);
+ }
+
+ SetActive();
+ }
+
+void CBTSynchronousLinkAttacher::RunL()
+ {
+ iParent.HandleSetupConnectionCompleteL(iStatus.Int(), iSCOType);
+ }
+
+TInt CBTSynchronousLinkAttacher::RunError(TInt /*aError*/)
+ {
+ // Swallow the error
+ return KErrNone;
+ }
+
+
+void CBTSynchronousLinkAttacher::DoCancel()
+ {
+ FLOG(_L("CBTSynchronousLinkAttacher cancel attach sync link"));
+ if (iSCOType == ESCO)
+ {
+ iParent.SCOSocket().CancelConnect();
+ }
+ else
+ {
+ iParent.ESCOSocket().CancelConnect();
+ }
+ }
+
+
+//--
+CBTSynchronousLinkDetacher* CBTSynchronousLinkDetacher::NewL(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ {
+ CBTSynchronousLinkDetacher* self = new (ELeave) CBTSynchronousLinkDetacher(aParent, aSCOType);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CBTSynchronousLinkDetacher::CBTSynchronousLinkDetacher(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ : CActive(CActive::EPriorityStandard), iParent(aParent), iSCOType(aSCOType)
+ {
+ }
+
+void CBTSynchronousLinkDetacher::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CBTSynchronousLinkDetacher::~CBTSynchronousLinkDetacher()
+ {
+ Cancel();
+ }
+
+void CBTSynchronousLinkDetacher::DetachSCOLink(const TDesC8& aDesOut, TDes8& aDesIn)
+ {
+ __ASSERT_ALWAYS(!IsActive(), Panic(EUnfinishedBusiness));
+
+ FTRACE(FPrint(_L("CBTSynchronousLinkDetacher detach sync link (0x%08x)"), &iParent));
+
+ if(iSCOType == ESCO)
+ {
+ iParent.SCOSocket().Shutdown(RSocket::ENormal, aDesOut, aDesIn, iStatus);
+ }
+ else
+ {
+ iParent.ESCOSocket().Shutdown(RSocket::ENormal, aDesOut, aDesIn, iStatus);
+ }
+
+ SetActive();
+ }
+
+void CBTSynchronousLinkDetacher::RunL()
+ {
+ FTRACE(FPrint(_L("CBTSynchronousLinkDetacher detached sync link (0x%08x)"), &iParent));
+ iParent.HandleDisconnectionCompleteL(iStatus.Int());
+ }
+
+TInt CBTSynchronousLinkDetacher::RunError(TInt /*aError*/)
+ {
+ // Swallow the error
+ return KErrNone;
+ }
+
+
+void CBTSynchronousLinkDetacher::DoCancel()
+//
+//not possible.
+//
+ {
+ FTRACE(FPrint(_L("CBTSynchronousLinkDetacher cancel detach sync link (0x%08x) -- no-op"), &iParent));
+ }
+
+
+//--
+CBTSynchronousLinkAccepter* CBTSynchronousLinkAccepter::NewL(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ {
+ CBTSynchronousLinkAccepter* self = new (ELeave) CBTSynchronousLinkAccepter(aParent, aSCOType);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CBTSynchronousLinkAccepter::CBTSynchronousLinkAccepter(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ : CActive(CActive::EPriorityStandard), iParent(aParent), iSCOType(aSCOType)
+ {
+ }
+
+void CBTSynchronousLinkAccepter::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CBTSynchronousLinkAccepter::~CBTSynchronousLinkAccepter()
+ {
+ Cancel();
+ }
+
+void CBTSynchronousLinkAccepter::Accept(RSocket& aSocket)
+
+ {
+ __ASSERT_ALWAYS(!IsActive(), Panic(EUnfinishedBusiness));
+
+ FLOG(_L("CBTSynchronousLinkAccepter accept sync link"));
+ if (iSCOType == ESCO)
+ {
+ aSocket.Accept(iParent.SCOSocket(), iStatus);
+ }
+ else
+ {
+ aSocket.Accept(iParent.ESCOSocket(), iStatus);
+ }
+ SetActive();
+ }
+
+
+void CBTSynchronousLinkAccepter::RunL()
+//
+//When logical socket has connected (only async bit),
+//opens baseband socket.
+//
+ {
+ FLOG(_L("CBTSynchronousLinkAccepter accepted sync link"));
+ iParent.HandleAcceptConnectionCompleteL(iStatus.Int(), iSCOType);
+ }
+
+TInt CBTSynchronousLinkAccepter::RunError(TInt /*aError*/)
+ {
+ // Swallow the error
+ return KErrNone;
+ }
+
+
+void CBTSynchronousLinkAccepter::DoCancel()
+ {
+ FLOG(_L("CBTSynchronousLinkAccepter cancel accept sync link"));
+ if (iSCOType == ESCO)
+ {
+ iParent.ListeningSCOSocket().CancelAccept();
+ }
+ else
+ {
+ iParent.ListeningESCOSocket().CancelAccept();
+ }
+ }
+
+
+//--
+CBTSynchronousLinkSender* CBTSynchronousLinkSender::NewL(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ {
+ CBTSynchronousLinkSender* self = new (ELeave) CBTSynchronousLinkSender(aParent, aSCOType);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CBTSynchronousLinkSender::CBTSynchronousLinkSender(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ : CActive(CActive::EPriorityStandard), iParent(aParent), iSCOType(aSCOType)
+ {
+ }
+
+void CBTSynchronousLinkSender::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CBTSynchronousLinkSender::~CBTSynchronousLinkSender()
+ {
+ Cancel();
+ }
+
+
+void CBTSynchronousLinkSender::SendSCOData(const TDesC8& aSCOData)
+ {
+ __ASSERT_ALWAYS(!IsActive(), Panic(EUnfinishedBusiness));
+
+#ifdef STACK_SCO_DATA
+
+ if (iSCOType == ESCO)
+ {
+ iParent.SCOSocket().Write(aSCOData, iStatus);
+ }
+ else
+ {
+ iParent.ESCOSocket().Write(aSCOData, iStatus);
+ }
+
+ SetActive();
+#else
+ (void)aSCOData;
+
+ // As transferring data through the HCI is not supported in this configuration,
+ // complete our own request with Not Supported.
+ // Uses event completion to keep sync/async behaviour consistent between
+ // configurations.
+ TRequestStatus* status = &iStatus;
+ iStatus = KRequestPending;
+ SetActive();
+ User::RequestComplete(status, KErrNotSupported);
+#endif
+ }
+
+void CBTSynchronousLinkSender::RunL()
+ {
+ iParent.HandleSendCompleteL(iStatus.Int());
+ }
+
+TInt CBTSynchronousLinkSender::RunError(TInt /*aError*/)
+ {
+ // Swallow the error
+ return KErrNone;
+ }
+
+
+void CBTSynchronousLinkSender::DoCancel()
+ {
+#ifdef STACK_SCO_DATA
+
+ if(iSCOType == ESCO)
+ {
+ iParent.SCOSocket().CancelWrite();
+ }
+ else
+ {
+ iParent.ESCOSocket().CancelWrite();
+ }
+
+#endif
+ // !STACK_SCO_DATA will have already completed the request, but Cancel() will
+ // swallow callback.
+ }
+
+
+//--
+CBTSynchronousLinkReceiver* CBTSynchronousLinkReceiver::NewL(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ {
+ CBTSynchronousLinkReceiver* self = new (ELeave) CBTSynchronousLinkReceiver(aParent, aSCOType);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CBTSynchronousLinkReceiver::CBTSynchronousLinkReceiver(CBluetoothSynchronousLink& aParent, TSCOType aSCOType)
+ : CActive(CActive::EPriorityStandard), iParent(aParent), iSCOType(aSCOType)
+ {
+ }
+
+void CBTSynchronousLinkReceiver::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CBTSynchronousLinkReceiver::~CBTSynchronousLinkReceiver()
+ {
+ Cancel();
+ }
+
+void CBTSynchronousLinkReceiver::ReadSCOData(TDes8& aDesc)
+
+ {
+ __ASSERT_ALWAYS(!IsActive(), Panic(EUnfinishedBusiness));
+
+#ifdef STACK_SCO_DATA
+
+ if(iSCOType == ESCO)
+ {
+ iParent.SCOSocket().Read(aDesc, iStatus);
+ }
+ else
+ {
+ iParent.ESCOSocket().Read(aDesc, iStatus);
+ }
+
+ SetActive();
+#else
+ (void)aDesc;
+
+ // As transferring data through the HCI is not supported in this configuration,
+ // complete our own request with Not Supported.
+ // Uses event completion to keep sync/async behaviour consistent between
+ // configurations.
+ TRequestStatus* status = &iStatus;
+ iStatus = KRequestPending;
+ SetActive();
+ User::RequestComplete(status, KErrNotSupported);
+#endif
+ }
+
+
+void CBTSynchronousLinkReceiver::RunL()
+ {
+ iParent.HandleReceiveCompleteL(iStatus.Int());
+ }
+
+TInt CBTSynchronousLinkReceiver::RunError(TInt /*aError*/)
+ {
+ // Swallow the error
+ return KErrNone;
+ }
+
+
+void CBTSynchronousLinkReceiver::DoCancel()
+ {
+#ifdef STACK_SCO_DATA
+
+ if (iSCOType == ESCO)
+ {
+ iParent.SCOSocket().CancelRead();
+ }
+ else
+ {
+ iParent.ESCOSocket().CancelRead();
+ }
+
+#endif
+ // !STACK_SCO_DATA will have already completed the request, but Cancel() will
+ // swallow callback.
+ }