Controlling the speakerphone

Funny as it might seem, the simple task of controlling the speakerphone, this very common device present on almost all the modern types of phones from fixed telephony stations to the most complex mobiles, is not such a simple task to achieve on devices with WM2003 or WM2005. The APIs that should toggle the speakerphone on and off simply fail, and you will loose time implementing programs with the TAPI lineXXX family or the phoneXXX set of functions just to find out that lineSetTerminal will never do what you want when trying to control the speakerphone and phoneSetHookSwitch will always return PHONEERR_OPERATIONFAILED.

Its not so nice to know that as a developer you are always limited by some OEM’s policy regarding disclosure of data. Still how one is expected to develop an application without having full specifications of the ways available for implementing the tasks he desires?

Companies like HTC in Taiwan, growing larger and larger by every day that passes, have “closed their gates”, and only God knows what they are putting inside those devices. On one hand they are controlling the hardware market (80% at this time), and because of the “forbidden knowledge” they are capable of controlling the software development by setting limits to the mobile-developers world.

Hey, these are the rules of the game, who doesnt want to play can step outside.
Fortunatelly, there is no thing created by man, that another man can’t understand…reproduce…dissassemble… ;). It just costs a lot of extra-time…


The WM5/WM6 solution

There were lots of expectations from the new WM2005. We all thought that it will change the world for us, to make it better, to offer more understanding. But it seems we cant get rid of our problems so easily.

Still, the solution that we are seeking for our speakerphone lays burried in the multitude of undocumented .dlls that come with our WM2005 devices. Lets take a closer look:

The cprog.exe (the Phone application) offers an option for enabling the speakerphone. That button relies on some exports from ossvcs.dll for accomplishing this task. In order to set the speakerphone mode, cprog calls the ossvcs_218 from the ossvcs.dll. So lets try do replicate this behaviour…

typedef HRESULT (* _SetSpeakerMode)(DWORD mode);
_SetSpeakerMode pfnSetSpeakerMode;

HINSTANCE hDll = LoadLibrary(L”\\windows\\ossvcs.dll”);
_debug(L”ossvcs.dll h=%X”,hDll);
pfnSetSpeakerMode = (_SetSpeakerMode)GetProcAddress(hDll,(LPCTSTR)218);
if (pfnSetSpeakerMode)
{
_debug(L”SetSpeakerMode imported.”);
DWORD sm = 1;
_debug(L”SpeakerMode set to %d”, sm);
pfnSetSpeakerMode(sm);
}
else
_debug(L”pfnSetSpeakerMode import failed.”);
FreeLibrary(hDll);

Nice to see that the debug entries can confirm that we successfuly imported that function. By calling this code while in a phone call, we get the speakerphone succesfully turned on. Playing with some values for the parameter of pfnSetSpeakerMode, we get interesting results: 0 turns off the speakerphone and 1 enables the speakerphone.

After some tests it is clear that ossvcs.dll also exports a function to get the current settings for the speakerphone. The ordinal number is 217, we can call it GetSpeakerMode. It returns 0 or 1.

Please also check this sample posted here:speakerphone_2005 . It contains a complete implementation of the speakerphone handling for 2005 devices: both GetSpearMode and SetSpeakerMode.


The Pocket PC 2003 solution

It is hard to dig into unknown, but it is even harder to have to dig for each of the different platforms/devices. On 2003 we are dealing with a totally different approach then the 2005. Still, I will try to provide a solution that works with all the HTC devices out on the market. In case one particular device doesnt work with my solution, feel free to contact me so we can work it out.
As the 2003 ossvcs.dll doesnt offer the same support for speakerphone (on 2005 ossvcs.dll’s 217 and 218 exports rely on the SPK1: driver, which is not present on the 2003 devices), we have to go down to the Audio Driver level to understand how to control the speakerphone.
Because one of my projects was to create an Audio Driver for the PocketPC/Smartphone platform, I was able to analyze the data at that particular low-level. The IOCTL_WAV_MESSAGE was very often pointing to a MMDRV_MESSAGE_PARAMS structure. The uMsg parameter of this structure was containing the normal, documented values from 3 to 62, and in the case of a speakerphone toggle (by pressing the Green, talk button while in a call) the value 102. As the code ‘102′ was undocummented, we where lucky enough that the incoming buffer was a DWORD, very easy to understand. So, when the user would have toggled the speakerphone on, the audio driver would have received an IOCTL_WAV_MESSAGE pointing to a MMDRV_MESSAGE_PARAMS with uMsg == 102. Same for toggling the speakerphone off.

All that one has to do in order to enable/disable the speakerphone on a HTC 2003 device, is to send to the audio driver (WAV1:) a DeviceIoControl constructed as follows:

DWORD out;
MMDRV_MESSAGE_PARAMS mp;
memset(&mp,0,sizeof(mp));
mp.uMsg = 102;
DeviceIoControl(g_hWavDev, IOCTL_WAV_MESSAGE, &mp,sizeof(mp),&out,sizeof(out), &dwRet,0);
CloseHandle(g_hWavDev);


In order to help you understand this technique, I’ve prepared another sample: speakerphone_2003

So that’s all you need to do for controlling the speakerphone. Im sure that we will have a different approach in the short future, hopefully the well documented API’s will start really doing what they are ment to do, and we’ll all be amazed and think a miracle had happened.
Until then, your feedback is most welcomed.

Radu Motisan
June 23, 2006

This article has 1 Comment

Leave a Reply