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/. */
6 
7 #include "mozilla/MozPromise.h"
8 #include "MediaFormatReader.h"
9 #include "ReaderProxy.h"
10 #include "TimeUnits.h"
11 
12 namespace mozilla {
13 
ReaderProxy(AbstractThread * aOwnerThread,MediaFormatReader * aReader)14 ReaderProxy::ReaderProxy(AbstractThread* aOwnerThread,
15                          MediaFormatReader* aReader)
16     : mOwnerThread(aOwnerThread),
17       mReader(aReader),
18       mWatchManager(this, aReader->OwnerThread()),
19       mDuration(aReader->OwnerThread(), media::NullableTimeUnit(),
20                 "ReaderProxy::mDuration (Mirror)") {
21   // Must support either heuristic buffering or WaitForData().
22   MOZ_ASSERT(mReader->UseBufferingHeuristics() ||
23              mReader->IsWaitForDataSupported());
24 }
25 
26 ReaderProxy::~ReaderProxy() = default;
27 
StartTime() const28 media::TimeUnit ReaderProxy::StartTime() const {
29   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
30   return mStartTime.ref();
31 }
32 
ReadMetadata()33 RefPtr<ReaderProxy::MetadataPromise> ReaderProxy::ReadMetadata() {
34   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
35   MOZ_ASSERT(!mShutdown);
36   return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
37                      &MediaFormatReader::AsyncReadMetadata)
38       ->Then(mOwnerThread, __func__, this, &ReaderProxy::OnMetadataRead,
39              &ReaderProxy::OnMetadataNotRead);
40 }
41 
OnAudioDataRequestCompleted(RefPtr<AudioData> aAudio)42 RefPtr<ReaderProxy::AudioDataPromise> ReaderProxy::OnAudioDataRequestCompleted(
43     RefPtr<AudioData> aAudio) {
44   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
45 
46   if (aAudio->AdjustForStartTime(StartTime())) {
47     return AudioDataPromise::CreateAndResolve(aAudio.forget(), __func__);
48   }
49   return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
50                                            __func__);
51 }
52 
OnAudioDataRequestFailed(const MediaResult & aError)53 RefPtr<ReaderProxy::AudioDataPromise> ReaderProxy::OnAudioDataRequestFailed(
54     const MediaResult& aError) {
55   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
56   return AudioDataPromise::CreateAndReject(aError, __func__);
57 }
58 
RequestAudioData()59 RefPtr<ReaderProxy::AudioDataPromise> ReaderProxy::RequestAudioData() {
60   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
61   MOZ_ASSERT(!mShutdown);
62 
63   return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
64                      &MediaFormatReader::RequestAudioData)
65       ->Then(mOwnerThread, __func__, this,
66              &ReaderProxy::OnAudioDataRequestCompleted,
67              &ReaderProxy::OnAudioDataRequestFailed);
68 }
69 
RequestVideoData(const media::TimeUnit & aTimeThreshold,bool aRequestNextVideoKeyFrame)70 RefPtr<ReaderProxy::VideoDataPromise> ReaderProxy::RequestVideoData(
71     const media::TimeUnit& aTimeThreshold, bool aRequestNextVideoKeyFrame) {
72   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
73   MOZ_ASSERT(!mShutdown);
74 
75   const auto threshold = aTimeThreshold > media::TimeUnit::Zero()
76                              ? aTimeThreshold + StartTime()
77                              : aTimeThreshold;
78 
79   auto startTime = StartTime();
80   return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
81                      &MediaFormatReader::RequestVideoData, threshold,
82                      aRequestNextVideoKeyFrame)
83       ->Then(
84           mOwnerThread, __func__,
85           [startTime](RefPtr<VideoData> aVideo) {
86             return aVideo->AdjustForStartTime(startTime)
87                        ? VideoDataPromise::CreateAndResolve(aVideo.forget(),
88                                                             __func__)
89                        : VideoDataPromise::CreateAndReject(
90                              NS_ERROR_DOM_MEDIA_OVERFLOW_ERR, __func__);
91           },
92           [](const MediaResult& aError) {
93             return VideoDataPromise::CreateAndReject(aError, __func__);
94           });
95 }
96 
Seek(const SeekTarget & aTarget)97 RefPtr<ReaderProxy::SeekPromise> ReaderProxy::Seek(const SeekTarget& aTarget) {
98   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
99   return SeekInternal(aTarget);
100 }
101 
SeekInternal(const SeekTarget & aTarget)102 RefPtr<ReaderProxy::SeekPromise> ReaderProxy::SeekInternal(
103     const SeekTarget& aTarget) {
104   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
105   SeekTarget adjustedTarget = aTarget;
106   adjustedTarget.SetTime(adjustedTarget.GetTime() + StartTime());
107   return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
108                      &MediaFormatReader::Seek, std::move(adjustedTarget));
109 }
110 
WaitForData(MediaData::Type aType)111 RefPtr<ReaderProxy::WaitForDataPromise> ReaderProxy::WaitForData(
112     MediaData::Type aType) {
113   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
114   MOZ_ASSERT(mReader->IsWaitForDataSupported());
115   return InvokeAsync(mReader->OwnerThread(), mReader.get(), __func__,
116                      &MediaFormatReader::WaitForData, aType);
117 }
118 
ReleaseResources()119 void ReaderProxy::ReleaseResources() {
120   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
121   nsCOMPtr<nsIRunnable> r =
122       NewRunnableMethod("MediaFormatReader::ReleaseResources", mReader,
123                         &MediaFormatReader::ReleaseResources);
124   nsresult rv = mReader->OwnerThread()->Dispatch(r.forget());
125   MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
126   Unused << rv;
127 }
128 
ResetDecode(TrackSet aTracks)129 void ReaderProxy::ResetDecode(TrackSet aTracks) {
130   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
131   nsCOMPtr<nsIRunnable> r =
132       NewRunnableMethod<TrackSet>("MediaFormatReader::ResetDecode", mReader,
133                                   &MediaFormatReader::ResetDecode, aTracks);
134   nsresult rv = mReader->OwnerThread()->Dispatch(r.forget());
135   MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
136   Unused << rv;
137 }
138 
Shutdown()139 RefPtr<ShutdownPromise> ReaderProxy::Shutdown() {
140   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
141   mShutdown = true;
142   RefPtr<ReaderProxy> self = this;
143   return InvokeAsync(mReader->OwnerThread(), __func__, [self]() {
144     self->mDuration.DisconnectIfConnected();
145     self->mWatchManager.Shutdown();
146     return self->mReader->Shutdown();
147   });
148 }
149 
OnMetadataRead(MetadataHolder && aMetadata)150 RefPtr<ReaderProxy::MetadataPromise> ReaderProxy::OnMetadataRead(
151     MetadataHolder&& aMetadata) {
152   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
153   if (mShutdown) {
154     return MetadataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_ABORT_ERR,
155                                             __func__);
156   }
157 
158   if (mStartTime.isNothing()) {
159     mStartTime.emplace(aMetadata.mInfo->mStartTime);
160   }
161   return MetadataPromise::CreateAndResolve(std::move(aMetadata), __func__);
162 }
163 
OnMetadataNotRead(const MediaResult & aError)164 RefPtr<ReaderProxy::MetadataPromise> ReaderProxy::OnMetadataNotRead(
165     const MediaResult& aError) {
166   return MetadataPromise::CreateAndReject(aError, __func__);
167 }
168 
SetVideoBlankDecode(bool aIsBlankDecode)169 void ReaderProxy::SetVideoBlankDecode(bool aIsBlankDecode) {
170   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
171   nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
172       "MediaFormatReader::SetVideoNullDecode", mReader,
173       &MediaFormatReader::SetVideoNullDecode, aIsBlankDecode);
174   nsresult rv = mReader->OwnerThread()->Dispatch(r.forget());
175   MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
176   Unused << rv;
177 }
178 
UpdateDuration()179 void ReaderProxy::UpdateDuration() {
180   MOZ_ASSERT(mReader->OwnerThread()->IsCurrentThreadIn());
181   mReader->UpdateDuration(mDuration.Ref().ref());
182 }
183 
SetCanonicalDuration(AbstractCanonical<media::NullableTimeUnit> * aCanonical)184 void ReaderProxy::SetCanonicalDuration(
185     AbstractCanonical<media::NullableTimeUnit>* aCanonical) {
186   using DurationT = AbstractCanonical<media::NullableTimeUnit>;
187   RefPtr<ReaderProxy> self = this;
188   RefPtr<DurationT> canonical = aCanonical;
189   nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
190       "ReaderProxy::SetCanonicalDuration", [this, self, canonical]() {
191         mDuration.Connect(canonical);
192         mWatchManager.Watch(mDuration, &ReaderProxy::UpdateDuration);
193       });
194   nsresult rv = mReader->OwnerThread()->Dispatch(r.forget());
195   MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
196   Unused << rv;
197 }
198 
199 }  // namespace mozilla
200