diff --git a/.gitignore b/.gitignore
index fbd6a97..f1c2c72 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,8 +3,11 @@
*.settings
*.classpath
*.factorypath
+
+.vscode
+
package-lock.json
logs
target
-node_modules
\ No newline at end of file
+node_modules
diff --git a/README.md b/README.md
index 7b3d0d1..5a4f363 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@ Android还在学习之中...
## TODO
* P2P
+* RTP
* 标识 -> ID
* 所有字段获取 -> get
* 优化JS错误回调 -> platform::error
diff --git a/docs/AOSP.md b/docs/AOSP.md
new file mode 100644
index 0000000..329e480
--- /dev/null
+++ b/docs/AOSP.md
@@ -0,0 +1,72 @@
+# AOSP
+
+本文档内容旨在独立定制编译`AOSP`系统,非必需使用。
+
+## 参考文档
+
+* https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/
+* https://source.android.google.cn/source/initializing?hl=zh-cn
+* https://source.android.google.cn/docs/setup/about/build-numbers?hl=zh-cn
+* https://developers.google.cn/android/drivers#sargosp2a.220505.008
+
+## 机器配置
+
+* 内存`32G`
+* 十六核`CPU`
+* 硬盘`300G`
+* 系统`Ubuntu 18.xx`
+* 公司网络`100Mbps/s`
+* 整个下载过程大概需要四到五个小时
+* 整个编译过程大概需要半到一个小时
+
+## 源码
+
+```
+# 工具
+mkdir /data/android
+cd /data/android
+curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o repo
+chmod a+x repo
+export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'
+
+git config --global user.email "taoyao@acgist.com"
+git config --global user.name "acgist"
+
+# 源码
+./repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-12.1.0_r27
+./repo sync
+```
+
+ROOT权限
+
+## 裁剪
+
+```
+# 应用
+
+# 驱动
+
+# root
+userdebug
+
+# framework
+```
+
+## 编译
+
+```
+lunch aosp_arm64-user
+make -j 8
+```
+
+## 刷机
+
+```
+adb reboot bootloader
+fastboot flashall
+```
+
+
+https://blog.csdn.net/u012932409/article/details/106792906
+https://blog.csdn.net/qq_33240707/article/details/123704679
+https://blog.csdn.net/weixin_42929891/article/details/122667831
\ No newline at end of file
diff --git a/docs/Deploy.md b/docs/Deploy.md
index 4d77bff..b4e6aa5 100644
--- a/docs/Deploy.md
+++ b/docs/Deploy.md
@@ -278,90 +278,6 @@ SELINUX=disabled
---
```
-## libwebrtc(可选)
-
-* https://webrtc.github.io/webrtc-org/native-code/android/
-* https://webrtc.github.io/webrtc-org/native-code/development/
-* https://webrtc.github.io/webrtc-org/native-code/development/prerequisite-sw/
-* https://www.chromium.org/developers/how-tos/install-depot-tools/
-
-建议直接购买国外的按需使用的主机,用完直接释放,配置建议:
-
-* 内存`8G`
-* 四核`CPU`
-* 硬盘`100G`
-* 系统`Ubuntu 20.xx`
-* 宽带按需`100Mbps/s`(不要固定宽带)
-* 整个编译过程大概需要两到三个小时(不会下载回来很慢)
-
-```
-# 编译工具
-mkdir -p /data
-git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
-
-# 源码
-mkdir -p /data/webrtc
-cd /data/webrtc
-fetch --nohooks webrtc_android
-/data/depot_tools/gclient sync
-
-# 分支
-cd src
-git checkout -b m94 branch-heads/4606
-/data/depot_tools/gclient sync
-
-# 编译依赖
-./build/install-build-deps.sh
-./build/install-build-deps-android.sh
-source ./build/android/envsetup.sh
-
----
-'target_os': 'android',
-'is_clang': True,
-'is_debug': False,
-'use_rtti': True,
-'rtc_use_h264': True,
-'use_custom_libcxx': False,
-'rtc_include_tests': False,
-'is_component_build': False,
-'treat_warnings_as_errors': False,
-'use_goma': use_goma,
-'target_cpu': _GetTargetCpu(arch)
----
-
-# 编译.so
-./tools_webrtc/android/build_aar.py --build-dir ./out/release-build/
-# 指定CPU架构:--arch x86 x86_64 arm64-v8a armeabi-v7a
-
-# 编译.a
-/data/depot_tools/autoninja -C ./out/release-build/x86 webrtc &&
-/data/depot_tools/autoninja -C ./out/release-build/x86_64 webrtc &&
-/data/depot_tools/autoninja -C ./out/release-build/arm64-v8a webrtc &&
-/data/depot_tools/autoninja -C ./out/release-build/armeabi-v7a webrtc
-
-# 依赖打包
-zip -r webrtc.zip out libwebrtc.aar
-```
-
-[WebRTC](https://pan.baidu.com/s/1E_DXv32D9ODyj5J-o-ji_g?pwd=hudc)
-
-## libmediasoupclient(可选)
-
-https://mediasoup.org/documentation/v3/libmediasoupclient/installation/
-
-```
-# 编译
-cmake . -B build \
--DCMAKE_BUILD_TYPE=Debug | Release \
--DMEDIASOUPCLIENT_LOG_DEV=OFF \
--DMEDIASOUPCLIENT_LOG_TRACE=OFF \
--DMEDIASOUPCLIENT_BUILD_TESTS=OFF \
--DLIBWEBRTC_INCLUDE_PATH:PATH=PATH_TO_LIBWEBRTC_SOURCES \
--DLIBWEBRTC_BINARY_PATH:PATH=PATH_TO_LIBWEBRTC_BINARY
-make -C build
-make install -C build
-```
-
## 下载源码
```
diff --git a/docs/WebRTC.md b/docs/WebRTC.md
new file mode 100644
index 0000000..d56d721
--- /dev/null
+++ b/docs/WebRTC.md
@@ -0,0 +1,90 @@
+# WebRTC
+
+本文档内容旨在独立编译`WebRTC`项目,非必需使用。
+
+## libwebrtc
+
+* https://webrtc.github.io/webrtc-org/native-code/android/
+* https://webrtc.github.io/webrtc-org/native-code/development/
+* https://webrtc.github.io/webrtc-org/native-code/development/prerequisite-sw/
+* https://www.chromium.org/developers/how-tos/install-depot-tools/
+
+国内镜像需要配置比较麻烦,建议直接按需购买能够访问外网的主机,用完直接释放,配置建议:
+
+* 内存`8G`
+* 四核`CPU`
+* 硬盘`100G`
+* 系统`Ubuntu 20.xx`
+* 宽带按需`100Mbps/s`(不要固定宽带)
+* 整个下载过程大概需要半到一个小时
+* 整个编译过程大概需要一到两个小时
+* 最痛苦的就是下载回来速度很慢
+
+```
+# 编译工具
+mkdir -p /data
+git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
+
+# 源码
+mkdir -p /data/webrtc
+cd /data/webrtc
+fetch --nohooks webrtc_android
+/data/depot_tools/gclient sync
+
+# 分支
+cd src
+git checkout -b m94 branch-heads/4606
+/data/depot_tools/gclient sync
+
+# 编译依赖
+./build/install-build-deps.sh
+./build/install-build-deps-android.sh
+source ./build/android/envsetup.sh
+
+# 编译配置:./tools_webrtc/android/build_aar.py
+---
+'target_os': 'android',
+'is_clang': True,
+'is_debug': False,
+'use_rtti': True,
+'rtc_use_h264': True,
+'use_custom_libcxx': False,
+'rtc_include_tests': False,
+'is_component_build': False,
+'treat_warnings_as_errors': False,
+'use_goma': use_goma,
+'target_cpu': _GetTargetCpu(arch)
+---
+
+# 编译项目
+./tools_webrtc/android/build_aar.py --build-dir ./out/release-build/
+# 指定CPU架构:--arch x86 x86_64 arm64-v8a armeabi-v7a
+
+# 生成静态库
+/data/depot_tools/autoninja -C ./out/release-build/x86 webrtc
+/data/depot_tools/autoninja -C ./out/release-build/x86_64 webrtc
+/data/depot_tools/autoninja -C ./out/release-build/arm64-v8a webrtc
+/data/depot_tools/autoninja -C ./out/release-build/armeabi-v7a webrtc
+
+# 打包
+zip -r webrtc.zip out libwebrtc.aar
+```
+
+[WebRTC](https://pan.baidu.com/s/1E_DXv32D9ODyj5J-o-ji_g?pwd=hudc)
+
+## libmediasoupclient
+
+https://mediasoup.org/documentation/v3/libmediasoupclient/installation/
+
+```
+# 编译
+cmake . -B build \
+-DCMAKE_BUILD_TYPE=Debug | Release \
+-DMEDIASOUPCLIENT_LOG_DEV=OFF \
+-DMEDIASOUPCLIENT_LOG_TRACE=OFF \
+-DMEDIASOUPCLIENT_BUILD_TESTS=OFF \
+-DLIBWEBRTC_INCLUDE_PATH:PATH=PATH_TO_LIBWEBRTC_SOURCES \
+-DLIBWEBRTC_BINARY_PATH:PATH=PATH_TO_LIBWEBRTC_BINARY
+make -C build
+make install -C build
+```
diff --git a/taoyao-client-android/README.md b/taoyao-client-android/README.md
index 3762511..0810594 100644
--- a/taoyao-client-android/README.md
+++ b/taoyao-client-android/README.md
@@ -10,8 +10,7 @@
## 项目配置
-可以自己编译`WebRTC`依赖或者下载已有依赖,
-项目导入以后拷贝`libmediasoupclient`源码还有`WebRTC`头文件和二进制文件到`deps`目录。
+可以自己编译`WebRTC`依赖或者下载已有依赖,项目导入以后拷贝`libmediasoupclient`源码还有`WebRTC`头文件和二进制文件到`deps`目录。
[WebRTC](https://pan.baidu.com/s/1E_DXv32D9ODyj5J-o-ji_g?pwd=hudc)
@@ -22,7 +21,7 @@
* https://developer.android.google.cn/docs?hl=zh-cn
* https://developer.android.google.cn/guide?hl=zh-cn
-## 依赖编译
+## 依赖编译(可选)
* https://webrtc.github.io/webrtc-org/native-code/android/
* https://webrtc.github.io/webrtc-org/native-code/development/
@@ -30,6 +29,11 @@
* https://www.chromium.org/developers/how-tos/install-depot-tools/
* https://mediasoup.org/documentation/v3/libmediasoupclient/installation/
+## 安卓编译(可选)
+
+* https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/
+* https://source.android.google.cn/source/initializing?hl=zh-cn
+
## 参考项目
* https://github.com/haiyangwu/webrtc-android-build
diff --git a/taoyao-client-android/taoyao/client/src/main/AndroidManifest.xml b/taoyao-client-android/taoyao/client/src/main/AndroidManifest.xml
index 8862696..5d1fd29 100644
--- a/taoyao-client-android/taoyao/client/src/main/AndroidManifest.xml
+++ b/taoyao-client-android/taoyao/client/src/main/AndroidManifest.xml
@@ -4,6 +4,7 @@
+
-
-
+ android:supportsRtl="true">
+ android:exported="true"
+ android:label="@string/title_activity_main">
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/BootReceiver.java b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/BootReceiver.java
new file mode 100644
index 0000000..6e45f68
--- /dev/null
+++ b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/BootReceiver.java
@@ -0,0 +1,23 @@
+package com.acgist.taoyao.client;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * 开机启动
+ *
+ * @author acgist
+ */
+public class BootReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
+ final Intent mainActivity = new Intent(context, MainActivity.class);
+ mainActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(mainActivity);
+ }
+ }
+
+}
diff --git a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/MainActivity.java b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/MainActivity.java
index efc2428..01ca806 100644
--- a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/MainActivity.java
+++ b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/MainActivity.java
@@ -1,32 +1,38 @@
package com.acgist.taoyao.client;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
import androidx.appcompat.app.AppCompatActivity;
-import android.os.Bundle;
-import android.widget.TextView;
-
import com.acgist.taoyao.client.databinding.ActivityMainBinding;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import java.util.List;
-import java.util.Map;
-
+/**
+ * 预览界面
+ *
+ * @author acgist
+ */
public class MainActivity extends AppCompatActivity {
- static {
- System.loadLibrary("taoyao");
- }
-
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- binding = ActivityMainBinding.inflate(getLayoutInflater());
- setContentView(binding.getRoot());
- TextView tv = binding.sampleText;
- tv.setText(stringFromJNI());
+ // 媒体服务
+ final Intent mediaService = new Intent(this, MediaService.class);
+ this.startService(mediaService);
+ // 布局
+ this.binding = ActivityMainBinding.inflate(this.getLayoutInflater());
+ this.setContentView(this.binding.getRoot());
+ // 设置按钮
+ this.binding.settings.setOnClickListener(view -> {
+ final Intent settings = new Intent(this, SettingsActivity.class);
+ this.startService(settings);
+ });
}
- public native String stringFromJNI();
-
}
\ No newline at end of file
diff --git a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/MediaService.java b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/MediaService.java
index 5d46401..6760feb 100644
--- a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/MediaService.java
+++ b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/MediaService.java
@@ -4,7 +4,19 @@ import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
+import com.acgist.taoyao.client.signal.Taoyao;
+
+/**
+ * 媒体服务
+ *
+ * @author acgist
+ */
public class MediaService extends Service {
+
+ static {
+ System.loadLibrary("taoyao");
+ }
+
public MediaService() {
}
diff --git a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/SettingsActivity.java b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/SettingsActivity.java
index d4ffa0a..76ca352 100644
--- a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/SettingsActivity.java
+++ b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/SettingsActivity.java
@@ -1,18 +1,38 @@
package com.acgist.taoyao.client;
+import android.content.Intent;
import android.os.Bundle;
+import android.util.Log;
-import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
-import com.acgist.taoyao.client.R;
+import com.acgist.taoyao.client.databinding.ActivitySettingsBinding;
+import com.acgist.taoyao.client.signal.Taoyao;
+/**
+ * 设置界面
+ *
+ * @author acgist
+ */
public class SettingsActivity extends AppCompatActivity {
+ private ActivitySettingsBinding binding;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_settings);
+ // 布局
+ this.binding = ActivitySettingsBinding.inflate(this.getLayoutInflater());
+ this.setContentView(this.binding.getRoot());
+ // 设置按钮
+ this.binding.connect.setOnClickListener(view -> {
+// final Taoyao taoyao = new Taoyao(
+//
+// );
+// Log.d(SettingsActivity.class.getSimpleName(), "连接信令:" + taoyao);
+ final Intent main = new Intent(this, MainActivity.class);
+ this.startService(main);
+ });
}
}
\ No newline at end of file
diff --git a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java
index 5fbe6cb..944060f 100644
--- a/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java
+++ b/taoyao-client-android/taoyao/client/src/main/java/com/acgist/taoyao/client/signal/Taoyao.java
@@ -1,5 +1,8 @@
package com.acgist.taoyao.client.signal;
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
@@ -7,8 +10,12 @@ import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.util.Log;
+import androidx.core.app.ActivityCompat;
+
import com.acgist.taoyao.boot.model.Header;
import com.acgist.taoyao.boot.model.Message;
+import com.acgist.taoyao.boot.model.MessageCode;
+import com.acgist.taoyao.boot.model.MessageCodeException;
import com.acgist.taoyao.boot.utils.CloseableUtils;
import com.acgist.taoyao.boot.utils.JSONUtils;
import com.acgist.taoyao.client.media.Recorder;
@@ -26,8 +33,11 @@ import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@@ -51,14 +61,21 @@ public final class Taoyao {
*/
private final String host;
/**
- * 终端ID
+ * 信令版本
*/
- private final String clientId;
- private final String clientType = "camera";
+ private final String version;
/**
* 终端名称
*/
private final String name;
+ /**
+ * 终端ID
+ */
+ private final String clientId;
+ /**
+ * 终端类型
+ */
+ private final String clientType;
/**
* 桃夭帐号
*/
@@ -67,55 +84,122 @@ public final class Taoyao {
* 桃夭密码
*/
private final String password;
- private String version;
/**
- * Socket
+ * 是否关闭
*/
- private Socket socket;
- private InputStream input;
- private OutputStream output;
private boolean close;
/**
* 是否连接
*/
private boolean connect;
+ /**
+ * 超时时间
+ */
+ private final int timeout;
+ /**
+ * Socket
+ */
+ private Socket socket;
+ /**
+ * 信令输入
+ */
+ private InputStream input;
+ /**
+ * 信令输出
+ */
+ private OutputStream output;
+ /**
+ * 加密工具
+ */
private final Cipher encrypt;
+ /**
+ * 解密工具
+ */
private final Cipher decrypt;
+ /**
+ * 服务上下文
+ */
+ private final Context context;
+ /**
+ * Wifi管理器
+ */
private final WifiManager wifiManager;
+ /**
+ * 电池管理器
+ */
private final BatteryManager batteryManager;
+ /**
+ * 位置管理器
+ */
private final LocationManager locationManager;
- // 线程池
- private final ExecutorService executor = Executors.newFixedThreadPool(8);
- // 定时任务线程池
- private final ExecutorService scheduled = Executors.newScheduledThreadPool(2);
+ /**
+ * 请求消息:同步消息
+ */
+ private final Map requestMessage;
+ /**
+ * 线程池
+ */
+ private final ExecutorService executor;
+ /**
+ * 定时任务线程池
+ */
+ private final ScheduledExecutorService scheduled;
+ /**
+ * 全局单例
+ */
+ private static Taoyao instance;
public Taoyao(
- int port, String host, String algo, String secret, String clientId, String name, String username, String password,
- WifiManager wifiManager, BatteryManager batteryManager, LocationManager locationManager
+ int port, String host, String version,
+ String name, String clientId, String clientType, String username, String password,
+ int timeout, String algo, String secret,
+ Context context, WifiManager wifiManager, BatteryManager batteryManager, LocationManager locationManager
) {
- this.port = port;
- this.host = host;
this.close = false;
this.connect = false;
- if (algo == null || algo.isEmpty() || algo.equals("PLAINTEXT")) {
- // 明文
- this.encrypt = null;
- this.decrypt = null;
- } else {
- this.encrypt = this.buildCipher(Cipher.ENCRYPT_MODE, algo, secret);
- this.decrypt = this.buildCipher(Cipher.DECRYPT_MODE, algo, secret);
- }
- this.clientId = clientId;
+ this.port = port;
+ this.host = host;
+ this.version = version;
this.name = name;
+ this.clientId = clientId;
+ this.clientType = clientType;
this.username = username;
this.password = password;
+ this.timeout = timeout;
+ final boolean plaintext = algo == null || algo.isEmpty() || algo.equals("PLAINTEXT");
+ this.encrypt = plaintext ? null : this.buildCipher(Cipher.ENCRYPT_MODE, algo, secret);
+ this.decrypt = plaintext ? null : this.buildCipher(Cipher.DECRYPT_MODE, algo, secret);
+ this.context = context;
this.wifiManager = wifiManager;
this.batteryManager = batteryManager;
this.locationManager = locationManager;
- executor.submit(this::read);
- scheduled.submit(this::heartbeat);
+ this.requestMessage = new ConcurrentHashMap<>();
+ // 读取线程 + 两条处理线程
+ this.executor = Executors.newFixedThreadPool(3);
+ // 心跳线程
+ this.scheduled = Executors.newScheduledThreadPool(1);
+ executor.submit(this::loopMessage);
+ scheduled.scheduleWithFixedDelay(this::heartbeat, 30, 30, TimeUnit.SECONDS);
+ if(Taoyao.instance != null) {
+ Taoyao.instance.close();
+ }
+ Taoyao.instance = this;
}
+ /**
+ * @return 信令
+ */
+ public static final Taoyao getInstance() {
+ return Taoyao.instance;
+ }
+
+ /**
+ * @param mode 加密/解密
+ * @param name 算法名称
+ * @param secret 密钥
+ *
+ * @return 加解密工具
+ */
private Cipher buildCipher(int mode, String name, String secret) {
try {
final String algo = name.equals("DES") ? "DES/ECB/PKCS5Padding" : "AES/ECB/PKCS5Padding";
@@ -123,7 +207,7 @@ public final class Taoyao {
cipher.init(mode, new SecretKeySpec(Base64.getMimeDecoder().decode(secret), name));
return cipher;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
- // TODO:日志
+ Log.e(Taoyao.class.getSimpleName(), "创建加解密工具异常", e);
}
return null;
}
@@ -131,44 +215,51 @@ public final class Taoyao {
/**
* 连接信令
*/
- public void connect() {
- this.close();
-// HiLog.debug(this.label, "连接信令:%s:%d", this.host, this.port);
+ public synchronized void connect() {
+ if(this.close) {
+ return;
+ }
+ // 释放连接
+ this.disconnect();
+ // 开始连接
+ Log.d(Taoyao.class.getSimpleName(), "连接信令:" + this.host + ":" + this.port);
this.socket = new Socket();
try {
-// socket.setSoTimeout(5000);
- this.socket.connect(new InetSocketAddress(this.host, this.port), 5000);
+ // 设置读取超时时间:不要设置一直阻塞
+// socket.setSoTimeout(this.timeout);
+ this.socket.connect(new InetSocketAddress(this.host, this.port), this.timeout);
if (this.socket.isConnected()) {
this.input = this.socket.getInputStream();
this.output = this.socket.getOutputStream();
this.register();
+ this.connect = true;
synchronized (this) {
this.notifyAll();
}
}
} catch (Exception e) {
- e.printStackTrace();
-// HiLog.error(this.label, "连接信令异常:%s:%d", this.host, this.port);
+ Log.e(Taoyao.class.getSimpleName(), "连接信令异常:" + this.host + ":" + this.port, e);
}
}
- private void heartbeat() {
-
- }
-
- private void read() {
+ /**
+ * 循环读取信令消息
+ */
+ private void loopMessage() {
int length = 0;
short messageLength = 0;
final byte[] bytes = new byte[1024];
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (!this.close) {
try {
- while (this.input == null) {
+ // 重连
+ while (!this.close && !this.connect) {
this.connect();
synchronized (this) {
- this.wait(5000);
+ this.wait(this.timeout);
}
}
+ // 读取
while ((length = this.input.read(bytes)) >= 0) {
buffer.put(bytes, 0, length);
while (buffer.position() > 0) {
@@ -195,6 +286,7 @@ public final class Taoyao {
buffer.get(message);
buffer.compact();
final String content = new String(this.decrypt.doFinal(message));
+ Log.d(Taoyao.class.getSimpleName(), "处理信令:" + content);
executor.submit(() -> {
try {
Taoyao.this.on(content);
@@ -207,16 +299,15 @@ public final class Taoyao {
}
}
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(Taoyao.class.getSimpleName(), "接收信令异常", e);
this.connect();
- // TODO:日志
-// log.error("读取异常", e);
}
}
}
/**
- * @param message 消息
+ * @param message 原始消息
+ *
* @return 加密消息
*/
private byte[] encrypt(Message message) {
@@ -225,41 +316,67 @@ public final class Taoyao {
try {
// 加密
final byte[] encryptBytes = this.encrypt.doFinal(bytes);
- // 发送
+ // 编码
final ByteBuffer buffer = ByteBuffer.allocateDirect(Short.BYTES + encryptBytes.length);
buffer.putShort((short) encryptBytes.length);
buffer.put(encryptBytes);
buffer.flip();
- final byte[] sendBytes = new byte[buffer.capacity()];
- buffer.get(sendBytes);
- return sendBytes;
+ // 编码
+ final byte[] encodingBytes = new byte[buffer.capacity()];
+ buffer.get(encodingBytes);
+ return encodingBytes;
} catch (IllegalBlockSizeException | BadPaddingException e) {
- e.printStackTrace();
-// log.error("加密异常:{}", message);
+ Log.e(Taoyao.class.getSimpleName(), "加密异常:" + message, e);
}
}
return bytes;
}
+ /**
+ * @param message 信令消息
+ */
public void push(Message message) {
if (this.output == null) {
+ Log.w(Taoyao.class.getSimpleName(), "通道没有打开:" + message);
return;
}
try {
this.output.write(this.encrypt(message));
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(Taoyao.class.getSimpleName(), "请求信令异常:" + message, e);
}
}
+ /**
+ * @param request 信令请求消息
+ *
+ * @return 信令响应消息
+ */
public Message request(Message request) {
- return null;
+ final Header header = request.getHeader();
+ final Long id = header.getId();
+ this.requestMessage.put(id, request);
+ synchronized (request) {
+ this.push(request);
+ try {
+ request.wait(this.timeout);
+ } catch (InterruptedException e) {
+ Log.e(Taoyao.class.getSimpleName(), "请求信令等待异常:" + request, e);
+ }
+ }
+ final Message response = this.requestMessage.remove(id);
+ if (response == null || request.equals(response)) {
+ Log.w(Taoyao.class.getSimpleName(), "请求信令没有响应:" + request);
+ throw MessageCodeException.of(MessageCode.CODE_2001, "请求信令没有响应");
+ }
+ return response;
}
/**
* 释放连接
*/
- private void close() {
+ private void disconnect() {
+ Log.d(Taoyao.class.getSimpleName(), "释放信令:" + this.host + ":" + this.port);
this.connect = false;
CloseableUtils.close(this.input);
CloseableUtils.close(this.output);
@@ -272,8 +389,8 @@ public final class Taoyao {
/**
* 关闭信令
*/
- private void shutdown() {
- this.close();
+ private void close() {
+ this.disconnect();
this.close = true;
executor.shutdownNow();
scheduled.shutdownNow();
@@ -285,7 +402,7 @@ public final class Taoyao {
*
* @return 消息
*/
- public Message buildMessage(String signal, Object ... args) {
+ public Message buildMessage(String signal, Object... args) {
final Map