msgbartop
Various ramblings-on, mostly about Red5
msgbarbottom

31 Mar 10 Stop complaining about Flash

If people aren’t complaining about Flash and HTML5 they are falling back to NoSQL vs RDBMS. There is a time and a place for everything, just remember that tidbit. So to get on with it, I would like to state that I am mostly a Windows user and I love Windows 7.. It f#@king rocks! I also use Google Chrome as my primary browser on both OSX and Windows. I recently loaded the latest dev build of Chrome that contains a streamlined Flash Player and I can say that it is awesome.
To test, I started up a Red5 instance with some mp4 and vp6 videos to see what the CPU usage would be and here is the result: Red5 = 0% to 7% and Chrome = 3% to 6% (average 3%)
The playback was smooth as silk and the audio was perfect. Next up for comparison, I tried IE and FF:
IE 8 with FP10.1 = 5% to 11% (average 5%)
Firefox 3.6 with FP 10.1 = 14% to 66% (average 40%)

Tags: , , , , , , ,

Buzz it!

12 Nov 09 Native RTMPS in Red5

Red5 now supports “native” RTMPS in addition to RTMPT over SSL. To use this feature you will need to use the current trunk version until 0.9 RC3 or Final are released. A big shout-out goes to Kevin Green for providing the original patch. Using this communication channel, your data will be secured throughout the process from connection to shutdown using TLS/SSL and should provide the secure features you need until RTMPE is ready.

Red5NativeRTMPS

Red5NativeRTMPS


To use this mode in your NetConnection, you must set the proxy type to best like so:

nc = new NetConnection();
nc.client = this;
nc.proxyType = "best";

For this example I used a free opensource ssl cert provided by godaddy.

Step by step process:

1. Create your key

keytool -keysize 2048 -genkey -alias red5 -keyalg RSA -keystore keystore
Enter keystore password:
Re-enter new password:
What is your first and last name?
  [Unknown]:  ssl.red5.org
What is the name of your organizational unit?
  [Unknown]:  Dev
What is the name of your organization?
  [Unknown]:  Red5
What is the name of your City or Locality?
  [Unknown]:  Henderson
What is the name of your State or Province?
  [Unknown]:  Nevada
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=ssl.red5.org, OU=Dev, O=Red5, L=Henderson, ST=Nevada, C=US correct?
  [no]:  yes

Enter key password for <red5>
        (RETURN if same as keystore password):

2. Create a CSR

keytool -certreq -keyalg RSA -alias red5 -file red5.csr -keystore keystore
Enter keystore password:

3. Submit your CSR to your SSL certificate provider. Godaddy process is described below.

4. After your receive your certificate, import the root cert into your keystore file

keytool -import -alias root -keystore keystore -trustcacerts -file valicert_class2_root.crt
Enter keystore password:
Certificate already exists in system-wide CA keystore under alias <valicertclass2ca>
Do you still want to add it to your own keystore? [no]:  yes
Certificate was added to keystore

5. Import the cross certificates

keytool -import -alias cross -keystore keystore -trustcacerts -file gd_cross_intermediate.crt
Enter keystore password:
Certificate was added to keystore

6. Import the intermediate certificates

keytool -import -alias intermed -keystore keystore -trustcacerts -file gd_intermediate.crt
Enter keystore password:
Certificate was added to keystore

7. Import your certificate

keytool -import -alias red5 -keystore keystore -trustcacerts -file ssl.red5.org.crt
Enter keystore password:
Certificate reply was installed in keystore

8. Setup RTMPS in your red5/conf/red5-core.xml. You may notice that some of the rtmp variables are used here, that is only for ease of setup; you could set them to whatever you prefer.

    <bean id="rtmpsMinaIoHandler"
        class="org.red5.server.net.rtmps.RTMPSMinaIoHandler">
        <property name="handler" ref="rtmpHandler" />
        <property name="codecFactory" ref="rtmpCodecFactory" />
        <property name="rtmpConnManager" ref="rtmpMinaConnManager" />
	<property name="keyStorePassword" value="${rtmps.keystorepass}" />
        <property name="keystoreFile" value="conf/keystore" />
    </bean>

    <bean id="rtmpsTransport" class="org.red5.server.net.rtmp.RTMPMinaTransport" init-method="start" destroy-method="stop">
        <property name="ioHandler" ref="rtmpsMinaIoHandler" />
        <property name="connectors">
            <list>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg index="0" type="java.lang.String" value="${rtmps.host}" />
                    <constructor-arg index="1" type="int" value="${rtmps.port}" />
                </bean>
            </list>
        </property>
        <property name="receiveBufferSize" value="${rtmp.receive_buffer_size}" />
        <property name="sendBufferSize" value="${rtmp.send_buffer_size}" />
        <property name="eventThreadsCore" value="${rtmp.event_threads_core}" />
        <property name="eventThreadsMax" value="${rtmp.event_threads_max}" />
        <property name="eventThreadsQueue" value="${rtmp.event_threads_queue}" />
        <property name="eventThreadsKeepalive" value="${rtmp.event_threads_keepalive}" />
        <property name="jmxPollInterval" value="1000" />
        <property name="tcpNoDelay" value="${rtmp.tcp_nodelay}" />
    </bean>

Additional security info can be found here
The testing player source can be found here

Tags: , ,

Buzz it!

27 Sep 09 NSV live streaming on Red5

Screenshot of playing nsv stream in flash

Screenshot of playing nsv stream in flash

This morning I was successful in playing a live NSV stream with FlashPlayer via Red5. I used NSVCap encoding VP62 and AAC. The code is implemented using the new Red5 plug-in system and will be released with 0.9.0 (soon). Huge thank yous go out to Andy Shaules and Wittawas Nakkasem for their help developing this feature.

Buzz it!

07 Aug 09 How to add an IoFilter per Application or Server

A new feature has been added to Red5 to allow any number of Mina IoFilters to be added to a connection at the Server or Application level. The particular filter detailed here is one that simply counts the connections and rejects any that exceed the set maximum number. This post details setting the filter at the Application level, but if you want it at the server level simply add the below bean definitions to your global webapp configuration located here: red5/webapps/red5-default.xml.

To add the filter you must first edit your applications red5-web.xml and add your beans:

<!-- Limits connections on a per-session basis -->
<bean id="connectionFilter" class="org.gregoire.red5.ConnectionShapeFilter">
    <property name="maxConnections" value="2"/>
</bean>

Next create a “config” bean to inform the server about your filter bean names:

<bean id="config" class="org.red5.server.adapter.Config">
    <!-- List of filter bean names to be loaded -->
    <property name="filterNames">
        <list>
	    <value>connectionFilter</value>
	</list>
    </property>
</bean>

One important thing to note is that since classes in the main server are creating the connections, your filter classes must be found by the URLClassloader. The URLClassloader created by the server uses jar files within Red5′s lib directory, so put your filter classes here (red5/lib) inside a jar. Once your classes are in-place, start your server and the filters will take effect.

An example Eclipse / FlexBuilder project can be found here.

Tags: , , ,

Buzz it!

15 Jun 09 Quartz schedulers

When you want to schedule a particular task or job within Red5, you have at least two options available which are built into the server. We use Quartz for our scheduler, but you are not required to use it; I just wanted to get that disclaimer out of the way, this is Java so use whatever you like.  The first option is the “server-wide” scheduler which is created when the server starts up and requires no configuration from your application. This scheduler is sufficient for most of the jobs you may want to create, but you will run into problems if you attempt to access an application class from within your job. The second option resolves this issue by providing an application level scheduler, one which can access your classes. The only caveat with this scheduler is that you must provide some configuration details, your applications context name.

Accessing the “server-wide” scheduler is done in your application like so (using scope):

schedulingService = (ISchedulingService) scope.getContext().getBean(ISchedulingService.BEAN_NAME);

Accessing the application scheduler is slightly different (using app context):

schedulingService = (ApplicationSchedulingService) ((BeanFactory) applicationContext).getBean("scheduler");

I prefer to make sure the schedulingService member is setup in my “appStart” method, since this is essentially where the application is “started” within Red5.

The following entry must be made in your applications red5-web.xml file if you want to use an application scheduler:

<bean id="scheduler" class="org.red5.server.scheduling.ApplicationSchedulingService">
    <property name="applicationName" value="myapp" />
</bean>

Make sure you set the correct application name / context (replace “myapp”).
Once you have the scheduling service, you can add your job amongst many other options which I don’t want to cover here.

Tags: , , , , , ,

Buzz it!

06 Jun 09 PHP support in Red5

I’ve updated my “parameterdemo” to include a couple PHP pages. The latest trunk (0.8.1-dev) now supports PHP through the use of Quercus. To enable it simply set a context parameter in your web.xml and include the quercus and resin-utils jars in your WEB-INF/lib. See the zip file for a complete example (eclipse + ant).

Once you deploy the war, go to these urls to test (update your port to match your servers setting):

PHP example getting value from Red5 application: 

<a href="http://localhost/parameterdemo/getparam.php">http://localhost/parameterdemo/getparam.php</a>

Same example with debug output: 

<a href="http://localhost/parameterdemo/getparam.php?debug=true">http://localhost/parameterdemo/getparam.php?debug=true</a>

Java servlet example: 

<a href="http://localhost/parameterdemo/myservlet">http://localhost/parameterdemo/myservlet</a>

The web.xml entry must look like so:

	<context-param>
	   <param-name>enable-php</param-name>
	   <param-value>true</param-value>
	</context-param>

Note: You dont have to install Resin to use Quercus, simply download one of the wars on this page: http://quercus.caucho.com/ and grab the libraries from WEB-INF/lib

Tags: , , , , ,

Buzz it!

05 Jun 09 Red5 0.8.0 released

Come one, come all.. Red5 0.8.0 is now available. Make your way to our google code page and download the installer for your platform. http://code.google.com/p/red5/

PS. If someone wants to build the Debian package, we are looking for a volunteer.

Tags: , ,

Buzz it!

03 Jun 09 Multiple HTTP socket configurations

Red5 version 0.8.0 introduces the ability to bind multiple ports and hosts for HTTP access; starting at revision 3632. Previously there were other options to accomplish this feature, but now it is built-in. So I’ll get right to it. The older configuration style for the tomcat server bean was like so:

<bean id="tomcat.server" class="org.red5.server.tomcat.TomcatLoader" init-method="init" destroy-method="shutdown" depends-on="context.loader">
	<property name="webappFolder" value="${red5.root}/webapps" />
	<property name="connector">
		<bean class="org.apache.catalina.connector.Connector">
			<constructor -arg type="java.lang.String" value="org.apache.coyote.http11.Http11NioProtocol" />
			<property name="port"><value>${http.port}</value></property>
			<property name="redirectPort"><value>${https.port}</value></property>
			<property name="enableLookups"><value>false</value></property>
		</bean>
	</property>
	<property name="baseHost">
		<bean class="org.apache.catalina.core.StandardHost">
			<property name="name" value="${http.host}" />
			<property name="unpackWARs" value="true" />
			<property name="autoDeploy" value="true" />
			<property name="xmlValidation" value="false" />
			<property name="xmlNamespaceAware" value="false" />
		</bean>
	</property>
</bean>

This allowed for one connector (port) and one host (like www.red5.org). If http.host were set to “192.168.0.1″ and http.port was set to “5080″, then you would be able to connect to “http://192.168.0.1:5080/” in your browser.
This latest configuration still supports this configuration, but allows for much more.

<bean id="tomcat.server" class="org.red5.server.tomcat.TomcatLoader" init-method="init" destroy-method="shutdown" depends-on="context.loader">
	<property name="webappFolder" value="${red5.root}/webapps" />
	<property name="connectors">
		<list>
			<bean id="defaultHttp" class="org.apache.catalina.connector.Connector">
				<constructor -arg type="java.lang.String" value="org.apache.coyote.http11.Http11NioProtocol" />
				<property name="port"><value>${http.host}</value></property>
				<property name="redirectPort"><value>8080</value></property>
				<property name="enableLookups"><value>false</value></property>
			</bean>
			<bean id="defaultProxy" class="org.apache.catalina.connector.Connector">
				<constructor -arg type="java.lang.String" value="org.apache.coyote.http11.Http11NioProtocol" />
				<property name="port"><value>8080</value></property>
				<property name="redirectPort"><value>${https.port}</value></property>
				<property name="enableLookups"><value>false</value></property>
			</bean>
		</list>
	</property>
	<property name="baseHost">
		<bean class="org.apache.catalina.core.StandardHost">
			<property name="name" value="${http.host}" />
			<property name="unpackWARs" value="true" />
			<property name="autoDeploy" value="true" />
			<property name="xmlValidation" value="false" />
			<property name="xmlNamespaceAware" value="false" />
		</bean>
	</property>
	<property name="hosts">
		<list>
			<bean id="local2" class="org.apache.catalina.core.StandardHost">
				<property name="name" value="192.168.0.2" />
				<property name="autoDeploy" value="false" />
				<property name="xmlValidation" value="false" />
				<property name="xmlNamespaceAware" value="false" />
			</bean>
			<bean id="local3" class="org.apache.catalina.core.StandardHost">
				<property name="name" value="10.0.0.2" />
				<property name="autoDeploy" value="false" />
				<property name="xmlValidation" value="false" />
				<property name="xmlNamespaceAware" value="false" />
			</bean>
		</list>
	</property>
</bean>

This allows for two connector (ports on each host) and three hosts. If http.host were set to “192.168.0.1″ and http.port was set to “5080″, then you would be able to connect to “http://192.168.0.1:5080/” in your browser. In addition you would also have these urls available:

  • http://192.168.0.1:8080/
  • http://192.168.0.2:5080/
  • http://192.168.0.2:8080/
  • http://10.0.0.2:5080/
  • http://10.0.0.2:8080/

Each application (context) within your red5/webapps directory is made available on each host as well.
Lastly, the “host” name does not have to be an IP address; you can specify a valid dns host name instead.

Tags: , , , ,

Buzz it!

25 May 09 Memory leak?

A poster to the Red5 list posted this today and claims that it exposes a memory leak in the server. The individual states that he doesnt know Java very well, so having been in the Java-game for 10+ years I immediately spot a potential leak in his method.

public void privMessage(String sendto, String message) {
IConnection conn = Red5.getConnectionLocal();
IClient client = conn.getClient();
IScope scope = getScope();
IContext context = getContext();
IClientRegistry reg = context.getClientRegistry();
if (reg.hasClient(sendto)) {
IClient recip = reg.lookupClient(sendto);
Set[IConnection] rcons = recip.getConnections(scope);
Iterator[IConnection] it = rcons.iterator();
while (it.hasNext()) {
IConnection rcon = it.next();
if (rcon instanceof IServiceCapableConnection)
((IServiceCapableConnection) rcon).invoke("privComm", new Object[]{client.getId(),message});
}
}
}

The big red flag for me is the use of an Iterator and the second thing is the use of an object reference within a loop. So to fix these potential leak candidates, I offer two solutions below.

Removal of the Iterator by using for-each:

IConnection conn = Red5.getConnectionLocal();
IClient client = conn.getClient();
IContext context = getContext();
IClientRegistry reg = context.getClientRegistry();
if (reg.hasClient(sendto)) {
IClient recip = reg.lookupClient(sendto);
String clientId = client.getId();
Set[IConnection] rcons = recip.getConnections(scope);
for (IConnection rcon : rcons) {
if (rcon instanceof IServiceCapableConnection)
((IServiceCapableConnection) rcon).invoke("privComm", new Object[]{clientId,message});
break;
}
}

Overall I think this is the best solution and is what I would implement:

1. In your ApplicationAdapter, create a map containing your client id to connection mappings

// map to keep track of connections by client id
private static ConcurrentMap[String, IConnection] connectionMap = new ConcurrentHashMap[String, IConnection](31);

2. In your connect method, add the incomming clients to the map

@Override
public boolean connect(final IConnection conn, IScope scope, Object[] params) {
// call original method of parent class
if (!super.connect(conn, scope, params)) {
return false;
}
// get the connections client id
IClient client = conn.getClient();
if (client != null) {
String clientId = client.getId();
// check the map for the client
if (!connectionMap.containsKey(clientId)) {
// register the connection
connectionMap.put(clientId, conn);
} else {
log.warn("Client id {} already exists in connection map",
clientId);
}
}
return true;
}

3. Simplify your method

public void privMessage(String sendto, String message) {
IConnection conn = Red5.getConnectionLocal();
IClient client = conn.getClient();
//senders client id
String clientId = client.getId();
if (connectionMap.containsKey(sendto)) {
IConnection rcon = connectionMap.get(sendto);
if (!ServiceUtils.invokeOnConnection(rcon, "privComm", new Object[]{clientId, message})) {
log.warn("Private message to client id: {} failed", sendto);
}
} else {
//notify sender that recipient is not available
ServiceUtils.invokeOnConnection(conn, "onError", new Object[]{"Client was not available"});
}
}

4. Dont forget to remove the map entries when the client disconnects

@Override
public void appDisconnect(IConnection conn) {
// get the previously stored id
String clientId = conn.getClient().getId();
// unregister user
IConnection cn = connectionMap.remove(clientId);
}

Please note that for the generic type args, I am using square braces for word press formatting reasons. Make sure you replace them with < and > before using the code

Tags: , , , , ,

Buzz it!

08 May 09 Flash on Tap: Red5 Workshop

FOT is coming up real soon… I’m co-presenting with Dominick for the Red5 workshop and I would like to know what you guys want to see? Since its an all-day thing, I would be glad to get some input from the community. Post your ideas as comments.

Tags: , , , , ,

Buzz it!
12,920 spam comments
blocked by
Akismet