Bug 823273 - Part 1: Music volume should be faded when notification sound is on going - AudioChannel changes. r=baku

This commit is contained in:
Marco Chen 2013-09-02 17:45:44 +08:00
parent 74b1d0c3d5
commit 1375174442
7 changed files with 118 additions and 56 deletions

View File

@ -95,7 +95,7 @@ AudioChannelAgent::InitInternal(int32_t aChannelType,
}
/* boolean startPlaying (); */
NS_IMETHODIMP AudioChannelAgent::StartPlaying(bool *_retval)
NS_IMETHODIMP AudioChannelAgent::StartPlaying(int32_t *_retval)
{
AudioChannelService *service = AudioChannelService::GetAudioChannelService();
if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
@ -105,7 +105,7 @@ NS_IMETHODIMP AudioChannelAgent::StartPlaying(bool *_retval)
service->RegisterAudioChannelAgent(this,
static_cast<AudioChannelType>(mAudioChannelType));
*_retval = !service->GetMuted(this, !mVisible);
*_retval = service->GetState(this, !mVisible);
mIsRegToService = true;
return NS_OK;
}
@ -134,7 +134,7 @@ NS_IMETHODIMP AudioChannelAgent::SetVisibilityState(bool visible)
mVisible = visible;
if (mIsRegToService && oldVisibility != mVisible && callback) {
AudioChannelService *service = AudioChannelService::GetAudioChannelService();
callback->CanPlayChanged(!service->GetMuted(this, !mVisible));
callback->CanPlayChanged(service->GetState(this, !mVisible));
}
return NS_OK;
}
@ -144,7 +144,7 @@ void AudioChannelAgent::NotifyAudioChannelStateChanged()
nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
if (callback) {
AudioChannelService *service = AudioChannelService::GetAudioChannelService();
callback->CanPlayChanged(!service->GetMuted(this, !mVisible));
callback->CanPlayChanged(service->GetState(this, !mVisible));
}
}

View File

@ -24,6 +24,12 @@ enum AudioChannelType {
AUDIO_CHANNEL_LAST
};
enum AudioChannelState {
AUDIO_CHANNEL_STATE_NORMAL = 0,
AUDIO_CHANNEL_STATE_MUTED,
AUDIO_CHANNEL_STATE_FADED,
AUDIO_CHANNEL_STATE_LAST
};
} // namespace dom
} // namespace mozilla

View File

@ -98,8 +98,8 @@ AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
MOZ_ASSERT(aType != AUDIO_CHANNEL_DEFAULT);
AudioChannelAgentData* data = new AudioChannelAgentData(aType,
true /* mElementHidden */,
true /* mMuted */);
true /* aElementHidden */,
AUDIO_CHANNEL_STATE_MUTED /* aState */);
mAgents.Put(aAgent, data);
RegisterType(aType, CONTENT_PROCESS_ID_MAIN);
}
@ -203,27 +203,25 @@ AudioChannelService::UpdateChannelType(AudioChannelType aType,
}
}
bool
AudioChannelService::GetMuted(AudioChannelAgent* aAgent, bool aElementHidden)
AudioChannelState
AudioChannelService::GetState(AudioChannelAgent* aAgent, bool aElementHidden)
{
AudioChannelAgentData* data;
if (!mAgents.Get(aAgent, &data)) {
return true;
return AUDIO_CHANNEL_STATE_MUTED;
}
bool oldElementHidden = data->mElementHidden;
// Update visibility.
data->mElementHidden = aElementHidden;
bool muted = GetMutedInternal(data->mType, CONTENT_PROCESS_ID_MAIN,
data->mState = GetStateInternal(data->mType, CONTENT_PROCESS_ID_MAIN,
aElementHidden, oldElementHidden);
data->mMuted = muted;
return muted;
return data->mState;
}
bool
AudioChannelService::GetMutedInternal(AudioChannelType aType, uint64_t aChildID,
AudioChannelState
AudioChannelService::GetStateInternal(AudioChannelType aType, uint64_t aChildID,
bool aElementHidden, bool aElementWasHidden)
{
UpdateChannelType(aType, aChildID, aElementHidden, aElementWasHidden);
@ -269,24 +267,64 @@ AudioChannelService::GetMutedInternal(AudioChannelType aType, uint64_t aChildID,
// Let play any visible audio channel.
if (!aElementHidden) {
return false;
if (CheckVolumeFadedCondition(newType, aElementHidden)) {
return AUDIO_CHANNEL_STATE_FADED;
}
return AUDIO_CHANNEL_STATE_NORMAL;
}
bool muted = false;
// We are not visible, maybe we have to mute.
if (newType == AUDIO_CHANNEL_INT_NORMAL_HIDDEN ||
(newType == AUDIO_CHANNEL_INT_CONTENT_HIDDEN &&
!mActiveContentChildIDs.Contains(aChildID))) {
muted = true;
return AUDIO_CHANNEL_STATE_MUTED;
}
if (!muted) {
// After checking the condition on normal & content channel, if the state
// is not on muted then checking other higher channels type here.
if (ChannelsActiveWithHigherPriorityThan(newType)) {
MOZ_ASSERT(newType != AUDIO_CHANNEL_INT_NORMAL_HIDDEN);
muted = ChannelsActiveWithHigherPriorityThan(newType);
if (CheckVolumeFadedCondition(newType, aElementHidden)) {
return AUDIO_CHANNEL_STATE_FADED;
}
return AUDIO_CHANNEL_STATE_MUTED;
}
return muted;
return AUDIO_CHANNEL_STATE_NORMAL;
}
bool
AudioChannelService::CheckVolumeFadedCondition(AudioChannelInternalType aType,
bool aElementHidden)
{
// Only normal & content channels are considered
if (aType > AUDIO_CHANNEL_INT_CONTENT_HIDDEN) {
return false;
}
// Consider that audio from notification is with short duration
// so just fade the volume not pause it
if (mChannelCounters[AUDIO_CHANNEL_INT_NOTIFICATION].IsEmpty() &&
mChannelCounters[AUDIO_CHANNEL_INT_NOTIFICATION_HIDDEN].IsEmpty()) {
return false;
}
// Since this element is on the foreground, it can be allowed to play always.
// So return true directly when there is any notification channel alive.
if (aElementHidden == false) {
return true;
}
// If element is on the background, it is possible paused by channels higher
// then notification.
for (int i = AUDIO_CHANNEL_INT_LAST - 1;
i != AUDIO_CHANNEL_INT_NOTIFICATION_HIDDEN; --i) {
if (!mChannelCounters[i].IsEmpty()) {
return false;
}
}
return true;
}
bool
@ -476,7 +514,8 @@ AudioChannelService::Notify(nsITimer* aTimer)
}
bool
AudioChannelService::ChannelsActiveWithHigherPriorityThan(AudioChannelInternalType aType)
AudioChannelService::ChannelsActiveWithHigherPriorityThan(
AudioChannelInternalType aType)
{
for (int i = AUDIO_CHANNEL_INT_LAST - 1;
i != AUDIO_CHANNEL_INT_CONTENT_HIDDEN; --i) {

View File

@ -29,11 +29,12 @@ public:
NS_DECL_NSITIMERCALLBACK
/**
* Returns the AudioChannelServce singleton. Only to be called from main thread.
* Returns the AudioChannelServce singleton. Only to be called from main
* thread.
*
* @return NS_OK on proper assignment, NS_ERROR_FAILURE otherwise.
*/
static AudioChannelService*
GetAudioChannelService();
static AudioChannelService* GetAudioChannelService();
/**
* Shutdown the singleton.
@ -54,9 +55,11 @@ public:
virtual void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
/**
* Return true if this type should be muted.
* Return the state to indicate this agent should keep playing/
* fading volume/muted.
*/
virtual bool GetMuted(AudioChannelAgent* aAgent, bool aElementHidden);
virtual AudioChannelState GetState(AudioChannelAgent* aAgent,
bool aElementHidden);
/**
* Return true if there is a content channel active in this process
@ -65,8 +68,8 @@ public:
virtual bool ContentOrNormalChannelIsActive();
/**
* Return true iff a normal or content channel is active for the given process
* ID.
* Return true if a normal or content channel is active for the given
* process ID.
*/
virtual bool ProcessContentOrNormalChannelIsActive(uint64_t aChildID);
@ -93,8 +96,9 @@ protected:
void UnregisterTypeInternal(AudioChannelType aType, bool aElementHidden,
uint64_t aChildID);
bool GetMutedInternal(AudioChannelType aType, uint64_t aChildID,
bool aElementHidden, bool aElementWasHidden);
AudioChannelState GetStateInternal(AudioChannelType aType, uint64_t aChildID,
bool aElementHidden,
bool aElementWasHidden);
/* Update the internal type value following the visibility changes */
void UpdateChannelType(AudioChannelType aType, uint64_t aChildID,
@ -127,6 +131,9 @@ protected:
bool ChannelsActiveWithHigherPriorityThan(AudioChannelInternalType aType);
bool CheckVolumeFadedCondition(AudioChannelInternalType aType,
bool aElementHidden);
const char* ChannelName(AudioChannelType aType);
AudioChannelInternalType GetInternalType(AudioChannelType aType,
@ -136,15 +143,15 @@ protected:
public:
AudioChannelAgentData(AudioChannelType aType,
bool aElementHidden,
bool aMuted)
AudioChannelState aState)
: mType(aType)
, mElementHidden(aElementHidden)
, mMuted(aMuted)
, mState(aState)
{}
AudioChannelType mType;
bool mElementHidden;
bool mMuted;
AudioChannelState mState;
};
static PLDHashOperator

View File

@ -58,16 +58,16 @@ AudioChannelServiceChild::~AudioChannelServiceChild()
{
}
bool
AudioChannelServiceChild::GetMuted(AudioChannelAgent* aAgent, bool aElementHidden)
AudioChannelState
AudioChannelServiceChild::GetState(AudioChannelAgent* aAgent, bool aElementHidden)
{
AudioChannelAgentData* data;
if (!mAgents.Get(aAgent, &data)) {
return true;
return AUDIO_CHANNEL_STATE_MUTED;
}
ContentChild *cc = ContentChild::GetSingleton();
bool muted = true;
AudioChannelState state = AUDIO_CHANNEL_STATE_MUTED;
bool oldElementHidden = data->mElementHidden;
UpdateChannelType(data->mType, CONTENT_PROCESS_ID_MAIN, aElementHidden, oldElementHidden);
@ -76,15 +76,15 @@ AudioChannelServiceChild::GetMuted(AudioChannelAgent* aAgent, bool aElementHidde
data->mElementHidden = aElementHidden;
if (cc) {
cc->SendAudioChannelGetMuted(data->mType, aElementHidden, oldElementHidden, &muted);
cc->SendAudioChannelGetState(data->mType, aElementHidden, oldElementHidden, &state);
}
data->mMuted = muted;
data->mState = state;
if (cc) {
cc->SendAudioChannelChangedNotification();
}
return muted;
return state;
}
void

View File

@ -21,11 +21,12 @@ class AudioChannelServiceChild : public AudioChannelService
public:
/**
* Returns the AudioChannelServce singleton. Only to be called from main thread.
* Returns the AudioChannelServce singleton. Only to be called from main
* thread.
*
* @return NS_OK on proper assignment, NS_ERROR_FAILURE otherwise.
*/
static AudioChannelService*
GetAudioChannelService();
static AudioChannelService* GetAudioChannelService();
static void Shutdown();
@ -34,9 +35,11 @@ public:
virtual void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
/**
* Return true if this type + this mozHidden should be muted.
* Return the state to indicate this agent should keep playing/
* fading volume/muted.
*/
virtual bool GetMuted(AudioChannelAgent* aAgent, bool aMozHidden);
virtual AudioChannelState GetState(AudioChannelAgent* aAgent,
bool aElementHidden);
virtual void SetDefaultVolumeControlChannel(AudioChannelType aType, bool aHidden);

View File

@ -12,10 +12,11 @@ interface nsIAudioChannelAgentCallback : nsISupports
*
* @param canPlay
* Callback from agent to notify component of the playable status
* of the channel. If canPlay is false, component SHOULD stop playing
* media associated with this channel as soon as possible.
* of the channel. If canPlay is muted state, component SHOULD stop
* playing media associated with this channel as soon as possible. if
* it is faded state then the volume of media should be reduced.
*/
void canPlayChanged(in boolean canPlay);
void canPlayChanged(in long canPlay);
};
/**
@ -31,7 +32,7 @@ interface nsIAudioChannelAgentCallback : nsISupports
* 1. Changes to the playable status of this channel.
*/
[scriptable, uuid(f012a9b7-6431-4915-a4ac-4ba7d833e28e)]
[scriptable, uuid(7a4c0b06-63a4-11e2-8c1b-10bf48d64bd4)]
interface nsIAudioChannelAgent : nsISupports
{
const long AUDIO_AGENT_CHANNEL_NORMAL = 0;
@ -44,6 +45,10 @@ interface nsIAudioChannelAgent : nsISupports
const long AUDIO_AGENT_CHANNEL_ERROR = 1000;
const long AUDIO_AGENT_STATE_NORMAL = 0;
const long AUDIO_AGENT_STATE_MUTED = 1;
const long AUDIO_AGENT_STATE_FADED = 2;
/**
* Before init() is called, this returns AUDIO_AGENT_CHANNEL_ERROR.
*/
@ -80,12 +85,14 @@ interface nsIAudioChannelAgent : nsISupports
*
*
* @return
* true: the agent has registered with audio channel service and the
* component should start playback.
* false: the agent has registered with audio channel service but the
* component should not start playback.
* normal state: the agent has registered with audio channel service and
* the component should start playback.
* muted state: the agent has registered with audio channel service but
* the component should not start playback.
* faded state: the agent has registered with audio channel service the
* component should start playback as well as reducing the volume.
*/
boolean startPlaying();
long startPlaying();
/**
* Notify the agent we no longer want to play.