use of org.red5.io.utils.ObjectMap in project red5-client by Red5.
the class RTMPSClientTest method test31.
// https://github.com/Red5/red5-client/pull/31
@Test
public void test31() throws InterruptedException {
final RTMPSClient client = new RTMPSClient();
client.setConnectionClosedHandler(new Runnable() {
@Override
public void run() {
System.out.println("Connection closed");
}
});
client.setExceptionHandler(new ClientExceptionHandler() {
@Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
}
});
Thread t = new Thread(new Runnable() {
@Override
public void run() {
client.connect(PropertiesReader.getProperty("rtmps.server"), Integer.valueOf(PropertiesReader.getProperty("rtmps.port")), PropertiesReader.getProperty("rtmps.app"), new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall result) {
System.out.println("resultReceived: " + result);
ObjectMap<?, ?> map = (ObjectMap<?, ?>) result.getResult();
String code = (String) map.get("code");
System.out.printf("Response code: %s\n", code);
if ("NetConnection.Connect.Rejected".equals(code)) {
System.out.printf("Rejected: %s\n", map.get("description"));
client.disconnect();
} else if ("NetConnection.Connect.Success".equals(code)) {
System.out.println("Success: " + result.isSuccess());
// if its oflaDemo, get the list of flvs
if ("oflaDemo".equals(PropertiesReader.getProperty("rtmps.app"))) {
client.invoke("demoService.getListOfAvailableFLVs", new Object[] {}, new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
System.out.println("methodCallCallback");
Map<?, ?> map = (Map<?, ?>) call.getResult();
System.out.printf("Response %s\n", map);
}
});
}
client.createStream(new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
Number streamId = (Number) call.getResult();
// live buffer 0.5s / vod buffer 4s
if (Boolean.valueOf(PropertiesReader.getProperty("rtmps.live"))) {
client.ping(Ping.CLIENT_BUFFER, streamId, 500);
client.play(streamId, PropertiesReader.getProperty("rtmps.name"), -1, -1);
} else {
client.ping(Ping.CLIENT_BUFFER, streamId, 4000);
client.play(streamId, PropertiesReader.getProperty("rtmps.name"), 0, -1);
}
}
});
}
}
});
}
});
t.start();
t.join();
System.out.println("Joined");
Thread.sleep(60000L);
// disconnect
client.disconnect();
}
use of org.red5.io.utils.ObjectMap in project red5-io by Red5.
the class Input method readObject.
@SuppressWarnings({ "unchecked", "rawtypes", "serial" })
@Override
public Object readObject() {
log.trace("readObject - amf3_mode: {}", amf3_mode);
int type = readInteger();
log.debug("Type: {} and {} ref {}", new Object[] { type, (type & 1), (type >> 1) });
if ((type & 1) == 0) {
// Reference
Object ref = getReference(type >> 1);
if (ref != null) {
return ref;
}
byte b = buf.get();
if (b == 7) {
// 7
log.debug("BEL: {}", b);
} else {
log.debug("Non-BEL byte: {} extra byte: {}", b, buf.get());
}
}
type >>= 1;
List<String> attributes = null;
String className;
Object result = null;
boolean inlineClass = (type & 1) == 1;
log.debug("Class is in-line? {}", inlineClass);
if (!inlineClass) {
ClassReference info = refStorage.classReferences.get(type >> 1);
className = info.className;
attributes = info.attributeNames;
type = info.type;
if (attributes != null) {
type |= attributes.size() << 2;
}
} else {
type >>= 1;
className = readString();
log.debug("Type: {} classname: {}", type, className);
// check for flex class alias since these wont be detected as externalizable
if (classAliases.containsKey(className)) {
// make sure type is externalizable
type = 1;
} else if (className.startsWith("flex")) {
// set the attributes for messaging classes
if (className.endsWith("CommandMessage")) {
attributes = new LinkedList<String>() {
{
add("timestamp");
add("headers");
add("operation");
add("body");
add("correlationId");
add("messageId");
add("timeToLive");
add("clientId");
add("destination");
}
};
} else {
log.debug("Attributes for {} were not set", className);
}
}
}
amf3_mode += 1;
Object instance = newInstance(className);
Map<String, Object> properties = null;
PendingObject pending = new PendingObject();
int tempRefId = storeReference(pending);
log.debug("Object type: {}", (type & 0x03));
switch(type & 0x03) {
case AMF3.TYPE_OBJECT_PROPERTY:
log.debug("Detected: Object property type");
// Load object properties into map
int count = type >> 2;
log.debug("Count: {}", count);
if (attributes == null) {
attributes = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
attributes.add(readString());
}
refStorage.classReferences.add(new ClassReference(className, AMF3.TYPE_OBJECT_PROPERTY, attributes));
}
properties = new ObjectMap<>();
for (int i = 0; i < count; i++) {
String name = attributes.get(i);
properties.put(name, Deserializer.deserialize(this, getPropertyType(instance, name)));
}
break;
case AMF3.TYPE_OBJECT_EXTERNALIZABLE:
log.debug("Detected: Externalizable type");
// Use custom class to deserialize the object
if ("".equals(className)) {
throw new RuntimeException("Classname is required to load an Externalizable object");
}
log.debug("Externalizable class: {}", className);
if (className.length() == 3) {
// check for special DS class aliases
className = classAliases.get(className);
}
result = newInstance(className);
if (result == null) {
throw new RuntimeException(String.format("Could not instantiate class: %s", className));
}
if (!(result instanceof IExternalizable)) {
throw new RuntimeException(String.format("Class must implement the IExternalizable interface: %s", className));
}
refStorage.classReferences.add(new ClassReference(className, AMF3.TYPE_OBJECT_EXTERNALIZABLE, null));
storeReference(tempRefId, result);
((IExternalizable) result).readExternal(new DataInput(this));
break;
case AMF3.TYPE_OBJECT_VALUE:
if (log.isDebugEnabled()) {
log.debug("Detected: Object value type");
}
// First, we should read typed (non-dynamic) properties ("sealed traits" according to AMF3 specification).
// Property names are stored in the beginning, then values are stored.
count = type >> 2;
if (log.isDebugEnabled()) {
log.debug("Count: {}", count);
}
if (attributes == null) {
attributes = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
attributes.add(readString());
}
}
// use the size of the attributes if we have no count
if (count == 0 && attributes != null) {
count = attributes.size();
if (log.isDebugEnabled()) {
log.debug("Using class attribute size for property count: {}", count);
}
// read the attributes from the stream and log if count doesnt match
List<String> tmpAttributes = new ArrayList<String>(count);
for (int i = 0; i < count; i++) {
tmpAttributes.add(readString());
}
if (log.isDebugEnabled()) {
if (count != tmpAttributes.size()) {
log.debug("Count and attributes length does not match!");
}
}
}
// create a single reference for attributes
refStorage.classReferences.add(new ClassReference(className, AMF3.TYPE_OBJECT_VALUE, attributes));
// create props
properties = new ObjectMap<>();
for (String key : attributes) {
if (log.isDebugEnabled()) {
log.debug("Looking for property: {}", key);
}
Object value = Deserializer.deserialize(this, getPropertyType(instance, key));
if (log.isDebugEnabled()) {
log.debug("Key: {} Value: {}", key, value);
}
properties.put(key, value);
}
if (log.isTraceEnabled()) {
log.trace("Buffer - position: {} limit: {}", buf.position(), buf.limit());
}
// no more items to read if we are at the end of the buffer
if (buf.hasRemaining()) {
// Now we should read dynamic properties which are stored as name-value pairs.
// Dynamic properties are NOT remembered in 'classReferences'.
String key = readString();
if (log.isDebugEnabled()) {
log.debug("Looking for property: {}", key);
}
while (!"".equals(key)) {
Object value = Deserializer.deserialize(this, getPropertyType(instance, key));
properties.put(key, value);
if (!buf.hasRemaining()) {
break;
}
key = readString();
}
}
break;
default:
case AMF3.TYPE_OBJECT_PROXY:
if (log.isDebugEnabled()) {
log.debug("Detected: Object proxy type");
}
if ("".equals(className)) {
throw new RuntimeException("Classname is required to load an Externalizable object");
}
if (log.isDebugEnabled()) {
log.debug("Externalizable class: {}", className);
}
result = newInstance(className);
if (result == null) {
throw new RuntimeException(String.format("Could not instantiate class: %s", className));
}
if (!(result instanceof IExternalizable)) {
throw new RuntimeException(String.format("Class must implement the IExternalizable interface: %s", className));
}
refStorage.classReferences.add(new ClassReference(className, AMF3.TYPE_OBJECT_PROXY, null));
storeReference(tempRefId, result);
((IExternalizable) result).readExternal(new DataInput(this));
}
amf3_mode -= 1;
if (result == null) {
// Create result object based on classname
if ("".equals(className)) {
// Resolve circular references
for (Map.Entry<String, Object> entry : properties.entrySet()) {
if (entry.getValue() == pending) {
entry.setValue(properties);
}
}
storeReference(tempRefId, properties);
result = properties;
} else if ("RecordSet".equals(className)) {
// TODO: how are RecordSet objects encoded?
throw new RuntimeException("Objects of type RecordSet not supported yet.");
} else if ("RecordSetPage".equals(className)) {
// TODO: how are RecordSetPage objects encoded?
throw new RuntimeException("Objects of type RecordSetPage not supported yet.");
} else {
// Apply properties to object
result = newInstance(className);
if (result != null) {
storeReference(tempRefId, result);
Class resultClass = result.getClass();
pending.resolveProperties(result);
for (Map.Entry<String, Object> entry : properties.entrySet()) {
// Resolve circular references
final String key = entry.getKey();
Object value = entry.getValue();
if (value == pending) {
value = result;
}
if (value instanceof PendingObject) {
// Defer setting of value until real object is created
((PendingObject) value).addPendingProperty(result, resultClass, key);
continue;
}
if (value != null) {
try {
final Field field = resultClass.getField(key);
final Class fieldType = field.getType();
if (!fieldType.isAssignableFrom(value.getClass())) {
value = ConversionUtils.convert(value, fieldType);
} else if (value instanceof Enum) {
value = Enum.valueOf(fieldType, value.toString());
}
field.set(result, value);
} catch (Exception e) {
try {
BeanUtils.setProperty(result, key, value);
} catch (IllegalAccessException ex) {
log.warn("Error mapping key: {} value: {}", key, value);
} catch (InvocationTargetException ex) {
log.warn("Error mapping key: {} value: {}", key, value);
}
}
} else {
if (log.isDebugEnabled()) {
log.debug("Skipping null property: {}", key);
}
}
}
}
// else fall through
}
}
return result;
}
use of org.red5.io.utils.ObjectMap in project red5-client by Red5.
the class StreamRelay method main.
/**
* Creates a stream client to consume a stream from an end point and a proxy to relay the stream to another end point.
*
* @param args
* application arguments
*/
public static void main(String... args) {
// handle the args
if (args == null || args.length < 7) {
System.out.println("Not enough args supplied. Usage: <source uri> <source app> <source stream name> <destination uri> <destination app> <destination stream name> <publish mode>");
} else {
// parse the args
String sourceHost = args[0], destHost = args[3];
String sourceApp = args[1], destApp = args[4];
int sourcePort = 1935, destPort = 1935;
sourceStreamName = args[2];
String destStreamName = args[5];
// live, record, or append
String publishMode = args[6];
// look to see if port was included in host string
int colonIdx = sourceHost.indexOf(':');
if (colonIdx > 0) {
sourcePort = Integer.valueOf(sourceHost.substring(colonIdx + 1));
sourceHost = sourceHost.substring(0, colonIdx);
System.out.printf("Source host: %s port: %d\n", sourceHost, sourcePort);
}
colonIdx = destHost.indexOf(':');
if (colonIdx > 0) {
destPort = Integer.valueOf(destHost.substring(colonIdx + 1));
destHost = destHost.substring(0, colonIdx);
System.out.printf("Destination host: %s port: %d\n", destHost, destPort);
}
// create a timer
timer = new Timer();
// create our publisher
proxy = new StreamingProxy();
proxy.setHost(destHost);
proxy.setPort(destPort);
proxy.setApp(destApp);
proxy.init();
proxy.setConnectionClosedHandler(new Runnable() {
@Override
public void run() {
System.out.println("Publish connection has been closed, source will be disconnected");
client.disconnect();
}
});
proxy.setExceptionHandler(new ClientExceptionHandler() {
@Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
System.exit(2);
}
});
proxy.start(destStreamName, publishMode, new Object[] {});
// wait for the publish state
do {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (!proxy.isPublished());
System.out.println("Publishing...");
// create the consumer
client = new RTMPClient();
client.setStreamEventDispatcher(new StreamEventDispatcher());
client.setStreamEventHandler(new INetStreamEventHandler() {
@Override
public void onStreamEvent(Notify notify) {
System.out.printf("onStreamEvent: %s\n", notify);
ObjectMap<?, ?> map = (ObjectMap<?, ?>) notify.getCall().getArguments()[0];
String code = (String) map.get("code");
System.out.printf("<:%s\n", code);
if (StatusCodes.NS_PLAY_STREAMNOTFOUND.equals(code)) {
System.out.println("Requested stream was not found");
client.disconnect();
} else if (StatusCodes.NS_PLAY_UNPUBLISHNOTIFY.equals(code) || StatusCodes.NS_PLAY_COMPLETE.equals(code)) {
System.out.println("Source has stopped publishing or play is complete");
client.disconnect();
}
}
});
client.setConnectionClosedHandler(new Runnable() {
@Override
public void run() {
System.out.println("Source connection has been closed, proxy will be stopped");
proxy.stop();
}
});
client.setExceptionHandler(new ClientExceptionHandler() {
@Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
System.exit(1);
}
});
// connect the consumer
Map<String, Object> defParams = client.makeDefaultConnectionParams(sourceHost, sourcePort, sourceApp);
// add pageurl and swfurl
defParams.put("pageUrl", "");
defParams.put("swfUrl", "app:/Red5-StreamRelay.swf");
// indicate for the handshake to generate swf verification data
client.setSwfVerification(true);
// connect the client
client.connect(sourceHost, sourcePort, defParams, new IPendingServiceCallback() {
@Override
public void resultReceived(IPendingServiceCall call) {
System.out.println("connectCallback");
ObjectMap<?, ?> map = (ObjectMap<?, ?>) call.getResult();
String code = (String) map.get("code");
if ("NetConnection.Connect.Rejected".equals(code)) {
System.out.printf("Rejected: %s\n", map.get("description"));
client.disconnect();
proxy.stop();
} else if ("NetConnection.Connect.Success".equals(code)) {
// 1. Wait for onBWDone
timer.schedule(new BandwidthStatusTask(), 2000L);
} else {
System.out.printf("Unhandled response code: %s\n", code);
}
}
});
// keep sleeping main thread while the proxy runs
do {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (!proxy.isRunning());
// kill the timer
// timer.cancel();
System.out.println("Stream relay exit");
}
}
use of org.red5.io.utils.ObjectMap in project red5-io by Red5.
the class InputTest method testOnStreamSendMap.
@Test
public void testOnStreamSendMap() {
// 02 = string
// 08 = mixed array (map) max number = 0
IoBuffer data = IoBuffer.wrap(IOUtils.hexStringToByteArray("02 00 0c 6f 6e 53 74 72 65 61 6d 53 65 6e 64 08 00000000 00 05 76 616c7565 02 00 01 31 00 00 09"));
Input in0 = new Input(data);
assertEquals(DataTypes.CORE_STRING, in0.readDataType());
String method = in0.readString();
assertEquals("onStreamSend", method);
assertEquals(DataTypes.CORE_MAP, in0.readDataType());
@SuppressWarnings("rawtypes") ObjectMap map = (ObjectMap) in0.readMap();
assertEquals(map.get("value"), "1");
}
use of org.red5.io.utils.ObjectMap in project red5-io by Red5.
the class AMFIOTest method testAMF0Wiki.
/**
* Sample data from https://en.wikipedia.org/wiki/Action_Message_Format
*/
@Test
public void testAMF0Wiki() {
log.debug("\ntestAMF0Wiki");
IoBuffer data = IoBuffer.wrap(IOUtils.hexStringToByteArray("03 00 04 6e 61 6d 65 02 00 04 4d 69 6b 65 00 03 61 67 65 00 40 3e 00 00 00 00 00 00 00 05 61 6c 69 61 73 02 00 04 4d 69 6b 65 00 00 09"));
Input in0 = new Input(data);
// object
assertEquals(DataTypes.CORE_OBJECT, in0.readDataType());
@SuppressWarnings("rawtypes") ObjectMap person = (ObjectMap) in0.readObject();
assertEquals(person.get("name"), "Mike");
assertEquals(person.get("alias"), "Mike");
assertEquals(person.get("age"), 30d);
}
Aggregations