The Adobe Stratus Beta Sample App and PHP/MySQL

Written by Bob de Wit. Posted in ActionScript, AIR, Developer Blog, Flex

There is a new ActionScript 3.0 API in Flash Player 10 to support RTMFP, allowing for some really exciting stuff with regard to C2C (Client-To-Client) communications between Flex apps. This requires you to set up an account and a callback URL with the Adobe Stratus beta. There’s a really cool Stratus sample application on Adobe Labs, unfortunately the callback script syntax and responses are not described in much detail. This article attempts to reconstruct this and provide some PHP/MySQL code to work with Stratus.

Introduction

Flash Player 10 and Adobe AIR 1.5 introduce a new communications protocol called the Real-Time Media Flow Protocol (RTMFP). The most important features of RTMFP include low latency, end-to-end peering capability, security and scalability. These properties make RTMFP especially well suited for developing real-time collaboration applications by not only providing superior user experience but also reducing cost for operators. In order to use RTMFP, Flash Player endpoints must connect to an RTMFP-capable server, such as the Adobe Stratus service. Stratus is a beta, hosted rendezvous service that aids establishing communications between Flash Player endpoints. Unlike Flash Media Server, Stratus does not support media relay, shared objects, scripting, etc. So by using Stratus, you can only develop applications where Flash Player endpoints are directly communicating with each other. Connecting to the Stratus service and creating end-to-end media streams are analogous to working with Flash Media Server. Please note that you must use ActionScript 3.0 with either Flash Professional CS4 or Flex Builder 3 targeting Flash Player 10 or AIR 1.5. For details, check these resources: Please read these carefully as I’m not going to repeat what’s described there. The Callback Script The python callback script (reg.cgi) included with the sample source is a bit cryptic: So let’s see if we can make a better documented PHP/MySQL equivalent of this.

The Database

I’ve created a database in MySQL using the following script:
CREATE TABLE IF NOT EXISTS `registrations` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`appid` BIGINT(20) NOT NULL DEFAULT0,
`username` VARCHAR(60) NOT NULL DEFAULT,
`identity` VARCHAR(120) NOT NULL DEFAULT,
`updated` DATETIME NOT NULL DEFAULT0000-00-00 00:00:00,
PRIMARY KEY (`id`),
KEY `updated` (`updated`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
The appid field is not really required, I plan to use it to distinghuish between connects from various apps.

Callback Scenarios

So far I’ve found three callback scenarios:
  • The user connects
  • The user disconnects
  • The user calls another user (by passing the username)

The user connects

The REST-based call Stratus will make to your callback URL looks like this: http://your.domain/reg.php?username=foo&identity=1234 Stratus expects you to return a simple XML document:
true
where updated is true or false depending on whether the database was updated.

The user disconnects

Exactly the same REST call as for a connect, except that the identity value will be ZERO.

The user calls another user

The REST-based call Stratus will make to your callback URL looks like this: http://your.domain/reg.php?friends=foo Stratus expects you to return a simple XML document:
foo
1234

PHP Code

I’m using a fairly straightforward Database abstraction class here. There’s also a simple LogFile() function in the code that dumps the entire callback request to a text file. Zipped code with my database class and XML templates is here.
//****************************************************************************
// Database Configuration
//****************************************************************************
require_once(‘Database.php’);
define(‘DB_HOST’, ‘localhost’);
define(‘DB_USER’, ‘stratus’);
define(‘DB_PW’,******);
define(‘DB_DBNAME’, ‘db_stratus’);

//****************************************************************************
// Validation of script call
//****************************************************************************

//Log the entire request into a log file for easy inspection
LogFile($_REQUEST);

//Check if the request contains a value for "friends" or for "username/identity"
$valid = false;

if( isset( $_REQUEST[‘friends’] ))
{
$valid = true;
ProcessFriendRequest();
}

if( (isset($_REQUEST[‘username’]) && (isset($_REQUEST[‘identity’])) ))
{
$valid = true;
ProcessRegistration();
}

if(! $valid )
{
ProcessError();
}

//****************************************************************************
// Process a friend request
//****************************************************************************
function ProcessFriendRequest()
{
$db = new Database();
$query = sprintf("SELECT id, appid, username, identity, updated FROM registrations WHERE username=’%s‘",
mysql_real_escape_string($_REQUEST[‘friends’]));
LogFile($query);

$result = $db->GetObject($query);

if(! $result)
{
$update =false;
$reply = file_get_contents(‘update.xml’);
$reply = str_replace($update, $update, $reply);
echo $reply;
}
else
{
//Get the XML Response Template file and format it
$reply = file_get_contents(‘friends.xml’);
$reply = str_replace($user, $result->username, $reply);
$reply = str_replace($identity, $result->identity, $reply);
LogFile($reply);
echo $reply;
}
}

//****************************************************************************
// Process a registration (identity will be 0 when disconnecting)
//****************************************************************************
function ProcessRegistration()
{
$db = new Database();
$query = sprintf("SELECT id, appid, username, identity, updated FROM registrations WHERE username=’%s‘",
mysql_real_escape_string($_REQUEST[‘username’]));

LogFile($query);
$result = $db->GetObject($query);

if(! $result)
{
//Record does not exist yet
$update = "true";
$sql = sprintf("INSERT INTO registrations (appid, username, identity, updated) VALUES ( 0, ‘%s‘, ‘%s‘, NOW())",
mysql_real_escape_string($_REQUEST[‘username’]),
mysql_real_escape_string($_REQUEST[‘identity’]));
$db->execute($sql);
LogFile($sql);
}
else
{
//Record already exists
$update = "true";
$sql = sprintf("UPDATE registrations SET updated = NOW(), identity = ‘%s‘ WHERE username = ‘%s‘",
mysql_real_escape_string($_REQUEST[‘identity’]),
mysql_real_escape_string($_REQUEST[‘username’]));
$db->execute($sql);
LogFile($sql);
}

//Get the XML Response Template file and format it
$reply = file_get_contents(‘update.xml’);
$reply = str_replace($update, $update, $reply);
LogFile($reply);
echo $reply;
}

//****************************************************************************
// Process an error
//****************************************************************************
function ProcessError()
{
$update =false;
$reply = file_get_contents(‘update.xml’);
$reply = str_replace($update, $update, $reply);
LogFile($reply);
echo $reply;
}

//****************************************************************************
// Log File function
//****************************************************************************
function LogFile($msg)
{
$smsg = print_r($msg, true);
$time = date("F jS Y, h:iA");
$ip = $REMOTE_ADDR;
$referer = $HTTP_REFERER;
$browser = $HTTP_USER_AGENT;
$fp = fopen("log.txt", "a");
fputs($fp, "Time: $time IP: $ipReferer: $referer Browser: $browser | $smsg");
fclose($fp);
}

Trackback from your site.

Comments (16)

  • Todd

    |

    Great work, I am having trouble writing into the mysql table. Not a great php coder. Any pointers as to how to research this problem?……. agaain Thank you

    Todd

    Reply

  • tom

    |

    Thanks for your work! :) .. but I’m also having trouble getting the mysql table to work. Some kind of SQL syntax error??
    Sorry for the noob-ish question :O .. ‘#1064 – You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘‘0′, `username` VARCHAR(60) NOT NULL DEFAULT ‒

    Reply

    • Cris

      |

      Thanks!!!

      Reply

  • Mark

    |

    Awesome. Precisely what I was looking for!
    Thanks.

    Reply

  • Javi

    |

    Hi,
    I’m trying to run the example Video Phone but it does not work. I’m using your MYSQL table and the PHP files. When i try to connect to the other person, i receive this error:
    ID event: registerFailure
    Error description: HTTP update error
    Disconnecting.
    Hanging up call
    NetConnection event: NetConnection.Connect.Closed

    You can see it in: http://www.futuromestalla.com/webcamchat2/VP/VideoPhone.html

    Thanks!

    Reply

  • Javi

    |

    It workrs now. It was a problem with the name of the database

    Reply

  • via

    |

    excelent !!!!!!

    Reply

  • Eddy

    |

    Hello people, So i have everything up and running when i as a html file im able to connect and call other people and video chat works perfectly.
    However when i do this same file as php and send flashVars to populate the name i want to connect as, automatically connect me and populate the name of the user i want to chat with, the video chat only streams one end and audio works both ways. any clues what im doing wrong please???
    ask away if wasnt explained well.
    Need this urgent please, your help is much appreciated.
    Many thanks,
    Eddy.

    Reply

  • Bob de Wit

    |

    It’s a bit hard to say what’s going on without seeing your code, but my best guess is that your PHP script doesn’t generate the “equivalent” embed code & FlashVars as your static HTML…or at least not for both clients. HTH.

    Reply

  • Eddy

    |

    Flashvars are OKay it knows what im after,I’m sending $_SESSION['id'] and the id of the user im supose to call however i believe when its supppose to stream the video of the person i called, it looks-up they’re register id and not the id i passed on the flashvars..?
    Im quite confused.. is there a tutorial that explain how to use stratus apart from the sample one?
    Need this urgent please, your help is much appreciated.
    Many thanks,
    Eddy.

    Reply

  • nick

    |

    I noticed one error in your article. The code is fine, but the article contains a small issue. I only found this because I’m writing this in asp.net and referenced the article as a guide. The result XML has and it should be . Other than that it looks good… thanks for making that python script easier for me to read.

    Reply

    • nick

      |

      The missing part of my comment is in the update tag which in the article reads updated. This was missing in my last comment because I tried to use the actual XML tags.

      Reply

  • tom

    |

    hi
    how do i get this to join to the flash code so i can try it out and publish it…?

    added these files in dreamweaver.. but not sure how to add the as files and what page i need to go to to start the application?

    cheers for the help

    Reply

Leave a comment