1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 /** @suppress {duplicate} */
8 var remoting = remoting || {};
11 * @param {HTMLMediaElement} videoTag <video> tag to render to.
14 remoting.MediaSourceRenderer = function(videoTag) {
15 /** @type {HTMLMediaElement} */
16 this.video_ = videoTag;
18 /** @type {MediaSource} */
19 this.mediaSource_ = null;
21 /** @type {SourceBuffer} */
22 this.sourceBuffer_ = null;
24 /** @type {!Array.<ArrayBuffer>} Queue of pending buffers that haven't been
25 * processed. A null element indicates that the SourceBuffer can be reset
26 * because the following buffer contains a keyframe. */
31 * @param {string} format Format of the stream.
33 remoting.MediaSourceRenderer.prototype.reset = function(format) {
37 // Create a new MediaSource instance.
38 this.sourceBuffer_ = null;
39 this.mediaSource_ = new MediaSource();
40 this.mediaSource_.addEventListener('sourceopen',
41 this.onSourceOpen_.bind(this, format));
42 this.mediaSource_.addEventListener('sourceclose', function(e) {
43 console.error("MediaSource closed unexpectedly.");
45 this.mediaSource_.addEventListener('sourceended', function(e) {
46 console.error("MediaSource ended unexpectedly.");
49 // Start playback from new MediaSource.
51 /** @type {string} */(
52 window.URL.createObjectURL(/** @type {!Blob} */(this.mediaSource_)));
57 * @param {string} format
60 remoting.MediaSourceRenderer.prototype.onSourceOpen_ = function(format) {
62 this.mediaSource_.addSourceBuffer(format);
64 this.sourceBuffer_.addEventListener(
65 'updateend', this.processPendingData_.bind(this));
66 this.processPendingData_();
72 remoting.MediaSourceRenderer.prototype.processPendingData_ = function() {
73 if (this.sourceBuffer_) {
74 while (this.buffers_.length > 0 && !this.sourceBuffer_.updating) {
75 var buffer = /** @type {ArrayBuffer} */ this.buffers_.shift();
77 // Remove all data from the SourceBuffer. By default Chrome buffers up
78 // 150MB of data in SourceBuffer. We never need to seek the stream, so
79 // it doesn't make sense to keep any of that data.
80 if (this.sourceBuffer_.buffered.length > 0) {
81 this.sourceBuffer_.remove(
82 this.sourceBuffer_.buffered.start(0),
83 this.sourceBuffer_.buffered.end(
84 this.sourceBuffer_.buffered.length - 1));
87 // TODO(sergeyu): Figure out the way to determine when a frame is
88 // rendered and use it to report performance statistics.
89 this.sourceBuffer_.appendBuffer(buffer);
96 * @param {ArrayBuffer} data
97 * @param {boolean} keyframe
99 remoting.MediaSourceRenderer.prototype.onIncomingData =
100 function(data, keyframe) {
102 // Queue SourceBuffer reset request.
103 this.buffers_.push(null);
105 this.buffers_.push(data);
106 this.processPendingData_();