diff --git a/dom/bluetooth/BluetoothHfpManager.cpp b/dom/bluetooth/BluetoothHfpManager.cpp index 10198378ecb..fb77c553065 100644 --- a/dom/bluetooth/BluetoothHfpManager.cpp +++ b/dom/bluetooth/BluetoothHfpManager.cpp @@ -72,6 +72,12 @@ namespace { // Wait for 2 seconds for Dialer processing event 'BLDN'. '2' seconds is a // magic number. The mechanism should be revised once we can get call history. static int sWaitingForDialingInterval = 2000; //unit: ms + + // Wait 3.7 seconds until Dialer stops playing busy tone. '3' seconds is the + // time window set in Dialer and the extra '0.7' second is a magic number. + // The mechanism should be revised once we know the exact time at which + // Dialer stops playing. + static int sBusyToneInterval = 3700; //unit: ms } // anonymous namespace /* CallState for sCINDItems[CINDType::CALL].value @@ -279,6 +285,17 @@ private: int mType; }; +class BluetoothHfpManager::CloseScoTask : public Task +{ +private: + void Run() MOZ_OVERRIDE + { + MOZ_ASSERT(gBluetoothHfpManager); + + gBluetoothHfpManager->DisconnectSco(); + } +}; + static bool IsValidDtmf(const char aChar) { // Valid DTMF: [*#0-9ABCD] @@ -1397,8 +1414,17 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex, // -1 is necessary because call 0 is an invalid (padding) call object. if (mCurrentCallArray.Length() - 1 == GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_DISCONNECTED)) { - // There is no call, close Sco and clear mCurrentCallArray - DisconnectSco(); + // In order to let user hear busy tone via connected Bluetooth headset, + // we postpone the timing of dropping SCO. + if (prevCallState != nsITelephonyProvider::CALL_STATE_BUSY) { + DisconnectSco(); + } else { + // Close Sco later since Dialer is still playing busy tone via HF. + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new CloseScoTask(), + sBusyToneInterval); + } + ResetCallArray(); } break; @@ -1678,11 +1704,17 @@ BluetoothHfpManager::ConnectSco(BluetoothReplyRunnable* aRunnable) bool BluetoothHfpManager::DisconnectSco() { - if (!mScoSocket) { + if (!IsConnected()) { NS_WARNING("BluetoothHfpManager is not connected"); return false; } + SocketConnectionStatus status = mScoSocket->GetConnectionStatus(); + if (status != SOCKET_CONNECTED && status != SOCKET_CONNECTING) { + NS_WARNING("No SCO exists"); + return false; + } + mScoSocket->Disconnect(); return true; } @@ -1725,4 +1757,3 @@ BluetoothHfpManager::IsScoConnected() } NS_IMPL_ISUPPORTS1(BluetoothHfpManager, nsIObserver) - diff --git a/dom/bluetooth/BluetoothHfpManager.h b/dom/bluetooth/BluetoothHfpManager.h index 6785e7a84c8..6e2f805854b 100644 --- a/dom/bluetooth/BluetoothHfpManager.h +++ b/dom/bluetooth/BluetoothHfpManager.h @@ -93,10 +93,12 @@ public: bool IsScoConnected(); private: + class CloseScoTask; class GetVolumeTask; class RespondToBLDNTask; class SendRingIndicatorTask; + friend class CloseScoTask; friend class GetVolumeTask; friend class RespondToBLDNTask; friend class SendRingIndicatorTask;