| Reply | « Previous Thread | Next Thread » |
|
Hi All,
I hope - that text helps somebody during research of BT problems. In our application it was required to establish SPP connection over BT (with GPS receiver or Car-Kit which also sends GPS data). Parallel the phone uses the A2DP or the HFP to pass the Audio to the Car-Kit. Here is description of some problems and solutions (works at S60, tested with N95). 1) If you call the Notifier to get the BT Power "On", and the BT Power was already "On" - the existing audio BT connection will be broken (so if you already have the audio connection before that notifier call - it will be stopped from Symbian). Solution: check if the BT is off before call that notifier: Code:
TInt MyClass::GetCurrentPowerState()
{
CRepository *crep = CRepository::NewL(KCRUidBluetoothPowerState);
TInt value=0;
CleanupStack::PushL( crep );
User::LeaveIfError( crep->Get(KBTPowerState, value) );
CleanupStack::PopAndDestroy( crep );
return value;
}
if (EBTPowerOn == GetCurrentPowerState())
{
// the BT is already "on", just do what you like to do
}
else
{
User::LeaveIfError(MyRNotifier.Connect());
MyRNotifier.StartNotifierAndGetResponse(
iStatus,
KPowerModeSettingNotifierUid,
m_pckg,
m_result);
SetActive();
}
Solution: try to discover the services at the target BT-device before connect to it (You don't need to discover the devices, just discover the services for known address). Note: discovering the services at BT devices (so far as discovering of BT devices) "loads" the BT - so the audio transmition (sound) will be interrupted, but will stay "alive" (so the audio connection will not be broken). To avoid a high loading of audio connection through services discovering - add an adaptive timeout between trying to reconnect. For example - initially try to reconnect 3 times with delay = 5 seconds between reconnections, then try to connect each 40 seconds. So far the connection was established - you can reset the counter of timeouts. I'm talking here about connection to the already known device (i.e. to address which is already saved in your program configuration as "last used"). In case you just connect to the device which was discovered right now (i.e. which was selected by user from corresponding dialog) - you don't need such complex behaviour, just connect to it. If the device is here - the discovering of first SPP service goes really fast (less that 2 seconds), so you can use it before each connection. In case the device is not present - it takes longer, so you need a timeout to abort the discovering (for example - 5 seconds). Hope, that helps for somebody. Good Luck! Andrey |
| Andrey.Tetyuev |
| View Public Profile |
| Find all posts by Andrey.Tetyuev |
|
P.S. here is the example of checker - if the device is still here (i.e. Discover of SPP services):
// Header Code:
#ifndef CBTDeviceDiscover_h
#define CBTDeviceDiscover_h 1
// required capabilities: LocalServices
// used libraries: sdpagent.lib, sdpdatabase.lib
#include <btsdp.h>
// determines template for callback class/function which is used by CBTDeviceDiscover so far it gets result
class CBTDeviceDiscover_CallBack
{
public:
// callback function declaration to be implemented in your class; bDevicePresent=true if the device was found;
virtual void BTDeviceDiscovered( bool bDevicePresent, TUint uiPort, bool bPortValid ) = 0;
};
// class CBTDeviceDiscover used to check if the BT device with given address is still present (by discovering the services of device)
class CBTDeviceDiscover : public CBase,
public MSdpAgentNotifier,
public MSdpAttributeValueVisitor
{
public:
// constructor
CBTDeviceDiscover(CBTDeviceDiscover_CallBack & rCallBackClass);
// destructor
~CBTDeviceDiscover();
// discover if the device with given address present (asynchronous).
void DiscoverDeviceL(TBTDevAddr & devAddr);
// stopes the discovery (aborts it and delete variables used for it)
void StopDiscovery();
private:
// from MSdpAgentNotifier:
void NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount);
void AttributeRequestResult(TSdpServRecordHandle aHandle, TSdpAttributeID aAttrID, CSdpAttrValue* aAttrValue);
void AttributeRequestComplete(TSdpServRecordHandle aHandle, TInt aError);
// from MSdpAttributeValueVisitor:
void VisitAttributeValueL(CSdpAttrValue &aValue, TSdpElementType aType); // Called for processing of each service attribute.
void StartListL(CSdpAttrValueList &aList); // should be declared, but not needed to be implemented
void EndListL(); // should be declared, but not needed to be implemented
// member variables:
CBTDeviceDiscover_CallBack & m_rCallBackClass; // reference to callback class used if the discovery is finished
TBTDevAddr m_devAddr; // BT device address
CSdpAgent * m_pAgent; // Service discovery agent
CSdpSearchPattern * m_pSearchPattern; // Service discovery search pattern
TUUID m_uiCurrUUID; // currently discovered attribute uuid in the service attributes
TUint m_uiPort; // Port (comm channel) found in the service attributes
bool m_bPortValid; // true if the Port was retrieved
bool m_bDiscovering; // true if currently discovering the device (if interested on results of listener functions)
};
#endif // #ifndef CBTDeviceDiscover_h
Code:
#include <bt_sock.h>
// don't forget to adapt to your paths
#include "CBTDeviceDiscover.h"
CBTDeviceDiscover::CBTDeviceDiscover(CBTDeviceDiscover_CallBack & rCallBackClass)
: m_rCallBackClass(rCallBackClass),
m_pAgent(NULL),
m_pSearchPattern(NULL),
m_uiCurrUUID(0),
m_uiPort(0),
m_bPortValid(FALSE),
m_bDiscovering(FALSE)
{
m_devAddr.Reset();
}
CBTDeviceDiscover::~CBTDeviceDiscover()
{
StopDiscovery();
}
void CBTDeviceDiscover::DiscoverDeviceL(TBTDevAddr & devAddr)
{
StopDiscovery(); // to avoid conflicts if called several times before the old discovery is finished
const TInt BT_UUID_SPP_SP = 0x1101; // SPP (Serial Port) UUID
m_devAddr = devAddr;
// Init new service discovery agent
m_pAgent = CSdpAgent::NewL( *this, m_devAddr );
// Set search properties for agent (use SPP service-UUID to filter the services discovered)
m_pSearchPattern = CSdpSearchPattern::NewL();
m_pSearchPattern->AddL(BT_UUID_SPP_SP);
m_pAgent->SetRecordFilterL(*m_pSearchPattern);
m_bDiscovering = TRUE;
// Initiate search, result will be received with call of NextRecordRequestComplete()
m_pAgent->NextRecordRequestL();
}
void CBTDeviceDiscover::StopDiscovery()
{
m_bDiscovering = FALSE;
if(m_pAgent)
{
m_pAgent->Cancel();
delete m_pAgent;
m_pAgent = NULL;
}
if(m_pSearchPattern)
{
m_pSearchPattern->Reset();
delete m_pSearchPattern;
m_pSearchPattern = NULL;
}
m_bPortValid = FALSE;
m_uiPort = 0; // the BT port is unknown
}
// called when the service discovery agent has completed discovering services on device (i.e. if next service found or not)
void CBTDeviceDiscover::NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount)
{
if ( ( KErrNone==aError) && (0<aTotalRecordsCount) )
{
// We got next service record, request protocol descriptor to retrieve remote port
// (it calls later the AttributeRequestResult() when the answer is ready)
TRAPD(err,m_pAgent->AttributeRequestL(aHandle, KSdpAttrIdProtocolDescriptorList));
if( err )
{
StopDiscovery();
m_rCallBackClass.BTDeviceDiscovered(true, 0, false);
}
}
else
{
// no any services found or error occures (probably the device is not present or SPP service is not present)
StopDiscovery();
m_rCallBackClass.BTDeviceDiscovered(false, 0, false);
}
}
// Called when the service attributes for the service record have been retrieved.
void CBTDeviceDiscover::AttributeRequestResult(TSdpServRecordHandle, TSdpAttributeID,
CSdpAttrValue* aAttrValue)
{
// can't ignore the call of this function because we need take care about aAttrValue
// Parse attributes, it will return results by several calls of VisitAttributeValue()
TRAPD( err, aAttrValue->AcceptVisitorL(*this) );
if( err )
{
StopDiscovery();
m_rCallBackClass.BTDeviceDiscovered(true, 0, false);
}
delete aAttrValue;
}
// Called when the request to resolve the service attributes for the service record completes.
void CBTDeviceDiscover::AttributeRequestComplete(TSdpServRecordHandle, TInt aError)
{
m_rCallBackClass.BTDeviceDiscovered(true, m_uiPort, m_bPortValid);
// if KErrNone ==aError and we need not just the first SPP service but check several services,
// can call for m_pAgent->NextRecordRequestL() here (and add corresponded processing in
// NextRecordRequestComplete() )
if (KErrNone != aError)
{
// Error processing (if required)
}
StopDiscovery();
}
// Called for processing of each service attribute.
void CBTDeviceDiscover::VisitAttributeValueL(CSdpAttrValue &aValue, TSdpElementType aType)
{
if ( ! m_bDiscovering )
{
return; // ignore calls to that function if not discovering currently
}
// Check for attributes of UUID type. If the UUID is RFCOMM UUID, resolve the value for this attribute,
// which will be the channel number.
switch (aType)
{
case ETypeUUID: // UUID of attribute, store it
{
TPtrC8 uuid(aValue.UUID().ShortestForm());
m_uiCurrUUID.SetL(uuid);
break;
}
case ETypeUint: // uint value, check if the current attribute type is KRFCOMM, store the port value if "yes"
{
if ( m_uiCurrUUID==KRFCOMM )
{
m_uiPort=aValue.Uint();
m_bPortValid = TRUE;
m_bDiscovering = FALSE;
}
break;
}
default:
// other attributes are not interesting for processing...
break;
}
}
void CBTDeviceDiscover::StartListL(CSdpAttrValueList&)
{
}
void CBTDeviceDiscover::EndListL()
{
}
![]() |
| Andrey.Tetyuev |
| View Public Profile |
| Find all posts by Andrey.Tetyuev |
| Reply | « Previous Thread | Next Thread » |
| Thread Tools | Search this Thread |
|---|---|
| Thread | Thread Starter | Forum | Replies | Last Post |
|---|---|---|---|---|
| Bluesoleil Software | kencooper | Bluetooth Technology | 9 | 2008-08-29 20:46 |
| Bluelet - Rapid Bluetooth App Development (Free source) | huiben | Mobile Java General | 4 | 2008-07-25 16:52 |
| Bluetooth State | satyadeepg | Mobile Java Networking & Messaging & Security | 2 | 2007-06-10 19:11 |
| Bluetooth GPS simulator for j2me phone | vgps | Mobile Java Networking & Messaging & Security | 2 | 2007-02-09 05:30 |
| Bluetooth Emulation | aohx075 | Mobile Java Tools & SDKs | 0 | 2004-08-24 05:14 |