summaryrefslogtreecommitdiffstats
path: root/dom/speakermanager/SpeakerManagerService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/speakermanager/SpeakerManagerService.cpp')
-rw-r--r--dom/speakermanager/SpeakerManagerService.cpp224
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);
+}