Bug 1073494 - Audio is not routing to headset while playback is on BT. r=mwu
--- 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);