Bug 1324629. Part 3 - remove AudioWait and videoWait callbacks. r?kaku
MozReview-Commit-ID: 9pXLLrYLN4c
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -71,98 +71,49 @@ MediaDecoderReaderWrapper::RequestVideoD
aSkipToNextKeyframe, aTimeThreshold.ToMicroseconds())
->Then(mOwnerThread, __func__,
[startTime] (MediaData* aVideo) {
aVideo->AdjustForStartTime(startTime);
},
[] (const MediaResult& aError) {});
}
-bool
-MediaDecoderReaderWrapper::IsWaitingAudioData() const
-{
- MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
- return mAudioWaitRequest.Exists();
-}
-
-bool
-MediaDecoderReaderWrapper::IsWaitingVideoData() const
-{
- MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
- return mVideoWaitRequest.Exists();
-}
-
RefPtr<MediaDecoderReader::SeekPromise>
MediaDecoderReaderWrapper::Seek(const SeekTarget& aTarget)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
SeekTarget adjustedTarget = aTarget;
adjustedTarget.SetTime(adjustedTarget.GetTime() + StartTime());
return InvokeAsync<SeekTarget&&>(
mReader->OwnerThread(), mReader.get(), __func__,
&MediaDecoderReader::Seek,
Move(adjustedTarget));
}
-void
+RefPtr<MediaDecoderReaderWrapper::WaitForDataPromise>
MediaDecoderReaderWrapper::WaitForData(MediaData::Type aType)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
-
- auto p = InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
- &MediaDecoderReader::WaitForData, aType);
-
- RefPtr<MediaDecoderReaderWrapper> self = this;
- WaitRequestRef(aType).Begin(p->Then(mOwnerThread, __func__,
- [self] (MediaData::Type aType) {
- self->WaitRequestRef(aType).Complete();
- self->WaitCallbackRef(aType).Notify(AsVariant(aType));
- },
- [self, aType] (WaitForDataRejectValue aRejection) {
- self->WaitRequestRef(aType).Complete();
- self->WaitCallbackRef(aType).Notify(AsVariant(aRejection));
- }));
-}
-
-MediaCallbackExc<WaitCallbackData>&
-MediaDecoderReaderWrapper::WaitCallbackRef(MediaData::Type aType)
-{
- MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
- return aType == MediaData::AUDIO_DATA ? mAudioWaitCallback : mVideoWaitCallback;
-}
-
-MozPromiseRequestHolder<MediaDecoderReader::WaitForDataPromise>&
-MediaDecoderReaderWrapper::WaitRequestRef(MediaData::Type aType)
-{
- MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
- return aType == MediaData::AUDIO_DATA ? mAudioWaitRequest : mVideoWaitRequest;
+ return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
+ &MediaDecoderReader::WaitForData, aType);
}
void
MediaDecoderReaderWrapper::ReleaseResources()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
nsCOMPtr<nsIRunnable> r =
NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseResources);
mReader->OwnerThread()->Dispatch(r.forget());
}
void
MediaDecoderReaderWrapper::ResetDecode(TrackSet aTracks)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
-
- if (aTracks.contains(TrackInfo::kAudioTrack)) {
- mAudioWaitRequest.DisconnectIfExists();
- }
-
- if (aTracks.contains(TrackInfo::kVideoTrack)) {
- mVideoWaitRequest.DisconnectIfExists();
- }
-
nsCOMPtr<nsIRunnable> r =
NewRunnableMethod<TrackSet>(mReader,
&MediaDecoderReader::ResetDecode,
aTracks);
mReader->OwnerThread()->Dispatch(r.forget());
}
RefPtr<ShutdownPromise>
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -32,41 +32,31 @@ typedef Variant<MediaData::Type, WaitFor
class MediaDecoderReaderWrapper {
typedef MediaDecoderReader::MetadataPromise MetadataPromise;
typedef MediaDecoderReader::MediaDataPromise MediaDataPromise;
typedef MediaDecoderReader::SeekPromise SeekPromise;
typedef MediaDecoderReader::WaitForDataPromise WaitForDataPromise;
typedef MediaDecoderReader::TrackSet TrackSet;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper);
-private:
- MediaCallbackExc<WaitCallbackData> mAudioWaitCallback;
- MediaCallbackExc<WaitCallbackData> mVideoWaitCallback;
-
public:
MediaDecoderReaderWrapper(AbstractThread* aOwnerThread,
MediaDecoderReader* aReader);
media::TimeUnit StartTime() const;
RefPtr<MetadataPromise> ReadMetadata();
- decltype(mAudioWaitCallback)& AudioWaitCallback() { return mAudioWaitCallback; }
- decltype(mVideoWaitCallback)& VideoWaitCallback() { return mVideoWaitCallback; }
-
// NOTE: please set callbacks before requesting audio/video data!
RefPtr<MediaDataPromise> RequestAudioData();
RefPtr<MediaDataPromise>
RequestVideoData(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold);
// NOTE: please set callbacks before invoking WaitForData()!
- void WaitForData(MediaData::Type aType);
-
- bool IsWaitingAudioData() const;
- bool IsWaitingVideoData() const;
+ RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType);
RefPtr<SeekPromise> Seek(const SeekTarget& aTarget);
RefPtr<ShutdownPromise> Shutdown();
void ReleaseResources();
void ResetDecode(TrackSet aTracks);
nsresult Init() { return mReader->Init(); }
@@ -103,27 +93,21 @@ public:
}
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
void SetVideoBlankDecode(bool aIsBlankDecode);
private:
~MediaDecoderReaderWrapper();
-
void OnMetadataRead(MetadataHolder* aMetadata);
void OnMetadataNotRead() {}
- MediaCallbackExc<WaitCallbackData>& WaitCallbackRef(MediaData::Type aType);
- MozPromiseRequestHolder<WaitForDataPromise>& WaitRequestRef(MediaData::Type aType);
const RefPtr<AbstractThread> mOwnerThread;
const RefPtr<MediaDecoderReader> mReader;
bool mShutdown = false;
Maybe<media::TimeUnit> mStartTime;
-
- MozPromiseRequestHolder<WaitForDataPromise> mAudioWaitRequest;
- MozPromiseRequestHolder<WaitForDataPromise> mVideoWaitRequest;
};
} // namespace mozilla
#endif // MediaDecoderReaderWrapper_h_
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -232,17 +232,17 @@ protected:
MediaDecoderReaderWrapper* Reader() const { return mMaster->mReader; }
const MediaInfo& Info() const { return mMaster->Info(); }
bool IsExpectingMoreData() const
{
// We are expecting more data if either the resource states so, or if we
// have a waiting promise pending (such as with non-MSE EME).
return Resource()->IsExpectingMoreData() ||
(Reader()->IsWaitForDataSupported() &&
- (Reader()->IsWaitingAudioData() || Reader()->IsWaitingVideoData()));
+ (mMaster->IsWaitingAudioData() || mMaster->IsWaitingVideoData()));
}
MediaQueue<MediaData>& AudioQueue() const { return mMaster->mAudioQueue; }
MediaQueue<MediaData>& VideoQueue() const { return mMaster->mVideoQueue; }
// Note this function will delete the current state object.
// Don't access members to avoid UAF after this call.
template <class S, typename... Ts>
auto SetState(Ts... aArgs)
@@ -678,18 +678,18 @@ private:
return !mMaster->IsVideoDecoding() ||
static_cast<uint32_t>(mMaster->VideoQueue().GetSize()) >=
mMaster->VideoPrerollFrames() * mMaster->mPlaybackRate + 1;
}
void MaybeStopPrerolling()
{
if (mIsPrerolling &&
- (DonePrerollingAudio() || Reader()->IsWaitingAudioData()) &&
- (DonePrerollingVideo() || Reader()->IsWaitingVideoData())) {
+ (DonePrerollingAudio() || mMaster->IsWaitingAudioData()) &&
+ (DonePrerollingVideo() || mMaster->IsWaitingVideoData())) {
mIsPrerolling = false;
// Check if we can start playback.
mMaster->ScheduleStateMachine();
}
}
void EnterDormant()
{
@@ -923,17 +923,17 @@ public:
// Ignore pending requests from video-only seek.
if (aType == MediaData::AUDIO_DATA && mSeekJob.mTarget->IsVideoOnly()) {
return;
}
// If the decoder is waiting for data, we tell it to call us back when the
// data arrives.
if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
- Reader()->WaitForData(aType);
+ mMaster->WaitForData(aType);
return;
}
if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
if (aType == MediaData::AUDIO_DATA) {
RequestAudioData();
} else {
RequestVideoData();
@@ -1060,25 +1060,25 @@ private:
MOZ_ASSERT(NS_FAILED(aError), "Cancels should also disconnect mSeekRequest");
mMaster->DecodeError(aError);
}
void RequestAudioData()
{
MOZ_ASSERT(!mDoneAudioSeeking);
MOZ_ASSERT(!mMaster->IsRequestingAudioData());
- MOZ_ASSERT(!Reader()->IsWaitingAudioData());
+ MOZ_ASSERT(!mMaster->IsWaitingAudioData());
mMaster->RequestAudioData();
}
void RequestVideoData()
{
MOZ_ASSERT(!mDoneVideoSeeking);
MOZ_ASSERT(!mMaster->IsRequestingVideoData());
- MOZ_ASSERT(!Reader()->IsWaitingVideoData());
+ MOZ_ASSERT(!mMaster->IsWaitingVideoData());
mMaster->RequestVideoData(false, media::TimeUnit());
}
void AdjustFastSeekIfNeeded(MediaData* aSample)
{
if (mSeekJob.mTarget->IsFast() &&
mSeekJob.mTarget->GetTime() > mCurrentTimeBeforeSeek &&
aSample->mTime < mCurrentTimeBeforeSeek.ToMicroseconds()) {
@@ -1276,17 +1276,17 @@ private:
auto currentTime = mCurrentTime;
DiscardFrames(VideoQueue(), [currentTime] (int64_t aSampleTime) {
return aSampleTime <= currentTime;
});
if (!NeedMoreVideo()) {
FinishSeek();
} else if (!mMaster->IsRequestingVideoData() &&
- !Reader()->IsWaitingVideoData()) {
+ !mMaster->IsWaitingVideoData()) {
RequestVideoData();
}
}
class AysncNextFrameSeekTask : public Runnable
{
public:
explicit AysncNextFrameSeekTask(NextFrameSeekingState* aStateObject)
@@ -1362,17 +1362,17 @@ private:
VideoQueue().Finish();
FinishSeek();
break;
}
// Video seek not finished.
switch (aError.Code()) {
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
- Reader()->WaitForData(MediaData::VIDEO_DATA);
+ mMaster->WaitForData(MediaData::VIDEO_DATA);
break;
case NS_ERROR_DOM_MEDIA_CANCELED:
RequestVideoData();
break;
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
MOZ_ASSERT(false, "Shouldn't want more data for ended video.");
break;
default:
@@ -1711,17 +1711,17 @@ StateObject::HandleNotDecoded(MediaData:
bool isAudio = aType == MediaData::AUDIO_DATA;
MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA);
// If the decoder is waiting for data, we tell it to call us back when the
// data arrives.
if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
MOZ_ASSERT(Reader()->IsWaitForDataSupported(),
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
- Reader()->WaitForData(aType);
+ mMaster->WaitForData(aType);
HandleWaitingForData();
return;
}
if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
if (isAudio) {
mMaster->EnsureAudioDecodeTaskQueued();
} else {
@@ -2042,18 +2042,18 @@ DecodingState::MaybeStartBuffering()
bool shouldBuffer;
if (Reader()->UseBufferingHeuristics()) {
shouldBuffer = IsExpectingMoreData() &&
mMaster->HasLowDecodedData() &&
mMaster->HasLowBufferedData();
} else {
MOZ_ASSERT(Reader()->IsWaitForDataSupported());
shouldBuffer =
- (mMaster->OutOfDecodedAudio() && Reader()->IsWaitingAudioData()) ||
- (mMaster->OutOfDecodedVideo() && Reader()->IsWaitingVideoData());
+ (mMaster->OutOfDecodedAudio() && mMaster->IsWaitingAudioData()) ||
+ (mMaster->OutOfDecodedVideo() && mMaster->IsWaitingVideoData());
}
if (shouldBuffer) {
SetState<BufferingState>();
}
}
void
MediaDecoderStateMachine::
@@ -2133,21 +2133,21 @@ BufferingState::Step()
}
} else if (mMaster->OutOfDecodedAudio() || mMaster->OutOfDecodedVideo()) {
MOZ_ASSERT(Reader()->IsWaitForDataSupported(),
"Don't yet have a strategy for non-heuristic + non-WaitForData");
mMaster->DispatchDecodeTasksIfNeeded();
MOZ_ASSERT(mMaster->mMinimizePreroll ||
!mMaster->OutOfDecodedAudio() ||
mMaster->IsRequestingAudioData() ||
- Reader()->IsWaitingAudioData());
+ mMaster->IsWaitingAudioData());
MOZ_ASSERT(mMaster->mMinimizePreroll ||
!mMaster->OutOfDecodedVideo() ||
mMaster->IsRequestingVideoData() ||
- Reader()->IsWaitingVideoData());
+ mMaster->IsWaitingVideoData());
SLOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
"mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
mMaster->OutOfDecodedAudio(), mMaster->AudioRequestStatus(),
mMaster->OutOfDecodedVideo(), mMaster->VideoRequestStatus());
return;
}
SLOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
@@ -2184,16 +2184,18 @@ ShutdownState::Enter()
if (master->IsPlaying()) {
master->StopPlayback();
}
// To break the cycle-reference between MediaDecoderReaderWrapper and MDSM.
master->CancelMediaDecoderReaderWrapperCallback();
master->mAudioDataRequest.DisconnectIfExists();
master->mVideoDataRequest.DisconnectIfExists();
+ master->mAudioWaitRequest.DisconnectIfExists();
+ master->mVideoWaitRequest.DisconnectIfExists();
master->Reset();
master->mMediaSink->Shutdown();
// Prevent dangling pointers by disconnecting the listeners.
master->mAudioQueueListener.Disconnect();
master->mVideoQueueListener.Disconnect();
@@ -2710,42 +2712,22 @@ nsresult MediaDecoderStateMachine::Init(
return NS_OK;
}
void
MediaDecoderStateMachine::SetMediaDecoderReaderWrapperCallback()
{
MOZ_ASSERT(OnTaskQueue());
-
- mAudioWaitCallback = mReader->AudioWaitCallback().Connect(
- mTaskQueue, [this] (WaitCallbackData aData) {
- if (aData.is<MediaData::Type>()) {
- OnAudioWaited(aData.as<MediaData::Type>());
- } else {
- OnNotWaited(aData.as<WaitForDataRejectValue>());
- }
- });
-
- mVideoWaitCallback = mReader->VideoWaitCallback().Connect(
- mTaskQueue, [this] (WaitCallbackData aData) {
- if (aData.is<MediaData::Type>()) {
- OnVideoWaited(aData.as<MediaData::Type>());
- } else {
- OnNotWaited(aData.as<WaitForDataRejectValue>());
- }
- });
}
void
MediaDecoderStateMachine::CancelMediaDecoderReaderWrapperCallback()
{
MOZ_ASSERT(OnTaskQueue());
- mAudioWaitCallback.Disconnect();
- mVideoWaitCallback.Disconnect();
}
void MediaDecoderStateMachine::StopPlayback()
{
MOZ_ASSERT(OnTaskQueue());
DECODER_LOG("StopPlayback()");
mOnPlaybackEvent.Notify(MediaEventType::PlaybackStopped);
@@ -3065,17 +3047,17 @@ MediaDecoderStateMachine::EnsureAudioDec
if (mState != DECODER_STATE_DECODING &&
mState != DECODER_STATE_DECODING_FIRSTFRAME &&
mState != DECODER_STATE_BUFFERING) {
return;
}
if (!IsAudioDecoding() ||
IsRequestingAudioData() ||
- mReader->IsWaitingAudioData()) {
+ IsWaitingAudioData()) {
return;
}
RequestAudioData();
}
void
MediaDecoderStateMachine::RequestAudioData()
@@ -3113,17 +3095,17 @@ MediaDecoderStateMachine::EnsureVideoDec
if (mState != DECODER_STATE_DECODING &&
mState != DECODER_STATE_DECODING_FIRSTFRAME &&
mState != DECODER_STATE_BUFFERING) {
return;
}
if (!IsVideoDecoding() ||
IsRequestingVideoData() ||
- mReader->IsWaitingVideoData()) {
+ IsWaitingVideoData()) {
return;
}
RequestVideoData(NeedToSkipToNextKeyframe(),
media::TimeUnit::FromMicroseconds(GetMediaTime()));
}
void
@@ -3144,16 +3126,50 @@ MediaDecoderStateMachine::RequestVideoDa
},
[this] (const MediaResult& aError) {
OnVideoNotDecoded(aError);
})
);
}
void
+MediaDecoderStateMachine::WaitForData(MediaData::Type aType)
+{
+ MOZ_ASSERT(OnTaskQueue());
+ MOZ_ASSERT(aType == MediaData::AUDIO_DATA || aType == MediaData::VIDEO_DATA);
+ if (aType == MediaData::AUDIO_DATA) {
+ mAudioWaitRequest.Begin(
+ mReader->WaitForData(MediaData::AUDIO_DATA)->Then(
+ OwnerThread(), __func__,
+ [this] (MediaData::Type aType) {
+ mAudioWaitRequest.Complete();
+ OnAudioWaited(aType);
+ },
+ [this] (const WaitForDataRejectValue& aRejection) {
+ mAudioWaitRequest.Complete();
+ OnNotWaited(aRejection);
+ })
+ );
+ } else {
+ mVideoWaitRequest.Begin(
+ mReader->WaitForData(MediaData::VIDEO_DATA)->Then(
+ OwnerThread(), __func__,
+ [this] (MediaData::Type aType) {
+ mVideoWaitRequest.Complete();
+ OnVideoWaited(aType);
+ },
+ [this] (const WaitForDataRejectValue& aRejection) {
+ mVideoWaitRequest.Complete();
+ OnNotWaited(aRejection);
+ })
+ );
+ }
+}
+
+void
MediaDecoderStateMachine::StartMediaSink()
{
MOZ_ASSERT(OnTaskQueue());
if (!mMediaSink->IsStarted()) {
mAudioCompleted = false;
mMediaSink->Start(GetMediaTime(), Info());
auto videoPromise = mMediaSink->OnEnded(TrackInfo::kVideoTrack);
@@ -3371,23 +3387,25 @@ MediaDecoderStateMachine::Reset(TrackSet
StopMediaSink();
}
if (aTracks.contains(TrackInfo::kVideoTrack)) {
mDecodedVideoEndTime = 0;
mVideoCompleted = false;
VideoQueue().Reset();
mVideoDataRequest.DisconnectIfExists();
+ mVideoWaitRequest.DisconnectIfExists();
}
if (aTracks.contains(TrackInfo::kAudioTrack)) {
mDecodedAudioEndTime = 0;
mAudioCompleted = false;
AudioQueue().Reset();
mAudioDataRequest.DisconnectIfExists();
+ mAudioWaitRequest.DisconnectIfExists();
}
mPlaybackOffset = 0;
mReader->ResetDecode(aTracks);
}
int64_t
@@ -3781,32 +3799,32 @@ MediaDecoderStateMachine::OnMediaNotSeek
return mReader->OnMediaNotSeekable();
}
const char*
MediaDecoderStateMachine::AudioRequestStatus() const
{
MOZ_ASSERT(OnTaskQueue());
if (IsRequestingAudioData()) {
- MOZ_DIAGNOSTIC_ASSERT(!mReader->IsWaitingAudioData());
+ MOZ_DIAGNOSTIC_ASSERT(!IsWaitingAudioData());
return "pending";
- } else if (mReader->IsWaitingAudioData()) {
+ } else if (IsWaitingAudioData()) {
return "waiting";
}
return "idle";
}
const char*
MediaDecoderStateMachine::VideoRequestStatus() const
{
MOZ_ASSERT(OnTaskQueue());
if (IsRequestingVideoData()) {
- MOZ_DIAGNOSTIC_ASSERT(!mReader->IsWaitingVideoData());
+ MOZ_DIAGNOSTIC_ASSERT(!IsWaitingVideoData());
return "pending";
- } else if (mReader->IsWaitingVideoData()) {
+ } else if (IsWaitingVideoData()) {
return "waiting";
}
return "idle";
}
void
MediaDecoderStateMachine::OnSuspendTimerResolved()
{
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -472,18 +472,22 @@ protected:
// The decoder monitor must be held.
void RequestAudioData();
// Start a task to decode video.
// The decoder monitor must be held.
void RequestVideoData(bool aSkipToNextKeyframe,
const media::TimeUnit& aCurrentTime);
+ void WaitForData(MediaData::Type aType);
+
bool IsRequestingAudioData() const { return mAudioDataRequest.Exists(); }
bool IsRequestingVideoData() const { return mVideoDataRequest.Exists(); }
+ bool IsWaitingAudioData() const { return mAudioWaitRequest.Exists(); }
+ bool IsWaitingVideoData() const { return mVideoWaitRequest.Exists(); }
// Re-evaluates the state and determines whether we need to dispatch
// events to run the decode, or if not whether we should set the reader
// to idle mode. This is threadsafe, and can be called from any thread.
// The decoder monitor must be held.
void DispatchDecodeTasksIfNeeded();
// Returns the "media time". This is the absolute time which the media
@@ -654,23 +658,22 @@ private:
uint32_t VideoPrerollFrames() const
{
MOZ_ASSERT(OnTaskQueue());
return GetAmpleVideoFrames() / 2;
}
// Only one of a given pair of ({Audio,Video}DataPromise, WaitForDataPromise)
// should exist at any given moment.
-
- MediaEventListener mAudioWaitCallback;
- MediaEventListener mVideoWaitCallback;
-
using MediaDataPromise = MediaDecoderReader::MediaDataPromise;
+ using WaitForDataPromise = MediaDecoderReader::WaitForDataPromise;
MozPromiseRequestHolder<MediaDataPromise> mAudioDataRequest;
MozPromiseRequestHolder<MediaDataPromise> mVideoDataRequest;
+ MozPromiseRequestHolder<WaitForDataPromise> mAudioWaitRequest;
+ MozPromiseRequestHolder<WaitForDataPromise> mVideoWaitRequest;
const char* AudioRequestStatus() const;
const char* VideoRequestStatus() const;
void OnSuspendTimerResolved();
void OnSuspendTimerRejected();
// True if we shouldn't play our audio (but still write it to any capturing