bluetoothmgmt/bluetoothclientlib/btlib/btsynclink.cpp
changeset 0 29b1cd4cb562
child 22 786b94c6f0a4
--- /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.
+	}