Bug 1315551 - part2 : check we have initialized agent when we want to call the agent's function.
Because the agent's initialization might fail if we don't get the valid inner window, we need to
check whether the agent exists before calling the agent's method.
MozReview-Commit-ID: IUuvyGh7CMd
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2944,17 +2944,17 @@ HTMLMediaElement::HTMLMediaElement(alrea
MOZ_ASSERT(NS_IsMainThread());
mWatchManager.Watch(mDownloadSuspendedByCache, &HTMLMediaElement::UpdateReadyStateInternal);
// Paradoxically, there is a self-edge whereby UpdateReadyStateInternal refuses
// to run until mReadyState reaches at least HAVE_METADATA by some other means.
mWatchManager.Watch(mReadyState, &HTMLMediaElement::UpdateReadyStateInternal);
mShutdownObserver->Subscribe(this);
- CreateAudioChannelAgent();
+ MaybeCreateAudioChannelAgent();
}
HTMLMediaElement::~HTMLMediaElement()
{
NS_ASSERTION(!mHasSelfReference,
"How can we be destroyed if we're still holding a self reference?");
mShutdownObserver->Unsubscribe();
@@ -2985,16 +2985,17 @@ HTMLMediaElement::~HTMLMediaElement()
NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 0,
"Destroyed media element should no longer be in element table");
if (mChannelLoader) {
mChannelLoader->Cancel();
}
WakeLockRelease();
+ mAudioChannelAgent = nullptr;
}
void HTMLMediaElement::StopSuspendingAfterFirstFrame()
{
mAllowSuspendAfterFirstFrame = false;
if (!mSuspendedAfterFirstFrame)
return;
mSuspendedAfterFirstFrame = false;
@@ -5757,27 +5758,36 @@ NS_IMETHODIMP HTMLMediaElement::SetMozPr
}
ImageContainer* HTMLMediaElement::GetImageContainer()
{
VideoFrameContainer* container = GetVideoFrameContainer();
return container ? container->GetImageContainer() : nullptr;
}
-void
-HTMLMediaElement::CreateAudioChannelAgent()
+bool
+HTMLMediaElement::MaybeCreateAudioChannelAgent()
{
if (mAudioChannelAgent) {
- return;
+ return true;
}
mAudioChannelAgent = new AudioChannelAgent();
- mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetInnerWindow(),
+ nsresult rv = mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetInnerWindow(),
static_cast<int32_t>(mAudioChannel),
this);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ mAudioChannelAgent = nullptr;
+ MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
+ ("HTMLMediaElement, Fail to initialize the audio channel agent,"
+ " this = %p\n", this));
+ return false;
+ }
+
+ return true;
}
bool
HTMLMediaElement::IsPlayingThroughTheAudioChannel() const
{
// If we have an error, we are not playing.
if (mError) {
return false;
@@ -5823,16 +5833,20 @@ HTMLMediaElement::IsPlayingThroughTheAud
void
HTMLMediaElement::UpdateAudioChannelPlayingState(bool aForcePlaying)
{
bool playingThroughTheAudioChannel =
aForcePlaying || IsPlayingThroughTheAudioChannel();
if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) {
+ if (!MaybeCreateAudioChannelAgent()) {
+ return;
+ }
+
mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel;
NotifyAudioChannelAgent(mPlayingThroughTheAudioChannel);
}
}
void
HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying)
{
@@ -6033,29 +6047,30 @@ HTMLMediaElement::IsAllowedToPlay()
if (mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_PAUSE ||
mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_BLOCK) {
return false;
}
// If the tab hasn't been activated yet, the media element in that tab can't
// be playback now until the tab goes to foreground first time or user clicks
// the unblocking tab icon.
- if (!IsTabActivated()) {
+ if (MaybeCreateAudioChannelAgent() && !IsTabActivated()) {
// Even we haven't start playing yet, we still need to notify the audio
// channe system because we need to receive the resume notification later.
UpdateAudioChannelPlayingState(true /* force to start */);
return false;
}
return true;
}
bool
HTMLMediaElement::IsTabActivated() const
{
+ MOZ_ASSERT(mAudioChannelAgent);
return !mAudioChannelAgent->ShouldBlockMedia();
}
static const char* VisibilityString(Visibility aVisibility) {
switch(aVisibility) {
case Visibility::UNTRACKED: {
return "UNTRACKED";
}
@@ -6457,19 +6472,18 @@ HTMLMediaElement::SetAudibleState(bool a
NotifyAudioPlaybackChanged(
AudioChannelService::AudibleChangedReasons::eDataAudibleChanged);
}
}
void
HTMLMediaElement::NotifyAudioPlaybackChanged(AudibleChangedReasons aReason)
{
- MOZ_ASSERT(mAudioChannelAgent);
-
- if (!mAudioChannelAgent->IsPlayingStarted()) {
+ if (MaybeCreateAudioChannelAgent() &&
+ !mAudioChannelAgent->IsPlayingStarted()) {
return;
}
if (mAudible == IsAudible()) {
return;
}
mAudible = IsAudible();
@@ -6502,16 +6516,17 @@ HTMLMediaElement::MaybeNotifyMediaResume
{
// In fennec, we should send the notification when media is resumed from the
// pause-disposable which was called by media control.
if (mAudioChannelSuspended != nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE &&
aSuspend != nsISuspendedTypes::NONE_SUSPENDED) {
return;
}
+ MOZ_ASSERT(mAudioChannelAgent);
uint64_t windowID = mAudioChannelAgent->WindowID();
NS_DispatchToMainThread(NS_NewRunnableFunction([windowID]() -> void {
nsCOMPtr<nsIObserverService> observerService =
services::GetObserverService();
if (NS_WARN_IF(!observerService)) {
return;
}
@@ -6578,24 +6593,23 @@ HTMLMediaElement::SetMediaInfo(const Med
{
mMediaInfo = aInfo;
AudioCaptureStreamChangeIfNeeded();
}
void
HTMLMediaElement::AudioCaptureStreamChangeIfNeeded()
{
- MOZ_ASSERT(mAudioChannelAgent);
-
// No need to capture a silence media element.
if (!HasAudio()) {
return;
}
- if (!mAudioChannelAgent->IsPlayingStarted()) {
+ if (MaybeCreateAudioChannelAgent() &&
+ !mAudioChannelAgent->IsPlayingStarted()) {
return;
}
if (mAudioCapturedByWindow && !mCaptureStreamPort) {
nsCOMPtr<nsPIDOMWindowInner> window = OwnerDoc()->GetInnerWindow();
if (!OwnerDoc()->GetInnerWindow()) {
return;
}
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -1224,19 +1224,21 @@ protected:
TextTrackManager* GetOrCreateTextTrackManager();
// Recomputes ready state and fires events as necessary based on current state.
void UpdateReadyStateInternal();
// Notifies the audio channel agent when the element starts or stops playing.
void NotifyAudioChannelAgent(bool aPlaying);
- // Creates the audio channel agent in the beginning and this agent would be
- // used to communicate with the AudioChannelService.
- void CreateAudioChannelAgent();
+ // True if we create the audio channel agent successfully or we already have
+ // one. The agent is used to communicate with the AudioChannelService. eg.
+ // notify we are playing/audible and receive muted/unmuted/suspend/resume
+ // commands from AudioChannelService.
+ bool MaybeCreateAudioChannelAgent();
// Determine if the element should be paused because of suspend conditions.
bool ShouldElementBePaused();
// Create or destroy the captured stream depend on mAudioCapturedByWindow.
void AudioCaptureStreamChangeIfNeeded();
/**