Let's create an application based on the previous article. We will log connecting client’s ip, referrer and connection time to a database, then send back a list of the avaiable videos based on the database to the client, and 20 seconds after the client started playing a stream disconnect client because time is up.
We need a database first, I used mySQL 5.0, download and install it
from here. For administration, use its own admin tool, or download phpMyAdmin
from here.Create a new table named red5first_users in the test database. In this table, create four fileds: counter( int , auto increment, primary ), ip ( varchar 256 ) . referrer ( varchar 256 ) , flashversion ( varchar 256 ) , connection ( double ). Then create a new table named red5first_streams with four fields: counter ( int , auto increment , primary ) , id ( varchar 256 ) , filename ( varchar 256 ) , duration ( integer 11 ).
After this download the java mysql driver from
mysql home. Copy mysql-connector-java*.jar to the Eclipse project root. Switch back to Eclipse, Project menuitem -> Properties -> Build Path -> Libraries -> Add External JARs, and choose the connector java from project root.
We also need to copy the driver to red5/lib, and export it to the java classpath, so the red5 application will reach it.
On os x, it looks like this:
[as]
export CLASSPATH=$CLASSPATH:/Applications/Red5/lib/mysql-connector-java-5.0.6-bin.jar
[/as]
Application code:
[as]
package com.milgra;
// amf object
import org.red5.io.utils.ObjectMap;
import java.util.Map;
import java.util.Vector;
import java.util.Iterator;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.red5.server.api.IScope;
import org.red5.server.api.IClient;
import org.red5.server.api.IConnection;
import org.red5.server.api.stream.ISubscriberStream;
import org.red5.server.api.service.IServiceCapableConnection;
import org.red5.server.api.scheduling.IScheduledJob;
import org.red5.server.api.scheduling.ISchedulingService;
import org.red5.server.adapter.ApplicationAdapter;
// IScheduledJob implementation is needed for timing
public class Application extends ApplicationAdapter implements IScheduledJob
{
//dbase adress
private static final String url = "jdbc:mysql://127.0.0.1:3306/test";
private static final String user = "youruser";
private static final String pass = "yourpass";
//logger
private static final Log log = LogFactory.getLog( Application.class );
// we want class initialization at start, so its static
static
{
try
{
Class.forName("com.mysql.jdbc.Driver");
}
catch ( ClassNotFoundException exception )
{
log.error( "ClassNotFoundException " + exception.getMessage( ) );
}
}
public boolean appStart ( IScope scope )
{
//start timer, cheking user presence every second
addScheduledJob( 1000 , this );
return true;
}
public void appStop ( IScope scope )
{
log.info( "Red5First.appStop" );
}
public boolean appConnect( IConnection conn , Object[] params )
{
log.info( "Red5First.appConnect " + conn.getClient().getId() );
// getting client parameters
Map properties = conn.getConnectParams();
//connection time
Long stamp = System.currentTimeMillis( );
// client ip
String ip = (String)conn.getRemoteAddress( );
// agent
String agent = (String)properties.get( "flashVer" );
// referrer
String referrer = (String)properties.get( "swfUrl" );
// this will be our stream list
Object[ ] streamList = { };
try
{
// trying to connect
Connection mySQLConn = DriverManager.getConnection( url , user , pass );
// we put the parameters into the dbase
Statement sttmnt = mySQLConn.createStatement( );
String insert = "INSERT INTO "
+ "`test`.`red5first_users` "
+ "(`counter`,`ip`,`referrer`,`flashversion`,`connection`)"
+ "VALUES(NULL,'" + ip + "','" + referrer + "','" + agent + "','" + stamp + "')";
// execute query
sttmnt.executeUpdate( insert );
// getting stream list
String query = "SELECT * FROM "
+ "`red5first_streams`";
ResultSet streamSet = sttmnt.executeQuery( query );
// converting resultSet to ObjectMap-based Vector
Vector results = new Vector( );
int counter = 0;
while ( streamSet.next( ) )
{
int duration = streamSet.getInt( “duration” );
String id = streamSet.getString( “id” );
String filename = streamSet.getString( “filename” );
ObjectMap oneRow = new ObjectMap( );
oneRow.put( “id” , id );
oneRow.put( “filename” , filename );
oneRow.put( “duration” , duration );
results.add( oneRow );
counter++;
}
//creating streamList
streamList = new Object[counter];
for ( int a = 0 ; a < results.size( ) ; a++ )
streamList[a] = results.get( a );
}
catch ( SQLException exception )
{
log.error( "SQLException at appConnect: " + exception.getMessage( ) );
}
// if streamlist is not empty, sending it to client
if ( streamList.length != 0 )
{
IServiceCapableConnection iconn = (IServiceCapableConnection)conn;
iconn.invoke( "message" , new Object[] {streamList} );
}
IClient client = conn.getClient( );
// setting client timestamp to 0, because it doesn't started any stream
client.setAttribute( "stamp" , new Long( 0 ) );
return true;
}
public void appDisconnect( IConnection conn , Object[] params )
{
log.info( "Red5First.appDisconnect " + conn.getClient().getId() );
}
public void streamSubscriberStart ( ISubscriberStream stream )
{
log.info( "Red5First.streamSubscriberStart" );
// somebody started a stream
IConnection conn = stream.getConnection( );
IClient client = conn.getClient( );
Long stamp = (Long)client.getAttribute( "stamp" );
// if client isn't already watching, setting stamp
if ( stamp == 0 ) client.setAttribute( "stamp" , System.currentTimeMillis( ) );
}
public void streamSubscriberStop ( ISubscriberStream stream )
{
log.info( "Red5First.streamSubscriberStop" );
}
// this function is called every second by SchedulingService
public void execute ( ISchedulingService isservice )
{
log.info( "Red5First.execute" );
long now = System.currentTimeMillis( );
Iterator it = this.getScope( ).getClients( ).iterator( );
// iterating through clients
while ( it.hasNext() )
{
IClient client = ( IClient )it.next( );
long stamp = ( Long ) client.getAttribute( "stamp" );
// if client is watching a stream
if ( stamp > 0 )
{
long duration = ( now - stamp ) / 1000;
// if time is up, disconnect
if ( duration > 20 ) client.disconnect( );
}
}
}
}
[/as]
And that's it.
Create a directory in red5/webapps/firstapp called streams, and copy a few flv streams here, then fill up red5first_streams table in the database with the attributes of these streams. Our application will reach them by default, because if we check WEB-INF/web.xml:
[as]
<security-constraint>
<web-resource-collection>
<web-resource-name>Forbidden</web-resource-name>
<url-pattern>/streams/*</url-pattern>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
[/as]
This folder will be enabled by Tomcat.
After Eclipse auto-built the application, copy your project's WEB-INF under red5/webapps/firstapp, and you can start the server.