summaryrefslogtreecommitdiff
path: root/dom/speakermanager/SpeakerManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/speakermanager/SpeakerManager.cpp')
-rw-r--r--dom/speakermanager/SpeakerManager.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/dom/speakermanager/SpeakerManager.cpp b/dom/speakermanager/SpeakerManager.cpp
new file mode 100644
index 0000000000..2b30fa72c8
--- /dev/null
+++ b/dom/speakermanager/SpeakerManager.cpp
@@ -0,0 +1,217 @@
+/* -*- 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 "SpeakerManager.h"
+
+#include "mozilla/Services.h"
+
+#include "mozilla/dom/Event.h"
+
+#include "AudioChannelService.h"
+#include "nsIDocShell.h"
+#include "nsIDOMClassInfo.h"
+#include "nsIDOMEventListener.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIPermissionManager.h"
+#include "SpeakerManagerService.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_QUERY_INTERFACE_INHERITED(SpeakerManager, DOMEventTargetHelper,
+ nsIDOMEventListener)
+NS_IMPL_ADDREF_INHERITED(SpeakerManager, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(SpeakerManager, DOMEventTargetHelper)
+
+SpeakerManager::SpeakerManager()
+ : mForcespeaker(false)
+ , mVisible(false)
+{
+ SpeakerManagerService *service =
+ SpeakerManagerService::GetOrCreateSpeakerManagerService();
+ MOZ_ASSERT(service);
+ service->RegisterSpeakerManager(this);
+}
+
+SpeakerManager::~SpeakerManager()
+{
+ SpeakerManagerService *service = SpeakerManagerService::GetOrCreateSpeakerManagerService();
+ MOZ_ASSERT(service);
+
+ service->UnRegisterSpeakerManager(this);
+ nsCOMPtr<EventTarget> target = do_QueryInterface(GetOwner());
+ NS_ENSURE_TRUE_VOID(target);
+
+ target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
+ this,
+ /* useCapture = */ true);
+}
+
+bool
+SpeakerManager::Speakerforced()
+{
+ // If a background app calls forcespeaker=true that doesn't change anything.
+ // 'speakerforced' remains false everywhere.
+ if (mForcespeaker && !mVisible) {
+ return false;
+ }
+ SpeakerManagerService *service = SpeakerManagerService::GetOrCreateSpeakerManagerService();
+ MOZ_ASSERT(service);
+ return service->GetSpeakerStatus();
+
+}
+
+bool
+SpeakerManager::Forcespeaker()
+{
+ return mForcespeaker;
+}
+
+void
+SpeakerManager::SetForcespeaker(bool aEnable)
+{
+ SpeakerManagerService *service = SpeakerManagerService::GetOrCreateSpeakerManagerService();
+ MOZ_ASSERT(service);
+
+ service->ForceSpeaker(aEnable, mVisible);
+ mForcespeaker = aEnable;
+}
+
+void
+SpeakerManager::DispatchSimpleEvent(const nsAString& aStr)
+{
+ MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
+ nsresult rv = CheckInnerWindowCorrectness();
+ if (NS_FAILED(rv)) {
+ return;
+ }
+
+ RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
+ event->InitEvent(aStr, false, false);
+ event->SetTrusted(true);
+
+ rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+ if (NS_FAILED(rv)) {
+ NS_ERROR("Failed to dispatch the event!!!");
+ return;
+ }
+}
+
+void
+SpeakerManager::Init(nsPIDOMWindowInner* aWindow)
+{
+ BindToOwner(aWindow);
+
+ nsCOMPtr<nsIDocShell> docshell = GetOwner()->GetDocShell();
+ NS_ENSURE_TRUE_VOID(docshell);
+ docshell->GetIsActive(&mVisible);
+
+ nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
+ NS_ENSURE_TRUE_VOID(target);
+
+ target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
+ this,
+ /* useCapture = */ true,
+ /* wantsUntrusted = */ false);
+}
+
+nsPIDOMWindowInner*
+SpeakerManager::GetParentObject() const
+{
+ return GetOwner();
+}
+
+/* static */ already_AddRefed<SpeakerManager>
+SpeakerManager::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+ nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.GetAsSupports());
+ if (!sgo) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ nsCOMPtr<nsPIDOMWindowInner> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
+ if (!ownerWindow) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
+ NS_ENSURE_TRUE(permMgr, nullptr);
+
+ uint32_t permission = nsIPermissionManager::DENY_ACTION;
+ nsresult rv =
+ permMgr->TestPermissionFromWindow(ownerWindow, "speaker-control",
+ &permission);
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ if (permission != nsIPermissionManager::ALLOW_ACTION) {
+ aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return nullptr;
+ }
+
+ RefPtr<SpeakerManager> object = new SpeakerManager();
+ object->Init(ownerWindow);
+ return object.forget();
+}
+
+JSObject*
+SpeakerManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return MozSpeakerManagerBinding::Wrap(aCx, this, aGivenProto);
+}
+
+NS_IMETHODIMP
+SpeakerManager::HandleEvent(nsIDOMEvent* aEvent)
+{
+ nsAutoString type;
+ aEvent->GetType(type);
+
+ if (!type.EqualsLiteral("visibilitychange")) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
+ NS_ENSURE_TRUE(docshell, NS_ERROR_FAILURE);
+ docshell->GetIsActive(&mVisible);
+
+ // If an app that has called forcespeaker=true is switched
+ // from the background to the foreground 'speakerforced'
+ // switches to true in all apps. I.e. the app doesn't have to
+ // call forcespeaker=true again when it comes into foreground.
+ SpeakerManagerService *service =
+ SpeakerManagerService::GetOrCreateSpeakerManagerService();
+ MOZ_ASSERT(service);
+
+ if (mVisible && mForcespeaker) {
+ service->ForceSpeaker(mForcespeaker, mVisible);
+ }
+ // If an application that has called forcespeaker=true, but no audio is
+ // currently playing in the app itself, if application switch to
+ // the background, we switch 'speakerforced' to false.
+ if (!mVisible && mForcespeaker) {
+ RefPtr<AudioChannelService> audioChannelService =
+ AudioChannelService::GetOrCreate();
+ if (audioChannelService && !audioChannelService->AnyAudioChannelIsActive()) {
+ service->ForceSpeaker(false, mVisible);
+ }
+ }
+ return NS_OK;
+}
+
+void
+SpeakerManager::SetAudioChannelActive(bool isActive)
+{
+ if (mForcespeaker) {
+ SpeakerManagerService *service =
+ SpeakerManagerService::GetOrCreateSpeakerManagerService();
+ MOZ_ASSERT(service);
+ service->ForceSpeaker(isActive, mVisible);
+ }
+}
+
+} // namespace dom
+} // namespace mozilla