feat(streaming): 添加自编码串流模式切换功能

This commit is contained in:
2026-07-23 12:01:08 +08:00
parent a1c29246d7
commit e56723a010
20 changed files with 1684 additions and 16 deletions

View File

@@ -16,6 +16,10 @@ import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.RadioGroup;
import android.widget.Switch;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import com.ttstd.controller.webrtc.SelfCodecDecoder;
import androidx.appcompat.app.AlertDialog;
import java.util.ArrayList;
@@ -58,6 +62,14 @@ public class MainActivity extends AppCompatActivity {
private TextView tvStats;
private Spinner spinnerResolution;
// 屏幕串流"自编码"模式相关 UI 与解码器
private Switch switchStreamMode;
private TextView tvStreamMode;
private SurfaceView selfCodecSurface;
private SelfCodecDecoder selfCodecDecoder;
private SurfaceHolder.Callback surfaceCallback;
private boolean programmaticSwitch = false;
private WebSocketClient wsClient;
private WebRtcClient webRtcClient;
private EglBase eglBase;
@@ -162,6 +174,8 @@ public class MainActivity extends AppCompatActivity {
setupResolutionSpinner();
updateUI(false);
setupSelfCodecUi();
}
private void adjustVideoSize(int videoWidth, int videoHeight, int rotation) {
@@ -309,6 +323,8 @@ public class MainActivity extends AppCompatActivity {
private void initWebRtcAndConnect() {
webRtcClient = new WebRtcClient(this, wsClient, myDeviceId);
webRtcClient.initialize(eglBase);
webRtcClient.setSelfCodecDecoder(selfCodecDecoder);
webRtcClient.setStreamModeReportListener(mode -> runOnUiThread(() -> syncStreamModeUi(mode)));
webRtcClient.setConnectionListener(new WebRtcClient.ConnectionListener() {
@Override
public void onConnectionEstablished() {
@@ -598,8 +614,83 @@ public class MainActivity extends AppCompatActivity {
if (connected) {
statsHandler.post(statsRunnable);
if (switchStreamMode != null) switchStreamMode.setEnabled(true);
} else {
statsHandler.removeCallbacks(statsRunnable);
if (switchStreamMode != null) {
switchStreamMode.setEnabled(false);
programmaticSwitch = true;
switchStreamMode.setChecked(false);
programmaticSwitch = false;
}
if (tvStreamMode != null) tvStreamMode.setText("串流: WebRTC");
if (selfCodecDecoder != null) selfCodecDecoder.release();
}
}
/** 初始化"自编码"串流模式的 UI 与解码器。 */
private void setupSelfCodecUi() {
switchStreamMode = findViewById(R.id.switch_stream_mode);
tvStreamMode = findViewById(R.id.tv_stream_mode);
selfCodecSurface = findViewById(R.id.self_codec_surface);
selfCodecDecoder = new SelfCodecDecoder();
surfaceCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (selfCodecDecoder != null) {
selfCodecDecoder.setSurface(holder.getSurface());
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
};
selfCodecSurface.getHolder().addCallback(surfaceCallback);
switchStreamMode.setEnabled(false);
switchStreamMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (programmaticSwitch) return;
applyStreamMode(isChecked);
});
}
/** 用户切换串流模式:发送信令并切换本地视图。 */
private void applyStreamMode(boolean self) {
if (webRtcClient != null && webRtcClient.isDataChannelOpen()) {
webRtcClient.sendStreamMode(self ? WebRtcClient.STREAM_MODE_SELF_CODEC
: WebRtcClient.STREAM_MODE_WEBRTC);
}
tvStreamMode.setText(self ? "串流: 自编码" : "串流: WebRTC");
if (self) {
selfCodecSurface.setVisibility(View.VISIBLE);
remoteVideoView.setVisibility(View.GONE);
selfCodecDecoder.setEnabled(true);
} else {
selfCodecSurface.setVisibility(View.GONE);
remoteVideoView.setVisibility(View.VISIBLE);
selfCodecDecoder.setEnabled(false);
}
}
/** 收到被控端回报的当前模式:同步 UI 与视图(防止切换失败不一致)。 */
private void syncStreamModeUi(int mode) {
boolean self = (mode == WebRtcClient.STREAM_MODE_SELF_CODEC);
programmaticSwitch = true;
switchStreamMode.setChecked(self);
programmaticSwitch = false;
tvStreamMode.setText(self ? "串流: 自编码" : "串流: WebRTC");
if (self) {
selfCodecSurface.setVisibility(View.VISIBLE);
remoteVideoView.setVisibility(View.GONE);
selfCodecDecoder.setEnabled(true);
} else {
selfCodecSurface.setVisibility(View.GONE);
remoteVideoView.setVisibility(View.VISIBLE);
selfCodecDecoder.setEnabled(false);
}
}