Bug 847255 - [Bluetooth/AudioChannel] A2DP failed to start session due to music resume too fast during SCO is disconnecting. r=baku

This commit is contained in:
Marco Chen 2013-04-29 10:47:15 +08:00
Родитель 4eb960baaf
Коммит 088e5b7a15
2 изменённых файлов: 52 добавлений и 4 удалений

Просмотреть файл

@ -63,7 +63,7 @@ AudioChannelService::Shutdown()
}
}
NS_IMPL_ISUPPORTS0(AudioChannelService)
NS_IMPL_ISUPPORTS2(AudioChannelService, nsIObserver, nsITimerCallback)
AudioChannelService::AudioChannelService()
: mCurrentHigherChannel(AUDIO_CHANNEL_LAST)
@ -102,9 +102,17 @@ AudioChannelService::RegisterType(AudioChannelType aType, uint64_t aChildID)
AudioChannelInternalType type = GetInternalType(aType, true);
mChannelCounters[type].AppendElement(aChildID);
// In order to avoid race conditions, it's safer to notify any existing
// agent any time a new one is registered.
if (XRE_GetProcessType() == GeckoProcessType_Default) {
// Since there is another telephony registered, we can unregister old one
// immediately.
if (mDeferTelChannelTimer && aType == AUDIO_CHANNEL_TELEPHONY) {
mDeferTelChannelTimer->Cancel();
mDeferTelChannelTimer = nullptr;
UnregisterTypeInternal(aType, mTimerElementHidden, mTimerChildID);
}
// In order to avoid race conditions, it's safer to notify any existing
// agent any time a new one is registered.
SendAudioChannelChangedNotification(aChildID);
Notify();
}
@ -125,6 +133,28 @@ void
AudioChannelService::UnregisterType(AudioChannelType aType,
bool aElementHidden,
uint64_t aChildID)
{
// There are two reasons to defer the decrease of telephony channel.
// 1. User can have time to remove device from his ear before music resuming.
// 2. Give BT SCO to be disconnected before starting to connect A2DP.
if (XRE_GetProcessType() == GeckoProcessType_Default &&
aType == AUDIO_CHANNEL_TELEPHONY &&
(mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN].Length() +
mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY].Length()) == 1) {
mTimerElementHidden = aElementHidden;
mTimerChildID = aChildID;
mDeferTelChannelTimer = do_CreateInstance("@mozilla.org/timer;1");
mDeferTelChannelTimer->InitWithCallback(this, 1500, nsITimer::TYPE_ONE_SHOT);
return;
}
UnregisterTypeInternal(aType, aElementHidden, aChildID);
}
void
AudioChannelService::UnregisterTypeInternal(AudioChannelType aType,
bool aElementHidden,
uint64_t aChildID)
{
// The array may contain multiple occurrence of this appId but
// this should remove only the first one.
@ -400,6 +430,14 @@ AudioChannelService::Notify()
}
}
NS_IMETHODIMP
AudioChannelService::Notify(nsITimer* aTimer)
{
UnregisterTypeInternal(AUDIO_CHANNEL_TELEPHONY, mTimerElementHidden, mTimerChildID);
mDeferTelChannelTimer = nullptr;
return NS_OK;
}
bool
AudioChannelService::ChannelsActiveWithHigherPriorityThan(AudioChannelInternalType aType)
{

Просмотреть файл

@ -10,6 +10,7 @@
#include "nsAutoPtr.h"
#include "nsIObserver.h"
#include "nsTArray.h"
#include "nsITimer.h"
#include "AudioChannelCommon.h"
#include "AudioChannelAgent.h"
@ -18,11 +19,14 @@
namespace mozilla {
namespace dom {
class AudioChannelService : public nsIObserver
class AudioChannelService
: public nsIObserver
, public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSITIMERCALLBACK
/**
* Returns the AudioChannelServce singleton. Only to be called from main thread.
@ -79,6 +83,8 @@ protected:
void RegisterType(AudioChannelType aType, uint64_t aChildID);
void UnregisterType(AudioChannelType aType, bool aElementHidden,
uint64_t aChildID);
void UnregisterTypeInternal(AudioChannelType aType, bool aElementHidden,
uint64_t aChildID);
bool GetMutedInternal(AudioChannelType aType, uint64_t aChildID,
bool aElementHidden, bool aElementWasHidden);
@ -144,6 +150,10 @@ protected:
nsTArray<uint64_t> mActiveContentChildIDs;
bool mActiveContentChildIDsFrozen;
nsCOMPtr<nsITimer> mDeferTelChannelTimer;
bool mTimerElementHidden;
uint64_t mTimerChildID;
// This is needed for IPC comunication between
// AudioChannelServiceChild and this class.
friend class ContentParent;