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 1c838936c0
commit 0995fd61d9
10 changed files with 122 additions and 3 deletions

View File

@@ -35,6 +35,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioChannelAgent)
AudioChannelAgent::AudioChannelAgent() AudioChannelAgent::AudioChannelAgent()
: mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR) : mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR)
, mInnerWindowID(0)
, mIsRegToService(false) , mIsRegToService(false)
{ {
} }
@@ -104,6 +105,10 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
} }
if (aWindow) { if (aWindow) {
nsCOMPtr<nsPIDOMWindow> pInnerWindow = do_QueryInterface(aWindow);
MOZ_ASSERT(pInnerWindow->IsInnerWindow());
mInnerWindowID = pInnerWindow->WindowID();
nsCOMPtr<nsIDOMWindow> topWindow; nsCOMPtr<nsIDOMWindow> topWindow;
aWindow->GetScriptableTop(getter_AddRefs(topWindow)); aWindow->GetScriptableTop(getter_AddRefs(topWindow));
mWindow = do_QueryInterface(topWindow); mWindow = do_QueryInterface(topWindow);
@@ -191,3 +196,18 @@ AudioChannelAgent::WindowID() const
{ {
return mWindow ? mWindow->WindowID() : 0; 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(); AudioChannelAgent();
void WindowVolumeChanged(); void WindowVolumeChanged();
void WindowAudioCaptureChanged(uint64_t aInnerWindowID);
nsPIDOMWindow* Window() const nsPIDOMWindow* Window() const
{ {
@@ -61,6 +62,7 @@ private:
nsWeakPtr mWeakCallback; nsWeakPtr mWeakCallback;
int32_t mAudioChannelType; int32_t mAudioChannelType;
uint64_t mInnerWindowID;
bool mIsRegToService; 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* /* static */ const nsAttrValue::EnumTable*
AudioChannelService::GetAudioChannelTable() AudioChannelService::GetAudioChannelTable()
{ {

View File

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

View File

@@ -6,13 +6,18 @@
interface nsIDOMWindow; interface nsIDOMWindow;
[uuid(4f537c88-3722-4946-9a09-ce559fa0591d)] [uuid(5fe83b24-38b9-4901-a4a1-d1bd57d3fe18)]
interface nsIAudioChannelAgentCallback : nsISupports interface nsIAudioChannelAgentCallback : nsISupports
{ {
/** /**
* Notified when the window volume/mute is changed * Notified when the window volume/mute is changed
*/ */
void windowVolumeChanged(in float aVolume, in bool aMuted); 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), mMayHavePointerEnterLeaveEventListener(false),
mIsModalContentWindow(false), mIsModalContentWindow(false),
mIsActive(false), mIsBackground(false), mIsActive(false), mIsBackground(false),
mAudioMuted(false), mAudioVolume(1.0), mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false),
mDesktopModeViewport(false), mInnerWindow(nullptr), mDesktopModeViewport(false), mInnerWindow(nullptr),
mOuterWindow(aOuterWindow), mOuterWindow(aOuterWindow),
// Make sure no actual window ends up with mWindowID == 0 // Make sure no actual window ends up with mWindowID == 0
@@ -3745,6 +3745,26 @@ nsPIDOMWindow::RefreshMediaElements()
service->RefreshAgentsVolume(GetOuterWindow()); 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 // nsISpeechSynthesisGetter
#ifdef MOZ_WEBSPEECH #ifdef MOZ_WEBSPEECH

View File

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

View File

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

View File

@@ -4492,7 +4492,7 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
if (!mAudioChannelAgent) { if (!mAudioChannelAgent) {
return; return;
} }
mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetWindow(), mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetInnerWindow(),
static_cast<int32_t>(mAudioChannel), static_cast<int32_t>(mAudioChannel),
this); this);
} }
@@ -4504,6 +4504,10 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
void void
HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying) 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(). // This is needed to pass nsContentUtils::IsCallerChrome().
// AudioChannel API should not called from content but it can happen that // AudioChannel API should not called from content but it can happen that
// this method has some content JS in its stack. // this method has some content JS in its stack.
@@ -4674,6 +4678,15 @@ HTMLMediaElement::GetTopLevelPrincipal()
} }
#endif // MOZ_EME #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* AudioTrackList*
HTMLMediaElement::AudioTracks() HTMLMediaElement::AudioTracks()
{ {

View File

@@ -505,6 +505,21 @@ AudioDestinationNode::WindowVolumeChanged(float aVolume, bool aMuted)
return NS_OK; 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 AudioChannel
AudioDestinationNode::MozAudioChannelType() const AudioDestinationNode::MozAudioChannelType() const
{ {
@@ -591,6 +606,8 @@ AudioDestinationNode::CreateAudioChannelAgent()
// The AudioChannelAgent must start playing immediately in order to avoid // The AudioChannelAgent must start playing immediately in order to avoid
// race conditions with mozinterruptbegin/end events. // race conditions with mozinterruptbegin/end events.
InputMuted(false); InputMuted(false);
WindowAudioCaptureChanged();
} }
void void