control-freak-ide/data/system/drivers/Audio-Player/VLC.js
plastic-hub-dev-node-saturn 538369cff7 latest
2021-05-12 18:35:18 +02:00

580 lines
20 KiB
JavaScript

define([
"dcl/dcl",
"xdojo/has!host-node?nxapp/protocols/ProtocolBase",
"dojo/has",
"xide/utils",
"dojo/node!path",
"xdojo/has!host-node?nxapp/utils/FileUtils",
"xdojo/has!host-node?dojo/node!vlc-ffi/vlc",
"xdojo/has!host-node?dojo/node!yargs-parser"
], function (dcl,ProtocolBase,has, utils,_path, FileUtils, vlc, yargs) {
var isIDE = has('xcf-ui');
var Module = null;
//No ProtocolBase means we're running on client side
if (!ProtocolBase) {
//create dummy module
Module = dcl(null, {});
}
/**
* Function to implement optional Command Interface.
* @param Module
*/
function patchModule(Module){
//////////////////////////////////////////////////////////
//
// Optional: An example implementation to modify the string sent to a advice. This makes sense if you added additional fields as shown above.
//
/**
* Callback when a command is before parsing the expression in the "send" field.
* @param command {module:xcf/model/Command}
* @param inputString {string}
* @returns {string}
*/
Module.resolveBefore = function (command,inputString) {
return inputString;
};
/**
* Callback when a command was parsing the expression in the "send" field.
* @param command {module:xcf/model/Command}
* @param inputString {string}
* @returns {string}
*/
/*
Module.resolveAfter = function (command,inputString) {
console.log('resolve after: ' + inputString);
return inputString;
};
*/
}
//////////////////////////////////////////////////////////
//
// Optional: An example implementation to extend commands in the interface for additional fields in the command properties.
//
if(isIDE) {
/**
*
* @param command {module:xcf/model/Command}
* @param fields {Object[]}
*/
/*
Module.getFields = function (command, fields) {
return [utils.createCI('test',0,command.test,{
group:'General',
title:'asdasd',
dst:'test',
order:198
})];
};
*/
}
//we're in client mode, return dummy module with patches.
if(!ProtocolBase){
patchModule(Module);
return Module;
}
Module = dcl([ProtocolBase], {
_player: null,
connect: function () {
this.owner.onConnected();
},
_send: function (data, command, options) {
var wait = options.params.wait;
var self = this;
var outString = JSON.stringify(utils.mixin({
command: command
}, data, null, 2));
if (wait) {
self.owner.onFinish(command, options, new Buffer(outString));
} else {
self.owner.onData(outString, new Buffer(outString));
}
},
_sendProgress: function (data, command, options) {
var self = this;
var outString = JSON.stringify(utils.mixin({
command: command
}, data, null, 2));
self.owner.onProgress(command, options, new Buffer(outString));
},
_sendPaused: function (data, command, options) {
var self = this;
var outString = JSON.stringify(utils.mixin({
command: command
}, data, null, 2));
self.owner.onPaused(command, options, new Buffer(outString));
},
sendStopped: function (data, command, options) {
var self = this;
var outString = JSON.stringify(utils.mixin({
command: command
}, data, null, 2));
self.owner.onStopped(command, options, new Buffer(outString));
},
volume: function (path, vol, options) {
var playData = this.getPlayer(path,options,false);
if(playData){
playData.player.setVolume(vol);
this.sendUpdate(playData,options);
}else{
console.warn("VLC -> set position: cant find player for "+path );
}
},
sendUpdate:function(playData,options){
this._sendProgress({
file: playData.media.path,
duration: playData.media.duration,
position: playData.player.position,
muted:playData.muted,
volume:playData.player.getVolume(),
repeat:playData.repeat,
index:playData.list ? playData.current : -1,
count:playData.list ? playData.list.count() : -1
}, 'play', options);
},
mute: function (path, mute, options) {
var playData = this.getPlayer(path,options,false);
if(playData){
var _muted = mute =='on';
_muted && (playData._lastVolume = playData.player.getVolume());
playData.muted = mute;
if(_muted){
playData._lastVolume = playData.player.setVolume(0);
}else{
playData.player.setVolume(playData._lastVolume || 100);
}
this.sendUpdate(playData,options);
}else{
console.warn("VLC -> set position: cant find player for "+path );
}
},
repeat: function (path, repeat, options) {
var playData = this.getPlayer(path,options,false);
if(playData){
playData.repeat = repeat;
this.sendUpdate(playData,options);
}else{
console.warn("VLC -> set position: cant find player for "+path );
}
},
getVLC: function () {
return new vlc([
'-I', 'dummy',
'-V', 'dummy',
//'-vvvv', 'dummy',
//'--verbose', '1',
'--no-video-title-show',
'--no-disable-screensaver',
'--no-snapshot-preview',
'--ignore-config'
]);
if (!global['__vlcInstance']) {
global['__vlcInstance'] = new vlc([
'-I', 'dummy',
'-V', 'dummy',
//'-vvvv', 'dummy',
//'--verbose', '1',
'--no-video-title-show',
'--no-disable-screensaver',
'--no-snapshot-preview',
'--ignore-config'
]);
}
return global['__vlcInstance'];
},
next: function (path, options) {
var playData = this.getPlayer(path, options, false);
if (playData) {
playData.current += 1;
if (playData.current > playData.list.count()) {
playData.current = 0;
}
playData.isManual = true;
var newMedia = playData.list.at(playData.current);
if (newMedia) {
playData.player.media = newMedia;
playData.media = newMedia;
this.sendUpdate(playData,options);
if(playData.module && playData.soundcard) {
playData.player.setOut(outmodule,soundcard);
}
playData.player.play();
} else {
console.error('cant find media at ' + playData.current);
}
} else {
console.error('cant get player for ' + path);
}
},
prev: function (path, options) {
var playData = this.getPlayer(path, options, false);
if (playData) {
playData.current -= 1;
if (playData.current < 0) {
playData.current = 0;
}
playData.isManual = true;
var newMedia = playData.list.at(playData.current);
if (newMedia) {
playData.player.media = newMedia;
playData.media = newMedia;
if(playData.module && playData.soundcard) {
playData.player.setOut(outmodule,soundcard);
}
playData.player.play();
this.sendUpdate(playData,options);
} else {
console.error('cant find media at ' + playData.current);
}
} else {
console.error('cant get player for ' + path);
}
},
shuffle: function (path, options) {
var playData = this.getPlayer(path, options, false);
if (playData) {
if(playData.list){
playData.list._list.shuffle();
}
} else {
console.error('cant get player for ' + path);
}
},
pos:function(path,position,options){
var playData = this.getPlayer(path,options,false);
if(playData){
playData.player.position = position;
this.sendUpdate(playData,options);
}else{
console.warn("VLC -> set position: cant find player for "+path );
}
},
diagnose:function(){
try {
var vlc = this.getVLC();
vlc.diagnose();
vlc.release();
}catch(e){
console.error(e);
}
},
getPlayer: function (path, options, create) {
var id = "" + path;
if (!this._player) {
this._player = {};
}
var self = this;
if (!this._player[id] && create !== false) {
var _vlc = this.getVLC();
_vlc.releasePlayer();
var player = null;
var media = null;
var mediaList = false;
var files = null;
//individual file selection
if(id.indexOf('http')!==-1){
media = _vlc.mediaFromUrl(id);
player = _vlc.mediaplayer;
player.media = media;
}else {
var parts = path.indexOf(';') !== -1 ? path.split(';') : null;
if (parts && parts.length > 0) {
files = parts;
files = [];
_.each(parts, function (part) {
files.push({
realPath: part
});
});
} else {
files = FileUtils.ls(_path.normalize(path));
}
if (_.isArray(files)) {
mediaList = _vlc.mediaList();
_.each(files, function (item) {
var media = _vlc.mediaFromFile(item.realPath);
if (media) {
mediaList.add(media);
} else {
console.warn("invalid media : " + item.realPath);
}
});
media = mediaList.at(0);
player = _vlc.mediaplayer;
player.media = media;
} else {
media = _vlc.mediaFromFile(path);
player = _vlc.mediaplayer;
player.media = media;
}
}
var struct = {
player: player,
isPlaying: false,
error: null,
path: path,
id:id,
media: media,
vlc: _vlc,
list: mediaList,
duration: media.duration,
current: 0,
repeat:'off',
muted:'off',
release: function () {
try {
clearInterval(this.poller);
delete this.poller;
if(this.isFinished!==true){
this.vlc.releasePlayer();
}
if(this.media && this.media.release){
this.media.release();
}
if(this.isFinished === true && this.vlc){
try {
//this.vlc.release();
}catch(e){
console.error(e);
}
}
delete this.vlc;
delete this.media;
delete this.player;
delete self._player[id];
} catch (e) {
console.error('error releasing player', e);
}
}
};
function creatPoller(_player) {
clearInterval(struct.poller);
struct.poller = setInterval(function () {
if (struct.isPaused || struct.isStopped || struct.isFinished) {
return;
}
self.sendUpdate(struct,options);
}, 2000);
}
this._player[id] = struct;
function wirePlayer(player) {
player.on('Stopped', function (e) {
if (struct.player.songEnded) {
return;
}
try {
var outString = JSON.stringify(utils.mixin({
command: 'play'
}, {
file: path
}, null, 2));
self.owner.onStopped('play', options, new Buffer(outString));
} catch (e) {
console.error('error ', e);
}
struct.release();
});
player.on('Paused', function (e) {
self._sendPaused({
file: path,
duration: media.duration,
position: player.position
}, 'play', options);
});
player.on('EndReached', function (e) {
struct.isFinished = true;
if (struct.list) {
var next = struct.current + 1;
//reached the end
if (next == struct.list.count()) {
//we're in repeat mode so we are setting back the index
if(struct.repeat==='on'){
setTimeout(function(){
struct.current = -1;
var _player = _vlc.createPlayer();
struct.player = _player;
wirePlayer(_player);
creatPoller(_player);
self.next(id, options);
struct.isFinished = false;
},100);
return;
}
struct.isFinished = true;
struct.release();
self._send({
file: id,
duration: 0,
position: 1
}, 'play', options);
return;
}
setTimeout(function() {
var _player = _vlc.createPlayer();
struct.player = _player;
wirePlayer(_player);
creatPoller(_player);
self.next(id, options);
struct.isFinished = false;
}, 100);
return;
}
self._send({
file: path,
duration: media.duration,
position: player.position
}, 'play', options);
struct.release();
});
}
wirePlayer(player);
creatPoller(player);
}
return this._player[id];
},
play: function (path,outmodule,soundcard) {
var id = "" + path;
var options = arguments.length > 2 ? arguments[arguments.length-1] : arguments[1];
if(path.indexOf('http')==-1) {
path = FileUtils.resolve(path);
}
if (!path) {
this.debug() && console.error('Cant play +' + id + " : path doesnt exists!");
return;
}
this.isDebug () && console.log('play audio : ' + path, options.params);
var stop = options && options.params ? options.params.stop === true : false;
if(stop){
var _p = this.getPlayer(id, options,false);
if(!_p){
return;
}
}
var playData = this.getPlayer(id, options);
if(!playData){
console.error('cant find a player for '+id);
return;
}
var player = playData.player;
if (playData.isPaused === true) {
playData.isPaused = false;
player.play();
return;
}
if (options.params.pause === true) {
player.pause();
playData.isPaused = true;
return;
}
if (options.params.stop === true) {
playData.isStopped = true;
playData.isFinished = true;
playData.player.stop();
playData.release();
return;
}
if (playData.isPaused === true) {
player.pause();
playData.isPaused = false;
return;
}
if (playData.isPlaying) {
return;
}
//player.test();
if(outmodule && soundcard) {
player.setOut(outmodule,soundcard);
playData.module = outmodule;
playData.soundcard = soundcard;
}
player.play();
this.sendUpdate(playData,options);
playData.isPlaying = true;
},
write: function (data, options) {
var intArray = utils.bufferFromDecString(data);
var buffer = new Buffer(intArray);
var str = buffer.toString();
this.isDebug() && console.log('write : ' + str, options.params);
var args = yargs(str,{array:true});
var cmd = args['_'][0];
delete args['_'];
args = _.values(args);
if (typeof this[cmd] === 'function') {
args.push(options);
return this[cmd].apply(this, args);
}
},
send: function (data) {
this.isDebug() && console.log('send : ', data);
},
destroy: function () {
this._player && _.each(this._player, function (item) {
item.release();
});
delete this._player;
}
});
patchModule(Module);
return Module;
});