author | Marco Chen <mchen@mozilla.com> |
Mon, 02 Sep 2013 17:45:44 +0800 | |
changeset 160197 | fd8ca2b2cbdb91f3af8f77145076aaee04a86d4a |
parent 160081 | e63b6d17fbfd966d2ad77c2d4cd8dbaf1efbf2e8 |
child 160198 | 7b4046fcaf530b4ad96a042e5e51ad2818ab093d |
push id | 2961 |
push user | lsblakk@mozilla.com |
push date | Mon, 28 Oct 2013 21:59:28 +0000 |
treeherder | mozilla-beta@73ef4f13486f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | baku |
bugs | 823273 |
milestone | 26.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
|
--- a/dom/audiochannel/AudioChannelAgent.cpp +++ b/dom/audiochannel/AudioChannelAgent.cpp @@ -90,27 +90,27 @@ AudioChannelAgent::InitInternal(int32_t } else { mCallback = aCallback; } return NS_OK; } /* 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 || service == nullptr || mIsRegToService) { return NS_ERROR_FAILURE; } service->RegisterAudioChannelAgent(this, static_cast<AudioChannelType>(mAudioChannelType)); - *_retval = !service->GetMuted(this, !mVisible); + *_retval = service->GetState(this, !mVisible); mIsRegToService = true; return NS_OK; } /* void stopPlaying (); */ NS_IMETHODIMP AudioChannelAgent::StopPlaying(void) { if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR || @@ -129,27 +129,27 @@ NS_IMETHODIMP AudioChannelAgent::SetVisi { bool oldVisibility = mVisible; nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback(); 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; } 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)); } } already_AddRefed<nsIAudioChannelAgentCallback> AudioChannelAgent::GetCallback() { nsCOMPtr<nsIAudioChannelAgentCallback> callback = mCallback; if (!callback) {
--- a/dom/audiochannel/AudioChannelCommon.h +++ b/dom/audiochannel/AudioChannelCommon.h @@ -19,13 +19,19 @@ enum AudioChannelType { AUDIO_CHANNEL_NOTIFICATION, AUDIO_CHANNEL_ALARM, AUDIO_CHANNEL_TELEPHONY, AUDIO_CHANNEL_RINGER, AUDIO_CHANNEL_PUBLICNOTIFICATION, 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 #endif
--- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -93,18 +93,18 @@ AudioChannelService::~AudioChannelServic void AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent, AudioChannelType aType) { 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); } void AudioChannelService::RegisterType(AudioChannelType aType, uint64_t aChildID) { AudioChannelInternalType type = GetInternalType(aType, true); @@ -198,37 +198,35 @@ AudioChannelService::UpdateChannelType(A if (newType != oldType) { mChannelCounters[newType].AppendElement(aChildID); MOZ_ASSERT(mChannelCounters[oldType].Contains(aChildID)); mChannelCounters[oldType].RemoveElement(aChildID); } } -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); // Calculating the new and old type and update the hashtable if needed. AudioChannelInternalType newType = GetInternalType(aType, aElementHidden); AudioChannelInternalType oldType = GetInternalType(aType, aElementWasHidden); @@ -264,34 +262,74 @@ AudioChannelService::GetMutedInternal(Au if (newType != oldType && aType == AUDIO_CHANNEL_CONTENT) { Notify(); } SendAudioChannelChangedNotification(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; + } + + // 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); + if (CheckVolumeFadedCondition(newType, aElementHidden)) { + return AUDIO_CHANNEL_STATE_FADED; + } + return AUDIO_CHANNEL_STATE_MUTED; } - if (!muted) { - MOZ_ASSERT(newType != AUDIO_CHANNEL_INT_NORMAL_HIDDEN); - muted = ChannelsActiveWithHigherPriorityThan(newType); + 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; } - return muted; + // 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 AudioChannelService::ContentOrNormalChannelIsActive() { return !mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].IsEmpty() || !mChannelCounters[AUDIO_CHANNEL_INT_CONTENT_HIDDEN].IsEmpty() || !mChannelCounters[AUDIO_CHANNEL_INT_NORMAL].IsEmpty(); @@ -471,17 +509,18 @@ NS_IMETHODIMP AudioChannelService::Notify(nsITimer* aTimer) { UnregisterTypeInternal(AUDIO_CHANNEL_TELEPHONY, mTimerElementHidden, mTimerChildID); mDeferTelChannelTimer = nullptr; return NS_OK; } bool -AudioChannelService::ChannelsActiveWithHigherPriorityThan(AudioChannelInternalType aType) +AudioChannelService::ChannelsActiveWithHigherPriorityThan( + AudioChannelInternalType aType) { for (int i = AUDIO_CHANNEL_INT_LAST - 1; i != AUDIO_CHANNEL_INT_CONTENT_HIDDEN; --i) { if (i == aType) { return false; } if (!mChannelCounters[i].IsEmpty()) {
--- a/dom/audiochannel/AudioChannelService.h +++ b/dom/audiochannel/AudioChannelService.h @@ -24,21 +24,22 @@ class AudioChannelService , public nsITimerCallback { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER 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. */ static void Shutdown(); /** * Any audio channel agent that starts playing should register itself to @@ -49,29 +50,31 @@ public: /** * Any audio channel agent that stops playing should unregister itself to * this service. */ 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 * or one of its subprocesses. */ 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); /*** * AudioChannelManager calls this function to notify the default channel used * to adjust volume when there is no any active channel. */ virtual void SetDefaultVolumeControlChannel(AudioChannelType aType, @@ -88,18 +91,19 @@ protected: /* Register/Unregister IPC types: */ 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); + 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, bool aElementHidden, bool aElementWasHidden); /* Send the default-volume-channel-changed notification */ void SetDefaultVolumeControlChannelInternal(AudioChannelType aType, bool aHidden, uint64_t aChildID); @@ -122,34 +126,37 @@ protected: AUDIO_CHANNEL_INT_RINGER_HIDDEN, AUDIO_CHANNEL_INT_PUBLICNOTIFICATION, AUDIO_CHANNEL_INT_PUBLICNOTIFICATION_HIDDEN, AUDIO_CHANNEL_INT_LAST }; bool ChannelsActiveWithHigherPriorityThan(AudioChannelInternalType aType); + bool CheckVolumeFadedCondition(AudioChannelInternalType aType, + bool aElementHidden); + const char* ChannelName(AudioChannelType aType); AudioChannelInternalType GetInternalType(AudioChannelType aType, bool aElementHidden); class AudioChannelAgentData { 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 NotifyEnumerator(AudioChannelAgent* aAgent, AudioChannelAgentData* aData, void *aUnused); nsClassHashtable< nsPtrHashKey<AudioChannelAgent>, AudioChannelAgentData > mAgents;
--- a/dom/audiochannel/AudioChannelServiceChild.cpp +++ b/dom/audiochannel/AudioChannelServiceChild.cpp @@ -53,43 +53,43 @@ AudioChannelServiceChild::Shutdown() AudioChannelServiceChild::AudioChannelServiceChild() { } 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); // Update visibility. 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 AudioChannelServiceChild::RegisterAudioChannelAgent(AudioChannelAgent* aAgent, AudioChannelType aType) { MOZ_ASSERT(aType != AUDIO_CHANNEL_DEFAULT);
--- a/dom/audiochannel/AudioChannelServiceChild.h +++ b/dom/audiochannel/AudioChannelServiceChild.h @@ -16,32 +16,35 @@ namespace mozilla { namespace dom { 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(); virtual void RegisterAudioChannelAgent(AudioChannelAgent* aAgent, AudioChannelType aType); 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); protected: AudioChannelServiceChild(); virtual ~AudioChannelServiceChild(); };
--- a/dom/audiochannel/nsIAudioChannelAgent.idl +++ b/dom/audiochannel/nsIAudioChannelAgent.idl @@ -7,48 +7,53 @@ [function, scriptable, uuid(c7227506-5f8e-11e2-8bb3-10bf48d64bd4)] interface nsIAudioChannelAgentCallback : nsISupports { /** * Notified when the playable status of channel is changed. * * @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); }; /** * This interface provides an agent for gecko components to participate * in the audio channel service. Gecko components are responsible for * 1. Indicating what channel type they are using (via the init() member function). * 2. Before playing, checking the playable status of the channel. * 3. Notifying the agent when they start/stop using this channel. * 4. Notifying the agent of changes to the visibility of the component using * this channel. * * The agent will invoke a callback to notify Gecko components of * 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; const long AUDIO_AGENT_CHANNEL_CONTENT = 1; const long AUDIO_AGENT_CHANNEL_NOTIFICATION = 2; const long AUDIO_AGENT_CHANNEL_ALARM = 3; const long AUDIO_AGENT_CHANNEL_TELEPHONY = 4; const long AUDIO_AGENT_CHANNEL_RINGER = 5; const long AUDIO_AGENT_CHANNEL_PUBLICNOTIFICATION = 6; 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. */ readonly attribute long audioChannelType; /** * Initialize the agent with a channel type. * Note: This function should only be called once. @@ -75,22 +80,24 @@ interface nsIAudioChannelAgent : nsISupp /** * Notify the agent that we want to start playing. * Note: Gecko component SHOULD call this function first then start to * play audio stream only when return value is true. * * * @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. * * Note : even if startPlaying() returned false, the agent would still be * registered with the audio channel service and receive callbacks for status changes. * So stopPlaying must still eventually be called to unregister the agent with the * channel service.