📄 handler.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 <windows.h>
#include <initguid.h>
#include <bt_sdp.h>
#include "btagpriv.h"
#include "btagnetwork.h"
#ifndef PREFAST_ASSERT
#define PREFAST_ASSERT(x) ASSERT(x)
#endif
#define AT_OK "\r\nOK\r\n"
#define AT_ERROR "\r\nERROR\r\n"
#define AT_VGS "\r\n+VGS=%d\r\n"
#define AT_VGM "\r\n+VGM=%d\r\n"
#define AT_RING "\r\nRING\r\n"
void PhoneExtServiceCallback(BOOL fHaveService);
BOOL IsHandsfreeUUID(const GUID* pGuid)
{
ASSERT(pGuid);
return !memcmp(pGuid, &HandsfreeServiceClass_UUID, sizeof(*pGuid));
}
CAGEngine::CAGEngine(void)
{
}
// This method initializes the AG engine
DWORD CAGEngine::Init(CATParser* pParser)
{
DWORD dwRetVal = ERROR_SUCCESS;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: AG Engine is being initialized.\n"));
Lock();
ASSERT(pParser);
m_pParser = pParser;
m_fExpectHeadsetButton = FALSE;
m_fAudioConnect = FALSE;
m_hSco = 0;
m_hUIThread = NULL;
m_fPhoneExtInited = FALSE;
m_fNetworkInited = FALSE;
m_wszCLI[0] = 0;
m_fCancelCloseConnection = FALSE;
m_CloseCookie = NULL;
m_SniffCookie = NULL;
memset(&m_AGProps, 0, sizeof(AG_PROPS));
m_AGProps.fPCMMode = TRUE;
m_AGProps.usMicVolume = 8;
m_AGProps.usSpeakerVolume = 8;
m_AGProps.fAuth = TRUE;
m_AGProps.fEncrypt = TRUE;
m_AGProps.usHFCapability = DEFAULT_AG_CAPABILITY;
m_AGProps.usPageTimeout = DEFAULT_PAGE_TIMEOUT;
m_AGProps.ulSniffDelay = DEFAULT_SNIFF_DELAY;
m_AGProps.usSniffMax = DEFAULT_SNIFF_MAX;
m_AGProps.usSniffMin = DEFAULT_SNIFF_MIN;
m_AGProps.usSniffAttempt = DEFAULT_SNIFF_ATTEMPT;
m_AGProps.usSniffTimeout = DEFAULT_SNIFF_TO;
m_pTP = new SVSThreadPool(2);
if (! m_pTP) {
Unlock();
return ERROR_OUTOFMEMORY;
}
DWORD dwErr = BthAGNetworkInit(g_hInstance);
if (ERROR_SUCCESS != dwErr) {
// This is not a critical failure, continue to load service.
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Error initializing network module: %d.\n", dwErr));
}
else {
m_fNetworkInited = TRUE;
}
dwErr = BthAGPhoneExtInit();
if (ERROR_SUCCESS != dwErr) {
// This is not a critical failure, continue to load service.
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Error initializing PhoneExt module: %d.\n", dwErr));
}
else {
m_fPhoneExtInited = TRUE;
}
Unlock();
if (ERROR_SUCCESS != BthAGSetServiceCallback(PhoneExtServiceCallback)) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Error setting service callback in PhoneExt.\n"));
}
return dwRetVal;
}
// This method deinitializes the AG engine
void CAGEngine::Deinit(void)
{
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: AG Engine is being de-initialized.\n"));
Lock();
if (m_pParser) {
CloseAudioChannel();
CloseControlChannel();
if (m_fPhoneExtInited) {
BthAGPhoneExtDeinit();
}
if (m_fNetworkInited) {
BthAGNetworkDeinit();
}
delete m_pTP;
m_pTP = NULL;
memset(&m_AGProps, 0, sizeof(AG_PROPS));
m_pParser = NULL;
while (GetRefCount() > 1) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Sleeping while AGEngine ref count is still active.\n"));
Unlock();
Sleep(500);
Lock();
}
}
Unlock();
}
//
// This function gets the list of HF devices from the registry
//
DWORD GetBTAddrList(AG_DEVICE* pDevices, const USHORT usNumDevices)
{
DWORD dwRetVal = ERROR_SUCCESS;
HKEY hk = NULL;
int dwIdx = 0;
WCHAR szName[MAX_PATH];
DWORD cchName = ARRAY_SIZE(szName);
ASSERT(pDevices && usNumDevices);
// Clear the current list
memset(pDevices, 0, usNumDevices*sizeof(pDevices[0]));
dwRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY_DEVICES, 0, 0, &hk);
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Could not open registry key for BT Addr: %d.\n", dwRetVal));
goto exit;
}
// Enumerate devices in registry
while (ERROR_SUCCESS == RegEnumKeyEx(hk, dwIdx, szName, &cchName, NULL, NULL, NULL, NULL)) {
HKEY hkAddr;
BT_ADDR btAddr = 0;
GUID service;
DWORD cdwSize;
DWORD dwErr = RegOpenKeyEx(hk, szName, 0, 0, &hkAddr);
if (ERROR_SUCCESS != dwErr) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Could not open registry key for BT Addr: %d.\n", dwRetVal));
break;
}
cdwSize = sizeof(btAddr);
dwErr = RegQueryValueEx(hkAddr, L"Address", NULL, NULL, (PBYTE)&btAddr, &cdwSize);
if (dwErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Could not query registry value for BT Addr: %d.\n", dwErr));
RegCloseKey(hkAddr);
break;
}
cdwSize = sizeof(service);
dwErr = RegQueryValueEx(hkAddr, L"Service", NULL, NULL, (PBYTE)&service, &cdwSize);
if (dwErr != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Could not query registry value for service: %d.\n", dwErr));
RegCloseKey(hkAddr);
break;
}
RegCloseKey(hkAddr);
WCHAR* p;
int iDeviceIdx = wcstol(szName, &p, 10);
if (btAddr != 0 && ((iDeviceIdx >= 1) || (iDeviceIdx <= usNumDevices))) {
DEBUGMSG(ZONE_OUTPUT, (L"BTAGSVC: Setting btAddr at index %d to %04x%08x.\n", iDeviceIdx, GET_NAP(btAddr), GET_SAP(btAddr)));
pDevices[iDeviceIdx-1].bta = btAddr;
memcpy(&pDevices[iDeviceIdx-1].service, &service, sizeof(GUID));
}
cchName = ARRAY_SIZE(szName);
dwIdx++;
}
RegCloseKey(hk);
exit:
return dwRetVal;
}
BOOL CAGEngine::FindBTAddrInList(const BT_ADDR btaSearch)
{
BOOL fRetVal = FALSE;
Lock();
GetBTAddrList(m_AGProps.DeviceList, ARRAY_SIZE(m_AGProps.DeviceList)); // Update from registry
// Loop through list until we find the address
int i = 0;
while ((i < ARRAY_SIZE(m_AGProps.DeviceList)) && (btaSearch != m_AGProps.DeviceList[i].bta)) {
i++;
}
if (i < ARRAY_SIZE(m_AGProps.DeviceList)) {
fRetVal = TRUE;
}
Unlock();
return fRetVal;
}
// This method writes the address list back to the registry
// sets the parameter btAddrDefault at the top of the list
// and as the active device.
DWORD CAGEngine::SetBTAddrList(BT_ADDR btAddrDefault, BOOL fHfSupport)
{
DWORD dwRetVal = ERROR_SUCCESS;
DWORD dwDis = 0;
HKEY hk = NULL;
Lock();
GetBTAddrList(m_AGProps.DeviceList, ARRAY_SIZE(m_AGProps.DeviceList)); // Update from registry
m_AGProps.btAddrClient = btAddrDefault;
// Loop through list until we find the address
int i = 0;
while ((i < ARRAY_SIZE(m_AGProps.DeviceList)) && (btAddrDefault != m_AGProps.DeviceList[i].bta)) {
i++;
}
if (i > 0) {
GUID service;
if (i == ARRAY_SIZE(m_AGProps.DeviceList)) {
// This is a very unlikely scenario. We get a connection request after pairing
// with the device but before SDP is done.
service = fHfSupport ? HandsfreeServiceClass_UUID : HeadsetServiceClass_UUID;
}
else {
service = m_AGProps.DeviceList[i].service;
}
memmove(&m_AGProps.DeviceList[1], m_AGProps.DeviceList, i*sizeof(AG_DEVICE));
m_AGProps.DeviceList[0].bta = btAddrDefault;
m_AGProps.DeviceList[0].service = service;
}
// Write the list back to the registry
dwRetVal = RegCreateKeyEx(HKEY_LOCAL_MACHINE, RK_AUDIO_GATEWAY_DEVICES, 0, NULL, 0, NULL, NULL, &hk, &dwDis);
if (ERROR_SUCCESS == dwRetVal) {
int dwIdx = 0;
DWORD cbName = MAX_PATH;
while ((dwIdx < ARRAY_SIZE(m_AGProps.DeviceList)) && m_AGProps.DeviceList[dwIdx].bta != 0) {
HKEY hkAddr;
WCHAR wszIdx[10];
_itow(dwIdx+1, wszIdx, 10);
dwDis = 0;
DWORD dwErr = RegCreateKeyEx(hk, wszIdx, 0, NULL, 0, NULL, NULL, &hkAddr, &dwDis);
if (ERROR_SUCCESS != dwErr) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Could not open registry key for BT Addr: %d.\n", dwRetVal));
break;
}
dwErr = RegSetValueEx(hkAddr, L"Address", NULL, REG_BINARY, (PBYTE)&m_AGProps.DeviceList[dwIdx].bta, sizeof(BT_ADDR));
if (dwErr != ERROR_SUCCESS) {
RegCloseKey(hkAddr);
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Could not set registry value for BT Addr: %d.\n", dwErr));
break;
}
dwErr = RegSetValueEx(hkAddr, L"Service", NULL, REG_BINARY, (PBYTE)&m_AGProps.DeviceList[dwIdx].service, sizeof(GUID));
if (dwErr != ERROR_SUCCESS) {
RegCloseKey(hkAddr);
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Could not set registry value for service: %d.\n", dwErr));
break;
}
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Saving to registry btAddr %04x%08x at index %d.\n", GET_NAP(m_AGProps.DeviceList[dwIdx].bta), GET_SAP(m_AGProps.DeviceList[dwIdx].bta), dwIdx+1));
RegCloseKey(hkAddr);
dwIdx++;
}
RegCloseKey (hk);
}
Unlock();
return dwRetVal;
}
// This method notifies the AG Engine that a connection has been made with a peer
DWORD CAGEngine::NotifyConnect(SOCKET sockClient, BOOL fHFSupport)
{
DWORD dwRetVal = ERROR_SUCCESS;
Lock();
if (m_AGProps.state >= AG_STATE_CONNECTED) {
dwRetVal = ERROR_ALREADY_INITIALIZED;
goto exit;
}
m_AGProps.state = AG_STATE_CONNECTING;
if (m_pParser) {
dwRetVal = m_pParser->Start(this, sockClient);
}
else {
dwRetVal = ERROR_NOT_READY;
}
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error starting parser module: %d\n", dwRetVal));
goto exit;
}
ASSERT(INVALID_SOCKET != sockClient);
m_sockClient = sockClient;
AddRef();
Unlock();
BthAGPhoneExtEvent(AG_PHONE_EVENT_BT_CTRL, 1, NULL);
Lock();
DelRef();
m_fAudioConnect = FALSE;
m_AGProps.fHandsfree = fHFSupport;
if (!m_AGProps.fHandsfree) {
// For headset devices, connect audio after we have made
// an RFCOMM connection.
m_fExpectHeadsetButton = TRUE;
m_AGProps.state = AG_STATE_CONNECTED;
dwRetVal = OpenAudioChannel();
}
exit:
if (ERROR_SUCCESS != dwRetVal) {
CloseControlChannel();
}
Unlock();
return dwRetVal;
}
// This method is called when a connection event occurs
void CAGEngine::ConnectionEvent(void)
{
BASEBAND_CONNECTION connections[5];
int cConnectionsIn = 5;
int cConnectionsOut = 0;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: ConnectionEvent.\n"));
//
// Ensure SCO is in the correct state
//
Lock();
BASEBAND_CONNECTION* pConnections = connections;
int iErr;
do {
if (cConnectionsOut > cConnectionsIn) {
if (pConnections != connections)
delete[] pConnections;
pConnections = new BASEBAND_CONNECTION[cConnectionsOut];
if (! pConnections) {
break;
}
cConnectionsIn = cConnectionsOut;
}
iErr = BthGetBasebandConnections(cConnectionsIn, pConnections, &cConnectionsOut);
} while (ERROR_INSUFFICIENT_BUFFER == iErr);
if (ERROR_SUCCESS == iErr) {
BOOL fScoPresent = FALSE;
for (int i = 0; i < cConnectionsOut; i++) {
if ((pConnections[i].baAddress == m_AGProps.btAddrClient) &&
(0 == pConnections[i].fLinkType) &&
(m_AGProps.state >= AG_STATE_CONNECTED)
) {
// SCO link with same address as ACL connection
NotifySCOConnect(pConnections[i].hConnection);
fScoPresent = TRUE;
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -