diff --git a/RTMPS.md b/RTMPS.md
index ea2f808c6..e34a6d029 100644
--- a/RTMPS.md
+++ b/RTMPS.md
@@ -2,54 +2,190 @@
RTMPS is a secure version of RTMP that uses TLS/SSL to encrypt the data. This is a guide to setting up RTMPS with Red5. An example keystore and truststore creation process will be explained as these files are required for the RTMPS feature. Examples will be provided for both the server and client side which will demonstrate how to use RTMPS and PKCS12 type keystores; JKS keystores can also be used, but are not covered here.
-## Configuration
+## Keystore and Truststore Creation
-### Server
+The following commands will create the necessary files for the RTMPS feature. The keystore will contain the server certificate and private key, while the truststore will contain the CA certificate. The client will use the truststore to verify the server certificate. Self-signed certificates are used in this example and are not expected to prevent the client from connecting to the server; in testing, the `ffplay` worked without issue. Examples show sample input for the certificate creation process.
-On a server where RTMPS will be employed, two files in `conf` must be updated: `red5.properties` and `red5-core.xml`. This is in-addition to the keystore and truststore proceedure.
+* Create our CA key and certificate for self-signing:
-* In `red5-core.xml` uncomment the beans named `rtmpsMinaIoHandler` and `rtmpsTransport` which may be updated as required, otherwise their values come from the `red5.properties` file. See [Advanced-configuration](#advanced-configuration) for more information.
+```bash
+openssl ecparam -name prime256v1 -genkeopenssl ecparam -name prime256v1 -genkey -noout -out ca.key
-* In `red5.properties`, update these properties to utilize your values; especially for store passwords and locations:
+openssl req -new -x509 -sha256 -key ca.key -out ca.crt -days 3650
-```properties
-# RTMPS
-rtmps.host=0.0.0.0
-rtmps.port=8443
-rtmps.ping_interval=5000
-rtmps.max_inactivity=60000
-rtmps.max_keep_alive_requests=-1
-rtmps.max_threads=8
-rtmps.acceptor_thread_count=2
-rtmps.processor_cache=20
-# RTMPS Key and Trust store parameters
-rtmps.keystorepass=password123
-rtmps.keystorefile=conf/server.p12
-rtmps.truststorepass=password123
-rtmps.truststorefile=conf/truststore.p12
+You are about to be asked to enter information that will be incorporated
+into your certificate request.
+What you are about to enter is what is called a Distinguished Name or a DN.
+There are quite a few fields but you can leave some blank
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.
+-----
+Country Name (2 letter code) [AU]:US
+State or Province Name (full name) [Some-State]:Nevada
+Locality Name (eg, city) []:Henderson
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:Red5
+Organizational Unit Name (eg, section) []:dev
+Common Name (e.g. server FQDN or YOUR name) []:Paul Gregoire
+Email Address []:mondain@gmail.com
```
-### Client
+* Create the server key and certificate request:
+```bash
+openssl ecparam -name prime256v1 -genkey -noout -out server.key
-```java
-TLSFactory.setKeystorePath("/workspace/client/conf/rtmps_server.p12");
-TLSFactory.setTruststorePath("/workspace/client/conf/rtmps_truststore.p12");
+openssl req -new -sha256 -key server.key -out server.csr
+
+You are about to be asked to enter information that will be incorporated
+into your certificate request.
+What you are about to enter is what is called a Distinguished Name or a DN.
+There are quite a few fields but you can leave some blank
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.
+-----
+Country Name (2 letter code) [AU]:US
+State or Province Name (full name) [Some-State]:Nevada
+Locality Name (eg, city) []:Henderson
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:Red5
+Organizational Unit Name (eg, section) []:dev
+Common Name (e.g. server FQDN or YOUR name) []:mondain-XPS-8930
+Email Address []:mondain@gmail.com
+
+Please enter the following 'extra' attributes
+to be sent with your certificate request
+A challenge password []:
+An optional company name []:
```
-## Testing
+* CA sign the server certificate request:
-Using ffplay issue the following, update for your server IP and stream name as needed: `ffplay rtmps://localhost:8443/live/stream1`
+```bash
+openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650
+Certificate request self-signature ok
+subject=C = US, ST = Nevada, L = Henderson, O = Red5, OU = dev, CN = mondain-XPS-8930, emailAddress = mondain@gmail.com
+```
-### Useful System Properties
+* Create the client key and certificate request:
+
+```bash
+openssl ecparam -name prime256v1 -genkey -noout -out client.key
+
+openssl req -new -sha256 -key client.key -out client.csr
+
+You are about to be asked to enter information that will be incorporated
+into your certificate request.
+What you are about to enter is what is called a Distinguished Name or a DN.
+There are quite a few fields but you can leave some blank
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.
+-----
+Country Name (2 letter code) [AU]:US
+State or Province Name (full name) [Some-State]:Nevada
+Locality Name (eg, city) []:Henderson
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:Red5
+Organizational Unit Name (eg, section) []:dev
+Common Name (e.g. server FQDN or YOUR name) []:mondain-XPS-8930
+Email Address []:mondain@gmail.com
+
+Please enter the following 'extra' attributes
+to be sent with your certificate request
+A challenge password []:
+An optional company name []:
+```
+
+* CA sign the client certificate request:
+
+```bash
+openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 3650
+
+Certificate request self-signature ok
+subject=C = US, ST = Nevada, L = Henderson, O = Red5, OU = dev, CN = mondain-XPS-8930, emailAddress = mondain@gmail.com
+```
+
+* Add the server certificate to the keystore (_Make sure to use the same password for the key and store_):
+
+```bash
+keytool -genkey -dname "CN=mondain-XPS-8930, OU=dev, O=Red5, L=Henderson, S=Nevada, C=US" -keystore rtmps_keystore.jks -storepass password123 -keypass password123 -alias server -keyalg RSA -file server.crt
+
+Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 90 days
+ for: CN=mondain-XPS-8930, OU=dev, O=Red5, L=Henderson, ST=Nevada, C=US
+```
+
+* Add the self-signed CA root certificate to the truststore (_Make sure to use the same password for the store_):
+
+```bash
+keytool -import -trustcacerts -file ca.crt -alias CARoot -keystore rtmps_truststore.jks -storepass password123
+
+Owner: EMAILADDRESS=mondain@gmail.com, CN=Paul Gregoire, OU=dev, O=Red5, L=Henderson, ST=Nevada, C=US
+Issuer: EMAILADDRESS=mondain@gmail.com, CN=Paul Gregoire, OU=dev, O=Red5, L=Henderson, ST=Nevada, C=US
+Serial number: 7139dce6b44a5e3d50ace573849cf88e63366153
+Valid from: Mon Mar 04 18:10:14 PST 2024 until: Thu Mar 02 18:10:14 PST 2034
+Certificate fingerprints:
+ SHA1: 48:CC:8A:65:5B:96:5B:7B:39:6C:55:27:30:84:24:B8:67:B0:91:6A
+ SHA256: C0:41:37:4C:DB:49:12:6B:14:C5:B4:8E:4A:28:1C:33:A0:C2:38:C7:76:44:97:6B:5E:A0:7B:20:01:0F:C9:2C
+Signature algorithm name: SHA256withECDSA
+Subject Public Key Algorithm: 256-bit EC (secp256r1) key
+Version: 3
+
+Extensions:
+
+#1: ObjectId: 2.5.29.35 Criticality=false
+AuthorityKeyIdentifier [
+KeyIdentifier [
+0000: FF 05 5E DA 39 EB B5 40 E2 0D 5F 6A 90 DC C3 0B ..^.9..@.._j....
+0010: 12 B2 6D F6 ..m.
+]
+]
+
+#2: ObjectId: 2.5.29.19 Criticality=true
+BasicConstraints:[
+ CA:true
+ PathLen: no limit
+]
+
+#3: ObjectId: 2.5.29.14 Criticality=false
+SubjectKeyIdentifier [
+KeyIdentifier [
+0000: FF 05 5E DA 39 EB B5 40 E2 0D 5F 6A 90 DC C3 0B ..^.9..@.._j....
+0010: 12 B2 6D F6 ..m.
+]
+]
+
+Trust this certificate? [no]: yes
+Certificate was added to keystore
+```
+
+* Last step is to convert the keystore and truststore to PKCS12 format (_Make sure to use the same passwords_):
+
+```bash
+
+keytool -importkeystore -srckeystore rtmps_keystore.jks -destkeystore rtmps_keystore.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass password123 -deststorepass password123 -srcalias server -destalias server -noprompt
+
+keytool -importkeystore -srckeystore rtmps_truststore.jks -destkeystore rtmps_truststore.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass password123 -deststorepass password123
+```
+
+## Configuration
+
+The following configuration changes are required to enable RTMPS in Red5.
+### Server
+
+On a server where RTMPS will be employed, two files in `conf` must be updated: `red5.properties` and `red5-core.xml`. This is in-addition to the keystore and truststore proceedure.
-`-Djavax.net.debug=SSL,handshake,verbose,trustmanager,keymanager,record,plaintext`
+* In `red5-core.xml` uncomment the beans named `rtmpsMinaIoHandler` and `rtmpsTransport` which may be updated as required, otherwise their values come from the `red5.properties` file.
-## Advanced configuration
+```xml
+
+
+
+
+
+
+
+```
-* The ciphers and protocols can be modified in the `rtmpsMinaIoHandler` bean in `red5-core.xml` to suit any special needs.
+To modify the ciphers and / or protocols in the `rtmpsMinaIoHandler` bean in `red5-core.xml`, see the example below:
```xml
@@ -72,3 +208,51 @@ Using ffplay issue the following, update for your server IP and stream name as n
```
+
+* In `red5.properties`, update these properties to utilize your values; especially for store passwords and locations:
+
+```properties
+# RTMPS
+rtmps.host=0.0.0.0
+rtmps.port=8443
+rtmps.ping_interval=5000
+rtmps.max_inactivity=60000
+rtmps.max_keep_alive_requests=-1
+rtmps.max_threads=8
+rtmps.acceptor_thread_count=2
+rtmps.processor_cache=20
+# RTMPS Key and Trust store parameters
+rtmps.keystorepass=password123
+rtmps.keystorefile=conf/rtmps_keystore.p12
+rtmps.truststorepass=password123
+rtmps.truststorefile=conf/rtmps_truststore.p12
+```
+
+### Client
+
+When connecting to a server that uses RTMPS, the client must have the server's certificate in its truststore. The following example demonstrates how to use the truststore with the Red5 client. Before connecting to the server, the client must set the keystore and truststore paths with password.
+
+* Using full paths to the keystore and truststore files:
+
+```java
+TLSFactory.setKeystorePath("/workspace/client/conf/rtmps_keystore.p12");
+TLSFactory.setTruststorePath("/workspace/client/conf/rtmps_truststore.p12");
+```
+
+* When the keystore and truststore are contained within a jar file, use the following format: `jar:file:/path/to/your.jar!/path/to/file/in/jar` for the keystore and truststore paths. This example assumes the jar file which is named `my_rtmps_client.jar` file is contained in a `lib` sub-directory of the application client launch location and the keystore and truststore are in the root:
+
+```java
+String jarKeystorePath = String.format("jar:file:%s/lib/my_rtmps_client.jar!/rtmps_%s.p12", Paths.get(System.getProperty("user.dir"), "keystore");
+TLSFactory.setKeystorePath(jarKeystorePath);
+String jarTruststorePath = String.format("jar:file:%s/lib/my_rtmps_client.jar!/rtmps_%s.p12", Paths.get(System.getProperty("user.dir"), "truststore");
+TLSFactory.setTruststorePath(jarTruststorePath);
+```
+
+## Testing
+
+Using ffplay to test playback, issue the following, but make sure to update the command for your server IP and stream name: `ffplay rtmps://localhost:8443/live/stream1` (this assumes a stream named `stream1` is being published already).
+
+### Useful System Properties
+
+* To enable SSL debugging, add the following system property to the JVM: `-Djavax.net.debug=SSL`
+* To enable more detailed SSL debugging, add the following system property to the JVM: `-Djavax.net.debug=SSL,handshake,verbose,trustmanager,keymanager,record,plaintext`
diff --git a/client/src/main/java/org/red5/client/net/rtmps/RTMPSClient.java b/client/src/main/java/org/red5/client/net/rtmps/RTMPSClient.java
index 63950ad3a..c2acaf235 100644
--- a/client/src/main/java/org/red5/client/net/rtmps/RTMPSClient.java
+++ b/client/src/main/java/org/red5/client/net/rtmps/RTMPSClient.java
@@ -7,7 +7,12 @@
package org.red5.client.net.rtmps;
+import java.io.IOException;
+import java.io.InputStream;
import java.net.InetSocketAddress;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import javax.net.ssl.SSLContext;
@@ -50,6 +55,11 @@ public class RTMPSClient extends RTMPClient {
*/
private char[] password = "password123".toCharArray();
+ /**
+ * Path to the keystore and truststore files.
+ */
+ private InputStream keystoreStream, truststoreStream;
+
/**
* The keystore type, valid options are JKS and PKCS12
*/
@@ -87,6 +97,26 @@ public RTMPSClient(String keyStoreType, String password) {
ioHandler.setHandler(this);
}
+ /**
+ * Creates a new RTMPSClient with the given keystore type, password, and paths to store files. If the stores
+ * are inside a jar file, use the following format: jar:file:/path/to/your.jar!/path/to/file/in/jar
+ *
+ * @param keyStoreType keystore type
+ * @param password keystore password
+ * @param keystorePath path to keystore file
+ * @param truststorePath path to truststore file
+ * @throws IOException
+ */
+ public RTMPSClient(String keyStoreType, String password, String keystorePath, String truststorePath) throws IOException {
+ protocol = "rtmps";
+ this.keyStoreType = keyStoreType;
+ this.password = password.toCharArray();
+ this.keystoreStream = Files.newInputStream(Paths.get(URI.create(keystorePath)));
+ this.truststoreStream = Files.newInputStream(Paths.get(URI.create(truststorePath)));
+ ioHandler = new RTMPSClientIoHandler();
+ ioHandler.setHandler(this);
+ }
+
@SuppressWarnings({ "rawtypes" })
@Override
protected void startConnector(String server, int port) {
@@ -141,8 +171,13 @@ private class RTMPSClientIoHandler extends RTMPMinaIoHandler {
@Override
public void sessionOpened(IoSession session) throws Exception {
log.debug("RTMPS sessionOpened: {}", session);
- // do tls stuff
- SSLContext context = TLSFactory.getTLSContext(keyStoreType, password);
+ // if we're using a input streams, pass them to the ctor
+ SSLContext context = null;
+ if (keystoreStream != null && truststoreStream != null) {
+ context = TLSFactory.getTLSContext(keyStoreType, password, keystoreStream, password, truststoreStream);
+ } else {
+ context = TLSFactory.getTLSContext(keyStoreType, password);
+ }
SslFilter sslFilter = new SslFilter(context);
if (sslFilter != null) {
// we are a client
diff --git a/io/src/main/java/org/red5/io/tls/TLSFactory.java b/io/src/main/java/org/red5/io/tls/TLSFactory.java
index f06d7b5b1..6ce2fb2a8 100644
--- a/io/src/main/java/org/red5/io/tls/TLSFactory.java
+++ b/io/src/main/java/org/red5/io/tls/TLSFactory.java
@@ -1,6 +1,7 @@
package org.red5.io.tls;
import java.io.FileInputStream;
+import java.io.InputStream;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
@@ -63,7 +64,8 @@ public class TLSFactory {
Security.setProperty("crypto.policy", "unlimited");
// set extensions
System.setProperty("jdk.tls.useExtendedMasterSecret", "true"); // https://bugs.openjdk.org/browse/JDK-8192045 not for DTLS 1.3
- System.setProperty("jdk.tls.allowLegacyMasterSecret", "false"); // allows rejection if session hash and master secret are not supported
+ // allows rejection if session hash and master secret are not supported
+ System.setProperty("jdk.tls.allowLegacyMasterSecret", "false");
System.setProperty("jdk.tls.acknowledgeCloseNotify", "true");
// https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html
// https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/ReadDebug.html
@@ -78,6 +80,12 @@ public class TLSFactory {
log.info("Max key size for AES: {}", (maxKeySize == Integer.MAX_VALUE ? "unlimited" : maxKeySize));
}
+ /**
+ * Returns an SSLContext for the configured keystore and truststore with the default password.
+ *
+ * @return SSLContext
+ * @throws Exception
+ */
public static SSLContext getTLSContext() throws Exception {
log.info("Creating SSL context with keystore: {} and truststore: {} using {}", keystorePath, truststorePath, storeType);
KeyStore ks = KeyStore.getInstance(storeType);
@@ -109,6 +117,13 @@ public static SSLContext getTLSContext() throws Exception {
return sslCtx;
}
+ /**
+ * Returns an SSLContext for the configured keystore and truststore with the provided password.
+ *
+ * @param passphrase
+ * @return SSLContext
+ * @throws Exception
+ */
public static SSLContext getTLSContext(String storeType, char[] passphrase) throws Exception {
log.info("Creating SSL context with keystore: {} and truststore: {} using {}", keystorePath, truststorePath, storeType);
log.debug("Keystore - file: {} password: {}", keystorePath, passphrase);
@@ -143,6 +158,17 @@ public static SSLContext getTLSContext(String storeType, char[] passphrase) thro
return sslCtx;
}
+ /**
+ * Returns an SSLContext for the provided keystore, truststore, and password.
+ *
+ * @param storeType
+ * @param keystorePassword
+ * @param keystorePath
+ * @param truststorePassword
+ * @param truststorePath
+ * @return SSLContext
+ * @throws Exception
+ */
public static SSLContext getTLSContext(String storeType, String keystorePassword, String keystorePath, String truststorePassword, String truststorePath) throws Exception {
log.info("Creating SSL context with keystore: {} and truststore: {} using {}", keystorePath, truststorePath, storeType);
log.debug("Keystore - file: {} password: {}", keystorePath, keystorePassword);
@@ -166,6 +192,34 @@ public static SSLContext getTLSContext(String storeType, String keystorePassword
return sslCtx;
}
+ /**
+ * Returns an SSLContext for the provided keystore and truststore input streams.
+ *
+ * @param storeType
+ * @param keyStrorePassphrase
+ * @param keystoreInput
+ * @param trustStorePassphrase
+ * @param truststoreInput
+ * @return SSLContext
+ * @throws Exception
+ */
+ public static SSLContext getTLSContext(String storeType, char[] keyStrorePassphrase, InputStream keystoreInput, char[] trustStorePassphrase, InputStream truststoreInput) throws Exception {
+ log.info("Creating SSL context with keystore and truststore input streams, using {}", storeType);
+ log.debug("Keystore - passphrase: {}", keyStrorePassphrase);
+ log.debug("Truststore - passphrase: {}", trustStorePassphrase);
+ KeyStore ks = KeyStore.getInstance(storeType);
+ KeyStore ts = KeyStore.getInstance(storeType);
+ ks.load(keystoreInput, keyStrorePassphrase);
+ ts.load(truststoreInput, trustStorePassphrase);
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+ kmf.init(ks, keyStrorePassphrase);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+ tmf.init(ts);
+ SSLContext sslCtx = SSLContext.getInstance(PROTOCOL_VERSION);
+ sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), RANDOM);
+ return sslCtx;
+ }
+
public static SSLEngine createSSLEngine(boolean isClient) throws Exception {
SSLContext context = getTLSContext();
SSLEngine engine = context.createSSLEngine();
diff --git a/pom.xml b/pom.xml
index 45fb3aa2c..56dbab29f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -104,7 +104,7 @@
1.78.1
2.0.23
- 5.3.33
+ 5.3.39
8.5.100
[4.13.1,)
1.9.59
diff --git a/server/src/main/java/org/red5/server/net/rtmps/RTMPSMinaIoHandler.java b/server/src/main/java/org/red5/server/net/rtmps/RTMPSMinaIoHandler.java
index 3af459118..34f703665 100644
--- a/server/src/main/java/org/red5/server/net/rtmps/RTMPSMinaIoHandler.java
+++ b/server/src/main/java/org/red5/server/net/rtmps/RTMPSMinaIoHandler.java
@@ -53,24 +53,14 @@ public class RTMPSMinaIoHandler extends RTMPMinaIoHandler {
private static Logger log = LoggerFactory.getLogger(RTMPSMinaIoHandler.class);
/**
- * Password for accessing the keystore.
+ * Password for accessing the keystore and / or truststore.
*/
- private String keystorePassword;
+ private String keystorePassword, truststorePassword;
/**
- * Password for accessing the truststore.
+ * Stores the keystore and truststore paths.
*/
- private String truststorePassword;
-
- /**
- * Stores the keystore path.
- */
- private String keystorePath;
-
- /**
- * Stores the truststore path.
- */
- private String truststorePath;
+ private String keystorePath, truststorePath;
/**
* Names of the SSL cipher suites which are currently enabled for use.
diff --git a/server/src/test/java/org/red5/client/net/rtmps/RTMPSClientTest.java b/server/src/test/java/org/red5/client/net/rtmps/RTMPSClientTest.java
index 2986cf756..a5c27c383 100644
--- a/server/src/test/java/org/red5/client/net/rtmps/RTMPSClientTest.java
+++ b/server/src/test/java/org/red5/client/net/rtmps/RTMPSClientTest.java
@@ -22,50 +22,47 @@ public void test31() throws InterruptedException {
final RTMPSClient client = new RTMPSClient();
client.setConnectionClosedHandler(() -> System.out.println("Connection closed"));
- 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() {
+ Thread t = new Thread(() -> {
+ 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) {
- 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);
- }
+ 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();
@@ -74,6 +71,7 @@ public void resultReceived(IPendingServiceCall call) {
RTMP rtmpState = conn.getState();
System.out.println("Joined with state: " + rtmpState);
if (rtmpState != null && rtmpState.getState() == RTMP.STATE_CONNECTED) {
+ System.out.println("Connection is connected, waiting for 60s");
Thread.sleep(60000L);
} else {
System.out.println("Connection is not connected");