Bug 1922912 apply PlaybackParams at AudioSink::Start() r=padenot

for single thread access to AudioSinkWrapper::mParams.

Differential Revision: https://phabricator.services.mozilla.com/D225020
This commit is contained in:
Karl Tomlinson 2024-10-10 05:55:06 +00:00
parent 5a7954ec49
commit de8c8c0ed6
4 changed files with 47 additions and 47 deletions

View File

@ -98,7 +98,7 @@ AudioSink::~AudioSink() {
}
nsresult AudioSink::InitializeAudioStream(
const PlaybackParams& aParams, const RefPtr<AudioDeviceInfo>& aAudioDevice,
const RefPtr<AudioDeviceInfo>& aAudioDevice,
AudioSink::InitializationType aInitializationType) {
if (aInitializationType == AudioSink::InitializationType::UNMUTING) {
// Consider the stream to be audible immediately, before initialization
@ -133,19 +133,19 @@ nsresult AudioSink::InitializeAudioStream(
return rv;
}
return NS_OK;
}
RefPtr<MediaSink::EndedPromise> AudioSink::Start(
const PlaybackParams& aParams, const media::TimeUnit& aStartTime) {
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
// Set playback params before calling Start() so they can take effect
// as soon as the 1st DataCallback of the AudioStream fires.
mAudioStream->SetVolume(aParams.mVolume);
mAudioStream->SetPlaybackRate(aParams.mPlaybackRate);
mAudioStream->SetPreservesPitch(aParams.mPreservesPitch);
return NS_OK;
}
RefPtr<MediaSink::EndedPromise> AudioSink::Start(
const media::TimeUnit& aStartTime) {
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
mAudioQueueListener = mAudioQueue.PushEvent().Connect(
mOwnerThread, this, &AudioSink::OnAudioPushed);
mAudioQueueFinishListener = mAudioQueue.FinishEvent().Connect(

View File

@ -47,13 +47,13 @@ class AudioSink : private AudioStream::DataSource {
~AudioSink();
// Allocate and initialize mAudioStream. Returns NS_OK on success.
nsresult InitializeAudioStream(const PlaybackParams& aParams,
const RefPtr<AudioDeviceInfo>& aAudioDevice,
nsresult InitializeAudioStream(const RefPtr<AudioDeviceInfo>& aAudioDevice,
InitializationType aInitializationType);
// Start audio playback. aStartTime is compared with MediaData::mTime to
// identify the first audio frame to be played.
RefPtr<MediaSink::EndedPromise> Start(const media::TimeUnit& aStartTime);
RefPtr<MediaSink::EndedPromise> Start(const PlaybackParams& aParams,
const media::TimeUnit& aStartTime);
/*
* All public functions are not thread-safe.

View File

@ -332,8 +332,8 @@ void AudioSinkWrapper::StartAudioSink(UniquePtr<AudioSink> aAudioSink,
AssertOwnerThread();
MOZ_ASSERT(!mAudioSink);
mAudioSink = std::move(aAudioSink);
mAudioSink->Start(aStartTime)
->Then(mOwnerThread.get(), __func__, this,
mAudioSink->Start(mParams, aStartTime)
->Then(mOwnerThread.GetEventTarget(), __func__, this,
&AudioSinkWrapper::OnAudioEnded)
->Track(mAudioSinkEndedRequest);
}
@ -370,37 +370,36 @@ RefPtr<GenericPromise> AudioSinkWrapper::MaybeAsyncCreateAudioSink(
++mAsyncCreateCount;
using Promise =
MozPromise<UniquePtr<AudioSink>, nsresult, /* IsExclusive = */ true>;
return InvokeAsync(mAsyncInitTaskQueue,
"MaybeAsyncCreateAudioSink (Async part: initialization)",
[self = RefPtr<AudioSinkWrapper>(this),
audioSink{std::move(audioSink)},
audioDevice = mAudioDevice, this]() mutable {
if (!audioSink || !mAsyncInitTaskQueue->IsEmpty()) {
// Either an AudioSink is not required or there's a
// pending task to init an AudioSink with a possibly
// different device.
return Promise::CreateAndResolve(nullptr, __func__);
}
return InvokeAsync(
mAsyncInitTaskQueue,
"MaybeAsyncCreateAudioSink (Async part: initialization)",
[self = RefPtr<AudioSinkWrapper>(this),
audioSink{std::move(audioSink)}, audioDevice = mAudioDevice,
this]() mutable {
if (!audioSink || !mAsyncInitTaskQueue->IsEmpty()) {
// Either an AudioSink is not required or there's a
// pending task to init an AudioSink with a possibly
// different device.
return Promise::CreateAndResolve(nullptr, __func__);
}
LOG("AudioSink initialization on background thread");
// This can take about 200ms, e.g. on Windows, we don't
// want to do it on the MDSM thread, because it would
// make the clock not update for that amount of time, and
// the video would therefore not update. The Start() call
// is very cheap on the other hand, we can do it from the
// MDSM thread.
nsresult rv = audioSink->InitializeAudioStream(
mParams, audioDevice,
AudioSink::InitializationType::UNMUTING);
if (NS_FAILED(rv)) {
LOG("Async AudioSink initialization failed");
return Promise::CreateAndReject(rv, __func__);
}
return Promise::CreateAndResolve(std::move(audioSink),
__func__);
})
LOG("AudioSink initialization on background thread");
// This can take about 200ms, e.g. on Windows, we don't
// want to do it on the MDSM thread, because it would
// make the clock not update for that amount of time, and
// the video would therefore not update. The Start() call
// is very cheap on the other hand, we can do it from the
// MDSM thread.
nsresult rv = audioSink->InitializeAudioStream(
audioDevice, AudioSink::InitializationType::UNMUTING);
if (NS_FAILED(rv)) {
LOG("Async AudioSink initialization failed");
return Promise::CreateAndReject(rv, __func__);
}
return Promise::CreateAndResolve(std::move(audioSink), __func__);
})
->Then(
mOwnerThread,
mOwnerThread.GetEventTarget(),
"MaybeAsyncCreateAudioSink (Async part: start from MDSM thread)",
[self = RefPtr<AudioSinkWrapper>(this), audioDevice = mAudioDevice,
this](Promise::ResolveOrRejectValue&& aValue) mutable {
@ -478,7 +477,7 @@ nsresult AudioSinkWrapper::SyncCreateAudioSink(const TimeUnit& aStartTime) {
UniquePtr<AudioSink> audioSink = mSinkCreator();
nsresult rv = audioSink->InitializeAudioStream(
mParams, mAudioDevice, AudioSink::InitializationType::INITIAL);
mAudioDevice, AudioSink::InitializationType::INITIAL);
if (NS_FAILED(rv)) {
LOG("Sync AudioSinkWrapper initialization failed");
// If a specific device has been specified through setSinkId()

View File

@ -8,6 +8,7 @@
#define AudioSinkWrapper_h_
#include "mozilla/AbstractThread.h"
#include "mozilla/EventTargetCapability.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
@ -85,8 +86,8 @@ class AudioSinkWrapper : public MediaSink {
void OnMuted(bool aMuted);
virtual ~AudioSinkWrapper();
void AssertOwnerThread() const {
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
void AssertOwnerThread() const MOZ_ASSERT_CAPABILITY(mOwnerThread) {
mOwnerThread.AssertOnCurrentThread();
}
bool NeedAudioSink();
@ -121,7 +122,7 @@ class AudioSinkWrapper : public MediaSink {
bool IsAudioSourceEnded(const MediaInfo& aInfo) const;
const RefPtr<AbstractThread> mOwnerThread;
const EventTargetCapability<AbstractThread> mOwnerThread;
const RefPtr<TaskQueue> mAsyncInitTaskQueue;
SinkCreator mSinkCreator;
UniquePtr<AudioSink> mAudioSink;
@ -133,7 +134,7 @@ class AudioSinkWrapper : public MediaSink {
MozPromiseHolder<EndedPromise> mEndedPromiseHolder;
// true between Start() and Stop()
bool mIsStarted = false;
PlaybackParams mParams;
PlaybackParams MOZ_GUARDED_BY(mOwnerThread) mParams;
// mClockStartTime is null before Start(), after Stop(), and between
// SetPlaying(false) and SetPlaying(true). When the system time is used for
// the clock, this is the time corresponding to mPositionAtClockStart. When