www.pudn.com > WINCEOS.zip > audiogw.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
#include "btagpriv.h"
#include "btagnetwork.h"
#ifdef DEBUG
DBGPARAM dpCurSettings =
{
TEXT("BTAGSVC"),
{
TEXT("Output"),
TEXT("Misc"),
TEXT("Service"),
TEXT("Parser"),
TEXT("Handler"),
TEXT("Network"),
TEXT("PhoneUI"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Warning"),
TEXT("Error")
},
0x0000C001
};
#endif
#define MAX_SDP_RECORD_SIZE 0x048
#define SDP_HS_RECORD_SIZE 0x0000003d
BYTE rgbSdpRecordHeadsetHS[] = {
0x35, 0x3b, 0x09, 0x00, 0x01, 0x35, 0x06, 0x19,
0x11, 0x12, 0x19, 0x12, 0x03, 0x09, 0x00, 0x04,
0x35, 0x0c, 0x35, 0x03, 0x19, 0x01, 0x00, 0x35,
0x05, 0x19, 0x00, 0x03, 0x08, 0x0a, 0x09, 0x00,
0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x11, 0x08,
0x09, 0x01, 0x00, 0x09, 0x01, 0x00, 0x25, 0x0d,
0x56, 0x6f, 0x69, 0x63, 0x65, 0x20, 0x47, 0x61,
0x74, 0x65, 0x77, 0x61, 0x79
};
#define SDP_HS_CHANNEL_OFFSET 29
#define SDP_HF_RECORD_SIZE 0x00000048
BYTE rgbSdpRecordHeadsetHF[] = {
0x35, 0x46, 0x09, 0x00, 0x01, 0x35, 0x06, 0x19,
0x11, 0x1f, 0x19, 0x12, 0x03, 0x09, 0x00, 0x04,
0x35, 0x0c, 0x35, 0x03, 0x19, 0x01, 0x00, 0x35,
0x05, 0x19, 0x00, 0x03, 0x08, 0x0a, 0x09, 0x00,
0x09, 0x35, 0x08, 0x35, 0x06, 0x19, 0x11, 0x1e,
0x09, 0x01, 0x01, 0x09, 0x01, 0x00, 0x25, 0x0d,
0x56, 0x6f, 0x69, 0x63, 0x65, 0x20, 0x47, 0x61,
0x74, 0x65, 0x77, 0x61, 0x79, 0x09, 0x03, 0x01,
0x08, 0x01, 0x09, 0x03, 0x11, 0x09, 0x00, 0x00
};
#define SDP_HF_CHANNEL_OFFSET 29
#define SDP_HF_CAPABILITY_OFFSET 71
CAGService::CAGService()
{
m_hThread = NULL;
m_sockServer[0] = INVALID_SOCKET;
m_sockServer[1] = INVALID_SOCKET;
m_fShutdown = FALSE;
m_SDPRecordHS = 0;
m_SDPRecordHF = 0;
}
// This method initializes the AG
DWORD CAGService::Init(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
WSADATA wsd;
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Initializing Audio Gateway Service.\n"));
g_pAGEngine = &m_AGEngine;
svsutil_Initialize();
dwRetVal = WSAStartup(MAKEWORD(1,0), &wsd);
return dwRetVal;
}
// This method deinitializes the AG
void CAGService::Deinit(void)
{
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Deinitializing Audio Gateway Service.\n"));
WSACleanup();
svsutil_DeInitialize();
g_pAGEngine = NULL;
}
// This method starts the AG
DWORD CAGService::Start(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
AG_PROPS AGProps;
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Starting Audio Gateway Service.\n"));
Lock();
m_fShutdown = FALSE;
(void) m_ATParser.Init();
dwRetVal = m_AGEngine.Init(&m_ATParser);
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error initializing AG engine: %d.\n", dwRetVal));
goto exit;
}
(void) LoadAGState();
m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (! m_hCloseEvent) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error creating close event: %d.\n", dwRetVal));
goto exit;
}
m_hThread = CreateThread(NULL, 0, ListenThread, this, 0, NULL);
if (! m_hThread) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error creating ListenThread: %d.\n", dwRetVal));
goto exit;
}
m_AGEngine.GetAGProps(&AGProps);
m_hScoThread = CreateThread(NULL, 0, SCOListenThread, this, 0, NULL);
if (! m_hScoThread) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error creating SCOListenThread: %d.\n", dwRetVal));
goto exit;
}
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Audio Gateway Service started successfully.\n"));
exit:
Unlock();
if (ERROR_SUCCESS != dwRetVal) {
Stop();
}
return dwRetVal;
}
// This method stops the AG
void CAGService::Stop(void)
{
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Stopping Audio Gateway Service.\n"));
Lock();
SaveAGState();
HANDLE h1 = m_hThread;
HANDLE h2 = m_hScoThread;
m_hThread = NULL;
m_hScoThread = NULL;
m_fShutdown = TRUE;
if (INVALID_SOCKET != m_sockServer[0]) {
closesocket(m_sockServer[0]);
m_sockServer[0] = INVALID_SOCKET;
}
if (INVALID_SOCKET != m_sockServer[1]) {
closesocket(m_sockServer[1]);
m_sockServer[1] = INVALID_SOCKET;
}
if (m_hCloseEvent) {
SetEvent(m_hCloseEvent);
}
m_AGEngine.Deinit();
m_ATParser.Deinit();
Unlock();
if (h1) {
if (h1 != (HANDLE) GetCurrentThreadId()) {
WaitForSingleObject(h1, INFINITE);
}
CloseHandle(h1);
}
if (h2) {
if (h2 != (HANDLE) GetCurrentThreadId()) {
WaitForSingleObject(h2, INFINITE);
}
CloseHandle(h2);
}
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Audio Gateway Service stopped.\n"));
}
// This method opens an audio session on the headset
DWORD CAGService::OpenAudio(void)
{
DWORD dwRetVal;
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Opening Bluetooth audio connection.\n"));
Lock();
dwRetVal = m_AGEngine.OpenAGConnection(TRUE, FALSE);
if ((ERROR_SUCCESS != dwRetVal) && (ERROR_ALREADY_INITIALIZED != dwRetVal)) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error opening AG Connection: %d.\n", dwRetVal));
goto exit;
}
dwRetVal = ERROR_SUCCESS;
exit:
Unlock();
return dwRetVal;
}
// This method closes an audio session on the headset
DWORD CAGService::CloseAudio(void)
{
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Closing Bluetooth audio connection.\n"));
Lock();
m_AGEngine.CloseAGConnection(FALSE);
Unlock();
return ERROR_SUCCESS;
}
// This method opens the control connection
DWORD CAGService::OpenControlConnection(BOOL fFirstOnly)
{
DWORD dwRetVal;
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Opening Bluetooth control connection.\n"));
Lock();
dwRetVal = m_AGEngine.OpenAGConnection(FALSE, fFirstOnly);
if ((ERROR_SUCCESS != dwRetVal) && (ERROR_ALREADY_INITIALIZED != dwRetVal)) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error opening AG Connection: %d.\n", dwRetVal));
goto exit;
}
dwRetVal = ERROR_SUCCESS;
exit:
Unlock();
return dwRetVal;
}
// This method opens the control connection
DWORD CAGService::CloseControlConnection(void)
{
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Closing Bluetooth control connection.\n"));
Lock();
m_AGEngine.CloseAGConnection(TRUE);
Unlock();
return ERROR_SUCCESS;
}
// This method sets the speaker volume of the peer
DWORD CAGService::SetSpeakerVolume(unsigned short usVolume)
{
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Setting Bluetooth audio speaker volume.\n"));
if (usVolume <= 15) {
Lock();
m_AGEngine.SetSpeakerVolume(usVolume);
Unlock();
return ERROR_SUCCESS;
}
return ERROR_INVALID_PARAMETER;
}
// This method sets the mic volume of the peer
DWORD CAGService::SetMicVolume(unsigned short usVolume)
{
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Setting Bluetooth audio microphone volume.\n"));
if (usVolume <= 15) {
Lock();
m_AGEngine.SetMicVolume(usVolume);
Unlock();
return ERROR_SUCCESS;
}
return ERROR_INVALID_PARAMETER;
}
// This method gets the speaker volume of the peer
DWORD CAGService::GetSpeakerVolume(unsigned short* pusVolume)
{
AG_PROPS AGProps;
Lock();
m_AGEngine.GetAGProps(&AGProps);
*pusVolume = AGProps.usSpeakerVolume;
Unlock();
return ERROR_SUCCESS;
}
// This method gets the mic volume of the peer
DWORD CAGService::GetMicVolume(unsigned short* pusVolume)
{
AG_PROPS AGProps;
Lock();
m_AGEngine.GetAGProps(&AGProps);
*pusVolume = AGProps.usMicVolume;
Unlock();
return ERROR_SUCCESS;
}
// Get the power-save mode
DWORD CAGService::GetPowerMode(BOOL* pfPowerSave)
{
AG_PROPS AGProps;
Lock();
m_AGEngine.GetAGProps(&AGProps);
*pfPowerSave = AGProps.fPowerSave;
Unlock();
return ERROR_SUCCESS;
}
// Get the power-save mode
DWORD CAGService::SetPowerMode(BOOL fPowerSave)
{
AG_PROPS AGProps;
Lock();
m_AGEngine.GetAGProps(&AGProps);
if (AGProps.fPowerSave != fPowerSave) {
AGProps.fPowerSave = fPowerSave;
m_AGEngine.SetAGProps(&AGProps);
SaveAGState();
}
Unlock();
return ERROR_SUCCESS;
}
// AG server thread
DWORD WINAPI CAGService::ListenThread(LPVOID pv)
{
CAGService* pInst = (CAGService*)pv;
pInst->ListenThread_Int();
return 0;
}
// This method listens for incoming connections to the AG
void CAGService::ListenThread_Int(void)
{
SOCKADDR_BTH saServer;
int iLen;
int on = TRUE;
AG_PROPS AGProps;
BOOL fStackUp = FALSE;
BOOL fHandsfree;
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: ++ListenThread_Int\n"));
Lock();
// Make sure BT stack is up
for (int i = 0 ; i < 100 ; ++i) {
HANDLE hBthStackInited = OpenEvent (EVENT_ALL_ACCESS, FALSE, BTH_NAMEDEVENT_STACK_INITED);
if (hBthStackInited) {
DWORD dwRes = WaitForSingleObject (hBthStackInited, INFINITE);
CloseHandle (hBthStackInited);
if (WAIT_OBJECT_0 == dwRes) {
fStackUp = TRUE;
break;
}
}
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: BT stack is not ready, waiting...\n"));
Sleep (1000);
}
if (! fStackUp) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Bluetooth stack is not up - aborting ListenThread_Int: %d.\n", GetLastError()));
goto exit;
}
m_AGEngine.GetAGProps(&AGProps);
fHandsfree = ! AGProps.fNoHandsfree;
// Create headset and hands-free sockets
m_sockServer[0] = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if (INVALID_SOCKET == m_sockServer[0]) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error opening socket: %d.\n", GetLastError()));
goto exit;
}
if (fHandsfree) {
m_sockServer[1] = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if (INVALID_SOCKET == m_sockServer[1]) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error opening socket: %d.\n", GetLastError()));
goto exit;
}
}
// Bind headset socket and add SDP record
memset(&saServer, 0, sizeof(saServer));
saServer.addressFamily = AF_BTH;
if (0 != bind(m_sockServer[0], (SOCKADDR*)&saServer, sizeof(saServer))) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error calling bind: %d.\n", GetLastError()));
goto exit;
}
iLen = sizeof(saServer);
if (SOCKET_ERROR == getsockname(m_sockServer[0], (SOCKADDR*)&saServer, &iLen)) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error calling getsockname: %d.\n", GetLastError()));
goto exit;
}
if (ERROR_SUCCESS != AddSDPRecord(rgbSdpRecordHeadsetHS, SDP_HS_RECORD_SIZE, SDP_HS_CHANNEL_OFFSET, saServer.port, &m_SDPRecordHS)) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error adding headset SDP record.\n"));
goto exit;
}
// Bind hands-free socket and add SDP record
if (fHandsfree) {
memset(&saServer, 0, sizeof(saServer));
saServer.addressFamily = AF_BTH;
if (0 != bind(m_sockServer[1], (SOCKADDR*)&saServer, sizeof(saServer))) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error calling bind: %d.\n", GetLastError()));
goto exit;
}
iLen = sizeof(saServer);
if (SOCKET_ERROR == getsockname(m_sockServer[1], (SOCKADDR*)&saServer, &iLen)) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error calling getsockname: %d.\n", GetLastError()));
goto exit;
}
rgbSdpRecordHeadsetHF[SDP_HF_CAPABILITY_OFFSET] = (BYTE) AGProps.usHFCapability;
if (ERROR_SUCCESS != AddSDPRecord(rgbSdpRecordHeadsetHF, SDP_HF_RECORD_SIZE, SDP_HF_CHANNEL_OFFSET, saServer.port, &m_SDPRecordHF)) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error adding hands-free SDP record.\n"));
goto exit;
}
}
// Continue setting up sockets
listen(m_sockServer[0], 2);
if (fHandsfree) {
listen(m_sockServer[1], 2);
}
m_AGEngine.GetAGProps(&AGProps);
if (AGProps.fAuth) {
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: Setting SO_BTH_AUTHENTICATE on server socket.\n"));
setsockopt(m_sockServer[0], SOL_RFCOMM, SO_BTH_AUTHENTICATE, (char *)&on, sizeof(on));
if (fHandsfree) {
setsockopt(m_sockServer[1], SOL_RFCOMM, SO_BTH_AUTHENTICATE, (char *)&on, sizeof(on));
}
}
if (AGProps.fEncrypt) {
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: Setting SO_BTH_ENCRYPT on server socket.\n"));
setsockopt(m_sockServer[0], SOL_RFCOMM, SO_BTH_ENCRYPT, (char *)&on, sizeof(on));
if (fHandsfree) {
setsockopt(m_sockServer[1], SOL_RFCOMM, SO_BTH_ENCRYPT, (char *)&on, sizeof(on));
}
}
while (1) {
SOCKADDR_BTH saClient;
SOCKET sockClient;
BOOL fHFSupport = FALSE;
fd_set sockSet;
FD_ZERO(&sockSet);
FD_SET(m_sockServer[0], &sockSet);
if (fHandsfree) {
FD_SET(m_sockServer[1], &sockSet);
}
Unlock();
int iSockets = select(0,&sockSet,NULL,NULL,NULL);
Lock();
if (m_fShutdown || (0 == iSockets) || (SOCKET_ERROR == iSockets)) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error in call to select: %d\n", GetLastError()));
goto exit;
}
SOCKET s = sockSet.fd_array[iSockets - 1];
if (fHandsfree && (s == m_sockServer[1])) {
// Peer device supports HFP
fHFSupport = TRUE;
}
iLen = sizeof(saClient);
sockClient = accept(s, (SOCKADDR*)&saClient, &iLen);
if (INVALID_SOCKET == sockClient) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error in call to accept, breaking... - error:%d\n", GetLastError()));
goto exit;
}
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: A Bluetooth peer device has connected to the Audio Gateway.\n"));
if (!m_AGEngine.FindBTAddrInList(saClient.btAddr)) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: The peer device was not accepted since the user has never confirmed it as a device to be used.\n"));
closesocket(sockClient);
continue;
}
m_AGEngine.GetAGProps(&AGProps);
if (AGProps.btAddrClient && (AGProps.btAddrClient != saClient.btAddr)) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: The peer device was not accepted since we already have an active connection.\n"));
closesocket(sockClient);
continue;
}
(void) m_AGEngine.SetBTAddrList(saClient.btAddr, fHFSupport); // ignore return value in this case
if (ERROR_SUCCESS != m_AGEngine.NotifyConnect(sockClient, fHFSupport)) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: The AG Engine did not accept the connection to the device.\n"));
closesocket(sockClient);
continue;
}
}
exit:
if (m_SDPRecordHF) {
RemoveSDPRecord(&m_SDPRecordHF);
}
if (m_SDPRecordHS) {
RemoveSDPRecord(&m_SDPRecordHS);
}
g_dwState = SERVICE_STATE_OFF;
Unlock();
if (! m_fShutdown) {
Stop();
}
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: --ListenThread_Int\n"));
}
// AG SCO Server Thread
DWORD WINAPI CAGService::SCOListenThread(LPVOID pv)
{
CAGService* pInst = (CAGService*)pv;
pInst->SCOListenThread_Int();
return 0;
}
// This method listens for incoming SCO connections to the AG
void CAGService::SCOListenThread_Int(void)
{
DWORD dwErr = ERROR_SUCCESS;
AG_PROPS AGProps;
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: ++SCOListenThread_Int\n"));
Lock();
m_AGEngine.GetAGProps(&AGProps);
if (AGProps.fPCMMode) {
dwErr = BthAcceptSCOConnections(TRUE);
}
if (ERROR_SUCCESS == dwErr) {
HANDLE hBTConnect = OpenEvent(EVENT_ALL_ACCESS, FALSE, L"system/events/bluetooth/ConnectionsChange");
if (hBTConnect) {
HANDLE h[2];
DWORD dwWait;
h[0] = hBTConnect;
h[1] = m_hCloseEvent;
while (1) {
Unlock();
dwWait = WaitForMultipleObjects(2, h, FALSE, INFINITE);
Lock();
if (dwWait != WAIT_OBJECT_0) {
break;
}
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: SCOListenThread_Int - Connection Event.\n"));
m_AGEngine.ConnectionEvent();
}
}
else {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: SCOListenThread_Int: Error opening named event: %d\n", dwErr));
}
if (AGProps.fPCMMode) {
BthAcceptSCOConnections(FALSE);
}
}
else {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: SCOListenThread_Int: Error accepting SCO connections: %d\n", dwErr));
}
Unlock();
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: --SCOListenThread_Int\n"));
}
// This method loads AG settings
DWORD CAGService::LoadAGState(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
DWORD cdwBytes = 0;
DWORD dwData = 0;
HKEY hk = NULL;
AG_PROPS AGProps;
m_AGEngine.GetAGProps(&AGProps);
dwRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY, 0, 0, &hk);
if (dwRetVal != ERROR_SUCCESS) {
goto exit;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("MapAudioToPcmMode"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.fPCMMode = dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("MicVolume"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.usMicVolume = (USHORT) dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("SpkVolume"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.usSpeakerVolume = (USHORT) dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("Authenticate"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.fAuth = dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("Enrypt"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.fEncrypt = dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("NoHandsfree"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.fNoHandsfree = dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("PowerSave"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.fPowerSave = dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("Capability"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.usHFCapability = (USHORT) dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("PageTimeout"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.usPageTimeout = (USHORT) dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("SniffDelay"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.ulSniffDelay = (ULONG) dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("SniffMax"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.usSniffMax = (USHORT) dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("SniffMin"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.usSniffMin = (USHORT) dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("SniffAttempt"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.usSniffAttempt = (USHORT) dwData;
}
cdwBytes = sizeof(dwData);
if (ERROR_SUCCESS == RegQueryValueEx(hk, _T("SniffTimeout"), 0, NULL, (PBYTE)&dwData, &cdwBytes)) {
AGProps.usSniffTimeout = (USHORT) dwData;
}
RegCloseKey(hk);
m_AGEngine.SetAGProps(&AGProps);
exit:
return dwRetVal;
}
// This method saves AG settings
DWORD CAGService::SaveAGState(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
DWORD dwDisp = 0;
DWORD dwData = 0;
HKEY hk = NULL;
AG_PROPS AGProps;
dwRetVal = RegCreateKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY, 0, NULL, 0, NULL, NULL, &hk, &dwDisp);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
m_AGEngine.GetAGProps(&AGProps);
dwData = AGProps.usMicVolume;
dwRetVal = RegSetValueEx(hk, _T("MicVolume"), 0, REG_DWORD, (PBYTE)&dwData, sizeof(dwData));
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
dwData = AGProps.usSpeakerVolume;
dwRetVal = RegSetValueEx(hk, _T("SpkVolume"), 0, REG_DWORD, (PBYTE)&dwData, sizeof(dwData));
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
dwData = AGProps.fPowerSave;
dwRetVal = RegSetValueEx(hk, _T("PowerSave"), 0, REG_DWORD, (PBYTE)&dwData, sizeof(dwData));
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
exit:
if (hk) {
RegCloseKey(hk);
}
return dwRetVal;
}
// This method adds an SDP record
DWORD CAGService::AddSDPRecord(PBYTE rbgSdpRecord, DWORD cbSdpRecord, DWORD dwChannelOffset, unsigned long ulPort, unsigned long* pSdpRecord)
{
DWORD dwRetVal = ERROR_SUCCESS;
DWORD dwSizeOut = 0;
struct {
BTHNS_SETBLOB b;
unsigned char uca[MAX_SDP_RECORD_SIZE];
} bigBlob;
ULONG ulSdpVersion = BTH_SDP_VERSION;
*pSdpRecord = 0;
bigBlob.b.pRecordHandle = pSdpRecord;
bigBlob.b.pSdpVersion = &ulSdpVersion;
bigBlob.b.fSecurity = 0;
bigBlob.b.fOptions = 0;
bigBlob.b.ulRecordLength = cbSdpRecord;
memcpy(bigBlob.b.pRecord, rbgSdpRecord, cbSdpRecord);
bigBlob.b.pRecord[dwChannelOffset] = (unsigned char)ulPort;
BLOB blob;
blob.cbSize = sizeof(BTHNS_SETBLOB) + cbSdpRecord - 1;
blob.pBlobData = (PBYTE) &bigBlob;
WSAQUERYSET Service;
memset(&Service, 0, sizeof(Service));
Service.dwSize = sizeof(Service);
Service.lpBlob = &blob;
Service.dwNameSpace = NS_BTH;
dwRetVal = WSASetService(&Service, RNRSERVICE_REGISTER, 0);
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error adding SDP record.\n"));
goto exit;
}
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: Successfully added SDP record.\n"));
exit:
return dwRetVal;
}
// This method removes an SDP record
DWORD CAGService::RemoveSDPRecord(unsigned long* pSdpRecord)
{
DWORD dwRetVal = ERROR_SUCCESS;
ULONG ulSdpVersion = BTH_SDP_VERSION;
BTHNS_SETBLOB delBlob;
memset(&delBlob, 0, sizeof(delBlob));
delBlob.pRecordHandle = pSdpRecord;
delBlob.pSdpVersion = &ulSdpVersion;
BLOB blob;
blob.cbSize = sizeof(BTHNS_SETBLOB);
blob.pBlobData = (PBYTE) &delBlob;
WSAQUERYSET Service;
memset(&Service, 0, sizeof(Service));
Service.dwSize = sizeof(Service);
Service.lpBlob = &blob;
Service.dwNameSpace = NS_BTH;
dwRetVal = WSASetService(&Service, RNRSERVICE_DELETE, 0);
*pSdpRecord = 0;
#ifdef DEBUG
if (ERROR_SUCCESS == dwRetVal) {
DEBUGMSG(ZONE_SERVICE, (L"BTAGSVC: Successfully removed SDP record.\n"));
}
#endif // DEBUG
return dwRetVal;
}