Version: 1.6
Copyright © 2012 Smaxe Ltd
Table of Contents
List of Examples
JUV RTMP Client is a lightweight library that provides RTMP/RTMPT-enabled server access API for Java applications.
Features:
Related:
JUV RTMP Client (J2ME edition) - J2ME RTMP client
JUV RTMP Researcher - RTMP protocol debugger application
JUV RTMP Tester - RTMP functional/regression/load testing library
JUV RTMP Client library consists of the only JAR file (no dependencies) that should be placed in the application's class path.
It requires the license key: either Evaluation Key (get it) or Developer Key (buy it).
Java RTMP Client API is very similar to the API provided by Adobe® in the
ActionScript's flash.net.* package.
There are 3 core classes defined in com.smaxe.uv.client.rtmp package:
Every method invoked by the server is processed by the IMethodInvoker instance.
public interface IMethodInvoker
{
/**
* Invokes method with the args of the object o.
* The result is returned through the {@link ICallback callback}.
*
* @param o object which method is invoked
* @param method method to invoke
* @param callback callback to receive invocation result
* @param args method arguments
*/
public void invoke(final Object o, final String method, final ICallback callback, final Object... args);
}
The default implementation is based on reflection (com.smaxe.uv.invoker.support.MethodInvoker).
Every custom Java object that is sent/received to/from the server must be presented as ClassObject, i.e. class name + {property : property value} map. The IObjectCreator implementation is responsible for the such transformation.
public interface IObjectCreator
{
/**
* Converts {@link ClassObject co} to the custom type object.
*
* @param co ClassObject instance
* @return custom object
*/
public Object toObject(final ClassObject co);
/**
* Converts {@link Object o} to the {@link ClassObject} instance.
*
* @param o object to represent as ClassObject
* @return ClassObject instance
*/
public ClassObject toClassObject(final Object o);
}
A simple implementation of IObjectCreator may look like:
/**
* Simple class we want to send to the RTMP server.
*/
public class CustomClass extends Object
{
public int field1;
public String field2;
}
/**
* IObjectCreator implementation.
*/
public class ObjectCreator implements IObjectCreator
{
public ClassObject toClassObject(final Object o)
{
if (o instanceof CustomClass)
{
final CustomClass cc = (CustomClass) o;
Map propertyValues = new HashMap();
propertyValues.put("field1", cc.field1);
propertyValues.put("field2", cc.field2);
return new ClassObject("CustomClass", propertyValues);
}
else
{
// process other classes
}
}
public Object toObject(final ClassObject co)
{
if ("CustomClass".equals(co.className))
{
CustomClass cc = new CustomClass();
cc.field1 = (Integer) co.propertyValues.get("field1");
cc.field2 = (String) co.propertyValues.get("field2");
return cc;
}
else
{
// process other classes
}
}
// other methods necessary for amf3 serializing/deserializing
}
The library doesn't use any specific logging system. It provides a simple interface that lets you either integrate the library with any logging library or use ILogger implementations provided in the com.smaxe.logger.support package.
public interface ILogger
{
/**
* Logs the message.
*
* @param level message level
* @param message message to log
* @param t thrown exception, null if the exception is not thrown
* @param args optional arguments
*/
public void log(final int level, final String message, final Throwable t, final Object... args);
}
You can define proxy server to use. Proxy instance is used as Socket constructor parameter. The default value is Proxy.NO_PROXY.
Example 4.1. Set license key
com.smaxe.uv.client.rtmp.License.setKey("00000-00000-00000-00000-00000");
Example 4.2. Create and configure NetConnection
NetConnection connection = new NetConnection(); // configure connection.configuration().put(NetConnection.Configuration.INACTIVITY_TIMEOUT, -1 /*seconds, -1 means indefinite timeout*/); connection.configuration().put(NetConnection.Configuration.PAGE_URL, "www.myhost.com/app"); // etc...
Example 4.3. Connect to the server and invoke server method
NetConnection connection = new NetConnection();
// configure connection (if necessary)
// set callback object
connection.client(new Object()
{
// note: this method is invoked in the Dispatch-Thread
public boolean test()
{
System.out.println("NetConnectionCallback#test");
return true;
}
});
// add event listener to get notified about connection status change
connection.addEventListener(new NetConnection.ListenerAdapter()
{
// note: this method is invoked in the Dispatch-Thread
public void onNetStatus(final INetConnection source, final Map info)
{
final Object code = info.get("code");
if (NetConnection.CONNECT_SUCCESS.equals(code))
{
System.out.println("Connected to the server!");
}
}
});
connection.connect("rtmp://localhost:1935/live", "arg1", "arg2" /*arguments*/);
// wait till NetConnection.CONNECT_SUCCESS message is received
// ... waiting ...
// invoke server method
connection.call("testConnection", new com.smaxe.uv.Responder()
{
// note: this method is invoked in the Dispatch-Thread
public void onResult(final Object result)
{
System.out.println("Method testConnection result: " + result);
}
// note: this method is invoked in the Dispatch-Thread
public void onStatus(final Map status)
{
System.out.println("Method testConnection status: " + status);
}
}, "arg3", "arg4" /*arguments*/);
Example 4.4. Connect to the remote shared object
NetConnection connection = new NetConnection();
// ... configure and connect ...
SharedObject so = new SharedObject(name);
so.addEventListener(new ISharedObject.ListenerAdapter()
{
// note: this method is invoked in the Scheduler-Thread
public void onSync(ISharedObject source, final List changeList)
{
for (ISharedObject.Change change : changeList)
{
switch (change.code)
{
case ISharedObject.Change.CONNECT:
{
// connected to the remote shared object
} break;
case ISharedObject.Change.CHANGE:
{
// change.attribute data was changed from the change.oldValue
// to the change.newValue
} break;
case ISharedObject.Change.STATUS:
{
// shared object status notification
} break;
}
}
}
});
so.connect(connection, name);
Example 4.5. Publish local FLV file as live stream
NetConnection connection = new NetConnection();
// ... configure and connect ...
NetStream stream = new NetStream(connection);
stream.addEventListener(new NetStream.ListenerAdapter()
{
@Override
public void onNetStatus(final INetStream source, final Map info)
{
final String code = (String) info.get("code");
if (NetStream.PUBLISH_START.equals(code))
{
}
else
if (NetStream.UNPUBLISHED_SUCCESS.equals(code))
{
}
}
});
final MediaStreamController controller = new MediaStreamController();
stream.attachAudio(new MediaStreamMicrophone(controller));
stream.attachCamera(new MediaStreamCamera(controller), -1);
stream.publish("streamName", NetStream.LIVE);
controller.play(new FlvFileMediaStream("stream.flv"), -1 /*play the whole file*/);
Example 4.6. Publish audio source as live stream (ExRtmpVoicePublisher.java)
public final class MyMicrophone extends AbstractMicrophone
{
// starts microphone capture
public void start()
{
new Thread(new Runnable()
{
while (true)
{
byte[] data = getAudioData(); // returns audio data captured from your source
fireOnAudioData(new MediaDataByteArray(33 /*relative time*/, new ByteArray(data)));
try
{
Thread.sleep(33);
{
catch (Exception e) {}
}
}).start();
}
}
NetConnection connection = new NetConnection();
// ... configure and connect ...
NetStream stream = new NetStream(connection);
stream.addEventListener(new NetStream.ListenerAdapter()
{
@Override
public void onNetStatus(final INetStream source, final Map info)
{
final String code = (String) info.get("code");
if (NetStream.PUBLISH_START.equals(code))
{
}
else
if (NetStream.UNPUBLISHED_SUCCESS.equals(code))
{
}
}
});
MyMicrophone mic = new MyMicrophone();
stream.attachAudio(mic);
stream.publish("streamName", NetStream.LIVE);
mic.start();