12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "AudioChannelService.h"
- #include "base/basictypes.h"
- #include "mozilla/Services.h"
- #include "mozilla/StaticPtr.h"
- #include "mozilla/Unused.h"
- #include "mozilla/dom/ContentChild.h"
- #include "mozilla/dom/ContentParent.h"
- #include "mozilla/dom/TabParent.h"
- #include "nsContentUtils.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsISupportsPrimitives.h"
- #include "nsThreadUtils.h"
- #include "nsHashPropertyBag.h"
- #include "nsComponentManagerUtils.h"
- #include "nsGlobalWindow.h"
- #include "nsPIDOMWindow.h"
- #include "nsServiceManagerUtils.h"
- #include "mozilla/dom/SettingChangeNotificationBinding.h"
- #include "mozilla/Preferences.h"
- using namespace mozilla;
- using namespace mozilla::dom;
- using namespace mozilla::hal;
- namespace {
- // If true, any new AudioChannelAgent will be muted when created.
- bool sAudioChannelMutedByDefault = false;
- bool sAudioChannelCompeting = false;
- bool sAudioChannelCompetingAllAgents = false;
- bool sXPCOMShuttingDown = false;
- class NotifyChannelActiveRunnable final : public Runnable
- {
- public:
- NotifyChannelActiveRunnable(uint64_t aWindowID, AudioChannel aAudioChannel,
- bool aActive)
- : mWindowID(aWindowID)
- , mAudioChannel(aAudioChannel)
- , mActive(aActive)
- {}
- NS_IMETHOD Run() override
- {
- nsCOMPtr<nsIObserverService> observerService =
- services::GetObserverService();
- if (NS_WARN_IF(!observerService)) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsISupportsPRUint64> wrapper =
- do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
- if (NS_WARN_IF(!wrapper)) {
- return NS_ERROR_FAILURE;
- }
- wrapper->SetData(mWindowID);
- nsAutoString name;
- AudioChannelService::GetAudioChannelString(mAudioChannel, name);
- nsAutoCString topic;
- topic.Assign("audiochannel-activity-");
- topic.Append(NS_ConvertUTF16toUTF8(name));
- observerService->NotifyObservers(wrapper, topic.get(),
- mActive
- ? u"active"
- : u"inactive");
- // TODO : remove b2g related event in bug1299390.
- observerService->NotifyObservers(wrapper,
- "media-playback",
- mActive
- ? u"active"
- : u"inactive");
- MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
- ("NotifyChannelActiveRunnable, type = %d, active = %d\n",
- mAudioChannel, mActive));
- return NS_OK;
- }
- private:
- const uint64_t mWindowID;
- const AudioChannel mAudioChannel;
- const bool mActive;
- };
- bool
- IsParentProcess()
- {
- return XRE_GetProcessType() == GeckoProcessType_Default;
- }
- class AudioPlaybackRunnable final : public Runnable
- {
- public:
- AudioPlaybackRunnable(nsPIDOMWindowOuter* aWindow, bool aActive,
- AudioChannelService::AudibleChangedReasons aReason)
- : mWindow(aWindow)
- , mActive(aActive)
- , mReason(aReason)
- {}
- NS_IMETHOD Run() override
- {
- nsCOMPtr<nsIObserverService> observerService =
- services::GetObserverService();
- if (NS_WARN_IF(!observerService)) {
- return NS_ERROR_FAILURE;
- }
- nsAutoString state;
- GetActiveState(state);
- observerService->NotifyObservers(ToSupports(mWindow),
- "audio-playback",
- state.get());
- MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
- ("AudioPlaybackRunnable, active = %d, reason = %d\n",
- mActive, mReason));
- return NS_OK;
- }
- private:
- void GetActiveState(nsAString& astate)
- {
- if (mActive) {
- CopyASCIItoUTF16("active", astate);
- } else {
- if(mReason == AudioChannelService::AudibleChangedReasons::ePauseStateChanged) {
- CopyASCIItoUTF16("inactive-pause", astate);
- } else {
- CopyASCIItoUTF16("inactive-nonaudible", astate);
- }
- }
- }
- nsCOMPtr<nsPIDOMWindowOuter> mWindow;
- bool mActive;
- AudioChannelService::AudibleChangedReasons mReason;
- };
- bool
- IsEnableAudioCompetingForAllAgents()
- {
- // In general, the audio competing should only be for audible media and it
- // helps user can focus on one media at the same time.
- return sAudioChannelCompetingAllAgents;
- }
- } // anonymous namespace
- StaticRefPtr<AudioChannelService> gAudioChannelService;
- // Mappings from 'mozaudiochannel' attribute strings to an enumeration.
- static const nsAttrValue::EnumTable kMozAudioChannelAttributeTable[] = {
- { "normal", (int16_t)AudioChannel::Normal },
- { "content", (int16_t)AudioChannel::Content },
- { "notification", (int16_t)AudioChannel::Notification },
- { "alarm", (int16_t)AudioChannel::Alarm },
- { "telephony", (int16_t)AudioChannel::Telephony },
- { "ringer", (int16_t)AudioChannel::Ringer },
- { "publicnotification", (int16_t)AudioChannel::Publicnotification },
- { "system", (int16_t)AudioChannel::System },
- { nullptr, 0 }
- };
- /* static */ void
- AudioChannelService::CreateServiceIfNeeded()
- {
- MOZ_ASSERT(NS_IsMainThread());
- if (!gAudioChannelService) {
- gAudioChannelService = new AudioChannelService();
- }
- }
- /* static */ already_AddRefed<AudioChannelService>
- AudioChannelService::GetOrCreate()
- {
- if (sXPCOMShuttingDown) {
- return nullptr;
- }
- CreateServiceIfNeeded();
- RefPtr<AudioChannelService> service = gAudioChannelService.get();
- return service.forget();
- }
- /* static */ PRLogModuleInfo*
- AudioChannelService::GetAudioChannelLog()
- {
- static PRLogModuleInfo *gAudioChannelLog;
- if (!gAudioChannelLog) {
- gAudioChannelLog = PR_NewLogModule("AudioChannel");
- }
- return gAudioChannelLog;
- }
- /* static */ void
- AudioChannelService::Shutdown()
- {
- if (gAudioChannelService) {
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->RemoveObserver(gAudioChannelService, "xpcom-shutdown");
- obs->RemoveObserver(gAudioChannelService, "outer-window-destroyed");
- if (IsParentProcess()) {
- obs->RemoveObserver(gAudioChannelService, "ipc:content-shutdown");
- }
- }
- gAudioChannelService->mWindows.Clear();
- gAudioChannelService->mPlayingChildren.Clear();
- gAudioChannelService->mTabParents.Clear();
- gAudioChannelService = nullptr;
- }
- }
- /* static */ bool
- AudioChannelService::IsEnableAudioCompeting()
- {
- CreateServiceIfNeeded();
- return sAudioChannelCompeting;
- }
- NS_INTERFACE_MAP_BEGIN(AudioChannelService)
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAudioChannelService)
- NS_INTERFACE_MAP_ENTRY(nsIAudioChannelService)
- NS_INTERFACE_MAP_ENTRY(nsIObserver)
- NS_INTERFACE_MAP_END
- NS_IMPL_ADDREF(AudioChannelService)
- NS_IMPL_RELEASE(AudioChannelService)
- AudioChannelService::AudioChannelService()
- : mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
- , mTelephonyChannel(false)
- , mContentOrNormalChannel(false)
- , mAnyChannel(false)
- {
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->AddObserver(this, "xpcom-shutdown", false);
- obs->AddObserver(this, "outer-window-destroyed", false);
- if (IsParentProcess()) {
- obs->AddObserver(this, "ipc:content-shutdown", false);
- }
- }
- Preferences::AddBoolVarCache(&sAudioChannelMutedByDefault,
- "dom.audiochannel.mutedByDefault");
- Preferences::AddBoolVarCache(&sAudioChannelCompeting,
- "dom.audiochannel.audioCompeting");
- Preferences::AddBoolVarCache(&sAudioChannelCompetingAllAgents,
- "dom.audiochannel.audioCompeting.allAgents");
- }
- AudioChannelService::~AudioChannelService()
- {
- }
- void
- AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
- AudibleState aAudible)
- {
- MOZ_ASSERT(aAgent);
- uint64_t windowID = aAgent->WindowID();
- AudioChannelWindow* winData = GetWindowData(windowID);
- if (!winData) {
- winData = new AudioChannelWindow(windowID);
- mWindows.AppendElement(winData);
- }
- // To make sure agent would be alive because AppendAgent() would trigger the
- // callback function of AudioChannelAgentOwner that means the agent might be
- // released in their callback.
- RefPtr<AudioChannelAgent> kungFuDeathGrip(aAgent);
- winData->AppendAgent(aAgent, aAudible);
- MaybeSendStatusUpdate();
- }
- void
- AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
- {
- MOZ_ASSERT(aAgent);
- AudioChannelWindow* winData = GetWindowData(aAgent->WindowID());
- if (!winData) {
- return;
- }
- // To make sure agent would be alive because AppendAgent() would trigger the
- // callback function of AudioChannelAgentOwner that means the agent might be
- // released in their callback.
- RefPtr<AudioChannelAgent> kungFuDeathGrip(aAgent);
- winData->RemoveAgent(aAgent);
- MaybeSendStatusUpdate();
- }
- void
- AudioChannelService::RegisterTabParent(TabParent* aTabParent)
- {
- MOZ_ASSERT(aTabParent);
- MOZ_ASSERT(!mTabParents.Contains(aTabParent));
- mTabParents.AppendElement(aTabParent);
- }
- void
- AudioChannelService::UnregisterTabParent(TabParent* aTabParent)
- {
- MOZ_ASSERT(aTabParent);
- mTabParents.RemoveElement(aTabParent);
- }
- AudioPlaybackConfig
- AudioChannelService::GetMediaConfig(nsPIDOMWindowOuter* aWindow,
- uint32_t aAudioChannel) const
- {
- MOZ_ASSERT(!aWindow || aWindow->IsOuterWindow());
- MOZ_ASSERT(aAudioChannel < NUMBER_OF_AUDIO_CHANNELS);
- AudioPlaybackConfig config(1.0, false,
- nsISuspendedTypes::NONE_SUSPENDED);
- if (!aWindow || !aWindow->IsOuterWindow()) {
- config.SetConfig(0.0, true,
- nsISuspendedTypes::SUSPENDED_BLOCK);
- return config;
- }
- AudioChannelWindow* winData = nullptr;
- nsCOMPtr<nsPIDOMWindowOuter> window = aWindow;
- // The volume must be calculated based on the window hierarchy. Here we go up
- // to the top window and we calculate the volume and the muted flag.
- do {
- winData = GetWindowData(window->WindowID());
- if (winData) {
- config.mVolume *= winData->mChannels[aAudioChannel].mVolume;
- config.mMuted = config.mMuted || winData->mChannels[aAudioChannel].mMuted;
- config.mSuspend = winData->mOwningAudioFocus ?
- config.mSuspend : nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE;
- }
- config.mVolume *= window->GetAudioVolume();
- config.mMuted = config.mMuted || window->GetAudioMuted();
- if (window->GetMediaSuspend() != nsISuspendedTypes::NONE_SUSPENDED) {
- config.mSuspend = window->GetMediaSuspend();
- }
- nsCOMPtr<nsPIDOMWindowOuter> win = window->GetScriptableParentOrNull();
- if (!win) {
- break;
- }
- window = do_QueryInterface(win);
- // If there is no parent, or we are the toplevel we don't continue.
- } while (window && window != aWindow);
- return config;
- }
- void
- AudioChannelService::AudioAudibleChanged(AudioChannelAgent* aAgent,
- AudibleState aAudible,
- AudibleChangedReasons aReason)
- {
- MOZ_ASSERT(aAgent);
- uint64_t windowID = aAgent->WindowID();
- AudioChannelWindow* winData = GetWindowData(windowID);
- if (winData) {
- winData->AudioAudibleChanged(aAgent, aAudible, aReason);
- }
- }
- bool
- AudioChannelService::TelephonyChannelIsActive()
- {
- nsTObserverArray<nsAutoPtr<AudioChannelWindow>>::ForwardIterator windowsIter(mWindows);
- while (windowsIter.HasMore()) {
- AudioChannelWindow* next = windowsIter.GetNext();
- if (next->mChannels[(uint32_t)AudioChannel::Telephony].mNumberOfAgents != 0 &&
- !next->mChannels[(uint32_t)AudioChannel::Telephony].mMuted) {
- return true;
- }
- }
- if (IsParentProcess()) {
- nsTObserverArray<nsAutoPtr<AudioChannelChildStatus>>::ForwardIterator
- childrenIter(mPlayingChildren);
- while (childrenIter.HasMore()) {
- AudioChannelChildStatus* child = childrenIter.GetNext();
- if (child->mActiveTelephonyChannel) {
- return true;
- }
- }
- }
- return false;
- }
- bool
- AudioChannelService::ContentOrNormalChannelIsActive()
- {
- // This method is meant to be used just by the child to send status update.
- MOZ_ASSERT(!IsParentProcess());
- nsTObserverArray<nsAutoPtr<AudioChannelWindow>>::ForwardIterator iter(mWindows);
- while (iter.HasMore()) {
- AudioChannelWindow* next = iter.GetNext();
- if (next->mChannels[(uint32_t)AudioChannel::Content].mNumberOfAgents > 0 ||
- next->mChannels[(uint32_t)AudioChannel::Normal].mNumberOfAgents > 0) {
- return true;
- }
- }
- return false;
- }
- AudioChannelService::AudioChannelChildStatus*
- AudioChannelService::GetChildStatus(uint64_t aChildID) const
- {
- nsTObserverArray<nsAutoPtr<AudioChannelChildStatus>>::ForwardIterator
- iter(mPlayingChildren);
- while (iter.HasMore()) {
- AudioChannelChildStatus* child = iter.GetNext();
- if (child->mChildID == aChildID) {
- return child;
- }
- }
- return nullptr;
- }
- void
- AudioChannelService::RemoveChildStatus(uint64_t aChildID)
- {
- nsTObserverArray<nsAutoPtr<AudioChannelChildStatus>>::ForwardIterator
- iter(mPlayingChildren);
- while (iter.HasMore()) {
- nsAutoPtr<AudioChannelChildStatus>& child = iter.GetNext();
- if (child->mChildID == aChildID) {
- mPlayingChildren.RemoveElement(child);
- break;
- }
- }
- }
- bool
- AudioChannelService::ProcessContentOrNormalChannelIsActive(uint64_t aChildID)
- {
- AudioChannelChildStatus* child = GetChildStatus(aChildID);
- if (!child) {
- return false;
- }
- return child->mActiveContentOrNormalChannel;
- }
- bool
- AudioChannelService::AnyAudioChannelIsActive()
- {
- nsTObserverArray<nsAutoPtr<AudioChannelWindow>>::ForwardIterator iter(mWindows);
- while (iter.HasMore()) {
- AudioChannelWindow* next = iter.GetNext();
- for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].tag; ++i) {
- if (next->mChannels[kMozAudioChannelAttributeTable[i].value].mNumberOfAgents
- != 0) {
- return true;
- }
- }
- }
- if (IsParentProcess()) {
- return !mPlayingChildren.IsEmpty();
- }
- return false;
- }
- NS_IMETHODIMP
- AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic,
- const char16_t* aData)
- {
- if (!strcmp(aTopic, "xpcom-shutdown")) {
- sXPCOMShuttingDown = true;
- Shutdown();
- } else if (!strcmp(aTopic, "outer-window-destroyed")) {
- nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
- NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
- uint64_t outerID;
- nsresult rv = wrapper->GetData(&outerID);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- nsAutoPtr<AudioChannelWindow> winData;
- {
- nsTObserverArray<nsAutoPtr<AudioChannelWindow>>::ForwardIterator
- iter(mWindows);
- while (iter.HasMore()) {
- nsAutoPtr<AudioChannelWindow>& next = iter.GetNext();
- if (next->mWindowID == outerID) {
- uint32_t pos = mWindows.IndexOf(next);
- winData = next.forget();
- mWindows.RemoveElementAt(pos);
- break;
- }
- }
- }
- if (winData) {
- nsTObserverArray<AudioChannelAgent*>::ForwardIterator
- iter(winData->mAgents);
- while (iter.HasMore()) {
- iter.GetNext()->WindowVolumeChanged();
- }
- }
- } else if (!strcmp(aTopic, "ipc:content-shutdown")) {
- nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
- if (!props) {
- NS_WARNING("ipc:content-shutdown message without property bag as subject");
- return NS_OK;
- }
- uint64_t childID = 0;
- nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
- &childID);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- if (mDefChannelChildID == childID) {
- SetDefaultVolumeControlChannelInternal(-1, false, childID);
- mDefChannelChildID = CONTENT_PROCESS_ID_UNKNOWN;
- }
- RemoveChildStatus(childID);
- }
- return NS_OK;
- }
- void
- AudioChannelService::RefreshAgentsVolumeAndPropagate(AudioChannel aAudioChannel,
- nsPIDOMWindowOuter* aWindow)
- {
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aWindow->IsOuterWindow());
- nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetScriptableTop();
- if (!topWindow) {
- return;
- }
- AudioChannelWindow* winData = GetWindowData(topWindow->WindowID());
- if (!winData) {
- return;
- }
- for (uint32_t i = 0; i < mTabParents.Length(); ++i) {
- mTabParents[i]->AudioChannelChangeNotification(aWindow, aAudioChannel,
- winData->mChannels[(uint32_t)aAudioChannel].mVolume,
- winData->mChannels[(uint32_t)aAudioChannel].mMuted);
- }
- RefreshAgentsVolume(aWindow);
- }
- void
- AudioChannelService::RefreshAgents(nsPIDOMWindowOuter* aWindow,
- mozilla::function<void(AudioChannelAgent*)> aFunc)
- {
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aWindow->IsOuterWindow());
- nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetScriptableTop();
- if (!topWindow) {
- return;
- }
- AudioChannelWindow* winData = GetWindowData(topWindow->WindowID());
- if (!winData) {
- return;
- }
- nsTObserverArray<AudioChannelAgent*>::ForwardIterator
- iter(winData->mAgents);
- while (iter.HasMore()) {
- aFunc(iter.GetNext());
- }
- }
- void
- AudioChannelService::RefreshAgentsVolume(nsPIDOMWindowOuter* aWindow)
- {
- RefreshAgents(aWindow, [] (AudioChannelAgent* agent) {
- agent->WindowVolumeChanged();
- });
- }
- void
- AudioChannelService::RefreshAgentsSuspend(nsPIDOMWindowOuter* aWindow,
- nsSuspendedTypes aSuspend)
- {
- RefreshAgents(aWindow, [aSuspend] (AudioChannelAgent* agent) {
- agent->WindowSuspendChanged(aSuspend);
- });
- }
- void
- AudioChannelService::SetWindowAudioCaptured(nsPIDOMWindowOuter* aWindow,
- uint64_t aInnerWindowID,
- bool aCapture)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aWindow->IsOuterWindow());
- MOZ_LOG(GetAudioChannelLog(), LogLevel::Debug,
- ("AudioChannelService, SetWindowAudioCaptured, window = %p, "
- "aCapture = %d\n", aWindow, aCapture));
- nsCOMPtr<nsPIDOMWindowOuter> topWindow = aWindow->GetScriptableTop();
- if (!topWindow) {
- return;
- }
- AudioChannelWindow* winData = GetWindowData(topWindow->WindowID());
- // This can happen, but only during shutdown, because the the outer window
- // changes ScriptableTop, so that its ID is different.
- // In this case either we are capturing, and it's too late because the window
- // has been closed anyways, or we are un-capturing, and everything has already
- // been cleaned up by the HTMLMediaElements or the AudioContexts.
- if (!winData) {
- return;
- }
- if (aCapture != winData->mIsAudioCaptured) {
- winData->mIsAudioCaptured = aCapture;
- nsTObserverArray<AudioChannelAgent*>::ForwardIterator
- iter(winData->mAgents);
- while (iter.HasMore()) {
- iter.GetNext()->WindowAudioCaptureChanged(aInnerWindowID, aCapture);
- }
- }
- }
- /* static */ const nsAttrValue::EnumTable*
- AudioChannelService::GetAudioChannelTable()
- {
- return kMozAudioChannelAttributeTable;
- }
- /* static */ AudioChannel
- AudioChannelService::GetAudioChannel(const nsAString& aChannel)
- {
- for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].tag; ++i) {
- if (aChannel.EqualsASCII(kMozAudioChannelAttributeTable[i].tag)) {
- return static_cast<AudioChannel>(kMozAudioChannelAttributeTable[i].value);
- }
- }
- return AudioChannel::Normal;
- }
- /* static */ AudioChannel
- AudioChannelService::GetDefaultAudioChannel()
- {
- nsAutoString audioChannel(Preferences::GetString("media.defaultAudioChannel"));
- if (audioChannel.IsEmpty()) {
- return AudioChannel::Normal;
- }
- for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].tag; ++i) {
- if (audioChannel.EqualsASCII(kMozAudioChannelAttributeTable[i].tag)) {
- return static_cast<AudioChannel>(kMozAudioChannelAttributeTable[i].value);
- }
- }
- return AudioChannel::Normal;
- }
- /* static */ void
- AudioChannelService::GetAudioChannelString(AudioChannel aChannel,
- nsAString& aString)
- {
- aString.AssignASCII("normal");
- for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].tag; ++i) {
- if (aChannel ==
- static_cast<AudioChannel>(kMozAudioChannelAttributeTable[i].value)) {
- aString.AssignASCII(kMozAudioChannelAttributeTable[i].tag);
- break;
- }
- }
- }
- /* static */ void
- AudioChannelService::GetDefaultAudioChannelString(nsAString& aString)
- {
- aString.AssignASCII("normal");
- nsAutoString audioChannel(Preferences::GetString("media.defaultAudioChannel"));
- if (!audioChannel.IsEmpty()) {
- for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].tag; ++i) {
- if (audioChannel.EqualsASCII(kMozAudioChannelAttributeTable[i].tag)) {
- aString = audioChannel;
- break;
- }
- }
- }
- }
- AudioChannelService::AudioChannelWindow*
- AudioChannelService::GetOrCreateWindowData(nsPIDOMWindowOuter* aWindow)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aWindow->IsOuterWindow());
- AudioChannelWindow* winData = GetWindowData(aWindow->WindowID());
- if (!winData) {
- winData = new AudioChannelWindow(aWindow->WindowID());
- mWindows.AppendElement(winData);
- }
- return winData;
- }
- AudioChannelService::AudioChannelWindow*
- AudioChannelService::GetWindowData(uint64_t aWindowID) const
- {
- nsTObserverArray<nsAutoPtr<AudioChannelWindow>>::ForwardIterator
- iter(mWindows);
- while (iter.HasMore()) {
- AudioChannelWindow* next = iter.GetNext();
- if (next->mWindowID == aWindowID) {
- return next;
- }
- }
- return nullptr;
- }
- float
- AudioChannelService::GetAudioChannelVolume(nsPIDOMWindowOuter* aWindow,
- AudioChannel aAudioChannel)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aWindow->IsOuterWindow());
- AudioChannelWindow* winData = GetOrCreateWindowData(aWindow);
- return winData->mChannels[(uint32_t)aAudioChannel].mVolume;
- }
- NS_IMETHODIMP
- AudioChannelService::GetAudioChannelVolume(mozIDOMWindowProxy* aWindow,
- unsigned short aAudioChannel,
- float* aVolume)
- {
- MOZ_ASSERT(NS_IsMainThread());
- auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
- *aVolume = GetAudioChannelVolume(window, (AudioChannel)aAudioChannel);
- return NS_OK;
- }
- void
- AudioChannelService::SetAudioChannelVolume(nsPIDOMWindowOuter* aWindow,
- AudioChannel aAudioChannel,
- float aVolume)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aWindow->IsOuterWindow());
- MOZ_LOG(GetAudioChannelLog(), LogLevel::Debug,
- ("AudioChannelService, SetAudioChannelVolume, window = %p, type = %d, "
- "volume = %f\n", aWindow, aAudioChannel, aVolume));
- AudioChannelWindow* winData = GetOrCreateWindowData(aWindow);
- winData->mChannels[(uint32_t)aAudioChannel].mVolume = aVolume;
- RefreshAgentsVolumeAndPropagate(aAudioChannel, aWindow);
- }
- NS_IMETHODIMP
- AudioChannelService::SetAudioChannelVolume(mozIDOMWindowProxy* aWindow,
- unsigned short aAudioChannel,
- float aVolume)
- {
- MOZ_ASSERT(NS_IsMainThread());
- auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
- SetAudioChannelVolume(window, (AudioChannel)aAudioChannel, aVolume);
- return NS_OK;
- }
- bool
- AudioChannelService::GetAudioChannelMuted(nsPIDOMWindowOuter* aWindow,
- AudioChannel aAudioChannel)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aWindow->IsOuterWindow());
- AudioChannelWindow* winData = GetOrCreateWindowData(aWindow);
- return winData->mChannels[(uint32_t)aAudioChannel].mMuted;
- }
- NS_IMETHODIMP
- AudioChannelService::GetAudioChannelMuted(mozIDOMWindowProxy* aWindow,
- unsigned short aAudioChannel,
- bool* aMuted)
- {
- MOZ_ASSERT(NS_IsMainThread());
- auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
- *aMuted = GetAudioChannelMuted(window, (AudioChannel)aAudioChannel);
- return NS_OK;
- }
- void
- AudioChannelService::SetAudioChannelMuted(nsPIDOMWindowOuter* aWindow,
- AudioChannel aAudioChannel,
- bool aMuted)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aWindow->IsOuterWindow());
- MOZ_LOG(GetAudioChannelLog(), LogLevel::Debug,
- ("AudioChannelService, SetAudioChannelMuted, window = %p, type = %d, "
- "mute = %d\n", aWindow, aAudioChannel, aMuted));
- if (aAudioChannel == AudioChannel::System) {
- // Workaround for bug1183033, system channel type can always playback.
- return;
- }
- AudioChannelWindow* winData = GetOrCreateWindowData(aWindow);
- winData->mChannels[(uint32_t)aAudioChannel].mMuted = aMuted;
- RefreshAgentsVolumeAndPropagate(aAudioChannel, aWindow);
- }
- NS_IMETHODIMP
- AudioChannelService::SetAudioChannelMuted(mozIDOMWindowProxy* aWindow,
- unsigned short aAudioChannel,
- bool aMuted)
- {
- MOZ_ASSERT(NS_IsMainThread());
- auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
- SetAudioChannelMuted(window, (AudioChannel)aAudioChannel, aMuted);
- return NS_OK;
- }
- bool
- AudioChannelService::IsAudioChannelActive(nsPIDOMWindowOuter* aWindow,
- AudioChannel aAudioChannel)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aWindow);
- MOZ_ASSERT(aWindow->IsOuterWindow());
- AudioChannelWindow* winData = GetOrCreateWindowData(aWindow);
- return !!winData->mChannels[(uint32_t)aAudioChannel].mNumberOfAgents;
- }
- NS_IMETHODIMP
- AudioChannelService::IsAudioChannelActive(mozIDOMWindowProxy* aWindow,
- unsigned short aAudioChannel,
- bool* aActive)
- {
- MOZ_ASSERT(NS_IsMainThread());
- auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
- *aActive = IsAudioChannelActive(window, (AudioChannel)aAudioChannel);
- return NS_OK;
- }
- void
- AudioChannelService::SetDefaultVolumeControlChannel(int32_t aChannel,
- bool aVisible)
- {
- SetDefaultVolumeControlChannelInternal(aChannel, aVisible,
- CONTENT_PROCESS_ID_MAIN);
- }
- void
- AudioChannelService::SetDefaultVolumeControlChannelInternal(int32_t aChannel,
- bool aVisible,
- uint64_t aChildID)
- {
- if (!IsParentProcess()) {
- ContentChild* cc = ContentChild::GetSingleton();
- if (cc) {
- cc->SendAudioChannelChangeDefVolChannel(aChannel, aVisible);
- }
- return;
- }
- // If this child is in the background and mDefChannelChildID is set to
- // others then it means other child in the foreground already set it's
- // own default channel.
- if (!aVisible && mDefChannelChildID != aChildID) {
- return;
- }
- // Workaround for the call screen app. The call screen app is running on the
- // main process, that will results in wrong visible state. Because we use the
- // docshell's active state as visible state, the main process is always
- // active. Therefore, we will see the strange situation that the visible
- // state of the call screen is always true. If the mDefChannelChildID is set
- // to others then it means other child in the foreground already set it's
- // own default channel already.
- // Summary :
- // Child process : foreground app always can set type.
- // Parent process : check the mDefChannelChildID.
- else if (aChildID == CONTENT_PROCESS_ID_MAIN &&
- mDefChannelChildID != CONTENT_PROCESS_ID_UNKNOWN) {
- return;
- }
- mDefChannelChildID = aVisible ? aChildID : CONTENT_PROCESS_ID_UNKNOWN;
- nsAutoString channelName;
- if (aChannel == -1) {
- channelName.AssignASCII("unknown");
- } else {
- GetAudioChannelString(static_cast<AudioChannel>(aChannel), channelName);
- }
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->NotifyObservers(nullptr, "default-volume-channel-changed",
- channelName.get());
- }
- }
- void
- AudioChannelService::MaybeSendStatusUpdate()
- {
- if (IsParentProcess()) {
- return;
- }
- bool telephonyChannel = TelephonyChannelIsActive();
- bool contentOrNormalChannel = ContentOrNormalChannelIsActive();
- bool anyChannel = AnyAudioChannelIsActive();
- if (telephonyChannel == mTelephonyChannel &&
- contentOrNormalChannel == mContentOrNormalChannel &&
- anyChannel == mAnyChannel) {
- return;
- }
- mTelephonyChannel = telephonyChannel;
- mContentOrNormalChannel = contentOrNormalChannel;
- mAnyChannel = anyChannel;
- ContentChild* cc = ContentChild::GetSingleton();
- if (cc) {
- cc->SendAudioChannelServiceStatus(telephonyChannel, contentOrNormalChannel,
- anyChannel);
- }
- }
- void
- AudioChannelService::ChildStatusReceived(uint64_t aChildID,
- bool aTelephonyChannel,
- bool aContentOrNormalChannel,
- bool aAnyChannel)
- {
- if (!aAnyChannel) {
- RemoveChildStatus(aChildID);
- return;
- }
- AudioChannelChildStatus* data = GetChildStatus(aChildID);
- if (!data) {
- data = new AudioChannelChildStatus(aChildID);
- mPlayingChildren.AppendElement(data);
- }
- data->mActiveTelephonyChannel = aTelephonyChannel;
- data->mActiveContentOrNormalChannel = aContentOrNormalChannel;
- }
- void
- AudioChannelService::RefreshAgentsAudioFocusChanged(AudioChannelAgent* aAgent)
- {
- MOZ_ASSERT(aAgent);
- nsTObserverArray<nsAutoPtr<AudioChannelWindow>>::ForwardIterator
- iter(mWindows);
- while (iter.HasMore()) {
- AudioChannelWindow* winData = iter.GetNext();
- if (winData->mOwningAudioFocus) {
- winData->AudioFocusChanged(aAgent);
- }
- }
- }
- void
- AudioChannelService::AudioChannelWindow::RequestAudioFocus(AudioChannelAgent* aAgent)
- {
- MOZ_ASSERT(aAgent);
- // Don't need to check audio focus for window-less agent.
- if (!aAgent->Window()) {
- return;
- }
- // We already have the audio focus. No operation is needed.
- if (mOwningAudioFocus) {
- return;
- }
- // Only foreground window can request audio focus, but it would still own the
- // audio focus even it goes to background. Audio focus would be abandoned
- // only when other foreground window starts audio competing.
- // One exception is if the pref "media.block-autoplay-until-in-foreground"
- // is on and the background page is the non-visited before. Because the media
- // in that page would be blocked until the page is going to foreground.
- mOwningAudioFocus = (!(aAgent->Window()->IsBackground()) ||
- aAgent->Window()->GetMediaSuspend() == nsISuspendedTypes::SUSPENDED_BLOCK) ;
- MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
- ("AudioChannelWindow, RequestAudioFocus, this = %p, "
- "agent = %p, owning audio focus = %d\n",
- this, aAgent, mOwningAudioFocus));
- }
- void
- AudioChannelService::AudioChannelWindow::NotifyAudioCompetingChanged(AudioChannelAgent* aAgent)
- {
- // This function may be called after RemoveAgentAndReduceAgentsNum(), so the
- // agent may be not contained in mAgent. In addition, the agent would still
- // be alive because we have kungFuDeathGrip in UnregisterAudioChannelAgent().
- MOZ_ASSERT(aAgent);
- RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
- MOZ_ASSERT(service);
- if (!service->IsEnableAudioCompeting()) {
- return;
- }
- if (!IsAgentInvolvingInAudioCompeting(aAgent)) {
- return;
- }
- MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
- ("AudioChannelWindow, NotifyAudioCompetingChanged, this = %p, "
- "agent = %p\n",
- this, aAgent));
- service->RefreshAgentsAudioFocusChanged(aAgent);
- }
- bool
- AudioChannelService::AudioChannelWindow::IsAgentInvolvingInAudioCompeting(AudioChannelAgent* aAgent) const
- {
- MOZ_ASSERT(aAgent);
- if(!mOwningAudioFocus) {
- return false;
- }
- if (IsAudioCompetingInSameTab()) {
- return false;
- }
- // TODO : add MediaSession::ambient kind, because it doens't interact with
- // other kinds.
- return true;
- }
- bool
- AudioChannelService::AudioChannelWindow::IsAudioCompetingInSameTab() const
- {
- bool hasMultipleActiveAgents = IsEnableAudioCompetingForAllAgents() ?
- mAgents.Length() > 1 : mAudibleAgents.Length() > 1;
- return mOwningAudioFocus && hasMultipleActiveAgents;
- }
- void
- AudioChannelService::AudioChannelWindow::AudioFocusChanged(AudioChannelAgent* aNewPlayingAgent)
- {
- // This agent isn't always known for the current window, because it can comes
- // from other window.
- MOZ_ASSERT(aNewPlayingAgent);
- if (IsInactiveWindow()) {
- // These would happen in two situations,
- // (1) Audio in page A was ended, and another page B want to play audio.
- // Page A should abandon its focus.
- // (2) Audio was paused by remote-control, page should still own the focus.
- mOwningAudioFocus = IsContainingPlayingAgent(aNewPlayingAgent);
- } else {
- nsTObserverArray<AudioChannelAgent*>::ForwardIterator
- iter(IsEnableAudioCompetingForAllAgents() ? mAgents : mAudibleAgents);
- while (iter.HasMore()) {
- AudioChannelAgent* agent = iter.GetNext();
- MOZ_ASSERT(agent);
- // Don't need to update the playing state of new playing agent.
- if (agent == aNewPlayingAgent) {
- continue;
- }
- uint32_t type = GetCompetingBehavior(agent,
- aNewPlayingAgent->AudioChannelType());
- // If window will be suspended, it needs to abandon the audio focus
- // because only one window can own audio focus at a time. However, we
- // would support multiple audio focus at the same time in the future.
- mOwningAudioFocus = (type == nsISuspendedTypes::NONE_SUSPENDED);
- // TODO : support other behaviors which are definded in MediaSession API.
- switch (type) {
- case nsISuspendedTypes::NONE_SUSPENDED:
- case nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE:
- agent->WindowSuspendChanged(type);
- break;
- }
- }
- }
- MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
- ("AudioChannelWindow, AudioFocusChanged, this = %p, "
- "OwningAudioFocus = %d\n", this, mOwningAudioFocus));
- }
- bool
- AudioChannelService::AudioChannelWindow::IsContainingPlayingAgent(AudioChannelAgent* aAgent) const
- {
- return (aAgent->WindowID() == mWindowID);
- }
- uint32_t
- AudioChannelService::AudioChannelWindow::GetCompetingBehavior(AudioChannelAgent* aAgent,
- int32_t aIncomingChannelType) const
- {
- MOZ_ASSERT(aAgent);
- MOZ_ASSERT(IsEnableAudioCompetingForAllAgents() ?
- mAgents.Contains(aAgent) : mAudibleAgents.Contains(aAgent));
- uint32_t competingBehavior = nsISuspendedTypes::NONE_SUSPENDED;
- int32_t presentChannelType = aAgent->AudioChannelType();
- // TODO : add other competing cases for MediaSession API
- if (presentChannelType == int32_t(AudioChannel::Normal) &&
- aIncomingChannelType == int32_t(AudioChannel::Normal)) {
- competingBehavior = nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE;
- }
- MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
- ("AudioChannelWindow, GetCompetingBehavior, this = %p, "
- "present type = %d, incoming channel = %d, behavior = %d\n",
- this, presentChannelType, aIncomingChannelType, competingBehavior));
- return competingBehavior;
- }
- /* static */ bool
- AudioChannelService::IsAudioChannelMutedByDefault()
- {
- CreateServiceIfNeeded();
- return sAudioChannelMutedByDefault;
- }
- void
- AudioChannelService::AudioChannelWindow::AppendAgent(AudioChannelAgent* aAgent,
- AudibleState aAudible)
- {
- MOZ_ASSERT(aAgent);
- RequestAudioFocus(aAgent);
- AppendAgentAndIncreaseAgentsNum(aAgent);
- AudioCapturedChanged(aAgent, AudioCaptureState::eCapturing);
- if (aAudible == AudibleState::eAudible) {
- AudioAudibleChanged(aAgent,
- AudibleState::eAudible,
- AudibleChangedReasons::eDataAudibleChanged);
- } else if (IsEnableAudioCompetingForAllAgents() &&
- aAudible != AudibleState::eAudible) {
- NotifyAudioCompetingChanged(aAgent);
- }
- }
- void
- AudioChannelService::AudioChannelWindow::RemoveAgent(AudioChannelAgent* aAgent)
- {
- MOZ_ASSERT(aAgent);
- RemoveAgentAndReduceAgentsNum(aAgent);
- AudioCapturedChanged(aAgent, AudioCaptureState::eNotCapturing);
- AudioAudibleChanged(aAgent,
- AudibleState::eNotAudible,
- AudibleChangedReasons::ePauseStateChanged);
- }
- void
- AudioChannelService::AudioChannelWindow::AppendAgentAndIncreaseAgentsNum(AudioChannelAgent* aAgent)
- {
- MOZ_ASSERT(aAgent);
- MOZ_ASSERT(!mAgents.Contains(aAgent));
- int32_t channel = aAgent->AudioChannelType();
- mAgents.AppendElement(aAgent);
- ++mChannels[channel].mNumberOfAgents;
- // The first one, we must inform the BrowserElementAudioChannel.
- if (mChannels[channel].mNumberOfAgents == 1) {
- NotifyChannelActive(aAgent->WindowID(),
- static_cast<AudioChannel>(channel),
- true);
- }
- }
- void
- AudioChannelService::AudioChannelWindow::RemoveAgentAndReduceAgentsNum(AudioChannelAgent* aAgent)
- {
- MOZ_ASSERT(aAgent);
- MOZ_ASSERT(mAgents.Contains(aAgent));
- int32_t channel = aAgent->AudioChannelType();
- mAgents.RemoveElement(aAgent);
- MOZ_ASSERT(mChannels[channel].mNumberOfAgents > 0);
- --mChannels[channel].mNumberOfAgents;
- if (mChannels[channel].mNumberOfAgents == 0) {
- NotifyChannelActive(aAgent->WindowID(),
- static_cast<AudioChannel>(channel),
- false);
- }
- }
- void
- AudioChannelService::AudioChannelWindow::AudioCapturedChanged(AudioChannelAgent* aAgent,
- AudioCaptureState aCapture)
- {
- MOZ_ASSERT(aAgent);
- if (mIsAudioCaptured) {
- aAgent->WindowAudioCaptureChanged(aAgent->InnerWindowID(), aCapture);
- }
- }
- void
- AudioChannelService::AudioChannelWindow::AudioAudibleChanged(AudioChannelAgent* aAgent,
- AudibleState aAudible,
- AudibleChangedReasons aReason)
- {
- MOZ_ASSERT(aAgent);
- if (aAudible == AudibleState::eAudible) {
- AppendAudibleAgentIfNotContained(aAgent, aReason);
- } else {
- RemoveAudibleAgentIfContained(aAgent, aReason);
- }
- if (aAudible == AudibleState::eAudible) {
- NotifyAudioCompetingChanged(aAgent);
- } else if (aAudible != AudibleState::eNotAudible) {
- MaybeNotifyMediaBlocked(aAgent);
- }
- }
- void
- AudioChannelService::AudioChannelWindow::AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent,
- AudibleChangedReasons aReason)
- {
- MOZ_ASSERT(aAgent);
- MOZ_ASSERT(mAgents.Contains(aAgent));
- if (!mAudibleAgents.Contains(aAgent)) {
- mAudibleAgents.AppendElement(aAgent);
- if (IsFirstAudibleAgent()) {
- NotifyAudioAudibleChanged(aAgent->Window(), AudibleState::eAudible, aReason);
- }
- }
- }
- void
- AudioChannelService::AudioChannelWindow::RemoveAudibleAgentIfContained(AudioChannelAgent* aAgent,
- AudibleChangedReasons aReason)
- {
- MOZ_ASSERT(aAgent);
- if (mAudibleAgents.Contains(aAgent)) {
- mAudibleAgents.RemoveElement(aAgent);
- if (IsLastAudibleAgent()) {
- NotifyAudioAudibleChanged(aAgent->Window(), AudibleState::eNotAudible, aReason);
- }
- }
- }
- bool
- AudioChannelService::AudioChannelWindow::IsFirstAudibleAgent() const
- {
- return (mAudibleAgents.Length() == 1);
- }
- bool
- AudioChannelService::AudioChannelWindow::IsLastAudibleAgent() const
- {
- return mAudibleAgents.IsEmpty();
- }
- bool
- AudioChannelService::AudioChannelWindow::IsInactiveWindow() const
- {
- return IsEnableAudioCompetingForAllAgents() ?
- mAudibleAgents.IsEmpty() && mAgents.IsEmpty() : mAudibleAgents.IsEmpty();
- }
- void
- AudioChannelService::AudioChannelWindow::NotifyAudioAudibleChanged(nsPIDOMWindowOuter* aWindow,
- AudibleState aAudible,
- AudibleChangedReasons aReason)
- {
- RefPtr<AudioPlaybackRunnable> runnable =
- new AudioPlaybackRunnable(aWindow,
- aAudible == AudibleState::eAudible,
- aReason);
- DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(runnable);
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
- }
- void
- AudioChannelService::AudioChannelWindow::NotifyChannelActive(uint64_t aWindowID,
- AudioChannel aChannel,
- bool aActive)
- {
- RefPtr<NotifyChannelActiveRunnable> runnable =
- new NotifyChannelActiveRunnable(aWindowID, aChannel, aActive);
- DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(runnable);
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
- }
- void
- AudioChannelService::AudioChannelWindow::MaybeNotifyMediaBlocked(AudioChannelAgent* aAgent)
- {
- nsCOMPtr<nsPIDOMWindowOuter> window = aAgent->Window();
- if (!window) {
- return;
- }
- MOZ_ASSERT(window->IsOuterWindow());
- if (window->GetMediaSuspend() != nsISuspendedTypes::SUSPENDED_BLOCK) {
- return;
- }
- NS_DispatchToCurrentThread(NS_NewRunnableFunction([window] () -> void {
- nsCOMPtr<nsIObserverService> observerService =
- services::GetObserverService();
- if (NS_WARN_IF(!observerService)) {
- return;
- }
- observerService->NotifyObservers(ToSupports(window),
- "audio-playback",
- u"block");
- })
- );
- }
|