host = ROKU_HOST; $this->port = ROKU_PORT; $this->debug = false; if( !$this->connect() ) return false; $this->lastlistresultsize = 0; } function connect(){ if( $this->debug ) echo "Connecting to ".$this->host.":".$this->port."\n"; $this->socket = fsockopen( $this->host, $this->port ); if( !$this->socket ) return false; if( $this->debug ) echo "Success\n"; $str = fgets( $this->socket, 255 ); if( $this->debug ) echo $str; return true; } function send( $str ){ if( $this->debug ) echo "=>".$str."\n"; fwrite( $this->socket, $str."\n" ); } function execTransaction( $name, $args="" ){ $end = false; $aReturn = array(); if( $args !== "" ) $args = " ".$args; $this->send( $name.$args ); $list = preg_match( "/^List/", $name ); $transaction = false; while( !$end ){ $line = fgets( $this->socket, 255 ); if( $this->debug ) echo "<=".$line; if( preg_match( "/".$name.": ListResultSize/", $line ) ){ continue; } if( preg_match( "/".$name.": TransactionInitiated/", $line ) ){ if( $this->debug ) echo "Transaction set to true\n"; $transaction = true; continue; } if( preg_match( "/".$name.": TransactionComplete/", $line ) ){ $end = true; if( $this->debug ) echo "Finishing transaction\n"; continue; } if( $list && preg_match( "/".$name.": ListResultSize (\d+)/", $line, $m ) ){ $this->lastlistresultsize = $m[1]; $transaction = true; continue; } if( preg_match( "/".$name.": ListResultEnd/", $line ) ){ if( $list ) $end = true; continue; } preg_match( "/".$name.": (.+)$/", $line, $aMatch ); $aReturn[] = trim( $aMatch[1] ); } $this->lastlistresultsize = sizeof( $aReturn ); return $aReturn; } function execSynchronous( $command, $requireok=true ){ $this->send( $command ); $read = true; preg_match( "/^([^ ]+)/", $command, $cmd ); while( $read ){ $line = fgets( $this->socket, 255 ); if( $this->debug ) echo "<=".$line; preg_match( "/([^ ]+) (.+)/", $line, $m ); if( $requireok ){ if( trim( $m[2] ) == "OK" ) $read = false; }else{ $read = false; } } return trim( $m[2] ); } function keyArrayData( $aInfo ){ $aReturn = array(); foreach( $aInfo as $key => $value ){ if( trim( $value ) == "" ) continue; preg_match( "/([^:]+): (.+)$/", $value, $m ); $aReturn[$m[1]] = trim( $m[2] ); } return $aReturn; } function Pause(){ return $this->execSynchronous( "Pause" ); } function Play(){ return $this->execSynchronous( "Play" ); } function Shuffle( $state="" ){ return $this->execSynchronous( "Shuffle ".$state ); } function Next(){ return $this->execSynchronous( "Next" ); } function SetPowerState( $state ){ return $this->execSynchronous( "SetPowerState ".$state ); } function GetPowerState(){ return $this->execSynchronous( "GetPowerState", false ); } function on( $reconnect="yes" ){ $this->SetPowerState( "on ".$reconnect ); } function standby(){ $this->SetPowerState( "standby" ); } function SetVolume( $vol ){ return $this->execSynchronous( "SetVolume ".intval( $vol ) ); } function GetVolume(){ return $this->execSynchronous( "GetVolume", false ); } function fadeTo( $end, $time ){ $start = intval( $this->GetVolume() ); $speed = ( $end - $start )/$time; if( sqrt( pow( $speed, 2 ) ) < 1 ){ $delay = 1/sqrt( pow( $speed, 2 ) ); $speed *= $delay; }else{ $delay = 1; } if( $this->debug ){ echo "Start vol: ".$start."\n"; echo "End vol: ".$end."\n"; echo "Speed: ".$speed."\n"; echo "Delay: ".$delay."\n"; } $vol = $start; $done = false; while( !$done ){ $vol = $this->GetVolume(); $vol += $speed; $this->SetVolume( $vol ); if( $start > $end && $vol <= $end ) $done = true; if( $start < $end && $vol >= $end ) $done = true; sleep($delay); } } function fadeOut( $time=10 ){ if( $this->debug ) echo "fadeOut( $time )\n"; $vol = $this->GetVolume(); if( $vol == 0 || $time == 0 ){ $this->standby(); return true; } $this->fadeTo( 0, $time ); $this->standby(); } function fadeIn( $end, $time=10 ){ if( $this->GetPowerState() == "standby" ) $this->on(); $this->SetVolume( 0 ); if( $time == 0 ){ $this->SetVolume( $end ); return true; } if( $end == 0 ){ $this->on(); return true; } $this->SetVolume( 0 ); $this->fadeTo( $end, $time ); } function GetConnectedServer(){ return $this->execSynchronous( "GetConnectedServer", false ); } function ServerDisconnect(){ return $this->execTransaction( "ServerDisconnect" ); } function SetServerFilter( $server ){ return $this->execSynchronous( "SetServerFilter ".$server ); } function ListServers(){ return $this->execTransaction( "ListServers" ); } function ServerConnect(){ return $this->execTransaction( "ServerConnect", "0" ); } function ClearWorkingSong(){ return $this->execSynchronous( "ClearWorkingSong" ); } function SetWorkingSongInfo( $info ){ return $this->execSynchronous( "SetWorkingSongInfo ".$info ); } function GetWorkingSongInfo(){ return $this->execSynchronous( "GetWorkingSongInfo" ); } function ClearWorkingSongInfo(){ return $this->execSynchronous( "ClearWorkingSongInfo" ); } function GetSongInfo($track){ return $this->keyArrayData( $this->execTransaction( "GetSongInfo", $track ) ); } function GetSongId( $track ){ $aInfo = $this->GetSongInfo( $track ); return $aInfo["id"]; } function SearchAlbums( $str ){ return $this->execTransaction( "SearchAlbums", $str ); } function SearchArtists( $str ){ return $this->execTransaction( "SearchArtists", $str ); } function SearchSongs( $str ){ return $this->execTransaction( "SearchSongs", $str ); } function SearchComposers( $str ){ return $this->execTransaction( "SearchComposers", $str ); } function SearchAll( $str ){ return $this->execTransaction( "SearchAll", $str ); } function NowPlayingInsert( $track, $index="" ){ return $this->execSynchronous( "NowPlayingInsert ".$track." ".$index ); } function QueueAndPlayOne( $track ){ return $this->execSynchronous( "QueueAndPlayOne ".$track ); } function ListNowPlayingQueue(){ return $this->execTransaction( "ListNowPlayingQueue" ); } function SetPreset( $preset, $track ){ return $this->execSynchronous( "SetPreset ".$preset." ".$track ); } function PlayPreset( $preset ){ return $this->execSynchronous( "PlayPreset ".$preset, true ); } function IrDispatchCommand( $command ){ return $this->execSynchronous( "IrDispatchCommand ".$command ); } function IrDemodSubscribe(){ return $this->startSubscription( "IrDemodSubscribe", "IrDemod" ); } function IrDemodUnsubscribe(){ return $this->execSynchronous( "IrDemodUnsubscribe" ); } function GetNowPlayingSongIds(){ $this->ListNowPlayingQueue(); $aIds = array(); for( $i=0; $i<$this->lastlistresultsize; $i++ ){ $aIds[] = $this->GetSongId($i); } return $aIds; } function ListPlaylists(){ $this->ensureServerConnection( "rsp" ); return $this->execTransaction( "ListPlaylists" ); } function ListPlaylistSongs( $id ){ return $this->execTransaction( "ListPlaylistSongs", $id ); } function LoadPlaylist( $name ){ $aPls = $this->ListPlaylists(); foreach( $aPls as $key => $val ){ if( $val == $name ){ $aSongs = $this->ListPlaylistSongs( $key ); foreach( $aSongs as $songid => $song ){ $this->NowPlayingInsert( $songid ); } return true; } } return false; } function SavePlaylist( $file ){ $aIds = $this->GetNewPlayingSongIds(); $str = implode( ",", $aIds ); file_put_contents( $file, $str."\n" ); return file_exists( $file ); } function ensureServerConnection( $filter, $server=0 ){ $str = trim( $this->GetConnectedServer()); if( $this->debug ) echo $str."\n"; if( $str != "OK" ){ $this->ServerDisconnect(); $this->SetServerFilter( $filter ); $this->ListServers(); $this->ServerConnect( $server ); } } function QueueAndPlaySongFromUrl( $url, $title ){ $this->ensureServerConnection( "radio" ); $this->ClearWorkingSong(); $this->SetWorkingSongInfo("title ".$title ); $this->SetWorkingSongInfo("url ".$url ); $this->SetWorkingSongInfo( "format MP3" ); $this->QueueAndPlayOne( "working" ); } } ?>