Add PHP Client and Playout classes from Skyler Sully
authorDan Dennedy <dan@dennedy.org>
Wed, 10 Feb 2010 04:03:19 +0000 (20:03 -0800)
committerDan Dennedy <dan@dennedy.org>
Wed, 10 Feb 2010 04:03:19 +0000 (20:03 -0800)
src/swig/php/client.php [new file with mode: 0644]
src/swig/php/playout.php [new file with mode: 0644]

diff --git a/src/swig/php/client.php b/src/swig/php/client.php
new file mode 100644 (file)
index 0000000..7dd499a
--- /dev/null
@@ -0,0 +1,242 @@
+<?php
+/**
+ * Client class
+ *
+ * This class will handle all communications with a server
+ *
+ * PHP version 5.2.0+
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @filesource
+ * @copyright       2010 Skyler Sully
+ * @link            %link%
+ * @since           %since%
+ * @version         $Revision: $
+ * @modifiedby      $LastChangedBy: ssully$
+ * @lastmodified    $Date: $
+ * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+class Client
+{
+       /**
+        * Address of the server
+        *
+        * @access      public
+        * @var         String
+        */
+       var $address;
+       
+       /**
+        * Port to connect to on server
+        *
+        * @access      public
+        * @var         int
+        */
+       var $port;
+       
+       /**
+        * Connection to the server
+        *
+        * @access      public
+        * @var         Resource
+        */
+       var $connection;
+       
+       /**
+        * Tells if client is connected
+        *
+        * @access      public
+        * @var         boolean
+        */
+       var $connected;
+       
+       /**
+        * Expect Welcome flag
+        *
+        * @access      public
+        * @var         boolean
+        */
+       var $expectWelcome;
+       
+       /**
+        * Client Constructor
+        */
+       function __construct($address, $port, $mode = 1) {
+               $this->setup($address, $port, $mode);
+               $this->_initialize();
+       }
+       
+       /**
+        * Client Destructor
+        */
+       function __destruct() {
+               
+       }
+       
+       /**
+        * Sets the address and port of the server
+        *
+        * @access      public
+        * @return      void
+        */
+       function setup($address, $port, $mode = 1) {
+               $this->address = $address;
+               $this->port = $port;
+               
+               $this->connected = false;
+               $this->expectWelcome = false;
+               if( $mode > 1 ) {
+                       $mode = 1;
+               }
+               $this->mode = $mode;
+       }
+       
+       /**
+        * Initialization function to be extended by descendent classes
+        *
+        * @access    protected
+        * @return    void
+        */
+       function _initialize() {
+               
+       }
+       
+       /**
+        * Connects to the server using $address and $port
+        *
+        * @access      public
+        * @param       $expect_welcome - should we expect a welcome message
+        * @param       $welcome - welcome message
+        * @return      boolean - true if connected, false if not connected
+        */
+       function connect($expectWelcome = false, &$welcome = null) {
+               if( $this->connected ) {
+                       $this->disconnect();
+               }
+               $this->connected = false;
+               $this->connection = @fsockopen($this->address, $this->port, $errno, $errstr, 30); 
+               $this->expectWelcome = $expectWelcome;
+               if( !$this->connection === false ) {
+                       $this->setBlockingMode($this->mode);
+                       $this->connected = true;
+                       if( $expectWelcome === true ) {
+                               $welcome = $this->read();
+                       }
+               }
+               return $this->connected;
+       }
+       
+       /**
+        * Disconnects from the server
+        *
+        * @access      public
+        */
+       function disconnect() {
+               if( is_resource($this->connection) ) {
+                       fclose($this->connection);
+               }
+               $this->connected = false;
+               return !$this->connected;
+       }
+       
+       /**
+        * Attempts to reconnect to the server
+        *
+        * @access      public
+        */
+       function reconnect() {
+               $this->disconnect();
+               return $this->connect($this->expectWelcome);
+       }
+       
+       /**
+        * Writes a message to the server
+        *
+        * @access      public
+        * @param       String - Message to write to the server
+        * @return      number of bytes written or false on error
+        */
+       function write($message) {
+               if( $this->connected ) {
+                       if( !is_string($message) ) {
+                               return false;
+                       }
+                       $message = trim($message).PHP_EOL;
+                       $result = @fputs($this->connection, $message, strlen($message));
+                       if( $result == false ) {
+                               if( $this->reconnect() ) {
+                                       return $this->write($message);
+                               } else {
+                                       return $this->connected = false;
+                               }
+                       }
+               } else {
+                       return false;
+               }
+               
+               return $result;
+       }
+       
+       /**
+        * Reads a message from the server
+        *
+        * @access      public
+        * @return      Response from server, or false on error
+        */
+       function read() {
+               $response = '';
+               if( $this->connected ) {
+                       if( $this->mode ) {
+                               $response = @fgets($this->connection, 65535);
+                               if($response === false) {
+                                       if( $this->reconnect() ) {
+                                               return $this->read();
+                                       } else {
+                                               return $this->connected = false;
+                                       }
+                               }
+                       } else {
+                               while($tmp = @fgets($this->connection)) {
+                                       $response .= $tmp;
+                               }
+                       }
+               } else {
+                       $response = '*** NOT CONNECTED ***';
+               }
+               
+               return trim($response);
+       }
+       
+       /**
+        * Sets the blocking mode of the connection
+        *
+        * @access      public
+        * @param       $mode
+        * @return      boolean
+        */
+       function setBlockingMode($mode) {
+               if( !is_int($mode) ) {
+                       return false;
+               }
+               if( $mode == 0 ) {
+                       $this->mode = 0;
+               } else {
+                       $this->mode = 1;
+               }
+               stream_set_blocking($this->connection, $this->mode);
+       }
+       
+       /**
+        * Returns the connection status of the server
+        *
+        * @access      public
+        * @return      boolean
+        */
+       function isConnected() {
+               return $this->connected;
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/src/swig/php/playout.php b/src/swig/php/playout.php
new file mode 100644 (file)
index 0000000..9441311
--- /dev/null
@@ -0,0 +1,581 @@
+<?php
+/**
+ * Playout Client
+ *
+ * The classes in this file are responsible for controlling the MVCP server.
+ * 
+ * The class Melted is responsible for handling the connection to the MVCP server as well
+ * as passing commands and receiving responses from the server.
+ *
+ * The class Playout is responsible for retreiving and loading the appropriate items on the
+ * schedule.  It will use the Melted class to initialize and update the server.
+ *
+ * PHP version 5.2.0+
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @filesource
+ * @copyright       2010 Skyler Sully
+ * @link            %link%
+ * @since           %since%
+ * @version         $Revision: $
+ * @modifiedby      $LastChangedBy: ssully$
+ * @lastmodified    $Date: $
+ * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+/**
+ * Playout Controller.
+ *
+ * Retreives schedule information and performs functions to playout assets based on
+ * the schedule on time.  Uses the Melted class
+ *
+ * @package       playout
+ * @subpackage    application.vendors.socket.library.client
+ */
+class Playout
+{
+       /**
+        * Name of the module
+        *
+        * @access    public
+        * @var       string
+        */
+       var $name = 'playout';
+       
+       /**
+        * Contains defaults for the Playout class.  They will be overwritten
+        * by the config passed to the constructor
+        *
+        * @access    protected
+        * @var       array
+        */
+       var $_defaults = array(
+               'host' => 'localhost',
+               'port' => 5250,
+               'mode' => 1,
+       );
+       
+       /**
+        * Contains the settings necessary for the Playout Client.
+        *
+        * @access    public
+        * @var       array
+        */
+       var $settings = array();
+       
+       /**
+        * SDI Cards
+        *
+        * @access    public
+        * @var       array
+        */
+       var $units = array(
+               'U0' => 0,
+               'U1' => 1,
+               'U2' => 2,
+               'U3' => 3
+       );
+       
+       /**
+        * Array of command responses from the MVCP server.
+        *
+        * @access    protected
+        * @var       array
+        */
+       var $responses = array();
+       
+       /**
+        * Contains the MVCP client
+        *
+        * @access    public
+        * @var       object
+        */
+       var $Mvcp;
+       
+       /**
+        * Contains the playlist for the current hour
+        *
+        * @access    public
+        * @var       array
+        */
+       var $playlist = array();
+       
+       /**
+        * Playout constructor
+        */
+       function __construct($config = array()) {
+               $this->settings = array_merge($this->_defaults, $config);
+               $this->_initialize();
+       }
+       
+       /**
+        * Initializes the MVCP client
+        *
+        * @access    protected
+        * @return    void
+        */
+       function _initialize() {
+               extract($this->settings);
+               $this->Mvcp = new MvcpClient($host, $port, $mode);
+               $this->_connect();
+       }
+       
+       /**
+        * Connects to the MVCP server.  If the connection has failed because the service is down,
+        * it attempts to restart the MVCP service.  If the service cannot be restarted after the
+        * $maxRestartTries setting, it will reboot the server.
+        *
+        * @access    protected
+        * @return    boolean
+        */
+       function connect() {
+               if( !$this->Mvcp->open() ) {
+                       return false;
+               } else {
+                       return $this->Mvcp->isConnected();
+               }
+       }
+       
+       /**
+        * Disconnects from the MVCP server
+        *
+        * @access    protected
+        * @return    void
+        */
+       function disconnect() {
+               $this->Mvcp->close();
+       }
+       
+       /**
+        * Shuts down the Playout service by stopping whatever is playing and clearing the unit.
+        *
+        * @access    public
+        * @return    void
+        */
+       function shutdown() {
+               if( !$this->Mvcp->isConnected() ) {
+                       $this->_connect();
+               }
+               $this->_command('stop');
+               $this->_command('clear');
+               $this->_disconnect();
+       }
+       
+       /**
+        * Sets the key and value on the unit
+        *
+        * @access    public
+        * @param     $key
+        * @param     $value
+        * @param     $unit (optional)
+        * @return    void
+        */
+       function uset($key, $value, $unit = 0) {
+               $this->command('uset', array($key, $value), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Get the value for the specified key on the unit
+        *
+        * @access    public
+        * @param     $key
+        * @param     $unit (optional)
+        * @return    boolean
+        */
+       function uget($key, $unit = 0) {
+               $this->command('uget', array($key), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Loads a clip onto the unit
+        *
+        * @access    public
+        * @param     $clip
+        * @param     $in (optional)
+        * @param     $out (optional)
+        * @param     $unit (optional)
+        * @return    boolean
+        */
+       function load($clip, $in = null, $out = null, $unit = 0) {
+               $this->command('load', array($clip, $in, $out), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Appends a clip to the unit
+        *
+        * @access    public
+        * @param     $clip
+        * @param     $in (optional)
+        * @param     $out (optional)
+        * @param     $unit (optional)
+        * @return    boolean
+        */
+       function append($clip, $in = null, $out = null, $unit = 0) {
+               $this->command('apnd', array($clip, $in, $out), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Sets the in point for the current clip
+        *
+        * @access     public
+        * @param      $frame
+        * @param      $unit (optional)
+        * @return     boolean
+        */
+       function set_in($frame, $unit = 0) {
+               $this->command('set_in', array($frame), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Sets the out point for the current clip
+        *
+        * @access     public
+        * @param      $frame
+        * @param      $unit (optional)
+        * @return     boolean
+        */
+       function set_out($frame, $unit = 0) {
+               $this->command('set_out', array($frame), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Steps a certain number of frames (positive or negative)
+        *
+        * @access     public
+        * @param      $frames
+        * @param      $unit (optional)
+        * @return     boolean
+        */
+       function step($frames, $unit = 0) {
+               $this->command('step', array($frames), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Plays the current clip(s) on the specified unit
+        *
+        * @access    public
+        * @param     $unit (optional)
+        * @return    boolean
+        */
+       function play($unit = 0) {
+               $this->command('play', array(), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Stops the current playing clips on the specified unit
+        *
+        * @access    public
+        * @param     $unit (optional)
+        * @return    boolean
+        */
+       function stop($unit = 0) {
+               $this->command('stop', array(), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Clears the entire unit
+        *
+        * @access     public
+        * @param      $unit (optional)
+        * @return     boolean
+        */
+       function clear($unit = 0) {
+               $this->command('clear', array(), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Clears everything from the playlist that has already been played
+        *
+        * @access     public
+        * @param      $unit (optional)
+        * @return     boolean
+        */
+       function wipe($unit = 0) {
+               $this->command('wipe', array(), $errors, $unit);
+               return $errors;
+       }
+       
+       /**
+        * Convenience function to send commands to the MVCP server via the Mvcp class.
+        *
+        * @access    protected
+        * @param     $command - function name that corresponds with the command
+        *            in the Mvcp class
+        * @param     $arguments - array of arguments for command
+        * @return    boolean - status of command
+        */
+       function command($command, $arguments = array(), &$errors = array(), $unit = 0) {
+               $response = null;
+               $this->Mvcp->setUnit($unit);
+               $errors[] = $this->Mvcp->sendCommand($command, $arguments, $response);
+               usleep(100000);
+               $this->responses[] = $response;
+       }
+}
+
+/**
+ * Melted Client.
+ *
+ * Handles communication between the application and the MVCP server.
+ *
+ * @package       playout
+ */
+class MvcpClient extends Client
+{
+       /**
+        * Contains the name of the program
+        *
+        * @access    public
+        * @var       string
+        */
+       var $name = 'melted';
+       
+       /**
+        * Contains all of the units that can be used in
+        * the MVCP server
+        *
+        * @access    public
+        * @var       array
+        */
+       var $units = array('U0', 'U1', 'U2', 'U3');
+       
+       /**
+        * The current unit that operations are being done on
+        *
+        * @access    public
+        * @var       string
+        */
+       var $_unit;
+       
+       /**
+        * Initializes the MVCP by setting the default unit to U0
+        *
+        * @access    protected
+        * @return    void
+        */
+       function _initialize() {
+               $this->setUnit();
+       }
+       
+       /**
+        * Opens a connection with the MVCP server
+        *
+        * @access    public
+        * @return    boolean
+        */
+       function open() {
+               if( $this->isConnected() ) {
+                       return true;
+               }
+               $retval = $this->connect(true, $status);
+               sleep(1);
+               return $retval;
+       }
+       
+       /**
+        * Closes the connection with the MVCP server
+        *
+        * @access    public
+        * @return    boolean
+        */
+       function close() {
+               if( !$this->isConnected() ) {
+                       return true;
+               }
+               $this->write('bye');
+               return !$this->disconnect();
+       }
+       
+       /**
+        * Restarts the MVCP service.  This should be done if a connection cannot be made
+        * with the Mvcp Client class
+        *
+        * @access    public
+        * @return    boolean
+        */
+       function restart() {
+               $output = array();
+               $return = null;
+               exec("/sbin/service {$this->name} restart 2&>1", $output, $return);
+               if( $return != 0 ) {
+                       return false;
+               } else {
+                       return true;
+               }
+       }
+       
+       /**
+        * Sets the current unit.  By default, sets the unit to the default
+        * unit U0
+        *
+        * @access    public
+        * @param     $unit
+        * @return    boolean
+        */
+       function setUnit($unit = 0) {
+               if( !is_int($unit) ) {
+                       $this->_unit = $this->units[0];
+               } elseif( $unit < 0 || $unit > sizeof($this->units) - 1 ) {
+                       return false;
+               }
+               $this->_unit = $this->units[$unit];
+               return true;
+       }
+       
+       /**
+        * Sends the appropriate command to the MVCP server.
+        *
+        * @access    public
+        * @param     $command - command to run
+        * @param     $arguments - array of arguments
+        * @param     $response - response to return
+        * @return    boolean - status of command
+        */
+       function sendCommand($command, $arguments = array(), &$response) {
+               switch($command) {
+                       case 'uset':
+                               list($key, $value) = $arguments;
+                               $_command = "uset {$this->_unit} {$key}={$value}";
+                               break;
+                       case 'uget':
+                               list($key) = arguments;
+                               $_command = "uget {$this->_unit} {$key}";
+                               break;
+                       case 'load':
+                               list($clip, $in, $out) = $arguments;
+                               $_command = trim("load {$this->_unit} {$clip} {$in} {$out}");
+                               break;
+                       case 'apnd':
+                       case 'append':
+                               list($clip, $in, $out) = $arguments;
+                               $_command = trim("apnd {$this->_unit} {$clip} {$in} {$out}");
+                               break;
+                       case 'set_in':
+                       case 'setIn':
+                               list($frame) = $arguments;
+                               $_command = "sin {$this->_unit} {$frame}";
+                               break;
+                       case 'set_out':
+                       case 'setOut':
+                               list($frame) = $arguments;
+                               $_command = "sout {$this->_unit} {$frame}";
+                               break;
+                       case 'play':
+                               $_command = "play {$this->_unit}";
+                               break;
+                       case 'stop':
+                               $_command = "stop {$this->_unit}";
+                               break;
+                       case 'step':
+                               list($frames) = $arguments;
+                               $_command = "step {$this->_unit} {$frames}";
+                               break;
+                       case 'wipe':
+                               $_command = "wipe {$this->_unit}";
+                               break;
+                       case 'clear':
+                               $_command = "clear {$this->_unit}";
+                               break;
+                       default:
+                               return false;
+                               break;
+               }
+               return $this->runCommand($_command, $response);
+       }
+       
+       /**
+        * Gets the status of the unit
+        *
+        * @access    public
+        * @return    array
+        */
+       function status() {
+               if( !$this->isConnected() ) {
+                       return array();
+               }
+               $this->write("usta {$this->_unit}");
+               sleep(1);
+               
+               $return = $this->read();
+               $status = $this->read();
+               
+               list($unit, $mode, $currentClip, $currentFrame, $speed, $fps, $in, $out,
+                        $length, $tailClip, $tailPosition, $tailIn, $tailOut, $tailLength,
+                        $seekable, $playlistGenNumber, $clipIndex) = split(' ', $status);
+               
+               return compact(array('unit', 'mode', 'currentClip', 'currentFrame', 'speed', 'fps', 'in', 'out',
+                                          'length', 'tailClip', 'tailPosition', 'tailIn', 'tailOut', 'tailLength',
+                                          'seekable', 'playlistGenNumber', 'clipIndex'));
+       }
+       
+       /**
+        * Lists the clips on the unit
+        *
+        * @access    public
+        * @return    array
+        */
+       function listClips() {
+               if( !$this->isConnected() ) {
+                       return array();
+               }
+               $this->setBlockingMode(0);
+               $this->write("list {$this->_unit}");
+               sleep(1);
+               
+               $response = $this->read();
+               $_list = explode(PHP_EOL, $response);
+               $response = array_shift($_list);
+               $genNum = array_shift($_list);
+               foreach( $_list as $clip ) {
+                       list($index, $file, $in, $out, $realLength, $estimatedLength) = explode(' ', $clip);
+                       $list[] = compact(array('index', 'file', 'in', 'out', 'realLength', 'estimatedLength'));
+               }
+               $this->setBlockingMode(1);
+               return $list;
+       }
+       
+       /**
+        * Writes a command to the miracle server, gets the reponse and returns the
+        * status of the command as well as the command itself and the response code.
+        *
+        * @access    public
+        * @param     $command
+        * @param     $response - stores the command and response code
+        * @return    boolean true on success, false on failure
+        */
+       function runCommand($command, &$response) {
+               if( !$this->isConnected() ) {
+                       $response = "command - \"{$command}\" : not connected";
+                       return false;
+               }
+               $this->write($command);
+               usleep(500000);
+               $_response = $this->read();
+               if( !empty($_response) ) {
+                       $_codes = explode(" ", $_response);
+                       if( isset($_codes[1]) && $_codes[1] != 'OK' ) {
+                               $error = false;
+                       } else {
+                               $error = true;
+                       }
+               } else {
+                       $_response = "not connected";
+                       $error = true;
+               }
+               $response = "command - \"{$command}\" : {$_response}";
+               return $error;
+       }
+}
+
+?>
\ No newline at end of file