S.A.R.A.H: Tutorial: Plugin XBMC
L’objectif de cet article est de présenter le développement d’un plugin XBMC, pas à pas, en intégrant toutes les fonctions de S.A.R.A.H. Le plugin communiquera avec le serveur XBMC via des requêtes HTTP JSON-RPC.
C’est aussi un bon moyen de faire le tour de toutes les possibilités de SARAH.
0. Pré-requis
Ce plugin est compatible avec la version 12 (Frodo) de XBMC.
- Télécharger et installer la dernière version de XBMC.
- Ajouter à la librairie un dossier de MP3.
- Activer l’accès réseau: System > Service > WebServer > Port 8077
- Désactiver le GUI: System > Service > Audio output > Play GUI sound: Never
- Passer en mode fenêtré.
1. Getting Started
La première étape consiste à créer un répertoire plugins/xbmc/
dans lequel il y aura 2 fichiers.
Le plugin sera ensuite accessible via l’URL http://127.0.0.1:8080/sarah/xbmc
depuis un navigateur.
xbmc.prop
Le fichier xbmc.prop
représente la configuration du plugin. Il ne contiendra qu’un champ supplémentaire api_url
.
[crayon]
{
« modules » : {
« xbmc »: {
« description »: « Commande Vocale pour XBMC »,
« version » : « 1.0 »,
« api_url » : « http://127.0.0.1:8077/jsonrpc »
}
}
}
[/crayon]
xbmc.js
Le fichier xbmc.js
représente le coeur du plugin.
data
: est un objet JSON qui représente les paramètres de requête.callback
: est une fonction à appeler à la fin avec un objet JSON.config
: est un objet JSON contenant la configuration.SARAH
: est le point d’entrée de toute l’API.
[crayon]
exports.action = function(data, callback, config, SARAH){
config = config.modules.xbmc;
if (!config.api_url){
return callback({ ‘tts’ : ‘Configuration XBMC invalide’ });
}
callback({ ‘tts’ : « Le plugin à terminé » });
}
[/crayon]
Un plugin doit obligatoirement appeler la fonction callback({})
. L’objet JSON étant renvoyé dans la réponse HTTP ou au moteur de règles.
2. Communication JSON-RPC
Le serveur XBMC se pilote en envoyant des requêtes HTTP en POST au format JSON. La libraire request présente dans SARAH simplifie le travail.
[crayon]
var sendJSONRequest = function(url, reqJSON, callback){
var request = require(‘request’);
request({
‘uri’ : url,
‘method’ : ‘POST’,
‘json’: reqJSON
},
function (err, response, json){
if (err || response.statusCode != 200) { return callback(false); }
// Return the response
callback(json);
});
}
[/crayon]
Le code de cette fonction est asynchrone. On construit un objet request avec les paramètres url
, POST
, reqJSON
. La fonction suivante est appelée pour traiter la réponse du serveur XBMC.
Une fonction de callback est enfin appelée avec l’objet JSON ou false
si il y a eu une erreur. Ce qui donne:
[crayon]
var introspect = { « jsonrpc »: « 2.0 », « method »: « JSONRPC.Introspect », « params »: { « filter »: { « id »: « AudioLibrary.GetSongs », « type »: « method » } }, « id »: 1 }
sendJSONRequest(config.api_url, introspect, function(json){
// Play with json response here
console.log(json);
})
[/crayon]
Il est possible de tester les autres exemples, comme play/pause en remplaçant introspect
par:
[crayon]
var play = {« jsonrpc »: « 2.0 », « method »: « Player.PlayPause », « params »: { « playerid »: 0 }, « id »: 1}
[/crayon]
Dans le plugin final une fonction handleJSONResponse()
se chargera de traiter tous les cas d’erreur XBMC avant de jouer avec la response.
3. Manipuler la playlist
La logique de XBMC est de piloter des players (audio, vidéo, images, …) à travers des playlists. Nous allons donc:
- Faire une recherche de chansons (par genre, auteur, titre, …)
- Itérer et ajouter les résultats à une playlist vide
- Lancer la lecture
Voici les commandes correspondantes JSON songs
, clearlist
, addtolist
, runlist
:
[crayon]
// Search songs
var songs = {« jsonrpc »: « 2.0 », « method »: « AudioLibrary.GetSongs », « params »: {« properties »: [« title », « genre », « artist », « duration », « album », « track » ], « limits »: { « start » : 0, « end »: 25 }, « sort »: { « order »: « ascending », « method »: « track », « ignorearticle »: true } }, « id »: « libSongs »}
// Clear a playlist
var clearlist = {« jsonrpc »: « 2.0 », « id »: 0, « method »: « Playlist.Clear », « params »: {« playlistid »: 0}}
// Add to a playlist
var addtolist = {« jsonrpc »: « 2.0 », « id »: 1, « method »: « Playlist.Add », « params »: {« playlistid »: 0, « item »: {« songid »: 10}}}
// Run the playlist
var runlist = {« jsonrpc »: « 2.0 », « id »: 2, « method »: « Player.Open », « params »: {« item »: {« playlistid »: 0}}}
[/crayon]
Et la fonction, qui utilise ces variables (le doAction()
exécute le code de l’étape 2.):
[crayon]
var doPlaylist = function(filter, config, callback){
// Apply filter
songs.params[‘filter’] = filter;
// Search songs
doAction(songs, config, callback, function(json){
// No results
if (!json.result.songs){
callback({ ‘tts’ : « Je n’ai pas trouvé de résultats » })
return false;
}
// Clear playlist
doAction(clearlist, config);
// Iterate
json.result.songs.forEach(function(song){
console.log(song.title);
addtolist.params.item.songid = song.songid;
doAction(addtolist, config);
});
doAction(runlist, config);
return true; // call callback
})
}
[/crayon]
Dans notre plugin, il suffit d’appeler doPlaylist()
avec les filtres décodés de la requête HTTP:
[crayon]
exports.action = function(data, callback, config){
…
if (data.action == ‘playlist’){
var filter = {« and »:[]};
if (data.genre) {
filter.and.push({« field »: « genre », « operator »: « contains »,
« value »: data.genre }); }
if (data.artist){
filter.and.push({« field »: « artist », « operator »: « contains »,
« value »: data.artist }); }
if (data.title) {
filter.and.push({« field »: « title », « operator »: « contains »,
« value »: data.title }); }
doPlaylist(filter, config, callback);
}
…
}
[/crayon]
Le plugin sera ensuite accessible via l’URL http://127.0.0.1:8080/sarah/xbmc?action=playlist&genre=pop&artist=madonna
depuis un navigateur.
4. QRCode
Maintenant qu’il est possible de piloter le plugin XBMC depuis une requête HTTP il suffit de transférer la requête sur un QRCode:
On peut imaginer des QRCodes pour lancer un album, un thème, faire play/pause, etc, …
5. Planification du Calendrier
De la même manière, il est possible de planifier le déclenchement de la musique avec Google Calendar:
Avec la récurrence le paramétrage est ultra simple !
6. Commandes Vocales
Les commandes vocales fonctionnent de la même manière. Une requête HTTP est construite en fonction d’une grammaire XML. Créer un fichier xbmc.xml
:
[crayon]
[/crayon]
Bon à savoir:
- Le premier mot (donc SARAH) nécessite une confidence plus élevée
- Seulement les
correspondant à la phrase sont utilisés - Les attributs comme
tts
permettent une réponse immédiate - Les fichiers dont le nom commence par
lazy
ne sont pas chargés. - La langue doit correspondre au recognizer.
Voici un exemple plus complet dans lequel le code précédent devient une sous règle.
[crayon]
[/crayon]
7. Commandes Vocales dictées
La reconnaissance vocale de Microsoft ne sait pas gérer correctement le texte libre. Mais SARAH peux interroger Google Speech pour tenter d’interpréter l’audio.
[crayon]
[/crayon]
Et il faut ajuster le JavaScript:
[crayon]
if (data.dictation){
var regexp = /sarahsrecherches(w+)/gi
var match = regexp.exec(data.dictation);
if (match){
filter = {« or »:[]};
filter.or.push({« field »: « title », « operator »: « contains », « value »: match[1] });
filter.or.push({« field »: « artist », « operator »: « contains », « value »: match[1] });
}
}
[/crayon]
Une expression régulière est utilisée pour repérer le texte dicté. Voici un exemple d’URL:
http://127.0.0.1:8080/sarah/xbmc?action=playlist&dictation=sarah+recherche+madonna+musique
Attention ! la recherche de nom propre est SUPER difficile ! Une autre alternative (faites dans le plugin movie) est de réécrire la grammaire à la volée.
8. Commandes Gestuelles
Il existe 2 manières de piloter le plugin XBMC avec des gestes.
Moteur de règles
Le plugin Gesture propose déjà un ensemble de règle gestuelles. Il suffit de chaîner ces règles avec le plugin XBMC.
Pour démarrer la reconnaissance gestuelle il suffit de dire « Sarah démarre la reconnaissance gestuelle ».
From scratch
Il est aussi possible de créer « from scratch » un fichier xbmc.gesture
qui enverra directement les commandes HTTP.
[crayon]
[/crayon]
Quand le poignet droit passe de la droite à la gauche de la colonne vertébrale une requête est envoyée. De même avec le poignet gauche de la gauche à la droite de la colonne.
9. Reconnaissance faciale
Peu de cas d’usage pour XBMC ici. Quand un visage est reconnu il est envoyé au plugin Face qui va stocker l’identifiant de la personne.
On peut imaginer dans le cas d’XBMC d’exploiter cette identifiant pour personnaliser les réponses Text to Speech:
[crayon]
if (data.action == ‘play’){
doAction(play, config, false);
callback({‘tts’ : ‘Voilà ‘ + SARAH.context.speaker});
}
[/crayon]
Le speaker peut être multiple ou absent donc le code doit être plus robuste. Pour démarrer la reconnaissance faciale, lancer la fenêtre ou dire « Sarah démarre la reconnaissance faciale ».
10. One more thing !
Le plugin est générique et donc réutilisable depuis une règle (comme le plugin gesture) ou même depuis le code:
[crayon]
SARAH.run(‘xbmc’, { ‘action’ : ‘play’ });
[/crayon]
Donc pensez à rédiger une petite doc de vos plugins en créant un fichier index.html
dans le même dossier.
Le plugin est accessible depuis le store !
Cool, merci.
Je me pecherais dessus quand j’aurais moins mal à la tronche ^^.
bonjour,
je suis très interessé par le fait de piloter mon xbmc en http, voir qrcod !
je viens de faire les premiers pas du tuto, mais je rencontre 1 probleme :
j’ai téléchargé la dernière version de xbmc pour raspberry, OpenELEC-RPi.arm-2.99.3.img.
j’ai mis le port du serveur web sur 8077.
je ne trouve pas ou il est possible de Désactiver le GUI: System > Service > Audio output > Play GUI sound: Never
ply-gui-sound n’existe pas dans ce menu
j’ai crée un répertoire /plugins/xbmc
et j’ai envoyé les 2 fichiers : xbmc.prop et xbmc.js, sans les modifier.
lorsque j’appelle l’url : http://192.168.0.4:8080/sarah/xbmc
j’ai un message d’erreur : La connexion a échoué
ai je raté qlq chose ?
y a t’il un plugin a telecharger par ailleurs ?
merci de votre aide.
@seb,
Le plugin est téléchargeable depuis le l’appstore de SARAH. Voici un lien direct:
http://goo.gl/yXsdr
Je n’ai pas fait le test sur Raspberry, j’ai installé le XBMC Windows (12. Frodo).
Tu as mis le port, mais est ce que tu as aussi autoriser le http ? Visiblement avec cette erreur il n’arrive pas à se connecter à XBMC.
Dans la conf du plugin il faut préciser l’URL de XBMC (par défaut 127.0.0.1 si installé sur la même machine)
Pour l’histoire GUI peut être qu’il n’y a pas sur Raspberry. Je l’ai indiqué car sous windows XBMC utilisait Kinect bloquant ainsi SARAH
merci pour la réponse rapide !
effectivement, je n’avais pas tous les fichiers du plugin (peux tu ajouter les lien de telechargement dans les prerequis, pour d’autres ?)
Ces fichiers sont envoyés en ftp sur le repertoire /plugins/xbmc/.
le http est bien activé, puisque si j’appelle http://192.168.0.4:8077/, je tombe sur l’interface web de controle de xbmc.
si j’appelle http://192.168.0.4:8080/sarah/xbmc, le message reste « erreur de connexion »
l’xbmc a toujours une adresse ip interne (127.0.0.1), mais si je met (dans le fichier xbmx.prop) son adresse local (192.168.0.4), ca ne change rien.
je ne vois pas la solution, c’est dommage.
Hum, c’est étrange, peut être que la version Raspberry est différente ? J’imagine que tu utilises YURI ? Ca marche avec les autres plugins ? En regardant le code je ne génère ce type de message d’erreur.
Sur Xbmc Eden, pour désactiver les sons, il faut aller dans :
Paramètre / Apparence / Son de Navigation = Désactiver
Sur Xbmc Frodo, ça doit être sensiblement la même chose 😉
Hello,
Voulant essayer de comprendre pourquoile plugin xbmc du store ne marchait pas chez moi, j’ai essayé ton script, mais quand je lance http://127.0.0.1:8080/sarah/xbmc?xbmc=music&action=introspect, la console me dit Run xbmc : xml is not defined…
Une idée? Merci
Oh là je pense que le mieux serait que tu poses la question à Jérôme Veyret sur la communauté G+ qui depuis a repris le plugin et rajouté plein de trucs
Oui, je sais. J’ai pas mal discuté avec lui mais on arrive pas a trouver pourquoi son plugins ne marchait pas chez moi.
Je prend donc le problème à l’envers depuis XBMC. je crois avoir réussi à vérifier que le serveur jsonRPC fonctionnait, et maintenant j’essaye de l’appeler via Sarah simplement. (Ca ne marche pas avec le plugin de Jérôme).
J’aimerai donc simplement faire un appel RPC depuis un plugins SARAH vers mon XBMC, et ton exemple me plaisait bien.