From 8aabe3c0d142230613393a917c68638c30df7543 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 10 Jul 2015 17:38:46 +0100 Subject: [PATCH] Bug 1113086 - AudioChannel policy in Browser API - patch 2 - IPC communication between AudioChannelServices, r=ehsan --- dom/audiochannel/AudioChannelService.cpp | 126 ++++++++++++++++++++--- dom/audiochannel/AudioChannelService.h | 37 +++++++ dom/ipc/ContentParent.cpp | 14 +++ dom/ipc/ContentParent.h | 5 + dom/ipc/PContent.ipdl | 4 + 5 files changed, 172 insertions(+), 14 deletions(-) diff --git a/dom/audiochannel/AudioChannelService.cpp b/dom/audiochannel/AudioChannelService.cpp index 6ce82c4315e..253ff3a7f57 100644 --- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -85,6 +85,12 @@ GetTopWindow(nsIDOMWindow* aWindow) return window.forget(); } +bool +IsParentProcess() +{ + return XRE_GetProcessType() == GeckoProcessType_Default; +} + } // anonymous namespace StaticRefPtr gAudioChannelService; @@ -118,7 +124,7 @@ void AudioChannelService::Shutdown() { if (gAudioChannelService) { - if (XRE_GetProcessType() == GeckoProcessType_Default) { + if (IsParentProcess()) { nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { obs->RemoveObserver(gAudioChannelService, "ipc:content-shutdown"); @@ -147,8 +153,11 @@ NS_IMPL_RELEASE(AudioChannelService) AudioChannelService::AudioChannelService() : mDisabled(false) , mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN) + , mTelephonyChannel(false) + , mContentOrNormalChannel(false) + , mAnyChannel(false) { - if (XRE_IsParentProcess()) { + if (IsParentProcess()) { nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { obs->AddObserver(this, "ipc:content-shutdown", false); @@ -199,6 +208,8 @@ AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent, NS_LITERAL_STRING("active").get()); } } + + MaybeSendStatusUpdate(); } void @@ -244,6 +255,8 @@ AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent) NS_LITERAL_STRING("inactive").get()); } } + + MaybeSendStatusUpdate(); } void @@ -296,33 +309,68 @@ AudioChannelService::TelephonyChannelIsActiveEnumerator( bool* isActive = static_cast(aPtr); *isActive = aWinData->mChannels[(uint32_t)AudioChannel::Telephony].mNumberOfAgents != 0 && - !aWinData->mChannels[(uint32_t)AudioChannel::Telephony].mMuted; + !aWinData->mChannels[(uint32_t)AudioChannel::Telephony].mMuted; + return *isActive ? PL_DHASH_STOP : PL_DHASH_NEXT; +} + +PLDHashOperator +AudioChannelService::TelephonyChannelIsActiveInChildrenEnumerator( + const uint64_t& aChildID, + nsAutoPtr& aData, + void* aPtr) +{ + bool* isActive = static_cast(aPtr); + *isActive = aData->mActiveTelephonyChannel; return *isActive ? PL_DHASH_STOP : PL_DHASH_NEXT; } bool AudioChannelService::TelephonyChannelIsActive() { - // TODO: no child process check. - bool active = false; mWindows.Enumerate(TelephonyChannelIsActiveEnumerator, &active); + + if (!active && IsParentProcess()) { + mPlayingChildren.Enumerate(TelephonyChannelIsActiveInChildrenEnumerator, + &active); + } + + return active; +} + +PLDHashOperator +AudioChannelService::ContentOrNormalChannelIsActiveEnumerator( + const uint64_t& aWindowID, + nsAutoPtr& aWinData, + void* aPtr) +{ + bool* isActive = static_cast(aPtr); + *isActive = + aWinData->mChannels[(uint32_t)AudioChannel::Content].mNumberOfAgents > 0 || + aWinData->mChannels[(uint32_t)AudioChannel::Normal].mNumberOfAgents > 0; + return *isActive ? PL_DHASH_STOP : PL_DHASH_NEXT; +} + +bool +AudioChannelService::ContentOrNormalChannelIsActive() +{ + // This method is meant to be used just by the child to send status update. + MOZ_ASSERT(!IsParentProcess()); + + bool active = false; + mWindows.Enumerate(ContentOrNormalChannelIsActiveEnumerator, &active); return active; } bool AudioChannelService::ProcessContentOrNormalChannelIsActive(uint64_t aChildID) { -/* TODO - AudioChannelChildData* data; - if (!mData.Get(aChildID, &data)) { + AudioChannelChildStatus* status = mPlayingChildren.Get(aChildID); + if (!status) { return false; } - return data->mChannels[(uint32_t)AudioChannel::Content].mNumberOfAgents != 0 || - data->mChannels[(uint32_t)AudioChannel::Normal].mNumberOfAgents != 0; -*/ - return true; + return status->mActiveContentOrNormalChannel; } PLDHashOperator @@ -346,9 +394,13 @@ AudioChannelService::AnyAudioChannelIsActiveEnumerator( bool AudioChannelService::AnyAudioChannelIsActive() { - // TODO: no child process check. bool active = false; mWindows.Enumerate(AnyAudioChannelIsActiveEnumerator, &active); + + if (!active && IsParentProcess()) { + active = !!mPlayingChildren.Count(); + } + return active; } @@ -441,6 +493,8 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, SetDefaultVolumeControlChannelInternal(-1, false, childID); mDefChannelChildID = CONTENT_PROCESS_ID_UNKNOWN; } + + mPlayingChildren.Remove(childID); } return NS_OK; @@ -680,7 +734,7 @@ AudioChannelService::SetDefaultVolumeControlChannelInternal(int32_t aChannel, bool aVisible, uint64_t aChildID) { - if (XRE_GetProcessType() != GeckoProcessType_Default) { + if (!IsParentProcess()) { ContentChild* cc = ContentChild::GetSingleton(); if (cc) { cc->SendAudioChannelChangeDefVolChannel(aChannel, aVisible); @@ -727,6 +781,50 @@ AudioChannelService::SetDefaultVolumeControlChannelInternal(int32_t aChannel, } } +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) { + mPlayingChildren.Remove(aChildID); + return; + } + + AudioChannelChildStatus* data = mPlayingChildren.LookupOrAdd(aChildID); + data->mActiveTelephonyChannel = aTelephonyChannel; + data->mActiveContentOrNormalChannel = aContentOrNormalChannel; +} + /* static */ PLDHashOperator AudioChannelService::NotifyEnumerator(AudioChannelAgent* aAgent, AudioChannel* aAudioChannel, diff --git a/dom/audiochannel/AudioChannelService.h b/dom/audiochannel/AudioChannelService.h index 2ff391a9365..2b9d10c63d6 100644 --- a/dom/audiochannel/AudioChannelService.h +++ b/dom/audiochannel/AudioChannelService.h @@ -127,10 +127,17 @@ public: void Notify(uint64_t aWindowID); + void ChildStatusReceived(uint64_t aChildID, bool aTelephonyChannel, + bool aContentOrNormalChannel, bool aAnyChannel); + private: AudioChannelService(); ~AudioChannelService(); + void MaybeSendStatusUpdate(); + + bool ContentOrNormalChannelIsActive(); + /* Send the default-volume-channel-changed notification */ void SetDefaultVolumeControlChannelInternal(int32_t aChannel, bool aVisible, uint64_t aChildID); @@ -163,6 +170,12 @@ private: nsAutoPtr& aWinData, void *aPtr); + static PLDHashOperator + ContentOrNormalChannelIsActiveEnumerator( + const uint64_t& aWindowID, + nsAutoPtr& aWinData, + void *aPtr); + static PLDHashOperator AnyAudioChannelIsActiveEnumerator(const uint64_t& aWindowID, nsAutoPtr& aWinData, @@ -180,6 +193,24 @@ private: nsClassHashtable mWindows; + struct AudioChannelChildStatus final { + AudioChannelChildStatus() + : mActiveTelephonyChannel(false) + , mActiveContentOrNormalChannel(false) + {} + + bool mActiveTelephonyChannel; + bool mActiveContentOrNormalChannel; + }; + + static PLDHashOperator + TelephonyChannelIsActiveInChildrenEnumerator( + const uint64_t& aChildID, + nsAutoPtr& aData, + void *aPtr); + + nsClassHashtable mPlayingChildren; + #ifdef MOZ_WIDGET_GONK nsTArray mSpeakerManager; #endif @@ -190,6 +221,12 @@ private: uint64_t mDefChannelChildID; + // These boolean are used to know if we have to send an status update to the + // service running in the main process. + bool mTelephonyChannel; + bool mContentOrNormalChannel; + bool mAnyChannel; + // This is needed for IPC comunication between // AudioChannelServiceChild and this class. friend class ContentParent; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index b306e0c4e04..aecace1223c 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2802,6 +2802,20 @@ ContentParent::RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel, return true; } +bool +ContentParent::RecvAudioChannelServiceStatus( + const bool& aTelephonyChannel, + const bool& aContentOrNormalChannel, + const bool& aAnyChannel) +{ + nsRefPtr service = AudioChannelService::GetOrCreate(); + MOZ_ASSERT(service); + + service->ChildStatusReceived(mChildID, aTelephonyChannel, + aContentOrNormalChannel, aAnyChannel); + return true; +} + bool ContentParent::RecvDataStoreGetStores( const nsString& aName, diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 506798625ed..9404a245602 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -754,6 +754,11 @@ private: virtual bool RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel, const bool& aHidden) override; + + virtual bool RecvAudioChannelServiceStatus(const bool& aTelephonyChannel, + const bool& aContentOrNormalChannel, + const bool& aAnyChannel) override; + virtual bool RecvGetSystemMemory(const uint64_t& getterId) override; virtual bool RecvGetLookAndFeelCache(nsTArray&& aLookAndFeelIntCache) override; diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 35a34c7c4a5..78293fb2c0c 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -863,6 +863,10 @@ parent: // Tell the parent that the child has gone idle for the first time async FirstIdle(); + async AudioChannelServiceStatus(bool aActiveTelephonyChannel, + bool aContentOrNormalChannel, + bool aAnyActiveChannel); + async AudioChannelChangeDefVolChannel(int32_t aChannel, bool aHidden); sync DataStoreGetStores(nsString aName, nsString aOwner, Principal aPrincipal)