📄 handler.cpp
字号:
if (! fScoPresent) {
ClearSCO();
}
}
if (pConnections != connections)
delete[] pConnections;
Unlock();
}
// This method notifies the AG Engine that a SCO connection has been made with a peer
DWORD CAGEngine::NotifySCOConnect(unsigned short handle)
{
DWORD dwRetVal = ERROR_SUCCESS;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: ++NotifySCOConnect.\n"));
ASSERT(IsLocked());
if (m_AGProps.state >= AG_STATE_AUDIO_UP) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: NotifySCOConnect - Audio connection already opened.\n"));
m_AGProps.state = AG_STATE_AUDIO_UP;
dwRetVal = ERROR_ALREADY_INITIALIZED;
goto exit;
}
if (m_AGProps.state < AG_STATE_CONNECTED) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: NotifySCOConnect - Cannot open audio connection until service-level connection has been made.\n"));
dwRetVal = ERROR_NOT_READY;
goto exit;
}
// TODO: See if we have a built-in audio driver and do switching.
waveOutMessage(0, WODM_BT_SCO_AUDIO_CONTROL, 0, TRUE);
if (m_AGProps.fPCMMode) {
m_hSco = handle;
}
m_AGProps.state = AG_STATE_AUDIO_UP;
AddRef();
Unlock();
BthAGPhoneExtEvent(AG_PHONE_EVENT_BT_AUDIO, 1, NULL);
Lock();
DelRef();
exit:
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: --NotifySCOConnect.\n"));
return dwRetVal;
}
// This method informs the AG that no SCO connections to the device are present. We need to
// make sure that audio state is no longer up.
void CAGEngine::ClearSCO(void)
{
BOOL fClearSCO = FALSE;
ASSERT(IsLocked());
if (AG_STATE_AUDIO_UP == m_AGProps.state) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: SCO connection was closed.\n"));
m_AGProps.state = AG_STATE_CONNECTED;
fClearSCO = TRUE;
}
else if (AG_STATE_RINGING_AUDIO_UP == m_AGProps.state) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: SCO connection was closed.\n"));
m_AGProps.state = AG_STATE_RINGING;
fClearSCO = TRUE;
}
if (fClearSCO) {
waveOutMessage(0, WODM_BT_SCO_AUDIO_CONTROL, 0, FALSE);
// TODO: See if we have a built-in audio driver and do switching.
m_hSco = 0;
AddRef();
Unlock();
BthAGPhoneExtEvent(AG_PHONE_EVENT_BT_AUDIO, 0, NULL);
Lock();
DelRef();
// 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);
}
}
}
// This method instructs the AG Engine to open a connection
DWORD CAGEngine::OpenAGConnection(BOOL fOpenAudio, BOOL fFirstOnly)
{
DWORD dwRetVal = ERROR_SUCCESS;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Opening AG connection.\n"));
Lock();
m_fAudioConnect = fOpenAudio;
dwRetVal = OpenControlChannel(fFirstOnly);
Unlock();
return dwRetVal;
}
// This private method opens control connection to peer
DWORD CAGEngine::OpenControlChannel(BOOL fFirstOnly)
{
DWORD dwRetVal = ERROR_SUCCESS;
SOCKADDR_BTH sa;
DWORD dwDeviceIdx = 0;
USHORT usPageTimeout;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Opening control connection.\n"));
ASSERT(IsLocked());
if (m_AGProps.state >= AG_STATE_CONNECTED) {
// Make sure we are not timing out the connection
m_pTP->UnScheduleEvent(m_CloseCookie);
m_CloseCookie = NULL;
m_fCancelCloseConnection = FALSE;
if (m_fAudioConnect) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Already connected, just opening audio connection.\n"));
m_fAudioConnect = FALSE;
dwRetVal = OpenAudioChannel();
}
else {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: OpenControlConnection returning ERROR_ALREADY_INITIALIZED\n"));
dwRetVal = ERROR_ALREADY_INITIALIZED;
}
goto exit;
}
usPageTimeout = m_AGProps.usPageTimeout;
if (fFirstOnly) {
// If we are only connecting to the pri-1 device, let's allow
// for a longer time out.
usPageTimeout *= 2;
}
(void) BthWritePageTimeout(usPageTimeout); // if this fails, we continue anyway
m_sockClient = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if (INVALID_SOCKET == m_sockClient) {
dwRetVal = GetLastError();
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error opening socket: %d\n", dwRetVal));
goto exit;
}
(void) GetBTAddrList(m_AGProps.DeviceList, ARRAY_SIZE(m_AGProps.DeviceList)); // if this fails, we continue anyway
if (m_AGProps.DeviceList[0].bta == 0) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Tried to open a connection but no device has been paired yet.\n"));
dwRetVal = ERROR_NOT_READY;
goto exit;
}
while (dwDeviceIdx < ARRAY_SIZE(m_AGProps.DeviceList)) {
if (m_AGProps.DeviceList[dwDeviceIdx].bta == 0) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Device with index %d does not exist, failed to connect.\n", dwDeviceIdx));
dwRetVal = ERROR_NOT_READY;
goto exit;
}
BOOL fHS = m_AGProps.fNoHandsfree || !IsHandsfreeUUID(&(m_AGProps.DeviceList[dwDeviceIdx].service));
memset(&sa, 0, sizeof(sa));
sa.addressFamily = AF_BTH;
sa.btAddr = m_AGProps.DeviceList[dwDeviceIdx].bta;
if (fHS) {
// Try to connect to a headset
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: OpenControlConnection - Attempting to connect to headset device at index %d.\n", dwDeviceIdx));
sa.serviceClassId = HeadsetServiceClass_UUID;
}
else {
// Try to connect to a hands-free
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: OpenControlConnection - Attempting to connect to HF device at index %d.\n", dwDeviceIdx));
sa.serviceClassId = HandsfreeServiceClass_UUID;
}
if (SOCKET_ERROR == connect(m_sockClient, (SOCKADDR *)&sa, sizeof(sa))) {
if (fFirstOnly) {
dwRetVal = ERROR_NOT_CONNECTED;
goto exit;
}
else {
dwDeviceIdx++;
continue;
}
}
if (fHS) {
m_AGProps.fHandsfree = FALSE;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Connected to a headset device.\n"));
}
else {
m_AGProps.fHandsfree = TRUE;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Connected to a hands-free device.\n"));
}
// If we get to here we are connected
SetBTAddrList(m_AGProps.DeviceList[dwDeviceIdx].bta, m_AGProps.fHandsfree);
break;
}
if (dwDeviceIdx == ARRAY_SIZE(m_AGProps.DeviceList)) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error: Could not connect to any devices.\n"));
dwRetVal = ERROR_NOT_CONNECTED;
goto exit;
}
if (m_AGProps.fHandsfree) {
m_AGProps.state = AG_STATE_CONNECTING;
}
else {
m_fExpectHeadsetButton = FALSE;
m_AGProps.state = AG_STATE_CONNECTED;
}
if (m_pParser) {
dwRetVal = m_pParser->Start(this, m_sockClient);
}
else {
dwRetVal = ERROR_NOT_READY;
}
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_ERROR, (L"BTAGSVC: Error starting parser module: %d\n", dwRetVal));
goto exit;
}
AddRef();
Unlock();
BthAGPhoneExtEvent(AG_PHONE_EVENT_BT_CTRL, 1, NULL);
Lock();
DelRef();
if (m_fAudioConnect && !m_AGProps.fHandsfree) {
// Open audio connection
m_fAudioConnect = FALSE;
dwRetVal = OpenAudioChannel();
}
exit:
if ((ERROR_SUCCESS != dwRetVal) && (ERROR_ALREADY_INITIALIZED != dwRetVal)) {
CloseControlChannel();
}
return dwRetVal;
}
// This method closes the connection to the peer device
void CAGEngine::CloseAGConnection(BOOL fCloseControl)
{
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Closing AG connection.\n"));
Lock();
if (fCloseControl || !m_AGProps.fHandsfree) {
CloseControlChannel();
}
else {
CloseAudioChannel();
}
Unlock();
}
// This private method closes the control connection to the peer
void CAGEngine::CloseControlChannel(void)
{
ASSERT(IsLocked());
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: ++CloseControlChannel\n"));
// Make sure audio connection is closed and we are unparked
CloseAudioChannel();
EnsureActiveBaseband();
AddRef();
Unlock();
if (m_pParser) {
m_pParser->Stop();
}
Lock();
DelRef();
m_sockClient = INVALID_SOCKET; // parser will close the socket
m_AGProps.state = AG_STATE_DISCONNECTED;
m_AGProps.usCallType = AG_CALL_TYPE_NONE;
m_AGProps.fHandsfree = FALSE;
m_AGProps.fNotifyCallWait = FALSE;
m_AGProps.fNotifyCLI = FALSE;
m_AGProps.fIndicatorUpdates = FALSE;
m_AGProps.btAddrClient = 0;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: --CloseControlChannel\n"));
}
void CAGEngine::ServiceConnectionUp()
{
//
// At this point, HF is initialized
//
ASSERT(IsLocked());
if (AG_STATE_CONNECTING == m_AGProps.state) {
// If we are still in connecting state, we are now connected.
m_AGProps.state = AG_STATE_CONNECTED;
if (m_AGProps.fIndicatorUpdates) {
CHAR szCommand[MAX_SEND_BUF];
int cbCommand;
if (m_AGProps.fHaveService) {
SendATCommand("\r\n+CIEV:1,1\r\n", 13);
}
if (m_AGProps.fInCall) {
SendATCommand("\r\n+CIEV:2,1\r\n", 13);
}
cbCommand = _snprintf(szCommand, MAX_SEND_BUF-1, "\r\n+CIEV:3,%d\r\n", m_AGProps.usCallSetup);
szCommand[MAX_SEND_BUF-1]='\0';
if (cbCommand > 0) {
SendATCommand(szCommand, cbCommand);
}
}
if (m_fAudioConnect) {
OpenAudioChannel();
m_fAudioConnect = FALSE;
}
if (m_AGProps.usHFCapability & AG_CAP_INBAND_RING) {
if (m_AGProps.state >= AG_STATE_AUDIO_UP) {
SendATCommand("\r\n+BSIR:1\r\n", 11); // In-band ring tone on
}
else {
SendATCommand("\r\n+BSIR:0\r\n", 11); // In-band ring tone off
}
}
}
}
// This method gets AG properties
void CAGEngine::GetAGProps(PAG_PROPS pAGProps)
{
PREFAST_ASSERT(pAGProps);
Lock();
*pAGProps = m_AGProps;
Unlock();
}
// This method sets AG properties
void CAGEngine::SetAGProps(PAG_PROPS pAGProps)
{
ASSERT((pAGProps->usSpeakerVolume >= 0) && (pAGProps->usSpeakerVolume <= 15));
ASSERT((pAGProps->usMicVolume >= 0) && (pAGProps->usMicVolume <= 15));
Lock();
m_AGProps = *pAGProps;
Unlock();
}
// This private method opens the audio connection to the peer
DWORD CAGEngine::OpenAudioChannel(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Opening audio connection.\n"));
ASSERT(IsLocked());
if (m_AGProps.state >= AG_STATE_AUDIO_UP) {
DEBUGMSG(ZONE_HANDLER, (L"BTAGSVC: Audio connection already opened.\n"));
m_AGProps.state = AG_STATE_AUDIO_UP;
dwRetVal = ERROR_ALREADY_INITIALIZED;
goto exit;
}
if (m_AGProps.state < AG_STATE_CONNECTED) {
DEBUGMSG(ZONE_WARN, (L"BTAGSVC: Cannot open audio connection until service-level connection has been made.\n"));
dwRetVal = ERROR_NOT_READY;
goto exit;
}
EnsureActiveBaseband();
if (m_AGProps.fPCMMode) {
ASSERT(m_hSco == 0);
dwRetVal = BthCreateSCOConnection (&m_AGProps.btAddrClient, &m_hSco);
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_ERROR, (_T("BTAGSVC: Error creating SCO connection: %d\n"), dwRetVal));
//retry to work around certain cases where the SCO connection seems to be oddly rejected by the HF unit
Sleep(100);
dwRetVal = BthCreateSCOConnection (&m_AGProps.btAddrClient, &m_hSco);
if (ERROR_SUCCESS != dwRetVal) {
DEBUGMSG(ZONE_ERROR, (_T("BTAGSVC: Error creating SCO connection: %d\n"), dwRetVal));
goto exit;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -