From f048891e775e888d3fa83b79d7b9d43e9a4f7cde Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 24 May 2022 13:09:06 +0000 Subject: [PATCH] Bug 1743834 - Wait for the audio callbacks to start being called before using the audio clock. r=alwu,media-playback-reviewers Because we're generally using high latency on the cubeb stream used by AudioStream instance, it can take some time for the callbacks to start being called, and the for the audio clock (cubeb_stream_get_position(...)) to advance. This waits for the first callback to be called before using the clock of the audio stream, and the system clock keeps being in use until then. Differential Revision: https://phabricator.services.mozilla.com/D136235 --- dom/media/AudioStream.cpp | 11 ++++++++--- dom/media/AudioStream.h | 4 ++++ dom/media/mediasink/AudioSink.h | 6 ++++++ dom/media/mediasink/AudioSinkWrapper.cpp | 3 +-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/dom/media/AudioStream.cpp b/dom/media/AudioStream.cpp index 8aa2cc0e5bfd..6a39d3d33556 100644 --- a/dom/media/AudioStream.cpp +++ b/dom/media/AudioStream.cpp @@ -148,7 +148,9 @@ AudioStream::AudioStream(DataSource& aSource, uint32_t aInRate, mSandboxed(CubebUtils::SandboxEnabled()), mPlaybackComplete(false), mPlaybackRate(1.0f), - mPreservesPitch(true) {} + mPreservesPitch(true), + mCallbacksStarted(false) + {} AudioStream::~AudioStream() { LOG("deleted, state %d", mState.load()); @@ -231,8 +233,8 @@ nsresult AudioStream::Init(AudioDeviceInfo* aSinkInfo) auto startTime = TimeStamp::Now(); TRACE("AudioStream::Init"); - LOG("%s channels: %d, rate: %d", __FUNCTION__, mOutChannels, - mAudioClock.GetInputRate()); + LOG("%s channels: %d, rate: %d", __FUNCTION__, mOutChannels, mAudioClock.GetInputRate()); + mSinkInfo = aSinkInfo; cubeb_stream_params params; @@ -595,6 +597,9 @@ long AudioStream::DataCallback(void* aBuffer, long aFrames) { CubebUtils::GetAudioThreadRegistry()->Register(mAudioThreadId); } WebCore::DenormalDisabler disabler; + if (!mCallbacksStarted) { + mCallbacksStarted = true; + } TRACE_AUDIO_CALLBACK_BUDGET(aFrames, mAudioClock.GetInputRate()); TRACE("AudioStream::DataCallback"); diff --git a/dom/media/AudioStream.h b/dom/media/AudioStream.h index 04ed62493dcc..86975c6a7124 100644 --- a/dom/media/AudioStream.h +++ b/dom/media/AudioStream.h @@ -297,6 +297,9 @@ class AudioStream final { bool IsPlaybackCompleted() const; + // Returns true if at least one DataCallback has been called. + bool CallbackStarted() const { return mCallbacksStarted; } + protected: friend class AudioClock; @@ -386,6 +389,7 @@ class AudioStream final { std::atomic mPreservesPitch; // Audio thread only bool mAudioThreadChanged = false; + Atomic mCallbacksStarted; }; } // namespace mozilla diff --git a/dom/media/mediasink/AudioSink.h b/dom/media/mediasink/AudioSink.h index 74cc793da14d..2877d7aed322 100644 --- a/dom/media/mediasink/AudioSink.h +++ b/dom/media/mediasink/AudioSink.h @@ -77,6 +77,12 @@ class AudioSink : private AudioStream::DataSource { const RefPtr& AudioDevice() { return mAudioDevice; } + // This returns true if the audio callbacks are being called, and so the + // audio stream-based clock is moving forward. + bool AudioStreamCallbackStarted() { + return mAudioStream && mAudioStream->CallbackStarted(); + } + private: // Allocate and initialize mAudioStream. Returns NS_OK on success. nsresult InitializeAudioStream(const PlaybackParams& aParams); diff --git a/dom/media/mediasink/AudioSinkWrapper.cpp b/dom/media/mediasink/AudioSinkWrapper.cpp index 21ec7d3b4eed..24eeb9f06376 100644 --- a/dom/media/mediasink/AudioSinkWrapper.cpp +++ b/dom/media/mediasink/AudioSinkWrapper.cpp @@ -77,8 +77,7 @@ TimeUnit AudioSinkWrapper::GetPosition(TimeStamp* aTimeStamp) { TimeUnit pos; TimeStamp t = TimeStamp::Now(); - if (!mAudioEnded && !IsMuted()) { - MOZ_ASSERT(mAudioSink); + if (!mAudioEnded && !IsMuted() && mAudioSink && mAudioSink->AudioStreamCallbackStarted()) { // Rely on the audio sink to report playback position when it is not ended. pos = mAudioSink->GetPosition(); LOGV("%p: Getting position from the Audio Sink %lf", this, pos.ToSeconds());