2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-12-04 23:46:07 +04:00
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
#ifndef mozilla_dom_audiochannelservice_h__
|
|
|
|
#define mozilla_dom_audiochannelservice_h__
|
|
|
|
|
|
|
|
#include "nsAutoPtr.h"
|
2012-12-28 21:57:35 +04:00
|
|
|
#include "nsIObserver.h"
|
2015-07-10 19:38:51 +03:00
|
|
|
#include "nsTObserverArray.h"
|
2013-03-17 11:55:16 +04:00
|
|
|
#include "nsTArray.h"
|
2012-12-04 23:46:07 +04:00
|
|
|
|
2012-12-06 19:25:18 +04:00
|
|
|
#include "AudioChannelAgent.h"
|
2014-04-10 21:39:20 +04:00
|
|
|
#include "nsAttrValue.h"
|
2017-03-21 05:38:48 +03:00
|
|
|
#include "mozilla/Logging.h"
|
2016-11-28 19:03:53 +03:00
|
|
|
|
|
|
|
#include <functional>
|
2012-12-04 23:46:07 +04:00
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
class nsPIDOMWindowOuter;
|
2015-11-10 13:32:00 +03:00
|
|
|
struct PRLogModuleInfo;
|
2014-03-11 14:46:55 +04:00
|
|
|
|
2012-12-04 23:46:07 +04:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
2015-12-11 19:17:33 +03:00
|
|
|
|
2016-05-03 04:52:38 +03:00
|
|
|
class AudioPlaybackConfig {
|
|
|
|
public:
|
|
|
|
AudioPlaybackConfig()
|
|
|
|
: mVolume(1.0),
|
|
|
|
mMuted(false),
|
|
|
|
mSuspend(nsISuspendedTypes::NONE_SUSPENDED),
|
2017-08-10 04:00:09 +03:00
|
|
|
mNumberOfAgents(0) {}
|
2016-05-03 04:52:38 +03:00
|
|
|
|
|
|
|
AudioPlaybackConfig(float aVolume, bool aMuted, uint32_t aSuspended)
|
|
|
|
: mVolume(aVolume),
|
|
|
|
mMuted(aMuted),
|
|
|
|
mSuspend(aSuspended),
|
2017-08-10 04:00:09 +03:00
|
|
|
mNumberOfAgents(0) {}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-05-03 04:52:38 +03:00
|
|
|
void SetConfig(float aVolume, bool aMuted, uint32_t aSuspended) {
|
|
|
|
mVolume = aVolume;
|
|
|
|
mMuted = aMuted;
|
|
|
|
mSuspend = aSuspended;
|
|
|
|
}
|
|
|
|
|
|
|
|
float mVolume;
|
|
|
|
bool mMuted;
|
|
|
|
uint32_t mSuspend;
|
2017-08-10 04:00:09 +03:00
|
|
|
uint32_t mNumberOfAgents;
|
2016-05-03 04:52:38 +03:00
|
|
|
};
|
|
|
|
|
2017-05-18 04:31:00 +03:00
|
|
|
class AudioChannelService final : public nsIObserver {
|
2012-12-04 23:46:07 +04:00
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
2012-12-28 21:57:35 +04:00
|
|
|
NS_DECL_NSIOBSERVER
|
2012-12-04 23:46:07 +04:00
|
|
|
|
2016-12-13 17:47:13 +03:00
|
|
|
/**
|
|
|
|
* eNotAudible : agent is not audible
|
|
|
|
* eMaybeAudible : agent is not audible now, but it might be audible later
|
|
|
|
* eAudible : agent is audible now
|
|
|
|
*/
|
|
|
|
enum AudibleState : uint8_t {
|
|
|
|
eNotAudible = 0,
|
|
|
|
eMaybeAudible = 1,
|
|
|
|
eAudible = 2
|
2016-05-03 05:03:02 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
enum AudioCaptureState : bool { eCapturing = true, eNotCapturing = false };
|
|
|
|
|
2016-06-01 05:26:04 +03:00
|
|
|
enum AudibleChangedReasons : uint32_t {
|
|
|
|
eVolumeChanged = 0,
|
|
|
|
eDataAudibleChanged = 1,
|
|
|
|
ePauseStateChanged = 2
|
|
|
|
};
|
|
|
|
|
2014-08-29 10:10:16 +04:00
|
|
|
/**
|
|
|
|
* Returns the AudioChannelServce singleton.
|
2017-02-09 04:03:22 +03:00
|
|
|
* If AudioChannelService doesn't exist, create and return new one.
|
2014-08-29 10:10:16 +04:00
|
|
|
* Only to be called from main thread.
|
|
|
|
*/
|
2015-07-10 19:38:44 +03:00
|
|
|
static already_AddRefed<AudioChannelService> GetOrCreate();
|
2014-08-29 10:10:16 +04:00
|
|
|
|
2017-02-09 04:03:22 +03:00
|
|
|
/**
|
|
|
|
* Returns the AudioChannelService singleton if one exists.
|
|
|
|
* If AudioChannelService doesn't exist, returns null.
|
|
|
|
*/
|
|
|
|
static already_AddRefed<AudioChannelService> Get();
|
|
|
|
|
2017-03-21 05:38:48 +03:00
|
|
|
static LogModule* GetAudioChannelLog();
|
2015-11-10 13:32:00 +03:00
|
|
|
|
2016-06-01 05:21:13 +03:00
|
|
|
static bool IsEnableAudioCompeting();
|
|
|
|
|
2012-12-04 23:46:07 +04:00
|
|
|
/**
|
2012-12-06 19:25:18 +04:00
|
|
|
* Any audio channel agent that starts playing should register itself to
|
2014-04-10 21:39:20 +04:00
|
|
|
* this service, sharing the AudioChannel.
|
2012-12-04 23:46:07 +04:00
|
|
|
*/
|
2016-05-03 12:59:27 +03:00
|
|
|
void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
|
|
|
AudibleState aAudible);
|
2012-12-04 23:46:07 +04:00
|
|
|
|
|
|
|
/**
|
2013-09-12 16:26:03 +04:00
|
|
|
* Any audio channel agent that stops playing should unregister itself to
|
2012-12-04 23:46:07 +04:00
|
|
|
* this service.
|
|
|
|
*/
|
2015-12-24 12:17:30 +03:00
|
|
|
void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
|
2012-12-04 23:46:07 +04:00
|
|
|
|
|
|
|
/**
|
2015-07-10 19:38:44 +03:00
|
|
|
* Return the state to indicate this audioChannel for his window should keep
|
2016-05-03 04:52:38 +03:00
|
|
|
* playing/muted/suspended.
|
2012-12-04 23:46:07 +04:00
|
|
|
*/
|
2017-08-10 04:00:09 +03:00
|
|
|
AudioPlaybackConfig GetMediaConfig(nsPIDOMWindowOuter* aWindow) const;
|
2015-07-10 19:38:44 +03:00
|
|
|
|
2016-05-03 05:03:02 +03:00
|
|
|
/**
|
|
|
|
* Called this method when the audible state of the audio playback changed,
|
|
|
|
* it would dispatch the playback event to observers which want to know the
|
|
|
|
* actual audible state of the window.
|
|
|
|
*/
|
2016-06-01 05:26:04 +03:00
|
|
|
void AudioAudibleChanged(AudioChannelAgent* aAgent, AudibleState aAudible,
|
|
|
|
AudibleChangedReasons aReason);
|
2016-05-03 05:03:02 +03:00
|
|
|
|
2017-02-09 04:03:22 +03:00
|
|
|
bool IsWindowActive(nsPIDOMWindowOuter* aWindow);
|
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
void RefreshAgentsVolume(nsPIDOMWindowOuter* aWindow);
|
2016-05-03 04:52:38 +03:00
|
|
|
void RefreshAgentsSuspend(nsPIDOMWindowOuter* aWindow,
|
|
|
|
nsSuspendedTypes aSuspend);
|
2014-03-11 14:46:55 +04:00
|
|
|
|
2015-07-09 17:40:08 +03:00
|
|
|
// This method needs to know the inner window that wants to capture audio. We
|
|
|
|
// group agents per top outer window, but we can have multiple innerWindow per
|
|
|
|
// top outerWindow (subiframes, etc.) and we have to identify all the agents
|
|
|
|
// just for a particular innerWindow.
|
2016-01-30 20:05:36 +03:00
|
|
|
void SetWindowAudioCaptured(nsPIDOMWindowOuter* aWindow,
|
2015-12-24 12:28:45 +03:00
|
|
|
uint64_t aInnerWindowID, bool aCapture);
|
2015-07-09 17:40:08 +03:00
|
|
|
|
2017-02-03 09:47:08 +03:00
|
|
|
void NotifyMediaResumedFromBlock(nsPIDOMWindowOuter* aWindow);
|
|
|
|
|
2015-07-10 19:38:44 +03:00
|
|
|
private:
|
|
|
|
AudioChannelService();
|
|
|
|
~AudioChannelService();
|
2015-07-10 19:38:46 +03:00
|
|
|
|
2016-05-03 04:52:38 +03:00
|
|
|
void RefreshAgents(nsPIDOMWindowOuter* aWindow,
|
2017-04-27 19:44:57 +03:00
|
|
|
const std::function<void(AudioChannelAgent*)>& aFunc);
|
2016-05-03 04:52:38 +03:00
|
|
|
|
2015-08-31 13:52:42 +03:00
|
|
|
static void CreateServiceIfNeeded();
|
|
|
|
|
2015-07-15 03:16:21 +03:00
|
|
|
/**
|
|
|
|
* Shutdown the singleton.
|
|
|
|
*/
|
|
|
|
static void Shutdown();
|
|
|
|
|
2017-02-24 12:15:20 +03:00
|
|
|
void RefreshAgentsAudioFocusChanged(AudioChannelAgent* aAgent);
|
2016-06-01 05:21:13 +03:00
|
|
|
|
2016-05-03 05:03:02 +03:00
|
|
|
class AudioChannelWindow final {
|
|
|
|
public:
|
2015-07-10 19:38:51 +03:00
|
|
|
explicit AudioChannelWindow(uint64_t aWindowID)
|
2016-06-01 05:21:13 +03:00
|
|
|
: mWindowID(aWindowID),
|
|
|
|
mIsAudioCaptured(false),
|
|
|
|
mOwningAudioFocus(!AudioChannelService::IsEnableAudioCompeting()),
|
2017-06-29 15:46:20 +03:00
|
|
|
mShouldSendActiveMediaBlockStopEvent(false) {}
|
2015-07-10 19:38:51 +03:00
|
|
|
|
2017-02-24 12:15:20 +03:00
|
|
|
void AudioFocusChanged(AudioChannelAgent* aNewPlayingAgent);
|
2016-06-01 05:26:04 +03:00
|
|
|
void AudioAudibleChanged(AudioChannelAgent* aAgent, AudibleState aAudible,
|
|
|
|
AudibleChangedReasons aReason);
|
2016-05-03 05:03:02 +03:00
|
|
|
|
2016-05-03 12:59:27 +03:00
|
|
|
void AppendAgent(AudioChannelAgent* aAgent, AudibleState aAudible);
|
2016-05-03 05:03:02 +03:00
|
|
|
void RemoveAgent(AudioChannelAgent* aAgent);
|
|
|
|
|
2017-02-03 09:47:08 +03:00
|
|
|
void NotifyMediaBlockStop(nsPIDOMWindowOuter* aWindow);
|
|
|
|
|
2015-07-10 19:38:51 +03:00
|
|
|
uint64_t mWindowID;
|
2015-12-24 12:28:45 +03:00
|
|
|
bool mIsAudioCaptured;
|
2017-08-10 04:00:09 +03:00
|
|
|
AudioPlaybackConfig mConfig;
|
2015-07-10 19:38:51 +03:00
|
|
|
|
|
|
|
// Raw pointer because the AudioChannelAgent must unregister itself.
|
|
|
|
nsTObserverArray<AudioChannelAgent*> mAgents;
|
2016-05-03 05:03:02 +03:00
|
|
|
nsTObserverArray<AudioChannelAgent*> mAudibleAgents;
|
|
|
|
|
2016-06-01 05:21:13 +03:00
|
|
|
// Owning audio focus when the window starts playing audible sound, and
|
|
|
|
// lose audio focus when other windows starts playing.
|
|
|
|
bool mOwningAudioFocus;
|
|
|
|
|
2017-06-29 15:46:20 +03:00
|
|
|
// If we've dispatched "activeMediaBlockStart" event, we must dispatch
|
|
|
|
// another event "activeMediablockStop" when the window is resumed from
|
|
|
|
// suspend-block.
|
|
|
|
bool mShouldSendActiveMediaBlockStopEvent;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-05-03 05:03:02 +03:00
|
|
|
private:
|
|
|
|
void AudioCapturedChanged(AudioChannelAgent* aAgent,
|
|
|
|
AudioCaptureState aCapture);
|
|
|
|
|
2016-06-01 05:26:04 +03:00
|
|
|
void AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent,
|
|
|
|
AudibleChangedReasons aReason);
|
|
|
|
void RemoveAudibleAgentIfContained(AudioChannelAgent* aAgent,
|
|
|
|
AudibleChangedReasons aReason);
|
2016-05-03 05:03:02 +03:00
|
|
|
|
|
|
|
void AppendAgentAndIncreaseAgentsNum(AudioChannelAgent* aAgent);
|
|
|
|
void RemoveAgentAndReduceAgentsNum(AudioChannelAgent* aAgent);
|
|
|
|
|
|
|
|
bool IsFirstAudibleAgent() const;
|
|
|
|
bool IsLastAudibleAgent() const;
|
|
|
|
|
|
|
|
void NotifyAudioAudibleChanged(nsPIDOMWindowOuter* aWindow,
|
2016-06-01 05:26:04 +03:00
|
|
|
AudibleState aAudible,
|
|
|
|
AudibleChangedReasons aReason);
|
|
|
|
|
2017-05-18 04:51:53 +03:00
|
|
|
void NotifyChannelActive(uint64_t aWindowID, bool aActive);
|
2017-02-03 09:47:11 +03:00
|
|
|
void MaybeNotifyMediaBlockStart(AudioChannelAgent* aAgent);
|
2016-06-01 05:21:13 +03:00
|
|
|
|
|
|
|
void RequestAudioFocus(AudioChannelAgent* aAgent);
|
2017-02-24 12:15:20 +03:00
|
|
|
|
|
|
|
// We need to do audio competing only when the new incoming agent started.
|
|
|
|
void NotifyAudioCompetingChanged(AudioChannelAgent* aAgent);
|
2016-06-01 05:21:13 +03:00
|
|
|
|
2017-08-10 04:00:09 +03:00
|
|
|
uint32_t GetCompetingBehavior(AudioChannelAgent* aAgent) const;
|
2016-06-01 05:21:13 +03:00
|
|
|
bool IsAgentInvolvingInAudioCompeting(AudioChannelAgent* aAgent) const;
|
|
|
|
bool IsAudioCompetingInSameTab() const;
|
|
|
|
bool IsContainingPlayingAgent(AudioChannelAgent* aAgent) const;
|
2016-09-09 04:50:40 +03:00
|
|
|
|
|
|
|
bool IsInactiveWindow() const;
|
2015-07-10 19:38:44 +03:00
|
|
|
};
|
2015-07-11 15:14:58 +03:00
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
AudioChannelWindow* GetOrCreateWindowData(nsPIDOMWindowOuter* aWindow);
|
2015-07-11 15:14:58 +03:00
|
|
|
|
2015-07-10 19:38:51 +03:00
|
|
|
AudioChannelWindow* GetWindowData(uint64_t aWindowID) const;
|
|
|
|
|
|
|
|
nsTObserverArray<nsAutoPtr<AudioChannelWindow>> mWindows;
|
2012-12-04 23:46:07 +04:00
|
|
|
};
|
|
|
|
|
2017-03-24 09:44:18 +03:00
|
|
|
const char* SuspendTypeToStr(const nsSuspendedTypes& aSuspend);
|
|
|
|
const char* AudibleStateToStr(
|
|
|
|
const AudioChannelService::AudibleState& aAudible);
|
|
|
|
const char* AudibleChangedReasonToStr(
|
|
|
|
const AudioChannelService::AudibleChangedReasons& aReason);
|
|
|
|
|
2012-12-04 23:46:07 +04:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif
|