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/SourceBuffer.h" 33 34#include "bindings/v8/ExceptionState.h" 35#include "core/dom/ExceptionCode.h" 36#include "core/dom/ExecutionContext.h" 37#include "core/events/Event.h" 38#include "core/events/GenericEventQueue.h" 39#include "core/fileapi/FileReaderLoader.h" 40#include "core/fileapi/Stream.h" 41#include "core/html/TimeRanges.h" 42#include "modules/mediasource/MediaSource.h" 43#include "platform/Logging.h" 44#include "platform/TraceEvent.h" 45#include "public/platform/WebSourceBuffer.h" 46#include "wtf/ArrayBuffer.h" 47#include "wtf/ArrayBufferView.h" 48#include "wtf/MathExtras.h" 49 50#include <limits> 51 52using blink::WebSourceBuffer; 53 54namespace WebCore { 55 56PassRefPtr<SourceBuffer> SourceBuffer::create(PassOwnPtr<WebSourceBuffer> webSourceBuffer, MediaSource* source, GenericEventQueue* asyncEventQueue) 57{ 58 RefPtr<SourceBuffer> sourceBuffer(adoptRef(new SourceBuffer(webSourceBuffer, source, asyncEventQueue))); 59 sourceBuffer->suspendIfNeeded(); 60 return sourceBuffer.release(); 61} 62 63SourceBuffer::SourceBuffer(PassOwnPtr<WebSourceBuffer> webSourceBuffer, MediaSource* source, GenericEventQueue* asyncEventQueue) 64 : ActiveDOMObject(source->executionContext()) 65 , m_webSourceBuffer(webSourceBuffer) 66 , m_source(source) 67 , m_asyncEventQueue(asyncEventQueue) 68 , m_updating(false) 69 , m_timestampOffset(0) 70 , m_appendWindowStart(0) 71 , m_appendWindowEnd(std::numeric_limits<double>::infinity()) 72 , m_appendBufferAsyncPartRunner(this, &SourceBuffer::appendBufferAsyncPart) 73 , m_pendingRemoveStart(-1) 74 , m_pendingRemoveEnd(-1) 75 , m_removeAsyncPartRunner(this, &SourceBuffer::removeAsyncPart) 76 , m_streamMaxSizeValid(false) 77 , m_streamMaxSize(0) 78 , m_appendStreamAsyncPartRunner(this, &SourceBuffer::appendStreamAsyncPart) 79{ 80 ASSERT(m_webSourceBuffer); 81 ASSERT(m_source); 82 ScriptWrappable::init(this); 83} 84 85SourceBuffer::~SourceBuffer() 86{ 87 ASSERT(isRemoved()); 88 ASSERT(!m_loader); 89 ASSERT(!m_stream); 90} 91 92PassRefPtr<TimeRanges> SourceBuffer::buffered(ExceptionState& exceptionState) const 93{ 94 // Section 3.1 buffered attribute steps. 95 // 1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an 96 // InvalidStateError exception and abort these steps. 97 if (isRemoved()) { 98 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 99 return 0; 100 } 101 102 // 2. Return a new static normalized TimeRanges object for the media segments buffered. 103 return TimeRanges::create(m_webSourceBuffer->buffered()); 104} 105 106double SourceBuffer::timestampOffset() const 107{ 108 return m_timestampOffset; 109} 110 111void SourceBuffer::setTimestampOffset(double offset, ExceptionState& exceptionState) 112{ 113 // Section 3.1 timestampOffset attribute setter steps. 114 // 1. Let new timestamp offset equal the new value being assigned to this attribute. 115 // 2. If this object has been removed from the sourceBuffers attribute of the parent media source, then throw an 116 // InvalidStateError exception and abort these steps. 117 // 3. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps. 118 if (isRemoved() || m_updating) { 119 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 120 return; 121 } 122 123 // 4. If the readyState attribute of the parent media source is in the "ended" state then run the following steps: 124 // 4.1 Set the readyState attribute of the parent media source to "open" 125 // 4.2 Queue a task to fire a simple event named sourceopen at the parent media source. 126 m_source->openIfInEndedState(); 127 128 // 5. If this object is waiting for the end of a media segment to be appended, then throw an InvalidStateError 129 // and abort these steps. 130 // 131 // FIXME: Add step 6 text when mode attribute is implemented. 132 if (!m_webSourceBuffer->setTimestampOffset(offset)) { 133 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 134 return; 135 } 136 137 // 7. Update the attribute to new timestamp offset. 138 m_timestampOffset = offset; 139} 140 141double SourceBuffer::appendWindowStart() const 142{ 143 return m_appendWindowStart; 144} 145 146void SourceBuffer::setAppendWindowStart(double start, ExceptionState& exceptionState) 147{ 148 // Enforce throwing an exception on restricted double values. 149 if (std::isnan(start) 150 || start == std::numeric_limits<double>::infinity() 151 || start == -std::numeric_limits<double>::infinity()) { 152 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError); 153 return; 154 } 155 156 // Section 3.1 appendWindowStart attribute setter steps. 157 // 1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an 158 // InvalidStateError exception and abort these steps. 159 // 2. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps. 160 if (isRemoved() || m_updating) { 161 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 162 return; 163 } 164 165 // 3. If the new value is less than 0 or greater than or equal to appendWindowEnd then throw an InvalidAccessError 166 // exception and abort these steps. 167 if (start < 0 || start >= m_appendWindowEnd) { 168 exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError); 169 return; 170 } 171 172 m_webSourceBuffer->setAppendWindowStart(start); 173 174 // 4. Update the attribute to the new value. 175 m_appendWindowStart = start; 176} 177 178double SourceBuffer::appendWindowEnd() const 179{ 180 return m_appendWindowEnd; 181} 182 183void SourceBuffer::setAppendWindowEnd(double end, ExceptionState& exceptionState) 184{ 185 // Section 3.1 appendWindowEnd attribute setter steps. 186 // 1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an 187 // InvalidStateError exception and abort these steps. 188 // 2. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps. 189 if (isRemoved() || m_updating) { 190 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 191 return; 192 } 193 194 // 3. If the new value equals NaN, then throw an InvalidAccessError and abort these steps. 195 // 4. If the new value is less than or equal to appendWindowStart then throw an InvalidAccessError 196 // exception and abort these steps. 197 if (std::isnan(end) || end <= m_appendWindowStart) { 198 exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError); 199 return; 200 } 201 202 m_webSourceBuffer->setAppendWindowEnd(end); 203 204 // 5. Update the attribute to the new value. 205 m_appendWindowEnd = end; 206} 207 208void SourceBuffer::appendBuffer(PassRefPtr<ArrayBuffer> data, ExceptionState& exceptionState) 209{ 210 // Section 3.2 appendBuffer() 211 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data 212 // 1. If data is null then throw an InvalidAccessError exception and abort these steps. 213 if (!data) { 214 exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError); 215 return; 216 } 217 218 appendBufferInternal(static_cast<const unsigned char*>(data->data()), data->byteLength(), exceptionState); 219} 220 221void SourceBuffer::appendBuffer(PassRefPtr<ArrayBufferView> data, ExceptionState& exceptionState) 222{ 223 // Section 3.2 appendBuffer() 224 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data 225 // 1. If data is null then throw an InvalidAccessError exception and abort these steps. 226 if (!data) { 227 exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError); 228 return; 229 } 230 231 appendBufferInternal(static_cast<const unsigned char*>(data->baseAddress()), data->byteLength(), exceptionState); 232} 233 234void SourceBuffer::appendStream(PassRefPtr<Stream> stream, ExceptionState& exceptionState) 235{ 236 m_streamMaxSizeValid = false; 237 appendStreamInternal(stream, exceptionState); 238} 239 240void SourceBuffer::appendStream(PassRefPtr<Stream> stream, unsigned long long maxSize, ExceptionState& exceptionState) 241{ 242 m_streamMaxSizeValid = maxSize > 0; 243 if (m_streamMaxSizeValid) 244 m_streamMaxSize = maxSize; 245 appendStreamInternal(stream, exceptionState); 246} 247 248void SourceBuffer::abort(ExceptionState& exceptionState) 249{ 250 // Section 3.2 abort() method steps. 251 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-abort-void 252 // 1. If this object has been removed from the sourceBuffers attribute of the parent media source 253 // then throw an InvalidStateError exception and abort these steps. 254 // 2. If the readyState attribute of the parent media source is not in the "open" state 255 // then throw an InvalidStateError exception and abort these steps. 256 if (isRemoved() || !m_source->isOpen()) { 257 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 258 return; 259 } 260 261 // 3. If the sourceBuffer.updating attribute equals true, then run the following steps: ... 262 abortIfUpdating(); 263 264 // 4. Run the reset parser state algorithm. 265 m_webSourceBuffer->abort(); 266 267 // 5. Set appendWindowStart to 0. 268 setAppendWindowStart(0, exceptionState); 269 270 // 6. Set appendWindowEnd to positive Infinity. 271 setAppendWindowEnd(std::numeric_limits<double>::infinity(), exceptionState); 272} 273 274void SourceBuffer::remove(double start, double end, ExceptionState& exceptionState) 275{ 276 // Section 3.2 remove() method steps. 277 // 1. If start is negative or greater than duration, then throw an InvalidAccessError exception and abort these steps. 278 // 2. If end is less than or equal to start, then throw an InvalidAccessError exception and abort these steps. 279 if (start < 0 || (m_source && (std::isnan(m_source->duration()) || start > m_source->duration())) || end <= start) { 280 exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError); 281 return; 282 } 283 284 // 3. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an 285 // InvalidStateError exception and abort these steps. 286 // 4. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps. 287 if (isRemoved() || m_updating) { 288 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 289 return; 290 } 291 292 TRACE_EVENT_ASYNC_BEGIN0("media", "SourceBuffer::remove", this); 293 294 // 5. If the readyState attribute of the parent media source is in the "ended" state then run the following steps: 295 // 5.1. Set the readyState attribute of the parent media source to "open" 296 // 5.2. Queue a task to fire a simple event named sourceopen at the parent media source . 297 m_source->openIfInEndedState(); 298 299 // 6. Set the updating attribute to true. 300 m_updating = true; 301 302 // 7. Queue a task to fire a simple event named updatestart at this SourceBuffer object. 303 scheduleEvent(EventTypeNames::updatestart); 304 305 // 8. Return control to the caller and run the rest of the steps asynchronously. 306 m_pendingRemoveStart = start; 307 m_pendingRemoveEnd = end; 308 m_removeAsyncPartRunner.runAsync(); 309} 310 311void SourceBuffer::abortIfUpdating() 312{ 313 // Section 3.2 abort() method step 3 substeps. 314 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-abort-void 315 316 if (!m_updating) 317 return; 318 319 const char* traceEventName = 0; 320 if (!m_pendingAppendData.isEmpty()) { 321 traceEventName = "SourceBuffer::appendBuffer"; 322 } else if (m_stream) { 323 traceEventName = "SourceBuffer::appendStream"; 324 } else if (m_pendingRemoveStart != -1) { 325 traceEventName = "SourceBuffer::remove"; 326 } else { 327 ASSERT_NOT_REACHED(); 328 } 329 330 // 3.1. Abort the buffer append and stream append loop algorithms if they are running. 331 m_appendBufferAsyncPartRunner.stop(); 332 m_pendingAppendData.clear(); 333 334 m_removeAsyncPartRunner.stop(); 335 m_pendingRemoveStart = -1; 336 m_pendingRemoveEnd = -1; 337 338 m_appendStreamAsyncPartRunner.stop(); 339 clearAppendStreamState(); 340 341 // 3.2. Set the updating attribute to false. 342 m_updating = false; 343 344 // 3.3. Queue a task to fire a simple event named abort at this SourceBuffer object. 345 scheduleEvent(EventTypeNames::abort); 346 347 // 3.4. Queue a task to fire a simple event named updateend at this SourceBuffer object. 348 scheduleEvent(EventTypeNames::updateend); 349 350 TRACE_EVENT_ASYNC_END0("media", traceEventName, this); 351} 352 353void SourceBuffer::removedFromMediaSource() 354{ 355 if (isRemoved()) 356 return; 357 358 abortIfUpdating(); 359 360 m_webSourceBuffer->removedFromMediaSource(); 361 m_webSourceBuffer.clear(); 362 m_source = 0; 363 m_asyncEventQueue = 0; 364} 365 366bool SourceBuffer::hasPendingActivity() const 367{ 368 return m_source; 369} 370 371void SourceBuffer::suspend() 372{ 373 m_appendBufferAsyncPartRunner.suspend(); 374 m_removeAsyncPartRunner.suspend(); 375 m_appendStreamAsyncPartRunner.suspend(); 376} 377 378void SourceBuffer::resume() 379{ 380 m_appendBufferAsyncPartRunner.resume(); 381 m_removeAsyncPartRunner.resume(); 382 m_appendStreamAsyncPartRunner.resume(); 383} 384 385void SourceBuffer::stop() 386{ 387 m_appendBufferAsyncPartRunner.stop(); 388 m_removeAsyncPartRunner.stop(); 389 m_appendStreamAsyncPartRunner.stop(); 390} 391 392ExecutionContext* SourceBuffer::executionContext() const 393{ 394 return ActiveDOMObject::executionContext(); 395} 396 397const AtomicString& SourceBuffer::interfaceName() const 398{ 399 return EventTargetNames::SourceBuffer; 400} 401 402bool SourceBuffer::isRemoved() const 403{ 404 return !m_source; 405} 406 407void SourceBuffer::scheduleEvent(const AtomicString& eventName) 408{ 409 ASSERT(m_asyncEventQueue); 410 411 RefPtr<Event> event = Event::create(eventName); 412 event->setTarget(this); 413 414 m_asyncEventQueue->enqueueEvent(event.release()); 415} 416 417void SourceBuffer::appendBufferInternal(const unsigned char* data, unsigned size, ExceptionState& exceptionState) 418{ 419 // Section 3.2 appendBuffer() 420 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data 421 422 // Step 1 is enforced by the caller. 423 // 2. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an InvalidStateError exception and abort these steps. 424 // 3. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps. 425 if (isRemoved() || m_updating) { 426 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 427 return; 428 } 429 430 TRACE_EVENT_ASYNC_BEGIN0("media", "SourceBuffer::appendBuffer", this); 431 432 // 4. If the readyState attribute of the parent media source is in the "ended" state then run the following steps: ... 433 m_source->openIfInEndedState(); 434 435 // Steps 5-6 436 437 // 7. Add data to the end of the input buffer. 438 m_pendingAppendData.append(data, size); 439 440 // 8. Set the updating attribute to true. 441 m_updating = true; 442 443 // 9. Queue a task to fire a simple event named updatestart at this SourceBuffer object. 444 scheduleEvent(EventTypeNames::updatestart); 445 446 // 10. Asynchronously run the buffer append algorithm. 447 m_appendBufferAsyncPartRunner.runAsync(); 448 449 TRACE_EVENT_ASYNC_STEP_INTO0("media", "SourceBuffer::appendBuffer", this, "waiting"); 450} 451 452void SourceBuffer::appendBufferAsyncPart() 453{ 454 ASSERT(m_updating); 455 456 TRACE_EVENT_ASYNC_STEP_INTO0("media", "SourceBuffer::appendBuffer", this, "appending"); 457 458 // Section 3.5.4 Buffer Append Algorithm 459 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-buffer-append 460 461 // 1. Run the segment parser loop algorithm. 462 // Step 2 doesn't apply since we run Step 1 synchronously here. 463 size_t appendSize = m_pendingAppendData.size(); 464 if (!appendSize) { 465 // Resize buffer for 0 byte appends so we always have a valid pointer. 466 // We need to convey all appends, even 0 byte ones to |m_webSourceBuffer| 467 // so that it can clear its end of stream state if necessary. 468 m_pendingAppendData.resize(1); 469 } 470 m_webSourceBuffer->append(m_pendingAppendData.data(), appendSize); 471 472 // 3. Set the updating attribute to false. 473 m_updating = false; 474 m_pendingAppendData.clear(); 475 476 // 4. Queue a task to fire a simple event named update at this SourceBuffer object. 477 scheduleEvent(EventTypeNames::update); 478 479 // 5. Queue a task to fire a simple event named updateend at this SourceBuffer object. 480 scheduleEvent(EventTypeNames::updateend); 481 TRACE_EVENT_ASYNC_END0("media", "SourceBuffer::appendBuffer", this); 482} 483 484void SourceBuffer::removeAsyncPart() 485{ 486 ASSERT(m_updating); 487 ASSERT(m_pendingRemoveStart >= 0); 488 ASSERT(m_pendingRemoveStart < m_pendingRemoveEnd); 489 490 // Section 3.2 remove() method steps 491 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-remove-void-double-start-double-end 492 493 // 9. Run the coded frame removal algorithm with start and end as the start and end of the removal range. 494 m_webSourceBuffer->remove(m_pendingRemoveStart, m_pendingRemoveEnd); 495 496 // 10. Set the updating attribute to false. 497 m_updating = false; 498 m_pendingRemoveStart = -1; 499 m_pendingRemoveEnd = -1; 500 501 // 11. Queue a task to fire a simple event named update at this SourceBuffer object. 502 scheduleEvent(EventTypeNames::update); 503 504 // 12. Queue a task to fire a simple event named updateend at this SourceBuffer object. 505 scheduleEvent(EventTypeNames::updateend); 506} 507 508void SourceBuffer::appendStreamInternal(PassRefPtr<Stream> stream, ExceptionState& exceptionState) 509{ 510 // Section 3.2 appendStream() 511 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendStream-void-Stream-stream-unsigned-long-long-maxSize 512 // 1. If stream is null then throw an InvalidAccessError exception and abort these steps. 513 if (!stream || stream->isNeutered()) { 514 exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError); 515 return; 516 } 517 518 // 2. Run the prepare append algorithm. 519 // Section 3.5.4 Prepare Append Algorithm. 520 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-prepare-append 521 // 1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an InvalidStateError exception and abort these steps. 522 // 2. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps. 523 if (isRemoved() || m_updating) { 524 exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError); 525 return; 526 } 527 528 TRACE_EVENT_ASYNC_BEGIN0("media", "SourceBuffer::appendStream", this); 529 530 // 3. If the readyState attribute of the parent media source is in the "ended" state then run the following steps: ... 531 m_source->openIfInEndedState(); 532 533 // Steps 4-5 of the prepare append algorithm are handled by m_webSourceBuffer. 534 535 // 3. Set the updating attribute to true. 536 m_updating = true; 537 538 // 4. Queue a task to fire a simple event named updatestart at this SourceBuffer object. 539 scheduleEvent(EventTypeNames::updatestart); 540 541 // 5. Asynchronously run the stream append loop algorithm with stream and maxSize. 542 543 stream->neuter(); 544 m_loader = adoptPtr(new FileReaderLoader(FileReaderLoader::ReadByClient, this)); 545 m_stream = stream; 546 m_appendStreamAsyncPartRunner.runAsync(); 547} 548 549void SourceBuffer::appendStreamAsyncPart() 550{ 551 ASSERT(m_updating); 552 ASSERT(m_loader); 553 ASSERT(m_stream); 554 555 // Section 3.5.6 Stream Append Loop 556 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-stream-append-loop 557 558 // 1. If maxSize is set, then let bytesLeft equal maxSize. 559 // 2. Loop Top: If maxSize is set and bytesLeft equals 0, then jump to the loop done step below. 560 if (m_streamMaxSizeValid && !m_streamMaxSize) { 561 appendStreamDone(true); 562 return; 563 } 564 565 // Steps 3-11 are handled by m_loader. 566 // Note: Passing 0 here signals that maxSize was not set. (i.e. Read all the data in the stream). 567 m_loader->start(executionContext(), *m_stream, m_streamMaxSizeValid ? m_streamMaxSize : 0); 568} 569 570void SourceBuffer::appendStreamDone(bool success) 571{ 572 ASSERT(m_updating); 573 ASSERT(m_loader); 574 ASSERT(m_stream); 575 576 clearAppendStreamState(); 577 578 if (!success) { 579 // Section 3.5.3 Append Error Algorithm 580 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-append-error 581 // 582 // 1. Run the reset parser state algorithm. (Handled by caller) 583 // 2. Set the updating attribute to false. 584 m_updating = false; 585 586 // 3. Queue a task to fire a simple event named error at this SourceBuffer object. 587 scheduleEvent(EventTypeNames::error); 588 589 // 4. Queue a task to fire a simple event named updateend at this SourceBuffer object. 590 scheduleEvent(EventTypeNames::updateend); 591 TRACE_EVENT_ASYNC_END0("media", "SourceBuffer::appendStream", this); 592 return; 593 } 594 595 // Section 3.5.6 Stream Append Loop 596 // Steps 1-11 are handled by appendStreamAsyncPart(), |m_loader|, and |m_webSourceBuffer|. 597 // 12. Loop Done: Set the updating attribute to false. 598 m_updating = false; 599 600 // 13. Queue a task to fire a simple event named update at this SourceBuffer object. 601 scheduleEvent(EventTypeNames::update); 602 603 // 14. Queue a task to fire a simple event named updateend at this SourceBuffer object. 604 scheduleEvent(EventTypeNames::updateend); 605 TRACE_EVENT_ASYNC_END0("media", "SourceBuffer::appendStream", this); 606} 607 608void SourceBuffer::clearAppendStreamState() 609{ 610 m_streamMaxSizeValid = false; 611 m_streamMaxSize = 0; 612 m_loader.clear(); 613 m_stream = 0; 614} 615 616void SourceBuffer::didStartLoading() 617{ 618 WTF_LOG(Media, "SourceBuffer::didStartLoading() %p", this); 619} 620 621void SourceBuffer::didReceiveDataForClient(const char* data, unsigned dataLength) 622{ 623 WTF_LOG(Media, "SourceBuffer::didReceiveDataForClient(%d) %p", dataLength, this); 624 ASSERT(m_updating); 625 ASSERT(m_loader); 626 627 m_webSourceBuffer->append(reinterpret_cast<const unsigned char*>(data), dataLength); 628} 629 630void SourceBuffer::didFinishLoading() 631{ 632 WTF_LOG(Media, "SourceBuffer::didFinishLoading() %p", this); 633 appendStreamDone(true); 634} 635 636void SourceBuffer::didFail(FileError::ErrorCode errorCode) 637{ 638 WTF_LOG(Media, "SourceBuffer::didFail(%d) %p", errorCode, this); 639 appendStreamDone(false); 640} 641 642} // namespace WebCore 643