
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]
SARAH joue de la musique Rock
out.action=new Object();
SARAH joue de la musique out.action.action= »playlist »;
Pop out.action.genre= »pop »
Rock out.action.genre= »rock »
Jazz out.action.genre= »jazz »
Electro out.action.genre= »electro »
out.action._attributes.tts = « Je m’en occupe »
out.action._attributes.uri= »http://127.0.0.1:8080/sarah/xbmc »;
[/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
ttspermettent une réponse immédiate - Les fichiers dont le nom commence par
lazyne 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]
out.action=new Object();
Sarah
out.action = rules.ruleXBMC_playlist;
musique suivanteout.action.action= »next »
musique précédenteout.action.action= »prev »
met en pause la musiqueout.action.action= »play »
reprends la musiqueout.action.action= »play »
out.action._attributes.tts = « Je m’en occupe »
out.action._attributes.uri= »http://127.0.0.1:8080/sarah/xbmc »;
SARAH joue de la musique Rock
out.action=new Object();
joue de la musique out.action.action= »playlist »;
Pop out.action.genre= »pop »
Rock out.action.genre= »rock »
Jazz out.action.genre= »jazz »
Electro out.action.genre= »electro »
[/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]
SARAH recherche * dans les musiques
out.action=new Object();
out.action.action= »playlist »;
recherchedans les musiques
out._attributes.dictation= »true »;
[/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 !



Laisser un commentaire