Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
166
gaia/tv_apps/dlna-player/js/avtransport_manager.js
Executable file
166
gaia/tv_apps/dlna-player/js/avtransport_manager.js
Executable file
|
|
@ -0,0 +1,166 @@
|
|||
/* globals ServiceManager, Plug */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
function AVTManager() {
|
||||
|
||||
}
|
||||
AVTManager.prototype = {
|
||||
__proto__: ServiceManager.prototype,
|
||||
|
||||
prevButton: document.getElementById('remotePrev'),
|
||||
rewindButton: document.getElementById('remoteRewind'),
|
||||
playButton: document.getElementById('remotePlay'),
|
||||
pauseButton: document.getElementById('remotePause'),
|
||||
stopButton: document.getElementById('remoteStop'),
|
||||
ffButton: document.getElementById('remoteFF'),
|
||||
nextButton: document.getElementById('remoteNext'),
|
||||
avtSelector: document.getElementById('AVTList'),
|
||||
trackInfoBar: document.getElementById('trackInfoBar'),
|
||||
|
||||
listElementId: 'AVTList',
|
||||
serviceType: 'upnp:urn:schemas-upnp-org:service:AVTransport:1',
|
||||
serviceConstructor: Plug.UPnP_AVTransport,
|
||||
|
||||
serverView: function avtm_serverView(serviceWrapper) {
|
||||
var option = document.createElement('option');
|
||||
option.value = serviceWrapper.svc.id;
|
||||
option.textContent = serviceWrapper.friendlyName;
|
||||
|
||||
return option;
|
||||
},
|
||||
get currentAVT() {
|
||||
var id = this.avtSelector[this.avtSelector.selectedIndex].value;
|
||||
return id == 'local' ? null : this.savedServices[id];
|
||||
},
|
||||
|
||||
/* Manipulations */
|
||||
prev: function avtm_prev() {
|
||||
if (!this.currentAVT) {
|
||||
return;
|
||||
}
|
||||
this.currentAVT.previous(0).then(null, function(e) {
|
||||
console.log(e.description);
|
||||
});
|
||||
},
|
||||
next: function avtm_next() {
|
||||
if (!this.currentAVT) {
|
||||
return;
|
||||
}
|
||||
this.currentAVT.next(0).then(null, function(e) {
|
||||
console.log(e.description);
|
||||
});
|
||||
},
|
||||
play: function avtm_play() {
|
||||
if (!this.currentAVT) {
|
||||
return;
|
||||
}
|
||||
this.currentAVT.play(0);
|
||||
},
|
||||
pause: function avtm_pause() {
|
||||
if (!this.currentAVT) {
|
||||
return;
|
||||
}
|
||||
this.currentAVT.pause(0);
|
||||
},
|
||||
stop: function avtm_stop() {
|
||||
if (!this.currentAVT) {
|
||||
return;
|
||||
}
|
||||
this.currentAVT.stop(0);
|
||||
},
|
||||
ff: function avtm_getPositionInfo() {
|
||||
if (!this.currentAVT) {
|
||||
return Promise.reject();
|
||||
}
|
||||
return this.currentAVT.getPositionInfo(0).then(function(response) {
|
||||
return this.currentAVT.seek(
|
||||
'0', 'REL_TIME', this.timeDelta(response.data.RelTime, 10));
|
||||
}.bind(this));
|
||||
},
|
||||
rwd: function avtm_getPositionInfo() {
|
||||
if (!this.currentAVT) {
|
||||
return Promise.reject();
|
||||
}
|
||||
return this.currentAVT.getPositionInfo(0).then(function(response) {
|
||||
return this.currentAVT.seek(
|
||||
'0', 'REL_TIME', this.timeDelta(response.data.RelTime, -10));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
timeDelta: function avtm_timeDelta(string, deltasec) {
|
||||
var hms = string.split(':').map(x => parseInt(x));
|
||||
var date = new Date(0, 0, 1, hms[0], hms[1], hms[2] + deltasec);
|
||||
if (date.getYear == -1) {
|
||||
return '00:00:00';
|
||||
}
|
||||
return date.getHours() + ':' +
|
||||
date.getMinutes() + ':' +
|
||||
date.getSeconds();
|
||||
},
|
||||
|
||||
getMediaInfo: function avtm_getMediaInfo() {
|
||||
if (!this.currentAVT) {
|
||||
return;
|
||||
}
|
||||
return this.currentAVT.getMediaInfo(0);
|
||||
},
|
||||
getPositionInfo: function avtm_getPositionInfo() {
|
||||
if (!this.currentAVT) {
|
||||
return Promise.reject();
|
||||
}
|
||||
return this.currentAVT.getPositionInfo(0);
|
||||
},
|
||||
|
||||
updateTrackInfoBar: function avtm_updateTrackInfoBar() {
|
||||
this.trackInfoBar.textContent =
|
||||
'<<' + this.artist + ' - ' + this.title + '>>' +
|
||||
this.duration + '/' + (this.position ? this.position : '00:00:00');
|
||||
},
|
||||
|
||||
updateMediaInfo: function avtm_updateMediaInfo() {
|
||||
return this.getMediaInfo().then(function(response) {
|
||||
if (!response || !response.data) {
|
||||
return;
|
||||
}
|
||||
var parser = new DOMParser();
|
||||
var metatree = parser.parseFromString(
|
||||
response.data.CurrentURIMetaData, 'text/xml');
|
||||
var titleElem = metatree.getElementsByTagName('dc:title')[0];
|
||||
var artistElem = metatree.getElementsByTagName('upnp:artist')[0];
|
||||
this.title = titleElem ? titleElem.textContent : 'Unknown Title';
|
||||
this.artist = artistElem ? artistElem.textContent : 'Unknown Artist';
|
||||
this.duration = response.data.MediaDuration;
|
||||
this.updateTrackInfoBar();
|
||||
}.bind(this));
|
||||
},
|
||||
updatePositionInfo: function avtm_getMediaInfo() {
|
||||
this.getPositionInfo().then(function(response) {
|
||||
if (!response || !response.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.position = response.data.RelTime;
|
||||
this.updateTrackInfoBar();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
init: function avtm_init() {
|
||||
ServiceManager.prototype.init.apply(this);
|
||||
|
||||
this.pauseButton.addEventListener('click', this.pause.bind(this));
|
||||
this.playButton.addEventListener('click', this.play.bind(this));
|
||||
this.stopButton.addEventListener('click', this.stop.bind(this));
|
||||
|
||||
this.prevButton.addEventListener('click', this.prev.bind(this));
|
||||
this.nextButton.addEventListener('click', this.next.bind(this));
|
||||
this.ffButton.addEventListener('click', this.ff.bind(this));
|
||||
this.rewindButton.addEventListener('click', this.rwd.bind(this));
|
||||
this.avtSelector.addEventListener(
|
||||
'change', this.updateMediaInfo.bind(this));
|
||||
setInterval(this.updatePositionInfo.bind(this), 1000);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
exports.AVTManager = AVTManager;
|
||||
})(window);
|
||||
17
gaia/tv_apps/dlna-player/js/connection_service_manager.js
Executable file
17
gaia/tv_apps/dlna-player/js/connection_service_manager.js
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
/* globals ServiceManager, Plug */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
function ConnectionServiceManager() {
|
||||
|
||||
}
|
||||
|
||||
ConnectionServiceManager.prototype = {
|
||||
__proto__: ServiceManager.prototype,
|
||||
|
||||
listElementId: 'rendererList',
|
||||
serviceType: 'upnp:urn:schemas-upnp-org:service:ConnectionManager:1',
|
||||
serviceConstructor: Plug.UPnP_ConnectionManager
|
||||
};
|
||||
exports.ConnectionServiceManager = ConnectionServiceManager;
|
||||
})(window);
|
||||
336
gaia/tv_apps/dlna-player/js/content_directory_manager.js
Executable file
336
gaia/tv_apps/dlna-player/js/content_directory_manager.js
Executable file
|
|
@ -0,0 +1,336 @@
|
|||
/* globals Plug, deviceManager */
|
||||
|
||||
(function(exports) {
|
||||
'use strict';
|
||||
//
|
||||
// TODO: Refactor to use ServiceManager as prototype.
|
||||
//
|
||||
var DEBUG = false;
|
||||
|
||||
var savedServices = {};
|
||||
|
||||
var debugEl;
|
||||
var avtSelector;
|
||||
var audioPlayer;
|
||||
var videoPlayer;
|
||||
var imagePlayer;
|
||||
var unknownPlayer;
|
||||
var discoverButton;
|
||||
var currentPlayer;
|
||||
var folderList;
|
||||
var debugPanel;
|
||||
var directoryPage;
|
||||
var toPlayerPage;
|
||||
|
||||
function debugLog(msg, level) {
|
||||
if (!DEBUG && level == 'debug') {
|
||||
return;
|
||||
}
|
||||
var logEl = document.createElement('div');
|
||||
logEl.textContent = msg;
|
||||
debugEl.appendChild(logEl);
|
||||
}
|
||||
|
||||
function toggleFolder(evt) {
|
||||
evt.preventDefault();
|
||||
var elem = evt.target;
|
||||
|
||||
if (elem.nextSibling && elem.nextSibling.tagName == 'UL') {
|
||||
// folder is opened. Close it.
|
||||
elem.parentElement.removeChild(elem.nextSibling);
|
||||
elem.classList.remove('opened');
|
||||
} else {
|
||||
// folder is closed. Open it.
|
||||
debugLog(elem.serviceId, 'debug');
|
||||
elem.classList.add('opened');
|
||||
browseFolder(
|
||||
elem.dataset.serviceId, elem.dataset.href, evt.target);
|
||||
}
|
||||
}
|
||||
|
||||
function togglePlayer(value) {
|
||||
if (typeof value != 'boolean') {
|
||||
value = currentPlayer.classList.contains('hide');
|
||||
}
|
||||
audioPlayer.classList.add('hide');
|
||||
videoPlayer.classList.add('hide');
|
||||
imagePlayer.classList.add('hide');
|
||||
unknownPlayer.classList.add('hide');
|
||||
if (value) {
|
||||
currentPlayer.classList.remove('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function togglePanel(name) {
|
||||
if (!name) {
|
||||
name = 'main';
|
||||
}
|
||||
window.location.hash = name;
|
||||
}
|
||||
|
||||
function switchPlayer(type) {
|
||||
var oldPlayer = currentPlayer;
|
||||
if (type == 'audio') {
|
||||
currentPlayer = audioPlayer;
|
||||
} else if (type == 'video') {
|
||||
currentPlayer = videoPlayer;
|
||||
} else if (type == 'image') {
|
||||
currentPlayer = imagePlayer;
|
||||
} else if (type == 'unknown') {
|
||||
currentPlayer = unknownPlayer;
|
||||
}
|
||||
if (oldPlayer != currentPlayer && currentPlayer != imagePlayer) {
|
||||
oldPlayer.src = '';
|
||||
}
|
||||
togglePlayer(true);
|
||||
togglePanel('playerPanel');
|
||||
}
|
||||
|
||||
function playFile(evt) {
|
||||
evt.preventDefault();
|
||||
var fileType = evt.target.dataset.type;
|
||||
var avtId = avtSelector.options[avtSelector.selectedIndex].value;
|
||||
if (avtId != 'local') {
|
||||
deviceManager.play(
|
||||
avtId, evt.target.dataset.href, evt.target.dataset.res);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switchPlayer(fileType);
|
||||
|
||||
currentPlayer.hidden = false;
|
||||
currentPlayer.src = evt.target.dataset.href;
|
||||
currentPlayer.oncanplay = function() {
|
||||
this.play();
|
||||
};
|
||||
}
|
||||
|
||||
function detectTypeByMime(mimeText) {
|
||||
var type = mimeText.split('/')[0];
|
||||
var format = mimeText.split('/')[1];
|
||||
switch (type) {
|
||||
case 'audio':
|
||||
case 'video':
|
||||
case 'image':
|
||||
return type;
|
||||
case 'application':
|
||||
switch (format) {
|
||||
case 'ogg':
|
||||
return 'video';
|
||||
case 'octet-stream':
|
||||
return 'unknown';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
function wrapIntoDIDL(string) {
|
||||
string = '<DIDL-Lite xmlns:dlna="urn:schemas-dlna-org:device-1-0"' +
|
||||
' xmlns:dc="http://purl.org/dc/elements/1.1/"' +
|
||||
' xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"' +
|
||||
' xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">' +
|
||||
string +
|
||||
'</DIDL-Lite>';
|
||||
return string;
|
||||
}
|
||||
|
||||
function browseFolder(serviceId, folderId, folderElement) {
|
||||
var mediaServer = savedServices[serviceId];
|
||||
if (!mediaServer) {
|
||||
return;
|
||||
}
|
||||
|
||||
folderId = folderId || '';
|
||||
|
||||
mediaServer.browse(folderId).then(function(response) {
|
||||
if (!response || !response.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var data = response.data.Result;
|
||||
if (data.indexOf('xmlns:dlna') == -1) {
|
||||
data = data.replace('<DIDL-Lite ',
|
||||
'<DIDL-Lite xmlns:dlna="urn:schemas-dlna-org:device-1-0" ')
|
||||
.replace(/<unknown\>/g, '<unknown>');
|
||||
}
|
||||
var parser = new DOMParser();
|
||||
var serializer = new XMLSerializer();
|
||||
var xmlResponse = parser.parseFromString(data, 'application/xml');
|
||||
var lists = xmlResponse.documentElement.children;
|
||||
|
||||
var sublist = document.createElement('ul');
|
||||
sublist.className = 'sublist';
|
||||
|
||||
for (var i = 0; i < lists.length; i++) {
|
||||
var item = lists[i];
|
||||
|
||||
var titleElem = item.getElementsByTagName('title')[0] ||
|
||||
item.getElementsByTagName('dc:title')[0];
|
||||
var title;
|
||||
if (titleElem) {
|
||||
title = titleElem.textContent;
|
||||
}
|
||||
|
||||
var newElem;
|
||||
if (item.tagName == 'container') {
|
||||
newElem = document.createElement('li');
|
||||
|
||||
newElem.dataset.serviceId = serviceId;
|
||||
newElem.addEventListener('click', toggleFolder);
|
||||
newElem.dataset.href = item.getAttribute('id');
|
||||
newElem.textContent = title;
|
||||
newElem.className = 'folder';
|
||||
|
||||
sublist.appendChild(newElem);
|
||||
} else if (item.tagName == 'item') {
|
||||
var linkElem = item.getElementsByTagName('res')[0];
|
||||
var link, protocol, mime;
|
||||
if (linkElem) {
|
||||
link = linkElem.textContent;
|
||||
protocol = linkElem.getAttribute('protocolInfo');
|
||||
mime = protocol.split(':')[2];
|
||||
}
|
||||
var fileType = detectTypeByMime(mime);
|
||||
newElem = document.createElement('li');
|
||||
newElem.addEventListener('click', playFile);
|
||||
newElem.dataset.mime = mime;
|
||||
newElem.dataset.protocol = protocol;
|
||||
newElem.dataset.type = fileType;
|
||||
newElem.dataset.res = wrapIntoDIDL(item.outerHTML);
|
||||
newElem.dataset.href = link;
|
||||
newElem.textContent = title;
|
||||
newElem.className = fileType;
|
||||
sublist.appendChild(newElem);
|
||||
}
|
||||
}
|
||||
if (!folderElement) {
|
||||
folderList.appendChild(sublist);
|
||||
} else {
|
||||
folderElement.parentElement.
|
||||
insertBefore(sublist, folderElement.nextSibling);
|
||||
}
|
||||
|
||||
debugLog(serializer.serializeToString(xmlResponse), 'debug');
|
||||
});
|
||||
}
|
||||
|
||||
function removeSiblingList(elem) {
|
||||
if (elem.nextElementSibling.classList.contains('sublist')) {
|
||||
elem.parentElement.removeChild(elem.nextElementSibling);
|
||||
}
|
||||
}
|
||||
|
||||
function onServices(services) {
|
||||
services.addEventListener('servicefound', function servicefound(e) {
|
||||
for (var i = 0; i < services.length; i++) {
|
||||
if (services[i].online) {
|
||||
updateService(services[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
services.addEventListener('servicelost', function servicelost(e) {
|
||||
for (var i = 0; i < services.length; i++) {
|
||||
if (!services[i].online) {
|
||||
removeService(services[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
debugLog(services.length + ' service' +
|
||||
(services.length !== 1 ? 's' : '') +
|
||||
' found in the current network');
|
||||
|
||||
// Update services individually
|
||||
for (var j = 0; j < services.length; j++) {
|
||||
updateService(services[j]);
|
||||
}
|
||||
}
|
||||
|
||||
function removeService(service) {
|
||||
for (var savedServiceId in savedServices) {
|
||||
if (service.id === savedServiceId) {
|
||||
var serverItem = savedServices[service.id].serverItem;
|
||||
removeSiblingList(serverItem);
|
||||
serverItem.parentElement.removeChild(serverItem);
|
||||
delete savedServices[service.id];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateService(service) {
|
||||
if (!savedServices[service.id]) {
|
||||
var mediaServer =
|
||||
new Plug.UPnP_ContentDirectory(service, { debug: false });
|
||||
|
||||
savedServices[service.id] = mediaServer;
|
||||
|
||||
// Add server node
|
||||
var serverItem = document.createElement('li');
|
||||
var serverName = mediaServer.configDocument.
|
||||
getElementsByTagName('friendlyName')[0].textContent;
|
||||
serverItem.className = 'server';
|
||||
serverItem.textContent = serverName;
|
||||
serverItem.dataset.serviceId = service.id;
|
||||
folderList.appendChild(serverItem);
|
||||
|
||||
mediaServer.serverItem = serverItem;
|
||||
|
||||
browseFolder(service.id, null, serverItem);
|
||||
}
|
||||
}
|
||||
|
||||
function discover() {
|
||||
if (navigator.getNetworkServices) {
|
||||
debugLog('Searching for UPnP services in the current network...');
|
||||
navigator.getNetworkServices(
|
||||
'upnp:urn:schemas-upnp-org:service:ContentDirectory:1')
|
||||
.then(onServices, function(error) {
|
||||
debugLog('An error occurred obtaining UPnP Services [CODE: ' +
|
||||
error.code + ']');
|
||||
});
|
||||
} else {
|
||||
debugLog(
|
||||
'navigator.getNetworkServices API is not supported in this browser');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
folderList = document.getElementById('folderList');
|
||||
debugEl = document.getElementById('debug');
|
||||
audioPlayer = document.getElementById('audioPlayer');
|
||||
videoPlayer = document.getElementById('videoPlayer');
|
||||
imagePlayer = document.getElementById('imagePlayer');
|
||||
unknownPlayer = document.getElementById('unknownPlayer');
|
||||
discoverButton = document.getElementById('discoverButton');
|
||||
avtSelector = document.getElementById('AVTList');
|
||||
directoryPage = document.getElementById('toDirectoryPage');
|
||||
toPlayerPage = document.getElementById('toPlayerPage');
|
||||
debugPanel = document.getElementById('debug');
|
||||
if (!DEBUG) {
|
||||
debugPanel.style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
currentPlayer = imagePlayer;
|
||||
togglePlayer(true);
|
||||
|
||||
discoverButton.addEventListener('click', discover);
|
||||
directoryPage.addEventListener('click', togglePanel.bind(null, ''));
|
||||
toPlayerPage.addEventListener('click',
|
||||
togglePanel.bind(null, 'playerPanel'));
|
||||
|
||||
discover();
|
||||
togglePanel();
|
||||
}
|
||||
|
||||
exports.ContentDirectoryManager = {
|
||||
init: init,
|
||||
savedServices: savedServices
|
||||
};
|
||||
})(window);
|
||||
85
gaia/tv_apps/dlna-player/js/device_manager.js
Executable file
85
gaia/tv_apps/dlna-player/js/device_manager.js
Executable file
|
|
@ -0,0 +1,85 @@
|
|||
'use strict';
|
||||
/* global avtManager */
|
||||
|
||||
(function(exports) {
|
||||
function DeviceManager() {
|
||||
|
||||
}
|
||||
|
||||
DeviceManager.prototype = {
|
||||
devices: {},
|
||||
avtSelector: document.getElementById('AVTList'),
|
||||
|
||||
init: function dm_init() {
|
||||
return this;
|
||||
},
|
||||
|
||||
_popDeviceId: function dm_popDeviceId(serviceId) {
|
||||
return serviceId.split('::')[0];
|
||||
},
|
||||
|
||||
getDeviceByService: function dm_getDeviceByService(serviceId) {
|
||||
return this.devices[this._popDeviceId(serviceId)];
|
||||
},
|
||||
|
||||
getSelectedService: function dm_getCurrentService(serviceName) {
|
||||
var selected = this.avtSelector[this.avtSelector.selectedIndex].value;
|
||||
if (selected == 'local') {
|
||||
return null;
|
||||
} else {
|
||||
return this.getOtherService(selected, serviceName);
|
||||
}
|
||||
},
|
||||
|
||||
getOtherService: function dm_getOtherService(serviceId, otherServiceName) {
|
||||
var deviceId = this._popDeviceId(serviceId);
|
||||
for (var sid in this.devices[deviceId]) {
|
||||
if (sid.indexOf(otherServiceName) != -1) {
|
||||
return this.devices[deviceId][sid];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
addService: function dm_addService(serviceWrapper) {
|
||||
var deviceId = this._popDeviceId(serviceWrapper.svc.id);
|
||||
if (!this.devices[deviceId]) {
|
||||
this.devices[deviceId] = {};
|
||||
}
|
||||
this.devices[deviceId][serviceWrapper.svc.id] = serviceWrapper;
|
||||
},
|
||||
|
||||
removeService: function dm_removeService(serviceId) {
|
||||
var deviceId = this._popDeviceId(serviceId);
|
||||
if (this.devices[deviceId]) {
|
||||
return;
|
||||
}
|
||||
delete this.devices[deviceId][serviceId];
|
||||
this.removeDeviceIfEmpty(deviceId);
|
||||
},
|
||||
|
||||
removeDeviceIfEmpty: function dm_removeIfEmpty(deviceId) {
|
||||
this.removeDevice(deviceId);
|
||||
},
|
||||
|
||||
removeDevice: function dm_removeDevice(deviceId) {
|
||||
delete this.devices[deviceId];
|
||||
},
|
||||
|
||||
play: function dm_play(serviceId, mediaUrl, mediaMetadata) {
|
||||
var deviceId = this._popDeviceId(serviceId);
|
||||
var avtService = this.devices[deviceId][serviceId];
|
||||
|
||||
avtService.stop(0).then(function(e) {
|
||||
return avtService.setAVTransportURI(0, mediaUrl, mediaMetadata);
|
||||
}).then(function(e) {
|
||||
return avtService.play(0).then(function() {
|
||||
return avtManager.updateMediaInfo();
|
||||
});
|
||||
}).then(null, function(e) {
|
||||
console.log('Error:' + e.description);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.DeviceManager = DeviceManager;
|
||||
}(window));
|
||||
12
gaia/tv_apps/dlna-player/js/dlna_player.js
Executable file
12
gaia/tv_apps/dlna-player/js/dlna_player.js
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
/* globals ConnectionServiceManager, ContentDirectoryManager, AVTManager,
|
||||
DeviceManager */
|
||||
'use strict';
|
||||
|
||||
function DlnaPlayer() {
|
||||
window.connectionServiceManager = new ConnectionServiceManager().init();
|
||||
ContentDirectoryManager.init();
|
||||
window.avtManager = new AVTManager().init();
|
||||
window.deviceManager = new DeviceManager().init();
|
||||
}
|
||||
|
||||
window.dlnaPlayer = new DlnaPlayer();
|
||||
336
gaia/tv_apps/dlna-player/js/lib/plug.play/AVTransport/plug.upnp_avtransport.js
Executable file
336
gaia/tv_apps/dlna-player/js/lib/plug.play/AVTransport/plug.upnp_avtransport.js
Executable file
|
|
@ -0,0 +1,336 @@
|
|||
/* Copyright (c) 2012 Opera Software ASA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A UPnP Media Renderer API for the following service types:
|
||||
*
|
||||
* - urn:schemas-upnp-org:service:AVTransport:1
|
||||
* - urn:schemas-upnp-org:service:AVTransport:2
|
||||
*
|
||||
*/
|
||||
/* jshint ignore:start */
|
||||
!(function( global, undefined ) {
|
||||
|
||||
if( !global.Plug || !global.Plug.UPnP ) {
|
||||
console.error("plug.play.js must be loaded before you can use this library");
|
||||
return;
|
||||
}
|
||||
|
||||
var allowedUPnPTypes = {
|
||||
'urn:schemas-upnp-org:service:AVTransport:1': true,
|
||||
'urn:schemas-upnp-org:service:AVTransport:2': true
|
||||
};
|
||||
|
||||
var UPnPAVTransport = function( serviceObj, opts ) {
|
||||
|
||||
Plug.UPnP.apply( this, [ serviceObj, opts ] );
|
||||
|
||||
this.upnpType = serviceObj.type;
|
||||
if( serviceObj.type.indexOf('upnp:') === 0 ) {
|
||||
this.upnpType = this.upnpType.replace('upnp:', '');
|
||||
}
|
||||
|
||||
if( !allowedUPnPTypes[ this.upnpType ] ) {
|
||||
console.error("Provided service is not a UPnP Media Renderer Service");
|
||||
return;
|
||||
}
|
||||
|
||||
// *** AVTransport:1 methods
|
||||
|
||||
this.getDeviceCapabilities = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetDeviceCapabilities', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
PlayMedia: {
|
||||
type: this.types.string
|
||||
},
|
||||
RecMedia: {
|
||||
type: this.types.string
|
||||
},
|
||||
RecQualityModes: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getMediaInfo = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetMediaInfo', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
NrTracks: {
|
||||
type: this.types.ui4
|
||||
},
|
||||
MediaDuration: {
|
||||
type: this.types.string
|
||||
},
|
||||
CurrentURI: {
|
||||
type: this.types.string
|
||||
},
|
||||
CurrentURIMetaData: {
|
||||
type: this.types.string
|
||||
},
|
||||
NextURI: {
|
||||
type: this.types.string
|
||||
},
|
||||
NextURIMetaData: {
|
||||
type: this.types.string
|
||||
},
|
||||
PlayMedium: {
|
||||
type: this.types.string
|
||||
},
|
||||
RecordMedium: {
|
||||
type: this.types.string
|
||||
},
|
||||
WriteStatus: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getPositionInfo = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetPositionInfo', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
Track: {
|
||||
type: this.types.ui4
|
||||
},
|
||||
TrackDuration: {
|
||||
type: this.types.string
|
||||
},
|
||||
TrackMetaData: {
|
||||
type: this.types.string
|
||||
},
|
||||
TrackURI: {
|
||||
type: this.types.string
|
||||
},
|
||||
RelTime: {
|
||||
type: this.types.string
|
||||
},
|
||||
AbsTime: {
|
||||
type: this.types.string
|
||||
},
|
||||
RelCount: {
|
||||
type: this.types.i4
|
||||
},
|
||||
AbsCount: {
|
||||
type: this.types.i4
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getTransportInfo = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetTransportInfo', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentTransportState: {
|
||||
type: this.types.string
|
||||
},
|
||||
CurrentTransportStatus: {
|
||||
type: this.types.string
|
||||
},
|
||||
CurrentSpeed: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getTransportSettings = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetTransportSettings', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
PlayMode: {
|
||||
type: this.types.ui4
|
||||
},
|
||||
RecQualityMode: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setAVTransportURI = function( instanceId, currentURI, currentURIMetaData, callback ) {
|
||||
|
||||
return this.action('SetAVTransportURI', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
CurrentURI: {
|
||||
value: currentURI,
|
||||
type: this.types.string
|
||||
},
|
||||
CurrentURIMetaData: {
|
||||
value: currentURIMetaData,
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.play = function( instanceId, speed, callback ) {
|
||||
|
||||
return this.action('Play', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Speed: {
|
||||
value: speed || '1',
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.pause = function( instanceId, callback ) {
|
||||
|
||||
return this.action('Pause', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.stop = function( instanceId, callback ) {
|
||||
|
||||
return this.action('Stop', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.next = function( instanceId, callback ) {
|
||||
|
||||
return this.action('Next', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.previous = function( instanceId, callback ) {
|
||||
|
||||
return this.action('Previous', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.seek = function( instanceId, unit, target, callback ) {
|
||||
|
||||
return this.action('Seek', {
|
||||
request: {
|
||||
InstanceID: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Unit: {
|
||||
value: unit,
|
||||
type: this.types.string
|
||||
},
|
||||
Target: {
|
||||
value: target,
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
// *** AVTransport:2 methods
|
||||
|
||||
if(this.upnpType === 'urn:schemas-upnp-org:service:AVTransport:2') {
|
||||
|
||||
// TODO
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
UPnPAVTransport.prototype = Object.create( Plug.UPnP.prototype );
|
||||
|
||||
// *** GLOBAL ASSIGNMENT ***
|
||||
|
||||
global.Plug.UPnP_AVTransport = UPnPAVTransport;
|
||||
|
||||
})( this );
|
||||
10
gaia/tv_apps/dlna-player/js/lib/plug.play/CHANGELOG
Executable file
10
gaia/tv_apps/dlna-player/js/lib/plug.play/CHANGELOG
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
ConnectionManager/plug.upnp_connectionmanager.js
|
||||
- This file is changed by Rex Lee(http://github.com/rexboy7) to meet requriments of DLNA app in Gaia:
|
||||
- add prepareForConnection method
|
||||
|
||||
plug.upnp_contentdirectory.js:
|
||||
- This file is changed by Rex Lee(http://github.com/rexboy7) to meet requriments of DLNA app in Gaia.
|
||||
- maintain a configDocument property,
|
||||
stop suppressing exceptions,
|
||||
add mozSystem: true to XMLHttpRequest,
|
||||
and missellaneous.
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
/* Copyright (c) 2012 Opera Software ASA
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* CHANGE LOG
|
||||
* - This file is changed by Rex Lee(http://github.com/rexboy7) to meet
|
||||
* requriments of DLNA app in Gaia:
|
||||
* - add prepareForConnection method
|
||||
*/
|
||||
|
||||
/**
|
||||
* A UPnP API for the following service types:
|
||||
*
|
||||
* - urn:schemas-upnp-org:service:ConnectionManager:1
|
||||
* - urn:schemas-upnp-org:service:ConnectionManager:2
|
||||
* - urn:schemas-upnp-org:service:ConnectionManager:3
|
||||
*
|
||||
*/
|
||||
/* jshint ignore:start */
|
||||
!(function( global, undefined ) {
|
||||
|
||||
if( !global.Plug || !global.Plug.UPnP ) {
|
||||
console.error("plug.play.js must be loaded before you can use this library");
|
||||
return;
|
||||
}
|
||||
|
||||
var allowedUPnPTypes = {
|
||||
'urn:schemas-upnp-org:service:ConnectionManager:1': true,
|
||||
'urn:schemas-upnp-org:service:ConnectionManager:2': true,
|
||||
'urn:schemas-upnp-org:service:ConnectionManager:3': true
|
||||
};
|
||||
|
||||
var UPnPConnectionManager = function( serviceObj, opts ) {
|
||||
|
||||
Plug.UPnP.apply( this, [ serviceObj, opts ] );
|
||||
|
||||
this.upnpType = serviceObj.type;
|
||||
if( serviceObj.type.indexOf('upnp:') === 0 ) {
|
||||
this.upnpType = this.upnpType.replace('upnp:', '');
|
||||
}
|
||||
|
||||
if( !allowedUPnPTypes[ this.upnpType ] ) {
|
||||
console.error("Provided service is not a UPnP Service");
|
||||
return;
|
||||
}
|
||||
|
||||
// *** ConnectionManager:1 methods
|
||||
this.prepareForConnection =
|
||||
function(protocol, peerCM, peerCID, direction, callback) {
|
||||
return this.action('PrepareForConnection', {
|
||||
request: {
|
||||
RemoteProtocolInfo: {
|
||||
type: this.types.string,
|
||||
value: protocol
|
||||
},
|
||||
PeerConnectionManager: {
|
||||
type: this.types.string,
|
||||
value: peerCM
|
||||
},
|
||||
PeerConnectionID: {
|
||||
type: this.types.i4,
|
||||
value: peerCID
|
||||
},
|
||||
Direction: {
|
||||
type: this.types.string,
|
||||
value: direction
|
||||
}
|
||||
},
|
||||
response: {
|
||||
ConnectionIDs: {
|
||||
type: this.types.string
|
||||
},
|
||||
AVTransportID: {
|
||||
type: this.types.i4
|
||||
},
|
||||
RcsID: {
|
||||
type: this.types.i4
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
};
|
||||
|
||||
this.getCurrentConnectionIDs = function( callback ) {
|
||||
|
||||
return this.action('GetCurrentConnectionIDs', {
|
||||
request: {},
|
||||
response: {
|
||||
ConnectionIDs: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getCurrentConnectionInfo = function( connectionId, callback ) {
|
||||
|
||||
return this.action('GetCurrentConnectionInfo', {
|
||||
request: {
|
||||
ConnectionID: {
|
||||
value: connectionId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
RcsID: {
|
||||
type: this.types.i4
|
||||
},
|
||||
AVTransportID: {
|
||||
type: this.types.i4
|
||||
},
|
||||
ProtocolInfo: {
|
||||
type: this.types.string
|
||||
},
|
||||
PeerConnectionManager: {
|
||||
type: this.types.string
|
||||
},
|
||||
PeerConnectionID: {
|
||||
type: this.types.i4
|
||||
},
|
||||
Direction: {
|
||||
type: this.types.string
|
||||
},
|
||||
Status: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
};
|
||||
|
||||
this.getProtocolInfo = function( callback ) {
|
||||
|
||||
return this.action('GetProtocolInfo', {
|
||||
request: {},
|
||||
response: {
|
||||
Source: {
|
||||
type: this.types.string
|
||||
},
|
||||
Sink: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
// *** ConnectionManager:2 methods
|
||||
|
||||
if(this.upnpType === 'urn:schemas-upnp-org:service:ConnectionManager:2') {
|
||||
// TODO
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
UPnPConnectionManager.prototype = Object.create( Plug.UPnP.prototype );
|
||||
|
||||
// *** GLOBAL ASSIGNMENT ***
|
||||
|
||||
global.Plug.UPnP_ConnectionManager = UPnPConnectionManager;
|
||||
|
||||
})( this );
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
/* Copyright (c) 2012 Opera Software ASA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A UPnP Media Server API for the following service types:
|
||||
*
|
||||
* - urn:schemas-upnp-org:service:ContentDirectory:1
|
||||
* - urn:schemas-upnp-org:service:ContentDirectory:2
|
||||
* - urn:schemas-upnp-org:service:ContentDirectory:3
|
||||
* - urn:schemas-upnp-org:service:ContentDirectory:4
|
||||
*
|
||||
*/
|
||||
/* jshint ignore:start */
|
||||
!(function( global, undefined ) {
|
||||
|
||||
if( !global.Plug || !global.Plug.UPnP ) {
|
||||
console.error("plug.play.js must be loaded before you can use this library");
|
||||
return;
|
||||
}
|
||||
|
||||
var allowedUPnPTypes = {
|
||||
'urn:schemas-upnp-org:service:ContentDirectory:1': true,
|
||||
'urn:schemas-upnp-org:service:ContentDirectory:2': true,
|
||||
'urn:schemas-upnp-org:service:ContentDirectory:3': true,
|
||||
'urn:schemas-upnp-org:service:ContentDirectory:4': true
|
||||
};
|
||||
|
||||
var UPnPContentDirectory = function( serviceObj, opts ) {
|
||||
|
||||
Plug.UPnP.apply( this, [ serviceObj, opts ] );
|
||||
|
||||
this.upnpType = serviceObj.type;
|
||||
if( serviceObj.type.indexOf('upnp:') === 0 ) {
|
||||
this.upnpType = this.upnpType.replace('upnp:', '');
|
||||
}
|
||||
|
||||
if( !allowedUPnPTypes[ this.upnpType ] ) {
|
||||
console.error("Provided service is not a UPnP Media Server Service");
|
||||
return;
|
||||
}
|
||||
|
||||
var parser = new DOMParser();
|
||||
this.configDocument = parser.parseFromString(this.svc.config, 'text/xml');
|
||||
|
||||
// *** ContentDirectory:1 methods
|
||||
|
||||
this.getSystemUpdateId = function( callback ) {
|
||||
|
||||
return this.action('GetSystemUpdateID', {
|
||||
request: {},
|
||||
response: {
|
||||
Id: {
|
||||
type: this.types.ui4
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getSearchCapabilities = function( callback ) {
|
||||
|
||||
return this.action('GetSearchCapabilities', {
|
||||
request: {},
|
||||
response: {
|
||||
SearchCaps: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getSortCapabilities = function( callback ) {
|
||||
|
||||
return this.action('GetSortCapabilities', {
|
||||
request: {},
|
||||
response: {
|
||||
SortCaps: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
};
|
||||
|
||||
this.browse = function( objectId, browseFlag, filter, startingIndex, requestedCount, sortCriteria, callback ) {
|
||||
|
||||
return this.action('Browse', {
|
||||
request: {
|
||||
ObjectID: {
|
||||
value: objectId || '0',
|
||||
type: this.types.string
|
||||
},
|
||||
BrowseFlag: {
|
||||
value: browseFlag || 'BrowseDirectChildren',
|
||||
type: this.types.string
|
||||
},
|
||||
Filter: {
|
||||
value: filter || '*',
|
||||
type: this.types.string
|
||||
},
|
||||
StartingIndex: {
|
||||
value: startingIndex || '0',
|
||||
type: this.types.ui4
|
||||
},
|
||||
RequestedCount: {
|
||||
value: requestedCount || '100000',
|
||||
type: this.types.ui4
|
||||
},
|
||||
SortCriteria: {
|
||||
value: sortCriteria,
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {
|
||||
Result: {
|
||||
type: this.types.string
|
||||
},
|
||||
NumberReturned: {
|
||||
type: this.types.ui4
|
||||
},
|
||||
TotalMatches: {
|
||||
type: this.types.ui4
|
||||
},
|
||||
UpdateID: {
|
||||
type: this.types.ui4
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.search = function( objectId, browseFlag, filter, startingIndex, requestedCount, sortCriteria, callback ) {
|
||||
|
||||
return this.action('Search', {
|
||||
request: {
|
||||
ObjectID: {
|
||||
value: objectId || '0',
|
||||
type: this.types.string
|
||||
},
|
||||
BrowseFlag: {
|
||||
value: browseFlag || 'BrowseDirectChildren',
|
||||
type: this.types.string
|
||||
},
|
||||
Filter: {
|
||||
value: filter || '*',
|
||||
type: this.types.string
|
||||
},
|
||||
StartingIndex: {
|
||||
value: startingIndex || '0',
|
||||
type: this.types.ui4
|
||||
},
|
||||
RequestedCount: {
|
||||
value: requestedCount || '100000',
|
||||
type: this.types.ui4
|
||||
},
|
||||
SortCriteria: {
|
||||
value: sortCriteria,
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {
|
||||
Result: {
|
||||
type: this.types.string
|
||||
},
|
||||
NumberReturned: {
|
||||
type: this.types.ui4
|
||||
},
|
||||
TotalMatches: {
|
||||
type: this.types.ui4
|
||||
},
|
||||
UpdateID: {
|
||||
type: this.types.ui4
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// *** ContentDirectory:2 methods
|
||||
|
||||
if(this.upnpType === 'urn:schemas-upnp-org:service:ContentDirectory:2') {
|
||||
|
||||
// TODO: GetFeatureList, GetSortExtensionCapabilities, MoveObject
|
||||
}
|
||||
|
||||
|
||||
// *** ContentDirectory:3 methods
|
||||
|
||||
if(this.upnpType === 'urn:schemas-upnp-org:service:ContentDirectory:3') {
|
||||
|
||||
// TODO
|
||||
|
||||
}
|
||||
|
||||
// *** ContentDirectory:4 methods
|
||||
|
||||
if(this.upnpType === 'urn:schemas-upnp-org:service:ContentDirectory:4') {
|
||||
|
||||
// TODO
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
UPnPContentDirectory.prototype = Object.create( Plug.UPnP.prototype );
|
||||
|
||||
// *** GLOBAL ASSIGNMENT ***
|
||||
|
||||
global.Plug.UPnP_ContentDirectory = UPnPContentDirectory;
|
||||
|
||||
})( this );
|
||||
|
|
@ -0,0 +1,903 @@
|
|||
/* Copyright (c) 2012 Opera Software ASA
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A UPnP Media Renderer API for the following service types:
|
||||
*
|
||||
* - urn:schemas-upnp-org:service:RenderingControl:1
|
||||
* - urn:schemas-upnp-org:service:RenderingControl:2
|
||||
* - urn:schemas-upnp-org:service:RenderingControl:3
|
||||
*
|
||||
*/
|
||||
/* jshint ignore:start */
|
||||
!(function( global, undefined ) {
|
||||
|
||||
if( !global.Plug || !global.Plug.UPnP ) {
|
||||
console.error("plug.play.js must be loaded before you can use this library");
|
||||
return;
|
||||
}
|
||||
|
||||
var allowedUPnPTypes = {
|
||||
'urn:schemas-upnp-org:service:RenderingControl:1': true,
|
||||
'urn:schemas-upnp-org:service:RenderingControl:2': true,
|
||||
'urn:schemas-upnp-org:service:RenderingControl:3': true
|
||||
};
|
||||
|
||||
var UPnPRenderingControl = function( serviceObj, opts ) {
|
||||
|
||||
Plug.UPnP.apply( this, [ serviceObj, opts ] );
|
||||
|
||||
this.upnpType = serviceObj.type;
|
||||
if( serviceObj.type.indexOf('upnp:') === 0 ) {
|
||||
this.upnpType = this.upnpType.replace('upnp:', '');
|
||||
}
|
||||
|
||||
if( !allowedUPnPTypes[ this.upnpType ] ) {
|
||||
console.error("Provided service is not a UPnP Media Renderer Service");
|
||||
return;
|
||||
}
|
||||
|
||||
// *** RenderingControl:1 methods
|
||||
|
||||
this.listPresets = function( instanceId, callback ) {
|
||||
|
||||
return this.action('ListPresets', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentPresetNameList: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.selectPreset = function( instanceId, presetName, callback ) {
|
||||
|
||||
return this.action('SelectPreset', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
PresetName: {
|
||||
value: presetName || "FactoryDefaults",
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getBrightness = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetBrightness', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentBrightness: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setBrightness = function( instanceId, desiredBrightness, callback ) {
|
||||
|
||||
return this.action('SetBrightness', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredBrightness: {
|
||||
value: desiredBrightness,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getContrast = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetContrast', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentContrast: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setContrast = function( instanceId, desiredContrast, callback ) {
|
||||
|
||||
return this.action('SetContrast', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredContrast: {
|
||||
value: desiredContrast,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getSharpness = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetSharpness', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentSharpness: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setSharpness = function( instanceId, desiredSharpness, callback ) {
|
||||
|
||||
return this.action('SetSharpness', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredSharpness: {
|
||||
value: desiredSharpness,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getRedVideoGain = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetRedVideoGain', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentRedVideoGain: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setRedVideoGain = function( instanceId, desiredRedVideoGain, callback ) {
|
||||
|
||||
return this.action('SetRedVideoGain', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredRedVideoGain: {
|
||||
value: desiredRedVideoGain,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getGreenVideoGain = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetGreenVideoGain', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentGreenVideoGain: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setGreenVideoGain = function( instanceId, desiredGreenVideoGain, callback ) {
|
||||
|
||||
return this.action('SetGreenVideoGain', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredGreenVideoGain: {
|
||||
value: desiredGreenVideoGain,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getBlueVideoGain = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetBlueVideoGain', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentBlueVideoGain: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setBlueVideoGain = function( instanceId, desiredBlueVideoGain, callback ) {
|
||||
|
||||
return this.action('SetBlueVideoGain', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredBlueVideoGain: {
|
||||
value: desiredBlueVideoGain,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getRedVideoBlackLevel = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetRedVideoBlackLevel', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentRedVideoBlackLevel: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setRedVideoBlackLevel = function( instanceId, desiredRedVideoBlackLevel, callback ) {
|
||||
|
||||
return this.action('SetRedVideoBlackLevel', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredRedVideoBlackLevel: {
|
||||
value: desiredRedVideoBlackLevel,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getGreenVideoBlackLevel = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetGreenVideoBlackLevel', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentGreenVideoBlackLevel: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setGreenVideoBlackLevel = function( instanceId, desiredGreenVideoBlackLevel, callback ) {
|
||||
|
||||
return this.action('SetGreenVideoBlackLevel', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredGreenVideoBlackLevel: {
|
||||
value: desiredGreenVideoBlackLevel,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getBlueVideoBlackLevel = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetBlueVideoBlackLevel', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentBlueVideoBlackLevel: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setBlueVideoBlackLevel = function( instanceId, desiredBlueVideoBlackLevel, callback ) {
|
||||
|
||||
return this.action('SetBlueVideoBlackLevel', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredBlueVideoBlackLevel: {
|
||||
value: desiredBlueVideoBlackLevel,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getBlueVideoBlackLevel = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetBlueVideoBlackLevel', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentBlueVideoBlackLevel: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getColorTemperature = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetColorTemperature', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentColorTemperature: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setColorTemperature = function( instanceId, desiredColorTemperature, callback ) {
|
||||
|
||||
return this.action('SetColorTemperature', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredColorTemperature: {
|
||||
value: desiredColorTemperature,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getHorizontalKeystone = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetHorizontalKeystone', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentHorizontalKeystone: {
|
||||
type: this.types.i2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setHorizontalKeystone = function( instanceId, desiredHorizontalKeystone, callback ) {
|
||||
|
||||
return this.action('SetHorizontalKeystone', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredHorizontalKeystone: {
|
||||
value: desiredHorizontalKeystone,
|
||||
type: this.types.i2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getVerticalKeystone = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetVerticalKeystone', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentVerticalKeystone: {
|
||||
type: this.types.i2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setVerticalKeystone = function( instanceId, desiredVerticalKeystone, callback ) {
|
||||
|
||||
return this.action('SetVerticalKeystone', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredVerticalKeystone: {
|
||||
value: desiredVerticalKeystone,
|
||||
type: this.types.i2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getMute = function( instanceId, channel, callback ) {
|
||||
|
||||
return this.action('GetMute', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Channel: {
|
||||
value: channel || 'Master',
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentMute: {
|
||||
type: this.types.boolean
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setMute = function( instanceId, channel, desiredMute, callback ) {
|
||||
|
||||
return this.action('SetMute', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Channel: {
|
||||
value: channel || 'Master',
|
||||
type: this.types.string
|
||||
},
|
||||
DesiredMute: {
|
||||
value: desiredMute,
|
||||
type: this.types.boolean
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getVolume = function( instanceId, channel, callback ) {
|
||||
|
||||
return this.action('GetVolume', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Channel: {
|
||||
value: channel || 'Master',
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentVolume: {
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setVolume = function( instanceId, channel, desiredVolume, callback ) {
|
||||
|
||||
return this.action('SetVolume', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Channel: {
|
||||
value: channel || 'Master',
|
||||
type: this.types.string
|
||||
},
|
||||
DesiredVolume: {
|
||||
value: desiredVolume,
|
||||
type: this.types.ui2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getVolumeDB = function( instanceId, channel, callback ) {
|
||||
|
||||
return this.action('GetVolumeDB', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Channel: {
|
||||
value: channel || 'Master',
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentVolume: {
|
||||
type: this.types.i2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setVolumeDB = function( instanceId, channel, desiredVolume, callback ) {
|
||||
|
||||
return this.action('SetVolumeDB', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Channel: {
|
||||
value: channel || 'Master',
|
||||
type: this.types.string
|
||||
},
|
||||
DesiredVolume: {
|
||||
value: desiredVolume,
|
||||
type: this.types.i2
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getVolumeDBRange = function( instanceId, channel, callback ) {
|
||||
|
||||
return this.action('GetVolumeDBRange', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Channel: {
|
||||
value: channel || 'Master',
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {
|
||||
MinValue: {
|
||||
type: this.types.i2
|
||||
},
|
||||
MaxValue: {
|
||||
type: this.types.i2
|
||||
},
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getLoudness = function( instanceId, channel, callback ) {
|
||||
|
||||
return this.action('GetLoudness', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Channel: {
|
||||
value: channel || 'Master',
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentLoudness: {
|
||||
type: this.types.boolean
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setLoudness = function( instanceId, channel, desiredLoudness, callback ) {
|
||||
|
||||
return this.action('SetLoudness', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
Channel: {
|
||||
value: channel || 'Master',
|
||||
type: this.types.string
|
||||
},
|
||||
DesiredLoudness: {
|
||||
value: desiredLoudness,
|
||||
type: this.types.boolean
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
// *** RenderingControl:2 methods
|
||||
|
||||
if(this.upnpType === 'urn:schemas-upnp-org:service:RenderingControl:2' ||
|
||||
this.upnpType === 'urn:schemas-upnp-org:service:RenderingControl:3') {
|
||||
|
||||
this.getStateVariables = function( instanceId, stateVariableList, callback ) {
|
||||
|
||||
return this.action('GetStateVariables', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
StateVariableList: {
|
||||
value: stateVariableList,
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {
|
||||
StateVariableValuePairs: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setStateVariables = function( instanceId, renderingControlUDN, serviceType, serviceId, stateVariableValuePairs, callback ) {
|
||||
|
||||
return this.action('SetStateVariables', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
RenderingControlUDN: {
|
||||
value: renderingControlUDN,
|
||||
type: this.types.string
|
||||
},
|
||||
ServiceType: {
|
||||
value: serviceType,
|
||||
type: this.types.string
|
||||
},
|
||||
ServiceId: {
|
||||
value: serviceId,
|
||||
type: this.types.string
|
||||
},
|
||||
StateVariableValuePairs: {
|
||||
value: stateVariableValuePairs,
|
||||
type: this.types.string
|
||||
}
|
||||
},
|
||||
response: {
|
||||
StateVariableList: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// *** RenderingControl:3 methods
|
||||
|
||||
if(this.upnpType === 'urn:schemas-upnp-org:service:RenderingControl:3') {
|
||||
|
||||
this.getAllowedTransforms = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetAllowedTransforms', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentAllowedTransformSettings: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getTransforms = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetTransforms', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
}
|
||||
},
|
||||
response: {
|
||||
CurrentTransformValues: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setTransforms = function( instanceId, desiredTransformValues, callback ) {
|
||||
|
||||
return this.action('SetTransforms', {
|
||||
request: {
|
||||
InstanceId: {
|
||||
value: instanceId,
|
||||
type: this.types.ui4
|
||||
},
|
||||
DesiredTransformValues: {
|
||||
value: desiredTransformValues,
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getAllAvailableTransforms = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetAllAvailableTransforms', {
|
||||
response: {
|
||||
AllAllowedTransformSettings: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getAllowedDefaultTransforms = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetAllowedDefaultTransforms', {
|
||||
response: {
|
||||
AllowedDefaultTransformSettings: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.getDefaultTransforms = function( instanceId, callback ) {
|
||||
|
||||
return this.action('GetDefaultTransforms', {
|
||||
response: {
|
||||
CurrentDefaultTransformSettings: {
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
this.setDefaultTransforms = function( instanceId, desiredDefaultTransformSettings, callback ) {
|
||||
|
||||
return this.action('SetDefaultTransforms', {
|
||||
request: {
|
||||
DesiredDefaultTransformSettings: {
|
||||
value: desiredDefaultTransformSettings,
|
||||
type: this.types.string
|
||||
}
|
||||
}
|
||||
}, callback);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
UPnPRenderingControl.prototype = Object.create( Plug.UPnP.prototype );
|
||||
|
||||
// *** GLOBAL ASSIGNMENT ***
|
||||
|
||||
global.Plug.UPnP_RenderingControl = UPnPRenderingControl;
|
||||
|
||||
})( this );
|
||||
1056
gaia/tv_apps/dlna-player/js/lib/plug.play/plug.upnp.js
Executable file
1056
gaia/tv_apps/dlna-player/js/lib/plug.play/plug.upnp.js
Executable file
File diff suppressed because it is too large
Load diff
521
gaia/tv_apps/dlna-player/js/lib/ssdp/ssdp.js
Executable file
521
gaia/tv_apps/dlna-player/js/lib/ssdp/ssdp.js
Executable file
|
|
@ -0,0 +1,521 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* jshint ignore:start */
|
||||
(function(global) {
|
||||
// Spec information:
|
||||
// http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
|
||||
|
||||
const SSDP_PORT = 1900;
|
||||
const SSDP_ADDRESS = "239.255.255.250";
|
||||
const SSDP_DISCOVER_MX = 2;
|
||||
|
||||
const SSDP_DISCOVER_PACKET =
|
||||
"M-SEARCH * HTTP/1.1\r\n" +
|
||||
"HOST: " + SSDP_ADDRESS + ":" + SSDP_PORT + "\r\n" +
|
||||
"MAN: \"ssdp:discover\"\r\n" +
|
||||
"MX: " + SSDP_DISCOVER_MX + "\r\n" +
|
||||
"ST: %SEARCH_TARGET%\r\n\r\n";
|
||||
|
||||
const SSDP_RESPONSE_HEADER = /HTTP\/\d{1}\.\d{1} \d+ .*/;
|
||||
const SSDP_HEADER = /^([^:]+):\s*(.*)$/;
|
||||
|
||||
var SimpleServiceDiscovery = {
|
||||
_targets: [],
|
||||
_commands: {},
|
||||
_searching: false,
|
||||
search: function _search(aInterval) {
|
||||
aInterval = aInterval || 0;
|
||||
if (aInterval > 0) {
|
||||
this._searchRepeat = setInterval(this._search.bind(this), aInterval);
|
||||
}
|
||||
this._search();
|
||||
},
|
||||
stopSearch: function _stopSearch() {
|
||||
if (this._searchRepeat) {
|
||||
clearInterval(this._searchRepeat);
|
||||
}
|
||||
},
|
||||
registerTarget: function _registerTarget(target) {
|
||||
if (this._targets.indexOf(target) < 0) {
|
||||
this._targets.push(target);
|
||||
}
|
||||
},
|
||||
|
||||
// internal function
|
||||
_search: function _search() {
|
||||
// create socket if not exist
|
||||
if (!this._searchSocket) {
|
||||
this._searchSocket = new UDPSocket({loopback: true, localPort: SSDP_PORT});
|
||||
this._searchSocket.joinMulticastGroup(SSDP_ADDRESS);
|
||||
this._searchSocket.onmessage = this._onmessage.bind(this);
|
||||
window.addEventListener('beforeunload', function(evt) {
|
||||
this._searchSocket.close();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
this._searchSocket.opened.then((function() {
|
||||
// Perform a UDP broadcast to search for SSDP devices
|
||||
this._searchTimeout = setTimeout(this._searchShutdown.bind(this), SSDP_DISCOVER_MX * 1000);
|
||||
this._searching = true;
|
||||
|
||||
var data = SSDP_DISCOVER_PACKET;
|
||||
this._targets.forEach((function(target) {
|
||||
var msgData = data.replace("%SEARCH_TARGET%", target);
|
||||
var ok = this._searchSocket.send(msgData, SSDP_ADDRESS, SSDP_PORT);
|
||||
}).bind(this));
|
||||
}).bind(this)).catch(function(evt) {
|
||||
});
|
||||
},
|
||||
_searchShutdown: function _searchShutdown() {
|
||||
this._searching = false;
|
||||
},
|
||||
_onmessage: function _onmessage(e) {
|
||||
// Listen for responses from specific targets. There could be more than
|
||||
// one available.
|
||||
|
||||
var msg = String.fromCharCode.apply(null, new Uint8Array(e.data));
|
||||
var lines = msg.toString().split("\r\n");
|
||||
var firstLine = lines.shift();
|
||||
var method = SSDP_RESPONSE_HEADER.test(firstLine) ? 'RESPONSE'
|
||||
: firstLine.split(' ')[0].toUpperCase();
|
||||
var headers = {};
|
||||
lines.forEach(function (line) {
|
||||
if (line.length) {
|
||||
var pairs = line.match(/^([^:]+):\s*(.*)$/);
|
||||
if (pairs) {
|
||||
headers[pairs[1].toLowerCase()] = pairs[2];
|
||||
}
|
||||
}
|
||||
});
|
||||
if (this._commands[method]) {
|
||||
this._commands[method].apply(this, [headers]);
|
||||
}
|
||||
},
|
||||
_found: function _found(aService) {
|
||||
// Use the REST api to request more information about this service
|
||||
var xhr = new XMLHttpRequest({mozSystem: true});
|
||||
xhr.open("GET", aService.location, true);
|
||||
xhr.overrideMimeType("text/xml");
|
||||
|
||||
xhr.addEventListener("load", (function() {
|
||||
if (xhr.status == 200) {
|
||||
// walk through root device and all the embedded devices
|
||||
var devices = xhr.responseXML.querySelectorAll('device');
|
||||
for (var i = 0; i < devices.length; i++) {
|
||||
this._parseDescriptor(devices[i], aService.location);
|
||||
}
|
||||
}
|
||||
}).bind(this), false);
|
||||
|
||||
xhr.send(null);
|
||||
},
|
||||
_parseDescriptor: function _parseDescriptor(device, refUrl) {
|
||||
var udn = device.querySelector("UDN").innerHTML;
|
||||
|
||||
var serviceList = device.querySelector('serviceList').querySelectorAll('service');
|
||||
for (var i = 0; i < serviceList.length; i++) {
|
||||
var service = serviceList[i];
|
||||
var serviceType = service.querySelector('serviceType').innerHTML;
|
||||
var eventsUrl = this._getAbsoluteURL(service.querySelector('eventSubURL'), refUrl);
|
||||
var options = {};
|
||||
options.id = udn + '::' + serviceType;
|
||||
options.deviceId = udn;
|
||||
options.name = service.querySelector('serviceId').innerHTML;
|
||||
options.type = 'upnp:' + serviceType;
|
||||
options.url = this._getAbsoluteURL(service.querySelector('controlURL').innerHTML, refUrl);
|
||||
options.config = device.outerHTML;
|
||||
if (eventsUrl) {
|
||||
options.eventsUrl = eventsUrl.innerHTML;
|
||||
}
|
||||
options.expiryTimestamp = ''; //TODO
|
||||
serviceHelper.add(new SSDPServiceRecord(options));
|
||||
}
|
||||
},
|
||||
_getAbsoluteURL: function _getAbsoluteURL(url, refUrl) {
|
||||
if (/^https?:\/\//.test(url)) {
|
||||
return url;
|
||||
} else {
|
||||
var absURL = new URL(url, refUrl);
|
||||
return absURL.toString();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SimpleServiceDiscovery._commands['RESPONSE'] = function _response(headers) {
|
||||
if (this._searching && headers.location && this._targets.indexOf(headers.st) >= 0) {
|
||||
this._found(headers);
|
||||
}
|
||||
};
|
||||
SimpleServiceDiscovery._commands['NOTIFY'] = function _notify(headers) {
|
||||
switch(headers.nts) {
|
||||
case 'ssdp:alive':
|
||||
var old_searching = this._searching;
|
||||
this._searching = true;
|
||||
headers['st'] = headers.nt;
|
||||
this._commands['RESPONSE'].apply(this, [headers]);
|
||||
this._searching = old_searching;
|
||||
break;
|
||||
case 'ssdp:byebye':
|
||||
serviceHelper.remove(new SSDPServiceRecord({id: headers.usn}));
|
||||
break;
|
||||
}
|
||||
};
|
||||
SimpleServiceDiscovery._commands['M-SEARCH'] = function _msearch(headers) {
|
||||
};
|
||||
|
||||
function SSDPServiceRecord(options) {
|
||||
this.update(options);
|
||||
}
|
||||
|
||||
SSDPServiceRecord.prototype = {
|
||||
id: '',
|
||||
deviceId: '',
|
||||
name: '',
|
||||
type: '',
|
||||
url: '',
|
||||
eventsUrl: '',
|
||||
config: '',
|
||||
expiryTimestamp: '',
|
||||
update: function(options) {
|
||||
var self = this;
|
||||
['id', 'deviceId', 'name', 'type', 'url', 'config', 'expiryTimestamp'].forEach(function(option) {
|
||||
self[option] = options[option];
|
||||
});
|
||||
|
||||
if (options.eventsUrl) {
|
||||
this.eventsUrl = options.eventsUrl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// polyfill Network Service Discovery API
|
||||
function NetworkService(record) {
|
||||
this._record = record;
|
||||
//XXX need weak reference
|
||||
this._callbacks = { 'available': [], 'unavailable': [], 'notify': [] };
|
||||
}
|
||||
|
||||
NetworkService.prototype = {
|
||||
online: true,
|
||||
get id() { return this._record.id; },
|
||||
get name() { return this._record.name; },
|
||||
get type() { return this._record.type; },
|
||||
get url() { return this._record.url; },
|
||||
get config() { return this._record.config; },
|
||||
|
||||
set onavailable(callback) {
|
||||
this.addEventListener('available', callback);
|
||||
},
|
||||
|
||||
set onunavailable(callback) {
|
||||
this.addEventListener('unavailable', callback);
|
||||
},
|
||||
|
||||
set onnotify(callback) {
|
||||
this.addEventListener('notify', callback);
|
||||
},
|
||||
|
||||
// EventTarget
|
||||
addEventListener: function(type, callback, capture) {
|
||||
if (!this._callbacks.hasOwnProperty(type)) {
|
||||
return;
|
||||
}
|
||||
this._callbacks[type].push(callback);
|
||||
},
|
||||
removeEventListener: function(type, callback, capture) {
|
||||
if (!this._callbacks.hasOwnProperty(type)) {
|
||||
return;
|
||||
}
|
||||
var callbacks = this._callbacks[type];
|
||||
|
||||
var index = callbacks.indexOf(callback);
|
||||
if (index >= 0) {
|
||||
callbacks.splice(index, 1);
|
||||
}
|
||||
},
|
||||
dispatchEvent: function(event) {
|
||||
if (this._callbacks.hasOwnProperty(event.type)) {
|
||||
var callbacks = this._callbacks[event.type];
|
||||
if (!event.detail || !event.detail.target) {
|
||||
event.detail = { target: this };
|
||||
}
|
||||
for (var i = 0; i < callbacks.length; i++) {
|
||||
callbacks[i](event);
|
||||
}
|
||||
}
|
||||
return event.cancelable === false || event.defaultPrevented === false;
|
||||
},
|
||||
};
|
||||
|
||||
function NetworkServices(types, services) {
|
||||
this._services = services || [];
|
||||
this._types = types || [];
|
||||
for (var i = 0; i < services.length; i++) {
|
||||
this[i] = services[i];
|
||||
}
|
||||
//XXX need weak reference
|
||||
this._callbacks = { 'servicefound': [], 'servicelost': [] };
|
||||
}
|
||||
|
||||
NetworkServices.prototype = {
|
||||
_append: function(service) {
|
||||
var i = this._services.length;
|
||||
this[i] = service;
|
||||
this._services.push(service);
|
||||
},
|
||||
|
||||
servicesAvailable: 0,
|
||||
|
||||
get length() {
|
||||
return this._services.length;
|
||||
},
|
||||
|
||||
getServiceById: function(id) {
|
||||
for (var i = 0; i < this._services.length; i++) {
|
||||
if (this._services[i].id === id) {
|
||||
return this._services[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
set onservicefound(callback) {
|
||||
this.addEventListener('servicefound', callback);
|
||||
},
|
||||
|
||||
set onservicelost(callback) {
|
||||
this.addEventListener('servicelost', callback);
|
||||
},
|
||||
|
||||
// EventTarget
|
||||
addEventListener: function(type, callback) {
|
||||
if (!this._callbacks.hasOwnProperty(type)) {
|
||||
return;
|
||||
}
|
||||
this._callbacks[type].push(callback);
|
||||
},
|
||||
removeEventListener: function(type, callback, capture) {
|
||||
if (!this._callbacks.hasOwnProperty(type)) {
|
||||
return;
|
||||
}
|
||||
var callbacks = this._callbacks[type];
|
||||
|
||||
var index = callbacks.indexOf(callback);
|
||||
if (index >= 0) {
|
||||
callbacks.splice(index, 1);
|
||||
}
|
||||
},
|
||||
dispatchEvent: function(event) {
|
||||
if (this._callbacks.hasOwnProperty(event.type)) {
|
||||
var callbacks = this._callbacks[event.type];
|
||||
if (!event.detail || !event.detail.target) {
|
||||
event.detail = {target: this};
|
||||
}
|
||||
for (var i = 0; i < callbacks.length; i++) {
|
||||
callbacks[i](event);
|
||||
}
|
||||
}
|
||||
return event.cancelable === false || event.defaultPrevented === false;
|
||||
},
|
||||
};
|
||||
|
||||
function _hasRequestedType(service, types) {
|
||||
return types.some(function(type) {
|
||||
return type === service.type;
|
||||
});
|
||||
}
|
||||
|
||||
var serviceHelper = (function() {
|
||||
return {
|
||||
add: function(record) {
|
||||
// try update existing service
|
||||
var index = availableServiceRecords.findIndex(function(activeService) {
|
||||
return activeService.id === record.id;
|
||||
});
|
||||
|
||||
if (index >= 0) {
|
||||
availableServiceRecords[index].update(record);
|
||||
return;
|
||||
}
|
||||
|
||||
// new service available
|
||||
availableServiceRecords.push(record);
|
||||
|
||||
activeServiceManagers.forEach(function(manager) {
|
||||
// wiring to existed NetworkService objects
|
||||
var index = manager._services.findIndex(function(service) {
|
||||
return service.id === record.id;
|
||||
});
|
||||
if (index >= 0 && manager._services[index].online === false) {
|
||||
var service = manager._services[index];
|
||||
service._record = record;
|
||||
service.online = true;
|
||||
setTimeout(function() {
|
||||
service.dispatchEvent(new CustomEvent('available',
|
||||
{ bubbles: false,
|
||||
cancelable: false,
|
||||
detail: {target: service},
|
||||
}));
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// notify correspoding service managers
|
||||
if (_hasRequestedType(record, manager._types)) {
|
||||
// XXX should we append new service to existing manager?
|
||||
if (index < 0) {
|
||||
var netService = new NetworkService(record);
|
||||
manager._append(netService);
|
||||
}
|
||||
manager.servicesAvailable++;
|
||||
setTimeout(function() {
|
||||
manager.dispatchEvent(new CustomEvent('servicefound',
|
||||
{ bubbles: false,
|
||||
cancelable: false,
|
||||
detail: {target: manager},
|
||||
}));
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
remove: function(record) {
|
||||
var index = availableServiceRecords.findIndex(function(activeService) {
|
||||
return activeService.id === record.id;
|
||||
});
|
||||
|
||||
if (index >= 0) {
|
||||
var activeService = availableServiceRecords[index];
|
||||
|
||||
activeServiceManagers.forEach(function(manager) {
|
||||
var index = manager._services.findIndex(function(service) {
|
||||
return service.id === record.id;
|
||||
});
|
||||
if (index >= 0 && manager._services[index].online === true) {
|
||||
// notify service unavailable
|
||||
var service = manager._services[index];
|
||||
service.online = false;
|
||||
setTimeout(function() {
|
||||
service.dispatchEvent(new CustomEvent('unavailable',
|
||||
{ bubbles: false,
|
||||
cancelable: false,
|
||||
detail: {target: service},
|
||||
}));
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// notify service lost
|
||||
if (_hasRequestedType(activeService, manager._types)) {
|
||||
manager.servicesAvailable--;
|
||||
setTimeout(function() {
|
||||
manager.dispatchEvent(new CustomEvent('servicelost',
|
||||
{ bubbles: false,
|
||||
cancelable: false,
|
||||
detail: {target: manager},
|
||||
}));
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
// XXX unregister UPnP event
|
||||
if (activeService.eventsUrl) {
|
||||
console.log('unregister event for ' + activeService.eventsUrl);
|
||||
}
|
||||
|
||||
// remove from available service list
|
||||
availableServiceRecords.splice(index, 1);
|
||||
}
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
var availableServiceRecords = []; // list of NetworkService
|
||||
var activeServiceManagers = []; // list of NetworkServices //XXX need weak reference
|
||||
var targetRegister = {
|
||||
'upnp:': {
|
||||
register: function(target) {
|
||||
SimpleServiceDiscovery.registerTarget(target.substr(5)); // remove upnp: prefix
|
||||
},
|
||||
search: function() {
|
||||
SimpleServiceDiscovery.search();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function getNetworkServices(type) {
|
||||
const UNKNOWN_TYPE_PREFIX_ERR = 'UnknownTypePrefixError';
|
||||
const PERMISSION_DENIED_ERR = 'PermissionDeniedError';
|
||||
|
||||
function _isValidServiceType (type) {
|
||||
return type && Object.keys(targetRegister).some(function(prefix) { return type.startsWith(prefix); });
|
||||
}
|
||||
|
||||
function _register(types) {
|
||||
var needSearch = {};
|
||||
types.forEach(function(type) {
|
||||
var found = Object.keys(targetRegister).find(function(prefix) { return type.startsWith(prefix); });
|
||||
if (found) {
|
||||
targetRegister[found].register(type);
|
||||
if (!needSearch.hasOwnProperty(found)) {
|
||||
needSearch[found] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
// trigger search on the discovery service if new search target
|
||||
// is registered
|
||||
Object.keys(needSearch).forEach(function(type) {
|
||||
targetRegister[type].search();
|
||||
});
|
||||
}
|
||||
|
||||
var requestedControlTypes = [].concat(type).filter(_isValidServiceType);
|
||||
|
||||
if (requestedControlTypes.length === 0) {
|
||||
return Promise.reject(new DOMError(UNKNOWN_TYPE_PREFIX_ERR));
|
||||
}
|
||||
|
||||
_register(requestedControlTypes);
|
||||
|
||||
var allPromises = [];
|
||||
availableServiceRecords.forEach(function(service) {
|
||||
if (_hasRequestedType(service, requestedControlTypes)) {
|
||||
// XXX doesn't check CORS yet
|
||||
// create a new instance of NetworkService
|
||||
allPromises.push(Promise.resolve(new NetworkService(service)));
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.all(allPromises).then(function(servicesFound) {
|
||||
var services = servicesFound.filter(function(service) {
|
||||
//XXX might also filter by user preference
|
||||
return service !== null;
|
||||
});
|
||||
|
||||
for (var i = 0; i < services.length; i++) {
|
||||
if (services[i]._record.eventsUrl) {
|
||||
//XXX perform UPnP event subscription
|
||||
console.log('register for ' + services[i]._record.eventsUrl);
|
||||
}
|
||||
}
|
||||
|
||||
var serviceManager = new NetworkServices(requestedControlTypes, services);
|
||||
serviceManager.servicesAvailable = availableServiceRecords.reduce(function(count, service) {
|
||||
return (_hasRequestedType(service, requestedControlTypes)) ? count + 1 : count;
|
||||
}, 0);
|
||||
activeServiceManagers.push(serviceManager);
|
||||
|
||||
return Promise.resolve(serviceManager);
|
||||
});
|
||||
}
|
||||
|
||||
// export NetworkServices and NetworkServices as pre-defined types
|
||||
global.NetworkService = NetworkService;
|
||||
global.NetworkServices = NetworkServices;
|
||||
navigator.getNetworkServices = getNetworkServices;
|
||||
|
||||
global.addEventListener('unload', function() {
|
||||
delete navigator.getNetworkServices;
|
||||
});
|
||||
})(window);
|
||||
145
gaia/tv_apps/dlna-player/js/service_manager.js
Executable file
145
gaia/tv_apps/dlna-player/js/service_manager.js
Executable file
|
|
@ -0,0 +1,145 @@
|
|||
/* globals Plug, deviceManager */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
var DEBUG = false;
|
||||
function ServiceManager() {
|
||||
|
||||
}
|
||||
|
||||
ServiceManager.prototype = {
|
||||
listElementId: 'elementList',
|
||||
serviceName: 'ConnectionManager',
|
||||
serviceType: 'upnp:urn:schemas-upnp-org:service:ConnectionManager:1',
|
||||
serviceConstructor: Plug.UPnP_ContentDirectory,
|
||||
savedServices: {},
|
||||
|
||||
init: function sm_init() {
|
||||
this.debugEl = document.getElementById('debug');
|
||||
this.listElement = document.getElementById(this.listElementId);
|
||||
this.discover();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
debugLog: function sm_debugLog(msg, level) {
|
||||
if (!DEBUG && level == 'debug') {
|
||||
return;
|
||||
}
|
||||
var logEl = document.createElement('div');
|
||||
logEl.textContent = msg;
|
||||
this.debugEl.appendChild(logEl);
|
||||
},
|
||||
|
||||
appendMixinProperties: function sm_appendConfigDocument(serviceWrapper) {
|
||||
var parser = new DOMParser();
|
||||
serviceWrapper.configDocument =
|
||||
parser.parseFromString(serviceWrapper.svc.config, 'text/xml');
|
||||
serviceWrapper.friendlyName = serviceWrapper.configDocument.
|
||||
getElementsByTagName('friendlyName')[0].textContent;
|
||||
},
|
||||
|
||||
updateService: function sm_updateService(service) {
|
||||
if (!this.savedServices[service.id]) {
|
||||
var mediaServer =
|
||||
new this.serviceConstructor(service, { debug: false });
|
||||
this.appendMixinProperties(mediaServer);
|
||||
this.savedServices[service.id] = mediaServer;
|
||||
deviceManager.addService(mediaServer);
|
||||
|
||||
var serverItem = this.serverView(mediaServer);
|
||||
this.listElement.appendChild(serverItem);
|
||||
mediaServer.serverItem = serverItem;
|
||||
}
|
||||
},
|
||||
|
||||
removeService: function sm_removeService(service) {
|
||||
for(var id in this.savedServices) {
|
||||
if (service.id === id) {
|
||||
var serverItem = this.savedServices[service.id].serverItem;
|
||||
this.removeSiblingList(serverItem);
|
||||
serverItem.parentElement.removeChild(serverItem);
|
||||
delete this.savedServices[service.id];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
serverView: function sm_serverView(serviceWrapper) {
|
||||
// Add server node
|
||||
var serverItem = document.createElement('li');
|
||||
var serverName = serviceWrapper.friendlyName;
|
||||
serverItem.className = 'server';
|
||||
serverItem.textContent = serverName;
|
||||
serverItem.dataset.serviceId = serviceWrapper.svc.id;
|
||||
return serverItem;
|
||||
},
|
||||
|
||||
onServices: function sm_onServices(services) {
|
||||
services.addEventListener('servicefound', function servicefound(e) {
|
||||
for (var i = 0; i < services.length; i++) {
|
||||
if (services[i].online) {
|
||||
this.updateService(services[i]);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
services.addEventListener('servicelost', function servicelost(e) {
|
||||
for (var i = 0; i < services.length; i++) {
|
||||
if (!services[i].online) {
|
||||
this.removeService(services[i]);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.debugLog(services.length + ' service' +
|
||||
(services.length !== 1 ? 's' : '') +
|
||||
' found in the current network');
|
||||
|
||||
// Remove offline services
|
||||
for (var savedServiceId in this.savedServices) {
|
||||
var removed = true;
|
||||
for (var i = 0; i < services.length; i++) {
|
||||
if (services[i].id == savedServiceId) {
|
||||
removed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (removed) {
|
||||
this.remove(savedServiceId);
|
||||
}
|
||||
}
|
||||
|
||||
// Update services individually
|
||||
for (var j = 0; j < services.length; j++) {
|
||||
this.updateService(services[j]);
|
||||
}
|
||||
},
|
||||
|
||||
get currentService() {
|
||||
return deviceManager.getSelectedService(this.serviceName);
|
||||
},
|
||||
|
||||
|
||||
removeSiblingList: function sm_remove(elem) {
|
||||
if (elem.nextElementSibling.classList.contains('sublist')) {
|
||||
elem.parentElement.removeChild(elem.nextElementSibling);
|
||||
}
|
||||
},
|
||||
|
||||
discover: function sm_discover() {
|
||||
if (navigator.getNetworkServices) {
|
||||
this.debugLog('Searching for UPnP services in the current network...');
|
||||
|
||||
navigator.getNetworkServices(this.serviceType)
|
||||
.then(this.onServices.bind(this), function(e) {
|
||||
this.debugLog('An error occurred obtaining UPnP Services [CODE: ' +
|
||||
e.code + ']');
|
||||
});
|
||||
} else {
|
||||
this.debugLog(
|
||||
'navigator.getNetworkServices API is not supported in this browser');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.ServiceManager = ServiceManager;
|
||||
})(window);
|
||||
Loading…
Reference in a new issue