shaka-player
Version:
DASH/EME video player library
345 lines (277 loc) • 7.7 kB
JavaScript
/**
* @license
* Copyright 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Chromecast sender functionality.
* @class
*/
var sender = function() {};
/**
* Custom message namespace for shaka cast app.
* @const {string}
**/
sender.MESSAGE_NAMESPACE = 'urn:x-cast:com.shaka.cast.messages';
/**
* The registered ID of the shaka receiver app.
* @const {string}
*/
sender.RECEIVER_APP_ID = '2CE0930D';
/**
* Current session object.
* @type {chrome.cast.Session}
*/
sender.session = null;
/**
* The casted video's seconds buffered ahead the current time.
* @type {string}
*/
sender.bufferedAheadDebug = '0 seconds';
/**
* The casted video's seconds buffered behind the current time.
* @type {string}
*/
sender.bufferedBehindDebug = '0 seconds';
/**
* The casted video's resolution.
* @type {string}
*/
sender.videoResDebug = '0 x 0';
/**
* The states of the cast connection.
* @enum {number}
*/
sender.states = {
CAST_UNAVAILABLE: 0,
CAST_AVAILABLE: 1,
CAST_CONNECTED: 2
};
/**
* The current state of the cast connection.
* @type {number}
*/
sender.state = sender.states.CAST_UNAVAILABLE;
/** @type {number} */
sender.currentMediaTime = 0;
/** @type {number} */
sender.currentMediaDuration = 0;
/**
* @typedef {{
* length: number,
* start: number,
* end: number
* }}
*/
sender.MediaBuffered;
/** @type {sender.MediaBuffered} */
sender.currentMediaBuffered = {'start': 0, 'end': 0, 'length': 0};
/** @type {boolean} */
sender.currentMediaMuted = false;
/** @type {number} */
sender.currentMediaVolume = 1;
/**
* Called when Google Cast API is available.
* @param {boolean} loaded
* @param {string} errorInfo
*/
window.__onGCastApiAvailable = function(loaded, errorInfo) {
if (loaded) {
sender.initialize();
} else {
sender.onError(errorInfo);
}
};
/**
* Initializes the sender
*/
sender.initialize = function() {
var sessionRequest = new chrome.cast.SessionRequest(sender.RECEIVER_APP_ID);
var apiConfig = new chrome.cast.ApiConfig(
sessionRequest,
sender.onSessionConnection_,
// On receiver connection callback not needed at this time.
function() {});
chrome.cast.initialize(
apiConfig,
sender.onInitSuccess_,
sender.onError.bind(null, 'Chromecast sender initialization error.'));
};
/**
* On successful initialization update app state.
* @private
*/
sender.onInitSuccess_ = function() {
sender.onSuccess('Chromecast sender initialization success.');
sender.state = sender.states.CAST_AVAILABLE;
playerControls.displayCastConnection(false);
};
/**
* Launches a casting session.
*/
sender.launch = function() {
chrome.cast.requestSession(
sender.onSessionConnection_, sender.onError.bind(null, 'Launch Error'));
};
/**
* Updates the app state on session connection.
* @param {chrome.cast.Session} newSession The current cast session.
* @private
*/
sender.onSessionConnection_ = function(newSession) {
sender.session = newSession;
sender.state = sender.states.CAST_CONNECTED;
app.switchStreamToCast();
app.enableStreamOptions(false);
playerControls.displayCastConnection(true);
sender.session.addUpdateListener(sender.onSessionUpdate_);
sender.session.addMessageListener(
sender.MESSAGE_NAMESPACE, sender.onReceiverMessage_);
};
/**
* Handles updates to the current session.
* @param {boolean} status True if the session is still alive.
* @private
*/
sender.onSessionUpdate_ = function(status) {
if (!status) {
sender.onAppStopped_();
}
};
/**
* Stops casting.
*/
sender.stop = function() {
if (!sender.session) return;
sender.session.stop(
sender.onSuccess.bind(null, 'Stopping Cast'),
sender.onError.bind(null, 'Error stopping app'));
};
/**
* Updates app state when casting stopped.
* @private
*/
sender.onAppStopped_ = function() {
sender.session = null;
sender.state = sender.states.CAST_AVAILABLE;
app.enableStreamOptions(true);
playerControls.displayCastConnection(false);
};
/**
* Loads the given stream into the cast receiver.
* @param {Object} value The type of stream and list of arguments.
*/
sender.loadStream = function(value) {
sender.sendMessage({'type': 'loadStream', 'value': value});
};
/**
* Sends a play command to the cast receiver.
*/
sender.play = function() {
sender.sendMessage({'type': 'play'});
};
/**
* Sends a pause command to the cast receiver.
*/
sender.pause = function() {
sender.sendMessage({'type': 'pause'});
};
/**
* Sends a play command to change the current video time to cast receiver.
* @param {number} time The new current time.
*/
sender.setCurrentTime = function(time) {
sender.sendMessage({'type': 'setCurrentTime', 'value': time});
};
/**
* Sends a mute/un-mute command to the cast receiver.
* @param {boolean} mute True to mute, false to un-mute.
*/
sender.mute = function(mute) {
sender.sendMessage({'type': 'mute', 'value': mute});
};
/**
* Sends a command to change the video volume to the cast receiver.
* @param {number} volume The new volume.
*/
sender.setVolume = function(volume) {
sender.sendMessage({'type': 'setVolume', 'value': volume});
};
/**
* Handles messages from the receiver application.
* @param {string} namespace The message namespace.
* @param {string} message A message string.
* @private
*/
sender.onReceiverMessage_ = function(namespace, message) {
var info = JSON.parse(message);
switch (info['type']) {
case 'currentTime' :
sender.currentMediaTime = info['value'];
playerControls.updateTimeAndSeekRange();
break;
case'playing' :
sender.currentMediaDuration = info['value'];
playerControls.displayPlayButton(false);
break;
case 'paused' :
playerControls.displayPlayButton(true);
break;
case 'buffered' :
sender.currentMediaBuffered = info['value'];
break;
case 'volume' :
sender.currentMediaVolume = info['value'].volume;
sender.currentMediaMuted = info['value'].muted;
playerControls.onVolumeChange();
break;
case 'debugInfo':
var debugInfo = info['value'];
sender.bufferedAheadDebug = debugInfo['bufferedAheadDebug'];
sender.bufferedBehindDebug = debugInfo['bufferedBehindDebug'];
sender.videoResDebug = debugInfo['videoResDebug'];
break;
case 'error' :
sender.onError(info['value']);
break;
}
};
/**
* Sends a message to the current session, if one is open.
* @param {!Object|string} message A message object
*/
sender.sendMessage = function(message) {
if (sender.session) {
sender.session.sendMessage(
sender.MESSAGE_NAMESPACE,
message,
sender.onSuccess.bind(null, 'Message sent: ' + JSON.stringify(message)),
sender.onError.bind(
null, 'Error sending message: ' + JSON.stringify(message)));
}
};
/**
* Error callback
* @param {string} message An error message.
*/
sender.onError = function(message) {
console.error(message);
};
/**
* Success callback
* @param {string} message A success message.
*/
sender.onSuccess = function(message) {
console.debug(message);
};