Bug 1073494 - Audio is not routing to headset while playback is on BT. r=mwu
authorRandy Lin <rlin@mozilla.com>
Wed, 08 Oct 2014 10:49:59 +0800
changeset 232479 d9d3423d423087cf96b0a43d69879485d5184838
parent 232478 e56bf4ea89fbe8633f23035e98bbd547ad262b0c
child 232480 d38de091ced03ac4c1389663741ab7e6a5ea58a3
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwu
bugs1073494
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1073494 - Audio is not routing to headset while playback is on BT. r=mwu
dom/system/gonk/AudioManager.cpp
dom/system/gonk/android_audio/AudioSystem.h
dom/system/gonk/nsIAudioManager.idl
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -73,16 +73,17 @@ static int sMaxStreamVolumeTbl[AUDIO_STR
   15,  // BT SCO
   15,  // enforced audible
   15,  // DTMF
   15,  // TTS
   15,  // FM
 };
 // A bitwise variable for recording what kind of headset is attached.
 static int sHeadsetState;
+static bool sBluetoothA2dpEnabled;
 static const int kBtSampleRate = 8000;
 static bool sSwitchDone = true;
 static bool sA2dpSwitchDone = true;
 
 namespace mozilla {
 namespace dom {
 namespace gonk {
 class RecoverTask : public nsRunnable
@@ -285,17 +286,23 @@ AudioManager::HandleBluetoothStatusChang
     } else {
       AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
                                             audioState, aAddress.get());
       String8 cmd("bluetooth_enabled=true");
       AudioSystem::setParameters(0, cmd);
       cmd.setTo("A2dpSuspended=false");
       AudioSystem::setParameters(0, cmd);
       sA2dpSwitchDone = true;
+#if ANDROID_VERSION >= 17
+      if (AudioSystem::getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_NO_BT_A2DP) {
+        SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE);
+      }
+#endif
     }
+    sBluetoothA2dpEnabled = audioState == AUDIO_POLICY_DEVICE_STATE_AVAILABLE;
   } else if (!strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
     AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
                                           audioState, aAddress.get());
     AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
                                           audioState, aAddress.get());
   }
 #endif
 }
@@ -391,33 +398,47 @@ NotifyHeadphonesStatus(SwitchState aStat
       obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_UNKNOWN);
     }
   }
 }
 
 class HeadphoneSwitchObserver : public SwitchObserver
 {
 public:
+  HeadphoneSwitchObserver(AudioManager* aAudioManager)
+  : mAudioManager(aAudioManager) { }
   void Notify(const SwitchEvent& aEvent) {
     NotifyHeadphonesStatus(aEvent.status());
     // When user pulled out the headset, a delay of routing here can avoid the leakage of audio from speaker.
     if (aEvent.status() == SWITCH_STATE_OFF && sSwitchDone) {
       MessageLoop::current()->PostDelayedTask(
         FROM_HERE, NewRunnableFunction(&ProcessDelayedAudioRoute, SWITCH_STATE_OFF), 1000);
       sSwitchDone = false;
     } else if (aEvent.status() != SWITCH_STATE_OFF) {
       InternalSetAudioRoutes(aEvent.status());
       sSwitchDone = true;
     }
+    // Handle the coexistence of a2dp / headset device, latest one wins.
+#if ANDROID_VERSION >= 17
+    int32_t forceUse = 0;
+    mAudioManager->GetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, &forceUse);
+    if (aEvent.status() != SWITCH_STATE_OFF && sBluetoothA2dpEnabled) {
+      mAudioManager->SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NO_BT_A2DP);
+    } else if (forceUse == AUDIO_POLICY_FORCE_NO_BT_A2DP) {
+      mAudioManager->SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE);
+    }
+#endif
   }
+private:
+  AudioManager* mAudioManager;
 };
 
 AudioManager::AudioManager()
   : mPhoneState(PHONE_STATE_CURRENT)
-  , mObserver(new HeadphoneSwitchObserver())
+  , mObserver(new HeadphoneSwitchObserver(this))
 #ifdef MOZ_B2G_RIL
   , mMuteCallToRIL(false)
 #endif
 {
   RegisterSwitchObserver(SWITCH_HEADPHONES, mObserver);
 
   InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES));
   NotifyHeadphonesStatus(GetCurrentSwitchState(SWITCH_HEADPHONES));
--- a/dom/system/gonk/android_audio/AudioSystem.h
+++ b/dom/system/gonk/android_audio/AudioSystem.h
@@ -37,22 +37,19 @@ typedef enum {
     AUDIO_POLICY_FORCE_NONE,
     AUDIO_POLICY_FORCE_SPEAKER,
     AUDIO_POLICY_FORCE_HEADPHONES,
     AUDIO_POLICY_FORCE_BT_SCO,
     AUDIO_POLICY_FORCE_BT_A2DP,
     AUDIO_POLICY_FORCE_WIRED_ACCESSORY,
     AUDIO_POLICY_FORCE_BT_CAR_DOCK,
     AUDIO_POLICY_FORCE_BT_DESK_DOCK,
-
-#ifdef VANILLA_ANDROID
     AUDIO_POLICY_FORCE_ANALOG_DOCK,
     AUDIO_POLICY_FORCE_DIGITAL_DOCK,
-#endif
-
+    AUDIO_POLICY_FORCE_NO_BT_A2DP,
     AUDIO_POLICY_FORCE_CFG_CNT,
     AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
 
     AUDIO_POLICY_FORCE_DEFAULT = AUDIO_POLICY_FORCE_NONE,
 } audio_policy_forced_cfg_t;
 
 /* usages used for audio_policy->set_force_use() */
 typedef enum {
@@ -719,16 +716,19 @@ public:
         FORCE_NONE,
         FORCE_SPEAKER,
         FORCE_HEADPHONES,
         FORCE_BT_SCO,
         FORCE_BT_A2DP,
         FORCE_WIRED_ACCESSORY,
         FORCE_BT_CAR_DOCK,
         FORCE_BT_DESK_DOCK,
+        FORCE_ANALOG_DOCK,
+        FORCE_DIGITAL_DOCK,
+        FORCE_NO_BT_A2DP,
         NUM_FORCE_CONFIG,
         FORCE_DEFAULT = FORCE_NONE
     };
 
     // usages used for setForceUse()
     enum force_use {
         FOR_COMMUNICATION,
         FOR_MEDIA,
--- a/dom/system/gonk/nsIAudioManager.idl
+++ b/dom/system/gonk/nsIAudioManager.idl
@@ -11,17 +11,17 @@ interface nsIAudioManager : nsISupports
    * Microphone muted?
    */
   attribute boolean microphoneMuted;
 
   /**
    * Are we playing audio from the FM radio?
    */
   attribute boolean fmRadioAudioEnabled;
- 
+
   /**
    * Set the phone's audio mode.
    */
   const long PHONE_STATE_INVALID          = -2;
   const long PHONE_STATE_CURRENT          = -1;
   const long PHONE_STATE_NORMAL           = 0;
   const long PHONE_STATE_RINGTONE         = 1;
   const long PHONE_STATE_IN_CALL          = 2;
@@ -36,17 +36,19 @@ interface nsIAudioManager : nsISupports
   const long FORCE_NONE            = 0; // the default
   const long FORCE_SPEAKER         = 1;
   const long FORCE_HEADPHONES      = 2;
   const long FORCE_BT_SCO          = 3;
   const long FORCE_BT_A2DP         = 4;
   const long FORCE_WIRED_ACCESSORY = 5;
   const long FORCE_BT_CAR_DOCK     = 6;
   const long FORCE_BT_DESK_DOCK    = 7;
-
+  const long FORCE_ANALOG_DOCK     = 8;
+  const long FORCE_DIGITAL_DOCK    = 9;
+  const long FORCE_NO_BT_A2DP      = 10;
   const long USE_COMMUNICATION     = 0;
   const long USE_MEDIA             = 1;
   const long USE_RECORD            = 2;
   const long USE_DOCK              = 3;
 
   void setForceForUse(in long usage, in long force);
   long getForceForUse(in long usage);