Search in sources :

Example 1 with ObjectMap

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();
}
Also used : IPendingServiceCallback(org.red5.server.api.service.IPendingServiceCallback) IPendingServiceCall(org.red5.server.api.service.IPendingServiceCall) ClientExceptionHandler(org.red5.client.net.rtmp.ClientExceptionHandler) ObjectMap(org.red5.io.utils.ObjectMap) ObjectMap(org.red5.io.utils.ObjectMap) Map(java.util.Map) Test(org.junit.Test)

Example 2 with ObjectMap

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;
}
Also used : ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) IOException(java.io.IOException) InvocationTargetException(java.lang.reflect.InvocationTargetException) InvocationTargetException(java.lang.reflect.InvocationTargetException) Field(java.lang.reflect.Field) ObjectMap(org.red5.io.utils.ObjectMap) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap)

Example 3 with ObjectMap

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");
    }
}
Also used : IPendingServiceCallback(org.red5.server.api.service.IPendingServiceCallback) Notify(org.red5.server.net.rtmp.event.Notify) INetStreamEventHandler(org.red5.client.net.rtmp.INetStreamEventHandler) IPendingServiceCall(org.red5.server.api.service.IPendingServiceCall) RTMPClient(org.red5.client.net.rtmp.RTMPClient) StreamingProxy(org.red5.proxy.StreamingProxy) Timer(java.util.Timer) ClientExceptionHandler(org.red5.client.net.rtmp.ClientExceptionHandler) ObjectMap(org.red5.io.utils.ObjectMap)

Example 4 with ObjectMap

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");
}
Also used : ObjectMap(org.red5.io.utils.ObjectMap) IoBuffer(org.apache.mina.core.buffer.IoBuffer) Test(org.junit.Test)

Example 5 with ObjectMap

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);
}
Also used : Input(org.red5.io.amf.Input) ObjectMap(org.red5.io.utils.ObjectMap) IoBuffer(org.apache.mina.core.buffer.IoBuffer) Test(org.junit.Test)

Aggregations

ObjectMap (org.red5.io.utils.ObjectMap)16 Test (org.junit.Test)6 IPendingServiceCall (org.red5.server.api.service.IPendingServiceCall)6 IPendingServiceCallback (org.red5.server.api.service.IPendingServiceCallback)5 Notify (org.red5.server.net.rtmp.event.Notify)5 IoBuffer (org.apache.mina.core.buffer.IoBuffer)4 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2 ClientExceptionHandler (org.red5.client.net.rtmp.ClientExceptionHandler)2 Input (org.red5.io.amf.Input)2 IEvent (org.red5.server.api.event.IEvent)2 IEventDispatcher (org.red5.server.api.event.IEventDispatcher)2 IClientSharedObject (org.red5.server.api.so.IClientSharedObject)2 RTMPConnection (org.red5.server.net.rtmp.RTMPConnection)2 IOException (java.io.IOException)1 Field (java.lang.reflect.Field)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 HashMap (java.util.HashMap)1 LinkedList (java.util.LinkedList)1 SortedMap (java.util.SortedMap)1