Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 "ChannelMediaDecoder.h"
8 : #include "MediaResource.h"
9 : #include "MediaShutdownManager.h"
10 :
11 : namespace mozilla {
12 :
13 0 : ChannelMediaDecoder::ResourceCallback::ResourceCallback(
14 0 : AbstractThread* aMainThread)
15 0 : : mAbstractMainThread(aMainThread)
16 : {
17 0 : MOZ_ASSERT(aMainThread);
18 0 : }
19 :
20 : void
21 0 : ChannelMediaDecoder::ResourceCallback::Connect(ChannelMediaDecoder* aDecoder)
22 : {
23 0 : MOZ_ASSERT(NS_IsMainThread());
24 0 : mDecoder = aDecoder;
25 0 : mTimer = do_CreateInstance("@mozilla.org/timer;1");
26 0 : mTimer->SetTarget(mAbstractMainThread->AsEventTarget());
27 0 : }
28 :
29 : void
30 0 : ChannelMediaDecoder::ResourceCallback::Disconnect()
31 : {
32 0 : MOZ_ASSERT(NS_IsMainThread());
33 0 : if (mDecoder) {
34 0 : mDecoder = nullptr;
35 0 : mTimer->Cancel();
36 0 : mTimer = nullptr;
37 : }
38 0 : }
39 :
40 : MediaDecoderOwner*
41 0 : ChannelMediaDecoder::ResourceCallback::GetMediaOwner() const
42 : {
43 0 : MOZ_ASSERT(NS_IsMainThread());
44 0 : return mDecoder ? mDecoder->GetOwner() : nullptr;
45 : }
46 :
47 : void
48 0 : ChannelMediaDecoder::ResourceCallback::SetInfinite(bool aInfinite)
49 : {
50 0 : MOZ_ASSERT(NS_IsMainThread());
51 0 : if (mDecoder) {
52 0 : mDecoder->SetInfinite(aInfinite);
53 : }
54 0 : }
55 :
56 : void
57 0 : ChannelMediaDecoder::ResourceCallback::NotifyNetworkError()
58 : {
59 0 : MOZ_ASSERT(NS_IsMainThread());
60 0 : if (mDecoder) {
61 0 : mDecoder->NetworkError();
62 : }
63 0 : }
64 :
65 : /* static */ void
66 0 : ChannelMediaDecoder::ResourceCallback::TimerCallback(nsITimer* aTimer,
67 : void* aClosure)
68 : {
69 0 : MOZ_ASSERT(NS_IsMainThread());
70 0 : ResourceCallback* thiz = static_cast<ResourceCallback*>(aClosure);
71 0 : MOZ_ASSERT(thiz->mDecoder);
72 0 : thiz->mDecoder->NotifyDataArrivedInternal();
73 0 : thiz->mTimerArmed = false;
74 0 : }
75 :
76 : void
77 0 : ChannelMediaDecoder::ResourceCallback::NotifyDataArrived()
78 : {
79 0 : MOZ_ASSERT(NS_IsMainThread());
80 0 : if (!mDecoder) {
81 0 : return;
82 : }
83 :
84 0 : mDecoder->DownloadProgressed();
85 :
86 0 : if (mTimerArmed) {
87 0 : return;
88 : }
89 : // In situations where these notifications come from stochastic network
90 : // activity, we can save significant computation by throttling the
91 : // calls to MediaDecoder::NotifyDataArrived() which will update the buffer
92 : // ranges of the reader.
93 0 : mTimerArmed = true;
94 0 : mTimer->InitWithNamedFuncCallback(
95 : TimerCallback, this, sDelay, nsITimer::TYPE_ONE_SHOT,
96 0 : "ChannelMediaDecoder::ResourceCallback::TimerCallback");
97 : }
98 :
99 : void
100 0 : ChannelMediaDecoder::ResourceCallback::NotifyDataEnded(nsresult aStatus)
101 : {
102 0 : RefPtr<ResourceCallback> self = this;
103 0 : nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
104 : "ChannelMediaDecoder::ResourceCallback::NotifyDataEnded",
105 0 : [=]() {
106 0 : if (!self->mDecoder) {
107 0 : return;
108 : }
109 0 : self->mDecoder->NotifyDownloadEnded(aStatus);
110 0 : if (NS_SUCCEEDED(aStatus)) {
111 0 : MediaDecoderOwner* owner = self->GetMediaOwner();
112 0 : MOZ_ASSERT(owner);
113 0 : owner->DownloadSuspended();
114 :
115 : // NotifySuspendedStatusChanged will tell the element that download
116 : // has been suspended "by the cache", which is true since we never
117 : // download anything. The element can then transition to HAVE_ENOUGH_DATA.
118 0 : self->mDecoder->NotifySuspendedStatusChanged();
119 : }
120 0 : });
121 0 : mAbstractMainThread->Dispatch(r.forget());
122 0 : }
123 :
124 : void
125 0 : ChannelMediaDecoder::ResourceCallback::NotifyPrincipalChanged()
126 : {
127 0 : MOZ_ASSERT(NS_IsMainThread());
128 0 : if (mDecoder) {
129 0 : mDecoder->NotifyPrincipalChanged();
130 : }
131 0 : }
132 :
133 : void
134 0 : ChannelMediaDecoder::ResourceCallback::NotifySuspendedStatusChanged()
135 : {
136 0 : MOZ_ASSERT(NS_IsMainThread());
137 0 : if (mDecoder) {
138 0 : mDecoder->NotifySuspendedStatusChanged();
139 : }
140 0 : }
141 :
142 : void
143 0 : ChannelMediaDecoder::ResourceCallback::NotifyBytesConsumed(int64_t aBytes,
144 : int64_t aOffset)
145 : {
146 0 : RefPtr<ResourceCallback> self = this;
147 0 : nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
148 : "ChannelMediaDecoder::ResourceCallback::NotifyBytesConsumed",
149 0 : [=]() {
150 0 : if (self->mDecoder) {
151 0 : self->mDecoder->NotifyBytesConsumed(aBytes, aOffset);
152 : }
153 0 : });
154 0 : mAbstractMainThread->Dispatch(r.forget());
155 0 : }
156 :
157 0 : ChannelMediaDecoder::ChannelMediaDecoder(MediaDecoderInit& aInit)
158 : : MediaDecoder(aInit)
159 0 : , mResourceCallback(new ResourceCallback(aInit.mOwner->AbstractMainThread()))
160 : {
161 0 : mResourceCallback->Connect(this);
162 0 : }
163 :
164 : void
165 0 : ChannelMediaDecoder::Shutdown()
166 : {
167 0 : mResourceCallback->Disconnect();
168 0 : MediaDecoder::Shutdown();
169 0 : }
170 :
171 : nsresult
172 0 : ChannelMediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
173 : {
174 0 : MOZ_ASSERT(NS_IsMainThread());
175 0 : if (aStreamListener) {
176 0 : *aStreamListener = nullptr;
177 : }
178 0 : return mResource->Open(aStreamListener);
179 : }
180 :
181 : nsresult
182 0 : ChannelMediaDecoder::Load(nsIChannel* aChannel,
183 : bool aIsPrivateBrowsing,
184 : nsIStreamListener** aStreamListener)
185 : {
186 0 : MOZ_ASSERT(NS_IsMainThread());
187 0 : MOZ_ASSERT(!mResource);
188 :
189 : mResource =
190 0 : MediaResource::Create(mResourceCallback, aChannel, aIsPrivateBrowsing);
191 0 : if (!mResource) {
192 0 : return NS_ERROR_FAILURE;
193 : }
194 :
195 0 : nsresult rv = MediaShutdownManager::Instance().Register(this);
196 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
197 0 : return rv;
198 : }
199 :
200 0 : rv = OpenResource(aStreamListener);
201 0 : NS_ENSURE_SUCCESS(rv, rv);
202 :
203 0 : SetStateMachine(CreateStateMachine());
204 0 : NS_ENSURE_TRUE(GetStateMachine(), NS_ERROR_FAILURE);
205 :
206 0 : return InitializeStateMachine();
207 : }
208 :
209 : nsresult
210 0 : ChannelMediaDecoder::Load(MediaResource* aOriginal)
211 : {
212 0 : MOZ_ASSERT(NS_IsMainThread());
213 0 : MOZ_ASSERT(!mResource);
214 :
215 0 : mResource = aOriginal->CloneData(mResourceCallback);
216 0 : if (!mResource) {
217 0 : return NS_ERROR_FAILURE;
218 : }
219 :
220 0 : nsresult rv = MediaShutdownManager::Instance().Register(this);
221 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
222 0 : return rv;
223 : }
224 :
225 0 : rv = OpenResource(nullptr);
226 0 : NS_ENSURE_SUCCESS(rv, rv);
227 :
228 0 : SetStateMachine(CreateStateMachine());
229 0 : NS_ENSURE_TRUE(GetStateMachine(), NS_ERROR_FAILURE);
230 :
231 0 : return InitializeStateMachine();
232 : }
233 :
234 : } // namespace mozilla
|