Bug 1156472 - Part 1 - Allow to capture all HTMLMediaElements and AudioContexts for a document. r=baku,padenot

This is built on top of the AudioChannel infrastructure. This patch does not
actually implement the capture, it just does the plumbing to be able to notify
all HTMLMediaElement/AudioContext for a document.
This commit is contained in:
Paul Adenot 2015-07-09 16:40:08 +02:00
parent 4db694f526
commit d3a9816e6b
10 changed files with 122 additions and 3 deletions

View File

@ -35,6 +35,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioChannelAgent)
AudioChannelAgent::AudioChannelAgent()
: mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR)
, mInnerWindowID(0)
, mIsRegToService(false)
{
}
@ -104,6 +105,10 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
}
if (aWindow) {
nsCOMPtr<nsPIDOMWindow> pInnerWindow = do_QueryInterface(aWindow);
MOZ_ASSERT(pInnerWindow->IsInnerWindow());
mInnerWindowID = pInnerWindow->WindowID();
nsCOMPtr<nsIDOMWindow> topWindow;
aWindow->GetScriptableTop(getter_AddRefs(topWindow));
mWindow = do_QueryInterface(topWindow);
@ -191,3 +196,18 @@ AudioChannelAgent::WindowID() const
{
return mWindow ? mWindow->WindowID() : 0;
}
void
AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID)
{
if (aInnerWindowID != mInnerWindowID) {
return;
}
nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
if (!callback) {
return;
}
callback->WindowAudioCaptureChanged();
}

View File

@ -34,6 +34,7 @@ public:
AudioChannelAgent();
void WindowVolumeChanged();
void WindowAudioCaptureChanged(uint64_t aInnerWindowID);
nsPIDOMWindow* Window() const
{
@ -61,6 +62,7 @@ private:
nsWeakPtr mWeakCallback;
int32_t mAudioChannelType;
uint64_t mInnerWindowID;
bool mIsRegToService;
};

View File

@ -546,6 +546,29 @@ AudioChannelService::RefreshAgentsVolume(nsPIDOMWindow* aWindow)
}
}
void
AudioChannelService::RefreshAgentsCapture(nsPIDOMWindow* aWindow,
uint64_t aInnerWindowID)
{
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsOuterWindow());
nsCOMPtr<nsIDOMWindow> topWindow;
aWindow->GetScriptableTop(getter_AddRefs(topWindow));
nsCOMPtr<nsPIDOMWindow> pTopWindow = do_QueryInterface(topWindow);
if (!pTopWindow) {
return;
}
AudioChannelWindow* winData = GetWindowData(pTopWindow->WindowID());
nsTObserverArray<AudioChannelAgent*>::ForwardIterator
iter(winData->mAgents);
while (iter.HasMore()) {
iter.GetNext()->WindowAudioCaptureChanged(aInnerWindowID);
}
}
/* static */ const nsAttrValue::EnumTable*
AudioChannelService::GetAudioChannelTable()
{

View File

@ -102,6 +102,14 @@ public:
void RefreshAgentsVolume(nsPIDOMWindow* aWindow);
// 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.
void RefreshAgentsCapture(nsPIDOMWindow* aWindow,
uint64_t aInnerWindowID);
#ifdef MOZ_WIDGET_GONK
void RegisterSpeakerManager(SpeakerManagerService* aSpeakerManager)
{

View File

@ -6,13 +6,18 @@
interface nsIDOMWindow;
[uuid(4f537c88-3722-4946-9a09-ce559fa0591d)]
[uuid(5fe83b24-38b9-4901-a4a1-d1bd57d3fe18)]
interface nsIAudioChannelAgentCallback : nsISupports
{
/**
* Notified when the window volume/mute is changed
*/
void windowVolumeChanged(in float aVolume, in bool aMuted);
/**
* Notified when the capture state is changed.
*/
void windowAudioCaptureChanged();
};
/**

View File

@ -564,7 +564,7 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
mMayHavePointerEnterLeaveEventListener(false),
mIsModalContentWindow(false),
mIsActive(false), mIsBackground(false),
mAudioMuted(false), mAudioVolume(1.0),
mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false),
mDesktopModeViewport(false), mInnerWindow(nullptr),
mOuterWindow(aOuterWindow),
// Make sure no actual window ends up with mWindowID == 0
@ -3745,6 +3745,26 @@ nsPIDOMWindow::RefreshMediaElements()
service->RefreshAgentsVolume(GetOuterWindow());
}
bool
nsPIDOMWindow::GetAudioCaptured() const
{
MOZ_ASSERT(IsInnerWindow());
return mAudioCaptured;
}
nsresult
nsPIDOMWindow::SetAudioCapture(bool aCapture)
{
MOZ_ASSERT(IsInnerWindow());
mAudioCaptured = aCapture;
nsRefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
service->RefreshAgentsCapture(GetOuterWindow(), mWindowID);
return NS_OK;
}
// nsISpeechSynthesisGetter
#ifdef MOZ_WEBSPEECH

View File

@ -185,6 +185,9 @@ public:
float GetAudioVolume() const;
nsresult SetAudioVolume(float aVolume);
bool GetAudioCaptured() const;
nsresult SetAudioCapture(bool aCapture);
virtual void SetServiceWorkersTestingEnabled(bool aEnabled)
{
MOZ_ASSERT(IsOuterWindow());
@ -822,6 +825,8 @@ protected:
bool mAudioMuted;
float mAudioVolume;
bool mAudioCaptured;
// current desktop mode flag.
bool mDesktopModeViewport;

View File

@ -471,6 +471,12 @@ FMRadio::WindowVolumeChanged(float aVolume, bool aMuted)
return NS_OK;
}
NS_IMETHODIMP
FMRadio::WindowAudioCaptureChanged()
{
return NS_OK;
}
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FMRadio)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)

View File

@ -4492,7 +4492,7 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
if (!mAudioChannelAgent) {
return;
}
mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetWindow(),
mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetInnerWindow(),
static_cast<int32_t>(mAudioChannel),
this);
}
@ -4504,6 +4504,10 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
void
HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying)
{
// Immediately check if this should go to the MSG instead of the normal
// media playback route.
WindowAudioCaptureChanged();
// This is needed to pass nsContentUtils::IsCallerChrome().
// AudioChannel API should not called from content but it can happen that
// this method has some content JS in its stack.
@ -4674,6 +4678,15 @@ HTMLMediaElement::GetTopLevelPrincipal()
}
#endif // MOZ_EME
NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
{
MOZ_ASSERT(mAudioChannelAgent);
DebugOnly<bool> captured = OwnerDoc()->GetInnerWindow()->GetAudioCaptured();
// Something is going to happen here!!
return NS_OK;
}
AudioTrackList*
HTMLMediaElement::AudioTracks()
{

View File

@ -505,6 +505,21 @@ AudioDestinationNode::WindowVolumeChanged(float aVolume, bool aMuted)
return NS_OK;
}
NS_IMETHODIMP
AudioDestinationNode::WindowAudioCaptureChanged()
{
MOZ_ASSERT(mAudioChannelAgent);
if (!mStream) {
return NS_OK;
}
DebugOnly<bool> captured = GetOwner()->GetAudioCaptured();
// XXXtodopadenot actually capture
return NS_OK;
}
AudioChannel
AudioDestinationNode::MozAudioChannelType() const
{
@ -591,6 +606,8 @@ AudioDestinationNode::CreateAudioChannelAgent()
// The AudioChannelAgent must start playing immediately in order to avoid
// race conditions with mozinterruptbegin/end events.
InputMuted(false);
WindowAudioCaptureChanged();
}
void