This source file includes following definitions.
- throwExceptionIfClosedOrUpdating
- m_attachedElement
- openKeyword
- closedKeyword
- endedKeyword
- setWebMediaSourceAndOpen
- addedToRegistry
- removedFromRegistry
- duration
- buffered
- setDuration
- setReadyState
- endOfStream
- endOfStream
- endOfStreamInternal
- isOpen
- isClosed
- close
- attachToElement
- openIfInEndedState
- hasPendingActivity
- stop
- createWebSourceBuffer
- scheduleEvent
- executionContext
- registry
#include "config.h"
#include "modules/mediasource/MediaSourceBase.h"
#include "RuntimeEnabledFeatures.h"
#include "bindings/v8/ExceptionMessages.h"
#include "bindings/v8/ExceptionState.h"
#include "bindings/v8/ExceptionStatePlaceholder.h"
#include "core/dom/ExceptionCode.h"
#include "core/events/Event.h"
#include "core/events/GenericEventQueue.h"
#include "core/html/HTMLMediaElement.h"
#include "core/html/TimeRanges.h"
#include "modules/mediasource/MediaSourceRegistry.h"
#include "platform/Logging.h"
#include "platform/TraceEvent.h"
#include "public/platform/WebMediaSource.h"
#include "public/platform/WebSourceBuffer.h"
#include "wtf/text/WTFString.h"
using blink::WebMediaSource;
using blink::WebSourceBuffer;
namespace WebCore {
namespace {
static bool throwExceptionIfClosedOrUpdating(bool isOpen, bool isUpdating, ExceptionState& exceptionState)
{
if (!isOpen) {
exceptionState.throwDOMException(InvalidStateError, "The MediaSource's readyState is not 'open'.");
return true;
}
if (isUpdating) {
exceptionState.throwDOMException(InvalidStateError, "The 'updating' attribute is true on one or more of this MediaSource's SourceBuffers.");
return true;
}
return false;
}
}
MediaSourceBase::MediaSourceBase(ExecutionContext* context)
: ActiveDOMObject(context)
, m_readyState(closedKeyword())
, m_asyncEventQueue(GenericEventQueue::create(this))
, m_attachedElement(0)
{
}
MediaSourceBase::~MediaSourceBase()
{
}
const AtomicString& MediaSourceBase::openKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, open, ("open", AtomicString::ConstructFromLiteral));
return open;
}
const AtomicString& MediaSourceBase::closedKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, closed, ("closed", AtomicString::ConstructFromLiteral));
return closed;
}
const AtomicString& MediaSourceBase::endedKeyword()
{
DEFINE_STATIC_LOCAL(const AtomicString, ended, ("ended", AtomicString::ConstructFromLiteral));
return ended;
}
void MediaSourceBase::setWebMediaSourceAndOpen(PassOwnPtr<WebMediaSource> webMediaSource)
{
TRACE_EVENT_ASYNC_END0("media", "MediaSourceBase::attachToElement", this);
ASSERT(webMediaSource);
ASSERT(!m_webMediaSource);
ASSERT(m_attachedElement);
m_webMediaSource = webMediaSource;
setReadyState(openKeyword());
}
void MediaSourceBase::addedToRegistry()
{
setPendingActivity(this);
}
void MediaSourceBase::removedFromRegistry()
{
unsetPendingActivity(this);
}
double MediaSourceBase::duration() const
{
return isClosed() ? std::numeric_limits<float>::quiet_NaN() : m_webMediaSource->duration();
}
PassRefPtr<TimeRanges> MediaSourceBase::buffered() const
{
Vector<RefPtr<TimeRanges> > ranges = activeRanges();
if (ranges.isEmpty())
return TimeRanges::create();
double highestEndTime = -1;
for (size_t i = 0; i < ranges.size(); ++i) {
unsigned length = ranges[i]->length();
if (length)
highestEndTime = std::max(highestEndTime, ranges[i]->end(length - 1, ASSERT_NO_EXCEPTION));
}
if (highestEndTime < 0)
return TimeRanges::create();
RefPtr<TimeRanges> intersectionRanges = TimeRanges::create(0, highestEndTime);
bool ended = readyState() == endedKeyword();
for (size_t i = 0; i < ranges.size(); ++i) {
TimeRanges* sourceRanges = ranges[i].get();
if (ended && sourceRanges->length())
sourceRanges->add(sourceRanges->start(sourceRanges->length() - 1, ASSERT_NO_EXCEPTION), highestEndTime);
intersectionRanges->intersectWith(sourceRanges);
}
return intersectionRanges.release();
}
void MediaSourceBase::setDuration(double duration, ExceptionState& exceptionState)
{
if (std::isnan(duration)) {
exceptionState.throwDOMException(InvalidAccessError, ExceptionMessages::notAFiniteNumber(duration, "duration"));
return;
}
if (duration < 0.0) {
exceptionState.throwDOMException(InvalidAccessError, ExceptionMessages::indexExceedsMinimumBound("duration", duration, 0.0));
return;
}
if (throwExceptionIfClosedOrUpdating(isOpen(), isUpdating(), exceptionState))
return;
m_attachedElement->durationChanged(duration);
m_webMediaSource->setDuration(duration);
}
void MediaSourceBase::setReadyState(const AtomicString& state)
{
ASSERT(state == openKeyword() || state == closedKeyword() || state == endedKeyword());
AtomicString oldState = readyState();
WTF_LOG(Media, "MediaSourceBase::setReadyState() %p : %s -> %s", this, oldState.ascii().data(), state.ascii().data());
if (state == closedKeyword()) {
m_webMediaSource.clear();
m_attachedElement = 0;
}
if (oldState == state)
return;
m_readyState = state;
onReadyStateChange(oldState, state);
}
void MediaSourceBase::endOfStream(const AtomicString& error, ExceptionState& exceptionState)
{
DEFINE_STATIC_LOCAL(const AtomicString, network, ("network", AtomicString::ConstructFromLiteral));
DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode", AtomicString::ConstructFromLiteral));
if (error == network) {
endOfStreamInternal(blink::WebMediaSource::EndOfStreamStatusNetworkError, exceptionState);
} else if (error == decode) {
endOfStreamInternal(blink::WebMediaSource::EndOfStreamStatusDecodeError, exceptionState);
} else {
ASSERT_NOT_REACHED();
exceptionState.throwTypeError("parameter 1 is not a valid enum value.");
}
}
void MediaSourceBase::endOfStream(ExceptionState& exceptionState)
{
endOfStreamInternal(blink::WebMediaSource::EndOfStreamStatusNoError, exceptionState);
}
void MediaSourceBase::endOfStreamInternal(const blink::WebMediaSource::EndOfStreamStatus eosStatus, ExceptionState& exceptionState)
{
if (throwExceptionIfClosedOrUpdating(isOpen(), isUpdating(), exceptionState))
return;
setReadyState(endedKeyword());
m_webMediaSource->markEndOfStream(eosStatus);
}
bool MediaSourceBase::isOpen() const
{
return readyState() == openKeyword();
}
bool MediaSourceBase::isClosed() const
{
return readyState() == closedKeyword();
}
void MediaSourceBase::close()
{
setReadyState(closedKeyword());
}
bool MediaSourceBase::attachToElement(HTMLMediaElement* element)
{
if (m_attachedElement)
return false;
ASSERT(isClosed());
TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourceBase::attachToElement", this);
m_attachedElement = element;
return true;
}
void MediaSourceBase::openIfInEndedState()
{
if (m_readyState != endedKeyword())
return;
setReadyState(openKeyword());
m_webMediaSource->unmarkEndOfStream();
}
bool MediaSourceBase::hasPendingActivity() const
{
return m_attachedElement || m_webMediaSource
|| m_asyncEventQueue->hasPendingEvents()
|| ActiveDOMObject::hasPendingActivity();
}
void MediaSourceBase::stop()
{
m_asyncEventQueue->close();
if (!isClosed())
setReadyState(closedKeyword());
m_webMediaSource.clear();
}
PassOwnPtr<WebSourceBuffer> MediaSourceBase::createWebSourceBuffer(const String& type, const Vector<String>& codecs, ExceptionState& exceptionState)
{
WebSourceBuffer* webSourceBuffer = 0;
WebMediaSource::FrameProcessorChoice frameProcessorChoice = RuntimeEnabledFeatures::mediaSourceExperimentalEnabled() ?
WebMediaSource::UseNewFrameProcessor : WebMediaSource::UseLegacyFrameProcessor;
WTF_LOG(Media, "MediaSourceBase::createWebSourceBuffer() %p : frameProcessorChoice = %i", this, frameProcessorChoice);
switch (m_webMediaSource->addSourceBuffer(type, codecs, frameProcessorChoice, &webSourceBuffer)) {
case WebMediaSource::AddStatusOk:
return adoptPtr(webSourceBuffer);
case WebMediaSource::AddStatusNotSupported:
ASSERT(!webSourceBuffer);
exceptionState.throwDOMException(NotSupportedError, "The type provided ('" + type + "') is not supported.");
return nullptr;
case WebMediaSource::AddStatusReachedIdLimit:
ASSERT(!webSourceBuffer);
exceptionState.throwDOMException(QuotaExceededError, "This MediaSource has reached the limit of SourceBuffer objects it can handle. No additional SourceBuffer objects may be added.");
return nullptr;
}
ASSERT_NOT_REACHED();
return nullptr;
}
void MediaSourceBase::scheduleEvent(const AtomicString& eventName)
{
ASSERT(m_asyncEventQueue);
RefPtrWillBeRawPtr<Event> event = Event::create(eventName);
event->setTarget(this);
m_asyncEventQueue->enqueueEvent(event.release());
}
ExecutionContext* MediaSourceBase::executionContext() const
{
return ActiveDOMObject::executionContext();
}
URLRegistry& MediaSourceBase::registry() const
{
return MediaSourceRegistry::registry();
}
}