void MediaSource::setDuration(double duration, ExceptionCode& ec) { // 2.1 Attributes - Duration // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#attributes // On setting, run the following steps: // 1. If the value being set is negative or NaN then throw an INVALID_ACCESS_ERR exception and abort these steps. if (duration < 0.0 || std::isnan(duration)) { ec = INVALID_ACCESS_ERR; return; } // 2. If the readyState attribute is not "open" then throw an INVALID_STATE_ERR exception and abort these steps. if (!isOpen()) { ec = INVALID_STATE_ERR; return; } // 3. If the updating attribute equals true on any SourceBuffer in sourceBuffers, then throw an INVALID_STATE_ERR // exception and abort these steps. for (auto& sourceBuffer : *m_sourceBuffers) { if (sourceBuffer->updating()) { ec = INVALID_STATE_ERR; return; } } // 4. Run the duration change algorithm with new duration set to the value being assigned to this attribute. setDurationInternal(MediaTime::createWithDouble(duration)); }
void MediaSource::streamEndedWithError(Optional<EndOfStreamError> error) { LOG(MediaSource, "MediaSource::streamEndedWithError(%p)", this); // 2.4.7 https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#end-of-stream-algorithm // 1. Change the readyState attribute value to "ended". // 2. Queue a task to fire a simple event named sourceended at the MediaSource. setReadyState(endedKeyword()); // 3. if (!error) { // ↳ If error is not set, is null, or is an empty string // 1. Run the duration change algorithm with new duration set to the highest end time reported by // the buffered attribute across all SourceBuffer objects in sourceBuffers. MediaTime maxEndTime; for (auto& sourceBuffer : *m_sourceBuffers) { if (auto length = sourceBuffer->buffered()->length()) maxEndTime = std::max(sourceBuffer->buffered()->ranges().end(length - 1), maxEndTime); } setDurationInternal(maxEndTime); // 2. Notify the media element that it now has all of the media data. m_private->markEndOfStream(MediaSourcePrivate::EosNoError); } else if (error == EndOfStreamError::Network) { // ↳ If error is set to "network" ASSERT(m_mediaElement); if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) { // ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING // Run the "If the media data cannot be fetched at all, due to network errors, causing // the user agent to give up trying to fetch the resource" steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed(). m_mediaElement->mediaLoadingFailed(MediaPlayer::NetworkError); } else { // ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING // Run the "If the connection is interrupted after some media data has been received, causing the // user agent to give up trying to fetch the resource" steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally(). m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::NetworkError); } } else { // ↳ If error is set to "decode" ASSERT(error == EndOfStreamError::Decode); ASSERT(m_mediaElement); if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) { // ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING // Run the "If the media data can be fetched but is found by inspection to be in an unsupported // format, or can otherwise not be rendered at all" steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed(). m_mediaElement->mediaLoadingFailed(MediaPlayer::FormatError); } else { // ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING // Run the media data is corrupted steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally(). m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::DecodeError); } } }
void MediaSource::streamEndedWithError(const AtomicString& error, ExceptionCode& ec) { DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, network, ("network", AtomicString::ConstructFromLiteral)); DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode", AtomicString::ConstructFromLiteral)); LOG(MediaSource, "MediaSource::streamEndedWithError(%p) : %s", this, error.string().ascii().data()); // 2.4.7 https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#end-of-stream-algorithm // 3. if (error.isEmpty()) { // ↳ If error is not set, is null, or is an empty string // 1. Run the duration change algorithm with new duration set to the highest end time reported by // the buffered attribute across all SourceBuffer objects in sourceBuffers. MediaTime maxEndTime; for (auto& sourceBuffer : *m_sourceBuffers) { if (auto length = sourceBuffer->buffered()->length()) maxEndTime = std::max(sourceBuffer->buffered()->ranges().end(length - 1), maxEndTime); } setDurationInternal(maxEndTime); // 2. Notify the media element that it now has all of the media data. m_private->markEndOfStream(MediaSourcePrivate::EosNoError); } // NOTE: Do steps 1 & 2 after step 3 (with an empty error) to avoid the MediaSource's readyState being re-opened by a // remove() operation resulting from a duration change. // FIXME: Re-number or update this section once <https://www.w3.org/Bugs/Public/show_bug.cgi?id=26316> is resolved. // 1. Change the readyState attribute value to "ended". // 2. Queue a task to fire a simple event named sourceended at the MediaSource. setReadyState(endedKeyword()); if (error == network) { // ↳ If error is set to "network" ASSERT(m_mediaElement); if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) { // ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING // Run the "If the media data cannot be fetched at all, due to network errors, causing // the user agent to give up trying to fetch the resource" steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed(). m_mediaElement->mediaLoadingFailed(MediaPlayer::NetworkError); } else { // ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING // Run the "If the connection is interrupted after some media data has been received, causing the // user agent to give up trying to fetch the resource" steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally(). m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::NetworkError); } } else if (error == decode) { // ↳ If error is set to "decode" ASSERT(m_mediaElement); if (m_mediaElement->readyState() == HTMLMediaElement::HAVE_NOTHING) { // ↳ If the HTMLMediaElement.readyState attribute equals HAVE_NOTHING // Run the "If the media data can be fetched but is found by inspection to be in an unsupported // format, or can otherwise not be rendered at all" steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailed(). m_mediaElement->mediaLoadingFailed(MediaPlayer::FormatError); } else { // ↳ If the HTMLMediaElement.readyState attribute is greater than HAVE_NOTHING // Run the media data is corrupted steps of the resource fetch algorithm. // NOTE: This step is handled by HTMLMediaElement::mediaLoadingFailedFatally(). m_mediaElement->mediaLoadingFailedFatally(MediaPlayer::DecodeError); } } else if (!error.isEmpty()) { // ↳ Otherwise // Throw an INVALID_ACCESS_ERR exception. ec = INVALID_ACCESS_ERR; } }