diff options
Diffstat (limited to 'dom/speakermanager/SpeakerManagerService.cpp')
-rw-r--r-- | dom/speakermanager/SpeakerManagerService.cpp | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/dom/speakermanager/SpeakerManagerService.cpp b/dom/speakermanager/SpeakerManagerService.cpp new file mode 100644 index 000000000..a444f7163 --- /dev/null +++ b/dom/speakermanager/SpeakerManagerService.cpp @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "SpeakerManagerService.h" +#include "SpeakerManagerServiceChild.h" +#include "mozilla/Services.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/Unused.h" +#include "mozilla/dom/ContentParent.h" +#include "nsIPropertyBag2.h" +#include "nsThreadUtils.h" +#include "nsServiceManagerUtils.h" +#include "AudioChannelService.h" +#include <cutils/properties.h> + +#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1" +#include "nsIAudioManager.h" + +using namespace mozilla; +using namespace mozilla::dom; + +StaticRefPtr<SpeakerManagerService> gSpeakerManagerService; + +// static +SpeakerManagerService* +SpeakerManagerService::GetOrCreateSpeakerManagerService() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!XRE_IsParentProcess()) { + return SpeakerManagerServiceChild::GetOrCreateSpeakerManagerService(); + } + + // If we already exist, exit early + if (gSpeakerManagerService) { + return gSpeakerManagerService; + } + + // Create new instance, register, return + RefPtr<SpeakerManagerService> service = new SpeakerManagerService(); + + gSpeakerManagerService = service; + + return gSpeakerManagerService; +} + +SpeakerManagerService* +SpeakerManagerService::GetSpeakerManagerService() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!XRE_IsParentProcess()) { + return SpeakerManagerServiceChild::GetSpeakerManagerService(); + } + + return gSpeakerManagerService; +} + +void +SpeakerManagerService::Shutdown() +{ + if (!XRE_IsParentProcess()) { + return SpeakerManagerServiceChild::Shutdown(); + } + + if (gSpeakerManagerService) { + gSpeakerManagerService = nullptr; + } +} + +NS_IMPL_ISUPPORTS(SpeakerManagerService, nsIObserver) + +void +SpeakerManagerService::ForceSpeaker(bool aEnable, uint64_t aChildId) +{ + TurnOnSpeaker(aEnable); + if (aEnable) { + mSpeakerStatusSet.Put(aChildId); + } + Notify(); + return; +} + +void +SpeakerManagerService::ForceSpeaker(bool aEnable, bool aVisible) +{ + // b2g main process without oop + TurnOnSpeaker(aEnable && aVisible); + mVisible = aVisible; + mOrgSpeakerStatus = aEnable; + Notify(); +} + +void +SpeakerManagerService::TurnOnSpeaker(bool aOn) +{ + nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID); + NS_ENSURE_TRUE_VOID(audioManager); + int32_t phoneState; + audioManager->GetPhoneState(&phoneState); + int32_t forceuse = (phoneState == nsIAudioManager::PHONE_STATE_IN_CALL || + phoneState == nsIAudioManager::PHONE_STATE_IN_COMMUNICATION) + ? nsIAudioManager::USE_COMMUNICATION : nsIAudioManager::USE_MEDIA; + if (aOn) { + audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_SPEAKER); + } else { + audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_NONE); + } +} + +bool +SpeakerManagerService::GetSpeakerStatus() +{ + char propQemu[PROPERTY_VALUE_MAX]; + property_get("ro.kernel.qemu", propQemu, ""); + if (!strncmp(propQemu, "1", 1)) { + return mOrgSpeakerStatus; + } + nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID); + NS_ENSURE_TRUE(audioManager, false); + int32_t usage; + audioManager->GetForceForUse(nsIAudioManager::USE_MEDIA, &usage); + return usage == nsIAudioManager::FORCE_SPEAKER; +} + +void +SpeakerManagerService::Notify() +{ + // Parent Notify to all the child processes. + nsTArray<ContentParent*> children; + ContentParent::GetAll(children); + for (uint32_t i = 0; i < children.Length(); i++) { + Unused << children[i]->SendSpeakerManagerNotify(); + } + + for (uint32_t i = 0; i < mRegisteredSpeakerManagers.Length(); i++) { + mRegisteredSpeakerManagers[i]-> + DispatchSimpleEvent(NS_LITERAL_STRING("speakerforcedchange")); + } +} + +void +SpeakerManagerService::SetAudioChannelActive(bool aIsActive) +{ + if (!aIsActive && !mVisible) { + ForceSpeaker(!mOrgSpeakerStatus, mVisible); + } +} + +NS_IMETHODIMP +SpeakerManagerService::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) +{ + 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_SUCCEEDED(rv)) { + // If the audio has paused by audiochannel, + // the enable flag should be false and don't need to handle. + if (mSpeakerStatusSet.Contains(childID)) { + TurnOnSpeaker(false); + mSpeakerStatusSet.Remove(childID); + } + if (mOrgSpeakerStatus) { + TurnOnSpeaker(!mOrgSpeakerStatus); + mOrgSpeakerStatus = false; + } + } else { + NS_WARNING("ipc:content-shutdown message without childID property"); + } + } else if (!strcmp(aTopic, "xpcom-will-shutdown")) { + // Note that we need to do this before xpcom-shutdown, since the + // AudioChannelService cannot be used past that point. + RefPtr<AudioChannelService> audioChannelService = + AudioChannelService::GetOrCreate(); + if (audioChannelService) { + audioChannelService->UnregisterSpeakerManager(this); + } + + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->RemoveObserver(this, "ipc:content-shutdown"); + obs->RemoveObserver(this, "xpcom-will-shutdown"); + } + + Shutdown(); + } + return NS_OK; +} + +SpeakerManagerService::SpeakerManagerService() + : mOrgSpeakerStatus(false), + mVisible(false) +{ + MOZ_COUNT_CTOR(SpeakerManagerService); + if (XRE_IsParentProcess()) { + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(this, "ipc:content-shutdown", false); + obs->AddObserver(this, "xpcom-will-shutdown", false); + } + } + RefPtr<AudioChannelService> audioChannelService = + AudioChannelService::GetOrCreate(); + if (audioChannelService) { + audioChannelService->RegisterSpeakerManager(this); + } +} + +SpeakerManagerService::~SpeakerManagerService() +{ + MOZ_COUNT_DTOR(SpeakerManagerService); +} |