|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set sw=2 ts=8 et 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 "RtspControllerChild.h" |
|
8 #include "RtspMetaData.h" |
|
9 #include "mozilla/dom/TabChild.h" |
|
10 #include "mozilla/net/NeckoChild.h" |
|
11 #include "nsITabChild.h" |
|
12 #include "nsILoadContext.h" |
|
13 #include "nsNetUtil.h" |
|
14 #include "mozilla/ipc/InputStreamUtils.h" |
|
15 #include "mozilla/ipc/URIUtils.h" |
|
16 #include "nsStringStream.h" |
|
17 #include "prlog.h" |
|
18 |
|
19 PRLogModuleInfo* gRtspChildLog = nullptr; |
|
20 #undef LOG |
|
21 #define LOG(args) PR_LOG(gRtspChildLog, PR_LOG_DEBUG, args) |
|
22 |
|
23 const uint32_t kRtspTotalTracks = 2; |
|
24 using namespace mozilla::ipc; |
|
25 |
|
26 namespace mozilla { |
|
27 namespace net { |
|
28 |
|
29 NS_IMPL_ADDREF(RtspControllerChild) |
|
30 |
|
31 NS_IMETHODIMP_(nsrefcnt) RtspControllerChild::Release() |
|
32 { |
|
33 NS_PRECONDITION(0 != mRefCnt, "dup release"); |
|
34 // Enable this to find non-threadsafe destructors: |
|
35 // NS_ASSERT_OWNINGTHREAD(RtspControllerChild); |
|
36 --mRefCnt; |
|
37 NS_LOG_RELEASE(this, mRefCnt, "RtspControllerChild"); |
|
38 |
|
39 if (mRefCnt == 1 && mIPCOpen) { |
|
40 Send__delete__(this); |
|
41 return mRefCnt; |
|
42 } |
|
43 |
|
44 if (mRefCnt == 0) { |
|
45 mRefCnt = 1; /* stabilize */ |
|
46 delete this; |
|
47 return 0; |
|
48 } |
|
49 return mRefCnt; |
|
50 } |
|
51 |
|
52 NS_INTERFACE_MAP_BEGIN(RtspControllerChild) |
|
53 NS_INTERFACE_MAP_ENTRY(nsIStreamingProtocolController) |
|
54 NS_INTERFACE_MAP_ENTRY(nsIStreamingProtocolListener) |
|
55 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamingProtocolController) |
|
56 NS_INTERFACE_MAP_END |
|
57 |
|
58 //----------------------------------------------------------------------------- |
|
59 // RtspControllerChild methods |
|
60 //----------------------------------------------------------------------------- |
|
61 RtspControllerChild::RtspControllerChild(nsIChannel *channel) |
|
62 : mIPCOpen(false) |
|
63 , mIPCAllowed(false) |
|
64 , mChannel(channel) |
|
65 , mTotalTracks(0) |
|
66 , mSuspendCount(0) |
|
67 { |
|
68 #if defined(PR_LOGGING) |
|
69 if (!gRtspChildLog) |
|
70 gRtspChildLog = PR_NewLogModule("nsRtspChild"); |
|
71 #endif |
|
72 AddIPDLReference(); |
|
73 gNeckoChild->SendPRtspControllerConstructor(this); |
|
74 } |
|
75 |
|
76 RtspControllerChild::~RtspControllerChild() |
|
77 { |
|
78 LOG(("RtspControllerChild::~RtspControllerChild()")); |
|
79 } |
|
80 |
|
81 void |
|
82 RtspControllerChild::ReleaseChannel() |
|
83 { |
|
84 static_cast<RtspChannelChild*>(mChannel.get())->ReleaseController(); |
|
85 } |
|
86 |
|
87 bool |
|
88 RtspControllerChild::OKToSendIPC() |
|
89 { |
|
90 MOZ_ASSERT(NS_IsMainThread()); |
|
91 if (mIPCOpen == false) { |
|
92 return false; |
|
93 } |
|
94 return mIPCAllowed; |
|
95 } |
|
96 |
|
97 void |
|
98 RtspControllerChild::AllowIPC() |
|
99 { |
|
100 MOZ_ASSERT(NS_IsMainThread()); |
|
101 mIPCAllowed = true; |
|
102 } |
|
103 |
|
104 void |
|
105 RtspControllerChild::DisallowIPC() |
|
106 { |
|
107 MOZ_ASSERT(NS_IsMainThread()); |
|
108 mIPCAllowed = false; |
|
109 } |
|
110 |
|
111 //----------------------------------------------------------------------------- |
|
112 // RtspControllerChild::PRtspControllerChild |
|
113 //----------------------------------------------------------------------------- |
|
114 bool |
|
115 RtspControllerChild::RecvOnMediaDataAvailable( |
|
116 const uint8_t& index, |
|
117 const nsCString& data, |
|
118 const uint32_t& length, |
|
119 const uint32_t& offset, |
|
120 const InfallibleTArray<RtspMetadataParam>& metaArray) |
|
121 { |
|
122 nsRefPtr<RtspMetaData> meta = new RtspMetaData(); |
|
123 nsresult rv = meta->DeserializeRtspMetaData(metaArray); |
|
124 NS_ENSURE_SUCCESS(rv, true); |
|
125 |
|
126 if (mListener) { |
|
127 mListener->OnMediaDataAvailable(index, data, length, offset, meta.get()); |
|
128 } |
|
129 return true; |
|
130 } |
|
131 |
|
132 void |
|
133 RtspControllerChild::AddMetaData( |
|
134 already_AddRefed<nsIStreamingProtocolMetaData>&& meta) |
|
135 { |
|
136 nsCOMPtr<nsIStreamingProtocolMetaData> data = meta; |
|
137 mMetaArray.AppendElement(data); |
|
138 } |
|
139 |
|
140 int |
|
141 RtspControllerChild::GetMetaDataLength() |
|
142 { |
|
143 return mMetaArray.Length(); |
|
144 } |
|
145 |
|
146 bool |
|
147 RtspControllerChild::RecvOnConnected( |
|
148 const uint8_t& index, |
|
149 const InfallibleTArray<RtspMetadataParam>& metaArray) |
|
150 { |
|
151 // Deserialize meta data. |
|
152 nsRefPtr<RtspMetaData> meta = new RtspMetaData(); |
|
153 nsresult rv = meta->DeserializeRtspMetaData(metaArray); |
|
154 NS_ENSURE_SUCCESS(rv, true); |
|
155 meta->GetTotalTracks(&mTotalTracks); |
|
156 if (mTotalTracks <= 0) { |
|
157 LOG(("RtspControllerChild::RecvOnConnected invalid tracks %d", mTotalTracks)); |
|
158 // Set the default value. |
|
159 mTotalTracks = kRtspTotalTracks; |
|
160 } |
|
161 AddMetaData(meta.forget().downcast<nsIStreamingProtocolMetaData>()); |
|
162 |
|
163 // Notify the listener when meta data of tracks are available. |
|
164 if ((static_cast<uint32_t>(index) + 1) == mTotalTracks) { |
|
165 // The controller provide |GetTrackMetaData| method for his client. |
|
166 if (mListener) { |
|
167 mListener->OnConnected(index, nullptr); |
|
168 } |
|
169 } |
|
170 return true; |
|
171 } |
|
172 |
|
173 bool |
|
174 RtspControllerChild::RecvOnDisconnected( |
|
175 const uint8_t& index, |
|
176 const nsresult& reason) |
|
177 { |
|
178 DisallowIPC(); |
|
179 LOG(("RtspControllerChild::RecvOnDisconnected for track %d reason = 0x%x", index, reason)); |
|
180 if (mListener) { |
|
181 mListener->OnDisconnected(index, reason); |
|
182 } |
|
183 ReleaseChannel(); |
|
184 return true; |
|
185 } |
|
186 |
|
187 bool |
|
188 RtspControllerChild::RecvAsyncOpenFailed(const nsresult& reason) |
|
189 { |
|
190 DisallowIPC(); |
|
191 LOG(("RtspControllerChild::RecvAsyncOpenFailed reason = 0x%x", reason)); |
|
192 if (mListener) { |
|
193 mListener->OnDisconnected(0, NS_ERROR_CONNECTION_REFUSED); |
|
194 } |
|
195 ReleaseChannel(); |
|
196 return true; |
|
197 } |
|
198 |
|
199 void |
|
200 RtspControllerChild::AddIPDLReference() |
|
201 { |
|
202 NS_ABORT_IF_FALSE(!mIPCOpen, |
|
203 "Attempt to retain more than one IPDL reference"); |
|
204 mIPCOpen = true; |
|
205 AllowIPC(); |
|
206 AddRef(); |
|
207 } |
|
208 |
|
209 void |
|
210 RtspControllerChild::ReleaseIPDLReference() |
|
211 { |
|
212 NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference"); |
|
213 mIPCOpen = false; |
|
214 DisallowIPC(); |
|
215 Release(); |
|
216 } |
|
217 |
|
218 NS_IMETHODIMP |
|
219 RtspControllerChild::GetTrackMetaData( |
|
220 uint8_t index, |
|
221 nsIStreamingProtocolMetaData **result) |
|
222 { |
|
223 if (GetMetaDataLength() <= 0 || index >= GetMetaDataLength()) { |
|
224 LOG(("RtspControllerChild:: meta data is not available")); |
|
225 return NS_ERROR_NOT_INITIALIZED; |
|
226 } |
|
227 LOG(("RtspControllerChild::GetTrackMetaData() %d", index)); |
|
228 NS_IF_ADDREF(*result = mMetaArray[index]); |
|
229 return NS_OK; |
|
230 } |
|
231 |
|
232 enum IPCEvent |
|
233 { |
|
234 SendNoneEvent = 0, |
|
235 SendPlayEvent, |
|
236 SendPauseEvent, |
|
237 SendSeekEvent, |
|
238 SendResumeEvent, |
|
239 SendSuspendEvent, |
|
240 SendStopEvent |
|
241 }; |
|
242 |
|
243 class SendIPCEvent : public nsRunnable |
|
244 { |
|
245 public: |
|
246 SendIPCEvent(RtspControllerChild *aController, IPCEvent aEvent) |
|
247 : mController(aController) |
|
248 , mEvent(aEvent) |
|
249 , mSeekTime(0) |
|
250 { |
|
251 } |
|
252 |
|
253 SendIPCEvent(RtspControllerChild *aController, |
|
254 IPCEvent aEvent, |
|
255 uint64_t aSeekTime) |
|
256 : mController(aController) |
|
257 , mEvent(aEvent) |
|
258 , mSeekTime(aSeekTime) |
|
259 { |
|
260 } |
|
261 |
|
262 NS_IMETHOD Run() |
|
263 { |
|
264 MOZ_ASSERT(NS_IsMainThread()); |
|
265 if (mController->OKToSendIPC() == false) { |
|
266 // Don't send any more IPC events; no guarantee that parent objects are |
|
267 // still alive. |
|
268 return NS_ERROR_FAILURE; |
|
269 } |
|
270 bool rv = true; |
|
271 |
|
272 if (mEvent == SendPlayEvent) { |
|
273 rv = mController->SendPlay(); |
|
274 } else if (mEvent == SendPauseEvent) { |
|
275 rv = mController->SendPause(); |
|
276 } else if (mEvent == SendSeekEvent) { |
|
277 rv = mController->SendSeek(mSeekTime); |
|
278 } else if (mEvent == SendResumeEvent) { |
|
279 rv = mController->SendResume(); |
|
280 } else if (mEvent == SendSuspendEvent) { |
|
281 rv = mController->SendSuspend(); |
|
282 } else if (mEvent == SendStopEvent) { |
|
283 rv = mController->SendStop(); |
|
284 } else { |
|
285 LOG(("RtspControllerChild::SendIPCEvent")); |
|
286 } |
|
287 if (!rv) { |
|
288 return NS_ERROR_FAILURE; |
|
289 } |
|
290 return NS_OK; |
|
291 } |
|
292 private: |
|
293 nsRefPtr<RtspControllerChild> mController; |
|
294 IPCEvent mEvent; |
|
295 uint64_t mSeekTime; |
|
296 }; |
|
297 |
|
298 //----------------------------------------------------------------------------- |
|
299 // RtspControllerChild::nsIStreamingProtocolController |
|
300 //----------------------------------------------------------------------------- |
|
301 NS_IMETHODIMP |
|
302 RtspControllerChild::Play(void) |
|
303 { |
|
304 LOG(("RtspControllerChild::Play()")); |
|
305 |
|
306 if (NS_IsMainThread()) { |
|
307 if (!OKToSendIPC() || !SendPlay()) { |
|
308 return NS_ERROR_FAILURE; |
|
309 } |
|
310 } else { |
|
311 nsresult rv = NS_DispatchToMainThread( |
|
312 new SendIPCEvent(this, SendPlayEvent)); |
|
313 NS_ENSURE_SUCCESS(rv, rv); |
|
314 } |
|
315 |
|
316 return NS_OK; |
|
317 } |
|
318 |
|
319 NS_IMETHODIMP |
|
320 RtspControllerChild::Pause(void) |
|
321 { |
|
322 LOG(("RtspControllerChild::Pause()")); |
|
323 |
|
324 if (NS_IsMainThread()) { |
|
325 if (!OKToSendIPC() || !SendPause()) { |
|
326 return NS_ERROR_FAILURE; |
|
327 } |
|
328 } else { |
|
329 nsresult rv = NS_DispatchToMainThread( |
|
330 new SendIPCEvent(this, SendPauseEvent)); |
|
331 NS_ENSURE_SUCCESS(rv, rv); |
|
332 } |
|
333 |
|
334 return NS_OK; |
|
335 } |
|
336 |
|
337 NS_IMETHODIMP |
|
338 RtspControllerChild::Resume(void) |
|
339 { |
|
340 LOG(("RtspControllerChild::Resume()")); |
|
341 NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED); |
|
342 |
|
343 if (!--mSuspendCount) { |
|
344 if (NS_IsMainThread()) { |
|
345 if (!OKToSendIPC() || !SendResume()) { |
|
346 return NS_ERROR_FAILURE; |
|
347 } |
|
348 } else { |
|
349 nsresult rv = NS_DispatchToMainThread( |
|
350 new SendIPCEvent(this, SendResumeEvent)); |
|
351 NS_ENSURE_SUCCESS(rv, rv); |
|
352 } |
|
353 } |
|
354 |
|
355 return NS_OK; |
|
356 } |
|
357 |
|
358 NS_IMETHODIMP |
|
359 RtspControllerChild::Suspend(void) |
|
360 { |
|
361 LOG(("RtspControllerChild::Suspend()")); |
|
362 |
|
363 if (!mSuspendCount++) { |
|
364 if (NS_IsMainThread()) { |
|
365 if (!OKToSendIPC() || !SendSuspend()) { |
|
366 return NS_ERROR_FAILURE; |
|
367 } |
|
368 } else { |
|
369 nsresult rv = NS_DispatchToMainThread( |
|
370 new SendIPCEvent(this, SendSuspendEvent)); |
|
371 NS_ENSURE_SUCCESS(rv, rv); |
|
372 } |
|
373 } |
|
374 |
|
375 return NS_OK; |
|
376 } |
|
377 |
|
378 NS_IMETHODIMP |
|
379 RtspControllerChild::Seek(uint64_t seekTimeUs) |
|
380 { |
|
381 LOG(("RtspControllerChild::Seek() %llu", seekTimeUs)); |
|
382 |
|
383 if (NS_IsMainThread()) { |
|
384 if (!OKToSendIPC() || !SendSeek(seekTimeUs)) { |
|
385 return NS_ERROR_FAILURE; |
|
386 } |
|
387 } else { |
|
388 nsresult rv = NS_DispatchToMainThread( |
|
389 new SendIPCEvent(this, SendSeekEvent, seekTimeUs)); |
|
390 NS_ENSURE_SUCCESS(rv, rv); |
|
391 } |
|
392 |
|
393 return NS_OK; |
|
394 } |
|
395 |
|
396 NS_IMETHODIMP |
|
397 RtspControllerChild::Stop() |
|
398 { |
|
399 LOG(("RtspControllerChild::Stop()")); |
|
400 |
|
401 if (NS_IsMainThread()) { |
|
402 if (!OKToSendIPC() || !SendStop()) { |
|
403 return NS_ERROR_FAILURE; |
|
404 } |
|
405 DisallowIPC(); |
|
406 } else { |
|
407 nsresult rv = NS_DispatchToMainThread( |
|
408 new SendIPCEvent(this, SendStopEvent)); |
|
409 NS_ENSURE_SUCCESS(rv, rv); |
|
410 } |
|
411 |
|
412 return NS_OK; |
|
413 } |
|
414 |
|
415 NS_IMETHODIMP |
|
416 RtspControllerChild::GetTotalTracks(uint8_t *aTracks) |
|
417 { |
|
418 NS_ENSURE_ARG_POINTER(aTracks); |
|
419 *aTracks = kRtspTotalTracks; |
|
420 if (mTotalTracks) { |
|
421 *aTracks = mTotalTracks; |
|
422 } |
|
423 LOG(("RtspControllerChild::GetTracks() %d", *aTracks)); |
|
424 return NS_OK; |
|
425 } |
|
426 |
|
427 //----------------------------------------------------------------------------- |
|
428 // RtspControllerChild::nsIStreamingProtocolListener |
|
429 //----------------------------------------------------------------------------- |
|
430 NS_IMETHODIMP |
|
431 RtspControllerChild::OnMediaDataAvailable(uint8_t index, |
|
432 const nsACString & data, |
|
433 uint32_t length, |
|
434 uint32_t offset, |
|
435 nsIStreamingProtocolMetaData *meta) |
|
436 { |
|
437 LOG(("RtspControllerChild::OnMediaDataAvailable()")); |
|
438 return NS_ERROR_NOT_IMPLEMENTED; |
|
439 } |
|
440 |
|
441 NS_IMETHODIMP |
|
442 RtspControllerChild::OnConnected(uint8_t index, |
|
443 nsIStreamingProtocolMetaData *meta) |
|
444 |
|
445 { |
|
446 LOG(("RtspControllerChild::OnConnected()")); |
|
447 return NS_ERROR_NOT_IMPLEMENTED; |
|
448 } |
|
449 |
|
450 NS_IMETHODIMP |
|
451 RtspControllerChild::OnDisconnected(uint8_t index, |
|
452 nsresult reason) |
|
453 { |
|
454 LOG(("RtspControllerChild::OnDisconnected() reason = 0x%x", reason)); |
|
455 return NS_ERROR_NOT_IMPLEMENTED; |
|
456 } |
|
457 |
|
458 //----------------------------------------------------------------------------- |
|
459 // RtspControllerChild::nsIStreamingProtocoController |
|
460 //----------------------------------------------------------------------------- |
|
461 NS_IMETHODIMP |
|
462 RtspControllerChild::Init(nsIURI *aURI) |
|
463 { |
|
464 nsresult rv; |
|
465 |
|
466 if (!aURI) { |
|
467 LOG(("RtspControllerChild::Init() - invalid URI")); |
|
468 return NS_ERROR_NOT_INITIALIZED; |
|
469 } |
|
470 |
|
471 nsAutoCString host; |
|
472 int32_t port = -1; |
|
473 |
|
474 rv = aURI->GetAsciiHost(host); |
|
475 if (NS_FAILED(rv)) return rv; |
|
476 |
|
477 // Reject the URL if it doesn't specify a host |
|
478 if (host.IsEmpty()) |
|
479 return NS_ERROR_MALFORMED_URI; |
|
480 |
|
481 rv = aURI->GetPort(&port); |
|
482 if (NS_FAILED(rv)) return rv; |
|
483 |
|
484 rv = aURI->GetAsciiSpec(mSpec); |
|
485 if (NS_FAILED(rv)) return rv; |
|
486 |
|
487 if (!strncmp(mSpec.get(), "rtsp:", 5) == 0) |
|
488 return NS_ERROR_UNEXPECTED; |
|
489 |
|
490 mURI = aURI; |
|
491 |
|
492 return NS_OK; |
|
493 } |
|
494 |
|
495 NS_IMETHODIMP |
|
496 RtspControllerChild::AsyncOpen(nsIStreamingProtocolListener *aListener) |
|
497 { |
|
498 LOG(("RtspControllerChild::AsyncOpen()")); |
|
499 if (!aListener) { |
|
500 LOG(("RtspControllerChild::AsyncOpen() - invalid listener")); |
|
501 return NS_ERROR_NOT_INITIALIZED; |
|
502 } |
|
503 mListener = aListener; |
|
504 |
|
505 if (!mChannel) { |
|
506 LOG(("RtspControllerChild::AsyncOpen() - invalid URI")); |
|
507 return NS_ERROR_NOT_INITIALIZED; |
|
508 } |
|
509 |
|
510 nsCOMPtr<nsIURI> uri; |
|
511 URIParams uriParams; |
|
512 mChannel->GetURI(getter_AddRefs(uri)); |
|
513 if (!uri) { |
|
514 LOG(("RtspControllerChild::AsyncOpen() - invalid URI")); |
|
515 return NS_ERROR_NOT_INITIALIZED; |
|
516 } |
|
517 SerializeURI(uri, uriParams); |
|
518 |
|
519 if (!OKToSendIPC() || !SendAsyncOpen(uriParams)) { |
|
520 return NS_ERROR_FAILURE; |
|
521 } |
|
522 return NS_OK; |
|
523 } |
|
524 |
|
525 } // namespace net |
|
526 } // namespace mozilla |