Bug 1651049 - Move the sink change logic in MediaStreamRenderer. r=padenot
The MediaStreamRenderer handles the AudioOutput of an HTMLMediaElement. it register/unregister the AudioOutput according to the rendering status. The sink-change follows the logic of AudioOutput thus it has been moved in it. The previous way created an error when the element had been muted and the sink had been changed before the source MediaStream was attached to the element. The error occured because it was possible, the same entry to be registered more than once in the AudioOutput's list, which resulted in the track to be unmuted when it should not. Differential Revision: https://phabricator.services.mozilla.com/D82529
This commit is contained in:
@@ -829,6 +829,10 @@ class HTMLMediaElement::MediaStreamRenderer
|
||||
|
||||
for (const auto& t : mAudioTracks) {
|
||||
if (t) {
|
||||
if (mAudioOutputSink) {
|
||||
t->AsAudioStreamTrack()->SetAudioOutputDevice(mAudioOutputKey,
|
||||
mAudioOutputSink);
|
||||
}
|
||||
t->AsAudioStreamTrack()->AddAudioOutput(mAudioOutputKey);
|
||||
t->AsAudioStreamTrack()->SetAudioOutputVolume(mAudioOutputKey,
|
||||
mAudioOutputVolume);
|
||||
@@ -878,11 +882,47 @@ class HTMLMediaElement::MediaStreamRenderer
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<GenericPromise::AllPromiseType> SetAudioOutputDevice(
|
||||
AudioDeviceInfo* aSink) {
|
||||
MOZ_ASSERT(aSink);
|
||||
MOZ_ASSERT(mAudioOutputSink != aSink);
|
||||
|
||||
mAudioOutputSink = aSink;
|
||||
|
||||
if (!mRendering) {
|
||||
return GenericPromise::AllPromiseType::CreateAndResolve(nsTArray<bool>(),
|
||||
__func__);
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<GenericPromise>> promises;
|
||||
for (const auto& t : mAudioTracks) {
|
||||
// SetAudioOutputDevice will create a new output MediaTrack, so the
|
||||
// AudioOutput is removed for the current MediaTrack and re-added after
|
||||
// the new MediaTrack has been created.
|
||||
t->AsAudioStreamTrack()->RemoveAudioOutput(mAudioOutputKey);
|
||||
promises.AppendElement(t->AsAudioStreamTrack()->SetAudioOutputDevice(
|
||||
mAudioOutputKey, mAudioOutputSink));
|
||||
t->AsAudioStreamTrack()->AddAudioOutput(mAudioOutputKey);
|
||||
t->AsAudioStreamTrack()->SetAudioOutputVolume(mAudioOutputKey,
|
||||
mAudioOutputVolume);
|
||||
}
|
||||
if (!promises.Length()) {
|
||||
// Not active track, save it for later
|
||||
return GenericPromise::AllPromiseType::CreateAndResolve(nsTArray<bool>(),
|
||||
__func__);
|
||||
}
|
||||
|
||||
return GenericPromise::All(GetCurrentSerialEventTarget(), promises);
|
||||
}
|
||||
|
||||
void AddTrack(AudioStreamTrack* aTrack) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mAudioTracks.Contains(aTrack));
|
||||
mAudioTracks.AppendElement(aTrack);
|
||||
EnsureGraphTimeDummy();
|
||||
if (mRendering) {
|
||||
if (mAudioOutputSink) {
|
||||
aTrack->SetAudioOutputDevice(mAudioOutputKey, mAudioOutputSink);
|
||||
}
|
||||
aTrack->AddAudioOutput(mAudioOutputKey);
|
||||
aTrack->SetAudioOutputVolume(mAudioOutputKey, mAudioOutputVolume);
|
||||
}
|
||||
@@ -972,6 +1012,9 @@ class HTMLMediaElement::MediaStreamRenderer
|
||||
// The audio output volume for all audio tracks.
|
||||
float mAudioOutputVolume = 1.0f;
|
||||
|
||||
// The sink device for all audio tracks.
|
||||
RefPtr<AudioDeviceInfo> mAudioOutputSink;
|
||||
|
||||
// WatchManager for mGraphTime.
|
||||
WatchManager<MediaStreamRenderer> mWatchManager;
|
||||
|
||||
@@ -5230,7 +5273,7 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream) {
|
||||
&HTMLMediaElement::UpdateSrcStreamTime);
|
||||
SetVolumeInternal();
|
||||
if (mSink.second) {
|
||||
SetSrcMediaStreamSink(mSink.second);
|
||||
mMediaStreamRenderer->SetAudioOutputDevice(mSink.second);
|
||||
}
|
||||
|
||||
UpdateSrcMediaStreamPlaying();
|
||||
@@ -7678,8 +7721,9 @@ already_AddRefed<Promise> HTMLMediaElement::SetSinkId(const nsAString& aSinkId,
|
||||
return p;
|
||||
}
|
||||
if (self->mSrcStream) {
|
||||
MOZ_ASSERT(self->mMediaStreamRenderer);
|
||||
RefPtr<SinkInfoPromise> p =
|
||||
self->SetSrcMediaStreamSink(aInfo)->Then(
|
||||
self->mMediaStreamRenderer->SetAudioOutputDevice(aInfo)->Then(
|
||||
self->mAbstractMainThread, __func__,
|
||||
[aInfo](const GenericPromise::AllPromiseType::
|
||||
ResolveOrRejectValue& aValue) {
|
||||
@@ -7728,43 +7772,6 @@ already_AddRefed<Promise> HTMLMediaElement::SetSinkId(const nsAString& aSinkId,
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
RefPtr<GenericPromise::AllPromiseType> HTMLMediaElement::SetSrcMediaStreamSink(
|
||||
AudioDeviceInfo* aSink) {
|
||||
MOZ_ASSERT(mSrcStream);
|
||||
nsTArray<RefPtr<AudioStreamTrack>> audioTracks;
|
||||
mSrcStream->GetAudioTracks(audioTracks);
|
||||
if (audioTracks.Length() == 0) {
|
||||
// Save it for later. At the moment the element does not contain any audio
|
||||
// track. Nevertheless, the requested sink-id is saved to be used when the
|
||||
// first audio track is available.
|
||||
return GenericPromise::AllPromiseType::CreateAndResolve(nsTArray<bool>(),
|
||||
__func__);
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<GenericPromise>> promises;
|
||||
for (const auto& audioTrack : audioTracks) {
|
||||
if (audioTrack->Ended()) {
|
||||
continue;
|
||||
}
|
||||
if (!mPaused) {
|
||||
audioTrack->RemoveAudioOutput(this);
|
||||
}
|
||||
promises.AppendElement(audioTrack->SetAudioOutputDevice(this, aSink));
|
||||
if (!mPaused) {
|
||||
audioTrack->AddAudioOutput(this);
|
||||
audioTrack->SetAudioOutputVolume(this, ComputedVolume());
|
||||
}
|
||||
}
|
||||
|
||||
if (!promises.Length()) {
|
||||
// Not active track, save it for later
|
||||
return GenericPromise::AllPromiseType::CreateAndResolve(nsTArray<bool>(),
|
||||
__func__);
|
||||
}
|
||||
|
||||
return GenericPromise::All(GetCurrentSerialEventTarget(), promises);
|
||||
}
|
||||
|
||||
void HTMLMediaElement::NotifyTextTrackModeChanged() {
|
||||
if (mPendingTextTrackChanged) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user