I'm trying to load a smoothstreaming media into the chromecast. For that I've used the samples provided by google:
<body>
<video id='vid' />
<script type="text/javascript"
src="//www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js">
</script>
<script type="text/javascript"
src="//www.gstatic.com/cast/sdk/libs/mediaplayer/0.3.0/media_player.js">
</script>
<script type="text/javascript">
window.onload = function() {
// If you set ?Debug=true in the URL, such as a different App ID in the
// developer console, include debugging information.
cast.receiver.logger.setLevelValue(cast.receiver.LoggerLevel.DEBUG);
var mediaElement = document.getElementById('vid');
// Create the media manager. This will handle all media messages by default.
window.mediaManager = new cast.receiver.MediaManager(mediaElement);
// Remember the default value for the Receiver onLoad, so this sample can Play
// non-adaptive media as well.
window.defaultOnLoad = mediaManager.onLoad;
mediaManager.onLoad = function (event) {
/proto
// MPEG-DASH
protocol = cast.player.api.CreateDashStreamingProtocol(host);
} else if (url.indexOf('.ism/') >= 0) {
// Smooth Streaming
protocol = cast.player.api.CreateSmoothStreamingProtocol(host);
}
// How to override a method in Host. I know that it's safe to just provide this
// method.
host.onError = function(errorCode) {
console.log("Fatal Error - "+errorCode);
window.player.unload();
};
// If you need cookies, then set withCredentials = true also set any header
// information you need. If you don't need them, there can be some unexpected
// effects by setting this value.
// host.updateSegmentRequestInfo = function(requestInfo) {
// requestInfo.withCredentials = true;
// };
console.log("we have protocol "+ext);
if (protocol !== null) {
console.log("Starting Media Player Library");
window.player = new cast.player.api.Player(host);
window.player.load(protocol, initStart);
}
mediaElement.autoplay = autoplay; // Make sure autoplay get's set
if (url.lastIndexOf('.m3u8') >= 0) {
// HTTP Live Streaming
protocol = cast.player.api.CreateHlsStreamingProtocol(host);
} else if (url.lastIndexOf('.mpd') >= 0) {
// MPEG-DASH
protocol = cast.player.api.CreateDashStreamingProtocol(host);
} else if (url.indexOf('.ism/') >= 0) {
// Smooth Streaming
protocol = cast.player.api.CreateSmoothStreamingProtocol(host);
}
// How to override a method in Host. I know that it's safe to just provide this
// method.
host.onError = function(errorCode) {
console.log("Fatal Error - "+errorCode);
window.player.unload();
};
// If you need cookies, then set withCredentials = true also set any header
// information you need. If you don't need them, there can be some unexpected
// effects by setting this value.
// host.updateSegmentRequestInfo = function(requestInfo) {
// requestInfo.withCredentials = true;
// };
console.log("we have protocol "+ext);
And on the sender:
/**
* global variables
*/
var currentMediaSession = null;
var currentVolume = 0.5;
var progressFlag = 1;
var mediaCurrentTime = 0;
var session = null;
var mediaURLs = [
'http://playready.directtaps.net/smoothstreaming/TTLSS720VC1/To_The_Limit_720.ism/',
'http://commondatastorage.googleapis.com/gtv-videos-bucket/ED_1280.mp4',
'http://commondatastorage.googleapis.com/gtv-videos-bucket/tears_of_steel_1080p.mov',
'http://commondatastorage.googleapis.com/gtv-videos-bucket/reel_2012_1280x720.mp4',
'http://commondatastorage.googleapis.com/gtv-videos-bucket/Google%20IO%202011%2045%20Min%20Walk%20Out.mp3'];
var mediaTitles = [
'Big Buck Bunny',
'Elephant Dream',
'Tears of Steel',
'Reel 2012',
'Google I/O 2011 Audio'];
var mediaThumbs = [
'images/bunny.jpg',
'images/ed.jpg',
'images/Tears.jpg',
'images/reel.jpg',
'images/google-io-2011.jpg'];
var currentMediaURL = mediaURLs[0];
/**
* Call initialization
*/
if (!chrome.cast || !chrome.cast.isAvailable) {
setTimeout(initializeCastApi, 1000);
}
/**
* initialization
*/
function initializeCastApi() {
// default app ID to the default media receiver app
// optional: you may change it to your own app ID/receiver
var applicationID = '21176C05';
var sessionRequest = new chrome.cast.SessionRequest(applicationID);
var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
sessionListener,
receiverListener);
chrome.cast.initialize(apiConfig, onInitSuccess, onError);
};
/**
* initialization success callback
*/
function onInitSuccess() {
appendMessage("init success");
}
/**
* initialization error callback
*/
function onError() {
console.log("error");
appendMessage("error");
}
/**
* generic success callback
*/
function onSuccess(message) {
console.log(message);
}
/**
* callback on success for stopping app
*/
function onStopAppSuccess() {
console.log('Session stopped');
appendMessage('Session stopped');
document.getElementById("casticon").src = 'images/cast_icon_idle.png';
}
/**
* session listener during initialization
*/
function sessionListener(e) {
console.log('New session ID: ' + e.sessionId);
appendMessage('New session ID:' + e.sessionId);
session = e;
if (session.media.length != 0) {
appendMessage(
'Found ' + session.media.length + ' existing media sessions.');
onMediaDiscovered('onRequestSessionSuccess_', session.media[0]);
}
session.addMediaListener(
onMediaDiscovered.bind(this, 'addMediaListener'));
session.addUpdateListener(sessionUpdateListener.bind(this));
}
/**
* session update listener
*/
function sessionUpdateListener(isAlive) {
var message = isAlive ? 'Session Updated' : 'Session Removed';
message += ': ' + session.sessionId;
appendMessage(message);
if (!isAlive) {
session = null;
}
};
/**
* receiver listener during initialization
*/
function receiverListener(e) {
if( e === 'available' ) {
console.log("receiver found");
appendMessage("receiver found");
}
else {
console.log("receiver list empty");
appendMessage("receiver list empty");
}
}
/**
* select a media URL
* @param {string} m An index for media URL
*/
function selectMedia(m) {
console.log("media selected" + m);
appendMessage("media selected" + m);
currentMediaURL = mediaURLs[m];
var playpauseresume = document.getElementById("playpauseresume");
document.getElementById('thumb').src = mediaThumbs[m];
}
/**
* launch app and request session
*/
function launchApp() {
console.log("launching app...");
appendMessage("launching app...");
chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);
}
/**
* callback on success for requestSession call
* @param {Object} e A non-null new session.
*/
function onRequestSessionSuccess(e) {
console.log("session success: " + e.sessionId);
appendMessage("session success: " + e.sessionId);
session = e;
document.getElementById("casticon").src = 'images/cast_icon_active.png';
}
/**
* callback on launch error
*/
function onLaunchError() {
console.log("launch error");
appendMessage("launch error");
}
/**
* stop app/session
*/
function stopApp() {
session.stop(onStopAppSuccess, onError);
}
/**
* load media
* @param {string} i An index for media
*/
function loadMedia(i) {
if (!session) {
console.log("no session");
appendMessage("no session");
return;
}
console.log("loading..." + currentMediaURL);
appendMessage("loading..." + currentMediaURL);
var mediaInfo = new chrome.cast.media.MediaInfo(currentMediaURL);
mediaInfo.contentType = 'application/vnd.ms-sstr+xml';
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.autoplay = false;
request.currentTime = 0;
var payload = {
"title:" : mediaTitles[i],
"thumb" : mediaThumbs[i]
};
var json = {
"payload" : payload
};
request.customData = json;
session.loadMedia(request,
onMediaDiscovered.bind(this, 'loadMedia'),
onMediaError);
}
/**
* callback on success for loading media
* @param {Object} e A non-null media object
*/
function onMediaDiscovered(how, mediaSession) {
console.log("new media session ID:" + mediaSession.mediaSessionId);
appendMessage("new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')');
currentMediaSession = mediaSession;
mediaSession.addUpdateListener(onMediaStatusUpdate);
mediaCurrentTime = currentMediaSession.currentTime;
playpauseresume.innerHTML = 'Play';
document.getElementById("casticon").src = 'images/cast_icon_active.png';
}
/**
* callback on media loading error
* @param {Object} e A non-null media object
*/
function onMediaError(e) {
console.log("media error");
appendMessage("media error");
document.getElementById("casticon").src = 'images/cast_icon_warning.png';
}
/**
* callback for media status event
* @param {Object} e A non-null media object
*/
function onMediaStatusUpdate(isAlive) {
if( progressFlag ) {
document.getElementById("progress").value = parseInt(100 * currentMediaSession.currentTime / currentMediaSession.media.duration);
}
document.getElementById("playerstate").innerHTML = currentMediaSession.playerState;
}
/**
* play media
*/
function playMedia() {
if( !currentMediaSession )
return;
var playpauseresume = document.getElementById("playpauseresume");
if( playpauseresume.innerHTML == 'Play' ) {
currentMediaSession.play(null,
mediaCommandSuccessCallback.bind(this,"playing started for " + currentMediaSession.sessionId),
onError);
playpauseresume.innerHTML = 'Pause';
//currentMediaSession.addListener(onMediaStatusUpdate);
appendMessage("play started");
}
else {
if( playpauseresume.innerHTML == 'Pause' ) {
currentMediaSession.pause(null,
mediaCommandSuccessCallback.bind(this,"paused " + currentMediaSession.sessionId),
onError);
playpauseresume.innerHTML = 'Resume';
appendMessage("paused");
}
else {
if( playpauseresume.innerHTML == 'Resume' ) {
currentMediaSession.play(null,
mediaCommandSuccessCallback.bind(this,"resumed " + currentMediaSession.sessionId),
onError);
playpauseresume.innerHTML = 'Pause';
appendMessage("resumed");
}
}
}
}
/**
* stop media
*/
function stopMedia() {
if( !currentMediaSession )
return;
currentMediaSession.stop(null,
mediaCommandSuccessCallback.bind(this,"stopped " + currentMediaSession.sessionId),
onError);
var playpauseresume = document.getElementById("playpauseresume");
playpauseresume.innerHTML = 'Play';
appendMessage("media stopped");
}
/**
* set media volume
* @param {Number} level A number for volume level
* @param {Boolean} mute A true/false for mute/unmute
*/
function setMediaVolume(level, mute) {
if( !currentMediaSession )
return;
var volume = new chrome.cast.Volume();
volume.level = level;
currentVolume = volume.level;
volume.muted = mute;
var request = new chrome.cast.media.VolumeRequest();
request.volume = volume;
currentMediaSession.setVolume(request,
mediaCommandSuccessCallback.bind(this, 'media set-volume done'),
onError);
}
/**
* mute media
* @param {DOM Object} cb A checkbox element
*/
function muteMedia(cb) {
if( cb.checked == true ) {
document.getElementById('muteText').innerHTML = 'Unmute media';
setMediaVolume(currentVolume, true);
appendMessage("media muted");
}
else {
document.getElementById('muteText').innerHTML = 'Mute media';
setMediaVolume(currentVolume, false);
appendMessage("media unmuted");
}
}
/**
* seek media position
* @param {Number} pos A number to indicate percent
*/
function seekMedia(pos) {
console.log('Seeking ' + currentMediaSession.sessionId + ':' +
currentMediaSession.mediaSessionId + ' to ' + pos + "%");
progressFlag = 0;
var request = new chrome.cast.media.SeekRequest();
request.currentTime = pos * currentMediaSession.media.duration / 100;
currentMediaSession.seek(request,
onSeekSuccess.bind(this, 'media seek done'),
onError);
}
/**
* callback on success for media commands
* @param {string} info A message string
* @param {Object} e A non-null media object
*/
function onSeekSuccess(info) {
console.log(info);
appendMessage(info);
setTimeout(function(){progressFlag = 1},1500);
}
/**
* callback on success for media commands
* @param {string} info A message string
* @param {Object} e A non-null media object
*/
function mediaCommandSuccessCallback(info) {
console.log(info);
appendMessage(info);
}
/**
* append message to debug message window
* @param {string} message A message string
*/
function appendMessage(message) {
var dw = document.getElementById("debugmessage");
dw.innerHTML += '\n' + JSON.stringify(message);
};
I am trying media #1 which is .ism - I also tried with the /Manifest - but no luck. In the debugging console I am getting:
[214.054s] [cast.player.api.Player] load -3
media_player.js:23
[214.060s] [goog.net.XhrIo] Opening Xhr [GET http://playready.directtaps.net/smoothstreaming/TTLSS720VC1/To_The_Limit_720.ism/Manifest -1]
media_player.js:23
[214.065s] [goog.net.XhrIo] Will abort after 10000ms if incomplete, xhr2 false [GET http://playready.directtaps.net/smoothstreaming/TTLSS720VC1/To_The_Limit_720.ism/Manifest -1]
media_player.js:23
[214.070s] [goog.net.XhrIo] Sending request [GET http://playready.directtaps.net/smoothstreaming/TTLSS720VC1/To_The_Limit_720.ism/Manifest -1]
media_player.js:23
[214.088s] [goog.net.XhrIo] Request complete [GET http://playready.directtaps.net/smoothstreaming/TTLSS720VC1/To_The_Limit_720.ism/Manifest 200]
media_player.js:23
[214.120s] [cast.player.api.Player] sourceopen
media_player.js:23
[214.142s] [cast.player.api.Player] play
media_player.js:23
[214.291s] [cast.receiver.MediaManager] Load metadata error
cast_receiver.js:19
[214.296s] [cast.receiver.MediaManager] Resetting media element
cast_receiver.js:19
[214.303s] [cast.receiver.MediaManager] Sending error message to 4:client-34217
cast_receiver.js:19
[214.307s] [cast.receiver.IpcChannel] IPC message sent: {"namespace":"urn:x-cast:com.google.cast.media","senderId":"4:client-34217","data":"{\"requestId\":9217017,\"type\":\"LOAD_FAILED\"}"}
cast_receiver.js:19
[214.171s] [cast.player.api.Player] error
media_player.js:23
Fatal Error - 1 index.html:61
[214.176s] [cast.player.api.Player] unload -3
Any idea???
Thanks!
Where did you find that URL? It's incomplete, the right one is http://playready.directtaps.net/smoothstreaming/TTLSS720VC1/To_The_Limit_720.ism/manifest, but it is unlikely to work. Other files have been posted at: Microsoft's SmoothStreaming samples files, that said, I don't believe that Microsoft is providing a CORS header that works for Chromecast.
We do provide some very simple media that you can host yourself. And we provide a very simple server, if you need that to host and provide a CORS header as well.