📄 btaudiogw.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
#include <windows.h>
#include "svsutil.hxx"
#include <bt_api.h>
#include "device.h"
#include "btagw_dbg.h"
#include "btagw_reg.h"
#define MAX_VOL 15
#define MIN_VOL 0
#define RING_TIMEOUT 3000
// Global Data
CRITICAL_SECTION g_csData;
USHORT g_usSpkVol;
USHORT g_usMicVol;
DWORD g_dwAGState;
HANDLE g_hHeadset;
HANDLE g_hRingStopEvent;
HANDLE g_hCloseEvent;
HANDLE g_hSpkVolEvent;
HANDLE g_hMicVolEvent;
HANDLE g_hRingAnswerEvent;
PFN_BTH_ATCMD_CALLBACK g_pfnATCmdCallback;
BOOL g_fPcmMode;
BT_ADDR g_btaddr;
unsigned short g_hSco;
#ifdef DEBUG
DBGPARAM dpCurSettings =
{
TEXT("BTAUDIOGW"),
{
TEXT("Output"),
TEXT("Events"),
TEXT("Packets"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Undefined"),
TEXT("Warning"),
TEXT("Error")
},
0x0000C000
};
#endif
DWORD LoadAGState(void);
DWORD SaveAGState(void);
DWORD InitSco(void);
DWORD DeinitSco(void);
DWORD GetBDAddr(void);
// Dll Entry point
extern "C" BOOL WINAPI DllMain(HANDLE hInstDll, DWORD dwReason, LPVOID lpvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH) {
DEBUGREGISTER((HINSTANCE)hInstDll);
InitializeCriticalSection(&g_csData);
}
else if (dwReason == DLL_PROCESS_DETACH) {
DeleteCriticalSection(&g_csData);
}
return TRUE;
}
// Initialize the Audio Gateway
extern "C" DWORD BthInitializeAudioGateway(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
EnterCriticalSection(&g_csData);
if (g_dwAGState != AG_UNINITIALIZED) {
dwRetVal = ERROR_ALREADY_INITIALIZED;
SetLastError(dwRetVal);
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: The audio gateway has already been initialized")));
goto exit;
}
g_hRingStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (! g_hRingStopEvent) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error creating stop event for ring thread: %d"), dwRetVal));
goto exit;
}
g_hRingAnswerEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (! g_hRingAnswerEvent) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error creating ring answer event: %d"), dwRetVal));
goto exit;
}
if (LoadAGState() != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARN, (_T("BTAUDIOGW: Warning - could not load state of Audio Gateway on start up")));
}
dwRetVal = InitializeDevice();
if (dwRetVal != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Error initializing device: %d"), dwRetVal));
goto exit;
}
if (g_fPcmMode) {
dwRetVal = GetBDAddr();
if (dwRetVal != ERROR_SUCCESS) {
goto exit;
}
dwRetVal = RegisterBthDevice(g_btaddr, &g_hHeadset);
if (dwRetVal != ERROR_SUCCESS) {
goto exit;
}
}
g_dwAGState = AG_DISCONNECTED;
exit:
if (dwRetVal != ERROR_SUCCESS) {
DeInitializeDevice();
if (g_hRingAnswerEvent) {
CloseHandle(g_hRingAnswerEvent);
g_hRingAnswerEvent = NULL;
}
if (g_hRingStopEvent) {
CloseHandle(g_hRingStopEvent);
g_hRingStopEvent = NULL;
}
}
LeaveCriticalSection(&g_csData);
return dwRetVal;
}
// Uninitialize the Audio Gateway
extern "C" DWORD BthUninitializeAudioGateway(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
EnterCriticalSection(&g_csData);
if (g_dwAGState == AG_UNINITIALIZED) {
dwRetVal = ERROR_NOT_READY;
SetLastError(dwRetVal);
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: The audio gateway has not yet been initialized")));
goto exit;
}
if (SaveAGState() != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARN, (_T("BTAUDIOGW: Warning - could not save state of the Audio Gateway on shutdown")));
}
dwRetVal = DeregisterBthDevice(g_hHeadset);
if (dwRetVal != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARN, (_T("BTAUDIOGW: Warning - could not deregister device")));
}
g_hHeadset = NULL;
DeInitializeDevice();
CloseHandle(g_hRingStopEvent);
CloseHandle(g_hRingAnswerEvent);
g_dwAGState = AG_UNINITIALIZED;
exit:
LeaveCriticalSection(&g_csData);
return TRUE;
}
// Create a connection for the paired device.
extern "C" DWORD BthCreateHeadsetConnection(PFN_BTH_ATCMD_CALLBACK pfnCallback)
{
DWORD dwRetVal;
EnterCriticalSection(&g_csData);
if (g_dwAGState == AG_UNINITIALIZED) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: The audio gateway has not been initialized yet")));
dwRetVal = ERROR_NOT_READY;
SetLastError(dwRetVal);
}
else if (g_dwAGState == AG_CONNECTED) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Already connected to the headset")));
dwRetVal = ERROR_ALREADY_INITIALIZED;
SetLastError(dwRetVal);
}
else if (g_dwAGState == AG_DISCONNECTED) {
dwRetVal = StartDevice();
if (dwRetVal != ERROR_SUCCESS) {
goto exit;
}
g_pfnATCmdCallback = pfnCallback;
g_dwAGState = AG_CONNECTED;
}
exit:
LeaveCriticalSection(&g_csData);
return dwRetVal;
}
// Close the current connection.
extern "C" DWORD BthCloseHeadsetConnection(void)
{
DWORD dwRetVal;
EnterCriticalSection(&g_csData);
if (g_dwAGState == AG_CONNECTED) {
if (g_fPcmMode) {
DeinitSco();
}
dwRetVal = StopDevice();
if (dwRetVal == ERROR_SUCCESS) {
g_dwAGState = AG_DISCONNECTED;
g_pfnATCmdCallback = NULL;
}
}
else {
dwRetVal = ERROR_NOT_CONNECTED;
SetLastError(dwRetVal);
}
LeaveCriticalSection(&g_csData);
return dwRetVal;
}
// Ring the headset until it is answered or preempted by StopRingingHeadset
extern "C" DWORD BthRingHeadset(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
HANDLE hEvents[2];
EnterCriticalSection(&g_csData);
if (g_dwAGState != AG_CONNECTED) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Cannot call StartHeadset before establishing an ACL connection")));
dwRetVal = ERROR_NOT_CONNECTED;
SetLastError(dwRetVal);
goto exit;
}
ResetEvent(g_hRingAnswerEvent);
SetRingingState(TRUE);
hEvents[0] = g_hRingAnswerEvent;
hEvents[1] = g_hRingStopEvent;
// Send RING commands
do {
dwRetVal = SendATCommand(AT_RING, 8);
if (dwRetVal != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: SendATCommand failed with error %d"), dwRetVal));
break;
}
LeaveCriticalSection(&g_csData);
dwRetVal = WaitForMultipleObjects(2, hEvents, FALSE, RING_TIMEOUT);
EnterCriticalSection(&g_csData);
if (g_dwAGState != AG_CONNECTED)
break;
} while (dwRetVal == WAIT_TIMEOUT);
SetRingingState(FALSE);
// Set proper return value;
if (dwRetVal == WAIT_OBJECT_0) {
dwRetVal = ERROR_SUCCESS;
if (g_fPcmMode) {
dwRetVal = InitSco();
if (dwRetVal != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Unable to initialize SCO connection - ACL connection closed")));
goto exit;
}
}
}
else {
DEBUGMSG(ZONE_OUTPUT, (_T("BTAUDIOGW: Ring was not answered by headset and exiting")));
dwRetVal = ERROR_OPERATION_ABORTED;
SetLastError(dwRetVal);
}
exit:
LeaveCriticalSection(&g_csData);
return dwRetVal;
}
// Stops the headset ringing.
extern "C" DWORD BthStopRingingHeadset(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
EnterCriticalSection(&g_csData);
if (g_dwAGState != AG_CONNECTED) {
DEBUGMSG(ZONE_ERROR, (_T("BTAUDIOGW: Cannot call StopHeadset before establishing an ACL connection")));
dwRetVal = ERROR_NOT_CONNECTED;
SetLastError(dwRetVal);
goto exit;
}
SetEvent(g_hRingStopEvent);
exit:
LeaveCriticalSection(&g_csData);
return dwRetVal;
}
// Send a custom AT command to the headset
extern "C" DWORD BthSendHeadsetCommand(char* pszCommand, DWORD cdwBuf)
{
DWORD dwRetVal = ERROR_SUCCESS;
if (! pszCommand) {
dwRetVal = ERROR_INVALID_PARAMETER;
goto exit;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -