2013-06-21 03:14:42 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "MediaSource.h"
|
|
|
|
|
2013-09-27 05:22:37 +00:00
|
|
|
#include "AsyncEventRunner.h"
|
|
|
|
#include "DecoderTraits.h"
|
2016-03-03 02:57:11 +00:00
|
|
|
#include "Benchmark.h"
|
2016-04-19 07:36:19 +00:00
|
|
|
#include "DecoderDoctorDiagnostics.h"
|
2017-01-18 00:59:03 +00:00
|
|
|
#include "MediaContainerType.h"
|
2016-09-11 22:54:10 +00:00
|
|
|
#include "MediaResult.h"
|
2014-08-20 08:07:00 +00:00
|
|
|
#include "MediaSourceUtils.h"
|
2013-06-21 03:14:42 +00:00
|
|
|
#include "SourceBuffer.h"
|
|
|
|
#include "SourceBufferList.h"
|
2013-09-27 05:22:37 +00:00
|
|
|
#include "mozilla/ErrorResult.h"
|
|
|
|
#include "mozilla/FloatingPoint.h"
|
2014-04-14 11:24:00 +00:00
|
|
|
#include "mozilla/Preferences.h"
|
2013-09-27 05:22:37 +00:00
|
|
|
#include "mozilla/dom/BindingDeclarations.h"
|
|
|
|
#include "mozilla/dom/HTMLMediaElement.h"
|
|
|
|
#include "mozilla/mozalloc.h"
|
|
|
|
#include "nsDebug.h"
|
|
|
|
#include "nsError.h"
|
|
|
|
#include "nsIRunnable.h"
|
2014-10-15 01:17:03 +00:00
|
|
|
#include "nsIScriptObjectPrincipal.h"
|
2013-09-27 05:22:37 +00:00
|
|
|
#include "nsPIDOMWindow.h"
|
2014-08-20 08:14:00 +00:00
|
|
|
#include "nsString.h"
|
2013-09-27 05:22:37 +00:00
|
|
|
#include "nsThreadUtils.h"
|
2015-05-19 18:15:34 +00:00
|
|
|
#include "mozilla/Logging.h"
|
2015-01-09 07:37:00 +00:00
|
|
|
#include "nsServiceManagerUtils.h"
|
2016-08-25 03:48:35 +00:00
|
|
|
#include "mozilla/gfx/gfxVars.h"
|
2016-08-15 06:43:21 +00:00
|
|
|
#include "mozilla/Sprintf.h"
|
2013-09-27 05:22:37 +00:00
|
|
|
|
2016-10-26 09:08:21 +00:00
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
|
|
#include "AndroidBridge.h"
|
|
|
|
#endif
|
|
|
|
|
2013-09-27 05:22:37 +00:00
|
|
|
struct JSContext;
|
|
|
|
class JSObject;
|
2013-06-21 03:14:42 +00:00
|
|
|
|
2015-11-15 13:49:01 +00:00
|
|
|
mozilla::LogModule* GetMediaSourceLog()
|
2014-08-11 01:21:17 +00:00
|
|
|
{
|
2015-11-15 13:49:01 +00:00
|
|
|
static mozilla::LazyLogModule sLogModule("MediaSource");
|
2014-08-11 01:21:17 +00:00
|
|
|
return sLogModule;
|
|
|
|
}
|
|
|
|
|
2015-11-15 13:49:01 +00:00
|
|
|
mozilla::LogModule* GetMediaSourceAPILog()
|
2014-08-11 01:21:17 +00:00
|
|
|
{
|
2015-11-15 13:49:01 +00:00
|
|
|
static mozilla::LazyLogModule sLogModule("MediaSource");
|
2014-08-11 01:21:17 +00:00
|
|
|
return sLogModule;
|
|
|
|
}
|
|
|
|
|
2015-06-03 22:25:57 +00:00
|
|
|
#define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("MediaSource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
|
|
|
#define MSE_API(arg, ...) MOZ_LOG(GetMediaSourceAPILog(), mozilla::LogLevel::Debug, ("MediaSource(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
2013-06-21 03:14:42 +00:00
|
|
|
|
2013-09-27 05:22:37 +00:00
|
|
|
// Arbitrary limit.
|
|
|
|
static const unsigned int MAX_SOURCE_BUFFERS = 16;
|
|
|
|
|
2013-06-21 03:14:42 +00:00
|
|
|
namespace mozilla {
|
|
|
|
|
2015-10-27 01:52:28 +00:00
|
|
|
// Returns true if we should enable MSE webm regardless of preferences.
|
|
|
|
// 1. If MP4/H264 isn't supported:
|
|
|
|
// * Windows XP
|
|
|
|
// * Windows Vista and Server 2008 without the optional "Platform Update Supplement"
|
|
|
|
// * N/KN editions (Europe and Korea) of Windows 7/8/8.1/10 without the
|
|
|
|
// optional "Windows Media Feature Pack"
|
2015-10-28 03:14:11 +00:00
|
|
|
// 2. If H264 hardware acceleration is not available.
|
2016-03-03 02:57:11 +00:00
|
|
|
// 3. The CPU is considered to be fast enough
|
2015-10-27 01:52:28 +00:00
|
|
|
static bool
|
2016-04-19 07:36:19 +00:00
|
|
|
IsWebMForced(DecoderDoctorDiagnostics* aDiagnostics)
|
2015-10-27 01:52:28 +00:00
|
|
|
{
|
|
|
|
bool mp4supported =
|
2017-01-18 00:59:03 +00:00
|
|
|
DecoderTraits::IsMP4SupportedType(MediaContainerType(MEDIAMIMETYPE("video/mp4")),
|
2017-01-01 01:27:45 +00:00
|
|
|
aDiagnostics);
|
2016-08-25 03:48:35 +00:00
|
|
|
bool hwsupported = gfx::gfxVars::CanUseHardwareVideoDecoding();
|
2016-10-26 09:08:21 +00:00
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
|
|
return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast() ||
|
|
|
|
java::HardwareCodecCapabilityUtils::HasHWVP9();
|
|
|
|
#else
|
2016-03-09 04:34:50 +00:00
|
|
|
return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast();
|
2016-10-26 09:08:21 +00:00
|
|
|
#endif
|
2015-10-27 01:52:28 +00:00
|
|
|
}
|
|
|
|
|
2016-07-01 01:36:57 +00:00
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
nsresult
|
|
|
|
MediaSource::IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* aDiagnostics)
|
2014-03-05 03:35:47 +00:00
|
|
|
{
|
|
|
|
if (aType.IsEmpty()) {
|
2016-07-14 10:47:02 +00:00
|
|
|
return NS_ERROR_DOM_TYPE_ERR;
|
2014-03-05 03:35:47 +00:00
|
|
|
}
|
2016-09-29 13:10:15 +00:00
|
|
|
|
2017-01-18 00:59:03 +00:00
|
|
|
Maybe<MediaContainerType> containerType = MakeMediaContainerType(aType);
|
|
|
|
if (!containerType) {
|
2017-01-13 03:58:23 +00:00
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
2014-03-05 03:35:47 +00:00
|
|
|
}
|
2015-07-21 04:03:57 +00:00
|
|
|
|
2017-01-18 00:59:03 +00:00
|
|
|
if (DecoderTraits::CanHandleContainerType(*containerType, aDiagnostics)
|
2016-09-29 13:10:15 +00:00
|
|
|
== CANPLAY_NO) {
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
}
|
2015-07-21 04:03:57 +00:00
|
|
|
|
2016-09-29 13:10:15 +00:00
|
|
|
// Now we know that this media type could be played.
|
|
|
|
// MediaSource imposes extra restrictions, and some prefs.
|
2017-01-18 00:59:03 +00:00
|
|
|
const MediaMIMEType& mimeType = containerType->Type();
|
2016-12-31 22:24:24 +00:00
|
|
|
if (mimeType == MEDIAMIMETYPE("video/mp4") ||
|
|
|
|
mimeType == MEDIAMIMETYPE("audio/mp4")) {
|
2016-09-29 13:10:15 +00:00
|
|
|
if (!Preferences::GetBool("media.mediasource.mp4.enabled", false)) {
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2016-12-31 22:24:24 +00:00
|
|
|
if (mimeType == MEDIAMIMETYPE("video/webm")) {
|
2016-09-29 13:10:15 +00:00
|
|
|
if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
|
|
|
|
IsWebMForced(aDiagnostics))) {
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
2014-03-05 03:35:47 +00:00
|
|
|
}
|
2016-09-29 13:10:15 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2016-12-31 22:24:24 +00:00
|
|
|
if (mimeType == MEDIAMIMETYPE("audio/webm")) {
|
2016-09-29 13:10:15 +00:00
|
|
|
if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
|
2016-10-26 09:31:22 +00:00
|
|
|
Preferences::GetBool("media.mediasource.webm.audio.enabled", true))) {
|
2016-09-29 13:10:15 +00:00
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
2014-03-05 03:35:47 +00:00
|
|
|
}
|
2015-06-28 02:17:35 +00:00
|
|
|
|
2015-07-21 04:03:57 +00:00
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
2014-03-05 03:35:47 +00:00
|
|
|
}
|
|
|
|
|
2013-06-21 03:14:42 +00:00
|
|
|
/* static */ already_AddRefed<MediaSource>
|
2013-08-23 05:17:08 +00:00
|
|
|
MediaSource::Constructor(const GlobalObject& aGlobal,
|
|
|
|
ErrorResult& aRv)
|
2013-06-21 03:14:42 +00:00
|
|
|
{
|
2016-01-30 17:05:36 +00:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
|
2013-06-21 03:14:42 +00:00
|
|
|
if (!window) {
|
|
|
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 05:24:48 +00:00
|
|
|
RefPtr<MediaSource> mediaSource = new MediaSource(window);
|
2013-06-21 03:14:42 +00:00
|
|
|
return mediaSource.forget();
|
|
|
|
}
|
|
|
|
|
2014-06-14 14:04:01 +00:00
|
|
|
MediaSource::~MediaSource()
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_API("");
|
2014-08-28 03:44:58 +00:00
|
|
|
if (mDecoder) {
|
|
|
|
mDecoder->DetachMediaSource();
|
|
|
|
}
|
2014-06-14 14:04:01 +00:00
|
|
|
}
|
|
|
|
|
2013-06-21 03:14:42 +00:00
|
|
|
SourceBufferList*
|
|
|
|
MediaSource::SourceBuffers()
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-06-21 03:14:42 +00:00
|
|
|
MOZ_ASSERT_IF(mReadyState == MediaSourceReadyState::Closed, mSourceBuffers->IsEmpty());
|
|
|
|
return mSourceBuffers;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceBufferList*
|
|
|
|
MediaSource::ActiveSourceBuffers()
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-06-21 03:14:42 +00:00
|
|
|
MOZ_ASSERT_IF(mReadyState == MediaSourceReadyState::Closed, mActiveSourceBuffers->IsEmpty());
|
|
|
|
return mActiveSourceBuffers;
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaSourceReadyState
|
|
|
|
MediaSource::ReadyState()
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-06-21 03:14:42 +00:00
|
|
|
return mReadyState;
|
|
|
|
}
|
|
|
|
|
|
|
|
double
|
|
|
|
MediaSource::Duration()
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-06-21 03:14:42 +00:00
|
|
|
if (mReadyState == MediaSourceReadyState::Closed) {
|
2014-02-27 15:23:16 +00:00
|
|
|
return UnspecifiedNaN<double>();
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
2014-11-12 04:11:33 +00:00
|
|
|
MOZ_ASSERT(mDecoder);
|
2016-07-15 13:38:33 +00:00
|
|
|
return mDecoder->GetDuration();
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSource::SetDuration(double aDuration, ErrorResult& aRv)
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_API("SetDuration(aDuration=%f, ErrorResult)", aDuration);
|
2013-06-21 03:14:42 +00:00
|
|
|
if (aDuration < 0 || IsNaN(aDuration)) {
|
2016-07-14 10:47:02 +00:00
|
|
|
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
|
2013-06-21 03:14:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (mReadyState != MediaSourceReadyState::Open ||
|
|
|
|
mSourceBuffers->AnyUpdating()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
2016-07-15 13:38:33 +00:00
|
|
|
DurationChange(aDuration, aRv);
|
2015-01-09 01:34:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-07-15 13:38:33 +00:00
|
|
|
MediaSource::SetDuration(double aDuration)
|
2015-01-09 01:34:41 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_API("SetDuration(aDuration=%f)", aDuration);
|
2016-07-15 13:38:33 +00:00
|
|
|
mDecoder->SetMediaSourceDuration(aDuration);
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<SourceBuffer>
|
|
|
|
MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv)
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-04-19 07:36:19 +00:00
|
|
|
DecoderDoctorDiagnostics diagnostics;
|
2016-07-01 01:36:57 +00:00
|
|
|
nsresult rv = IsTypeSupported(aType, &diagnostics);
|
2016-04-22 03:42:11 +00:00
|
|
|
diagnostics.StoreFormatDiagnostics(GetOwner()
|
|
|
|
? GetOwner()->GetExtantDoc()
|
|
|
|
: nullptr,
|
|
|
|
aType, NS_SUCCEEDED(rv), __func__);
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_API("AddSourceBuffer(aType=%s)%s",
|
|
|
|
NS_ConvertUTF16toUTF8(aType).get(),
|
2014-08-11 01:21:17 +00:00
|
|
|
rv == NS_OK ? "" : " [not supported]");
|
2014-03-05 03:35:47 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
2013-06-21 03:14:42 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2013-09-27 05:22:37 +00:00
|
|
|
if (mSourceBuffers->Length() >= MAX_SOURCE_BUFFERS) {
|
2013-06-21 03:14:42 +00:00
|
|
|
aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (mReadyState != MediaSourceReadyState::Open) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2017-01-18 00:59:03 +00:00
|
|
|
Maybe<MediaContainerType> containerType = MakeMediaContainerType(aType);
|
|
|
|
if (!containerType) {
|
2013-09-27 05:22:37 +00:00
|
|
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
Bug 1331289 - Use MediaContainerType in MediaResource, SourceBuffer, TrackBuffersManager, and dependencies - r=jya
Continuing the work of replacing MIME strings with MediaContainerType, starting
from MediaResource and following the dependencies.
Most changes are mechanical: Just change ns*String into MediaContainerType, and
MIME string literals into MEDIAMIMETYPE("a/b").
Some checks for empty/invalid strings and lowercase comparisons can go, thanks
to the always-valid always-lowercase-MIME invariants of MediaContainerType.
One special case in is MediaSourceResource, which used to have an empty string
as its type (because its own type is not relevant, but its SourceBuffers carry
types). Because the inherited GetContentType *must* be overridden, and must
return a MediaContainerType, we needed a valid type even though it should not
be seen in the real world. I've chosen "application/x.mediasource" for that.
MozReview-Commit-ID: 1aCH75Kh2e6
--HG--
extra : rebase_source : 0d9cd9b69c264e5dcfc3845f80ee107f4bcbcd9a
2016-12-28 07:59:02 +00:00
|
|
|
RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer(this, *containerType);
|
2014-04-21 13:31:00 +00:00
|
|
|
if (!sourceBuffer) {
|
2014-04-14 11:24:00 +00:00
|
|
|
aRv.Throw(NS_ERROR_FAILURE); // XXX need a better error here
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-06-21 03:14:42 +00:00
|
|
|
mSourceBuffers->Append(sourceBuffer);
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_DEBUG("sourceBuffer=%p", sourceBuffer.get());
|
2013-06-21 03:14:42 +00:00
|
|
|
return sourceBuffer.forget();
|
|
|
|
}
|
|
|
|
|
2015-03-18 03:10:56 +00:00
|
|
|
void
|
|
|
|
MediaSource::SourceBufferIsActive(SourceBuffer* aSourceBuffer)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mActiveSourceBuffers->ClearSimple();
|
|
|
|
bool found = false;
|
|
|
|
for (uint32_t i = 0; i < mSourceBuffers->Length(); i++) {
|
|
|
|
SourceBuffer* sourceBuffer = mSourceBuffers->IndexedGetter(i, found);
|
|
|
|
MOZ_ALWAYS_TRUE(found);
|
|
|
|
if (sourceBuffer == aSourceBuffer) {
|
|
|
|
mActiveSourceBuffers->Append(aSourceBuffer);
|
|
|
|
} else if (sourceBuffer->IsActive()) {
|
|
|
|
mActiveSourceBuffers->AppendSimple(sourceBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-21 03:14:42 +00:00
|
|
|
void
|
|
|
|
MediaSource::RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv)
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-06-21 03:14:42 +00:00
|
|
|
SourceBuffer* sourceBuffer = &aSourceBuffer;
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_API("RemoveSourceBuffer(aSourceBuffer=%p)", sourceBuffer);
|
2013-06-21 03:14:42 +00:00
|
|
|
if (!mSourceBuffers->Contains(sourceBuffer)) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
|
|
|
|
return;
|
|
|
|
}
|
2015-02-04 09:20:16 +00:00
|
|
|
|
|
|
|
sourceBuffer->AbortBufferAppend();
|
|
|
|
// TODO:
|
|
|
|
// abort stream append loop (if running)
|
|
|
|
|
2013-06-21 03:14:42 +00:00
|
|
|
// TODO:
|
|
|
|
// For all sourceBuffer audioTracks, videoTracks, textTracks:
|
|
|
|
// set sourceBuffer to null
|
|
|
|
// remove sourceBuffer video, audio, text Tracks from MediaElement tracks
|
|
|
|
// remove sourceBuffer video, audio, text Tracks and fire "removetrack" at affected lists
|
|
|
|
// fire "removetrack" at modified MediaElement track lists
|
|
|
|
// If removed enabled/selected, fire "change" at affected MediaElement list.
|
|
|
|
if (mActiveSourceBuffers->Contains(sourceBuffer)) {
|
|
|
|
mActiveSourceBuffers->Remove(sourceBuffer);
|
|
|
|
}
|
|
|
|
mSourceBuffers->Remove(sourceBuffer);
|
|
|
|
// TODO: Free all resources associated with sourceBuffer
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSource::EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv)
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_API("EndOfStream(aError=%d)",
|
|
|
|
aError.WasPassed() ? uint32_t(aError.Value()) : 0);
|
2013-06-21 03:14:42 +00:00
|
|
|
if (mReadyState != MediaSourceReadyState::Open ||
|
|
|
|
mSourceBuffers->AnyUpdating()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
2014-03-05 03:35:47 +00:00
|
|
|
|
|
|
|
SetReadyState(MediaSourceReadyState::Ended);
|
|
|
|
mSourceBuffers->Ended();
|
|
|
|
if (!aError.WasPassed()) {
|
2016-07-15 13:38:33 +00:00
|
|
|
DurationChange(mSourceBuffers->GetHighestBufferedEndTime(), aRv);
|
2015-03-23 10:08:05 +00:00
|
|
|
// Notify reader that all data is now available.
|
|
|
|
mDecoder->Ended(true);
|
2014-03-05 03:35:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (aError.Value()) {
|
|
|
|
case MediaSourceEndOfStreamError::Network:
|
2015-08-14 02:02:57 +00:00
|
|
|
mDecoder->NetworkError();
|
2014-03-05 03:35:47 +00:00
|
|
|
break;
|
|
|
|
case MediaSourceEndOfStreamError::Decode:
|
2016-09-10 14:56:09 +00:00
|
|
|
mDecoder->DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
2014-03-05 03:35:47 +00:00
|
|
|
break;
|
|
|
|
default:
|
2016-07-14 10:47:02 +00:00
|
|
|
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
|
2014-03-05 03:35:47 +00:00
|
|
|
}
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
|
|
|
|
2016-09-11 22:54:10 +00:00
|
|
|
void
|
|
|
|
MediaSource::EndOfStream(const MediaResult& aError)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-12-16 03:16:31 +00:00
|
|
|
MSE_API("EndOfStream(aError=%" PRId32")", static_cast<uint32_t>(aError.Code()));
|
2016-09-11 22:54:10 +00:00
|
|
|
|
|
|
|
SetReadyState(MediaSourceReadyState::Ended);
|
|
|
|
mSourceBuffers->Ended();
|
|
|
|
mDecoder->DecodeError(aError);
|
|
|
|
}
|
|
|
|
|
2013-06-21 03:14:42 +00:00
|
|
|
/* static */ bool
|
2016-04-19 07:36:19 +00:00
|
|
|
MediaSource::IsTypeSupported(const GlobalObject& aOwner, const nsAString& aType)
|
2013-06-21 03:14:42 +00:00
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-04-19 07:36:19 +00:00
|
|
|
DecoderDoctorDiagnostics diagnostics;
|
2016-07-01 01:36:57 +00:00
|
|
|
nsresult rv = IsTypeSupported(aType, &diagnostics);
|
2016-04-19 07:36:19 +00:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aOwner.GetAsSupports());
|
2016-04-22 03:42:11 +00:00
|
|
|
diagnostics.StoreFormatDiagnostics(window ? window->GetExtantDoc() : nullptr,
|
|
|
|
aType, NS_SUCCEEDED(rv), __func__);
|
2015-02-12 07:52:13 +00:00
|
|
|
#define this nullptr
|
|
|
|
MSE_API("IsTypeSupported(aType=%s)%s ",
|
|
|
|
NS_ConvertUTF16toUTF8(aType).get(), rv == NS_OK ? "OK" : "[not supported]");
|
|
|
|
#undef this // don't ever remove this line !
|
2014-04-14 11:24:00 +00:00
|
|
|
return NS_SUCCEEDED(rv);
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
|
|
|
|
2015-01-08 16:57:10 +00:00
|
|
|
/* static */ bool
|
|
|
|
MediaSource::Enabled(JSContext* cx, JSObject* aGlobal)
|
|
|
|
{
|
2015-07-30 23:48:09 +00:00
|
|
|
return Preferences::GetBool("media.mediasource.enabled");
|
2015-01-08 16:57:10 +00:00
|
|
|
}
|
|
|
|
|
2016-07-14 04:34:45 +00:00
|
|
|
void
|
|
|
|
MediaSource::SetLiveSeekableRange(double aStart, double aEnd, ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
// 1. If the readyState attribute is not "open" then throw an InvalidStateError
|
|
|
|
// exception and abort these steps.
|
2016-07-16 04:35:02 +00:00
|
|
|
if (mReadyState != MediaSourceReadyState::Open) {
|
2016-07-14 04:34:45 +00:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-16 04:35:02 +00:00
|
|
|
// 2. If start is negative or greater than end, then throw a TypeError
|
2016-07-14 04:34:45 +00:00
|
|
|
// exception and abort these steps.
|
|
|
|
if (aStart < 0 || aStart > aEnd) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-16 04:35:02 +00:00
|
|
|
// 3. Set live seekable range to be a new normalized TimeRanges object
|
2016-07-14 04:34:45 +00:00
|
|
|
// containing a single range whose start position is start and end position is
|
|
|
|
// end.
|
|
|
|
mLiveSeekableRange =
|
|
|
|
Some(media::TimeInterval(media::TimeUnit::FromSeconds(aStart),
|
|
|
|
media::TimeUnit::FromSeconds(aEnd)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSource::ClearLiveSeekableRange(ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
// 1. If the readyState attribute is not "open" then throw an InvalidStateError
|
|
|
|
// exception and abort these steps.
|
2016-07-16 04:35:02 +00:00
|
|
|
if (mReadyState != MediaSourceReadyState::Open) {
|
2016-07-14 04:34:45 +00:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-16 04:35:02 +00:00
|
|
|
// 2. If live seekable range contains a range, then set live seekable range to
|
2016-07-14 04:34:45 +00:00
|
|
|
// be a new empty TimeRanges object.
|
|
|
|
mLiveSeekableRange.reset();
|
|
|
|
}
|
|
|
|
|
2013-06-21 03:14:42 +00:00
|
|
|
bool
|
2013-09-27 05:22:37 +00:00
|
|
|
MediaSource::Attach(MediaSourceDecoder* aDecoder)
|
2013-06-21 03:14:42 +00:00
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_DEBUG("Attach(aDecoder=%p) owner=%p", aDecoder, aDecoder->GetOwner());
|
2013-09-27 05:22:37 +00:00
|
|
|
MOZ_ASSERT(aDecoder);
|
2014-12-29 03:18:41 +00:00
|
|
|
MOZ_ASSERT(aDecoder->GetOwner());
|
2013-06-21 03:14:42 +00:00
|
|
|
if (mReadyState != MediaSourceReadyState::Closed) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-12-29 03:18:41 +00:00
|
|
|
MOZ_ASSERT(!mMediaElement);
|
|
|
|
mMediaElement = aDecoder->GetOwner()->GetMediaElement();
|
2014-08-28 03:44:58 +00:00
|
|
|
MOZ_ASSERT(!mDecoder);
|
2013-09-27 05:22:37 +00:00
|
|
|
mDecoder = aDecoder;
|
|
|
|
mDecoder->AttachMediaSource(this);
|
2013-06-21 03:14:42 +00:00
|
|
|
SetReadyState(MediaSourceReadyState::Open);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-09-27 05:22:37 +00:00
|
|
|
MediaSource::Detach()
|
2013-06-21 03:14:42 +00:00
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_DEBUG("mDecoder=%p owner=%p",
|
|
|
|
mDecoder.get(), mDecoder ? mDecoder->GetOwner() : nullptr);
|
2014-08-28 03:44:58 +00:00
|
|
|
if (!mDecoder) {
|
|
|
|
MOZ_ASSERT(mReadyState == MediaSourceReadyState::Closed);
|
|
|
|
MOZ_ASSERT(mActiveSourceBuffers->IsEmpty() && mSourceBuffers->IsEmpty());
|
|
|
|
return;
|
|
|
|
}
|
2014-12-29 03:18:41 +00:00
|
|
|
mMediaElement = nullptr;
|
2014-08-28 03:44:58 +00:00
|
|
|
SetReadyState(MediaSourceReadyState::Closed);
|
2014-08-29 00:47:14 +00:00
|
|
|
if (mActiveSourceBuffers) {
|
|
|
|
mActiveSourceBuffers->Clear();
|
|
|
|
}
|
|
|
|
if (mSourceBuffers) {
|
|
|
|
mSourceBuffers->Clear();
|
|
|
|
}
|
2015-06-11 23:26:57 +00:00
|
|
|
mDecoder->DetachMediaSource();
|
|
|
|
mDecoder = nullptr;
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
|
|
|
|
2016-01-30 17:05:36 +00:00
|
|
|
MediaSource::MediaSource(nsPIDOMWindowInner* aWindow)
|
2014-04-01 06:13:50 +00:00
|
|
|
: DOMEventTargetHelper(aWindow)
|
2013-09-27 05:22:37 +00:00
|
|
|
, mDecoder(nullptr)
|
2014-10-15 01:17:03 +00:00
|
|
|
, mPrincipal(nullptr)
|
2016-11-29 05:03:36 +00:00
|
|
|
, mAbstractMainThread(GetOwnerGlobal()->AbstractMainThreadFor(TaskCategory::Other))
|
2013-06-21 03:14:42 +00:00
|
|
|
, mReadyState(MediaSourceReadyState::Closed)
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-06-21 03:14:42 +00:00
|
|
|
mSourceBuffers = new SourceBufferList(this);
|
|
|
|
mActiveSourceBuffers = new SourceBufferList(this);
|
2014-10-15 01:17:03 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
|
|
|
|
if (sop) {
|
|
|
|
mPrincipal = sop->GetPrincipal();
|
|
|
|
}
|
|
|
|
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_API("MediaSource(aWindow=%p) mSourceBuffers=%p mActiveSourceBuffers=%p",
|
|
|
|
aWindow, mSourceBuffers.get(), mActiveSourceBuffers.get());
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSource::SetReadyState(MediaSourceReadyState aState)
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2013-06-21 03:14:42 +00:00
|
|
|
MOZ_ASSERT(aState != mReadyState);
|
2016-12-16 03:16:31 +00:00
|
|
|
MSE_DEBUG("SetReadyState(aState=%" PRIu32 ") mReadyState=%" PRIu32,
|
|
|
|
static_cast<uint32_t>(aState), static_cast<uint32_t>(mReadyState));
|
2013-06-21 03:14:42 +00:00
|
|
|
|
2013-10-05 08:03:50 +00:00
|
|
|
MediaSourceReadyState oldState = mReadyState;
|
|
|
|
mReadyState = aState;
|
|
|
|
|
|
|
|
if (mReadyState == MediaSourceReadyState::Open &&
|
|
|
|
(oldState == MediaSourceReadyState::Closed ||
|
|
|
|
oldState == MediaSourceReadyState::Ended)) {
|
2013-06-21 03:14:42 +00:00
|
|
|
QueueAsyncSimpleEvent("sourceopen");
|
2015-03-23 10:08:05 +00:00
|
|
|
if (oldState == MediaSourceReadyState::Ended) {
|
|
|
|
// Notify reader that more data may come.
|
|
|
|
mDecoder->Ended(false);
|
|
|
|
}
|
2013-06-21 03:14:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-05 08:03:50 +00:00
|
|
|
if (mReadyState == MediaSourceReadyState::Ended &&
|
|
|
|
oldState == MediaSourceReadyState::Open) {
|
2013-06-21 03:14:42 +00:00
|
|
|
QueueAsyncSimpleEvent("sourceended");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-05 08:03:50 +00:00
|
|
|
if (mReadyState == MediaSourceReadyState::Closed &&
|
|
|
|
(oldState == MediaSourceReadyState::Open ||
|
|
|
|
oldState == MediaSourceReadyState::Ended)) {
|
2013-06-21 03:14:42 +00:00
|
|
|
QueueAsyncSimpleEvent("sourceclose");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_WARNING("Invalid MediaSource readyState transition");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSource::DispatchSimpleEvent(const char* aName)
|
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_API("Dispatch event '%s'", aName);
|
2013-06-21 03:14:42 +00:00
|
|
|
DispatchTrustedEvent(NS_ConvertUTF8toUTF16(aName));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaSource::QueueAsyncSimpleEvent(const char* aName)
|
|
|
|
{
|
2015-02-12 07:52:13 +00:00
|
|
|
MSE_DEBUG("Queuing event '%s'", aName);
|
2013-09-27 05:22:37 +00:00
|
|
|
nsCOMPtr<nsIRunnable> event = new AsyncEventRunner<MediaSource>(this, aName);
|
2014-05-23 19:53:17 +00:00
|
|
|
NS_DispatchToMainThread(event);
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-07-15 13:38:33 +00:00
|
|
|
MediaSource::DurationChange(double aNewDuration, ErrorResult& aRv)
|
2013-06-21 03:14:42 +00:00
|
|
|
{
|
2014-08-11 01:21:18 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-07-15 13:38:33 +00:00
|
|
|
MSE_DEBUG("DurationChange(aNewDuration=%f)", aNewDuration);
|
2014-11-12 04:11:33 +00:00
|
|
|
|
2016-07-15 13:38:33 +00:00
|
|
|
// 1. If the current value of duration is equal to new duration, then return.
|
|
|
|
if (mDecoder->GetDuration() == aNewDuration) {
|
|
|
|
return;
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
2016-07-15 13:38:33 +00:00
|
|
|
|
|
|
|
// 2. If new duration is less than the highest starting presentation timestamp
|
|
|
|
// of any buffered coded frames for all SourceBuffer objects in sourceBuffers,
|
|
|
|
// then throw an InvalidStateError exception and abort these steps.
|
|
|
|
if (aNewDuration < mSourceBuffers->HighestStartTime()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-26 04:39:36 +00:00
|
|
|
// 3. Let highest end time be the largest track buffer ranges end time across
|
|
|
|
// all the track buffers across all SourceBuffer objects in sourceBuffers.
|
|
|
|
double highestEndTime = mSourceBuffers->HighestEndTime();
|
|
|
|
// 4. If new duration is less than highest end time, then
|
|
|
|
// 4.1 Update new duration to equal highest end time.
|
2016-07-15 13:38:33 +00:00
|
|
|
aNewDuration =
|
2016-08-26 04:39:36 +00:00
|
|
|
std::max(aNewDuration, highestEndTime);
|
2016-07-15 13:38:33 +00:00
|
|
|
|
|
|
|
// 5. Update the media duration to new duration and run the HTMLMediaElement
|
|
|
|
// duration change algorithm.
|
|
|
|
mDecoder->SetMediaSourceDuration(aNewDuration);
|
2013-06-21 03:14:42 +00:00
|
|
|
}
|
|
|
|
|
2015-01-29 02:35:55 +00:00
|
|
|
void
|
|
|
|
MediaSource::GetMozDebugReaderData(nsAString& aString)
|
|
|
|
{
|
2017-01-18 08:51:31 +00:00
|
|
|
nsAutoCString result;
|
|
|
|
mDecoder->GetMozDebugReaderData(result);
|
|
|
|
aString = NS_ConvertUTF8toUTF16(result);
|
2015-01-29 02:35:55 +00:00
|
|
|
}
|
|
|
|
|
2016-01-30 17:05:36 +00:00
|
|
|
nsPIDOMWindowInner*
|
2014-08-11 01:21:17 +00:00
|
|
|
MediaSource::GetParentObject() const
|
|
|
|
{
|
|
|
|
return GetOwner();
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject*
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 14:13:33 +00:00
|
|
|
MediaSource::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
2014-08-11 01:21:17 +00:00
|
|
|
{
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 14:13:33 +00:00
|
|
|
return MediaSourceBinding::Wrap(aCx, this, aGivenProto);
|
2014-06-02 22:25:42 +00:00
|
|
|
}
|
|
|
|
|
2014-04-25 16:49:00 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaSource, DOMEventTargetHelper,
|
2014-12-29 03:18:41 +00:00
|
|
|
mMediaElement,
|
2014-04-25 16:49:00 +00:00
|
|
|
mSourceBuffers, mActiveSourceBuffers)
|
2013-06-21 03:14:42 +00:00
|
|
|
|
2014-04-01 06:13:50 +00:00
|
|
|
NS_IMPL_ADDREF_INHERITED(MediaSource, DOMEventTargetHelper)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(MediaSource, DOMEventTargetHelper)
|
2013-06-21 03:14:42 +00:00
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaSource)
|
2013-06-21 03:15:15 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(mozilla::dom::MediaSource)
|
2014-04-01 06:13:50 +00:00
|
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
2013-06-21 03:14:42 +00:00
|
|
|
|
2015-02-12 07:52:13 +00:00
|
|
|
#undef MSE_DEBUG
|
|
|
|
#undef MSE_API
|
|
|
|
|
2013-06-21 03:14:42 +00:00
|
|
|
} // namespace dom
|
2013-09-27 05:22:37 +00:00
|
|
|
|
2013-06-21 03:14:42 +00:00
|
|
|
} // namespace mozilla
|