From ffd58215b69dc3ecf3c8db91125a268abc04527d Mon Sep 17 00:00:00 2001 From: shogo4405 Date: Sat, 26 Nov 2016 01:07:11 +0900 Subject: [PATCH] add Logger --- .../com/haishinkit/amf/AMF0Serializer.java | 2 +- .../main/java/com/haishinkit/net/Socket.java | 10 +++- .../java/com/haishinkit/rtmp/RTMPChunk.java | 34 +++++++++-- .../com/haishinkit/rtmp/RTMPConnection.java | 19 ++++--- .../com/haishinkit/rtmp/RTMPHandshake.java | 6 ++ .../java/com/haishinkit/rtmp/RTMPSocket.java | 24 +++++--- .../haishinkit/util/AndroidLogAdapter.java | 49 ++++++++++++++++ .../com/haishinkit/util/ByteBufferUtils.java | 2 +- .../java/com/haishinkit/util/ILogAdapter.java | 15 +++++ .../main/java/com/haishinkit/util/Log.java | 56 +++++++++++++++++++ .../com/haishinkit/util/SystemLogAdapter.java | 52 +++++++++++++++++ .../com/haishinkit/rtmp/RTMPChunkTest.java | 41 +++++++++++++- .../haishinkit/rtmp/RTMPConnectionTests.java | 18 ++++++ 13 files changed, 301 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/com/haishinkit/util/AndroidLogAdapter.java create mode 100644 app/src/main/java/com/haishinkit/util/ILogAdapter.java create mode 100644 app/src/main/java/com/haishinkit/util/Log.java create mode 100644 app/src/main/java/com/haishinkit/util/SystemLogAdapter.java create mode 100644 app/src/test/java/com/haishinkit/rtmp/RTMPConnectionTests.java diff --git a/app/src/main/java/com/haishinkit/amf/AMF0Serializer.java b/app/src/main/java/com/haishinkit/amf/AMF0Serializer.java index 3c6dadf9e..f59d19773 100644 --- a/app/src/main/java/com/haishinkit/amf/AMF0Serializer.java +++ b/app/src/main/java/com/haishinkit/amf/AMF0Serializer.java @@ -46,7 +46,7 @@ public AMF0Serializer putMap(final Map value) { for (Map.Entry entry: value.entrySet()) { putString(entry.getKey(), true).putObject(entry.getValue()); } - putString("", false); + putString("", true); buffer.put(AMF0Marker.OBJECTEND.valueOf()); return this; } diff --git a/app/src/main/java/com/haishinkit/net/Socket.java b/app/src/main/java/com/haishinkit/net/Socket.java index 5a20de65d..b4376c3e8 100644 --- a/app/src/main/java/com/haishinkit/net/Socket.java +++ b/app/src/main/java/com/haishinkit/net/Socket.java @@ -1,6 +1,9 @@ package com.haishinkit.net; -import android.util.Log; +import com.haishinkit.util.Log; + +import org.apache.commons.lang3.builder.ToStringBuilder; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -72,6 +75,7 @@ private void doOutput() { while (socket != null && socket.isConnected()) { for (ByteBuffer buffer : outputQueue) { try { + buffer.flip(); outputStream.write(buffer.array()); outputStream.flush(); outputQueue.remove(buffer); @@ -105,6 +109,10 @@ public void run() { Log.v(getClass().getName(), e.toString()); } } + + public String toString() { + return ToStringBuilder.reflectionToString(this); + } } diff --git a/app/src/main/java/com/haishinkit/rtmp/RTMPChunk.java b/app/src/main/java/com/haishinkit/rtmp/RTMPChunk.java index 3c6afa6a7..0ff25f93d 100644 --- a/app/src/main/java/com/haishinkit/rtmp/RTMPChunk.java +++ b/app/src/main/java/com/haishinkit/rtmp/RTMPChunk.java @@ -14,6 +14,10 @@ public enum RTMPChunk { TWO((byte) 2), THREE((byte) 3); + public static final short CONTROL = 0x02; + public static final short COMMAND = 0x03; + public static final short AUDIO = 0x04; + public static final short VIDEO = 0x05; public static final int DEFAULT_SIZE = 128; private final byte value; @@ -31,11 +35,14 @@ public List encode(RTMPSocket socket, RTMPMessage message) { throw new IllegalArgumentException(); } - List list = new ArrayList(); ByteBuffer payload = message.encode(socket); + payload.flip(); + + List list = new ArrayList(); int length = payload.limit(); int timestamp = message.getTimestamp(); - ByteBuffer buffer = ByteBuffer.allocate(length(message.getChunkStreamID()) + length); + int chunkSize = socket.getChunkSizeC(); + ByteBuffer buffer = ByteBuffer.allocate(length(message.getChunkStreamID()) + (length < chunkSize ? length : chunkSize)); message.setLength(length); buffer.put(header(message.getChunkStreamID())); @@ -57,9 +64,26 @@ public List encode(RTMPSocket socket, RTMPMessage message) { break; } - payload.flip(); - buffer.put(payload); - buffer.flip(); + if (length < chunkSize) { + buffer.put(payload.array(), 0, length); + buffer.flip(); + list.add(buffer); + return list; + } + + int mod = length % chunkSize; + byte[] three = RTMPChunk.THREE.header(message.getChunkStreamID()); + buffer.put(payload.array(), 0, chunkSize); + list.add(buffer); + for (int i = 1; i < (length - mod) / chunkSize; ++i) { + buffer = ByteBuffer.allocate(three.length + chunkSize); + buffer.put(three); + buffer.put(payload.array(), chunkSize * i, chunkSize); + list.add(buffer); + } + buffer = ByteBuffer.allocate(three.length + mod); + buffer.put(three); + buffer.put(payload.array(), length - mod, mod); list.add(buffer); return list; diff --git a/app/src/main/java/com/haishinkit/rtmp/RTMPConnection.java b/app/src/main/java/com/haishinkit/rtmp/RTMPConnection.java index 764611b1b..42da3fe07 100644 --- a/app/src/main/java/com/haishinkit/rtmp/RTMPConnection.java +++ b/app/src/main/java/com/haishinkit/rtmp/RTMPConnection.java @@ -1,7 +1,5 @@ package com.haishinkit.rtmp; -import android.util.Log; - import java.net.URI; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -11,6 +9,7 @@ import com.haishinkit.rtmp.message.RTMPCommandMessage; import com.haishinkit.rtmp.message.RTMPMessage; +import com.haishinkit.util.Log; public class RTMPConnection { public static final int DEFAULT_PORT = 1935; @@ -126,12 +125,13 @@ public void setFlashVer(String flashVer) { } public void connect(final String command, Object... arguments) { - if (isConnected()) { + uri = URI.create(command); + if (isConnected() || !uri.getScheme().equals("rtmp")) { return; } - uri = URI.create(command); + int port = uri.getPort(); this.arguments = arguments; - socket.connect(command, 1935); + socket.connect(uri.getHost(), port == -1 ? RTMPConnection.DEFAULT_PORT : port); } public void close() { @@ -142,13 +142,14 @@ public void close() { } void listen(ByteBuffer buffer) { - Log.e(getClass().getName(), buffer.toString()); + } RTMPMessage createConnectionMessage() { + String[] paths = uri.getPath().split("/", 0); RTMPCommandMessage message = new RTMPCommandMessage(RTMPObjectEncoding.AMF0); Map commandObject = new HashMap(); - commandObject.put("app", ""); + commandObject.put("app", paths[1]); commandObject.put("flashVer", flashVer); commandObject.put("swfUrl", swfUrl); commandObject.put("tcUrl", uri.toString()); @@ -159,8 +160,10 @@ RTMPMessage createConnectionMessage() { commandObject.put("videoFunction", VideoFunction.CLIENT_SEEK.valueOf()); commandObject.put("pageUrl", pageUrl); commandObject.put("objectEncoding", objectEncoding.valueOf()); + message.setChunkStreamID(RTMPChunk.COMMAND); + message.setStreamID(0); message.setCommandName("connect"); - message.setTransactionID(transactionID++); + message.setTransactionID(++transactionID); message.setCommandObject(commandObject); if (arguments != null) { List args = new ArrayList(arguments.length); diff --git a/app/src/main/java/com/haishinkit/rtmp/RTMPHandshake.java b/app/src/main/java/com/haishinkit/rtmp/RTMPHandshake.java index 897730e4f..adc924da1 100644 --- a/app/src/main/java/com/haishinkit/rtmp/RTMPHandshake.java +++ b/app/src/main/java/com/haishinkit/rtmp/RTMPHandshake.java @@ -1,5 +1,7 @@ package com.haishinkit.rtmp; +import org.apache.commons.lang3.builder.ToStringBuilder; + import java.nio.ByteBuffer; import java.util.Random; @@ -66,4 +68,8 @@ public void clear() { C2Packet = null; S2Packet = null; } + + public String toString() { + return ToStringBuilder.reflectionToString(this); + } } diff --git a/app/src/main/java/com/haishinkit/rtmp/RTMPSocket.java b/app/src/main/java/com/haishinkit/rtmp/RTMPSocket.java index 81a35486b..843332a64 100644 --- a/app/src/main/java/com/haishinkit/rtmp/RTMPSocket.java +++ b/app/src/main/java/com/haishinkit/rtmp/RTMPSocket.java @@ -1,11 +1,12 @@ package com.haishinkit.rtmp; -import android.util.Log; - import java.nio.ByteBuffer; import com.haishinkit.net.Socket; +import com.haishinkit.util.Log; import com.haishinkit.rtmp.message.RTMPMessage; +import org.apache.commons.lang3.builder.ToStringBuilder; + public final class RTMPSocket extends Socket { enum ReadyState { Uninitialized, @@ -38,13 +39,15 @@ public void setChunkSizeC(int chunkSizeC) { this.chunkSizeC = chunkSizeC; } - public void doOutput(RTMPMessage message) { - + public void doOutput(RTMPChunk chunk, RTMPMessage message) { + for (ByteBuffer buffer : chunk.encode(this, message)) { + doOutput(buffer); + } } @Override protected void onConnect() { - Log.v(getClass().getName(), "onConnect"); + Log.v(getClass().getName() + "#onConnect", ""); handshake.clear(); readyState = ReadyState.VersionSent; doOutput(handshake.getC0C1Packet()); @@ -52,10 +55,10 @@ protected void onConnect() { @Override protected void listen(ByteBuffer buffer) { - Log.v(getClass().getName(), "readyState:" + readyState + ":" + buffer.toString()); + Log.v(getClass().getName() + "#listen", "readyState:" + readyState + ":" + buffer.toString()); switch (readyState) { case VersionSent: - if (buffer.limit() <= RTMPHandshake.SIGNAL_SIZE + 1) { + if (buffer.limit() < RTMPHandshake.SIGNAL_SIZE + 1) { break; } handshake.setS0S1Packet(buffer); @@ -67,12 +70,13 @@ protected void listen(ByteBuffer buffer) { } break; case AckSent: - if (buffer.limit() <= RTMPHandshake.SIGNAL_SIZE) { + if (buffer.limit() < RTMPHandshake.SIGNAL_SIZE) { break; } handshake.setS2Packet(buffer); buffer.position(RTMPHandshake.SIGNAL_SIZE); readyState = ReadyState.HandshakeDone; + doOutput(RTMPChunk.ZERO, connection.createConnectionMessage()); break; case HandshakeDone: connection.listen(buffer); @@ -81,4 +85,8 @@ protected void listen(ByteBuffer buffer) { break; } } + + public String toString() { + return ToStringBuilder.reflectionToString(this); + } } diff --git a/app/src/main/java/com/haishinkit/util/AndroidLogAdapter.java b/app/src/main/java/com/haishinkit/util/AndroidLogAdapter.java new file mode 100644 index 000000000..f862d5f76 --- /dev/null +++ b/app/src/main/java/com/haishinkit/util/AndroidLogAdapter.java @@ -0,0 +1,49 @@ +package com.haishinkit.util; + +import android.util.Log; + +public final class AndroidLogAdapter implements ILogAdapter { + public int v(String tag, String msg) { + return Log.v(tag, msg); + } + + public int v(String tag, String msg, Throwable tr) { + return Log.v(tag, msg, tr); + } + + public int d(String tag, String msg) { + return Log.d(tag, msg); + } + + public int d(String tag, String msg, Throwable tr) { + return Log.d(tag, msg, tr); + } + + public int i(String tag, String msg) { + return Log.i(tag, msg); + } + + public int i(String tag, String msg, Throwable tr) { + return Log.i(tag, msg, tr); + } + + public int w(String tag, String msg) { + return Log.w(tag, msg); + } + + public int w(String tag, String msg, Throwable tr) { + return Log.w(tag, msg, tr); + } + + public int w(String tag, Throwable tr) { + return Log.w(tag, tr); + } + + public int e(String tag, String msg) { + return Log.e(tag, msg); + } + + public int e(String tag, String msg, Throwable tr) { + return Log.e(tag, msg, tr); + } +} diff --git a/app/src/main/java/com/haishinkit/util/ByteBufferUtils.java b/app/src/main/java/com/haishinkit/util/ByteBufferUtils.java index ca0fcb3d5..06b6ba56b 100644 --- a/app/src/main/java/com/haishinkit/util/ByteBufferUtils.java +++ b/app/src/main/java/com/haishinkit/util/ByteBufferUtils.java @@ -10,7 +10,7 @@ public static String toHexString(ByteBuffer buffer) { StringBuilder builder = new StringBuilder(); byte[] bytes = buffer.array(); for (byte b : bytes) { - builder.append(String.format("%x", b)); + builder.append(String.format("0x%02x,", b & 0xff)); } return builder.toString(); } diff --git a/app/src/main/java/com/haishinkit/util/ILogAdapter.java b/app/src/main/java/com/haishinkit/util/ILogAdapter.java new file mode 100644 index 000000000..70d76642f --- /dev/null +++ b/app/src/main/java/com/haishinkit/util/ILogAdapter.java @@ -0,0 +1,15 @@ +package com.haishinkit.util; + +public interface ILogAdapter { + public int v(String tag, String msg); + public int v(String tag, String msg, Throwable tr); + public int d(String tag, String msg); + public int d(String tag, String msg, Throwable tr); + public int i(String tag, String msg); + public int i(String tag, String msg, Throwable tr); + public int w(String tag, String msg); + public int w(String tag, String msg, Throwable tr); + public int w(String tag, Throwable tr); + public int e(String tag, String msg); + public int e(String tag, String msg, Throwable tr); +} diff --git a/app/src/main/java/com/haishinkit/util/Log.java b/app/src/main/java/com/haishinkit/util/Log.java new file mode 100644 index 000000000..e41761671 --- /dev/null +++ b/app/src/main/java/com/haishinkit/util/Log.java @@ -0,0 +1,56 @@ +package com.haishinkit.util; + +public final class Log { + private static ILogAdapter adapter = new SystemLogAdapter(); + + static { + String runtime = System.getProperty("java.runtime.name"); + if (0 <= runtime.indexOf("Android")) { + adapter = new AndroidLogAdapter(); + } + } + + public static int v(String tag, String msg) { + return adapter.v(tag, msg); + } + + public static int v(String tag, String msg, Throwable tr) { + return adapter.v(tag, msg, tr); + } + + public static int d(String tag, String msg) { + return adapter.v(tag, msg); + } + + public static int d(String tag, String msg, Throwable tr) { + return adapter.d(tag, msg, tr); + } + + public static int i(String tag, String msg) { + return adapter.i(tag, msg); + } + + public static int i(String tag, String msg, Throwable tr) { + return adapter.i(tag, msg, tr); + } + + public static int w(String tag, String msg) { + return adapter.w(tag, msg); + } + + public static int w(String tag, String msg, Throwable tr) { + return adapter.w(tag, msg, tr); + } + + public static int w(String tag, Throwable tr) { + return adapter.w(tag, tr); + } + + public static int e(String tag, String msg) { + return adapter.e(tag, msg); + } + + public static int e(String tag, String msg, Throwable tr) { + return adapter.e(tag, msg, tr); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/haishinkit/util/SystemLogAdapter.java b/app/src/main/java/com/haishinkit/util/SystemLogAdapter.java new file mode 100644 index 000000000..7b1832074 --- /dev/null +++ b/app/src/main/java/com/haishinkit/util/SystemLogAdapter.java @@ -0,0 +1,52 @@ +package com.haishinkit.util; + +public final class SystemLogAdapter implements ILogAdapter { + public int v(String tag, String msg) { + return println("VERBOSE", tag, msg); + } + + public int v(String tag, String msg, Throwable tr) { + return println("VERBOSE", tag, tr.toString()); + } + + public int d(String tag, String msg) { + return println("DEBUG", tag, msg); + } + + public int d(String tag, String msg, Throwable tr) { + return println("DEBUG", tag, tr.toString()); + } + + public int i(String tag, String msg) { + return println("INFO", tag, msg); + } + + public int i(String tag, String msg, Throwable tr) { + return println("INFO", tag, tr.toString()); + } + + public int w(String tag, String msg) { + return println("WARN", tag, msg); + } + + public int w(String tag, String msg, Throwable tr) { + return println("WARN", tag, msg); + } + + public int w(String tag, Throwable tr) { + return println("WARN", tag, tr.toString()); + } + + public int e(String tag, String msg) { + return println("EMERGENCY", tag, msg); + } + + public int e(String tag, String msg, Throwable tr) { + return println("EMERGENCY", tag, msg); + } + + private int println(String level, String tag, String msg) { + System.out.println("[" + level + "][" + tag + "]" + msg); + return 0; + } +} diff --git a/app/src/test/java/com/haishinkit/rtmp/RTMPChunkTest.java b/app/src/test/java/com/haishinkit/rtmp/RTMPChunkTest.java index a89f6b3ac..06c501738 100644 --- a/app/src/test/java/com/haishinkit/rtmp/RTMPChunkTest.java +++ b/app/src/test/java/com/haishinkit/rtmp/RTMPChunkTest.java @@ -1,16 +1,20 @@ package com.haishinkit.rtmp; +import com.haishinkit.rtmp.message.RTMPCommandMessage; import com.haishinkit.rtmp.message.RTMPSetChunkSizeMessage; import com.haishinkit.util.ByteBufferUtils; import org.junit.Test; -import java.util.List; + import java.nio.ByteBuffer; -import static org.junit.Assert.*; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class RTMPChunkTest { @Test - public void encode() { + public void encodeSetChunkSize() { RTMPSetChunkSizeMessage message = new RTMPSetChunkSizeMessage(); message.setChunkStreamID((short) 1); message.setStreamID(1); @@ -24,4 +28,35 @@ public void encode() { System.out.println(ByteBufferUtils.toHexString(buffer)); } } + + @Test + public void encodeCommand() { + Map commandObject = new HashMap(); + commandObject.put("app", ""); + commandObject.put("flashVer", "MAC10"); + commandObject.put("swfUrl", "http://localhost/hoge.swf"); + commandObject.put("tcUrl", "rtmp://localhost/appName/instanceName/"); + commandObject.put("fpad", false); + commandObject.put("capabilities", 10); + commandObject.put("audioCodecs", 10); + commandObject.put("videoCodecs", 10); + commandObject.put("videoFunction", 1); + commandObject.put("pageUrl", "http://localhost/"); + commandObject.put("objectEncoding", 3); + commandObject.put("timestamp", new Date()); + + RTMPCommandMessage message = new RTMPCommandMessage(RTMPObjectEncoding.AMF0); + message.setChunkStreamID((short) 2); + message.setCommandName("connect"); + message.setCommandObject(commandObject); + + RTMPConnection connection = new RTMPConnection(); + RTMPSocket socket = new RTMPSocket(connection); + socket.setChunkSizeC(1024); + + List list = RTMPChunk.ZERO.encode(socket, message); + for (ByteBuffer buffer : list) { + System.out.println(ByteBufferUtils.toHexString(buffer)); + } + } } diff --git a/app/src/test/java/com/haishinkit/rtmp/RTMPConnectionTests.java b/app/src/test/java/com/haishinkit/rtmp/RTMPConnectionTests.java new file mode 100644 index 000000000..a5886400e --- /dev/null +++ b/app/src/test/java/com/haishinkit/rtmp/RTMPConnectionTests.java @@ -0,0 +1,18 @@ +package com.haishinkit.rtmp; + +import com.haishinkit.util.Log; + +import org.junit.Test; + +public final class RTMPConnectionTests { + @Test + public void connect() { + RTMPConnection connection = new RTMPConnection(); + connection.connect("rtmp://localhost/live"); + try { + Thread.sleep(1000 * 10); + } catch (InterruptedException e) { + Log.i("RTMPConnection#connect", e.toString()); + } + } +}