diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css
index a93a84f3d7..3a17ea195f 100644
--- a/dashboard-ui/css/librarybrowser.css
+++ b/dashboard-ui/css/librarybrowser.css
@@ -1574,6 +1574,7 @@ span.itemCommunityRating:not(:empty) + .userDataIcons {
.detailsMenuHeaderWithLogo h3 {
padding: 0 30px;
+ line-height: .5;
}
@media all and (min-height:500px) {
diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js
index 9718a909f4..e07cca4334 100644
--- a/dashboard-ui/scripts/chromecast.js
+++ b/dashboard-ui/scripts/chromecast.js
@@ -229,8 +229,6 @@
$(this).trigger('connect');
- MediaController.setActivePlayer(PlayerName);
-
this.sendMessage({
options: {},
command: 'Identify'
@@ -548,6 +546,8 @@
$(castPlayer).on("connect", function (e) {
+ MediaController.setActivePlayer(PlayerName, self.getCurrentTargetInfo());
+
console.log('cc: connect');
// Reset this so the next query doesn't make it appear like content is playing.
self.lastPlayerData = {};
@@ -837,6 +837,13 @@
console.log(JSON.stringify(data));
return data;
};
+
+ self.tryPair = function (target) {
+
+ var deferred = $.Deferred();
+ deferred.resolve();
+ return deferred.promise();
+ };
}
function initializeChromecast() {
diff --git a/dashboard-ui/scripts/librarylist.js b/dashboard-ui/scripts/librarylist.js
index 47a78a8996..33456a0176 100644
--- a/dashboard-ui/scripts/librarylist.js
+++ b/dashboard-ui/scripts/librarylist.js
@@ -532,7 +532,7 @@
html += '
';
diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js
index 08e5c8f663..ac8143ef73 100644
--- a/dashboard-ui/scripts/mediacontroller.js
+++ b/dashboard-ui/scripts/mediacontroller.js
@@ -118,15 +118,42 @@
}
currentPlayer = player;
- currentTargetInfo = targetInfo || player.getCurrentTargetInfo();
+ currentTargetInfo = targetInfo;
console.log('Active player: ' + JSON.stringify(currentTargetInfo));
$(self).trigger('playerchange');
};
+ self.trySetActivePlayer = function (player, targetInfo) {
+
+ if (typeof (player) === 'string') {
+ player = players.filter(function (p) {
+ return p.name == player;
+ })[0];
+ }
+
+ if (!player) {
+ throw new Error('null player');
+ }
+
+ player.tryPair(targetInfo).done(function() {
+
+ currentPlayer = player;
+ currentTargetInfo = targetInfo;
+
+ console.log('Active player: ' + JSON.stringify(currentTargetInfo));
+
+ $(self).trigger('playerchange');
+ });
+ };
+
self.setDefaultPlayerActive = function () {
- self.setActivePlayer(self.getDefaultPlayer());
+
+ var player = self.getDefaultPlayer();
+ var target = player.getTargets()[0];
+
+ self.setActivePlayer(player, target);
};
self.removeActivePlayer = function (name) {
@@ -597,7 +624,7 @@
var playableMediaTypes = this.getAttribute('data-mediatypes').split(',');
var supportedCommands = this.getAttribute('data-commands').split(',');
- MediaController.setActivePlayer(playerName, {
+ MediaController.trySetActivePlayer(playerName, {
id: targetId,
name: targetName,
playableMediaTypes: playableMediaTypes,
diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js
index c906e1638d..049ee50f0c 100644
--- a/dashboard-ui/scripts/mediaplayer.js
+++ b/dashboard-ui/scripts/mediaplayer.js
@@ -1731,15 +1731,18 @@
var getItemFields = "MediaSources,Chapters";
- self.getCurrentTargetInfo = function () {
- return self.getTargets()[0];
+ self.tryPair = function (target) {
+
+ var deferred = $.Deferred();
+ deferred.resolve();
+ return deferred.promise();
};
}
window.MediaPlayer = new mediaPlayer();
window.MediaController.registerPlayer(window.MediaPlayer);
- window.MediaController.setActivePlayer(window.MediaPlayer);
+ window.MediaController.setActivePlayer(window.MediaPlayer, window.MediaPlayer.getTargets()[0]);
})(document, setTimeout, clearTimeout, screen, window.store, $, setInterval, window);
\ No newline at end of file
diff --git a/dashboard-ui/scripts/remotecontrol.js b/dashboard-ui/scripts/remotecontrol.js
index a8ae221878..a698f8c44f 100644
--- a/dashboard-ui/scripts/remotecontrol.js
+++ b/dashboard-ui/scripts/remotecontrol.js
@@ -276,6 +276,13 @@
return deferred.promise();
};
+
+ self.tryPair = function(target) {
+
+ var deferred = $.Deferred();
+ deferred.resolve();
+ return deferred.promise();
+ };
}
var player = new remoteControlPlayer();
diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js
index 9a43b27fb0..5f10a5b428 100644
--- a/dashboard-ui/scripts/site.js
+++ b/dashboard-ui/scripts/site.js
@@ -1813,7 +1813,7 @@ var AppInfo = {};
});
if (Dashboard.isRunningInCordova()) {
- requirejs(['thirdparty/cordova/chromecast']);
+ requirejs(['thirdparty/cordova/connectsdk']);
} else {
if ($.browser.chrome) {
requirejs(['scripts/chromecast']);
diff --git a/dashboard-ui/thirdparty/cordova/chromecast.js b/dashboard-ui/thirdparty/cordova/chromecast.js
index 5f282702bb..fb2ff33e90 100644
--- a/dashboard-ui/thirdparty/cordova/chromecast.js
+++ b/dashboard-ui/thirdparty/cordova/chromecast.js
@@ -1 +1,348 @@
-
\ No newline at end of file
+(function () {
+
+ var PlayerName = "Chromecast";
+ var ApplicationID = "F4EB2E8E";
+ var currentDevice;
+
+ function chromecastPlayer() {
+
+ var self = this;
+
+ // MediaController needs this
+ self.name = PlayerName;
+
+ self.getItemsForPlayback = function (query) {
+
+ var userId = Dashboard.getCurrentUserId();
+
+ query.Limit = query.Limit || 100;
+ query.ExcludeLocationTypes = "Virtual";
+
+ return ApiClient.getItems(userId, query);
+ };
+
+ var castPlayer = {};
+
+ $(castPlayer).on("connect", function (e) {
+
+ console.log('cc: connect');
+ // Reset this so the next query doesn't make it appear like content is playing.
+ self.lastPlayerData = {};
+ });
+
+ $(castPlayer).on("playbackstart", function (e, data) {
+
+ console.log('cc: playbackstart');
+
+ castPlayer.initializeCastPlayer();
+
+ var state = self.getPlayerStateInternal(data);
+ $(self).trigger("playbackstart", [state]);
+ });
+
+ $(castPlayer).on("playbackstop", function (e, data) {
+
+ console.log('cc: playbackstop');
+ var state = self.getPlayerStateInternal(data);
+
+ $(self).trigger("playbackstop", [state]);
+
+ // Reset this so the next query doesn't make it appear like content is playing.
+ self.lastPlayerData = {};
+ });
+
+ $(castPlayer).on("playbackprogress", function (e, data) {
+
+ console.log('cc: positionchange');
+ var state = self.getPlayerStateInternal(data);
+
+ $(self).trigger("positionchange", [state]);
+ });
+
+ self.play = function (options) {
+
+ Dashboard.getCurrentUser().done(function (user) {
+
+ if (options.items) {
+
+ self.playWithCommand(options, 'PlayNow');
+
+ } else {
+
+ self.getItemsForPlayback({
+
+ Ids: options.ids.join(',')
+
+ }).done(function (result) {
+
+ options.items = result.Items;
+ self.playWithCommand(options, 'PlayNow');
+
+ });
+ }
+
+ });
+
+ };
+
+ self.playWithCommand = function (options, command) {
+
+ if (!options.items) {
+ ApiClient.getItem(Dashboard.getCurrentUserId(), options.ids[0]).done(function (item) {
+
+ options.items = [item];
+ self.playWithCommand(options, command);
+ });
+
+ return;
+ }
+
+ castPlayer.loadMedia(options, command);
+ };
+
+ self.unpause = function () {
+ castPlayer.playMedia();
+ };
+
+ self.pause = function () {
+ castPlayer.pauseMedia();
+ };
+
+ self.shuffle = function (id) {
+
+ var userId = Dashboard.getCurrentUserId();
+
+ ApiClient.getItem(userId, id).done(function (item) {
+
+ self.playWithCommand({
+
+ items: [item]
+
+ }, 'Shuffle');
+
+ });
+
+ };
+
+ self.instantMix = function (id) {
+
+ var userId = Dashboard.getCurrentUserId();
+
+ ApiClient.getItem(userId, id).done(function (item) {
+
+ self.playWithCommand({
+
+ items: [item]
+
+ }, 'InstantMix');
+
+ });
+
+ };
+
+ self.canQueueMediaType = function (mediaType) {
+ return mediaType == "Audio";
+ };
+
+ self.queue = function (options) {
+ self.playWithCommnd(options, 'PlayLast');
+ };
+
+ self.queueNext = function (options) {
+ self.playWithCommand(options, 'PlayNext');
+ };
+
+ self.stop = function () {
+ castPlayer.stopMedia();
+ };
+
+ self.displayContent = function (options) {
+
+ castPlayer.sendMessage({
+ options: options,
+ command: 'DisplayContent'
+ });
+ };
+
+ self.mute = function () {
+ castPlayer.mute();
+ };
+
+ self.unMute = function () {
+ self.setVolume(getCurrentVolume() + 2);
+ };
+
+ self.toggleMute = function () {
+
+ var state = self.lastPlayerData || {};
+ state = state.PlayState || {};
+
+ if (state.IsMuted) {
+ self.unMute();
+ } else {
+ self.mute();
+ }
+ };
+
+ function getBaseTargetInfo() {
+ var target = {};
+
+ target.playerName = PlayerName;
+ target.playableMediaTypes = ["Audio", "Video"];
+ target.isLocalPlayer = false;
+ target.appName = PlayerName;
+ target.supportedCommands = [
+ "VolumeUp",
+ "VolumeDown",
+ "Mute",
+ "Unmute",
+ "ToggleMute",
+ "SetVolume",
+ "SetAudioStreamIndex",
+ "SetSubtitleStreamIndex",
+ "DisplayContent"
+ ];
+
+ return target;
+ }
+
+ function convertDeviceToTarget(device) {
+
+ var target = getBaseTargetInfo();
+
+ target.name = target.deviceName = device.getFriendlyName();
+ target.id = device.getId();
+
+ return target;
+ }
+
+ self.getTargets = function () {
+
+ var manager = ConnectSDK.discoveryManager;
+
+ return manager.getDeviceList().map(convertDeviceToTarget);
+ };
+
+ self.seek = function (position) {
+ castPlayer.seekMedia(position);
+ };
+
+ self.setAudioStreamIndex = function (index) {
+ castPlayer.sendMessage({
+ options: {
+ index: index
+ },
+ command: 'SetAudioStreamIndex'
+ });
+ };
+
+ self.setSubtitleStreamIndex = function (index) {
+ castPlayer.sendMessage({
+ options: {
+ index: index
+ },
+ command: 'SetSubtitleStreamIndex'
+ });
+ };
+
+ self.nextTrack = function () {
+ castPlayer.sendMessage({
+ options: {},
+ command: 'NextTrack'
+ });
+ };
+
+ self.previousTrack = function () {
+ castPlayer.sendMessage({
+ options: {},
+ command: 'PreviousTrack'
+ });
+ };
+
+ self.beginPlayerUpdates = function () {
+ // Setup polling here
+ };
+
+ self.endPlayerUpdates = function () {
+ // Stop polling here
+ };
+
+ function getCurrentVolume() {
+ var state = self.lastPlayerData || {};
+ state = state.PlayState || {};
+
+ return state.VolumeLevel == null ? 100 : state.VolumeLevel;
+ }
+
+ self.volumeDown = function () {
+
+ self.setVolume(getCurrentVolume() - 2);
+ };
+
+ self.volumeUp = function () {
+
+ self.setVolume(getCurrentVolume() + 2);
+ };
+
+ self.setVolume = function (vol) {
+
+ vol = Math.min(vol, 100);
+ vol = Math.max(vol, 0);
+
+ castPlayer.setReceiverVolume(false, (vol / 100));
+ };
+
+ self.getPlayerState = function () {
+
+ var deferred = $.Deferred();
+
+ var result = self.getPlayerStateInternal();
+
+ deferred.resolveWith(null, [result]);
+
+ return deferred.promise();
+ };
+
+ self.lastPlayerData = {};
+
+ self.getPlayerStateInternal = function (data) {
+
+ data = data || self.lastPlayerData;
+ self.lastPlayerData = data;
+
+ console.log(JSON.stringify(data));
+ return data;
+ };
+
+ self.tryPair = function (target) {
+
+ var deferred = $.Deferred();
+ deferred.resolve();
+ return deferred.promise();
+ };
+ }
+
+ function onDeviceLost() {
+
+ }
+
+ function initSdk() {
+
+ var manager = ConnectSDK.discoveryManager;
+
+ manager.addListener('devicelost', onDeviceLost);
+
+ MediaController.registerPlayer(new chromecastPlayer());
+
+ $(MediaController).on('playerchange', function () {
+
+ if (MediaController.getPlayerInfo().name == PlayerName) {
+
+ // launch app if needed
+ }
+ });
+ }
+
+ initSdk();
+
+})();
\ No newline at end of file
diff --git a/dashboard-ui/thirdparty/cordova/connectsdk.js b/dashboard-ui/thirdparty/cordova/connectsdk.js
new file mode 100644
index 0000000000..bd58636556
--- /dev/null
+++ b/dashboard-ui/thirdparty/cordova/connectsdk.js
@@ -0,0 +1,37 @@
+(function () {
+
+
+ function onDeviceFound() {
+
+ }
+
+ function onDeviceLost() {
+
+ }
+
+ function initSdk() {
+
+ var manager = ConnectSDK.discoveryManager;
+
+ manager.setPairingLevel(ConnectSDK.PairingLevel.OFF);
+ manager.setAirPlayServiceMode(ConnectSDK.AirPlayServiceMode.Media);
+
+ // Show devices that support playing videos and pausing
+ manager.setCapabilityFilters([
+ new ConnectSDK.CapabilityFilter(["MediaPlayer.Display.Video", "MediaControl.Pause"])
+ ]);
+
+ manager.addListener('devicefound', onDeviceFound);
+ manager.addListener('devicelost', onDeviceLost);
+
+ requirejs(['thirdparty/cordova/chromecast']);
+ }
+
+ document.addEventListener("deviceready", function () {
+
+ initSdk();
+
+ }, false);
+
+
+})();
\ No newline at end of file