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
// Source file:
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()
{
}