mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
225 lines
6.3 KiB
C++
225 lines
6.3 KiB
C++
/* -*- 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);
|
|
}
|