package com.aipeople.by;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.aipeople.by.databinding.ActivityMainBinding;
import com.pedro.rtplibrary.rtsp.RtspCamera2;
import com.pedro.rtplibrary.view.OpenGlView;
import com.pedro.rtsp.utils.ConnectCheckerRtsp;
public class MainActivity extends AppCompatActivity implements ConnectCheckerRtsp {
private ActivityMainBinding binding;
private RtspCamera2 rtspCamera2;
private TextView tvStatus;
// 目标 RTSP 推流地址
private final String RTSP_URL = "rtsp://192.168.2.180:8554/zhxt";
// 状态标志位:解耦权限异步回调与 Surface 异步创建
private boolean isPermissionGranted = false;
private boolean isSurfaceReady = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
tvStatus = binding.tvStatus;
// 【关键】先注册 Surface 回调,再申请权限
setupSurfaceCallback();
checkAndRequestPermissions();
}
/**
* 监听 OpenGlView 底层 Surface 生命周期
* 防止在 Surface 未就绪时初始化 EGL 导致 glThread 崩溃
*/
private void setupSurfaceCallback() {
binding.openGlView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
isSurfaceReady = true;
tryStartPushIfReady();
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
// Surface 尺寸变化时可在此处理,当前无需操作
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
isSurfaceReady = false;
releaseStreamer();
}
});
}
/**
* 检查并请求相机和麦克风权限
*/
private void checkAndRequestPermissions() {
String[] perms = {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
boolean allGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
if (allGranted) {
isPermissionGranted = true;
tryStartPushIfReady();
} else {
ActivityCompat.requestPermissions(this, perms, 100);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 100 && grantResults.length >= 2
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
isPermissionGranted = true;
tryStartPushIfReady();
} else {
Toast.makeText(this, "需要相机和麦克风权限才能推流", Toast.LENGTH_SHORT).show();
}
}
/**
* 双重校验:权限已授予 + Surface 已创建且有效
*/
private void tryStartPushIfReady() {
if (!isPermissionGranted || !isSurfaceReady) return;
if (!binding.openGlView.getHolder().getSurface().isValid()) return;
startPush();
}
/**
* 初始化 RtspCamera2 并开始推流
*/
private void startPush() {
// 防止重复初始化
if (rtspCamera2 != null && rtspCamera2.isOnPreview()) return;
if (rtspCamera2 == null) {
// ✅ 使用 RtspCamera2,回调接口为 ConnectCheckerRtsp
rtspCamera2 = new RtspCamera2(binding.openGlView, this);
}
if (!rtspCamera2.isStreaming()) {
// prepareVideo(width, height, fps, bitrate, iFrameInterval, rotation)
// boolean videoReady = rtspCamera2.prepareVideo(640, 480, 30, 800 * 1024, 2, 0);
// prepareAudio(bitrate, sampleRate, isStereo, echoCanceler, noiseSuppressor)
boolean audioReady = rtspCamera2.prepareAudio(64 * 1024, 44100, true, false, false);
// boolean videoReady = rtspCamera2.prepareVideo(1280, 720, 30, 2000 * 1024, 2, 0);
// 参数依次为:width, height, fps, bitrate, iFrameInterval, rotation
boolean videoReady = rtspCamera2.prepareVideo(
1920, // 1. 宽度:1080P
1080, // 2. 高度:1080P
30, // 3. 帧率:30fps(保证流畅度)
4000 * 1024,// 4. 码率:4Mbps(1080P 30fps 的推荐高画质码率)
1, // 5. 关键帧间隔:设为 1秒(提升动态清晰度)
90 // 6. 旋转角度:0
);
if (!videoReady || !audioReady) {
updateStatus("编码器初始化失败,请检查设备");
return;
}
// ✅ startPreview() 无参版本,View 已在构造函数中绑定
rtspCamera2.startPreview();
// ✅ RtspCamera2 支持 rtsp:// 协议
rtspCamera2.startStream(RTSP_URL);
updateStatus("正在连接 RTSP 服务器...");
}
}
/**
* 安全释放推流资源
*/
private void releaseStreamer() {
if (rtspCamera2 != null) {
if (rtspCamera2.isStreaming()) rtspCamera2.stopStream();
if (rtspCamera2.isOnPreview()) rtspCamera2.stopPreview();
rtspCamera2 = null;
}
}
private void updateStatus(String status) {
runOnUiThread(() -> tvStatus.setText("当前状态:" + status));
}
// ==================== ConnectCheckerRtsp 回调实现 ====================
@Override
public void onConnectionSuccessRtsp() {
updateStatus("RTSP 推流中");
}
@Override
public void onConnectionFailedRtsp(@NonNull String reason) {
updateStatus("连接失败: " + reason);
}
@Override
public void onNewBitrateRtsp(long bitrate) {
// 可在此更新实时码率显示
}
@Override
public void onDisconnectRtsp() {
updateStatus("已断开连接");
}
@Override
public void onAuthErrorRtsp() {
updateStatus("RTSP 认证失败");
}
@Override
public void onAuthSuccessRtsp() {
updateStatus("认证成功,连接中...");
}
// ==================== Activity 生命周期 ====================
@Override
protected void onDestroy() {
super.onDestroy();
releaseStreamer();
}
}