feat: 控制指令消息改为protobuf二进制

This commit is contained in:
2026-07-15 17:03:58 +08:00
parent 92ad90cbeb
commit da1730ce19
21 changed files with 658 additions and 147 deletions

View File

@@ -1,5 +1,6 @@
plugins {
id 'com.android.application'
id 'com.google.protobuf'
}
def releaseTime() {
@@ -116,6 +117,19 @@ android {
}
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.25.1'
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {}
}
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
@@ -127,6 +141,8 @@ dependencies {
// OkHttp for WebSocket
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
// Gson for JSON
// Gson for JSON(信令消息仍使用 JSON
implementation 'com.google.code.gson:gson:2.10.1'
// ProtobufDataChannel 控制指令二进制)
implementation 'com.google.protobuf:protobuf-java:3.25.1'
}

View File

@@ -16,6 +16,8 @@ import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.ttstd.control.Action;
import com.ttstd.control.ControlMessage;
import com.ttstd.controller.signaling.SignalMessage;
import com.ttstd.controller.signaling.WebSocketClient;
import com.ttstd.controller.view.RemoteTouchView;
@@ -326,55 +328,60 @@ public class MainActivity extends AppCompatActivity {
private void sendTouchCommand(float relX, float relY) {
if (webRtcClient != null) {
JsonObject cmd = new JsonObject();
cmd.addProperty("action", "TOUCH");
cmd.addProperty("x", relX);
cmd.addProperty("y", relY);
webRtcClient.sendControlCommand(cmd.toString());
ControlMessage msg = ControlMessage.newBuilder()
.setAction(Action.TOUCH)
.setX(relX)
.setY(relY)
.build();
webRtcClient.sendControlCommand(msg);
}
}
private void sendSwipeCommand(float relX1, float relY1, float relX2, float relY2, long duration) {
if (webRtcClient != null) {
JsonObject cmd = new JsonObject();
cmd.addProperty("action", "SWIPE");
cmd.addProperty("x1", relX1);
cmd.addProperty("y1", relY1);
cmd.addProperty("x2", relX2);
cmd.addProperty("y2", relY2);
cmd.addProperty("duration", duration);
webRtcClient.sendControlCommand(cmd.toString());
ControlMessage msg = ControlMessage.newBuilder()
.setAction(Action.SWIPE)
.setX1(relX1)
.setY1(relY1)
.setX2(relX2)
.setY2(relY2)
.setDuration(duration)
.build();
webRtcClient.sendControlCommand(msg);
}
}
private void sendKeyCommand(int keyCode, int action) {
if (webRtcClient != null) {
JsonObject cmd = new JsonObject();
cmd.addProperty("action", "KEY");
cmd.addProperty("keyCode", keyCode);
cmd.addProperty("keyAction", action);
webRtcClient.sendControlCommand(cmd.toString());
ControlMessage msg = ControlMessage.newBuilder()
.setAction(Action.KEY)
.setKeyCode(keyCode)
.setKeyAction(action)
.build();
webRtcClient.sendControlCommand(msg);
}
}
private void sendLongPressCommand(float relX, float relY) {
if (webRtcClient != null) {
JsonObject cmd = new JsonObject();
cmd.addProperty("action", "LONG_PRESS");
cmd.addProperty("x", relX);
cmd.addProperty("y", relY);
webRtcClient.sendControlCommand(cmd.toString());
ControlMessage msg = ControlMessage.newBuilder()
.setAction(Action.LONG_PRESS)
.setX(relX)
.setY(relY)
.build();
webRtcClient.sendControlCommand(msg);
}
}
private void sendMotionEventCommand(int action, float relX, float relY) {
if (webRtcClient != null) {
JsonObject cmd = new JsonObject();
cmd.addProperty("action", "MOTION_EVENT");
cmd.addProperty("motionAction", action);
cmd.addProperty("x", relX);
cmd.addProperty("y", relY);
webRtcClient.sendControlCommand(cmd.toString());
ControlMessage msg = ControlMessage.newBuilder()
.setAction(Action.MOTION_EVENT)
.setMotionAction(action)
.setX(relX)
.setY(relY)
.build();
webRtcClient.sendControlCommand(msg);
}
}

View File

@@ -9,8 +9,8 @@ import android.view.SurfaceView;
import androidx.annotation.NonNull;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.ttstd.control.Action;
import com.ttstd.control.ControlMessage;
/**
* 自定义SurfaceView用于捕获触摸事件并转换为远端输入指令。
@@ -20,7 +20,6 @@ import com.google.gson.JsonObject;
public class RemoteTouchView extends SurfaceView {
private static final String TAG = "RemoteTouchView";
private final Gson gson = new Gson();
private TouchEventListener listener;
private float lastTouchX;
@@ -144,39 +143,39 @@ public class RemoteTouchView extends SurfaceView {
return super.onTouchEvent(event);
}
public String createTouchCommand(float relX, float relY) {
JsonObject cmd = new JsonObject();
cmd.addProperty("action", "TOUCH");
cmd.addProperty("x", relX);
cmd.addProperty("y", relY);
return cmd.toString();
public ControlMessage createTouchCommand(float relX, float relY) {
return ControlMessage.newBuilder()
.setAction(Action.TOUCH)
.setX(relX)
.setY(relY)
.build();
}
public String createSwipeCommand(float relX1, float relY1, float relX2, float relY2, long duration) {
JsonObject cmd = new JsonObject();
cmd.addProperty("action", "SWIPE");
cmd.addProperty("x1", relX1);
cmd.addProperty("y1", relY1);
cmd.addProperty("x2", relX2);
cmd.addProperty("y2", relY2);
cmd.addProperty("duration", duration);
return cmd.toString();
public ControlMessage createSwipeCommand(float relX1, float relY1, float relX2, float relY2, long duration) {
return ControlMessage.newBuilder()
.setAction(Action.SWIPE)
.setX1(relX1)
.setY1(relY1)
.setX2(relX2)
.setY2(relY2)
.setDuration(duration)
.build();
}
public String createLongPressCommand(float relX, float relY) {
JsonObject cmd = new JsonObject();
cmd.addProperty("action", "LONG_PRESS");
cmd.addProperty("x", relX);
cmd.addProperty("y", relY);
return cmd.toString();
public ControlMessage createLongPressCommand(float relX, float relY) {
return ControlMessage.newBuilder()
.setAction(Action.LONG_PRESS)
.setX(relX)
.setY(relY)
.build();
}
public String createMotionEventCommand(int action, float relX, float relY) {
JsonObject cmd = new JsonObject();
cmd.addProperty("action", "MOTION_EVENT");
cmd.addProperty("motionAction", action);
cmd.addProperty("x", relX);
cmd.addProperty("y", relY);
return cmd.toString();
public ControlMessage createMotionEventCommand(int action, float relX, float relY) {
return ControlMessage.newBuilder()
.setAction(Action.MOTION_EVENT)
.setMotionAction(action)
.setX(relX)
.setY(relY)
.build();
}
}

View File

@@ -7,6 +7,7 @@ import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.ttstd.controller.signaling.SignalMessage;
import com.ttstd.controller.signaling.WebSocketClient;
import com.ttstd.control.ControlMessage;
import org.webrtc.DataChannel;
import org.webrtc.DefaultVideoDecoderFactory;
@@ -27,7 +28,6 @@ import org.webrtc.VideoEncoderFactory;
import org.webrtc.VideoTrack;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@@ -231,10 +231,10 @@ public class WebRtcClient {
}
}
public void sendControlCommand(String commandJson) {
public void sendControlCommand(ControlMessage message) {
if (dataChannel != null && dataChannel.state() == DataChannel.State.OPEN) {
DataChannel.Buffer buffer = new DataChannel.Buffer(
ByteBuffer.wrap(commandJson.getBytes(StandardCharsets.UTF_8)), false);
ByteBuffer.wrap(message.toByteArray()), false);
dataChannel.send(buffer);
}
}
@@ -279,8 +279,7 @@ public class WebRtcClient {
public void onMessage(DataChannel.Buffer buffer) {
byte[] data = new byte[buffer.data.remaining()];
buffer.data.get(data);
String message = new String(data, StandardCharsets.UTF_8);
Log.d(TAG, "DataChannel message: " + message);
Log.d(TAG, "DataChannel message received, bytes=" + data.length);
}
});
}

View File

@@ -0,0 +1,41 @@
syntax = "proto3";
package com.ttstd.control;
option java_package = "com.ttstd.control";
option java_multiple_files = true;
// 控制指令类型,对应原 JSON 字段 action。
enum Action {
ACTION_UNKNOWN = 0;
TOUCH = 1;
SWIPE = 2;
KEY = 3;
LONG_PRESS = 4;
MOTION_EVENT = 5;
}
// 通过 RTCDataChannel 传输的控制指令protobuf 二进制)。
// 坐标 x/y/x1/y1/x2/y2 均为相对屏幕的百分比,取值范围 0.0 ~ 1.0。
message ControlMessage {
// 指令类型
Action action = 1;
// 单点坐标TOUCH / LONG_PRESS / MOTION_EVENT
double x = 2;
double y = 3;
// 滑动起止坐标SWIPE
double x1 = 4;
double y1 = 5;
double x2 = 6;
double y2 = 7;
int64 duration = 8;
// 按键KEYkey_action 0=按下 1=抬起(对应 Android KeyEvent ACTION_DOWN/UP
int32 key_code = 9;
int32 key_action = 10;
// 原始动作MOTION_EVENT对应 Android MotionEvent ACTION_*0=DOWN 1=UP 2=MOVE
int32 motion_action = 11;
}