michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "SpeakerManagerService.h" michael@0: #include "SpeakerManagerServiceChild.h" michael@0: #include "mozilla/Services.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: #include "mozilla/unused.h" michael@0: #include "mozilla/dom/ContentParent.h" michael@0: #include "nsIPropertyBag2.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "AudioChannelService.h" michael@0: #include michael@0: michael@0: #define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1" michael@0: #include "nsIAudioManager.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: StaticRefPtr gSpeakerManagerService; michael@0: michael@0: // static michael@0: SpeakerManagerService* michael@0: SpeakerManagerService::GetSpeakerManagerService() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (XRE_GetProcessType() != GeckoProcessType_Default) { michael@0: return SpeakerManagerServiceChild::GetSpeakerManagerService(); michael@0: } michael@0: michael@0: // If we already exist, exit early michael@0: if (gSpeakerManagerService) { michael@0: return gSpeakerManagerService; michael@0: } michael@0: michael@0: // Create new instance, register, return michael@0: nsRefPtr service = new SpeakerManagerService(); michael@0: NS_ENSURE_TRUE(service, nullptr); michael@0: michael@0: gSpeakerManagerService = service; michael@0: return gSpeakerManagerService; michael@0: } michael@0: michael@0: void michael@0: SpeakerManagerService::Shutdown() michael@0: { michael@0: if (XRE_GetProcessType() != GeckoProcessType_Default) { michael@0: return SpeakerManagerServiceChild::Shutdown(); michael@0: } michael@0: michael@0: if (gSpeakerManagerService) { michael@0: gSpeakerManagerService = nullptr; michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(SpeakerManagerService, nsIObserver) michael@0: michael@0: void michael@0: SpeakerManagerService::ForceSpeaker(bool aEnable, uint64_t aChildId) michael@0: { michael@0: TuruOnSpeaker(aEnable); michael@0: if (aEnable) { michael@0: mSpeakerStatusSet.Put(aChildId); michael@0: } michael@0: Notify(); michael@0: return; michael@0: } michael@0: michael@0: void michael@0: SpeakerManagerService::ForceSpeaker(bool aEnable, bool aVisible) michael@0: { michael@0: // b2g main process without oop michael@0: TuruOnSpeaker(aEnable && aVisible); michael@0: mVisible = aVisible; michael@0: mOrgSpeakerStatus = aEnable; michael@0: Notify(); michael@0: } michael@0: michael@0: void michael@0: SpeakerManagerService::TuruOnSpeaker(bool aOn) michael@0: { michael@0: nsCOMPtr audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID); michael@0: NS_ENSURE_TRUE_VOID(audioManager); michael@0: int32_t phoneState; michael@0: audioManager->GetPhoneState(&phoneState); michael@0: int32_t forceuse = (phoneState == nsIAudioManager::PHONE_STATE_IN_CALL || michael@0: phoneState == nsIAudioManager::PHONE_STATE_IN_COMMUNICATION) michael@0: ? nsIAudioManager::USE_COMMUNICATION : nsIAudioManager::USE_MEDIA; michael@0: if (aOn) { michael@0: audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_SPEAKER); michael@0: } else { michael@0: audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_NONE); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: SpeakerManagerService::GetSpeakerStatus() michael@0: { michael@0: char propQemu[PROPERTY_VALUE_MAX]; michael@0: property_get("ro.kernel.qemu", propQemu, ""); michael@0: if (!strncmp(propQemu, "1", 1)) { michael@0: return mOrgSpeakerStatus; michael@0: } michael@0: nsCOMPtr audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID); michael@0: NS_ENSURE_TRUE(audioManager, false); michael@0: int32_t usage; michael@0: audioManager->GetForceForUse(nsIAudioManager::USE_MEDIA, &usage); michael@0: return usage == nsIAudioManager::FORCE_SPEAKER; michael@0: } michael@0: michael@0: void michael@0: SpeakerManagerService::Notify() michael@0: { michael@0: // Parent Notify to all the child processes. michael@0: nsTArray children; michael@0: ContentParent::GetAll(children); michael@0: for (uint32_t i = 0; i < children.Length(); i++) { michael@0: unused << children[i]->SendSpeakerManagerNotify(); michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < mRegisteredSpeakerManagers.Length(); i++) { michael@0: mRegisteredSpeakerManagers[i]-> michael@0: DispatchSimpleEvent(NS_LITERAL_STRING("speakerforcedchange")); michael@0: } michael@0: } michael@0: michael@0: void michael@0: SpeakerManagerService::SetAudioChannelActive(bool aIsActive) michael@0: { michael@0: if (!aIsActive && !mVisible) { michael@0: ForceSpeaker(!mOrgSpeakerStatus, mVisible); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SpeakerManagerService::Observe(nsISupports* aSubject, const char* michael@0: aTopic, const char16_t* aData) michael@0: { michael@0: if (!strcmp(aTopic, "ipc:content-shutdown")) { michael@0: nsCOMPtr props = do_QueryInterface(aSubject); michael@0: if (!props) { michael@0: NS_WARNING("ipc:content-shutdown message without property bag as subject"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint64_t childID = 0; michael@0: nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), michael@0: &childID); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // If the audio has paused by audiochannel, michael@0: // the enable flag should be false and don't need to handle. michael@0: if (mSpeakerStatusSet.Contains(childID)) { michael@0: TuruOnSpeaker(false); michael@0: mSpeakerStatusSet.Remove(childID); michael@0: } michael@0: if (mOrgSpeakerStatus) { michael@0: TuruOnSpeaker(!mOrgSpeakerStatus); michael@0: mOrgSpeakerStatus = false; michael@0: } michael@0: } else { michael@0: NS_WARNING("ipc:content-shutdown message without childID property"); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: SpeakerManagerService::SpeakerManagerService() michael@0: : mOrgSpeakerStatus(false), michael@0: mVisible(false) michael@0: { michael@0: MOZ_COUNT_CTOR(SpeakerManagerService); michael@0: if (XRE_GetProcessType() == GeckoProcessType_Default) { michael@0: nsCOMPtr obs = mozilla::services::GetObserverService(); michael@0: if (obs) { michael@0: obs->AddObserver(this, "ipc:content-shutdown", false); michael@0: } michael@0: } michael@0: AudioChannelService* audioChannelService = michael@0: AudioChannelService::GetAudioChannelService(); michael@0: if (audioChannelService) { michael@0: audioChannelService->RegisterSpeakerManager(this); michael@0: } michael@0: } michael@0: michael@0: SpeakerManagerService::~SpeakerManagerService() michael@0: { michael@0: MOZ_COUNT_DTOR(SpeakerManagerService); michael@0: AudioChannelService* audioChannelService = michael@0: AudioChannelService::GetAudioChannelService(); michael@0: if (audioChannelService) michael@0: audioChannelService->UnregisterSpeakerManager(this); michael@0: }