📄 handler.cpp
字号:
// TODO: See if we have a built-in audio driver and do switching.
waveOutMessage(0, WODM_BT_SCO_AUDIO_CONTROL, 0, TRUE);
m_AGProps.state = AG_STATE_AUDIO_UP;
AddRef();
Unlock();
BthAGPhoneExtEvent(AG_PHONE_EVENT_BT_AUDIO, 1, NULL);
Lock();
DelRef();
exit:
return dwRetVal;
}
// This private method closes the audio connection to the peer
DWORD CAGEngine::CloseAudioChannel(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: ++CloseAudioChannel\n"));
ASSERT(IsLocked());
if (m_AGProps.state >= AG_STATE_AUDIO_UP) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: CloseAudioChannel - audio is up, closing connection\n"));
waveOutMessage(0, WODM_BT_SCO_AUDIO_CONTROL, 0, FALSE);
// TODO: See if we have a built-in audio driver and do switching.
if (m_AGProps.fPCMMode) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: CloseAudioChannel - Need to close SCO connection in PCM mode\n"));
dwRetVal = BthCloseConnection (m_hSco);
if (dwRetVal != ERROR_SUCCESS) {
DEBUGMSG(ZONE_WARN, (_T("BTAGSVC: Error closing SCO connection: %d\n"), dwRetVal));
}
m_hSco = 0;
}
AddRef();
Unlock();
BthAGPhoneExtEvent(AG_PHONE_EVENT_BT_AUDIO, 0, NULL);
Lock();
DelRef();
m_AGProps.state = AG_STATE_CONNECTED;
// If we have not already scheduled sniff thread and sniff mode is enabled and we
// are connected to a HF device and are persisting HF connections, schedule the
// sniff thread.
if ((! m_SniffCookie) && m_AGProps.ulSniffDelay && m_AGProps.fHandsfree && !m_AGProps.fPowerSave) {
m_SniffCookie = m_pTP->ScheduleEvent(EnterSniffModeThread, (LPVOID)this, m_AGProps.ulSniffDelay);
}
}
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: --CloseAudioChannel\n"));
return dwRetVal;
}
// This method sets the speaker volume for the peer device
void CAGEngine::SetSpeakerVolume(unsigned short usVolume)
{
CHAR szBuf[MAX_SEND_BUF];
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Setting the speaker volume to %d\n", usVolume));
ASSERT(usVolume <= 15);
Lock();
m_AGProps.usSpeakerVolume = usVolume;
if (m_AGProps.state >= AG_STATE_CONNECTING) {
int cbBuf = _snprintf(szBuf, MAX_SEND_BUF-1, AT_VGS, usVolume);
szBuf[MAX_SEND_BUF-1]='\0';
if (cbBuf > 0) {
SendATCommand(szBuf, cbBuf);
}
}
Unlock();
}
// This method sets the mic volume for the peer device
void CAGEngine::SetMicVolume(unsigned short usVolume)
{
CHAR szBuf[MAX_SEND_BUF];
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Setting the microphone volume to %d\n", usVolume));
ASSERT(usVolume <= 15);
Lock();
m_AGProps.usMicVolume = usVolume;
int cbBuf = _snprintf(szBuf, MAX_SEND_BUF-1, AT_VGM, usVolume);
szBuf[MAX_SEND_BUF-1]='\0';
if (cbBuf > 0) {
if (m_AGProps.state >= AG_STATE_CONNECTING) {
SendATCommand(szBuf, cbBuf);
}
}
Unlock();
}
// This method is called when the headset button is pressed
void CAGEngine::OnHeadsetButton(LPSTR pszParams, int cchParam)
{
DWORD dwErr = ERROR_SUCCESS;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnHeadsetButton\n"));
Lock();
ASSERT(m_AGProps.state >= AG_STATE_CONNECTED);
SendATCommand(AT_OK, sizeof(AT_OK) - 1);
if ((AG_STATE_RINGING == m_AGProps.state) || (AG_STATE_RINGING_AUDIO_UP == m_AGProps.state)) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnHeadsetButton - In ringing state, answer call.\n"));
m_AGProps.fUseHFAudio = TRUE;
AddRef();
Unlock();
dwErr = BthAGNetworkAnswerCall();
Lock();
DelRef();
m_fExpectHeadsetButton = FALSE;
if (ERROR_SUCCESS != dwErr) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error answering call: %d\n", dwErr));
m_AGProps.fUseHFAudio = FALSE;
}
}
else if (! m_fExpectHeadsetButton) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnHeadsetButton - Not expecting headset button, drop/swap call.\n"));
AddRef();
Unlock();
DWORD dwState = 0;
BthAGNetworkGetCallState(&dwState);
if ((dwState & NETWORK_FLAGS_STATE_HOLD) || // If bitmask indicates we have calls on hold, do a swap
((dwState & NETWORK_FLAGS_STATE_ACTIVE) &&
(dwState & NETWORK_FLAGS_STATE_OFFERING)) // If we have active call and offering call, do a swap
) {
m_AGProps.fUseHFAudio = TRUE;
dwErr = BthAGNetworkSwapCall();
}
else {
BthAGNetworkDropCall(NETWORK_FLAGS_DROP_ACTIVE);
}
Lock();
DelRef();
if (ERROR_SUCCESS != dwErr) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error swapping call: %d\n", dwErr));
m_AGProps.fUseHFAudio = FALSE;
}
}
else {
// After headset-initiated connection, the HeadsetButton command
// is expected once.
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnHeadsetButton - Expecting headset button after connect, do nothing.\n"));
m_fExpectHeadsetButton = FALSE;
}
Unlock();
}
// This method is called when the speaker volume on the device changes
void CAGEngine::OnSpeakerVol(LPSTR pszParams, int cchParam)
{
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnSpkVol\n"));
Lock();
ASSERT(m_AGProps.state >= AG_STATE_CONNECTING);
LPSTR pTmp;
unsigned short usVolume = (USHORT) strtol(pszParams, &pTmp, 10);
if (pTmp != (pszParams + strlen(pszParams))) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Speaker volume AT Command was poorly formatted.\n"));
SendATCommand(AT_ERROR, sizeof(AT_ERROR)-1);
}
else if (usVolume > 15) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Received speaker volume indication of %d - returning ERROR (out of range).\n", usVolume));
SendATCommand(AT_ERROR, sizeof(AT_ERROR)-1);
}
else {
m_AGProps.usSpeakerVolume = usVolume;
SendATCommand(AT_OK, sizeof(AT_OK)-1);
AddRef();
Unlock();
BthAGPhoneExtEvent(AG_PHONE_EVENT_SPEAKER_VOLUME, (DWORD)usVolume, NULL);
Lock();
DelRef();
}
Unlock();
}
// This method is called when the mic volume on the device changes
void CAGEngine::OnMicVol(LPSTR pszParams, int cchParam)
{
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnMicVol\n"));
Lock();
ASSERT(m_AGProps.state >= AG_STATE_CONNECTING);
LPSTR pTmp;
unsigned short usVolume = (USHORT) strtol(pszParams, &pTmp, 10);
if (pTmp != (pszParams + strlen(pszParams))) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Mic volume AT Command was poorly formatted.\n"));
SendATCommand(AT_ERROR, sizeof(AT_ERROR)-1);
}
else if (usVolume > 15) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Received microphone volume indication of %d - returning ERROR (out of range).\n", usVolume));
SendATCommand(AT_ERROR, sizeof(AT_ERROR)-1);
}
else {
m_AGProps.usMicVolume = usVolume;
SendATCommand(AT_OK, sizeof(AT_OK)-1);
AddRef();
Unlock();
BthAGPhoneExtEvent(AG_PHONE_EVENT_MIC_VOLUME, (DWORD)usVolume, NULL);
Lock();
DelRef();
}
Unlock();
}
// This method is called when the peer device dials a number
void CAGEngine::OnDial(LPSTR pszParams, int cchParam)
{
WCHAR wszNumber[MAX_PHONE_NUMBER];
DWORD dwErr;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnDial\n"));
Lock();
ASSERT(m_AGProps.state >= AG_STATE_CONNECTED);
SendATCommand(AT_OK, sizeof(AT_OK)-1);
if (pszParams[cchParam-1] == ';') {
pszParams[cchParam-1] = '\0';
}
if (m_AGProps.fIndicatorUpdates) {
SendATCommand("\r\n+CIEV:3,2\r\n", 13); // Call Setup is ongoing
}
m_AGProps.usCallSetup = 2;
m_AGProps.fUseHFAudio = TRUE; // Indicate call is initiated from HF
AddRef();
Unlock();
if (0 < MultiByteToWideChar(CP_ACP, 0, pszParams, -1, wszNumber, ARRAY_SIZE(wszNumber))) {
dwErr = BthAGNetworkDialNumber(wszNumber);
}
else {
ASSERT(0);
dwErr = GetLastError();
}
Lock();
DelRef();
if (ERROR_SUCCESS != dwErr) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error dialing number: %d\n", dwErr));
if (m_AGProps.fIndicatorUpdates) {
SendATCommand("\r\n+CIEV:3,0\r\n", 13); // Call Setup is done
}
m_AGProps.usCallSetup = 0;
m_AGProps.fUseHFAudio = FALSE;
}
Unlock();
}
// This method is called when the peer device wants to dial the last dialed number
void CAGEngine::OnDialLast(LPSTR pszParams, int cchParam)
{
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnDialLast\n"));
WCHAR wszNumber[MAX_PHONE_NUMBER];
Lock();
ASSERT(m_AGProps.state >= AG_STATE_CONNECTED);
SendATCommand(AT_OK, sizeof(AT_OK)-1);
AddRef();
Unlock();
BOOL fDialed = BthAGGetLastDialed(wszNumber);
Lock();
DelRef();
if (fDialed) {
if (m_AGProps.fIndicatorUpdates) {
SendATCommand("\r\n+CIEV:3,2\r\n", 13); // Call Setup is ongoing
}
m_AGProps.usCallSetup = 2;
m_AGProps.fUseHFAudio = TRUE; // Indicate call is initiated from HF
AddRef();
Unlock();
DWORD dwErr = BthAGNetworkDialNumber(wszNumber);
Lock();
DelRef();
if (ERROR_SUCCESS != dwErr) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error dialing number: %d\n", dwErr));
if (m_AGProps.fIndicatorUpdates) {
SendATCommand("\r\n+CIEV:3,0\r\n", 13); // Call Setup is done
}
m_AGProps.usCallSetup = 0;
m_AGProps.fUseHFAudio = FALSE;
}
}
Unlock();
}
// This method is called when the peer device wants to dial a number in memory
void CAGEngine::OnDialMemory(LPSTR pszParams, int cchParam)
{
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnDialMemory\n"));
if (pszParams[cchParam-1] == ';') {
pszParams[cchParam-1] = '\0';
}
Lock();
ASSERT(m_AGProps.state >= AG_STATE_CONNECTED);
LPSTR pTmp;
unsigned short usIndex = (USHORT) strtol(pszParams, &pTmp, 10);
if (pTmp != (pszParams + strlen(pszParams))) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: ATD> Command was poorly formatted.\n"));
SendATCommand(AT_ERROR, sizeof(AT_ERROR)-1);
}
else {
WCHAR wszNumber[MAX_PHONE_NUMBER];
SendATCommand(AT_OK, sizeof(AT_OK)-1);
AddRef();
Unlock();
BOOL fDialed = BthAGGetSpeedDial(usIndex, wszNumber);
Lock();
DelRef();
if (fDialed) {
if (m_AGProps.fIndicatorUpdates) {
SendATCommand("\r\n+CIEV:3,2\r\n", 13); // Call Setup is ongoing
}
m_AGProps.usCallSetup = 2;
m_AGProps.fUseHFAudio = TRUE; // Indicate call is initiated from HF
AddRef();
Unlock();
DWORD dwErr = BthAGNetworkDialNumber(wszNumber);
Lock();
DelRef();
if (ERROR_SUCCESS != dwErr) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error dialing number: %d\n", dwErr));
if (m_AGProps.fIndicatorUpdates) {
SendATCommand("\r\n+CIEV:3,0\r\n", 13); // Call Setup is done
}
m_AGProps.usCallSetup = 0;
m_AGProps.fUseHFAudio = FALSE;
}
}
}
Unlock();
}
// This method is called when the peer device to answer an incoming call
void CAGEngine::OnAnswerCall(LPSTR pszParams, int cchParam)
{
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Calling AGEngine::OnAnswerCall\n"));
Lock();
if (m_AGProps.state >= AG_STATE_RINGING) {
m_AGProps.fMuteRings = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -