void MediaSource::EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("EndOfStream(aError=%d)", aError.WasPassed() ? uint32_t(aError.Value()) : 0); if (mReadyState != MediaSourceReadyState::Open || mSourceBuffers->AnyUpdating()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } SetReadyState(MediaSourceReadyState::Ended); mSourceBuffers->Ended(); if (!aError.WasPassed()) { mDecoder->SetMediaSourceDuration(mSourceBuffers->GetHighestBufferedEndTime(), MSRangeRemovalAction::SKIP); if (aRv.Failed()) { return; } // Notify reader that all data is now available. mDecoder->Ended(true); return; } switch (aError.Value()) { case MediaSourceEndOfStreamError::Network: mDecoder->NetworkError(); break; case MediaSourceEndOfStreamError::Decode: mDecoder->DecodeError(); break; default: aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); } }
void SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("Remove(aStart=%f, aEnd=%f)", aStart, aEnd); if (!IsAttached()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (mUpdating) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (IsNaN(mMediaSource->Duration()) || aStart < 0 || aStart > mMediaSource->Duration() || aEnd <= aStart || IsNaN(aEnd)) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) { mMediaSource->SetReadyState(MediaSourceReadyState::Open); } StartUpdating(); nsCOMPtr<nsIRunnable> task = new RangeRemovalRunnable(this, aStart, aEnd); NS_DispatchToMainThread(task); }
void SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("Remove(aStart=%f, aEnd=%f)", aStart, aEnd); if (!IsAttached()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (mUpdating) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (IsNaN(mMediaSource->Duration()) || aStart < 0 || aStart > mMediaSource->Duration() || aEnd <= aStart || IsNaN(aEnd)) { aRv.Throw(NS_ERROR_DOM_TYPE_ERR); return; } if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) { mMediaSource->SetReadyState(MediaSourceReadyState::Open); } RangeRemoval(aStart, aEnd); }
void MediaSource::EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("EndOfStream(aError=%d)", aError.WasPassed() ? uint32_t(aError.Value()) : 0); if (mReadyState != MediaSourceReadyState::Open || mSourceBuffers->AnyUpdating()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } SetReadyState(MediaSourceReadyState::Ended); mSourceBuffers->Ended(); if (!aError.WasPassed()) { DurationChange(mSourceBuffers->GetHighestBufferedEndTime(), aRv); // Notify reader that all data is now available. mDecoder->Ended(true); return; } switch (aError.Value()) { case MediaSourceEndOfStreamError::Network: mDecoder->NetworkError(MediaResult(NS_ERROR_FAILURE, "MSE network")); break; case MediaSourceEndOfStreamError::Decode: mDecoder->DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR); break; default: aRv.Throw(NS_ERROR_DOM_TYPE_ERR); } }
void MediaSource::RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); SourceBuffer* sourceBuffer = &aSourceBuffer; MSE_API("MediaSource(%p)::RemoveSourceBuffer(aSourceBuffer=%p)", this, sourceBuffer); if (!mSourceBuffers->Contains(sourceBuffer)) { aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); return; } if (sourceBuffer->Updating()) { // TODO: // abort stream append loop (if running) // set updating to false // fire "abort" at sourceBuffer // fire "updateend" at sourceBuffer } // 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::SetDuration(double aDuration, MSRangeRemovalAction aAction) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("SetDuration(aDuration=%f)", aDuration); mDecoder->SetMediaSourceDuration(aDuration, aAction); }
void SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("SourceBuffer(%p)::Remove(aStart=%f, aEnd=%f)", this, aStart, aEnd); if (!IsAttached()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (IsNaN(mMediaSource->Duration()) || aStart < 0 || aStart > mMediaSource->Duration() || aEnd <= aStart || IsNaN(aEnd)) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } if (mUpdating || mMediaSource->ReadyState() != MediaSourceReadyState::Open) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } StartUpdating(); /// TODO: Run coded frame removal algorithm. // Run the final step of the coded frame removal algorithm asynchronously // to ensure the SourceBuffer's updating flag transition behaves as // required by the spec. nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating); NS_DispatchToMainThread(event); }
void SourceBufferList::DispatchSimpleEvent(const char* aName) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("Dispatch event '%s'", aName); DispatchTrustedEvent(NS_ConvertUTF8toUTF16(aName)); }
void MediaSource::DispatchSimpleEvent(const char* aName) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("MediaSource(%p) Dispatch event '%s'", this, aName); DispatchTrustedEvent(NS_ConvertUTF8toUTF16(aName)); }
void SourceBuffer::AppendBuffer(const ArrayBufferView& aData, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("AppendBuffer(ArrayBufferView)"); aData.ComputeLengthAndData(); AppendData(aData.Data(), aData.Length(), aRv); }
MediaSource::~MediaSource() { MOZ_ASSERT(NS_IsMainThread()); MSE_API(""); if (mDecoder) { mDecoder->DetachMediaSource(); } }
/* static */ bool MediaSource::IsTypeSupported(const GlobalObject&, const nsAString& aType) { MOZ_ASSERT(NS_IsMainThread()); nsresult rv = mozilla::IsTypeSupported(aType); MSE_API("MediaSource::IsTypeSupported(aType=%s)%s", NS_ConvertUTF16toUTF8(aType).get(), rv == NS_OK ? "" : " [not supported]"); return NS_SUCCEEDED(rv); }
void MediaSource::EndOfStream(const MediaResult& aError) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("EndOfStream(aError=%s)", aError.ErrorName().get()); SetReadyState(MediaSourceReadyState::Ended); mSourceBuffers->Ended(); mDecoder->DecodeError(aError); }
/* static */ bool MediaSource::IsTypeSupported(const GlobalObject&, const nsAString& aType) { MOZ_ASSERT(NS_IsMainThread()); nsresult rv = mozilla::IsTypeSupported(aType); #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 ! return NS_SUCCEEDED(rv); }
MediaSource::MediaSource(nsPIDOMWindow* aWindow) : DOMEventTargetHelper(aWindow) , mDuration(UnspecifiedNaN<double>()) , mDecoder(nullptr) , mReadyState(MediaSourceReadyState::Closed) , mWaitForDataMonitor("MediaSource.WaitForData.Monitor") { MOZ_ASSERT(NS_IsMainThread()); mSourceBuffers = new SourceBufferList(this); mActiveSourceBuffers = new SourceBufferList(this); MSE_API("MediaSource(%p)::MediaSource(aWindow=%p) mSourceBuffers=%p mActiveSourceBuffers=%p", this, aWindow, mSourceBuffers.get(), mActiveSourceBuffers.get()); }
/* static */ bool MediaSource::IsTypeSupported(const GlobalObject& aOwner, const nsAString& aType) { MOZ_ASSERT(NS_IsMainThread()); DecoderDoctorDiagnostics diagnostics; nsresult rv = IsTypeSupported(aType, &diagnostics); nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aOwner.GetAsSupports()); diagnostics.StoreFormatDiagnostics(window ? window->GetExtantDoc() : nullptr, aType, NS_SUCCEEDED(rv), __func__); #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 ! return NS_SUCCEEDED(rv); }
void SourceBuffer::SetAppendWindowStart(double aAppendWindowStart, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("SetAppendWindowStart(aAppendWindowStart=%f)", aAppendWindowStart); if (!IsAttached() || mUpdating) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (aAppendWindowStart < 0 || aAppendWindowStart >= mAppendWindowEnd) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } mAppendWindowStart = aAppendWindowStart; }
void MediaSource::SetDuration(double aDuration, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("SetDuration(aDuration=%f, ErrorResult)", aDuration); if (aDuration < 0 || IsNaN(aDuration)) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } if (mReadyState != MediaSourceReadyState::Open || mSourceBuffers->AnyUpdating()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } SetDuration(aDuration, MSRangeRemovalAction::RUN); }
void SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("SetAppendWindowEnd(aAppendWindowEnd=%f)", aAppendWindowEnd); if (!IsAttached() || mUpdating) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (IsNaN(aAppendWindowEnd) || aAppendWindowEnd <= mCurrentAttributes.GetAppendWindowStart()) { aRv.Throw(NS_ERROR_DOM_TYPE_ERR); return; } mCurrentAttributes.SetAppendWindowEnd(aAppendWindowEnd); }
void SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("SourceBuffer(%p)::SetAppendWindowEnd(aAppendWindowEnd=%f)", this, aAppendWindowEnd); if (!IsAttached() || mUpdating) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (IsNaN(aAppendWindowEnd) || aAppendWindowEnd <= mAppendWindowStart) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } mAppendWindowEnd = aAppendWindowEnd; }
void MediaSource::SetDuration(double aDuration, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("MediaSource(%p)::SetDuration(aDuration=%f)", this, aDuration); if (aDuration < 0 || IsNaN(aDuration)) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } if (mReadyState != MediaSourceReadyState::Open || mSourceBuffers->AnyUpdating()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } DurationChange(aDuration, aRv); }
MediaSource::MediaSource(nsPIDOMWindowInner* aWindow) : DOMEventTargetHelper(aWindow) , mDecoder(nullptr) , mPrincipal(nullptr) , mReadyState(MediaSourceReadyState::Closed) { MOZ_ASSERT(NS_IsMainThread()); mSourceBuffers = new SourceBufferList(this); mActiveSourceBuffers = new SourceBufferList(this); nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow); if (sop) { mPrincipal = sop->GetPrincipal(); } MSE_API("MediaSource(aWindow=%p) mSourceBuffers=%p mActiveSourceBuffers=%p", aWindow, mSourceBuffers.get(), mActiveSourceBuffers.get()); }
void SourceBuffer::Abort(ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("Abort()"); if (!IsAttached()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (mMediaSource->ReadyState() != MediaSourceReadyState::Open) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } AbortBufferAppend(); ResetParserState(); mCurrentAttributes.SetAppendWindowStart(0); mCurrentAttributes.SetAppendWindowEnd(PositiveInfinity<double>()); }
MediaSource::MediaSource(nsPIDOMWindow* aWindow) : DOMEventTargetHelper(aWindow) , mDuration(UnspecifiedNaN<double>()) , mDecoder(nullptr) , mPrincipal(nullptr) , mReadyState(MediaSourceReadyState::Closed) , mFirstSourceBufferInitialized(false) { MOZ_ASSERT(NS_IsMainThread()); mSourceBuffers = new SourceBufferList(this); mActiveSourceBuffers = new SourceBufferList(this); nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow); if (sop) { mPrincipal = sop->GetPrincipal(); } MSE_API("MediaSource(%p)::MediaSource(aWindow=%p) mSourceBuffers=%p mActiveSourceBuffers=%p", this, aWindow, mSourceBuffers.get(), mActiveSourceBuffers.get()); }
void SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("SourceBuffer(%p)::Remove(aStart=%f, aEnd=%f)", this, aStart, aEnd); if (IsNaN(mMediaSource->Duration()) || aStart < 0 || aStart > mMediaSource->Duration() || aEnd <= aStart || IsNaN(aEnd)) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } if (!IsAttached() || mUpdating || mMediaSource->ReadyState() != MediaSourceReadyState::Open) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } StartUpdating(); /// TODO: Run coded frame removal algorithm asynchronously (would call StopUpdating()). StopUpdating(); }
void SourceBuffer::Abort(ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("Abort()"); if (!IsAttached()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (mMediaSource->ReadyState() != MediaSourceReadyState::Open) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } AbortBufferAppend(); mTrackBuffer->ResetParserState(); mAppendWindowStart = 0; mAppendWindowEnd = PositiveInfinity<double>(); // Discard the current decoder so no new data will be added to it. MSE_DEBUG("Discarding decoder"); mTrackBuffer->DiscardCurrentDecoder(); }
already_AddRefed<SourceBuffer> MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); DecoderDoctorDiagnostics diagnostics; nsresult rv = IsTypeSupported(aType, &diagnostics); diagnostics.StoreFormatDiagnostics(GetOwner() ? GetOwner()->GetExtantDoc() : nullptr, aType, NS_SUCCEEDED(rv), __func__); MSE_API("AddSourceBuffer(aType=%s)%s", NS_ConvertUTF16toUTF8(aType).get(), rv == NS_OK ? "" : " [not supported]"); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } if (mSourceBuffers->Length() >= MAX_SOURCE_BUFFERS) { aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR); return nullptr; } if (mReadyState != MediaSourceReadyState::Open) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } Maybe<MediaContainerType> containerType = MakeMediaContainerType(aType); if (!containerType) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer(this, *containerType); if (!sourceBuffer) { aRv.Throw(NS_ERROR_FAILURE); // XXX need a better error here return nullptr; } mSourceBuffers->Append(sourceBuffer); DDLINKCHILD("sourcebuffer[]", sourceBuffer.get()); MSE_DEBUG("sourceBuffer=%p", sourceBuffer.get()); return sourceBuffer.forget(); }
void MediaSource::EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("MediaSource(%p)::EndOfStream(aError=%d)", this, aError.WasPassed() ? uint32_t(aError.Value()) : 0); if (mReadyState != MediaSourceReadyState::Open || mSourceBuffers->AnyUpdating()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } SetReadyState(MediaSourceReadyState::Ended); mSourceBuffers->Ended(); mDecoder->Ended(); if (!aError.WasPassed()) { DurationChange(mSourceBuffers->GetHighestBufferedEndTime(), aRv); if (aRv.Failed()) { return; } // TODO: // Notify media element that all data is now available. return; } switch (aError.Value()) { case MediaSourceEndOfStreamError::Network: // TODO: If media element has a readyState of: // HAVE_NOTHING -> run resource fetch algorithm // > HAVE_NOTHING -> run "interrupted" steps of resource fetch break; case MediaSourceEndOfStreamError::Decode: // TODO: If media element has a readyState of: // HAVE_NOTHING -> run "unsupported" steps of resource fetch // > HAVE_NOTHING -> run "corrupted" steps of resource fetch break; default: aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); } }
already_AddRefed<SourceBuffer> MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); nsresult rv = mozilla::IsTypeSupported(aType); MSE_API("MediaSource(%p)::AddSourceBuffer(aType=%s)%s", this, NS_ConvertUTF16toUTF8(aType).get(), rv == NS_OK ? "" : " [not supported]"); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } if (mSourceBuffers->Length() >= MAX_SOURCE_BUFFERS) { aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR); return nullptr; } if (mReadyState != MediaSourceReadyState::Open) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } nsContentTypeParser parser(aType); nsAutoString mimeType; rv = parser.GetType(mimeType); if (NS_FAILED(rv)) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return nullptr; } nsRefPtr<SourceBuffer> sourceBuffer = SourceBuffer::Create(this, NS_ConvertUTF16toUTF8(mimeType)); if (!sourceBuffer) { aRv.Throw(NS_ERROR_FAILURE); // XXX need a better error here return nullptr; } mSourceBuffers->Append(sourceBuffer); mActiveSourceBuffers->Append(sourceBuffer); MSE_DEBUG("MediaSource(%p)::AddSourceBuffer() sourceBuffer=%p", this, sourceBuffer.get()); return sourceBuffer.forget(); }
void SourceBuffer::Abort(ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); MSE_API("SourceBuffer(%p)::Abort()", this); if (!IsAttached()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (mMediaSource->ReadyState() != MediaSourceReadyState::Open) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (mUpdating) { // TODO: Abort segment parser loop, buffer append, and stream append loop algorithms. AbortUpdating(); } // TODO: Run reset parser algorithm. mAppendWindowStart = 0; mAppendWindowEnd = PositiveInfinity<double>(); MSE_DEBUG("SourceBuffer(%p)::Abort() Discarding decoder", this); DiscardDecoder(); }