SourceBuffer.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "SourceBuffer.h"
  6. #include "AsyncEventRunner.h"
  7. #include "MediaData.h"
  8. #include "MediaSourceDemuxer.h"
  9. #include "MediaSourceUtils.h"
  10. #include "mozilla/ErrorResult.h"
  11. #include "mozilla/FloatingPoint.h"
  12. #include "mozilla/Preferences.h"
  13. #include "mozilla/dom/MediaSourceBinding.h"
  14. #include "mozilla/dom/TimeRanges.h"
  15. #include "nsError.h"
  16. #include "nsIEventTarget.h"
  17. #include "nsIRunnable.h"
  18. #include "nsThreadUtils.h"
  19. #include "mozilla/Logging.h"
  20. #include <time.h>
  21. #include "TimeUnits.h"
  22. // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
  23. // GetTickCount() and conflicts with MediaDecoder::GetCurrentTime implementation.
  24. #ifdef GetCurrentTime
  25. #undef GetCurrentTime
  26. #endif
  27. struct JSContext;
  28. class JSObject;
  29. extern mozilla::LogModule* GetMediaSourceLog();
  30. extern mozilla::LogModule* GetMediaSourceAPILog();
  31. #define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
  32. #define MSE_DEBUGV(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Verbose, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
  33. #define MSE_API(arg, ...) MOZ_LOG(GetMediaSourceAPILog(), mozilla::LogLevel::Debug, ("SourceBuffer(%p:%s)::%s: " arg, this, mType.get(), __func__, ##__VA_ARGS__))
  34. namespace mozilla {
  35. using media::TimeUnit;
  36. typedef SourceBufferAttributes::AppendState AppendState;
  37. namespace dom {
  38. void
  39. SourceBuffer::SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv)
  40. {
  41. MOZ_ASSERT(NS_IsMainThread());
  42. MSE_API("SetMode(aMode=%d)", aMode);
  43. if (!IsAttached() || mUpdating) {
  44. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  45. return;
  46. }
  47. if (mCurrentAttributes.mGenerateTimestamps &&
  48. aMode == SourceBufferAppendMode::Segments) {
  49. aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
  50. return;
  51. }
  52. MOZ_ASSERT(mMediaSource->ReadyState() != MediaSourceReadyState::Closed);
  53. if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
  54. mMediaSource->SetReadyState(MediaSourceReadyState::Open);
  55. }
  56. if (mCurrentAttributes.GetAppendState() == AppendState::PARSING_MEDIA_SEGMENT){
  57. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  58. return;
  59. }
  60. if (aMode == SourceBufferAppendMode::Sequence) {
  61. // Will set GroupStartTimestamp to GroupEndTimestamp.
  62. mCurrentAttributes.RestartGroupStartTimestamp();
  63. }
  64. mCurrentAttributes.SetAppendMode(aMode);
  65. }
  66. void
  67. SourceBuffer::SetTimestampOffset(double aTimestampOffset, ErrorResult& aRv)
  68. {
  69. MOZ_ASSERT(NS_IsMainThread());
  70. MSE_API("SetTimestampOffset(aTimestampOffset=%f)", aTimestampOffset);
  71. if (!IsAttached() || mUpdating) {
  72. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  73. return;
  74. }
  75. MOZ_ASSERT(mMediaSource->ReadyState() != MediaSourceReadyState::Closed);
  76. if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
  77. mMediaSource->SetReadyState(MediaSourceReadyState::Open);
  78. }
  79. if (mCurrentAttributes.GetAppendState() == AppendState::PARSING_MEDIA_SEGMENT){
  80. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  81. return;
  82. }
  83. mCurrentAttributes.SetApparentTimestampOffset(aTimestampOffset);
  84. if (mCurrentAttributes.GetAppendMode() == SourceBufferAppendMode::Sequence) {
  85. mCurrentAttributes.SetGroupStartTimestamp(mCurrentAttributes.GetTimestampOffset());
  86. }
  87. }
  88. TimeRanges*
  89. SourceBuffer::GetBuffered(ErrorResult& aRv)
  90. {
  91. MOZ_ASSERT(NS_IsMainThread());
  92. // http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
  93. // 1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an InvalidStateError exception and abort these steps.
  94. if (!IsAttached()) {
  95. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  96. return nullptr;
  97. }
  98. bool rangeChanged = true;
  99. media::TimeIntervals intersection = mTrackBuffersManager->Buffered();
  100. MSE_DEBUGV("intersection=%s", DumpTimeRanges(intersection).get());
  101. if (mBuffered) {
  102. media::TimeIntervals currentValue(mBuffered);
  103. rangeChanged = (intersection != currentValue);
  104. MSE_DEBUGV("currentValue=%s", DumpTimeRanges(currentValue).get());
  105. }
  106. // 5. If intersection ranges does not contain the exact same range information as the current value of this attribute, then update the current value of this attribute to intersection ranges.
  107. if (rangeChanged) {
  108. mBuffered = new TimeRanges(ToSupports(this));
  109. intersection.ToTimeRanges(mBuffered);
  110. }
  111. // 6. Return the current value of this attribute.
  112. return mBuffered;
  113. }
  114. media::TimeIntervals
  115. SourceBuffer::GetTimeIntervals()
  116. {
  117. return mTrackBuffersManager->Buffered();
  118. }
  119. void
  120. SourceBuffer::SetAppendWindowStart(double aAppendWindowStart, ErrorResult& aRv)
  121. {
  122. MOZ_ASSERT(NS_IsMainThread());
  123. MSE_API("SetAppendWindowStart(aAppendWindowStart=%f)", aAppendWindowStart);
  124. if (!IsAttached() || mUpdating) {
  125. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  126. return;
  127. }
  128. if (aAppendWindowStart < 0 ||
  129. aAppendWindowStart >= mCurrentAttributes.GetAppendWindowEnd()) {
  130. aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
  131. return;
  132. }
  133. mCurrentAttributes.SetAppendWindowStart(aAppendWindowStart);
  134. }
  135. void
  136. SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv)
  137. {
  138. MOZ_ASSERT(NS_IsMainThread());
  139. MSE_API("SetAppendWindowEnd(aAppendWindowEnd=%f)", aAppendWindowEnd);
  140. if (!IsAttached() || mUpdating) {
  141. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  142. return;
  143. }
  144. if (IsNaN(aAppendWindowEnd) ||
  145. aAppendWindowEnd <= mCurrentAttributes.GetAppendWindowStart()) {
  146. aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
  147. return;
  148. }
  149. mCurrentAttributes.SetAppendWindowEnd(aAppendWindowEnd);
  150. }
  151. void
  152. SourceBuffer::AppendBuffer(const ArrayBuffer& aData, ErrorResult& aRv)
  153. {
  154. MOZ_ASSERT(NS_IsMainThread());
  155. MSE_API("AppendBuffer(ArrayBuffer)");
  156. aData.ComputeLengthAndData();
  157. AppendData(aData.Data(), aData.Length(), aRv);
  158. }
  159. void
  160. SourceBuffer::AppendBuffer(const ArrayBufferView& aData, ErrorResult& aRv)
  161. {
  162. MOZ_ASSERT(NS_IsMainThread());
  163. MSE_API("AppendBuffer(ArrayBufferView)");
  164. aData.ComputeLengthAndData();
  165. AppendData(aData.Data(), aData.Length(), aRv);
  166. }
  167. void
  168. SourceBuffer::Abort(ErrorResult& aRv)
  169. {
  170. MOZ_ASSERT(NS_IsMainThread());
  171. MSE_API("Abort()");
  172. if (!IsAttached()) {
  173. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  174. return;
  175. }
  176. if (mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
  177. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  178. return;
  179. }
  180. if (mPendingRemoval.Exists()) {
  181. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  182. return;
  183. }
  184. AbortBufferAppend();
  185. ResetParserState();
  186. mCurrentAttributes.SetAppendWindowStart(0);
  187. mCurrentAttributes.SetAppendWindowEnd(PositiveInfinity<double>());
  188. }
  189. void
  190. SourceBuffer::AbortBufferAppend()
  191. {
  192. if (mUpdating) {
  193. if (mPendingAppend.Exists()) {
  194. mPendingAppend.Disconnect();
  195. mTrackBuffersManager->AbortAppendData();
  196. }
  197. AbortUpdating();
  198. }
  199. }
  200. void
  201. SourceBuffer::ResetParserState()
  202. {
  203. mTrackBuffersManager->ResetParserState(mCurrentAttributes);
  204. }
  205. void
  206. SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
  207. {
  208. MOZ_ASSERT(NS_IsMainThread());
  209. MSE_API("Remove(aStart=%f, aEnd=%f)", aStart, aEnd);
  210. if (!IsAttached()) {
  211. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  212. return;
  213. }
  214. if (mUpdating) {
  215. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  216. return;
  217. }
  218. if (IsNaN(mMediaSource->Duration()) ||
  219. aStart < 0 || aStart > mMediaSource->Duration() ||
  220. aEnd <= aStart || IsNaN(aEnd)) {
  221. aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
  222. return;
  223. }
  224. if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
  225. mMediaSource->SetReadyState(MediaSourceReadyState::Open);
  226. }
  227. RangeRemoval(aStart, aEnd);
  228. }
  229. void
  230. SourceBuffer::RangeRemoval(double aStart, double aEnd)
  231. {
  232. StartUpdating();
  233. RefPtr<SourceBuffer> self = this;
  234. mPendingRemoval.Begin(
  235. mTrackBuffersManager->RangeRemoval(TimeUnit::FromSeconds(aStart),
  236. TimeUnit::FromSeconds(aEnd))
  237. ->Then(AbstractThread::MainThread(), __func__,
  238. [self] (bool) {
  239. self->mPendingRemoval.Complete();
  240. self->StopUpdating();
  241. },
  242. []() { MOZ_ASSERT(false); }));
  243. }
  244. void
  245. SourceBuffer::Detach()
  246. {
  247. MOZ_ASSERT(NS_IsMainThread());
  248. MSE_DEBUG("Detach");
  249. if (!mMediaSource) {
  250. MSE_DEBUG("Already detached");
  251. return;
  252. }
  253. AbortBufferAppend();
  254. if (mTrackBuffersManager) {
  255. mTrackBuffersManager->Detach();
  256. mMediaSource->GetDecoder()->GetDemuxer()->DetachSourceBuffer(
  257. mTrackBuffersManager.get());
  258. }
  259. mTrackBuffersManager = nullptr;
  260. mMediaSource = nullptr;
  261. }
  262. void
  263. SourceBuffer::Ended()
  264. {
  265. MOZ_ASSERT(NS_IsMainThread());
  266. MOZ_ASSERT(IsAttached());
  267. MSE_DEBUG("Ended");
  268. mTrackBuffersManager->Ended();
  269. }
  270. SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
  271. : DOMEventTargetHelper(aMediaSource->GetParentObject())
  272. , mMediaSource(aMediaSource)
  273. , mCurrentAttributes(aType.LowerCaseEqualsLiteral("audio/mpeg") ||
  274. aType.LowerCaseEqualsLiteral("audio/aac"))
  275. , mUpdating(false)
  276. , mActive(false)
  277. , mType(aType)
  278. {
  279. MOZ_ASSERT(NS_IsMainThread());
  280. MOZ_ASSERT(aMediaSource);
  281. mTrackBuffersManager =
  282. new TrackBuffersManager(aMediaSource->GetDecoder(), aType);
  283. MSE_DEBUG("Create mTrackBuffersManager=%p",
  284. mTrackBuffersManager.get());
  285. ErrorResult dummy;
  286. if (mCurrentAttributes.mGenerateTimestamps) {
  287. SetMode(SourceBufferAppendMode::Sequence, dummy);
  288. } else {
  289. SetMode(SourceBufferAppendMode::Segments, dummy);
  290. }
  291. mMediaSource->GetDecoder()->GetDemuxer()->AttachSourceBuffer(
  292. mTrackBuffersManager.get());
  293. }
  294. SourceBuffer::~SourceBuffer()
  295. {
  296. MOZ_ASSERT(NS_IsMainThread());
  297. MOZ_ASSERT(!mMediaSource);
  298. MSE_DEBUG("");
  299. }
  300. MediaSource*
  301. SourceBuffer::GetParentObject() const
  302. {
  303. return mMediaSource;
  304. }
  305. JSObject*
  306. SourceBuffer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  307. {
  308. return SourceBufferBinding::Wrap(aCx, this, aGivenProto);
  309. }
  310. void
  311. SourceBuffer::DispatchSimpleEvent(const char* aName)
  312. {
  313. MOZ_ASSERT(NS_IsMainThread());
  314. MSE_API("Dispatch event '%s'", aName);
  315. DispatchTrustedEvent(NS_ConvertUTF8toUTF16(aName));
  316. }
  317. void
  318. SourceBuffer::QueueAsyncSimpleEvent(const char* aName)
  319. {
  320. MSE_DEBUG("Queuing event '%s'", aName);
  321. nsCOMPtr<nsIRunnable> event = new AsyncEventRunner<SourceBuffer>(this, aName);
  322. NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
  323. }
  324. void
  325. SourceBuffer::StartUpdating()
  326. {
  327. MOZ_ASSERT(NS_IsMainThread());
  328. MOZ_ASSERT(!mUpdating);
  329. mUpdating = true;
  330. QueueAsyncSimpleEvent("updatestart");
  331. }
  332. void
  333. SourceBuffer::StopUpdating()
  334. {
  335. MOZ_ASSERT(NS_IsMainThread());
  336. if (!mUpdating) {
  337. // The buffer append or range removal algorithm has been interrupted by
  338. // abort().
  339. return;
  340. }
  341. mUpdating = false;
  342. QueueAsyncSimpleEvent("update");
  343. QueueAsyncSimpleEvent("updateend");
  344. }
  345. void
  346. SourceBuffer::AbortUpdating()
  347. {
  348. MOZ_ASSERT(NS_IsMainThread());
  349. mUpdating = false;
  350. QueueAsyncSimpleEvent("abort");
  351. QueueAsyncSimpleEvent("updateend");
  352. }
  353. void
  354. SourceBuffer::CheckEndTime()
  355. {
  356. MOZ_ASSERT(NS_IsMainThread());
  357. // Check if we need to update mMediaSource duration
  358. double endTime = mCurrentAttributes.GetGroupEndTimestamp().ToSeconds();
  359. double duration = mMediaSource->Duration();
  360. if (endTime > duration) {
  361. mMediaSource->SetDuration(endTime);
  362. }
  363. }
  364. void
  365. SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
  366. {
  367. MSE_DEBUG("AppendData(aLength=%u)", aLength);
  368. RefPtr<MediaByteBuffer> data = PrepareAppend(aData, aLength, aRv);
  369. if (!data) {
  370. return;
  371. }
  372. StartUpdating();
  373. mPendingAppend.Begin(mTrackBuffersManager->AppendData(data, mCurrentAttributes)
  374. ->Then(AbstractThread::MainThread(), __func__, this,
  375. &SourceBuffer::AppendDataCompletedWithSuccess,
  376. &SourceBuffer::AppendDataErrored));
  377. }
  378. void
  379. SourceBuffer::AppendDataCompletedWithSuccess(SourceBufferTask::AppendBufferResult aResult)
  380. {
  381. MOZ_ASSERT(mUpdating);
  382. mPendingAppend.Complete();
  383. if (aResult.first()) {
  384. if (!mActive) {
  385. mActive = true;
  386. mMediaSource->SourceBufferIsActive(this);
  387. }
  388. }
  389. if (mActive) {
  390. // Tell our parent decoder that we have received new data.
  391. mMediaSource->GetDecoder()->NotifyDataArrived();
  392. // Send progress event.
  393. mMediaSource->GetDecoder()->NotifyBytesDownloaded();
  394. }
  395. mCurrentAttributes = aResult.second();
  396. CheckEndTime();
  397. StopUpdating();
  398. }
  399. void
  400. SourceBuffer::AppendDataErrored(const MediaResult& aError)
  401. {
  402. MOZ_ASSERT(mUpdating);
  403. mPendingAppend.Complete();
  404. switch (aError.Code()) {
  405. case NS_ERROR_DOM_MEDIA_CANCELED:
  406. // Nothing further to do as the trackbuffer has been shutdown.
  407. // or append was aborted and abort() has handled all the events.
  408. break;
  409. default:
  410. AppendError(aError);
  411. break;
  412. }
  413. }
  414. void
  415. SourceBuffer::AppendError(const MediaResult& aDecodeError)
  416. {
  417. MOZ_ASSERT(NS_IsMainThread());
  418. ResetParserState();
  419. mUpdating = false;
  420. QueueAsyncSimpleEvent("error");
  421. QueueAsyncSimpleEvent("updateend");
  422. MOZ_ASSERT(NS_FAILED(aDecodeError));
  423. mMediaSource->EndOfStream(aDecodeError);
  424. }
  425. already_AddRefed<MediaByteBuffer>
  426. SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
  427. {
  428. typedef TrackBuffersManager::EvictDataResult Result;
  429. if (!IsAttached() || mUpdating) {
  430. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  431. return nullptr;
  432. }
  433. // If the HTMLMediaElement.error attribute is not null, then throw an
  434. // InvalidStateError exception and abort these steps.
  435. if (!mMediaSource->GetDecoder() ||
  436. mMediaSource->GetDecoder()->OwnerHasError()) {
  437. MSE_DEBUG("HTMLMediaElement.error is not null");
  438. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  439. return nullptr;
  440. }
  441. if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
  442. mMediaSource->SetReadyState(MediaSourceReadyState::Open);
  443. }
  444. // Eviction uses a byte threshold. If the buffer is greater than the
  445. // number of bytes then data is evicted.
  446. // TODO: Drive evictions off memory pressure notifications.
  447. // TODO: Consider a global eviction threshold rather than per TrackBuffer.
  448. // Give a chance to the TrackBuffersManager to evict some data if needed.
  449. Result evicted =
  450. mTrackBuffersManager->EvictData(TimeUnit::FromSeconds(mMediaSource->GetDecoder()->GetCurrentTime()),
  451. aLength);
  452. // See if we have enough free space to append our new data.
  453. if (evicted == Result::BUFFER_FULL) {
  454. aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
  455. return nullptr;
  456. }
  457. RefPtr<MediaByteBuffer> data = new MediaByteBuffer();
  458. if (!data->AppendElements(aData, aLength, fallible)) {
  459. aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
  460. return nullptr;
  461. }
  462. return data.forget();
  463. }
  464. double
  465. SourceBuffer::GetBufferedStart()
  466. {
  467. MOZ_ASSERT(NS_IsMainThread());
  468. ErrorResult dummy;
  469. RefPtr<TimeRanges> ranges = GetBuffered(dummy);
  470. return ranges->Length() > 0 ? ranges->GetStartTime() : 0;
  471. }
  472. double
  473. SourceBuffer::GetBufferedEnd()
  474. {
  475. MOZ_ASSERT(NS_IsMainThread());
  476. ErrorResult dummy;
  477. RefPtr<TimeRanges> ranges = GetBuffered(dummy);
  478. return ranges->Length() > 0 ? ranges->GetEndTime() : 0;
  479. }
  480. double
  481. SourceBuffer::HighestStartTime()
  482. {
  483. MOZ_ASSERT(NS_IsMainThread());
  484. return mTrackBuffersManager
  485. ? mTrackBuffersManager->HighestStartTime().ToSeconds()
  486. : 0.0;
  487. }
  488. double
  489. SourceBuffer::HighestEndTime()
  490. {
  491. MOZ_ASSERT(NS_IsMainThread());
  492. return mTrackBuffersManager
  493. ? mTrackBuffersManager->HighestEndTime().ToSeconds()
  494. : 0.0;
  495. }
  496. NS_IMPL_CYCLE_COLLECTION_CLASS(SourceBuffer)
  497. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SourceBuffer)
  498. // Tell the TrackBuffer to end its current SourceBufferResource.
  499. TrackBuffersManager* manager = tmp->mTrackBuffersManager;
  500. if (manager) {
  501. manager->Detach();
  502. }
  503. NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaSource)
  504. NS_IMPL_CYCLE_COLLECTION_UNLINK(mBuffered)
  505. NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DOMEventTargetHelper)
  506. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SourceBuffer,
  507. DOMEventTargetHelper)
  508. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSource)
  509. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBuffered)
  510. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  511. NS_IMPL_ADDREF_INHERITED(SourceBuffer, DOMEventTargetHelper)
  512. NS_IMPL_RELEASE_INHERITED(SourceBuffer, DOMEventTargetHelper)
  513. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SourceBuffer)
  514. NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
  515. #undef MSE_DEBUG
  516. #undef MSE_DEBUGV
  517. #undef MSE_API
  518. } // namespace dom
  519. } // namespace mozilla