Thursday, August 09, 2007

Bluetooth Audio on WinCE

This is derived from code I found on this blog. Basically, you do waveInOpen and waveOutOpen and then startup some special Bluetooth code. A paired headset's settings are stored in the registry and contains an address needed by the open connection function.
#include <winsock2.h>
#include <ws2bth.h>


typedef int (*BthCreateSCOConnectionWrapper)( BT_ADDR*, unsigned short* );
typedef int (*BthCloseConnectionWrapper)( unsigned short );

/* Hidden deep in the WinCE sources, I guess. */
#define WODM_BT_SCO_AUDIO_CONTROL 500

/*
Call this function with the address of a paired headset (use FindBTAudioDevice),
a valid handle from waveOutOpen and you will be given a connection handle.

Returns 0 if successful.

*/
int ConnectWaveOutToBT(BT_ADDR btaddress, /* Bluetooth device address. */
                       void *btserviceid, /* Unused */
                       HWAVEOUT hWaveOut, /* Audio device */
                       unsigned short *connection_handle) /* out parameter */
{
  int err = 0;
  HMODULE hMod = NULL;

  /* Code for creating a SCO connection */
  {
    BthCreateSCOConnectionWrapper dll_BthCreateSCOConnection;

    hMod = GetModuleHandle(L"btdrt.dll");
    if ( hMod == NULL )
      hMod = LoadLibrary(L"btdrt.dll");
    if ( hMod == NULL )
    {
      err = 1;
      goto exit_function;
    }

    dll_BthCreateSCOConnection = (BthCreateSCOConnectionWrapper)
                                 GetProcAddress(hMod, L"BthCreateSCOConnection");
    if ( dll_BthCreateSCOConnection == NULL )
    {
      err = 1;
      goto exit_function;
    }

    /* Use the address to get a connection. */
    dll_BthCreateSCOConnection(&btaddress, connection_handle);

    /* Tell the audio device to begin using Bluetooth (I think). */
    waveOutMessage(hWaveOut, WODM_BT_SCO_AUDIO_CONTROL, 0, TRUE);
    err = 0;
    goto exit_function;
  }

exit_function:

  return err;
}


int DisconnectWaveOutFromBT(HWAVEOUT waveouthandle,
                            unsigned short connection_handle )
{
  int err = 0;
  BthCloseConnectionWrapper dll_BthCloseConnection = NULL;
  HMODULE hMod = NULL;

  /* To close the audio channel, 
    1. Signal the audio driver to stop routing to the Bluetooth chip;
    2. Close the SCO connection.
  */
  waveOutMessage(waveouthandle, WODM_BT_SCO_AUDIO_CONTROL, 0, FALSE);

  hMod = GetModuleHandle(L"btdrt.dll");
  if( hMod == NULL )
  {
    err = 1;
    goto exit_function;
  }

  dll_BthCloseConnection = (BthCloseConnectionWrapper)
                            GetProcAddress(hMod, L"BthCloseConnection");
  if ( dll_BthCloseConnection == NULL )
  {
    err = 1;
    goto exit_function;
  }
  dll_BthCloseConnection(connection_handle);

exit_function:

  return err;
}

int FindBTAudioDevice(BT_ADDR *device, size_t *devices)
{
  HKEY hKey;
  size_t i = 0; /* < *devices */

#define AUDIOGATEWAY_DEVICES L"SOFTWARE\\Microsoft\\Bluetooth\\AudioGateway\\Devices"
  if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, AUDIOGATEWAY_DEVICES, 0, 0, &hKey))
  {
    DWORD dwIndex = 0;
    WCHAR wzSubKey[MAX_PATH];
    DWORD dwLen = MAX_PATH;

    while (ERROR_NO_MORE_ITEMS != 
            RegEnumKeyEx(hKey, dwIndex++, wzSubKey, &dwLen, NULL, NULL, NULL, NULL)
            && i < *devices)
    {
      HKEY hSubKey;
      WCHAR wzValue[MAX_PATH];

      StringCchCopy(wzValue, MAX_PATH, AUDIOGATEWAY_DEVICES);
      StringCchCat(wzValue, MAX_PATH, L"\\");
      StringCchCat(wzValue, MAX_PATH, wzSubKey);

      if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, wzValue, 0, 0, &hSubKey) )
      {
        DWORD dwType, dwLen;
        BYTE bData[1024];

        dwLen = 1024;

        if ( ERROR_SUCCESS == 
               RegQueryValueEx(hSubKey, L"Address", NULL, &dwType, bData, &dwLen) )
        {
          if ( dwType == REG_BINARY )
          {
            memset(&device[i], 0, sizeof(BT_ADDR));
            memcpy(&device[i], bData, dwLen);
            i++;
          }
        }

        RegCloseKey(hSubKey); /* Keys under AudioGateway\Devices in registry */
      }
    }

    RegCloseKey(hKey); /* AudioGateway\Devices in registry */
  }
  *devices = i;

  return 0;
}

1 comment:

Anonymous said...

I can't seem to get this to work on my i610. This is the only webpage that I have found when searching for dll_BthCreateSCOConnection.