Home | History | Annotate | Download | only in mediasource
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "modules/mediasource/MediaSource.h"
     33 
     34 #include "bindings/v8/ExceptionState.h"
     35 #include "bindings/v8/ExceptionStatePlaceholder.h"
     36 #include "core/dom/ExceptionCode.h"
     37 #include "core/events/GenericEventQueue.h"
     38 #include "core/html/TimeRanges.h"
     39 #include "modules/mediasource/MediaSourceRegistry.h"
     40 #include "platform/ContentType.h"
     41 #include "platform/Logging.h"
     42 #include "platform/MIMETypeRegistry.h"
     43 #include "public/platform/WebSourceBuffer.h"
     44 #include "wtf/Uint8Array.h"
     45 #include "wtf/text/CString.h"
     46 
     47 using blink::WebSourceBuffer;
     48 
     49 namespace WebCore {
     50 
     51 PassRefPtr<MediaSource> MediaSource::create(ExecutionContext* context)
     52 {
     53     RefPtr<MediaSource> mediaSource(adoptRef(new MediaSource(context)));
     54     mediaSource->suspendIfNeeded();
     55     return mediaSource.release();
     56 }
     57 
     58 MediaSource::MediaSource(ExecutionContext* context)
     59     : MediaSourceBase(context)
     60 {
     61     WTF_LOG(Media, "MediaSource::MediaSource %p", this);
     62     ScriptWrappable::init(this);
     63     m_sourceBuffers = SourceBufferList::create(executionContext(), asyncEventQueue());
     64     m_activeSourceBuffers = SourceBufferList::create(executionContext(), asyncEventQueue());
     65 }
     66 
     67 MediaSource::~MediaSource()
     68 {
     69     WTF_LOG(Media, "MediaSource::~MediaSource %p", this);
     70     ASSERT(isClosed());
     71 }
     72 
     73 SourceBuffer* MediaSource::addSourceBuffer(const String& type, ExceptionState& exceptionState)
     74 {
     75     WTF_LOG(Media, "MediaSource::addSourceBuffer(%s) %p", type.ascii().data(), this);
     76 
     77     // 2.2 https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-MediaSource-addSourceBuffer-SourceBuffer-DOMString-type
     78     // 1. If type is null or an empty then throw an InvalidAccessError exception and
     79     // abort these steps.
     80     if (type.isNull() || type.isEmpty()) {
     81         exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError);
     82         return 0;
     83     }
     84 
     85     // 2. If type contains a MIME type that is not supported ..., then throw a
     86     // NotSupportedError exception and abort these steps.
     87     if (!isTypeSupported(type)) {
     88         exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
     89         return 0;
     90     }
     91 
     92     // 4. If the readyState attribute is not in the "open" state then throw an
     93     // InvalidStateError exception and abort these steps.
     94     if (!isOpen()) {
     95         exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
     96         return 0;
     97     }
     98 
     99     // 5. Create a new SourceBuffer object and associated resources.
    100     ContentType contentType(type);
    101     Vector<String> codecs = contentType.codecs();
    102     OwnPtr<WebSourceBuffer> webSourceBuffer = createWebSourceBuffer(contentType.type(), codecs, exceptionState);
    103 
    104     if (!webSourceBuffer) {
    105         ASSERT(exceptionState.code() == NotSupportedError || exceptionState.code() == QuotaExceededError);
    106         // 2. If type contains a MIME type that is not supported ..., then throw a NotSupportedError exception and abort these steps.
    107         // 3. If the user agent can't handle any more SourceBuffer objects then throw a QuotaExceededError exception and abort these steps
    108         return 0;
    109     }
    110 
    111     RefPtr<SourceBuffer> buffer = SourceBuffer::create(webSourceBuffer.release(), this, asyncEventQueue());
    112     // 6. Add the new object to sourceBuffers and fire a addsourcebuffer on that object.
    113     m_sourceBuffers->add(buffer);
    114     m_activeSourceBuffers->add(buffer);
    115     // 7. Return the new object to the caller.
    116     return buffer.get();
    117 }
    118 
    119 void MediaSource::removeSourceBuffer(SourceBuffer* buffer, ExceptionState& exceptionState)
    120 {
    121     WTF_LOG(Media, "MediaSource::removeSourceBuffer() %p", this);
    122     RefPtr<SourceBuffer> protect(buffer);
    123 
    124     // 2.2 https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-MediaSource-removeSourceBuffer-void-SourceBuffer-sourceBuffer
    125     // 1. If sourceBuffer is null then throw an InvalidAccessError exception and
    126     // abort these steps.
    127     if (!buffer) {
    128         exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError);
    129         return;
    130     }
    131 
    132     // 2. If sourceBuffer specifies an object that is not in sourceBuffers then
    133     // throw a NotFoundError exception and abort these steps.
    134     if (!m_sourceBuffers->length() || !m_sourceBuffers->contains(buffer)) {
    135         exceptionState.throwUninformativeAndGenericDOMException(NotFoundError);
    136         return;
    137     }
    138 
    139     // 3. If the sourceBuffer.updating attribute equals true, then run the following steps: ...
    140     buffer->abortIfUpdating();
    141 
    142     // Steps 4-9 are related to updating audioTracks, videoTracks, and textTracks which aren't implmented yet.
    143     // FIXME(91649): support track selection
    144 
    145     // 10. If sourceBuffer is in activeSourceBuffers, then remove sourceBuffer from activeSourceBuffers ...
    146     m_activeSourceBuffers->remove(buffer);
    147 
    148     // 11. Remove sourceBuffer from sourceBuffers and fire a removesourcebuffer event
    149     // on that object.
    150     m_sourceBuffers->remove(buffer);
    151 
    152     // 12. Destroy all resources for sourceBuffer.
    153     buffer->removedFromMediaSource();
    154 }
    155 
    156 void MediaSource::onReadyStateChange(const AtomicString& oldState, const AtomicString& newState)
    157 {
    158     if (isOpen()) {
    159         scheduleEvent(EventTypeNames::sourceopen);
    160         return;
    161     }
    162 
    163     if (oldState == openKeyword() && newState == endedKeyword()) {
    164         scheduleEvent(EventTypeNames::sourceended);
    165         return;
    166     }
    167 
    168     ASSERT(isClosed());
    169 
    170     m_activeSourceBuffers->clear();
    171 
    172     // Clear SourceBuffer references to this object.
    173     for (unsigned long i = 0; i < m_sourceBuffers->length(); ++i)
    174         m_sourceBuffers->item(i)->removedFromMediaSource();
    175     m_sourceBuffers->clear();
    176 
    177     scheduleEvent(EventTypeNames::sourceclose);
    178 }
    179 
    180 Vector<RefPtr<TimeRanges> > MediaSource::activeRanges() const
    181 {
    182     Vector<RefPtr<TimeRanges> > activeRanges(m_activeSourceBuffers->length());
    183     for (size_t i = 0; i < m_activeSourceBuffers->length(); ++i)
    184         activeRanges[i] = m_activeSourceBuffers->item(i)->buffered(ASSERT_NO_EXCEPTION);
    185 
    186     return activeRanges;
    187 }
    188 
    189 bool MediaSource::isTypeSupported(const String& type)
    190 {
    191     WTF_LOG(Media, "MediaSource::isTypeSupported(%s)", type.ascii().data());
    192 
    193     // Section 2.2 isTypeSupported() method steps.
    194     // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#widl-MediaSource-isTypeSupported-boolean-DOMString-type
    195     // 1. If type is an empty string, then return false.
    196     if (type.isNull() || type.isEmpty())
    197         return false;
    198 
    199     ContentType contentType(type);
    200     String codecs = contentType.parameter("codecs");
    201 
    202     // 2. If type does not contain a valid MIME type string, then return false.
    203     if (contentType.type().isEmpty())
    204         return false;
    205 
    206     // 3. If type contains a media type or media subtype that the MediaSource does not support, then return false.
    207     // 4. If type contains at a codec that the MediaSource does not support, then return false.
    208     // 5. If the MediaSource does not support the specified combination of media type, media subtype, and codecs then return false.
    209     // 6. Return true.
    210     return MIMETypeRegistry::isSupportedMediaSourceMIMEType(contentType.type(), codecs);
    211 }
    212 
    213 const AtomicString& MediaSource::interfaceName() const
    214 {
    215     return EventTargetNames::MediaSource;
    216 }
    217 
    218 } // namespace WebCore
    219