Forum eedomus
http://forum.eedomus.fr/

Pour les utilisateurs de SONOS
http://forum.eedomus.fr/viewtopic.php?f=13&t=756
« Précédent  Page 17 sur 18  Suivant »
Auteur:  galaksy2001 [ 20 Jan 2017 12:15 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

J'utilise http://www.voicerss.org/ pour le tts.
Auteur:  fzaweb [ 20 Jan 2017 12:47 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

En effet cela parait tres bien. Meme avec la version gratuite.
(en jouant avec l'enregistrement des TTS precedent , cela devrait largement suffir)

Tu peux me donner le bout de code que tu utilise ?

Merci
Auteur:  galaksy2001 [ 20 Jan 2017 13:31 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Dans le fichier sonos.class.php tu vas au paragraphe :

// Google Translate API cannot handle strings > 100 characters.

Voici ensuite mon code :

Code : Tout sélectionner
$mp3[$i] = file_get_contents('http://api.voicerss.org/?key=xxxxxxxxxxxxxxxx&f=44khz_16bit_stereo&hl=fr-fr&src='.$words[$i].'&tl='.$lang);


La key corresponds au code API fourni par voicerss lorsque tu t'inscris.
Auteur:  fzaweb [ 20 Jan 2017 14:26 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Merci beaucoup ca marche nickel.

Je gere maintenant les MP3 personnels ( chien qui aboie par exemple) et les TTS via Voice RSS ou l'eedomus.

Thanks !
Auteur:  galaksy2001 [ 20 Jan 2017 14:44 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Your welcome ;)
Auteur:  agusta68 [ 23 Jan 2017 21:46 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Bonjour et merci pour ce poste qui est fort intéressant même si je n'ai, pour le moment (je perd presque espoir :mrgreen: ), réussi à faire dire bonjour à ma SONOS...

J'ai le message d'erreur sur l'appli SONOS fichier introuvable et pas de dossier audio ni de MP3 de créé (donc forcement il est introuvable :evil: )

Depuis le début de ce poste SONOS GOOGLE ont essuyé beaucoup de mise a jour... quelqu'un arrive t'il a faire marcher ces TTS à ce jour?

Si oui j'aurais besoin d'aide (après mes nuits blanche à passer sur 3 ou 4 forum différent qui traite de ce sujet)
je passe par un server Synology : pouvez me dire:
-Clairement quel sont les prérequis du server PHP(case a cocher dans le paquet WEB STATION?)
-quelle sont les permission qu'a besoin le dossier web et ces sous dossier SONOS?(guest/http/admin lecture écriture)
Pouvez vous partager les dernier fichier sonos.class.php et sonos.tts.php qui fonctionne?

Actuellement le lien qui fonctionne sans captcha sous google est le suivant:
http://translate.google.com/translate_tts?q=bonjour&tl=fr&idx=0&client=eedomus

les fichiers de djmomo et clement dispo sur github sont ils à jour?

Beaucoup de demande je sais...mais j'ai vraiment besoin d'aide je suis perdu...

Promis si j'arrive a faire parler ma sonos je mettrais en forme en ptit tutos "faire parler sa SONOS pour les nuls avec un synology". :lol:
Auteur:  fzaweb [ 23 Jan 2017 23:20 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Salut

Je suis dans la meme config que toi.

As-tu dejà suivi scrupuleusement le tuto ?
https://github.com/DjMomo/sonos

On va y aller petit a petit

Tu as activé par défaut ton site Web sur le Syno ?
Tu doit avoir a la racine du syno un répertoire "web"
Dans lequel tu aura créer un répertoire "sonos" et copier les fichiers PHP. (Via un explorateur depuis ton PC , ou l'explorateur dans l'interface du syno)

créer aussi un sous-répertoire "audio" (attention jamais de majuscule)
Via l'interface du syno , et son explorateur , faut rajouter des droits sur le répertoire "audio" pour l'utilisateur "HTTP" .. J'ai mis "Controle Total" (que sur audio).
Auteur:  agusta68 [ 24 Jan 2017 19:17 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Bonjour effectivement c'est mieux de reprendre petit à petit car j'ai fait beaucoup de test divers et varié....tous ce mélange un peu...

J'ai créé le fichier audio (faut il créer un sous dossier fr?)

Pour info j'arrive à lancer le script sonos.play.php depuis le syno de ce coté la on est bon le sonos ce met en play :)

j’attends la suite avec impatience je reste connecté ce soir... :mrgreen:

Merci pour ton aide en tous cas!!!
Auteur:  fzaweb [ 24 Jan 2017 20:40 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Si tu as bien mis les droits pour http , le sous repertoire FR , va se creer tous seul.

Dedans devrait apparaître les fichiers MP3

Peut etre un avec 0ko (ce qui veux dire que le tts google ne marche pas)
Auteur:  fzaweb [ 24 Jan 2017 20:50 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Coté SONOS
Dans l'appli , il faut que tu rajoute dans "paramètre de la bibliothèque musicale" le lien vers ton répertoire Audio

Ça donne : Audio //Diskstation/web/sonos/audio
Auteur:  fzaweb [ 24 Jan 2017 20:57 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Mon fichier de lancement ..

Verifie que tu as bien $directory (en debut et fin du fichier) , y a eu plusieurs versions qui ont circulé.

Code : Tout sélectionner
<?php
// Exemple de l'utilisation de la fonction Text-to-speech
require("sonos.class.php");
$IP_sonos_1 = "192.168.xx.xx"; // A adapter avec l'adresse IP du Sonos à contrôler
$directory = "diskstation/web/sonos";

$volume = 0;
$force_unmute = 0;

if (isset($_GET['ip'])) $IP_sonos_1 = $_GET['ip'];
if (isset($_GET['force_unmute'])) $force_unmute = $_GET['force_unmute']; // Force la désactivation de la sourdine. Optionnel
if (isset($_GET['volume'])) $volume = $_GET['volume']; // Niveau sonore. Optionnel.
$message = $_GET['message']; // Message à diffuser
echo $volume;
echo $force_unmute;
echo "message :".$message;
echo "IP:".$IP_sonos_1;
//Instanciation de la classe
$sonos_1 = new SonosPHPController($IP_sonos_1);
$sonos_1->PlayTTS($message,$directory,$volume,$force_unmute); //Lecture du message
?>



Pour les multiples "Echo" je m'en sert pour le debug
Auteur:  agusta68 [ 24 Jan 2017 22:28 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Re, voilà avec le dossier audio et les bon PHP j'arrive enfin à faire parler ma SONOS!! Merci comme quoi des fois il faut juste prendre un peu de recul!!
Merci je vais m'atteler à faire un petit récapitulatif pour les prochains!!
Je vais maintenant voir comment faire parler mes périphériques je ne suis malheureusement pas sur eedomus mais sur Zipabox. ... :o
Auteur:  fzaweb [ 24 Jan 2017 22:35 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Ca fonctionne avec le TTS de Google ? ou un autre ?

De mon coté , j'ai pris en charge les Playlists Spotify ( qui ne redemarre pas correctement apres un TTS)
Aussi la lecture de MP3 standard (sans passé par le TTS)
Auteur:  agusta68 [ 24 Jan 2017 22:55 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

En faite il me semble que dans le script il y a le tts de Google et de acapela mais je ne sais pas lequel il choisit par défaut je pense Google...
Pour lire un mp3 stocké la ligne de commande à rajouter m'intéresse...
Auteur:  fzaweb [ 24 Jan 2017 23:07 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Ce n'est pas qu'une commande ...
Je regarde si le message fini par MP3 .. et dans ce cas je lance la lecture du MP3 , au lieu de passer par la phase de conversion Text en MP3.

voici le bout de code que j'utilise

Toute la fonction PlayTTS() qui corrige le bug des playlists Spotify a l'occasion

Code : Tout sélectionner
   public function PlayTTS($message,$directory,$volume=0,$unmute=0,$lang='fr')
   {
      echo "\r\n- PlayTTS()".$message." - ".$directory." - ".$volume." - ".$unmute." - ".$lang."\r\n";
      $actual['track'] = $this->GetPositionInfo();
      $actual['volume'] = $this->GetVolume();
      $actual['mute'] = $this->GetMute();
      $actual['status'] = $this->GetTransportInfo();
      $this->Pause();
      if ($unmute == 1)
         $this->SetMute(0);
      if ($volume != 0)
         $this->SetVolume($volume);
      
      echo $actual['track'];
      echo $actual['volume'];
      echo $actual['mute'];
      echo $actual['status'];
      
   
    If ((stripos($message,".mp3")) !== false)
    {
      // Code permettant de lire le fichier MP3 si message contient ".mp3"
        $file = 'x-file-cifs://'.$directory.'/audio/'.$message;
    }
    else
    {
      // Commande permettant la traduction texte en MP3
        $file = 'x-file-cifs://'.$directory.'/'.$this->TTSToMp3($message,$lang);
   
    }
      

    // Si message = "TTS" alors utilise le MP3 genere par l'eedomus
    // MP3 a generer par l'Eedomus avant le lancement de ce script   (IP local de l'EEDOMUS)
    if ($message == "TTS") $file="http://192.168.xx.xxx/audio/_tts.wav" ;
   
   
      echo $file ;
      
      
      if ((stripos($actual['track']["TrackURI"],"radio://")) !== false)
      {
         //It's a radio
         echo "It's a radio only";
         $this->SetQueue($file);
         $this->Play();
         sleep(2);
         while ($this->GetTransportInfo() == "PLAYING") {}
         $this->Pause();
         $this->SetVolume($actual['volume']);
         $this->SetMute($actual['mute']);
         $this->SetQueue($actual['track']["TrackURI"]);
      
      }
      else
      {
      
         if (((stripos($actual['track']["TrackURI"],"x-file-cifs://")) !== false) or ((stripos($actual['track']["TrackURI"],".mp3")) !== false) or ((stripos($actual['track']["TrackURI"],"spotify")) !== false))
         {
                  
            // It's a MP3 file or playlist Spotify
            echo "It's a MP3 file or playlist Spotify";
            $TrackNumber = $this->AddURIToQueue($file);
            $this->ChangeTrack($TrackNumber);
            $this->Play();
            while (true) {
               @$ttsFile=$this->GetPositionInfo();
               if($ttsFile["TrackNumberInQueue"]!=$TrackNumber)
                  break;
               usleep(10000);
            }
            $this->Pause();
            $this->SetVolume($actual['volume']);
            $this->SetMute($actual['mute']);
            $this->ChangeTrack($actual['track']["TrackNumberInQueue"]);
            $this->SeekTime($actual['track']["RelTime"]);
            $this->RemoveTrackFromQueue($TrackNumber);
         
         }
         else
         {
         
            //It's a radio / or TV (playbar) / or nothing
            echo "It's a radio / or TV (playbar) / or nothing";
            $this->SetQueue($file);
            $this->Play();
            sleep(2);
            while ($this->GetTransportInfo() == "PLAYING") {}
            $this->Pause();
            $this->SetVolume($actual['volume']);
            $this->SetMute($actual['mute']);
            $this->SetQueue($actual['track']["TrackURI"]);
         
         }
      }
      if (strcmp($actual['status'],"PLAYING") == 0)
         $this->Play();
      return true;
   }
Auteur:  fzaweb [ 24 Jan 2017 23:11 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Dis mois quand meme si tu utilise Google ou acapela

Pour moi .. aucun des deux ne fonctionnent
Auteur:  agusta68 [ 24 Jan 2017 23:36 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

OK merci, je m'en occupe demain soir, je me lève très tôt demain...
je regarde pour savoir si c'est Google ou acapela et je test ton code aussi
Bonne soirée et merci
Auteur:  fzaweb [ 24 Jan 2017 23:58 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Parcontre si quelqu'un sait comment Grouper/degrouper les SONOS en PHP ... Je suis preneur :)

Idem si quelqu'un a trouvé la solution pour le bug sur les playlists en mode aléatoire.
(le TTS ne fonctionne pas ... car le script ne retrouve plus le son TTS )


Merci
Auteur:  agusta68 [ 25 Jan 2017 20:41 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Salut,
Voila mon sonos.tts.php
Code : Tout sélectionner
<?php
// Code from https://github.com/DjMomo/sonos
// Exemple de l'utilisation de la fonction Text-to-speech
require("sonos.class.php");
$directory = "ipsyno/web/sonos";      // Indiquer ici le dossier partage contenant les scrips PHP sonos (et qui contiendra le sous-dossier audio)
$ttsengine = 'acapela';                  // Indiquer ici le moteur vocal a utiliser (google ou acapela)
$lang = 'fr';

$volume = 30;   // De 0 a 100 %
$force_unmute = 1;

$IP_sonos = "192.168.x.xx"; // A adapter avec l'adresse IP du Sonos a controler


if (isset($_GET['force_unmute'])) $force_unmute = $_GET['force_unmute']; // Force la desactivation de la sourdine. Optionnel
if (isset($_GET['volume'])) $volume = $_GET['volume']; // Niveau sonore. Optionnel.
$message = $_GET['message']; // Message a diffuser

// Instanciation de la classe
$sonos = new SonosPHPController($IP_sonos);
$sonos->PlayTTS($message,$directory,$volume,$force_unmute,$lang,$ttsengine); // Lecture du message
?>

Du coup je pense qu'il utilise acapela chez moi
Auteur:  agusta68 [ 25 Jan 2017 20:48 ]
Sujet du message:  Re: Pour les utilisateurs de SONOS

Et pour ceux que ça peux aider le fichier sonos.classe.php les php ensemble fonctionne chez moi...

Code : Tout sélectionner
<?php

class SonosPHPController
{
   protected $Sonos_IP;
   protected $_raw = [];

   /**
   * Constructeur
   * @param string Sonos IP adress
   * @param string Sonos port (optional)
   */
   public function __construct($Sonos_IP,$Sonos_Port = '1400')
   {
      // On assigne les param�tres aux variables d'instance.
      $this->IP = $Sonos_IP;
      $this->PORT = $Sonos_Port;
   }

   protected function Upnp($url,$SOAP_service,$SOAP_action,$SOAP_arguments = '',$XML_filter = '')
   {
      $POST_xml = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">';
      $POST_xml .= '<s:Body>';
      $POST_xml .= '<u:'.$SOAP_action.' xmlns:u="'.$SOAP_service.'">';
      $POST_xml .= $SOAP_arguments;
      $POST_xml .= '</u:'.$SOAP_action.'>';
      $POST_xml .= '</s:Body>';
      $POST_xml .= '</s:Envelope>';

      $POST_url = $this->IP.":".$this->PORT.$url;

      $ch = curl_init();
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
      curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
      curl_setopt($ch, CURLOPT_URL, $POST_url);
      curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      curl_setopt($ch, CURLOPT_TIMEOUT, 30);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: text/xml", "SOAPAction: ".$SOAP_service."#".$SOAP_action));
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_POSTFIELDS, $POST_xml);
      $r = curl_exec($ch);
      curl_close($ch);

      if ($XML_filter != '')
         return $this->Filter($r,$XML_filter);
      else
         return $r;
   }

   protected function Filter($subject,$pattern)
   {
      preg_match('/\<'.$pattern.'\>(.+)\<\/'.$pattern.'\>/',$subject,$matches); ///'/\<'.$pattern.'\>(.+)\<\/'.$pattern.'\>/'
      return $matches[1];
   }

   /**
   * Play
   */
   public function Play()
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'Play';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID><Speed>1</Speed>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Pause
   */
   public function Pause()
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'Pause';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Stop
   */
   public function Stop()
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'Stop';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Next
   */
   public function Next()
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'Next';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Previous
   */
   public function Previous()
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'Previous';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Seek to position xx:xx:xx or track number x
   * @param string 'REL_TIME' for time position (xx:xx:xx) or 'TRACK_NR' for track in actual queue
   * @param string
   */
   public function Seek($type,$position)
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'Seek';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID><Unit>'.$type.'</Unit><Target>'.$position.'</Target>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Seek to time xx:xx:xx
   */
   public function SeekTime($time)
   {
      return $this->Seek("REL_TIME",$time);
   }

   /**
   * Change to track number
   */
   public function ChangeTrack($number)
   {
      return $this->Seek("TRACK_NR",$number);
   }

   /**
   * Restart actual track
   */
   public function RestartTrack()
   {
      return $this->Seek("REL_TIME","00:00:00");
   }

   /**
   * Restart actual queue
   */
   public function RestartQueue()
   {
      return $this->Seek("TRACK_NR","1");
   }

   /**
   * Get volume value (0-100)
   */
   public function GetVolume()
   {
      $url = '/MediaRenderer/RenderingControl/Control';
      $action = 'GetVolume';
      $service = 'urn:schemas-upnp-org:service:RenderingControl:1';
      $args = '<InstanceID>0</InstanceID><Channel>Master</Channel>';
      $filter = 'CurrentVolume';
      return $this->Upnp($url,$service,$action,$args,$filter);
   }

   /**
   * Set volume value (0-100)
   */
   public function SetVolume($volume)
   {
      $url = '/MediaRenderer/RenderingControl/Control';
      $action = 'SetVolume';
      $service = 'urn:schemas-upnp-org:service:RenderingControl:1';
      $args = '<InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>'.$volume.'</DesiredVolume>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Get mute status
   */
   public function GetMute()
   {
      $url = '/MediaRenderer/RenderingControl/Control';
      $action = 'GetMute';
      $service = 'urn:schemas-upnp-org:service:RenderingControl:1';
      $args = '<InstanceID>0</InstanceID><Channel>Master</Channel>';
      $filter = 'CurrentMute';
      return $this->Upnp($url,$service,$action,$args,$filter);
   }

   /**
   * Set mute
   * @param integer mute active=1
   */
   public function SetMute($mute = 0)
   {
      $url = '/MediaRenderer/RenderingControl/Control';
      $action = 'SetMute';
      $service = 'urn:schemas-upnp-org:service:RenderingControl:1';
      $args = '<InstanceID>0</InstanceID><Channel>Master</Channel><DesiredMute>'.$mute.'</DesiredMute>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Get Transport Info : get status about player
   */
   public function GetTransportInfo()
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'GetTransportInfo';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID>';
      $filter = 'CurrentTransportState';
      return $this->Upnp($url,$service,$action,$args,$filter);
   }

   /**
   * Get Media Info : get informations about media
   */
   public function GetMediaInfo()
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'GetMediaInfo';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID>';
      $filter = 'CurrentURI';
      return $this->Upnp($url,$service,$action,$args,$filter);
   }

   /**
   * Get Position Info : get some informations about track
   */
   public function GetPositionInfo()
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'GetPositionInfo';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID>';
      $xml = $this->Upnp($url,$service,$action,$args);

      $data["TrackNumberInQueue"] = $this->Filter($xml,"Track");
      $data["TrackURI"] = $this->Filter($xml,"TrackURI");
      $data["TrackDuration"] = $this->Filter($xml,"TrackDuration");
      $data["RelTime"] = $this->Filter($xml,"RelTime");
      $TrackMetaData = $this->Filter($xml,"TrackMetaData");

      $xml = substr($xml, stripos($TrackMetaData, '&lt;'));
      $xml = substr($xml, 0, strrpos($xml, '&gt;') + 4);
      $xml = str_replace(array("&lt;", "&gt;", "&quot;", "&amp;", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $xml);

      $data["Title"] = $this->Filter($xml,"dc:title");   // Track Title
      $data["AlbumArtist"] = $this->Filter($xml,"r:albumArtist");      // Album Artist
      $data["Album"] = $this->Filter($xml,"upnp:album");      // Album Title
      $data["TitleArtist"] = $this->Filter($xml,"dc:creator");   // Track Artist

      return $data;
   }

   /**
   * Add URI to Queue
   * @param string track/radio URI
   * @param bool added next (=1) or end queue (=0)
   */
   public function AddURIToQueue($URI,$next=0)
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'AddURIToQueue';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $next = (int)$next;
      $args = '<InstanceID>0</InstanceID><EnqueuedURI>'.$URI.'</EnqueuedURI><EnqueuedURIMetaData></EnqueuedURIMetaData><DesiredFirstTrackNumberEnqueued>0</DesiredFirstTrackNumberEnqueued><EnqueueAsNext>'.$next.'</EnqueueAsNext>';
      $filter = 'FirstTrackNumberEnqueued';
      return $this->Upnp($url,$service,$action,$args,$filter);
   }

   /**
   * Remove a track from Queue
   *
   */
   public function RemoveTrackFromQueue($tracknumber)
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'RemoveTrackFromQueue';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID><ObjectID>Q:0/'.$tracknumber.'</ObjectID>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Clear Queue
   *
   */
   public function RemoveAllTracksFromQueue()
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'RemoveAllTracksFromQueue';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Set Queue
   * @param string URI of new track
   */
   public function SetQueue($URI)
   {
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'SetAVTransportURI';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID><CurrentURI>'.$URI.'</CurrentURI><CurrentURIMetaData></CurrentURIMetaData>';
      return $this->Upnp($url,$service,$action,$args);
   }

   /**
   * Refresh music library
   *
   */
   public function RefreshShareIndex()
   {
      $url = '/MediaServer/ContentDirectory/Control';
      $action = 'RefreshShareIndex';
      $service = 'urn:schemas-upnp-org:service:ContentDirectory:1';
      return $this->Upnp($url,$service,$action,$args);
   }

   /******************************************************************************
   * Get Transport Settings : get PlayMode about player
   ******************************************************************************/
   public function GetPlayMode()   {
      
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'GetTransportSettings';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID>';
      $filter = 'PlayMode';
      return $this->Upnp($url,$service,$action,$args,$filter);
   }

   /******************************************************************************
   * Set Transport Settings : set PlayMode about player
   ******************************************************************************/
   public function SetPlayMode($playmode="NORMAL")   {
      
      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'SetPlayMode';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $args = '<InstanceID>0</InstanceID><NewPlayMode>'.$playmode.'</NewPlayMode>';
      return $this->Upnp($url,$service,$action,$args);
   }
   
   /**
   * Split string in several strings
   *
   */
   protected function CutString($string,$intmax)
   {
      $i = 0;
      while (strlen($string) > $intmax)
      {
         $string_cut = substr($string, 0, $intmax);
         $last_space = strrpos($string_cut, "+");
         $strings[$i] = substr($string, 0, $last_space);
         $string = substr($string, $last_space, strlen($string));
         $i++;
      }
      $strings[$i] = $string;
      return $strings;
   }


   
   
   /**
   * Download TTS file from Google
   *
   */
   protected function GetTtsFileFromGoogle($file,$words,$lang)
   {
      // Google Translate API cannot handle strings > 100 characters
      $words = $this->CutString($words,100);

      ini_set('user_agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0');
      $mp3 = "";
      for ($i = 0; $i < count($words); $i++)
         $mp3[$i] = file_get_contents('http://translate.google.com/translate_tts?q='.$words[$i].'&tl='.$lang.'&client=eedomus');

      file_put_contents($file, $mp3);
      
      return $file;
   }
   
   
   /**
   * Download TTS file from Acapala
   * Initial code from https://github.com/skmp/acapela-tts-zeroconf-proxy
   */
   protected function GetTtsFileFromAcapela($file,$words,$lang)
        {
                // Acapela demo TTS API cannot handle strings > 300 characters
                $words = substr($words, 0, 300);

                // Get PHP Session from cookies
                $ch = curl_init('http://www.acapela-group.com/?lang=fr');
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                curl_setopt($ch, CURLOPT_HEADER, 1);
                $result = curl_exec($ch);
                preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $result, $matches);
                $cookies = array();
                foreach($matches[1] as $item) {
                    parse_str($item, $cookie);
                    $cookies = array_merge($cookies, $cookie);
                }               
                //var_dump($cookies);
                //echo $cookies['PHPSESSID'];
               
                // Get sound
                $url = 'http://www.acapela-group.com/demo-tts/DemoHTML5Form_V2.php';
                $data =
                        array(
                        'MySelectedVoice' => 'Manon',
                        'MyTextForTTS' => urldecode($words),
                        'agreeterms' => 'on',
                        'SendToVaaS' =>'');
                        // use key 'http' even if you send the request to https://...
                        $options = array(
                            'http' => array(
                                'header'  => "Cookie: PHPSESSID=".$cookies['PHPSESSID']."\r\n",
                                'method'  => 'POST',
                                'content' => http_build_query($data),
                            ),
                        );
                $context  = stream_context_create($options);
                $result = file_get_contents($url, false, $context);
                $hookp = "var myPhpVar = '";
                $temp = substr(strstr($result,$hookp),strlen($hookp));
                $rv = substr($temp,0,strpos($temp,"'"));

                file_put_contents($file, file_get_contents($rv));

                return $file;
        }
   
   
   
   /**
   * Convert Words (text) to Speech (MP3)
   *
   */
   protected function TTSToMp3($words,$lang,$ttsengine)
   {
      // Directory
      $folder = "audio/".$lang;

      // Replace the non-alphanumeric characters
      // The spaces in the sentence are replaced with the Plus symbol
      $words = urlencode($words);

      // Name of the MP3 file generated using the MD5 hash
      $file = md5($words);

      // If folder doesn't exists, create it
      if (!file_exists($folder))
         mkdir($folder, 0755, true);

      // Save the MP3 file in this folder with the .mp3 extension
      $file = $folder."/TTS-".$file.".mp3";

      // If the MP3 file exists, do not create a new request
      if (!file_exists($file))
      {   
         if($ttsengine == 'google'){
            $file = $this->GetTtsFileFromGoogle($file,$words,$lang);
         }
         elseif($ttsengine == 'acapela'){
            $file = $this->GetTtsFileFromAcapela($file,$words,$lang);
         }

      }
      return $file;
   }

   /**
   * Say song name via TTS message
   * @param string message
   * @param string radio name display on sonos controller
   * @param int volume
   * @param string language
   */
   public function SongNameTTS($directory,$volume=0,$unmute=0,$lang='fr')
   {
      $ThisSong = "Cette chanson s'appelle ";
      $By = " de ";

      $actual['track'] = $this->GetPositionInfo();

      $SongName = $actual['track']['Title'];
      $Artist = $actual['track']['TitleArtist'];

      $message = $ThisSong . $SongName . $By . $Artist ;

      $this->PlayTTS($message,$directory,$volume,$unmute,$lang);

      return true;
   }

   /**
   * Play a TTS message
   * @param string message
   * @param string radio name display on sonos controller
   * @param int volume
   * @param string language
   */
   public function PlayTTS($message,$directory,$volume=0,$unmute=0,$lang='fr',$ttsengine='google')
   {
      $actual['track'] = $this->GetPositionInfo();
      $actual['volume'] = $this->GetVolume();
      $actual['mute'] = $this->GetMute();
      $actual['status'] = $this->GetTransportInfo();
      $this->Pause();

      if ($unmute == 1)
         $this->SetMute(0);
      if ($volume != 0)
         $this->SetVolume($volume);

      $file = 'x-file-cifs://'.$directory.'/'.$this->TTSToMp3($message,$lang,$ttsengine);

      if (((stripos($actual['track']["TrackURI"],"x-file-cifs://")) !== false) or ((stripos($actual['track']["TrackURI"],".mp3")) !== false))
      {
         // It's a MP3 file
         $TrackNumber = $this->AddURIToQueue($file);
         $this->ChangeTrack($TrackNumber);
         $this->Play();
         while (true) {
            @$ttsFile=$this->GetPositionInfo();
            if($ttsFile["TrackNumberInQueue"]!=$TrackNumber)
               break;
            usleep(10000);
         }
         $this->Pause();
         $this->SetVolume($actual['volume']);
         $this->SetMute($actual['mute']);
         $this->ChangeTrack($actual['track']["TrackNumberInQueue"]);
         $this->SeekTime($actual['track']["RelTime"]);
         $this->RemoveTrackFromQueue($TrackNumber);
      }
      else
      {
         //It's a radio / or TV (playbar) / or nothing
         $this->SetQueue($file);
         $this->Play();
         sleep(2);
         while ($this->GetTransportInfo() == "PLAYING") {}
         $this->Pause();
         $this->SetVolume($actual['volume']);
         $this->SetMute($actual['mute']);
         $this->SetQueue($actual['track']["TrackURI"]);
      }

      if (strcmp($actual['status'],"PLAYING") == 0)
         $this->Play();
      return true;
   }

   public function AddSpotifyToQueue($spotify_id, $next = false) {
      $rand = mt_rand(10000000, 99999999);

      $meta = '<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">
            <item id="'.$rand.'spotify%3atrack%3a'.$spotify_id.'" restricted="true">
               <dc:title></dc:title>
               <upnp:class>object.item.audioItem.musicTrack</upnp:class>
               <desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">SA_RINCON2311_X_#Svc2311-0-Token</desc>
            </item>
         </DIDL-Lite>';

      $meta = htmlentities($meta);

      $url = '/MediaRenderer/AVTransport/Control';
      $action = 'AddURIToQueue';
      $service = 'urn:schemas-upnp-org:service:AVTransport:1';
      $next = (int)$next;

      $args = "
         <InstanceID>0</InstanceID>
         <EnqueuedURI>x-sonos-spotify:spotify%3atrack%3a{$spotify_id}</EnqueuedURI>
         <EnqueuedURIMetaData>{$meta}</EnqueuedURIMetaData>
         <DesiredFirstTrackNumberEnqueued>0</DesiredFirstTrackNumberEnqueued>
         <EnqueueAsNext>{$next}</EnqueueAsNext>
      ";

      $filter = 'FirstTrackNumberEnqueued';

      return $this->Upnp($url, $service, $action, $args, $filter);
   }

   public function device_info() {
      $xml = $this->_device_info_raw('/xml/device_description.xml');

      $out = [
         'friendlyName' => (string)$xml->device->friendlyName,
         'modelNumber' => (string)$xml->device->modelNumber,
         'modelName' => (string)$xml->device->modelName,
         'softwareVersion' => (string)$xml->device->softwareVersion,
         'hardwareVersion' => (string)$xml->device->hardwareVersion,
         'roomName' => (string)$xml->device->roomName,
      ];

      return $out;
   }

   public function get_coordinator() {
      $topology = $this->_device_info_raw('/status/topology');

      $myself = null;
      $coordinators = [];

      // Loop players, build map of coordinators and find myself
      foreach ($topology->ZonePlayers->ZonePlayer as $player) {
         $player_data = $player->attributes();

         $ip = parse_url((string)$player_data->location)['host'];

         if ($ip == $this->IP) {
            $myself = $player_data;
         }

         if ((string)$player_data->coordinator == 'true') {
            $coordinators[(string)$player_data->group] = $ip;
         }
      }

      $coordinator = $coordinators[(string)$myself->group];

      return new static($coordinator);
   }

   protected function _device_info_raw($url) {
      $url = "http://{$this->IP}:{$this->PORT}{$url}";

      if (!isset($this->_raw[$url])) {
         $ch = curl_init();
         curl_setopt($ch, CURLOPT_URL, $url);
         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
         $data = curl_exec($ch);
         curl_close($ch);

         $this->_raw[$url] = simplexml_load_string($data);
      }

      return $this->_raw[$url];
   }

   public static function detect($ip = '239.255.255.250', $port = 1900) {
      $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
      socket_set_option($sock, getprotobyname('ip'), IP_MULTICAST_TTL, 2);

      $data = <<<DATA
M-SEARCH * HTTP/1.1
HOST: {$ip}:reservedSSDPport
MAN: ssdp:discover
MX: 1
ST: urn:schemas-upnp-org:device:ZonePlayer:1
DATA;

      socket_sendto($sock, $data, strlen($data), null, $ip, $port);

      // All passed by ref
      $read = [$sock];
      $write = $except = [];
      $name = $port = null;
      $tmp = '';

      // Read buffer
      $buff = '';

      // Loop until there's nothing more to read
      while (socket_select($read, $write, $except, 1) && $read) {
         socket_recvfrom($sock, $tmp, 2048, null, $name, $port);

         $buff .= $tmp;
      }

      // Parse buffer into devices
      $data = static::_parse_detection_replies($buff);

      // Make an array of myselfs
      $devices = [];
      $unique = [];

      foreach ($data as $datum) {
         if(in_array($datum['usn'],$unique)) {
            continue;
         }
         $url = parse_url($datum['location']);

         $devices[] = new static($url['host'], $url['port']);
         $unique[] = $datum['usn'];
      }

      return $devices;
   }

   protected static function _parse_detection_replies($replies) {
      $out = [];

      // Loop each reply
      foreach (explode("\r\n\r\n", $replies) as $reply) {
         if ( ! $reply) {
            continue;
         }

         // New array entry
         $arr =& $out[];

         // Loop each line
         foreach (explode("\r\n", $reply) as $line) {
            // End of header name
            if (($colon = strpos($line, ':')) !== false) {
               $name = strtolower(substr($line, 0, $colon));
               $val = trim(substr($line, $colon + 1));

               $arr[$name] = $val;
            }
         }
      }

      return $out;
   }

   public static function get_room_coordinator($room_name) {
      // Detect devices. Sometimes takes a few goes.
      do {
         $devices = static::detect();

         if (!$devices) {
            sleep(1);
         }
      } while (!$devices);

      foreach ($devices as $device) {
         if ($device->device_info()['roomName'] == $room_name) {
            return $device->get_coordinator();
         }
      }

      return false;
   }
}


A noter que j'ai modifier la 395 ligne ci dessous dans le code par rapport au PHP d'origine
Code : Tout sélectionner
$mp3[$i] = file_get_contents('http://translate.google.com/translate_tts?q='.$words[$i].'&tl='.$lang.'&client=eedomus')


et voila
Page 17 sur 18 Le fuseau horaire est UTC+1 heure