Discussing the nuts and bolts of software development

Monday, April 30, 2007


Bluetooth Handsfree Profile Support for Windows Mobile 5 - The Series (Part 2)

Bluetooth HandsFree Profile Support for Windows Mobile 5 - part 2

In our last article, we explored some of the interfaces offered by the Audio Gateway (AG) for developers.
The problem was that some of the mechanisms offered in WinCE to signal the AG core of specific network events are not present in the PPC and Smartphone SDK. In this article, I'll show you how to create a lightweight replacement for the AG without spending two weeks (or more) figuring out what's inside that little "black box" they call the Audio Gateway. Please be aware I've never worked for Microsoft and everything within this article should be considered "as is".

To start, I'll give you some background information on how the AG core is constructed and then I'll share specific details on creating a connection with the Bluetooth device, processing AT commands, and routing audio to the Bluetooth chip.

The AG core consists of 3 modules:

Parser: Once the AG core has established a socket connection with the Bluetooth Headset device, the interactions between the WM5 device and the Bluetooth Headset are signed via the socket connection with AT Commands. The parser' responsibility is to retrieve these messages from the socket, parse them and return them to the Handler module for processing.

Interface: Exposes methods to signal the network states and initiate commands from the services layer. It also listens for incoming Bluetooth device requests that are trying to create a baseband connection, whether synchronously or asynchronously.

Handler: The core module that receives input from both the Interface module and the Parser module and, based on those stimuli and the internal state of the AG core, will respond accordingly, i.e. send AT command responses, create a service level socket connection, an IOCTL call to the audio driver to route voice...etc.

The Meat and Bones of the Parser
The parser is quite simple. After the Handler creates a socket connection with the Bluetooth Headset (I'll talk more about that in the third installment) it passes the connected socket to the Parser module to listen for and receive incoming AT commands. Listed below are the AT commands that are supported by the Bluetooth HandsFree profile and their corresponding general definitions.

"AT+CKPD=200" - Indicates a Bluetooth button press
"AT+VGM=" - Indicates a microphone volume change
"AT+VGS=" - Indicates a speakerphone volume change
"AT+BRSF=" - The Headset is asking what features are supported
"AT+CIND?" - The Headset is asking about the indicators that are signaled
"AT+CIND=?" - The Headset is asking about the test indicators
"AT+CMER=" - The Headset is asking which indicates are registered for updates
"ATA" - When an incoming call has been answered, usually a Bluetooth button press
"AT+CHUP" - When a call has been hung up, usually a Bluetooth button press
"ATD>" - The Headset is requesting the local device to perform a memory dial
"ATD" - The Headset is requesting to dial the number
"AT+BLDN" - The Headset is requesting to perform last number dialed
"AT+CCWA=" - The Headset has enabled call waiting
"AT+CLIP=" - The Headset has enabled CLI (Calling Line Identification)
"AT+VTS=" - The Headset is asking to send DTMF digits
"AT+CHLD=" - The Headset is asking to put the call on Hold
"AT+BVRA=" - The Headset is requesting voice recognition
"ATH" - Call hang-up

Once the parser receives one of these commands, it parses the received buffer for these character sequences and passes the parsed command back to the Handler (discussed later) as an enumeration that the Handler will be able to identify and process.

The Meat and Bones of the Interface Module
The Interface module exposes methods for signaling the Handler of network connections, listens for incoming connections and calls Handler methods of services requests.

Firstly, the Interface layer must ensure that the Bluetooth stack has been started, otherwise there's no point in processing any other commands for the network layer or the services layer. The mechanism in which the underlying layer signals that the Bluetooth stack is fully functional is via waiting on an Event Handle. Here's some code to support this:
#define BTH_NAMEDEVENT_STACK_INITED L"system/events/bluetooth/StackInitialized"

// m_closeEvent is a previously Created Event to signal other
// waiting threads to stop waiting (created by the developer)

if( btStack && m_closeEvent )
HANDLE waitObjects[] = {btStack, m_closeEvent};
DWORD result = ::WaitForMultipleObjects( 2, &waitObjects[0], FALSE, INFINITE );
::CloseHandle( btStack );
if( result - WAIT_OBJECT_0 == 0 )
//The Bluetooth stack is up, signal core module to finish initialization
else if( 1 == result - WAIT_OBJECT_0 WAIT_FAILED == result )
// We've been signaled to close, Bluetooth stack is down!
// Or our application has signaled us to stop waiting

Here we wait on the Open Bluetooth Stack Initialized Event or our own pre-created event to indicate either the Bluetooth stack is operational or to exit, since our application is closing too.

This same scheme also works for waiting for a synchronous or asynchronous baseband connection (Which I'll discuss further in the third installment), but instead of waiting on the BTH_NAMEDEVENT_STACK_INITED wstring, we wait on the Opened Event BTH_NAMEDEVENT_CONNECTIONS_CHANGED, as defined below:
#define BTH_NAMEDEVENT_CONNECTIONS_CHANGED L"system/events/bluetooth/ConnectionsChange"

If the Interface module receives a signal of this event, it notifies the Handler module to check its baseband connections for changes.

Aside from the listening for baseband connections, or if the Bluetooth Stack is up, the Interface module also want to process service commands and network layer notifications. So, following the services interface, as mentioned in the previous article, the module needs to support:

Opening audio
Closing audio
Opening a control channel
Closing a control channel
Getting/setting the microphone volume
Getting/setting the speaker volume
Getting/setting the power mode

And these methods simply call the Handler methods for processing (Which I'll talk about more in the third installment).
For reliability, however, a developer can't create a control channel if no Bluetooth device has been paired with the WM5 device (obviously). Also, a developer can't open up a control channel without a fully initialized Interface Module (Bluetooth Stack is operational).
Secondly, you can't open an audio channel if there is no control channel open.

On the Network signaling side, the Interface Module exposes a method call to the network layer, which passes a number to identify the type of network call being signaled. The supported signaling calls are:

void BthAGOnNetworkEvent( DWORD dwEvent, LPSTR pszParam );

If you're designing the Interface module and the appliction accesses the network layer, you'll have to support these defines and signal your Handler class to handle these events. For more detail on these libraries, visit the MSDN website.

Important Note:
If you're developing the Interface Module alongside Microsoft's Audio Gateway, be sure that you turn off the MS AG in your Interface Module initialization code before doing anything else. If you don't, the Microsoft's AG will interfere with *your* Gateway application. The first article in this series lists code that turn offs the service. Please refer to it for the IOCTL call that corresponds to the service shutdown.

Ok, now we're getting to the really juicy part, The Handler Module. What's ticking underneath that hood, you might ask. In this article, we've explored a system level overview of the AG core and gone into details about the different responsibilities associated with the Parser Module and the Interface Module. But what ties them all together? The Handler module!

Stay tuned for a detailed description of the Handler Module...

Internet Explorer may not respond when you click Print or Print Preview in the File menu.When you try to connect to Web folders, you may receive the following error message:The current operation could not be completed because an unexpected error has occurred.
What version were you using?
This is very useful artical, I have developed tiny AG for bluetooth Hands Free (HF) device but I am facing issue to connect with HF when HF is made ON/OFF means connection from HF side.

I am able to make socket connection with BT_ADDRESS from registry to HF but how can I make it possible that HF make connection with me when it made start.
There are a few options you can use to detect that the Headset has either turned on or is trying to communicate with your device.
You can listen to the event "system/events/bluetooth/ConnectionsChange" just call OpenEvent with this string. Otherwise you can build a notification framework around RequestBluetoothNotifications(...). Look on msdn for more information about this. If your bluetooth device is paired and has turned on it will notify with an event
Another problem that you might run into is that MS AG might be interferring with your tiny AG. If that is the case simple do a IOControl call to the "BAG" to stop the control channel
Thanks for your prompt response.I tried both the methods to get event on connection change but I am facing issue like I get disconnect event immediately as I get connect event. I figure out the event type by second method Request......
I have already stoped MS AG (BAG ) service.
How can my AG accept the initiated connection request and get socket handle or should my AG try to connect with the BT_Address what my AG currently doing??
Try this out, don't stop the MS AG service entirely, keep it running. If you receive the disconnection from the headset (e.g. the headset has powered off or gone out of range) close the connection and start the MS AG control channel. When you receive a notification that there is a baseband connection again, stop MS AG control channel and then try to connect to the headset with your tiny AG. And yes connect with the BT_Address from the registry. Does this answer your question? - I'm a little unclear as to your second post.
Hello Quan Nguyen,

I tried your suggested way to connect with HF by stopping MS AG control channel on baseband connection event but the issue is my AG fails to connect with HF if my AG try to connect with HF on base band connection event, means MS AG start to make connection with HF earlier than my AG start on the event.

My AG is able to make connection with HF after few second (around 1)of the event by closing already opened MS AG connection by IOCTL_AG_CLOSE_CONTROL.

How can I stop MS AG to make connection on this connection event? or any other event that I can use for knowing about MS AG made connection with HF after base band connection event.

One thing I also want to know is if I stop entire MS AG service is there any functinality that may be affected like pairing or file transfer or other???

Any help will be very helpful to me.
Yes the MS AG when it receives the baseband notification will connect faster than your AG. And from my experience this is unavoidable unless you turn the MS AG off entirely. If MS AG service is running I do not know of any "clean" way of stopping the MS AG service from trying to connect.
You will be able to see that the headset makes a connection with the system through the RequestBluetoothNotifications notifications and you can equate that if you're not connect to it, it must be the MS AG.

If you turn off MS AG entirely, pairing and file transfer will not be affected (to my knowledge). However functionality related to BT audio while *your* AG has control of the control channel will be affected if you don't support it properly.
Hello Quan Nguyen,

Thanks for your response.
I did it by stopping MS AG entirely.
Again I have one issue related to connect() API with blocking mode. When HF is already OFF and I am trying to make connection by connect() it blocks for ever and it hangs my application. and also normally when HF is ON connect() takes 7-10 seconds to return. Can you please give me some guide line or how to tackle with such situation.
Well there a few things you can do to get around this. You can always run a multi-threaded application. One thread would call the connect() and on another thread you can set a timer which will closesocket() and stop the connect() from blocking. You can also use the select() method with a timeout. Drop by MSDN and take a look at the methods for socket programming. When the Headset is ON and it takes 7-10 seconds to connect, I think this is unavoidable. This is the latency it takes for the bluetooth connection to negotiate properly. From my experience it shouldn't take that long. If you analyse your code and it's not because of something you're doing in your application then from your perspective there is really nothing you can do (I believe - from an application level implementation).
Hello Quan Nguyen,

One time more I need your help.
I already created complete service for bluetooth AG and it works fine.

Issue I am facing in DOPOD 810 and HTC TyTN is Createfile("PFX0",0,0,NULL,OPEN_EXISTING,0,NULL);

But it fails every time I try to call createfile() and return invalid handle (0xFFFFFFFFF).

It is called in multithreaded application.
A few things here,
1# For your CreateFile(...) make sure that it is L"PFX0" and not "PFX0". I would imagine this is important. The compiler should catch this
2# Make sure that the index is correct, possibly it could be PFX1..etc
3# Make sure that you can find this within the active drivers list [HKEY_LOCAL_MACHINE\Drivers\Active] within the registry of the device
4# If createFile(...) returns an error what does GetLastError() return, this could reveal some possible hints.
Hello Quan Nguyen,

One hint I want, is service I made for tiny bluetooth gateway is working correctly with HTC Touch. I am facing issue with TyTN device is event socket gets connected with Hands Free it doesn't start to send AT commands to my service. Also some time I start to connect and it doesn't gets connected forever. Is there any thing missing to say bluetooth stack after socket gets closed??

Socket connection is not smooth as HTC Touch device I am getting.

I try to connect with hands free when STACK_UP, connect event from stack.
Hello Quan Nguyen,

I want to close connection on removing pairing from settings on PDA.

Can you please suggest me the way how can I get notification of removing perticular pairing??

One thing I found with my AG is once my AG gets connected with HF and I remove pairing from PDA, still registry entry for the same HF is there and not removed while in case of not connected with HF via my AG it removes the registry on removing pairing.

Any thing left to inform stack to take that action after closing socket??
Hello Quan Nguyen,

I really want help from you,

My service for BTAG works fine but I am facing issue for making pairing.
Pairing logic I am using from default , When device gets paired my service will try to make connection.

I handled BTE_KEY_REVOKED event to remove connection on removing pairing. Problem I am facing with Jabra BT135 is after removing pairing if I try to make pairing again then Jabra device continuously asking for passkey and give incorrect passkey msg.

On removing pairing my service just close the socket and tear down the connection. I think any thing is missed out during closing connection hence again pairing create issue.

Can you please tell me for closing connection with BTHF just close socket in any condition like active voice or active call? or anything need to take care with BTHF or stack.

After removing pairing if I try it again, device found successfully and asking for passkey again and again.

How can I tell BTHF or stack to remove previous connection completely sp I can make fresh pairing and new connection again??

Please respond atleast.

Thanks in advance.
Hello Quan Nguyen,

I didn't receive any reply for earlier post.

Can you please reply for this one atlest?

Proble I am facing is receiving AT commands.

After making BT radio ON when my AG try to connect with BTHF and gets connected and negotiated with proper At commends and responses successfully but after that my AG didn't receive any AT commands for call operating like ATA,CHUP or BLDN and none. When my AG sends AT commands like RING it operates correctly and play ring but my AG didn't receive any At commands from HF.

This problem happens only when I break active connection by making BT radio OFF. It doesn't create any problem if I break active connection by making BTHF OFF. Why my AG didn't get any AT commands from BTHF?????

Is there anything to say to BT stack or BTHF???

Any registry to cahnge?
When I make BTHF off and try to make connection after makinf ON, it works fine but not working when BT radio is made OFF and then ON, it gets negotiated correctly but after that not responding well and At commands are not received.

Please respond at lest, even have no answer.
Hi Paresh,
My apologies for not responding, I'm not a part of the Macadamian Files any longer and hence have not checked this blog site for quite some time.

My apologies again


Quan Nguyen
How can I control the AG to connect HF by my application?
I tried to use the bluetooth api, suck as: BthCreateACLConnection, BthCreateScoConnection, or via socket directly. But all did work.
Because the AG didn't know the connection status. Maybe i have to use the AG to connect HF in the application.
Dịch Thiến hai nàng.

Lúc này hai nàng lui qua một bên, cửu tinh thập tinh Đấu Tôn giao thủ bọn họ không muốn nhúng tay vào.

Mà đúng lúc này, hai nàng nhìn thấy hai lão nhân kia đánh về phía mình thì biến đổi sắc mặt.

- Các ngươi cẩn thận.

Trưởng lão Hoàng Vũ cất tiếndongtam
mu private
tim phong tro
nhac san cuc manh
tổng đài tư vấn luật
văn phòng luật
tổng đài tư vấn luật
dịch vụ thành lập công ty
chém gió
trung tâm ngoại ngữg hét một tiếng, nàng vốn định ngăn cản lão nhân kia.

Dịch Thiến cùng với Thượng Quan Uyển Nhi sắc mặt biến đổi lớn, lão nhân kia đã bắn về phía hai nàng, một đạo chưởng ấn phá không mà tới, trong nháy mắt đã hiện ra trước người của cả hai.

- Ầm ầm.

Một luồng tiếng nổ kinh thiên động địa vang lên ở trên không trung, khiên cho Dịch Thiến và Thượng Quan Uyển Nhi cũng cảm thấy sợ hãi.

Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?