📄 headsetctl.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 <commctrl.h>
#include "resource.h"
#include "utils.h"
#include "btaudiogw.h"
#define WM_HS_ANSWERED (WM_USER + 105)
#define WM_HS_NOANSWER (WM_USER + 106)
void OnStartHeadset(HWND hwndDlg);
void OnStopHeadset(HWND hwndDlg);
// Global data
HINSTANCE g_hAudioGW;
BOOL g_fActiveConnection;
DWORD g_dwSpkVolCache = -1;
DWORD g_dwMicVolCache = -1;
// Audio gateway functions
PFN_BthInitializeAudioGateway g_pfnInitAG;
PFN_BthUninitializeAudioGateway g_pfnUninitAG;
PFN_BthCreateHeadsetConnection g_pfnCreateHeadsetConnection;
PFN_BthCloseHeadsetConnection g_pfnCloseHeadsetConnection;
PFN_BthRingHeadset g_pfnRingHeadset;
PFN_BthStopRingingHeadset g_pfnStopRingingHeadset;
PFN_BthSetHeadsetEvents g_pfnSetHeadsetEvents;
PFN_BthSetHeadsetSpkVolume g_pfnSetSpkVolume;
PFN_BthGetHeadsetSpkVolume g_pfnGetSpkVolume;
PFN_BthSetHeadsetMicVolume g_pfnSetMicVolume;
PFN_BthGetHeadsetMicVolume g_pfnGetMicVolume;
// Audio gateway events
HANDLE g_hHSCloseEvent;
HANDLE g_hHSSpkVolEvent;
HANDLE g_hHSMicVolEvent;
// Load the audio gateway dll and get proc addresses
DWORD LoadAudioGW(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
g_hAudioGW = LoadLibrary(_T("btaudiogw.dll"));
if (! g_hAudioGW) {
OutputMessage(_T("BTHeadset: ***********************************\r\nBTAUDIOGW: ERROR: Could not load btaudiogw.dll!\r\nBTAUDIOGW: ***********************************"));
dwRetVal = GetLastError();
goto exit;
}
g_pfnInitAG = (PFN_BthInitializeAudioGateway) GetProcAddress(g_hAudioGW, _T("BthInitializeAudioGateway"));
g_pfnUninitAG = (PFN_BthUninitializeAudioGateway) GetProcAddress(g_hAudioGW, _T("BthUninitializeAudioGateway"));
g_pfnCreateHeadsetConnection = (PFN_BthCreateHeadsetConnection) GetProcAddress(g_hAudioGW, _T("BthCreateHeadsetConnection"));
g_pfnCloseHeadsetConnection = (PFN_BthCloseHeadsetConnection) GetProcAddress(g_hAudioGW, _T("BthCloseHeadsetConnection"));
g_pfnRingHeadset = (PFN_BthRingHeadset) GetProcAddress(g_hAudioGW, _T("BthRingHeadset"));
g_pfnStopRingingHeadset = (PFN_BthStopRingingHeadset) GetProcAddress(g_hAudioGW, _T("BthStopRingingHeadset"));
g_pfnSetHeadsetEvents = (PFN_BthSetHeadsetEvents) GetProcAddress(g_hAudioGW, _T("BthSetHeadsetEvents"));
g_pfnSetSpkVolume = (PFN_BthSetHeadsetSpkVolume) GetProcAddress(g_hAudioGW, _T("BthSetHeadsetSpkVolume"));
g_pfnGetSpkVolume = (PFN_BthGetHeadsetSpkVolume) GetProcAddress(g_hAudioGW, _T("BthGetHeadsetSpkVolume"));
g_pfnSetMicVolume = (PFN_BthSetHeadsetMicVolume) GetProcAddress(g_hAudioGW, _T("BthSetHeadsetMicVolume"));
g_pfnGetMicVolume = (PFN_BthGetHeadsetMicVolume) GetProcAddress(g_hAudioGW, _T("BthGetHeadsetMicVolume"));
if ((! g_pfnInitAG) || (! g_pfnUninitAG) || (! g_pfnCreateHeadsetConnection) || (! g_pfnCreateHeadsetConnection) || (! g_pfnRingHeadset) ||
(! g_pfnStopRingingHeadset) || (! g_pfnSetHeadsetEvents) || (! g_pfnSetSpkVolume) || (! g_pfnGetSpkVolume) ||
(! g_pfnSetMicVolume) || (! g_pfnGetMicVolume)) {
dwRetVal = GetLastError();
OutputMessage(_T("BTHeadset: Error getting proc address of one or more Audio Gateway functions: %d"), dwRetVal);
goto exit;
}
dwRetVal = g_pfnInitAG();
if (dwRetVal != ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: Error initializing Audio Gateway"));
goto exit;
}
g_hHSCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hHSSpkVolEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hHSMicVolEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if ((! g_hHSCloseEvent) || (! g_hHSCloseEvent) || (! g_hHSCloseEvent)) {
dwRetVal = GetLastError();
OutputMessage(_T("BTHeadset: Error creating headset events: %d"), dwRetVal);
g_pfnUninitAG();
goto exit;
}
dwRetVal = g_pfnSetHeadsetEvents(g_hHSCloseEvent, g_hHSSpkVolEvent, g_hHSMicVolEvent);
if (dwRetVal != ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: Error setting headset events in Audio Gateway: %d"), GetLastError());
g_pfnUninitAG();
goto exit;
}
exit:
if (dwRetVal != ERROR_SUCCESS) {
if (g_hAudioGW) {
FreeLibrary(g_hAudioGW);
}
if (! g_hHSCloseEvent) {
CloseHandle(g_hHSCloseEvent);
}
if (! g_hHSSpkVolEvent) {
CloseHandle(g_hHSSpkVolEvent);
}
if (! g_hHSMicVolEvent) {
CloseHandle(g_hHSMicVolEvent);
}
}
return dwRetVal;
}
// Unload the audio gateway dll
void UnloadAudioGW(void)
{
if (g_pfnSetHeadsetEvents(NULL, NULL, NULL) != ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: Error unregistering headset events"));
}
if (g_pfnUninitAG() != ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: Error uninitializing audio gateway"));
}
FreeLibrary(g_hAudioGW);
g_hAudioGW = NULL;
}
// Called when main dialog is initialized
void OnInitDialog(HWND hwndDlg)
{
HWND hWndSpkVol;
HWND hWndMicVol;
hWndSpkVol = GetDlgItem(hwndDlg, IDC_SPKVOL);
hWndMicVol = GetDlgItem(hwndDlg, IDC_MICVOL);
if ((! hWndSpkVol) || (! hWndMicVol)) {
OutputMessage(_T("BTHeadset: Error - Could not get trackbar controls: %d"), GetLastError());
goto exit;
}
// Set range for volume on trackbars
SendMessage(hWndSpkVol, TBM_SETRANGE, FALSE, MAKELONG(0, 15));
SendMessage(hWndMicVol, TBM_SETRANGE, FALSE, MAKELONG(0, 15));
exit:
return;
}
// Thread which calls the headset and wait for a response
DWORD WINAPI CallHeadsetThread(LPVOID pv)
{
HWND hwndDlg = (HWND) pv;
if (g_pfnRingHeadset() == ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: Started headset"));
PostMessage(hwndDlg, WM_HS_ANSWERED, 0, 0);
}
else {
OutputMessage(_T("BTHeadset: Error starting headset."));
PostMessage(hwndDlg, WM_HS_NOANSWER, 0, 0);
MessageBox(hwndDlg,
_T("An error occured trying to call the headset device."),
_T("Audio Gateway"),
MB_ICONEXCLAMATION | MB_OK);
OnStopHeadset(hwndDlg); // Close the connection
}
SetCursor(LoadCursor(NULL, IDC_ARROW));
return 0;
}
// Update the status message
DWORD UpdateStatusMessage(HWND hwndDlg, TCHAR* szMessage)
{
DWORD dwRetVal = ERROR_SUCCESS;
HWND hwndStatus;
hwndStatus = GetDlgItem(hwndDlg, IDC_STATUS);
if (! hwndStatus) {
OutputMessage(_T("BTHeadset: Error - Could not update status message"));
dwRetVal = GetLastError();
goto exit;
}
SetWindowText(hwndStatus, szMessage);
exit:
return dwRetVal;
}
// Headset Button was pressed to close ACL connection.
void OnHeadsetClose(HWND hwndDlg)
{
HWND hwndStartStop = GetDlgItem(hwndDlg, IDC_STARTSTOP);
g_fActiveConnection = FALSE;
SetWindowText(hwndStartStop, _T("Start"));
UpdateStatusMessage(hwndDlg, _T("Not Connected"));
}
// Update the speaker volume with audio gateway
DWORD UpdateSpeakerVolume(HWND hwndDlg)
{
DWORD dwRetVal = ERROR_SUCCESS;
HWND hwndSpkVol;
dwRetVal = g_pfnGetSpkVolume((USHORT*)&g_dwSpkVolCache);
if (dwRetVal != ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: Error updating speaker volume: %d"), dwRetVal);
goto exit;
}
hwndSpkVol = GetDlgItem(hwndDlg, IDC_SPKVOL);
SendMessage(hwndSpkVol, TBM_SETPOS, TRUE, 15 - g_dwSpkVolCache);
exit:
return dwRetVal;
}
// Update the mic volume with audio gateway
DWORD UpdateMicVolume(HWND hwndDlg)
{
DWORD dwRetVal = ERROR_SUCCESS;
HWND hwndMicVol;
dwRetVal = g_pfnGetMicVolume((USHORT*)&g_dwMicVolCache);
if (dwRetVal != ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: Error updating mic volume: %d"), dwRetVal);
goto exit;
}
hwndMicVol = GetDlgItem(hwndDlg, IDC_MICVOL);
SendMessage(hwndMicVol, TBM_SETPOS, TRUE, 15 - g_dwMicVolCache);
exit:
return dwRetVal;
}
// Speaker volume was adjusted on device
void OnSpeakerVolume(HWND hwndDlg)
{
HWND hwndSpkVol;
DWORD dwPos = 0;
hwndSpkVol = GetDlgItem(hwndDlg, IDC_SPKVOL);
dwPos = 15 - SendMessage(hwndSpkVol, TBM_GETPOS, 0, 0);
if(dwPos != g_dwSpkVolCache) {
if (g_pfnSetSpkVolume((USHORT)(dwPos)) != ERROR_SUCCESS) {
OutputMessage(_T("Error setting speaker volume: %d"), GetLastError());
}
else {
g_dwSpkVolCache = dwPos;
}
}
}
// Mic Volume was adjusted on device
void OnMicVolume(HWND hwndDlg)
{
HWND hwndMicVol;
DWORD dwPos = 0;
hwndMicVol = GetDlgItem(hwndDlg, IDC_MICVOL);
dwPos = 15 - SendMessage(hwndMicVol, TBM_GETPOS, 0, 0);
if (dwPos != g_dwMicVolCache) {
if (g_pfnSetMicVolume((USHORT)(dwPos)) != ERROR_SUCCESS) {
OutputMessage(_T("Error setting mic volume: %d"), GetLastError());
}
else {
g_dwMicVolCache = dwPos;
}
}
}
// User has clicked Start
void OnStartHeadset(HWND hwndDlg)
{
DWORD dwRetVal;
HWND hwndStartStop;
hwndStartStop = GetDlgItem(hwndDlg, IDC_STARTSTOP);
SetCursor(LoadCursor(NULL, IDC_WAIT));
SetWindowText(hwndStartStop, _T("Starting..."));
// Establish SCO Connection
dwRetVal = g_pfnCreateHeadsetConnection(NULL);
if (dwRetVal == ERROR_SUCCESS) {
DWORD dwVol = 0;
if (g_pfnGetSpkVolume((USHORT*)&dwVol) == ERROR_SUCCESS) {
HWND hWndSpk = GetDlgItem(hwndDlg, IDC_SPKVOL);
SendMessage(hWndSpk, TBM_SETPOS, TRUE, (15 - dwVol));
}
if (g_pfnGetMicVolume((USHORT*)&dwVol) == ERROR_SUCCESS) {
HWND hWndMic = GetDlgItem(hwndDlg, IDC_MICVOL);
SendMessage(hWndMic, TBM_SETPOS, TRUE, (15 - dwVol));
}
UpdateStatusMessage(hwndDlg, _T("Calling headset..."));
HANDLE hThread = CreateThread(NULL, 0, CallHeadsetThread, (LPVOID)hwndDlg, 0, NULL);
if (! hThread) {
dwRetVal = GetLastError();
OutputMessage(_T("BTHeadset: Error creating CallHeadsetThread: %d"), dwRetVal);
}
}
if (dwRetVal == ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: ACL connection created successfully"));
SetWindowText(hwndStartStop, _T("Stop"));
g_fActiveConnection = TRUE;
}
else {
SetCursor(LoadCursor(NULL, IDC_ARROW));
SetWindowText(hwndStartStop, _T("Start"));
MessageBox(hwndDlg,
_T("An error occured trying to connect with the headset device."),
_T("Audio Gateway"),
MB_ICONEXCLAMATION | MB_OK);
}
}
// User has clicked Stop
void OnStopHeadset(HWND hwndDlg)
{
DWORD dwRetVal;
HWND hwndStartStop;
hwndStartStop = GetDlgItem(hwndDlg, IDC_STARTSTOP);
SetCursor(LoadCursor(NULL, IDC_WAIT));
SetWindowText(hwndStartStop, _T("Stopping..."));
// Close SCO Connection
dwRetVal = g_pfnCloseHeadsetConnection();
SetCursor(LoadCursor(NULL, IDC_ARROW));
if (dwRetVal == ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: ACL connection closed successfully"));
SetWindowText(hwndStartStop, _T("Start"));
g_fActiveConnection = FALSE;
UpdateStatusMessage(hwndDlg, _T("Not Connected"));
}
else {
SetWindowText(hwndStartStop, _T("Stop"));
MessageBox(hwndDlg,
_T("An error occured trying to disconnect with the headset device."),
_T("Audio Gateway"),
MB_ICONEXCLAMATION | MB_OK);
}
}
// Callback function for main dialog box messages
BOOL CALLBACK MainDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
NMHDR* pnmh;
switch (uMsg) {
case WM_INITDIALOG:
OnInitDialog(hwndDlg);
break;
case WM_HS_ANSWERED:
UpdateStatusMessage(hwndDlg, _T("Connected to headset"));
break;
case WM_HS_NOANSWER:
UpdateStatusMessage(hwndDlg, _T("No answer from headset"));
break;
case WM_NOTIFY:
pnmh = (NMHDR*) lParam;
if (pnmh->idFrom == IDC_SPKVOL) {
OnSpeakerVolume(hwndDlg);
}
else if (pnmh->idFrom == IDC_MICVOL) {
OnMicVolume(hwndDlg);
}
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_STARTSTOP:
if (g_fActiveConnection) {
OnStopHeadset(hwndDlg);
}
else {
OnStartHeadset(hwndDlg);
}
break;
}
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
}
return FALSE;
}
// Application entry point
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
{
DWORD dwRetVal;
BOOL fAGLoaded = FALSE;
MSG msg;
HWND hwndDlg;
HANDLE hEvents[3];
InitCommonControls();
dwRetVal = LoadAudioGW();
if (dwRetVal != ERROR_SUCCESS) {
OutputMessage(_T("BTHeadset: Failed to load Audio Gateway"));
goto exit;
}
fAGLoaded = TRUE;
hwndDlg = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_HEADSET), NULL, MainDialogProc);
if (! hwndDlg) {
OutputMessage(_T("BTHeadset: Failed to create main window: 0x%08x"), GetLastError());
goto exit;
}
hEvents[0] = g_hHSCloseEvent;
hEvents[1] = g_hHSSpkVolEvent;
hEvents[2] = g_hHSMicVolEvent;
while (1) {
while (PeekMessage(&msg, hwndDlg, 0, 0, PM_REMOVE)) {
// If we got a quit, let's exit
if (msg.message == WM_QUIT) {
goto exit;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Check if an event fired.
dwRetVal = MsgWaitForMultipleObjects(3, hEvents, FALSE, INFINITE, QS_ALLINPUT);
if (dwRetVal == WAIT_OBJECT_0) {
OnHeadsetClose(hwndDlg);
}
else if (dwRetVal == WAIT_OBJECT_0 + 1) {
UpdateSpeakerVolume(hwndDlg);
}
else if (dwRetVal == WAIT_OBJECT_0 + 2) {
UpdateMicVolume(hwndDlg);
}
else if (dwRetVal == 0xFFFFFFFF) {
OutputMessage(_T("MsgWaitForMultipleObjects failed with error %d"), GetLastError());
}
}
exit:
if (fAGLoaded) {
UnloadAudioGW();
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -