PageRenderTime 102ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Server/services/sonos_hacsvc/PHPSonos.inc.php

https://github.com/nidayand/HAC-Now
PHP | 2320 lines | 1906 code | 95 blank | 319 comment | 35 complexity | 512ae70c6dbd9a0517a708a3529a267d MD5 | raw file
  1. <?php
  2. // URL to gen documentation on my (br) system http://192.168.0.5:82/user/PhpDocumentor/
  3. /**
  4. * PHPSonos.inc.php
  5. *
  6. * PHPSonos class originally released as: Sonos PHP Script - Copyright: Michael Maroszek - Version: 1.0, 09.07.2009
  7. *
  8. * Wiki: {@link http://www.ip-symcon.de/wiki/PHPSonos PHPSonos IPS-WIKI }
  9. *
  10. * @author Michael Maroszek <office@ip-symcon.de> and many others
  11. * @version see date of edit
  12. * @package PHPSonos.inc.php
  13. * @copyright original 1.0 version Michael Maroszek; later additions if not otherwise stated are released to public domain
  14. */
  15. /**
  16. * PHPSonos Class
  17. *
  18. * PHPSonos Class originally released as: Sonos PHP Script - Copyright: Michael Maroszek - Version: 1.0, 09.07.2009
  19. *
  20. * Wiki: {@link http://www.ip-symcon.de/wiki/PHPSonos PHPSonos IPS-WIKI }
  21. *
  22. * Die PHPSonos Klasse wurde von Paresy zuerst im Thread Einzelne Sonos Player ansteuern veröffentlicht und später in einer aktualisierten Fassung im Thread PHP Sonos (Klasse zum Ansteuern einzelner Player) als Klasse zur Verfügung gestellt.
  23. *
  24. * Verschiedene IPS Benutzer haben die Klasse inzwischen erweitert oder im zuletzt genannten Thread Hinweise zum Handling ausgetauscht.
  25. *
  26. * Paresy released his first version of PHPsonos in this forum thread Einzelne Sonos Player ansteuern. He later build a class and rereleased his routines in this thread: PHP Sonos (Klasse zum Ansteuern einzelner Player).
  27. *
  28. * There is a growing community of sonos enthusiasts supporting and developing PHPSONOS - we share knowledge and developements in this thread PHP Sonos (Klasse zum Ansteuern einzelner Player)
  29. *
  30. *
  31. *
  32. * <br>
  33. * <b>Changelog:</b><br>
  34. * <pre>
  35. *
  36. * - andre added setter functions
  37. * - 110108 - br added comments based on UPNP information from devicespy;
  38. * also added the function XMLsendPacket to get non filtered answers
  39. * - 110120 - br added Set and GetLEDState
  40. * - 110202 - br added GetZoneAttributes
  41. * - 110202 - br added GetZoneInfo
  42. * - 110203 - br added gestposinfo TrackURI (contains x-rincon of the zone master if we are slave)
  43. * - 110206 - br added AddMember(Rincon...) and RemoveMember(Rincon...)
  44. * - 110207 - br added RamptoVolume
  45. * - 110208 - br added calculation of Content-Length to some functions
  46. * - 110318 - br fiddled with Playmode (maybe fixed a bug)
  47. * - 110318 - br added Get and Set CrossfadeMode
  48. * - 110318 - br added SaveQueue
  49. * - 110328 - ta lun added GetPlaylist($value)
  50. * - 110328 - ta lun added GetImportedPlaylists()
  51. * - 110328 - ta lun added GetSonosPlaylists()
  52. * - 110328 - ta lun added GetCurrentPlaylist()
  53. * - 110328 - br corrected titel to title and other things...
  54. * - 110328 - br added optional parameter id to SaveQueue
  55. * - 110406 - br edited Seek to accept UPNP Unit parameter as option (sec. arg is Target then)
  56. * - 110406 - br edited GetPositionInfo to also reflect UPNP return value names
  57. * - 110406 - br fixed non valid soap request in seek()
  58. * - 110406 - br added return of CurrentURI and CurrentUriMetaData to Get (Current File or QUEUE)
  59. This info is needed to restart a queue, pl or radiostation
  60. * - 110407 - br consolidated SetRadio, SetQueue and SetAVTransportURI
  61. the two last now also support MetaData as optional, 2nd parameter; SetRadio supports the name of a radiostation as an optional second parameter
  62. * - 110529 - br GetMediaInfo now returns Radio station in the array, key is title
  63. * - 110529 - ta lun added browse functions
  64. * - 110529 - iamking added GetAlarmTime()
  65. * - 110529 - ta lun fixed misc bugs and GetAlarmTime() now returns an array
  66. * - 110530 - br edited Browse() to reflect upnp possibilities
  67. * - 110601 - br renamed GetAlarmtime to ListAlarms to reflect upnp Names
  68. * - 110601 - iamking improved ListAlarms - added ProgramURI, ProgramMetaData, PlayMode, Volume, IncludeLinkedZones
  69. * - 110614 - br added parameters to Browse / http://www.ip-symcon.de/forum/f53/php-sonos-klasse-ansteuern-einzelner-player-7676/index10.html#post120977
  70. * - 110627 - talun edited GetSonosPlaylists: urlencode file
  71. * - 110711 - br fixed Problems in SetAVTransportUri
  72. * - 110821 - br/talun edited Browse to return duration
  73. * - 110821 - br added GetAudioInputAttributes
  74. * - 110828 - br added Radiotime Radio Cover for GetPositionInfo (patching´in Raditiome Cover URI)
  75. * - 110901 - br shifted Radiotime Functions from getpositioninfo to new Function RadiotimeGetNowPlaying (returns array)
  76. * - 110905 - br fixed Bug in getpositioninfo for getting the actual Track in a playlist (quickfix)
  77. * - 110907 - br deleted, added and edited comment lines
  78. * - 110908 - br added phpdoc tags for documentation
  79. * - 110909 - br found sendpacket commented out in RemoveMember and reenabled the sending now (TEST?!)
  80. * - 110911 - br added phpdoc tags for documentation
  81. * - 110915 - br added PhpSonos API key/ partnerid for Intune (usable for ANYONE who uses the PHPSonos class noncommercial or commercial) - thanks to Ben@tunein for advocation and great support!
  82. * Drop me a note if you are a PHPSonos developer and need access to documentation of tunein APIs.
  83. * - 110916 - br added GetCurrentTransportActions() which returns the currently valid actions (nearly always returns all actions "Play, Stop, Pause, Seek, Next, Previous" for me)...
  84. * - 110916 - br added Get and SetInvisible to make it possible to change visibilty for party mode or other things (kids should not see their player in the night *g)
  85. * - 110916 - br improved phpdoc tags
  86. * - 111021 - br added soap parameters to ramptovolume (function did not work anymore without)
  87. * - 111028 - br added parameters id and parentid to setradio (only very rare use for this)
  88. * - 111130 - br minor improvements: phpdoc tags
  89. * - 120205 - PeterChrisben/br improved phpdoc for setplaymode and gettransportsettings
  90. * </pre>
  91. *
  92. * <b>Links:</b><br>
  93. * {@link http://travelmarx.blogspot.com/2010/06/exploring-sonos-via-upnp.html }<br>
  94. * {@link http://travelmarx.blogspot.com/2011/01/extracting-sonos-playlist-simple-sonos.html }<br>
  95. * {@link http://opentools.homeip.net/dev-tools-for-upnp }<br>
  96. * {@link http://www.ip-symcon.de/forum/f53/php-sonos-klasse-ansteuern-einzelner-player-7676/ }<br>
  97. * {@link http://your.sonos.i.p:1400/status }<br>
  98. * {@link http://your.sonos.i.p1400/support/review }<br>
  99. * {@link http://play.er.i.p:1400/xml/zone_player.xml }<br>
  100. *
  101. * @author Michael Maroszek <office@ip-symcon.de> and many others
  102. * @version see date of edit
  103. * @package PHPSonos
  104. * @copyright original 1.0 version Michael Maroszek; later additions if not otherwise stated are released to public domain
  105. **/
  106. class PHPSonos {
  107. private $address = "";
  108. public function __construct( $address ) {
  109. $this->address = $address;
  110. // Maybe we could integrate/provide some more info here (ZoneAttr / Zoneinfo etc.) ?
  111. }
  112. /*
  113. * urn:schemas-upnp-org:device:ZonePlayer:1
  114. * http://play.er.i.p:1400/xml/zone_player.xml
  115. */
  116. /*
  117. * urn:upnp-org:serviceId:AlarmClock
  118. * Not fully implemented
  119. */
  120. /**
  121. * Returns a list of alarms from sonos device
  122. *
  123. *
  124. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  125. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  126. * - <b>Service:</b> urn:upnp-org:serviceId:AlarmClock
  127. *
  128. * @return Array
  129. *
  130. * @link http://www.ip-symcon.de/forum/f53/php-sonos-klasse-ansteuern-einzelner-player-7676/index9.html#post120731 Forum-Post
  131. */
  132. public function ListAlarms()
  133. {
  134. $header='POST /AlarmClock/Control HTTP/1.1
  135. SOAPACTION: "urn:schemas-upnp-org:service:AlarmClock:1#ListAlarms"
  136. CONTENT-TYPE: text/xml; charset="utf-8"
  137. HOST: '.$this->address.':1400';
  138. $xml='<?xml version="1.0" encoding="utf-8"?> <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  139. xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  140. <s:Body>
  141. <u:AlarmClock xmlns:u="urn:schemas-upnp-org:service:AlarmClock:1"/>
  142. </s:Body>
  143. </s:Envelope>';
  144. $content=$header . '
  145. Content-Length: '. strlen($xml) .'
  146. '. $xml;
  147. $returnContent = $this->XMLsendPacket($content);
  148. $returnContent = substr($returnContent, stripos($returnContent, '&lt;'));
  149. $returnContent = substr($returnContent, 0, strrpos($returnContent, '&gt;') + 4);
  150. $returnContent = str_replace(array("&lt;", "&gt;", "&quot;", "&amp;", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent);
  151. $xmlr = new SimpleXMLElement($returnContent);
  152. $liste = array();
  153. for($i=0,$size=count($xmlr);$i<$size;$i++)
  154. {
  155. $attr = $xmlr->Alarm[$i]->attributes();
  156. $liste[$i]['ID'] = (string)$attr['ID'];
  157. $liste[$i]['StartTime'] = (string)$attr['StartTime'];
  158. $liste[$i]['Duration'] = (string)$attr['Duration'];
  159. $liste[$i]['Recurrence'] = (string)$attr['Recurrence'];
  160. $liste[$i]['Enabled'] = (string)$attr['Enabled'];
  161. $liste[$i]['RoomUUID'] = (string)$attr['RoomUUID'];
  162. $liste[$i]['ProgramURI'] = (string)$attr['ProgramURI'];
  163. $liste[$i]['ProgramMetaData'] = (string)$attr['ProgramMetaData'];
  164. $liste[$i]['PlayMode'] = (string)$attr['PlayMode'];
  165. $liste[$i]['Volume'] = (string)$attr['Volume'];
  166. $liste[$i]['IncludeLinkedZones'] = (string)$attr['IncludeLinkedZones'];
  167. }
  168. return $liste;
  169. }
  170. /**
  171. * Updates an existing alarm
  172. *
  173. *
  174. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  175. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  176. * - <b>Service:</b> urn:upnp-org:serviceId:AlarmClock
  177. * - <b>Returns:</b> None
  178. * - <b>NOTE:</b> fill in
  179. *
  180. * @param string $id Id of the Alarm
  181. * @param string $startzeit StartLocalTime
  182. * @param string $duration Duration
  183. * @param string $welchetage Recurrence
  184. * @param string $an Enabled? (true/false)
  185. * @param string $roomid Room UUID
  186. * @param string $programm ProgramUri
  187. * @param string $programmmeta ProgramMetadata
  188. * @param string $playmode PlayMode
  189. * @param string $volume Volume
  190. * @param string $linkedzone IncludeLinkedZones
  191. *
  192. * @return Void
  193. *
  194. * @link http://www.ip-symcon.de/forum/f53/php-sonos-klasse-ansteuern-einzelner-player-7676/index9.html#post120710 Forum-post
  195. */
  196. public function UpdateAlarm($id, $startzeit, $duration, $welchetage, $an, $roomid, $programm, $programmeta, $playmode, $volume, $linkedzone)
  197. {
  198. $payload = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  199. <s:Body><u:UpdateAlarm xmlns:u="urn:schemas-upnp-org:service:AlarmClock:1">
  200. <ID>'.$id.'</ID>
  201. <StartLocalTime>'.$startzeit.'</StartLocalTime>
  202. <Duration>'.$duration.'</Duration>
  203. <Recurrence>'.$welchetage.'</Recurrence>
  204. <Enabled>'.$an.'</Enabled>
  205. <RoomUUID>'.$roomid.'</RoomUUID>
  206. <ProgramURI>'.htmlspecialchars($programm).'</ProgramURI>
  207. <ProgramMetaData>'.htmlspecialchars($programmeta).'</ProgramMetaData>
  208. <PlayMode>'.$playmode.'</PlayMode>
  209. <Volume>'.$volume.'</Volume>
  210. <IncludeLinkedZones>'.$linkedzone.'</IncludeLinkedZones>
  211. </u:updateAlarm></s:Body></s:Envelope>';
  212. $content='POST /AlarmClock/Control HTTP/1.1
  213. CONNECTION: close
  214. HOST: '.$this->address.':1400
  215. CONTENT-LENGTH: '.strlen($payload).'
  216. CONTENT-TYPE: text/xml; charset="utf-8"
  217. SOAPACTION: "urn:schemas-upnp-org:service:AlarmClock:1#UpdateAlarm"
  218. '.$payload;
  219. $this->sendPacket($content);
  220. }
  221. /* urn:upnp-org:serviceId:AudioIn */
  222. // Not fully implemented
  223. /**
  224. * Get information of devices inputs
  225. *
  226. *
  227. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  228. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  229. * - <b>Service:</b> urn:upnp-org:serviceId:AudioIn
  230. * - <b>Returns:</b> Array
  231. * - <b>NOTE:</b> fill in
  232. *
  233. * @return Array
  234. *
  235. * @link http://www.ip-symcon.de/forum/f53/php-sonos-klasse-ansteuern-einzelner-player-7676/index15.html#post131481 Forum-Post
  236. */
  237. public function GetAudioInputAttributes() // added br
  238. {
  239. $header='POST /AudioIn/Control HTTP/1.1
  240. SOAPACTION: "urn:schemas-upnp-org:service:AudioIn:1#GetAudioInputAttributes"
  241. CONTENT-TYPE: text/xml; charset="utf-8"
  242. HOST: '.$this->address.':1400';
  243. $xml='<?xml version="1.0" encoding="utf-8"?>
  244. <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  245. xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  246. <s:Body>
  247. <u:GetAudioInputAttributes xmlns:u="urn:schemas-upnp-org:service:AudioIn:1"/>
  248. </s:Body>
  249. </s:Envelope>';
  250. $content=$header . '
  251. Content-Length: '. strlen($xml) .'
  252. '. $xml;
  253. $returnContent = $this->XMLsendPacket($content);
  254. $xmlParser = xml_parser_create("UTF-8");
  255. xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
  256. xml_parse_into_struct($xmlParser, $returnContent, $vals, $index);
  257. xml_parser_free($xmlParser);
  258. $AudioInReturn = Array();
  259. $key="CurrentName"; // Lookfor
  260. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$AudioInReturn[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  261. } else { $AudioInReturn[$key] = ""; }
  262. $key="CurrentIcon"; // Lookfor
  263. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$AudioInReturn[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  264. } else { $AudioInReturn[$key] = ""; }
  265. return $AudioInReturn; //Assoziatives Array
  266. }
  267. /* urn:upnp-org:serviceId:DeviceProperties */
  268. /**
  269. * Reads Zone Attributes
  270. *
  271. *
  272. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  273. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  274. * - <b>Service:</b> urn:upnp-org:serviceId:DeviceProperties
  275. * - <b>Returns:</b> Example:
  276. * <code> Array
  277. * (
  278. * [CurrentZoneName] => Kxz Boxyz
  279. * [CurrentIcon] => x-rincon-roomicon:office
  280. * )
  281. * </code>
  282. * @return Array
  283. *
  284. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  285. *
  286. **/
  287. public function GetZoneAttributes() // added br
  288. {
  289. $header='POST /DeviceProperties/Control HTTP/1.1
  290. SOAPACTION: "urn:schemas-upnp-org:service:DeviceProperties:1#GetZoneAttributes"
  291. CONTENT-TYPE: text/xml; charset="utf-8"
  292. HOST: '.$this->address.':1400';
  293. $xml='<?xml version="1.0" encoding="utf-8"?>
  294. <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  295. xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  296. <s:Body>
  297. <u:GetZoneAttributes xmlns:u="urn:schemas-upnp-org:service:DeviceProperties:1"/>
  298. </s:Body>
  299. </s:Envelope>';
  300. $content=$header . '
  301. Content-Length: '. strlen($xml) .'
  302. '. $xml;
  303. $returnContent = $this->XMLsendPacket($content);
  304. $xmlParser = xml_parser_create("UTF-8");
  305. xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
  306. xml_parse_into_struct($xmlParser, $returnContent, $vals, $index);
  307. xml_parser_free($xmlParser);
  308. $ZoneAttributes = Array();
  309. $key="CurrentZoneName"; // Lookfor
  310. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneAttributes[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  311. } else { $ZoneAttributes[$key] = ""; }
  312. $key="CurrentIcon"; // Lookfor
  313. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneAttributes[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  314. } else { $ZoneAttributes[$key] = ""; }
  315. return $ZoneAttributes; //Assoziatives Array
  316. }
  317. /**
  318. * Reads Zone Information
  319. *
  320. *
  321. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  322. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  323. * - <b>Service:</b> urn:upnp-org:serviceId:DeviceProperties
  324. * - <b>Returns:</b> Example:
  325. * <code> Array
  326. * (
  327. * [SerialNumber] => 00-zz-58-32-yy-xx:5
  328. * [SoftwareVersion] => 15.4-442xx
  329. * [DisplaySoftwareVersion] => 3.5.x
  330. * [HardwareVersion] => 1.16.3.z-y
  331. * [IPAddress] => yyy.168.z.xxx
  332. * [MACAddress] => 00:zz:58:32:yy:xx
  333. * [CopyrightInfo] => Š 2004-2007 Sonos, Inc. All Rights Reserved.
  334. * [ExtraInfo] => OTP: 1.1.x(1-yy-3-0.x)
  335. *)
  336. * </code>
  337. *
  338. * @return Array
  339. *
  340. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  341. */
  342. public function GetZoneInfo() // added br
  343. {
  344. $header='POST /DeviceProperties/Control HTTP/1.1
  345. SOAPACTION: "urn:schemas-upnp-org:service:DeviceProperties:1#GetZoneInfo"
  346. CONTENT-TYPE: text/xml; charset="utf-8"
  347. HOST: '.$this->address.':1400';
  348. $xml='<?xml version="1.0" encoding="utf-8"?>
  349. <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  350. xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  351. <s:Body>
  352. <u:GetZoneInfo xmlns:u="urn:schemas-upnp-org:service:DeviceProperties:1"/>
  353. </s:Body>
  354. </s:Envelope>';
  355. $content=$header . '
  356. Content-Length: '. strlen($xml) .'
  357. '. $xml;
  358. $returnContent = $this->XMLsendPacket($content);
  359. $xmlParser = xml_parser_create("UTF-8");
  360. xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
  361. xml_parse_into_struct($xmlParser, $returnContent, $vals, $index);
  362. xml_parser_free($xmlParser);
  363. $ZoneInfo = Array();
  364. $key="SerialNumber"; // Lookfor
  365. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneInfo[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  366. } else { $ZoneInfo[$key] = ""; }
  367. $key="SoftwareVersion"; // Lookfor
  368. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneInfo[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  369. } else { $ZoneInfo[$key] = ""; }
  370. $key="SoftwareVersion"; // Lookfor
  371. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneInfo[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  372. } else { $ZoneInfo[$key] = ""; }
  373. $key="DisplaySoftwareVersion"; // Lookfor
  374. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneInfo[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  375. } else { $ZoneInfo[$key] = ""; }
  376. $key="HardwareVersion"; // Lookfor
  377. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneInfo[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  378. } else { $ZoneInfo[$key] = ""; }
  379. $key="IPAddress"; // Lookfor
  380. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneInfo[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  381. } else { $ZoneInfo[$key] = ""; }
  382. $key="MACAddress"; // Lookfor
  383. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneInfo[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  384. } else { $ZoneInfo[$key] = ""; }
  385. $key="CopyrightInfo"; // Lookfor
  386. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneInfo[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  387. } else { $ZoneInfo[$key] = ""; }
  388. $key="ExtraInfo"; // Lookfor
  389. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneInfo[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  390. } else { $ZoneInfo[$key] = ""; }
  391. return $ZoneInfo; //Assoziatives Array
  392. }
  393. /**
  394. * Sets the state of the white LED
  395. *
  396. *
  397. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  398. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  399. * - <b>Service:</b> urn:upnp-org:serviceId:DeviceProperties
  400. *
  401. * @param string $state true||false value or On / Off
  402. *
  403. * @return Boolean
  404. *
  405. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  406. */
  407. public function SetLEDState($state) // added br
  408. {
  409. if($state=="On") { $state = "On"; } else
  410. { if($state=="Off") { $state = "Off"; } else {
  411. if($state) { $state = "On"; } else { $state = "Off"; }
  412. }
  413. }
  414. $content='POST /DeviceProperties/Control HTTP/1.1
  415. CONNECTION: close
  416. HOST: '.$this->address.':1400
  417. CONTENT-LENGTH: 250
  418. CONTENT-TYPE: text/xml; charset="utf-8"
  419. SOAPACTION: "urn:schemas-upnp-org:service:DeviceProperties:1#SetLEDState"
  420. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetLEDState xmlns:u="urn:schemas-upnp-org:service:DeviceProperties:1"><DesiredLEDState>' .$state. '</DesiredLEDState><u:SetLEDState></s:Body></s:Envelope>';
  421. return (bool)$this->sendPacket($content);
  422. }
  423. /**
  424. * Gets the state of the white LED
  425. *
  426. *
  427. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  428. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  429. * - <b>Service:</b> urn:upnp-org:serviceId:DeviceProperties
  430. *
  431. *
  432. * @return Boolean
  433. *
  434. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  435. */
  436. public function GetLEDState() // added br
  437. {
  438. $content='POST /DeviceProperties/Control HTTP/1.1
  439. CONNECTION: close
  440. HOST: '.$this->address.':1400
  441. CONTENT-LENGTH: 250
  442. CONTENT-TYPE: text/xml; charset="utf-8"
  443. SOAPACTION: "urn:schemas-upnp-org:service:DeviceProperties:1#GetLEDState"
  444. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetLEDState xmlns:u="urn:schemas-upnp-org:service:DeviceProperties:1"><InstanceID>0</InstanceID><u:GetLEDState></s:Body></s:Envelope>';
  445. if ($this->sendPacket($content)=="On") { return(true); }else return(false);
  446. }
  447. /**
  448. * Sets ZP to visible or unvisable
  449. *
  450. *
  451. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  452. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  453. * - <b>Service:</b> urn:upnp-org:serviceId:DeviceProperties
  454. * - <b>Returns:</b> True or False for invisble status
  455. * - <b>NOTE:</b> It is highly *NOT* recommended to try this function if you don´t know what it will do. Don´t cry if you miss a Zoneplayer!!
  456. *
  457. * @param string $state integer true||false value or string True/ False
  458. *
  459. * @return Boolean
  460. *
  461. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  462. */
  463. public function SetInvisible($state) // added br 110916
  464. {
  465. if($state=="True") { $state = "True"; } else
  466. { if($state=="False") { $state = "False"; } else {
  467. if($state) { $state = "True"; } else { $state = "False"; }
  468. }
  469. }
  470. $content='POST /DeviceProperties/Control HTTP/1.1
  471. CONNECTION: close
  472. HOST: '.$this->address.':1400
  473. CONTENT-LENGTH: 250
  474. CONTENT-TYPE: text/xml; charset="utf-8"
  475. SOAPACTION: "urn:schemas-upnp-org:service:DeviceProperties:1#SetInvisible"
  476. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetInvisible xmlns:u="urn:schemas-upnp-org:service:DeviceProperties:1"><DesiredInvisible>' .$state. '</DesiredInvisible><u:SetInvisible></s:Body></s:Envelope>';
  477. return (bool)$this->sendPacket($content);
  478. }
  479. /**
  480. * Gets ZP invisible information
  481. *
  482. *
  483. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  484. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  485. * - <b>Service:</b> urn:upnp-org:serviceId:DeviceProperties
  486. * - <b>Returns:</b> True or False for invisble status
  487. * - <b>NOTE:</b> If you miss a Zoneplayer try this!!
  488. *
  489. * @return Boolean
  490. *
  491. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  492. */
  493. public function GetInvisible() // added br 110916
  494. {
  495. $content='POST /DeviceProperties/Control HTTP/1.1
  496. CONNECTION: close
  497. HOST: '.$this->address.':1400
  498. CONTENT-LENGTH: 250
  499. CONTENT-TYPE: text/xml; charset="utf-8"
  500. SOAPACTION: "urn:schemas-upnp-org:service:DeviceProperties:1#GetInvisible"
  501. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetInvisible xmlns:u="urn:schemas-upnp-org:service:DeviceProperties:1"><InstanceID>0</InstanceID><u:GetInvisible></s:Body></s:Envelope>';
  502. if ($this->sendPacket($content)=="1") { return(true); }else return(false);
  503. }
  504. /* urn:upnp-org:serviceId:GroupManagement */
  505. function SubscribeZPGroupManagement($callback){ // added br
  506. $content='SUBSCRIBE /GroupManagement/Event HTTP/1.1
  507. HOST: '.$this->address.':1400
  508. CALLBACK: <'.$callback.'>
  509. NT: upnp:event
  510. TIMEOUT: Second-300
  511. Content-Length: 0
  512. ';
  513. $this->sendPacket($content);
  514. }
  515. /**
  516. * Adds a Member to a existing ZoneGroup
  517. * (a single player is also considered a existing group)
  518. *
  519. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  520. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  521. * - <b>Service:</b> urn:upnp-org:serviceId:GroupManagement
  522. * - <b>Returns:</b> array with CurrentTransportsettings and GroupUUIDJoined as keys
  523. *
  524. *
  525. * @param string $MemberID LocalUUID/ Rincon of Player to add
  526. *
  527. * @return Array
  528. *
  529. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  530. */
  531. public function AddMember($MemberID) // added br
  532. {
  533. $header='POST /GroupManagement/Control HTTP/1.1
  534. SOAPACTION: "urn:schemas-upnp-org:service:GroupManagement:1#AddMember"
  535. CONTENT-TYPE: text/xml; charset="utf-8"
  536. HOST: '.$this->address.':1400';
  537. $xml='<?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  538. <s:Body><u:AddMember xmlns:u="urn:schemas-upnp-org:service:GroupManagement:1"><MemberID>' . $MemberID . '</MemberID>
  539. </u:AddMember></s:Body></s:Envelope>';
  540. $content=$header . '
  541. Content-Length: '. strlen($xml) .'
  542. '. $xml;
  543. $returnContent = $this->XMLsendPacket($content);
  544. $xmlParser = xml_parser_create("UTF-8");
  545. xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
  546. xml_parse_into_struct($xmlParser, $returnContent, $vals, $index);
  547. xml_parser_free($xmlParser);
  548. $ZoneAttributes = Array();
  549. $key="CurrentTransportSettings"; // Lookfor
  550. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneAttributes[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  551. } else { $ZoneAttributes[$key] = ""; }
  552. $key="GroupUUIDJoined"; // Lookfor
  553. if ( isset($index[strtoupper($key)][0]) and isset($vals[ $index[strtoupper($key)][0] ]['value'])) {$ZoneAttributes[$key] = $vals[ $index[strtoupper($key)][0] ]['value'];
  554. } else { $ZoneAttributes[$key] = ""; }
  555. return $ZoneAttributes; //Assoziatives Array
  556. // set AVtransporturi ist notwendig
  557. }
  558. /**
  559. * Removes a Member from an existing ZoneGroup
  560. * (a single player is also considered an existing group and the action will result in muting the player)
  561. *
  562. * - <b>Device:</b> urn:schemas-upnp-org:device:ZonePlayer:1
  563. * - <b>WSDL:</b> http://play.er.i.p:1400/xml/zone_player.xml
  564. * - <b>Service:</b> urn:upnp-org:serviceId:GroupManagement
  565. * - <b>Returns:</b> for now the sendPacketAnswer
  566. *
  567. * @param string $MemberID LocalUUID/ Rincon of Player to remove
  568. *
  569. * @return Sring
  570. *
  571. * @todo br 20110909 return $this->sendPacket($content); this Line was commented out; i dont understand why... changed this
  572. *
  573. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  574. */
  575. public function RemoveMember($MemberID) // added br
  576. {
  577. $header='POST /GroupManagement/Control HTTP/1.1
  578. SOAPACTION: "urn:schemas-upnp-org:service:GroupManagement:1#RemoveMember"
  579. CONTENT-TYPE: text/xml; charset="utf-8"
  580. HOST: '.$this->address.':1400';
  581. $xml='<?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  582. <s:Body><u:RemoveMember xmlns:u="urn:schemas-upnp-org:service:GroupManagement:1"><MemberID>' . $MemberID . '</MemberID>
  583. </u:RemoveMember></s:Body></s:Envelope>';
  584. $content=$header . '
  585. Content-Length: '. strlen($xml) .'
  586. '. $xml;
  587. return $this->sendPacket($content);
  588. }
  589. /* urn:upnp-org:serviceId:MusicServices */
  590. // Not implemented
  591. /* urn:upnp-org:serviceId:SystemProperties */
  592. // Not implemented
  593. /* urn:upnp-org:serviceId:ZoneGroupTopology */
  594. // Not implemented
  595. /******************* urn:schemas-upnp-org:device:MediaRenderer:1 ***********
  596. ***************************************************************************/
  597. /* urn:upnp-org:serviceId:RenderingControl */
  598. /**
  599. * Ramps Volume to $volume using $ramp_type ; different algorithms are possible
  600. *
  601. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  602. * - <b>WSDL:</b> fill in
  603. * - <b>Service:</b> urn:upnp-org:serviceId:RenderingControl
  604. * - <b>Returns:</b> Function Should return Rampseconds but this is NOT implemented!
  605. * @todo Function Should return Rampseconds but this is NOT implemented!
  606. * @param string $ramp_type Ramp_type<br>
  607. * Ramps Volume to $volume using the Method mentioned in $ramp_type as string:<br>
  608. * "SLEEP_TIMER_RAMP_TYPE" - mutes and ups Volume per default within 17 seconds to desiredVolume<br>
  609. * "ALARM_RAMP_TYPE" -Switches audio off and slowly goes to volume<br>
  610. * "AUTOPLAY_RAMP_TYPE" - very fast and smooth; Implemented from Sonos for the autoplay feature.<br>
  611. *
  612. * @param string $volume DesiredVolume
  613. *
  614. * @return Void
  615. *
  616. *
  617. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  618. */
  619. public function RampToVolume($ramp_type, $volume) //added br // added soap parameters 20111021
  620. {
  621. $header='POST /MediaRenderer/RenderingControl/Control HTTP/1.1
  622. HOST: '.$this->address.':1400
  623. CONTENT-TYPE: text/xml; charset="utf-8"
  624. SOAPACTION: "urn:schemas-upnp-org:service:RenderingControl:1#RampToVolume"
  625. ';
  626. $xml='<?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  627. <s:Body><u:RampToVolume xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"><InstanceID>0</InstanceID><Channel>Master</Channel><RampType>'.$ramp_type.'</RampType><DesiredVolume>'.$volume.'</DesiredVolume>
  628. <ResetVolumeAfter>false</ResetVolumeAfter><ProgramURI></ProgramURI>
  629. </u:RampToVolume></s:Body></s:Envelope>';
  630. $content=$header . 'Content-Length: '. strlen($xml) .'
  631. '. $xml;
  632. return (int) $this->sendPacket($content);
  633. }
  634. /* urn:upnp-org:serviceId:AVTransport */
  635. /**
  636. * TEST Function for MediaRenderAVT Callback and IPS Register Vars
  637. *
  638. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  639. * - <b>WSDL:</b> fill in
  640. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1 none
  641. * - <b>Returns:</b> Sendpacket contents
  642. *
  643. * @param string $callback CallbackURL Well gat a HTTP Callback at this URl (SOAP)
  644. * @return Void
  645. */
  646. function SubscribeMRAVTransport($callback){ // added br
  647. $content='SUBSCRIBE /MediaRenderer/AVTransport/Event HTTP/1.1
  648. HOST: '.$this->address.':1400
  649. CALLBACK: <'.$callback.'>
  650. NT: upnp:event
  651. TIMEOUT: Second-300
  652. Content-Length: 0
  653. ';
  654. $this->sendPacket($content);
  655. }
  656. /**
  657. * Save current queue off to sonos
  658. *
  659. * - <b>NOTE:</b> If you don´t set the id to the playlist´s id you want to edit, you´ll get duplicate playlists with the same name $title!!
  660. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  661. * - <b>WSDL:</b> fill in
  662. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  663. * - <b>Returns:</b> Sendpacket contents
  664. *
  665. *
  666. * @param string $title Title of Playlist
  667. * @param string $id Playlists ID (optional)
  668. *
  669. * @return string
  670. *
  671. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  672. */
  673. public function SaveQueue($title,$id="") // added br
  674. {
  675. $header='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  676. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SaveQueue"
  677. CONTENT-TYPE: text/xml; charset="utf-8"
  678. HOST: '.$this->address.':1400';
  679. $xml='<?xml version="1.0" encoding="utf-8"?>
  680. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body>
  681. <u:SaveQueue xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><Title>'.$title.'</Title><ObjectID>'.$id.'</ObjectID></u:SaveQueue>
  682. </s:Body>
  683. </s:Envelope>';
  684. $content=$header . '
  685. Content-Length: '. strlen($xml) .'
  686. '. $xml;
  687. $returnContent = $this->sendPacket($content);
  688. }
  689. /**
  690. * Get info on actual crossfademode
  691. *
  692. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  693. * - <b>WSDL:</b> fill in
  694. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  695. * - <b>Returns:</b> Boolean
  696. *
  697. *
  698. * @return Boolean
  699. */
  700. public function GetCrossfadeMode() // added br
  701. {
  702. $header='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  703. HOST: '.$this->address.':1400
  704. CONTENT-TYPE: text/xml; charset="utf-8"
  705. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#GetCrossfadeMode"
  706. ';
  707. $xml='<?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  708. <s:Body><u:GetCrossfadeMode xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID>
  709. </u:GetCrossfadeMode></s:Body></s:Envelope>';
  710. $content=$header . 'Content-Length: '. strlen($xml) .'
  711. '. $xml;
  712. return (bool)$this->sendPacket($content);
  713. }
  714. /**
  715. * Set crossfade to true or false
  716. *
  717. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  718. * - <b>WSDL:</b> fill in
  719. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  720. * - <b>Returns:</b> Void; shoud return sendpacket return
  721. *
  722. * @param string $mode Enable/ Disable = 1/0 (string) = true /false (boolean)
  723. *
  724. * @return Void
  725. *
  726. * @link http://www.ip-symcon.de/wiki/PHPSonos Wiki
  727. */
  728. public function SetCrossfadeMode($mode) // added br
  729. {
  730. if($mode) { $mode = "1"; } else { $mode = "0"; }
  731. $header='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  732. HOST: '.$this->address.':1400
  733. CONTENT-TYPE: text/xml; charset="utf-8"
  734. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetCrossfadeMode"
  735. ';
  736. $xml='<?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  737. <s:Body><u:SetCrossfadeMode xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><CrossfadeMode>'.$mode.'</CrossfadeMode></u:SetCrossfadeMode></u:SetCrossfadeMode></s:Body></s:Envelope>';
  738. $content=$header . 'Content-Length: '. strlen($xml) .'
  739. '. $xml;
  740. $this->sendPacket($content);
  741. }
  742. /**
  743. * STOP Stops playback
  744. *
  745. * - <b>NOTE:</b> It is sometimes necessary to send a stop after removing a zone from a group
  746. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  747. * - <b>WSDL:</b> fill in
  748. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  749. * - <b>Returns:</b> Void
  750. * @todo return should be sendpacket contents
  751. *
  752. * @return Void
  753. */
  754. public function Stop()
  755. {
  756. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  757. CONNECTION: close
  758. HOST: '.$this->address.':1400
  759. CONTENT-LENGTH: 250
  760. CONTENT-TYPE: text/xml; charset="utf-8"
  761. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Stop"
  762. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Stop xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:Stop></s:Body></s:Envelope>';
  763. $this->sendPacket($content);
  764. }
  765. /**
  766. * PAUSE pauses playback
  767. *
  768. * - <b>NOTE:</b> It is NOT always possible to send a PAUSE command (so you may get an error)!!
  769. * Please look at the Soap Method GetCurrentTransportActions (which returns valid actions)
  770. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  771. * - <b>WSDL:</b> fill in
  772. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  773. * - <b>Returns:</b> Void
  774. * @todo return should be sendpacket contents
  775. *
  776. * @return Void
  777. */
  778. public function Pause()
  779. {
  780. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  781. CONNECTION: close
  782. HOST: '.$this->address.':1400
  783. CONTENT-LENGTH: 252
  784. CONTENT-TYPE: text/xml; charset="utf-8"
  785. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Pause"
  786. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Pause xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:Pause></s:Body></s:Envelope>';
  787. $this->sendPacket($content);
  788. }
  789. /**
  790. * PLAY plays or continues playback
  791. *
  792. * - <b>NOTE:</b> It is sometimes necessary to send a play after messing with zonegroups and/or starting a new play on a new uri
  793. * Please look at the Soap Method GetCurrentTransportActions (which returns valid actions)
  794. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  795. * - <b>WSDL:</b> fill in
  796. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  797. * - <b>Returns:</b> Void; shoud be sendpacket contents
  798. *
  799. * @return Void
  800. */
  801. public function Play()
  802. {
  803. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  804. CONNECTION: close
  805. HOST: '.$this->address.':1400
  806. CONTENT-LENGTH: 266
  807. CONTENT-TYPE: text/xml; charset="utf-8"
  808. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Play"
  809. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><Speed>1</Speed></u:Play></s:Body></s:Envelope>';
  810. $this->sendPacket($content);
  811. }
  812. /**
  813. * NEXT
  814. *
  815. * - <b>NOTE:</b> Please look at the Soap Method GetCurrentTransportActions (which returns valid actions)
  816. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  817. * - <b>WSDL:</b> fill in
  818. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  819. * - <b>Returns:</b> Void; shoud be sendpacket contents
  820. *
  821. * @return Void
  822. */
  823. public function Next()
  824. {
  825. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  826. CONNECTION: close
  827. HOST: '.$this->address.':1400
  828. CONTENT-LENGTH: 250
  829. CONTENT-TYPE: text/xml; charset="utf-8"
  830. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Next"
  831. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Next xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:Next></s:Body></s:Envelope>';
  832. $this->sendPacket($content);
  833. }
  834. /**
  835. * PREVIOUS
  836. *
  837. * - <b>NOTE:</b> Please look at the Soap Method GetCurrentTransportActions (which returns valid actions)
  838. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  839. * - <b>WSDL:</b> fill in
  840. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  841. * - <b>Returns:</b> Void; shoud be sendpacket contents
  842. *
  843. * @return Void
  844. */
  845. public function Previous()
  846. {
  847. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  848. CONNECTION: close
  849. HOST: '.$this->address.':1400
  850. CONTENT-LENGTH: 258
  851. CONTENT-TYPE: text/xml; charset="utf-8"
  852. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Previous"
  853. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Previous xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:Previous></s:Body></s:Envelope>';
  854. $this->sendPacket($content);
  855. }
  856. /**
  857. * SEEK
  858. *
  859. * - <b>NOTE:</b> Please look at the Soap Method GetCurrentTransportActions (which returns valid actions)
  860. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  861. * - <b>WSDL:</b> fill in
  862. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  863. * - <b>Returns:</b> String; shoud be sendpacket contents as array
  864. *
  865. * @param string $arg1 Unit ("TRACK_NR" || "REL_TIME" || "SECTION")
  866. * @param string $arg2 Target (if this Arg is not set Arg1 is considered to be "REL_TIME and the real arg1 value is set as arg2 value)
  867. *
  868. * @return String
  869. */
  870. public function Seek($arg1,$arg2="NONE")
  871. {
  872. // Abwärtskompatibel zu Paresys Original sein // edited by br
  873. if ($arg2=="NONE"){
  874. $Unit="REL_TIME"; $position=$arg1;
  875. } else {$Unit=$arg1; $position=$arg2;}
  876. $header='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  877. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Seek"
  878. CONTENT-TYPE: text/xml; charset="utf-8"
  879. CONNECTION: close
  880. HOST: '.$this->address.':1400';
  881. $xml='<?xml version="1.0" encoding="utf-8"?>
  882. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Seek xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><Unit>'. $Unit .'</Unit><Target>'.$position.'</Target></u:Seek></s:Envelope></s:Body></s:Envelope>';
  883. $content=$header . '
  884. Content-Length: '. strlen($xml) .'
  885. '. $xml;
  886. $returnContent = $this->sendPacket($content);
  887. }
  888. /**
  889. * REWIND
  890. *
  891. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  892. * - <b>WSDL:</b> fill in
  893. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  894. * - <b>Returns:</b> String
  895. * @todo should be sendpacket Return
  896. *
  897. * - <b>SOAP</b> this Functions calls seek REL_TIME with target set to 00:00:00
  898. * There is a also a function called previous.
  899. *
  900. * @return String
  901. */
  902. public function Rewind()
  903. {
  904. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  905. CONNECTION: close
  906. HOST: '.$this->address.':1400
  907. CONTENT-LENGTH: 296
  908. CONTENT-TYPE: text/xml; charset="utf-8"
  909. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Seek"
  910. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Seek xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><Unit>REL_TIME</Unit><Target>00:00:00</Target></u:Seek></s:Body></s:Envelope>';
  911. $this->sendPacket($content);
  912. }
  913. /**
  914. * Sets volume for a player
  915. *
  916. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  917. * - <b>WSDL:</b> fill in
  918. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  919. * - <b>Returns:</b> String; sendpacket Return
  920. *
  921. *
  922. * @param string $volume Volume in percent
  923. *
  924. * @return String
  925. */
  926. public function SetVolume($volume)
  927. {
  928. $content='POST /MediaRenderer/RenderingControl/Control HTTP/1.1
  929. CONNECTION: close
  930. HOST: '.$this->address.':1400
  931. CONTENT-LENGTH: 32'.strlen($volume).'
  932. CONTENT-TYPE: text/xml; charset="utf-8"
  933. SOAPACTION: "urn:schemas-upnp-org:service:RenderingControl:1#SetVolume"
  934. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetVolume xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"><InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>'.$volume.'</DesiredVolume></u:SetVolume></s:Body></s:Envelope>';
  935. $this->sendPacket($content);
  936. }
  937. /**
  938. * Gets current volume information from player
  939. *
  940. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  941. * - <b>WSDL:</b> fill in
  942. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  943. * - <b>Returns:</b> String; sendpacket Return
  944. *
  945. * @return String
  946. */
  947. public function GetVolume()
  948. {
  949. $content='POST /MediaRenderer/RenderingControl/Control HTTP/1.1
  950. CONNECTION: close
  951. HOST: '.$this->address.':1400
  952. CONTENT-LENGTH: 290
  953. CONTENT-TYPE: text/xml; charset="utf-8"
  954. SOAPACTION: "urn:schemas-upnp-org:service:RenderingControl:1#GetVolume"
  955. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetVolume xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"><InstanceID>0</InstanceID><Channel>Master</Channel></u:GetVolume></s:Body></s:Envelope>';
  956. return (int)$this->sendPacket($content);
  957. }
  958. /**
  959. * Sets mute/ unmute for a player
  960. *
  961. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  962. * - <b>WSDL:</b> fill in
  963. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  964. * - <b>Returns:</b> String; sendpacket Return
  965. *
  966. * @param string $mute Mute unmute as (boolean)true/false or (string)1/0
  967. *
  968. * @return String
  969. */
  970. public function SetMute($mute)
  971. {
  972. if($mute) { $mute = "1"; } else { $mute = "0"; }
  973. $content='POST /MediaRenderer/RenderingControl/Control HTTP/1.1
  974. CONNECTION: close
  975. HOST: '.$this->address.':1400
  976. CONTENT-LENGTH: 314
  977. CONTENT-TYPE: text/xml; charset="utf-8"
  978. SOAPACTION: "urn:schemas-upnp-org:service:RenderingControl:1#SetMute"
  979. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetMute xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"><InstanceID>0</InstanceID><Channel>Master</Channel><DesiredMute>'.$mute.'</DesiredMute></u:SetMute></s:Body></s:Envelope>';
  980. $this->sendPacket($content);
  981. }
  982. /**
  983. * Gets mute/ unmute status for a player
  984. *
  985. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  986. * - <b>WSDL:</b> fill in
  987. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  988. * - <b>Returns:</b> String; sendpacket Return
  989. *
  990. * @return string
  991. */
  992. public function GetMute()
  993. {
  994. $content='POST /MediaRenderer/RenderingControl/Control HTTP/1.1
  995. CONNECTION: close
  996. HOST: '.$this->address.':1400
  997. CONTENT-LENGTH: 286
  998. CONTENT-TYPE: text/xml; charset="utf-8"
  999. SOAPACTION: "urn:schemas-upnp-org:service:RenderingControl:1#GetMute"
  1000. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetMute xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"><InstanceID>0</InstanceID><Channel>Master</Channel></u:GetMute></s:Body></s:Envelope>';
  1001. return (bool)$this->sendPacket($content);
  1002. }
  1003. /**
  1004. * Sets Playmode for a renderer (could affect more than one zone!)
  1005. *
  1006. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1007. * - <b>WSDL:</b> fill in
  1008. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1009. * - <b>Returns:</b> String; sendpacket Return
  1010. * - <b>NOTE:</b>
  1011. * <PRE>
  1012. * NORMAL = SHUFFLE and REPEAT -->FALSE
  1013. * REPEAT_ALL = REPEAT --> TRUE, Shuffle --> FALSE
  1014. * SHUFFLE_NOREPEAT = SHUFFLE -->TRUE / REPEAT = FALSE
  1015. * SHUFFLE = SHUFFLE and REPEAT -->TRUE </PRE>
  1016. *
  1017. * @param string $mode "NORMAL" || "REPEAT_ALL" || "SHUFFLE_NOREPEAT" || "SHUFFLE"
  1018. *
  1019. * @return String
  1020. */
  1021. public function SetPlayMode($mode)
  1022. {
  1023. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1024. CONNECTION: close
  1025. HOST: '.$this->address.':1400
  1026. CONTENT-LENGTH: '.(291+strlen($mode)).'
  1027. CONTENT-TYPE: text/xml; charset="utf-8"
  1028. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetPlayMode"
  1029. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetPlayMode xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><NewPlayMode>'.$mode.'</NewPlayMode></u:SetPlayMode></s:Body></s:Envelope>';
  1030. $this->sendPacket($content);
  1031. }
  1032. /**
  1033. * Gets transport settings for a renderer
  1034. *
  1035. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1036. * - <b>WSDL:</b> fill in
  1037. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1038. * - <b>Returns:</b> Array with "repeat" and "shuffle" as keys and true/false as value
  1039. * - <b>NOTE:</b>
  1040. * <PRE>
  1041. * SOAP return sometimes is PLAYING; I don´t know what this means, maybe only Radio (see the code below).
  1042. *
  1043. * NORMAL = SHUFFLE and REPEAT -->FALSE
  1044. * REPEAT_ALL = REPEAT --> TRUE, Shuffle --> FALSE
  1045. * SHUFFLE_NOREPEAT = SHUFFLE -->TRUE / REPEAT = FALSE
  1046. * SHUFFLE = SHUFFLE and REPEAT -->TRUE </PRE>
  1047. *
  1048. * @todo: what is PLAYING??? TAG_NOTE_BR
  1049. *
  1050. * @return Array
  1051. */
  1052. public function GetTransportSettings()
  1053. {
  1054. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1055. CONNECTION: close
  1056. HOST: '.$this->address.':1400
  1057. CONTENT-LENGTH: 282
  1058. CONTENT-TYPE: text/xml; charset="utf-8"
  1059. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#GetTransportSettings"
  1060. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetTransportSettings xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:GetTransportSettings></s:Body></s:Envelope>';
  1061. $returnContent = $this->sendPacket($content);
  1062. // echo "\n===" . $this->address. "====\n" . $returnContent . "\n===\n";
  1063. if (strstr($returnContent, "NORMAL") !== false) {
  1064. return Array (
  1065. "repeat" => false,
  1066. "shuffle" => false
  1067. );
  1068. } elseif (strstr($returnContent, "REPEAT_ALL") !== false) {
  1069. return Array (
  1070. "repeat" => true,
  1071. "shuffle" => false
  1072. );
  1073. } elseif (strstr($returnContent, "SHUFFLE_NOREPEAT") !== false) {
  1074. return Array (
  1075. "repeat" => false,
  1076. "shuffle" => true
  1077. );
  1078. } elseif (strstr($returnContent, "SHUFFLE") !== false) {
  1079. return Array (
  1080. "repeat" => true,
  1081. "shuffle" => true
  1082. );
  1083. }
  1084. /* } elseif (strstr($returnContent, "PLAYING") !== false) {
  1085. return Array (
  1086. "repeat" => false,
  1087. "shuffle" => true
  1088. );
  1089. } */
  1090. }
  1091. /**
  1092. * Gets transport settings for a renderer
  1093. *
  1094. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1095. * - <b>WSDL:</b> fill in
  1096. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1097. * - <b>Returns:</b> String (comma sep.) with available actions
  1098. * - <b>NOTE:</b>
  1099. *
  1100. * @return String
  1101. */
  1102. public function GetCurrentTransportActions()
  1103. {
  1104. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1105. CONNECTION: close
  1106. HOST: '.$this->address.':1400
  1107. CONTENT-LENGTH: 282
  1108. CONTENT-TYPE: text/xml; charset="utf-8"
  1109. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#GetCurrentTransportActions"
  1110. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetCurrentTransportActions xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:GetCurrentTransportActions></s:Body></s:Envelope>';
  1111. $returnContent = $this->sendPacket($content);
  1112. // echo "\n===" . $this->address. "====\n" . $returnContent . "\n===\n";
  1113. $ret=preg_replace("#(.*)<Actions>(.*?)\</Actions>(.*)#is",'$2',$returnContent);
  1114. return $ret;
  1115. }
  1116. /**
  1117. * Gets transport settings for a renderer
  1118. *
  1119. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1120. * - <b>WSDL:</b> fill in
  1121. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1122. * - <b>Returns:</b> Array with "repeat" and "shuffle" as keys and true/false as value
  1123. * - <b>NOTE:</b> SOAP return sometimes is PLAYING; I don´t know what this means, maybe only Radio (see the code below).
  1124. *
  1125. * @return Array
  1126. */
  1127. public function GetTransportInfo()
  1128. {
  1129. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1130. CONNECTION: close
  1131. HOST: '.$this->address.':1400
  1132. CONTENT-LENGTH: 274
  1133. CONTENT-TYPE: text/xml; charset="utf-8"
  1134. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#GetTransportInfo"
  1135. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetTransportInfo xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:GetTransportInfo></s:Body></s:Envelope>';
  1136. $returnContent = $this->sendPacket($content);
  1137. if (strstr($returnContent, "PLAYING") !== false) {
  1138. return 1;
  1139. } elseif (strstr($returnContent, "PAUSED_PLAYBACK") !== false) {
  1140. return 2;
  1141. } elseif (strstr($returnContent, "STOPPED") !== false) {
  1142. return 3;
  1143. }
  1144. }
  1145. /**
  1146. * Gets Media Info
  1147. *
  1148. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1149. * - <b>WSDL:</b> fill in
  1150. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1151. * - <b>Returns:</b>
  1152. * <code>
  1153. * Array (
  1154. * [CurrentURI] => http://192.168.0.2:10243/WMPNSSv4/1458092455/0_ezg1ODYxQzMwLTEyNzgtNDc0Ri05MkQ0LTQxNzE1MDQ0MjMyMX0uMC40.mp3
  1155. * [CurrentURIMetaData] => <DIDL-Lite 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/"> <item id="{85861C30-1278-474F-92D4-417150442321}.0.4" restricted="0" parentID="4"> <dc:title>Car Crazy Cutie</dc:title> <dc:creator>Beach Boys</dc:creator> <res size="2753092" duration="0:02:50.000" bitrate="16000" protocolInfo="http-get:*:audio/mpeg:DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01500000000000000000000000000000" sampleFrequency="44100" bitsPerSample="16" nrAudioChannels="2" microsoft:codec="{00000055-0000-0010-8000-00AA00389B71}" xmlns:microsoft="urn:schemas-microsoft-com:WMPNSS-1-0/">http://192.168.0.2:10243/WMPNSSv4/1458092455/0_ezg1ODYxQzMwLTEyNzgtNDc0Ri05MkQ0LTQxNzE1MDQ0MjMyMX0uMC40.mp3</res> <res duration="0:02:50.000" bitrate="16000" protocolInfo="http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=10;DLNA.ORG_CI=1;DLNA.ORG_FLAGS=01500000000000000000000000000000" sampleFrequency="44100" nrAudioChannels="1" microso
  1156. * [title] => Car Crazy Cutie )
  1157. * </code>
  1158. *
  1159. * - <b>NOTE:</b> SOAP returns CurrentURIMetaData this has to be parsed
  1160. *
  1161. * @return Array
  1162. */
  1163. public function GetMediaInfo()
  1164. {
  1165. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1166. CONNECTION: close
  1167. HOST: '.$this->address.':1400
  1168. CONTENT-LENGTH: 266
  1169. CONTENT-TYPE: text/xml; charset="utf-8"
  1170. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#GetMediaInfo"
  1171. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetMediaInfo xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:GetMediaInfo></s:Body></s:Envelope>';
  1172. $returnContent = $this->XMLsendPacket($content);
  1173. $xmlParser = xml_parser_create("UTF-8");
  1174. //xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
  1175. xml_parse_into_struct($xmlParser, $returnContent, $vals, $index);
  1176. xml_parser_free($xmlParser);
  1177. $mediaInfo = Array();
  1178. if (isset($vals[$index["CURRENTURI"][0]]["value"])) {
  1179. $mediaInfo["CurrentURI"] = $vals[$index["CURRENTURI"][0]]["value"];
  1180. } else {
  1181. $mediaInfo["CurrentURI"] = "";
  1182. }
  1183. if (isset($vals[$index["CURRENTURIMETADATA"][0]]["value"])) {
  1184. $mediaInfo["CurrentURIMetaData"] = $vals[$index["CURRENTURIMETADATA"][0]]["value"];
  1185. // print_r($index);
  1186. // print_r($vals);
  1187. $xmlParser = xml_parser_create("UTF-8");
  1188. //xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
  1189. xml_parse_into_struct($xmlParser, $mediaInfo["CurrentURIMetaData"], $vals, $index);
  1190. xml_parser_free($xmlParser);
  1191. //print_r($index);
  1192. //print_r($vals);
  1193. if (isset($index["DC:TITLE"]) and isset($vals[$index["DC:TITLE"][0]]["value"])) {
  1194. $mediaInfo["title"] = $vals[$index["DC:TITLE"][0]]["value"];
  1195. } else {
  1196. $mediaInfo["title"] = "";
  1197. }
  1198. } else {
  1199. $mediaInfo["CurrentURIMetaData"] = "";
  1200. }
  1201. return $mediaInfo;
  1202. }
  1203. /**
  1204. * Gets position info
  1205. *
  1206. * - <b>NOTE:</b> this is one of the most interesting and complex functions with most interesting informations! You may get radio and zonegroup info out of parsing this information!
  1207. *
  1208. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1209. * - <b>WSDL:</b> fill in
  1210. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1211. * - <b>Returns:</b> Example:
  1212. * <code> Array
  1213. * (
  1214. * [position] => 0:00:59
  1215. * [RelTime] => 0:00:59
  1216. * [duration] => 0:01:51
  1217. * [TrackDuration] => 0:01:51
  1218. * [URI] => http://zzz.yyy.0.x:10243/WMPNSSv4/1458092455/0_ezRENTU5NjFDLUE3MDctNDIwRC04NTc4LUFDODgxQTVFMzMxQX0uMC40.mp3
  1219. * [TrackURI] => http://192.168.0.x:10243/WMPNSSv4/1458092455/0_ezRENTU5NjFDLUE3MDctNDIwRC04NTc4LUFDODgxQTVFMzMxQX0uMC40.mp3
  1220. * [artist] => Beach Bxxx....
  1221. * [title] => Cher... What?
  1222. * [album] => Little Deuce...
  1223. * [albumArtURI] => http://zzz.168.y.xxx:1400/getaa?u=http://zzz.168.y.xxx:10243/WMPNSSv4/1458092455/0_ezRENTU5NjFDLUE3MDctNDIwRC04NTc4LUFDODgxQTVFMzMxQX0uMC40.mp3&v=279
  1224. * [albumArtist] => Beach xxx....
  1225. * [albumTrackNumber] => 5
  1226. * [streamContent] =>
  1227. * [trackURI] =>
  1228. * [Track] => 1
  1229. * ) </code>
  1230. *
  1231. * @return Array
  1232. */
  1233. public function GetPositionInfo()
  1234. {
  1235. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1236. CONNECTION: close
  1237. HOST: '.$this->address.':1400
  1238. CONTENT-LENGTH: 272
  1239. CONTENT-TYPE: text/xml; charset="utf-8"
  1240. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#GetPositionInfo"
  1241. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetPositionInfo xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:GetPositionInfo></s:Body></s:Envelope>';
  1242. $returnContent = $this->sendPacket($content);
  1243. $position = substr($returnContent, stripos($returnContent, "NOT_IMPLEMENTED") - 7, 7);
  1244. $returnContent = substr($returnContent, stripos($returnContent, '&lt;'));
  1245. $returnContent = substr($returnContent, 0, strrpos($returnContent, '&gt;') + 4);
  1246. $returnContent = str_replace(array("&lt;", "&gt;", "&quot;", "&amp;", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent);
  1247. $xmlParser = xml_parser_create("UTF-8");
  1248. xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "UTF-8");
  1249. xml_parse_into_struct($xmlParser, $returnContent, $vals, $index);
  1250. xml_parser_free($xmlParser);
  1251. $positionInfo = Array ();
  1252. $positionInfo["position"] = $position;
  1253. $positionInfo["RelTime"] = $position;
  1254. if (isset($index["RES"]) and isset($vals[$index["RES"][0]]["attributes"]["DURATION"])) {
  1255. $positionInfo["duration"] = $vals[$index["RES"][0]]["attributes"]["DURATION"];
  1256. $positionInfo["TrackDuration"] = $vals[$index["RES"][0]]["attributes"]["DURATION"];
  1257. } else {
  1258. $positionInfo["duration"] = "";
  1259. $positionInfo["TrackDuration"] = "";
  1260. }
  1261. if (isset($index["RES"]) and isset($vals[$index["RES"][0]]["value"])) {
  1262. $positionInfo["URI"] = $vals[$index["RES"][0]]["value"];
  1263. $positionInfo["TrackURI"] = $vals[$index["RES"][0]]["value"];
  1264. } else {
  1265. $positionInfo["URI"] = "";
  1266. $positionInfo["TrackURI"] = "";
  1267. }
  1268. if (isset($index["DC:CREATOR"]) and isset($vals[$index["DC:CREATOR"][0]]["value"])) {
  1269. $positionInfo["artist"] = $vals[$index["DC:CREATOR"][0]]["value"];
  1270. } else {
  1271. $positionInfo["artist"] = "";
  1272. }
  1273. if (isset($index["DC:TITLE"]) and isset($vals[$index["DC:TITLE"][0]]["value"])) {
  1274. $positionInfo["title"] = $vals[$index["DC:TITLE"][0]]["value"];
  1275. } else {
  1276. $positionInfo["title"] = "";
  1277. }
  1278. if (isset($index["UPNP:ALBUM"]) and isset($vals[$index["UPNP:ALBUM"][0]]["value"])) {
  1279. $positionInfo["album"] = $vals[$index["UPNP:ALBUM"][0]]["value"];
  1280. } else {
  1281. $positionInfo["album"] = "";
  1282. }
  1283. if (isset($index["UPNP:ALBUMARTURI"]) and isset($vals[$index["UPNP:ALBUMARTURI"][0]]["value"])) {
  1284. $positionInfo["albumArtURI"] = "http://" . $this->address . ":1400" . $vals[$index["UPNP:ALBUMARTURI"][0]]["value"];
  1285. } else {
  1286. /*
  1287. // Ask Radiotime (added br as a test)
  1288. $mi=$this->GetMediaInfo();
  1289. $station=preg_replace("#(.*)x-sonosapi-stream:(.*?)\?sid(.*)#is",'$2',$mi['CurrentURI']);
  1290. // echo "\n!!!!!!!!!!!!!!!!!!!!!!!!!!".$station."########\n";
  1291. if (($station!="")and $station[0]=="s"){
  1292. $content = @file_get_contents("http://opml.radiotime.com/Describe.ashx?c=nowplaying&id=".$station."&partnerId=Sonos&serial=00-0E-58-25-41-12:4");
  1293. // echo "----". $content;
  1294. $albumArtURI=preg_replace("#(.*)<LOGO>(.*?)\</LOGO>(.*)#is",'$2',$content);
  1295. // echo $albumArtURI;
  1296. $positionInfo["albumArtURI"] = $albumArtURI;
  1297. } else{
  1298. */
  1299. $positionInfo["albumArtURI"] = "";
  1300. /* }
  1301. */
  1302. }
  1303. if (isset($index["R:ALBUMARTIST"]) and isset($vals[$index["R:ALBUMARTIST"][0]]["value"])) {
  1304. $positionInfo["albumArtist"] = $vals[$index["R:ALBUMARTIST"][0]]["value"];
  1305. } else {
  1306. $positionInfo["albumArtist"] = "";
  1307. }
  1308. if (isset($index["UPNP:ORIGINALTRACKNUMBER"]) and isset($vals[$index["UPNP:ORIGINALTRACKNUMBER"][0]]["value"])) {
  1309. $positionInfo["albumTrackNumber"] = $vals[$index["UPNP:ORIGINALTRACKNUMBER"][0]]["value"];
  1310. } else {
  1311. $positionInfo["albumTrackNumber"] = "";
  1312. }
  1313. if (isset($index["R:STREAMCONTENT"]) and isset($vals[$index["R:STREAMCONTENT"][0]]["value"])) {
  1314. $positionInfo["streamContent"] = $vals[$index["R:STREAMCONTENT"][0]]["value"];
  1315. } else {
  1316. $positionInfo["streamContent"] = "";
  1317. }
  1318. // added br if this contains "rincon" we are slave to a coordinator mentioned in this field (otherwise path to the file is provided)!
  1319. // implemented via second XMLsendpacket to not break michaels current code
  1320. if (isset($index["RES"][0]) and isset($vals[($index["RES"][0])]["value"])) {
  1321. $positionInfo["trackURI"] = $vals[($index["RES"][0])]["value"];
  1322. } else {
  1323. $returnContent = $this->XMLsendPacket($content);
  1324. $xmlParser = xml_parser_create("UTF-8");
  1325. xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
  1326. xml_parse_into_struct($xmlParser, $returnContent, $vals, $index);
  1327. xml_parser_free($xmlParser);
  1328. }
  1329. if (isset($index["TRACKURI"][0]) and isset($vals[($index["TRACKURI"][0])]["value"])) {
  1330. $positionInfo["trackURI"] = $vals[($index["TRACKURI"][0])]["value"];
  1331. $positionInfo["TrackURI"] = $vals[($index["TRACKURI"][0])]["value"];
  1332. } else {
  1333. $positionInfo["trackURI"] = "";
  1334. }
  1335. // Track Number in Playlist
  1336. $returnContent = $this->XMLsendPacket($content);
  1337. $xmlParser = xml_parser_create("UTF-8");
  1338. xml_parser_set_option($xmlParser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
  1339. xml_parse_into_struct($xmlParser, $returnContent, $vals, $index);
  1340. xml_parser_free($xmlParser);
  1341. if (isset($index["TRACK"][0]) and isset($vals[($index["TRACK"][0])]["value"])) {
  1342. $positionInfo["Track"] = $vals[($index["TRACK"][0])]["value"];
  1343. } else {
  1344. $positionInfo["Track"] = "";
  1345. }
  1346. return $positionInfo;
  1347. }
  1348. /**
  1349. * Play Radio station
  1350. *
  1351. * - <b>NOTE:</b> This is only a SetAVTransportURI Wrapper to switch to a radio station
  1352. *
  1353. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1354. * - <b>WSDL:</b> fill in
  1355. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1356. * - <b>Returns:</b> Array with $radio and $ MetaData as key
  1357. *
  1358. * @param string $radio radio url
  1359. * @param string $Name Name of station (optional, default IP-Symcon Radio)
  1360. * @param string $id ID of Station (optional, default R:0/0/0)
  1361. * @param string $parentID parentID (optional, default R:0/0)
  1362. * @return array
  1363. */
  1364. public function SetRadio($radio,$Name="IP-Symcon Radio",$id="R:0/0/0",$parentID="R:0/0")
  1365. {
  1366. $MetaData="&lt;DIDL-Lite xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:upnp=&quot;urn:schemas-upnp-org:metadata-1-0/upnp/&quot; xmlns:r=&quot;urn:schemas-rinconnetworks-com:metadata-1-0/&quot; xmlns=&quot;urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/&quot;&gt;&lt;item id=&quot;".$id."&quot; parentID=&quot;".$parentID."&quot; restricted=&quot;true&quot;&gt;&lt;dc:title&gt;".$Name."&lt;/dc:title&gt;&lt;upnp:class&gt;object.item.audioItem.audioBroadcast&lt;/upnp:class&gt;&lt;desc id=&quot;cdudn&quot; nameSpace=&quot;urn:schemas-rinconnetworks-com:metadata-1-0/&quot;&gt;SA_RINCON65031_&lt;/desc&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;";
  1367. $this->SetAVTransportURI($radio,$MetaData);
  1368. }
  1369. /**
  1370. * Sets Av Transport URI
  1371. *
  1372. * - <b>NOTE:</b> Main SOAP method to set play URI - this is the plain SetAVTransportURI
  1373. *
  1374. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1375. * - <b>WSDL:</b> fill in
  1376. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1377. * - <b>Returns:</b> sendpacket return
  1378. *
  1379. * @param string $tspuri Transport URI
  1380. * @param string $MetaData (optional for MetaData)
  1381. *
  1382. * @return String
  1383. */
  1384. public function SetAVTransportURI($tspuri,$MetaData="")
  1385. {
  1386. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1387. CONNECTION: close
  1388. HOST: '.$this->address.':1400
  1389. CONTENT-LENGTH: '.(342+strlen(htmlspecialchars($tspuri))+strlen($MetaData)).'
  1390. CONTENT-TYPE: text/xml; charset="utf-8"
  1391. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
  1392. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><CurrentURI>'.htmlspecialchars($tspuri).'</CurrentURI><CurrentURIMetaData>'.$MetaData.'.</CurrentURIMetaData></u:SetAVTransportURI></s:Body></s:Envelope>';
  1393. $this->sendPacket($content);
  1394. }
  1395. /**
  1396. * Sets Queue
  1397. *
  1398. * - <b>NOTE:</b> This is only a Wrapper for setting a queue via SetAVTransportURI
  1399. *
  1400. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1401. * - <b>WSDL:</b> fill in
  1402. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1403. * - <b>Returns:</b> Void
  1404. * @todo SHOULD return something else
  1405. *
  1406. * @param string $queue transport URI or Queue
  1407. * @param string $MetaData (optional for MetaData)
  1408. *
  1409. * @return Void
  1410. */
  1411. public function SetQueue($queue,$MetaData="")
  1412. {
  1413. $this->SetAVTransportURI($queue,$MetaData);
  1414. }
  1415. /**
  1416. * Clears devices Queue
  1417. *
  1418. * - <b>NOTE:</b> This function clears the actual playing queue but not the actually selected playlist
  1419. *
  1420. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1421. * - <b>WSDL:</b> fill in
  1422. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1423. * - <b>Returns:</b> Sendpacket returns
  1424. *
  1425. * @return String
  1426. */
  1427. public function ClearQueue()
  1428. {
  1429. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1430. CONNECTION: close
  1431. HOST: '.$this->address.':1400
  1432. CONTENT-LENGTH: 290
  1433. CONTENT-TYPE: text/xml; charset="utf-8"
  1434. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#RemoveAllTracksFromQueue"
  1435. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:RemoveAllTracksFromQueue xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:RemoveAllTracksFromQueue></s:Body></s:Envelope>';
  1436. $this->sendPacket($content);
  1437. }
  1438. /**
  1439. * Adds URI to Queue (not the Playlist!!)
  1440. *
  1441. * - <b>NOTE:</b> Works on queue
  1442. *
  1443. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1444. * - <b>WSDL:</b> fill in
  1445. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1446. * - <b>Returns:</b> Sendpacket returns
  1447. *
  1448. * @param string $file Uri or Filename
  1449. *
  1450. * @return String
  1451. */
  1452. public function AddToQueue($file)
  1453. {
  1454. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1455. CONNECTION: close
  1456. HOST: '.$this->address.':1400
  1457. CONTENT-LENGTH: '.(438+strlen(htmlspecialchars($file))).'
  1458. CONTENT-TYPE: text/xml; charset="utf-8"
  1459. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#AddURIToQueue"
  1460. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:AddURIToQueue xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><EnqueuedURI>'.htmlspecialchars($file).'</EnqueuedURI><EnqueuedURIMetaData></EnqueuedURIMetaData><DesiredFirstTrackNumberEnqueued>0</DesiredFirstTrackNumberEnqueued><EnqueueAsNext>1</EnqueueAsNext></u:AddURIToQueue></s:Body></s:Envelope>';
  1461. $this->sendPacket($content);
  1462. }
  1463. /**
  1464. * Removes track from queue (not the Playlist!!)
  1465. *
  1466. * - <b>NOTE:</b> Works on queue
  1467. *
  1468. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1469. * - <b>WSDL:</b> fill in
  1470. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1471. * - <b>Returns:</b> Sendpacket returns
  1472. *
  1473. * @param string $track Tracknumber/id to remove from current sonos queue (!)
  1474. *
  1475. * @return string
  1476. */
  1477. public function RemoveFromQueue($track)
  1478. {
  1479. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1480. CONNECTION: close
  1481. HOST: '.$this->address.':1400
  1482. CONTENT-LENGTH: '.(307+strlen($track)).'
  1483. CONTENT-TYPE: text/xml; charset="utf-8"
  1484. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#RemoveTrackFromQueue"
  1485. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:RemoveTrackFromQueue xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><ObjectID>Q:0/'.$track.'</ObjectID></u:RemoveTrackFromQueue></s:Body></s:Envelope>';
  1486. $this->sendPacket($content);
  1487. }
  1488. /**
  1489. * Jumps directly to the track
  1490. *
  1491. * - <b>NOTE:</b> I think I never used this method (br) ... ever used direkt seek call. So note this is only a wrapper!
  1492. *
  1493. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaRenderer:1
  1494. * - <b>WSDL:</b> fill in
  1495. * - <b>Service:</b> urn:schemas-upnp-org:service:AVTransport:1
  1496. * - <b>Returns:</b> Sendpacket returns
  1497. *
  1498. * @param string $track Number/ID of the track to play in queue
  1499. *
  1500. * @return string
  1501. */
  1502. public function SetTrack($track)
  1503. {
  1504. $content='POST /MediaRenderer/AVTransport/Control HTTP/1.1
  1505. CONNECTION: close
  1506. HOST: '.$this->address.':1400
  1507. CONTENT-LENGTH: '.(288+strlen($track)).'
  1508. CONTENT-TYPE: text/xml; charset="utf-8"
  1509. SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Seek"
  1510. <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Seek xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID><Unit>TRACK_NR</Unit><Target>'.$track.'</Target></u:Seek></s:Body></s:Envelope>';
  1511. $this->sendPacket($content);
  1512. }
  1513. /******************* // urn:schemas-upnp-org:device:MediaServer:1 ***********
  1514. ***************************************************************************/
  1515. /* urn:upnp-org:serviceId:ContentDirectory */
  1516. /**
  1517. * Returns an array with the songs of the actual sonos queue
  1518. *
  1519. * - <b>NOTE:</b> Wrapper for Browse
  1520. *
  1521. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaServer:1
  1522. * - <b>WSDL:</b> fill in
  1523. * - <b>Service:</b> urn:upnp-org:serviceId:ContentDirectory
  1524. * - <b>Returns:</b> (String) Playlist ID
  1525. *
  1526. * @return String
  1527. */
  1528. public function GetCurrentPlaylist()
  1529. {
  1530. $header='POST /MediaServer/ContentDirectory/Control HTTP/1.1
  1531. SOAPACTION: "urn:schemas-upnp-org:service:ContentDirectory:1#Browse"
  1532. CONTENT-TYPE: text/xml; charset="utf-8"
  1533. HOST: '.$this->address.':1400';
  1534. $xml='<?xml version="1.0" encoding="utf-8"?>
  1535. <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  1536. xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  1537. <s:Body>
  1538. <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"><ObjectID>Q:0</ObjectID><BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter></Filter><StartingIndex>0</StartingIndex><RequestedCount>1000</RequestedCount><SortCriteria></SortCriteria></u:Browse>
  1539. </s:Body>
  1540. </s:Envelope>';
  1541. $content=$header . '
  1542. Content-Length: '. strlen($xml) .'
  1543. '. $xml;
  1544. $returnContent = $this->sendPacket($content);
  1545. $returnContent = substr($returnContent, stripos($returnContent, '&lt;'));
  1546. $returnContent = substr($returnContent, 0, strrpos($returnContent, '&gt;') + 4);
  1547. $returnContent = str_replace(array("&lt;", "&gt;", "&quot;", "&amp;", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent);
  1548. $xml = new SimpleXMLElement($returnContent);
  1549. $liste = array();
  1550. for($i=0,$size=count($xml);$i<$size;$i++)
  1551. {
  1552. $aktrow = $xml->item[$i];
  1553. $albumart = $aktrow->xpath("upnp:albumArtURI");
  1554. $title = $aktrow->xpath("dc:title");
  1555. $artist = $aktrow->xpath("dc:creator");
  1556. $album = $aktrow->xpath("upnp:album");
  1557. $liste[$i]['listid']=$i+1;
  1558. if(isset($albumart[0])){
  1559. $liste[$i]['albumArtURI']="http://" . $this->address . ":1400".(string)$albumart[0];
  1560. }else{
  1561. $liste[$i]['albumArtURI'] ="";
  1562. }
  1563. $liste[$i]['title']=(string)$title[0];
  1564. if(isset($artist[0])){
  1565. $liste[$i]['artist']=(string)$artist[0];
  1566. }else{
  1567. $liste[$i]['artist']="";
  1568. }
  1569. if(isset($album[0])){
  1570. $liste[$i]['album']=(string)$album[0];
  1571. }else{
  1572. $liste[$i]['album']="";
  1573. }
  1574. }
  1575. return $liste;
  1576. }
  1577. /**
  1578. * Returns an array with all sonos playlists
  1579. *
  1580. * - <b>NOTE:</b> Wrapper for Browse
  1581. *
  1582. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaServer:1
  1583. * - <b>WSDL:</b> fill in
  1584. * - <b>Service:</b> urn:upnp-org:serviceId:ContentDirectory
  1585. * - <b>Returns:</b> Array with all Sonos Pl
  1586. *
  1587. * @return Array
  1588. */
  1589. public function GetSonosPlaylists()
  1590. {
  1591. $header='POST /MediaServer/ContentDirectory/Control HTTP/1.1
  1592. SOAPACTION: "urn:schemas-upnp-org:service:ContentDirectory:1#Browse"
  1593. CONTENT-TYPE: text/xml; charset="utf-8"
  1594. HOST: '.$this->address.':1400';
  1595. $xml='<?xml version="1.0" encoding="utf-8"?>
  1596. <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  1597. xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  1598. <s:Body>
  1599. <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"><ObjectID>SQ:</ObjectID><BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter></Filter><StartingIndex>0</StartingIndex><RequestedCount>100</RequestedCount><SortCriteria></SortCriteria></u:Browse>
  1600. </s:Body>
  1601. </s:Envelope>';
  1602. $content=$header . '
  1603. Content-Length: '. strlen($xml) .'
  1604. '. $xml;
  1605. $returnContent = $this->sendPacket($content);
  1606. $returnContent = substr($returnContent, stripos($returnContent, '&lt;'));
  1607. $returnContent = substr($returnContent, 0, strrpos($returnContent, '&gt;') + 4);
  1608. $returnContent = str_replace(array("&lt;", "&gt;", "&quot;", "&amp;", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent);
  1609. $xml = new SimpleXMLElement($returnContent);
  1610. $liste = array();
  1611. for($i=0,$size=count($xml);$i<$size;$i++)
  1612. {
  1613. $attr = $xml->container[$i]->attributes();
  1614. $liste[$i]['id'] = (string)$attr['id'];
  1615. $title = $xml->container[$i];
  1616. $title = $title->xpath('dc:title');
  1617. $liste[$i]['title'] = (string)$title[0];
  1618. $liste[$i]['typ'] = "Sonos";
  1619. $liste[$i]['file'] = urlencode((string)$xml->container[$i]->res);
  1620. }
  1621. return $liste;
  1622. }
  1623. /**
  1624. * Returns an array with all imported PL
  1625. *
  1626. * - <b>NOTE:</b> Wrapper for Browse
  1627. *
  1628. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaServer:1
  1629. * - <b>WSDL:</b> fill in
  1630. * - <b>Service:</b> urn:upnp-org:serviceId:ContentDirectory
  1631. * - <b>Returns:</b> Array with all imported PL (Share, Mediaplayer, itunes....)
  1632. *
  1633. * @return Array
  1634. */
  1635. public function GetImportedPlaylists()
  1636. {
  1637. $header='POST /MediaServer/ContentDirectory/Control HTTP/1.1
  1638. SOAPACTION: "urn:schemas-upnp-org:service:ContentDirectory:1#Browse"
  1639. CONTENT-TYPE: text/xml; charset="utf-8"
  1640. HOST: '.$this->address.':1400';
  1641. $xml='<?xml version="1.0" encoding="utf-8"?>
  1642. <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  1643. xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  1644. <s:Body>
  1645. <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"><ObjectID>A:PLAYLISTS</ObjectID><BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter></Filter><StartingIndex>0</StartingIndex><RequestedCount>100</RequestedCount><SortCriteria></SortCriteria></u:Browse>
  1646. </s:Body>
  1647. </s:Envelope>';
  1648. $content=$header . '
  1649. Content-Length: '. strlen($xml) .'
  1650. '. $xml;
  1651. $returnContent = $this->sendPacket($content);
  1652. $returnContent = substr($returnContent, stripos($returnContent, '&lt;'));
  1653. $returnContent = substr($returnContent, 0, strrpos($returnContent, '&gt;') + 4);
  1654. $returnContent = str_replace(array("&lt;", "&gt;", "&quot;", "&amp;", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent);
  1655. $xml = new SimpleXMLElement($returnContent);
  1656. $liste = array();
  1657. for($i=0,$size=count($xml);$i<$size;$i++)
  1658. {
  1659. $attr = $xml->container[$i]->attributes();
  1660. $liste[$i]['id'] = (string)$attr['id'];
  1661. $title = $xml->container[$i];
  1662. $title = $title->xpath('dc:title');
  1663. // br substring use cuts my playlist names at the 4th char
  1664. $liste[$i]['title'] = (string)$title[0];
  1665. $liste[$i]['title']=preg_replace("/^(.+)\.m3u$/i","\\1",$liste[$i]['title']);
  1666. $liste[$i]['typ'] = "Import";
  1667. $liste[$i]['file'] = (string)$xml->container[$i]->res;
  1668. }
  1669. return $liste;
  1670. }
  1671. /**
  1672. * Returns an array with all songs of a specific Playlist
  1673. *
  1674. * - <b>NOTE:</b> Wrapper for Browse
  1675. *
  1676. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaServer:1
  1677. * - <b>WSDL:</b> fill in
  1678. * - <b>Service:</b> urn:upnp-org:serviceId:ContentDirectory
  1679. * - <b>Returns:</b> Array with MetaData on the songs
  1680. *
  1681. * @param string $value Id of the playlist
  1682. *
  1683. * @return Array
  1684. */
  1685. public function GetPlaylist($value)
  1686. {
  1687. $header='POST /MediaServer/ContentDirectory/Control HTTP/1.1
  1688. SOAPACTION: "urn:schemas-upnp-org:service:ContentDirectory:1#Browse"
  1689. CONTENT-TYPE: text/xml; charset="utf-8"
  1690. HOST: '.$this->address.':1400';
  1691. $xml='<?xml version="1.0" encoding="utf-8"?>
  1692. <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  1693. xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  1694. <s:Body>
  1695. <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"><ObjectID>'.$value.'</ObjectID><BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter></Filter><StartingIndex>0</StartingIndex><RequestedCount>1000</RequestedCount><SortCriteria></SortCriteria></u:Browse>
  1696. </s:Body>
  1697. </s:Envelope>';
  1698. $content=$header . '
  1699. Content-Length: '. strlen($xml) .'
  1700. '. $xml;
  1701. $returnContent = $this->sendPacket($content);
  1702. $xmlParser = xml_parser_create();
  1703. $returnContent = substr($returnContent, stripos($returnContent, '&lt;'));
  1704. $returnContent = substr($returnContent, 0, strrpos($returnContent, '&gt;') + 4);
  1705. $returnContent = str_replace(array("&lt;", "&gt;", "&quot;", "&amp;", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent);
  1706. $xml = new SimpleXMLElement($returnContent);
  1707. $liste = array();
  1708. for($i=0,$size=count($xml);$i<$size;$i++)
  1709. {
  1710. $aktrow = $xml->item[$i];
  1711. $albumart = $aktrow->xpath("upnp:albumArtURI");
  1712. $title = $aktrow->xpath("dc:title");
  1713. $artist = $aktrow->xpath("dc:creator");
  1714. $album = $aktrow->xpath("upnp:album");
  1715. $liste[$i]['listid']=$i+1;
  1716. if(isset($albumart[0])){
  1717. $liste[$i]['albumArtURI']="http://" . $this->address . ":1400".(string)$albumart[0];
  1718. }else{
  1719. $liste[$i]['albumArtURI'] ="";
  1720. }
  1721. $liste[$i]['title']=(string)$title[0];
  1722. if(isset($interpret[0])){
  1723. $liste[$i]['artist']=(string)$artist[0];
  1724. }else{
  1725. $liste[$i]['artist']="";
  1726. }
  1727. if(isset($album[0])){
  1728. $liste[$i]['album']=(string)$album[0];
  1729. }else{
  1730. $liste[$i]['album']="";
  1731. }
  1732. }
  1733. return $liste;
  1734. }
  1735. /**
  1736. * Universal function to browse ContentDirectory
  1737. *
  1738. * - <b>NOTE:</b> please use upnp and sonos documentation to get an idea of the return
  1739. *
  1740. * - <b>Device:</b> urn:schemas-upnp-org:device:MediaServer:1
  1741. * - <b>WSDL:</b> fill in
  1742. * - <b>Service:</b> urn:upnp-org:serviceId:ContentDirectory
  1743. * - <b>Returns:</b> Array with metadata; please use upnp and sonos documentation to get an idea of the return
  1744. *
  1745. * @param string $value ObjectID
  1746. * @param string $meta BrowseFlag
  1747. * @param string $filter Filter
  1748. * @param string $sindex SearchIndex
  1749. * @param string $rcount ResultCount
  1750. * @param string $sc SortCriteria
  1751. *
  1752. * @return Array
  1753. */
  1754. public function Browse($value,$meta="BrowseDirectChildren",$filter="",$sindex="0",$rcount="1000",$sc="")
  1755. {
  1756. switch($meta){
  1757. case 'BrowseDirectChildren':
  1758. case 'c':
  1759. case 'child':
  1760. $meta="BrowseDirectChildren";
  1761. break;
  1762. case 'BrowseMetadata':
  1763. case 'm':
  1764. case 'meta':
  1765. $meta = "BrowseMetadata";
  1766. break;
  1767. default:
  1768. return false;
  1769. }
  1770. $header='POST /MediaServer/ContentDirectory/Control HTTP/1.1
  1771. SOAPACTION: "urn:schemas-upnp-org:service:ContentDirectory:1#Browse"
  1772. CONTENT-TYPE: text/xml; charset="utf-8"
  1773. HOST: '.$this->address.':1400';
  1774. $xml='<?xml version="1.0" encoding="utf-8"?>
  1775. <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  1776. xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  1777. <s:Body>
  1778. <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"><ObjectID>'.htmlspecialchars($value).'</ObjectID><BrowseFlag>'.$meta.'</BrowseFlag><Filter>'.$filter.'</Filter><StartingIndex>'.$sindex.'</StartingIndex><RequestedCount>'.$rcount.'</RequestedCount><SortCriteria>'.$sc.'</SortCriteria></u:Browse>
  1779. </s:Body>
  1780. </s:Envelope>';
  1781. $content=$header . '
  1782. Content-Length: '. strlen($xml) .'
  1783. '. $xml;
  1784. $returnContent = $this->sendPacket($content);
  1785. $xmlParser = xml_parser_create();
  1786. $returnContent = substr($returnContent, stripos($returnContent, '&lt;'));
  1787. $returnContent = substr($returnContent, 0, strrpos($returnContent, '&gt;') + 4);
  1788. $returnContent = str_replace(array("&lt;", "&gt;", "&quot;", "&amp;", "%3a", "%2f", "%25"), array("<", ">", "\"", "&", ":", "/", "%"), $returnContent);
  1789. $xml = new SimpleXMLElement($returnContent);
  1790. $liste = array();
  1791. for($i=0,$size=count($xml);$i<$size;$i++)
  1792. {
  1793. //Wenn Container vorhanden, dann ist es ein Browse Element
  1794. //Wenn Item vorhanden, dann ist es ein Song.
  1795. if(isset($xml->container[$i])){
  1796. $aktrow = $xml->container[$i];
  1797. $attr = $xml->container[$i]->attributes();
  1798. $liste[$i]['typ'] = "container";
  1799. }else if(isset($xml->item[$i])){
  1800. //Item vorhanden also nur noch Musik
  1801. $aktrow = $xml->item[$i];
  1802. $attr = $xml->item[$i]->attributes();
  1803. $liste[$i]['typ'] = "item";
  1804. }else{
  1805. //Fehler aufgetreten
  1806. return;
  1807. }
  1808. $id = $attr['id'];
  1809. $parentid = $attr['parentID'];
  1810. $albumart = $aktrow->xpath("upnp:albumArtURI");
  1811. $titel = $aktrow->xpath("dc:title");
  1812. $interpret = $aktrow->xpath("dc:creator");
  1813. $album = $aktrow->xpath("upnp:album");
  1814. if(isset($aktrow->res)){
  1815. $res = (string)$aktrow->res;
  1816. $liste[$i]['res'] = urlencode($res);
  1817. }else{
  1818. $liste[$i]['res'] = "leer";
  1819. }
  1820. $resattr = $aktrow->res->attributes();
  1821. if(isset($resattr['duration'])){
  1822. $liste[$i]['duration']=(string)$resattr['duration'];
  1823. }else{
  1824. $liste[$i]['duration']="leer";
  1825. }
  1826. if(isset($albumart[0])){
  1827. $liste[$i]['albumArtURI']="http://" . $this->address . ":1400".(string)$albumart[0];
  1828. }else{
  1829. $liste[$i]['albumArtURI'] ="leer";
  1830. }
  1831. $liste[$i]['title']=(string)$titel[0];
  1832. if(isset($interpret[0])){
  1833. $liste[$i]['artist']=(string)$interpret[0];
  1834. }else{
  1835. $liste[$i]['artist']="leer";
  1836. }
  1837. if(isset($id) && !empty($id)){
  1838. $liste[$i]['id']=urlencode((string)$id);
  1839. }else{
  1840. $liste[$i]['id']="leer";
  1841. }
  1842. if(isset($parentid) && !empty($parentid)){
  1843. $liste[$i]['parentid']=urlencode((string)$parentid);
  1844. }else{
  1845. $liste[$i]['parentid']="leer";
  1846. }
  1847. if(isset($album[0])){
  1848. $liste[$i]['album']=(string)$album[0];
  1849. }else{
  1850. $liste[$i]['album']="leer";
  1851. }
  1852. }
  1853. return $liste;
  1854. }
  1855. /***************************************************************************
  1856. Radiotime / Tunein
  1857. ***************************************************************************/
  1858. /**
  1859. *
  1860. Get Now Playing information from Radiotime via opml
  1861. *
  1862. * - <b>NOTE:</b> it´s maybe better to use SOAP to get this information
  1863. *
  1864. * - <b>Device:</b> -
  1865. * - <b>WSDL:</b> -
  1866. * - <b>Service:</b> -
  1867. * - <b>Returns:</b> Array with Status, Version info and Logos
  1868. *
  1869. * @return Array
  1870. */
  1871. // Note: Our partnerId is in here
  1872. public function RadiotimeGetNowPlaying() // added br
  1873. {
  1874. $list["version"] = "";
  1875. $list["status"] = "";
  1876. $list["logo"] = "";
  1877. // Serial for Tunein is our MAC - prevents block / throttling (maybe we should shift this off)
  1878. $zoneinfo=$this->GetZoneInfo($this->address);
  1879. $serial=$zoneinfo['MACAddress'];
  1880. // Get mi
  1881. $mi=$this->GetMediaInfo();
  1882. // Filter out station id
  1883. $station=preg_replace("#(.*)x-sonosapi-stream:(.*?)\?sid(.*)#is",'$2',$mi['CurrentURI']);
  1884. // Only Ask Radiotime / Tunein for valid stationids (!!)
  1885. if (($station!="")and $station[0]=="s"){
  1886. // Ask with PHPSonos PartnerID and serial (mac)
  1887. $content = @file_get_contents("http://opml.radiotime.com/Describe.ashx?c=nowplaying&id=".$station."&partnerId=IAeIhU42&serial=".$serial);
  1888. // DEBUG DEEP ONLY
  1889. // echo "----". $content;
  1890. $list["version"]=preg_replace('#(.*)version="(.*?)\">(.*)#is','$2',$content);
  1891. $list["status"]=preg_replace('#(.*)<status>(.*?)\</status>(.*)#is','$2',$content);
  1892. $list["outline"]=preg_replace('#(.*)<body>(.*)<outline type="text" text="(.*?)\" guide_id="(.*)\" key#is','$2',$content);
  1893. $list["logo"]=preg_replace('#(.*)<LOGO>(.*?)\</LOGO>(.*)#is','$2',$content);
  1894. // TAG_DEBUG_DEEP for Intune-Throttling (or blocking!)
  1895. // echo "\n!!!!!!!!!!!!!!!!!INTUNE REQUEST EXECUTED!!!!!!!!!!!!!!\n";
  1896. }
  1897. return $list;
  1898. }
  1899. /***************************************************************************
  1900. Helper / sendPacket
  1901. ***************************************************************************/
  1902. /**
  1903. * XMLsendPacket
  1904. *
  1905. * - <b>NOTE:</b> This function does send of a soap query and DOES NOT filter a xml answer
  1906. * - <b>Returns:</b> Answer as XML
  1907. *
  1908. * @return Array
  1909. */
  1910. private function XMLsendPacket( $content )
  1911. {
  1912. $fp = fsockopen($this->address, 1400 /* Port */, $errno, $errstr, 10);
  1913. if (!$fp)
  1914. throw new Exception("Error opening socket: ".$errstr." (".$errno.")");
  1915. fputs ($fp, $content);
  1916. $ret = "";
  1917. $buffer = "";
  1918. while (!feof($fp)) {
  1919. $buffer = fgets($fp,128);
  1920. // echo "\n;" . $buffer . ";\n"; //DEBUG
  1921. $ret.= $buffer;
  1922. }
  1923. // echo "\n\nReturn:" . $ret . "!!\n";
  1924. fclose($fp);
  1925. if(strpos($ret, "200 OK") === false)
  1926. throw new Exception("Error sending command: ".$ret);
  1927. $array = preg_split("/\n/", $ret);
  1928. return $array[count($array) - 1];
  1929. }
  1930. /**
  1931. * sendPacket - communicate with the device
  1932. *
  1933. * - <b>NOTE:</b> This function does send of a soap query and may filter xml answers
  1934. * - <b>Returns:</b> Answer
  1935. *
  1936. * @return Array
  1937. */
  1938. private function sendPacket( $content )
  1939. {
  1940. $fp = fsockopen($this->address, 1400 /* Port */, $errno, $errstr, 10);
  1941. if (!$fp)
  1942. throw new Exception("Error opening socket: ".$errstr." (".$errno.")");
  1943. fputs ($fp, $content);
  1944. $ret = "";
  1945. while (!feof($fp)) {
  1946. $ret.= fgetss($fp,128); // filters xml answer
  1947. }
  1948. fclose($fp);
  1949. if(strpos($ret, "200 OK") === false)
  1950. throw new Exception("Error sending command: ".$ret);
  1951. // TAG_DEBUG_DEEP sendpacketdebug
  1952. // echo "sendPacketDebug: "; //DEBUG
  1953. // print_r($ret);
  1954. $array = preg_split("/\n/", $ret);
  1955. return $array[count($array) - 1];
  1956. }
  1957. }
  1958. ?>