1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/CDMProxy.h"
8 #include "mozilla/MozPromise.h"
9 #include "MediaFormatReader.h"
10 #include "ReaderProxy.h"
11 #include "TimeUnits.h"
15 ReaderProxy::ReaderProxy(AbstractThread
* aOwnerThread
,
16 MediaFormatReader
* aReader
)
17 : mOwnerThread(aOwnerThread
),
19 mWatchManager(this, aReader
->OwnerThread()),
20 mDuration(aReader
->OwnerThread(), media::NullableTimeUnit(),
21 "ReaderProxy::mDuration (Mirror)") {
22 // Must support either heuristic buffering or WaitForData().
23 MOZ_ASSERT(mReader
->UseBufferingHeuristics() ||
24 mReader
->IsWaitForDataSupported());
27 ReaderProxy::~ReaderProxy() = default;
29 media::TimeUnit
ReaderProxy::StartTime() const {
30 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
31 return mStartTime
.ref();
34 RefPtr
<ReaderProxy::MetadataPromise
> ReaderProxy::ReadMetadata() {
35 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
36 MOZ_ASSERT(!mShutdown
);
37 return InvokeAsync(mReader
->OwnerThread(), mReader
.get(), __func__
,
38 &MediaFormatReader::AsyncReadMetadata
)
39 ->Then(mOwnerThread
, __func__
, this, &ReaderProxy::OnMetadataRead
,
40 &ReaderProxy::OnMetadataNotRead
);
43 RefPtr
<ReaderProxy::AudioDataPromise
> ReaderProxy::OnAudioDataRequestCompleted(
44 RefPtr
<AudioData
> aAudio
) {
45 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
47 if (aAudio
->AdjustForStartTime(StartTime())) {
48 return AudioDataPromise::CreateAndResolve(aAudio
.forget(), __func__
);
50 return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR
,
54 RefPtr
<ReaderProxy::AudioDataPromise
> ReaderProxy::OnAudioDataRequestFailed(
55 const MediaResult
& aError
) {
56 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
57 return AudioDataPromise::CreateAndReject(aError
, __func__
);
60 RefPtr
<ReaderProxy::AudioDataPromise
> ReaderProxy::RequestAudioData() {
61 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
62 MOZ_ASSERT(!mShutdown
);
64 return InvokeAsync(mReader
->OwnerThread(), mReader
.get(), __func__
,
65 &MediaFormatReader::RequestAudioData
)
66 ->Then(mOwnerThread
, __func__
, this,
67 &ReaderProxy::OnAudioDataRequestCompleted
,
68 &ReaderProxy::OnAudioDataRequestFailed
);
71 RefPtr
<ReaderProxy::VideoDataPromise
> ReaderProxy::RequestVideoData(
72 const media::TimeUnit
& aTimeThreshold
, bool aRequestNextVideoKeyFrame
) {
73 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
74 MOZ_ASSERT(!mShutdown
);
76 const auto threshold
= aTimeThreshold
> media::TimeUnit::Zero()
77 ? aTimeThreshold
+ StartTime()
80 auto startTime
= StartTime();
81 return InvokeAsync(mReader
->OwnerThread(), mReader
.get(), __func__
,
82 &MediaFormatReader::RequestVideoData
, threshold
,
83 aRequestNextVideoKeyFrame
)
85 mOwnerThread
, __func__
,
86 [startTime
](RefPtr
<VideoData
> aVideo
) {
87 return aVideo
->AdjustForStartTime(startTime
)
88 ? VideoDataPromise::CreateAndResolve(aVideo
.forget(),
90 : VideoDataPromise::CreateAndReject(
91 NS_ERROR_DOM_MEDIA_OVERFLOW_ERR
, __func__
);
93 [](const MediaResult
& aError
) {
94 return VideoDataPromise::CreateAndReject(aError
, __func__
);
98 RefPtr
<ReaderProxy::SeekPromise
> ReaderProxy::Seek(const SeekTarget
& aTarget
) {
99 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
100 return SeekInternal(aTarget
);
103 RefPtr
<ReaderProxy::SeekPromise
> ReaderProxy::SeekInternal(
104 const SeekTarget
& aTarget
) {
105 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
106 SeekTarget adjustedTarget
= aTarget
;
107 adjustedTarget
.SetTime(adjustedTarget
.GetTime() + StartTime());
108 return InvokeAsync(mReader
->OwnerThread(), mReader
.get(), __func__
,
109 &MediaFormatReader::Seek
, std::move(adjustedTarget
));
112 RefPtr
<ReaderProxy::WaitForDataPromise
> ReaderProxy::WaitForData(
113 MediaData::Type aType
) {
114 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
115 MOZ_ASSERT(mReader
->IsWaitForDataSupported());
116 return InvokeAsync(mReader
->OwnerThread(), mReader
.get(), __func__
,
117 &MediaFormatReader::WaitForData
, aType
);
120 void ReaderProxy::ReleaseResources() {
121 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
122 nsCOMPtr
<nsIRunnable
> r
=
123 NewRunnableMethod("MediaFormatReader::ReleaseResources", mReader
,
124 &MediaFormatReader::ReleaseResources
);
125 nsresult rv
= mReader
->OwnerThread()->Dispatch(r
.forget());
126 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv
));
130 void ReaderProxy::ResetDecode(TrackSet aTracks
) {
131 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
132 nsCOMPtr
<nsIRunnable
> r
=
133 NewRunnableMethod
<TrackSet
>("MediaFormatReader::ResetDecode", mReader
,
134 &MediaFormatReader::ResetDecode
, aTracks
);
135 nsresult rv
= mReader
->OwnerThread()->Dispatch(r
.forget());
136 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv
));
140 RefPtr
<ShutdownPromise
> ReaderProxy::Shutdown() {
141 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
143 RefPtr
<ReaderProxy
> self
= this;
144 return InvokeAsync(mReader
->OwnerThread(), __func__
, [self
]() {
145 self
->mDuration
.DisconnectIfConnected();
146 self
->mWatchManager
.Shutdown();
147 return self
->mReader
->Shutdown();
151 RefPtr
<ReaderProxy::MetadataPromise
> ReaderProxy::OnMetadataRead(
152 MetadataHolder
&& aMetadata
) {
153 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
155 return MetadataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_ABORT_ERR
,
159 if (mStartTime
.isNothing()) {
160 mStartTime
.emplace(aMetadata
.mInfo
->mStartTime
);
162 return MetadataPromise::CreateAndResolve(std::move(aMetadata
), __func__
);
165 RefPtr
<ReaderProxy::MetadataPromise
> ReaderProxy::OnMetadataNotRead(
166 const MediaResult
& aError
) {
167 return MetadataPromise::CreateAndReject(aError
, __func__
);
170 void ReaderProxy::SetVideoBlankDecode(bool aIsBlankDecode
) {
171 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
172 nsCOMPtr
<nsIRunnable
> r
= NewRunnableMethod
<bool>(
173 "MediaFormatReader::SetVideoNullDecode", mReader
,
174 &MediaFormatReader::SetVideoNullDecode
, aIsBlankDecode
);
175 nsresult rv
= mReader
->OwnerThread()->Dispatch(r
.forget());
176 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv
));
180 void ReaderProxy::UpdateDuration() {
181 MOZ_ASSERT(mReader
->OwnerThread()->IsCurrentThreadIn());
182 mReader
->UpdateDuration(mDuration
.Ref().ref());
185 void ReaderProxy::SetCanonicalDuration(
186 Canonical
<media::NullableTimeUnit
>& aCanonical
) {
187 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
188 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
189 "ReaderProxy::SetCanonicalDuration", [this, self
= RefPtr(this)]() {
190 mWatchManager
.Watch(mDuration
, &ReaderProxy::UpdateDuration
);
192 mReader
->OwnerThread()->DispatchStateChange(r
.forget());
193 aCanonical
.ConnectMirror(&mDuration
);
196 void ReaderProxy::UpdateMediaEngineId(uint64_t aMediaEngineId
) {
197 MOZ_ASSERT(mOwnerThread
->IsCurrentThreadIn());
198 nsCOMPtr
<nsIRunnable
> r
= NewRunnableMethod
<uint64_t>(
199 "MediaFormatReader::UpdateMediaEngineId", mReader
,
200 &MediaFormatReader::UpdateMediaEngineId
, aMediaEngineId
);
201 nsresult rv
= mReader
->OwnerThread()->Dispatch(r
.forget());
202 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv
));
206 RefPtr
<SetCDMPromise
> ReaderProxy::SetCDMProxy(CDMProxy
* aProxy
) {
207 return InvokeAsync
<RefPtr
<CDMProxy
>>(mReader
->OwnerThread(), mReader
.get(),
209 &MediaFormatReader::SetCDMProxy
, aProxy
);
212 } // namespace mozilla