Dana
2025-11-30 c795d1c28858b3300ad43792d58cfe825961f06d
1.tcp udp 切换
4个文件已修改
1个文件已添加
436 ■■■■■ 已修改文件
app/src/main/java/com/anyun/h264/AACEncoder.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/anyun/h264/H264Encoder.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/anyun/h264/JT1076ProtocolHelper.java 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/anyun/h264/JT1076TcpClient.java 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/anyun/h264/MainActivity.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/anyun/h264/AACEncoder.java
@@ -111,8 +111,8 @@
            // 2. 初始化AAC编码器
            initEncoder();
            
            // 3. 初始化UDP Socket
            if (!protocolHelper.initializeUdpSocket()) {
            // 3. 初始化Socket(UDP或TCP,根据协议类型自动选择)
            if (!protocolHelper.initializeSocket()) {
                return false;
            }
            
@@ -287,8 +287,8 @@
                byte[] rtpPacket = protocolHelper.createAudioRtpPacket(
                    packetData, timestamp, JT1076ProtocolHelper.DATA_TYPE_AUDIO, packetMark);
                
                // 发送UDP包
                protocolHelper.sendUdpPacket(rtpPacket);
                // 发送RTP包(UDP或TCP,根据协议类型自动选择)
                protocolHelper.sendPacket(rtpPacket);
                
                offset += packetDataSize;
            }
@@ -343,9 +343,9 @@
            audioRecord = null;
        }
        
        // 关闭UDP Socket
        // 关闭Socket(UDP或TCP,根据协议类型自动选择)
        if (protocolHelper != null) {
            protocolHelper.closeUdpSocket();
            protocolHelper.closeSocket();
        }
        
        Log.d(TAG, "AAC encoder stopped");
app/src/main/java/com/anyun/h264/H264Encoder.java
@@ -83,6 +83,7 @@
    public H264Encoder() {
        this.usbCamera = new UsbCamera();
        this.protocolHelper = new JT1076ProtocolHelper();
        protocolHelper.setProtocolType(JT1076ProtocolHelper.PROTOCOL_TYPE_TCP);
    }
    /**
@@ -178,8 +179,8 @@
            // 3. 初始化H264编码器
            initEncoder();
            // 4. 初始化UDP Socket
            if (!protocolHelper.initializeUdpSocket()) {
            // 4. 初始化Socket(UDP或TCP,根据协议类型自动选择)
            if (!protocolHelper.initializeSocket()) {
                return false;
            }
@@ -502,8 +503,8 @@
                        packetData, timestamp, dataType, packetMark,
                        lastIFrameInterval, lastFrameInterval);
                // 发送UDP包
                protocolHelper.sendUdpPacket(rtpPacket);
                // 发送RTP包(UDP或TCP,根据协议类型自动选择)
                protocolHelper.sendPacket(rtpPacket);
                offset += packetDataSize;
            }
@@ -548,9 +549,9 @@
            }
        }
        // 关闭UDP Socket
        // 关闭Socket(UDP或TCP,根据协议类型自动选择)
        if (protocolHelper != null) {
            protocolHelper.closeUdpSocket();
            protocolHelper.closeSocket();
        }
        // 关闭文件输出
app/src/main/java/com/anyun/h264/JT1076ProtocolHelper.java
@@ -10,7 +10,7 @@
/**
 * JT/T 1076-2016 协议工具类
 * 提供UDP发送、SIM卡号BCD转换、RTP包创建等公共功能
 * 提供UDP/TCP发送、SIM卡号BCD转换、RTP包创建等公共功能
 */
public class JT1076ProtocolHelper {
    private static final String TAG = "JT1076ProtocolHelper";
@@ -37,11 +37,23 @@
    public static final int RTP_PAYLOAD_TYPE_VIDEO = 96;  // 视频负载类型
    public static final int RTP_PAYLOAD_TYPE_AUDIO = 97;  // 音频负载类型
    
    // UDP参数
    // 传输协议类型
    public static final int PROTOCOL_TYPE_UDP = 0;  // UDP协议
    public static final int PROTOCOL_TYPE_TCP = 1;  // TCP协议
    // 服务器参数
    private String serverIp;
    private int serverPort;
    // 协议类型(默认UDP)
    private int protocolType = PROTOCOL_TYPE_UDP;
    // UDP参数
    private DatagramSocket udpSocket;
    private InetAddress serverAddress;
    // TCP参数
    private JT1076TcpClient tcpClient;
    
    // RTP协议参数
    private String simCardNumber = "123456789012"; // 12位SIM卡号
@@ -49,11 +61,45 @@
    private short sequenceNumber = 0; // 包序号(自动递增)
    
    /**
     * 设置UDP服务器地址
     * 设置服务器地址
     */
    public void setServerAddress(String ip, int port) {
        this.serverIp = ip;
        this.serverPort = port;
        // 如果TCP客户端已存在,更新地址
        if (tcpClient != null) {
            tcpClient.setServerAddress(ip, port);
        }
    }
    /**
     * 设置传输协议类型(UDP或TCP)
     * @param protocolType PROTOCOL_TYPE_UDP 或 PROTOCOL_TYPE_TCP
     */
    public void setProtocolType(int protocolType) {
        if (protocolType != PROTOCOL_TYPE_UDP && protocolType != PROTOCOL_TYPE_TCP) {
            Log.w(TAG, "Invalid protocol type: " + protocolType + ", using UDP");
            protocolType = PROTOCOL_TYPE_UDP;
        }
        // 如果协议类型改变,先关闭旧的连接
        if (this.protocolType != protocolType) {
            if (this.protocolType == PROTOCOL_TYPE_UDP) {
                closeUdpSocket();
            } else {
                closeTcpSocket();
            }
        }
        this.protocolType = protocolType;
        Log.d(TAG, "Protocol type set to: " + (protocolType == PROTOCOL_TYPE_UDP ? "UDP" : "TCP"));
    }
    /**
     * 获取当前协议类型
     */
    public int getProtocolType() {
        return protocolType;
    }
    
    /**
@@ -62,6 +108,17 @@
    public void setProtocolParams(String simCardNumber, byte logicalChannelNumber) {
        this.simCardNumber = simCardNumber;
        this.logicalChannelNumber = logicalChannelNumber;
    }
    /**
     * 初始化Socket(根据协议类型自动选择UDP或TCP)
     */
    public boolean initializeSocket() {
        if (protocolType == PROTOCOL_TYPE_UDP) {
            return initializeUdpSocket();
        } else {
            return initializeTcpSocket();
        }
    }
    
    /**
@@ -85,6 +142,59 @@
    }
    
    /**
     * 初始化TCP Socket
     */
    public boolean initializeTcpSocket() {
        try {
            if (serverIp == null || serverIp.isEmpty()) {
                Log.e(TAG, "Server IP not set");
                return false;
            }
            if (tcpClient == null) {
                tcpClient = new JT1076TcpClient();
                tcpClient.setServerAddress(serverIp, serverPort);
                // 设置连接状态监听器
                tcpClient.setConnectionListener(new JT1076TcpClient.ConnectionListener() {
                    @Override
                    public void onConnected() {
                        Log.d(TAG, "TCP connection established");
                    }
                    @Override
                    public void onDisconnected() {
                        Log.d(TAG, "TCP connection disconnected");
                    }
                    @Override
                    public void onError(Throwable cause) {
                        Log.e(TAG, "TCP connection error", cause);
                    }
                });
            }
            tcpClient.connect();
            Log.d(TAG, "TCP socket initializing, target: " + serverIp + ":" + serverPort);
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Initialize TCP socket failed", e);
            return false;
        }
    }
    /**
     * 关闭Socket(根据协议类型自动选择)
     */
    public void closeSocket() {
        if (protocolType == PROTOCOL_TYPE_UDP) {
            closeUdpSocket();
        } else {
            closeTcpSocket();
        }
    }
    /**
     * 关闭UDP Socket
     */
    public void closeUdpSocket() {
@@ -100,7 +210,28 @@
    }
    
    /**
     * 发送UDP包
     * 关闭TCP Socket
     */
    public void closeTcpSocket() {
        if (tcpClient != null) {
            tcpClient.disconnect();
            tcpClient = null;
        }
    }
    /**
     * 发送RTP包(根据协议类型自动选择UDP或TCP)
     */
    public void sendPacket(byte[] packet) {
        if (protocolType == PROTOCOL_TYPE_UDP) {
            sendUdpPacket(packet);
        } else {
            sendTcpPacket(packet);
        }
    }
    /**
     * 发送UDP包(保持向后兼容)
     */
    public void sendUdpPacket(byte[] packet) {
        try {
@@ -117,6 +248,17 @@
    }
    
    /**
     * 发送TCP包
     */
    public void sendTcpPacket(byte[] packet) {
        if (tcpClient != null && tcpClient.isConnected()) {
            tcpClient.sendPacket(packet);
        } else {
            Log.w(TAG, "TCP socket not connected");
        }
    }
    /**
     * 将SIM卡号转换为BCD格式(6字节)
     */
    public byte[] convertSimToBCD(String simNumber) {
app/src/main/java/com/anyun/h264/JT1076TcpClient.java
New file
@@ -0,0 +1,257 @@
package com.anyun.h264;
import android.util.Log;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.concurrent.TimeUnit;
/**
 * JT/T 1076-2016 TCP客户端工具类
 * 使用Netty实现TCP连接和RTP包发送
 */
public class JT1076TcpClient {
    private static final String TAG = "JT1076TcpClient";
    private String serverIp;
    private int serverPort;
    private EventLoopGroup workerGroup;
    private Channel channel;
    private boolean isConnected = false;
    // 连接状态回调接口
    public interface ConnectionListener {
        void onConnected();
        void onDisconnected();
        void onError(Throwable cause);
    }
    private ConnectionListener connectionListener;
    /**
     * 设置服务器地址
     */
    public void setServerAddress(String ip, int port) {
        this.serverIp = ip;
        this.serverPort = port;
    }
    /**
     * 设置连接状态监听器
     */
    public void setConnectionListener(ConnectionListener listener) {
        this.connectionListener = listener;
    }
    /**
     * 初始化TCP连接(异步)
     */
    public void connect() {
        if (serverIp == null || serverIp.isEmpty()) {
            Log.e(TAG, "Server IP not set");
            if (connectionListener != null) {
                connectionListener.onError(new IllegalArgumentException("Server IP not set"));
            }
            return;
        }
        if (workerGroup != null) {
            Log.w(TAG, "TCP client already initialized, disconnecting first");
            disconnect();
        }
        // 创建EventLoopGroup(使用单线程组即可)
        workerGroup = new NioEventLoopGroup(1);
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workerGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true) // 禁用Nagle算法,降低延迟
                    .option(ChannelOption.SO_KEEPALIVE, true) // 启用TCP keepalive
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) // 连接超时5秒
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new TcpClientHandler());
                        }
                    });
            Log.d(TAG, "Connecting to TCP server: " + serverIp + ":" + serverPort);
            // 异步连接
            ChannelFuture future = bootstrap.connect(serverIp, serverPort);
            future.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        channel = future.channel();
                        isConnected = true;
                        Log.d(TAG, "TCP connection established: " + serverIp + ":" + serverPort);
                        if (connectionListener != null) {
                            connectionListener.onConnected();
                        }
                    } else {
                        isConnected = false;
                        Throwable cause = future.cause();
                        Log.e(TAG, "TCP connection failed: " + serverIp + ":" + serverPort, cause);
                        if (connectionListener != null) {
                            connectionListener.onError(cause);
                        }
                        // 连接失败时清理资源
                        shutdown();
                    }
                }
            });
        } catch (Exception e) {
            Log.e(TAG, "Initialize TCP client failed", e);
            isConnected = false;
            if (connectionListener != null) {
                connectionListener.onError(e);
            }
            shutdown();
        }
    }
    /**
     * 发送RTP包(TCP方式)
     */
    public void sendPacket(byte[] packet) {
        if (!isConnected || channel == null || !channel.isActive()) {
            Log.w(TAG, "TCP channel not connected, packet dropped");
            return;
        }
        try {
            // 将字节数组包装为ByteBuf
            ByteBuf buffer = Unpooled.wrappedBuffer(packet);
            // 异步写入
            ChannelFuture future = channel.writeAndFlush(buffer);
            // 可选:监听发送结果
            future.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (!future.isSuccess()) {
                        Log.e(TAG, "Send TCP packet failed", future.cause());
                    }
                }
            });
        } catch (Exception e) {
            Log.e(TAG, "Send TCP packet error", e);
        }
    }
    /**
     * 断开TCP连接
     */
    public void disconnect() {
        isConnected = false;
        if (channel != null) {
            try {
                ChannelFuture future = channel.close();
                future.await(2, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                Log.w(TAG, "Close channel interrupted", e);
                Thread.currentThread().interrupt();
            } catch (Exception e) {
                Log.e(TAG, "Close channel error", e);
            }
            channel = null;
        }
        shutdown();
        if (connectionListener != null) {
            connectionListener.onDisconnected();
        }
        Log.d(TAG, "TCP connection closed");
    }
    /**
     * 关闭EventLoopGroup(清理资源)
     */
    private void shutdown() {
        if (workerGroup != null) {
            try {
                workerGroup.shutdownGracefully().await(3, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                Log.w(TAG, "Shutdown worker group interrupted", e);
                Thread.currentThread().interrupt();
            } catch (Exception e) {
                Log.e(TAG, "Shutdown worker group error", e);
            }
            workerGroup = null;
        }
    }
    /**
     * 检查是否已连接
     */
    public boolean isConnected() {
        return isConnected && channel != null && channel.isActive();
    }
    /**
     * TCP客户端通道处理器
     */
    private class TcpClientHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            super.channelActive(ctx);
            Log.d(TAG, "TCP channel active: " + ctx.channel().remoteAddress());
            isConnected = true;
        }
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            super.channelInactive(ctx);
            Log.d(TAG, "TCP channel inactive: " + ctx.channel().remoteAddress());
            isConnected = false;
            channel = null;
            if (connectionListener != null) {
                connectionListener.onDisconnected();
            }
        }
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            Log.e(TAG, "TCP channel exception", cause);
            isConnected = false;
            if (connectionListener != null) {
                connectionListener.onError(cause);
            }
            ctx.close();
        }
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            // 如果服务器有响应,可以在这里处理
            // 对于JT/T 1076-2016 RTP发送,通常不需要处理响应
            ByteBuf buf = (ByteBuf) msg;
            Log.d(TAG, "Received data from server: " + buf.readableBytes() + " bytes");
            buf.release(); // 释放ByteBuf
        }
    }
}
app/src/main/java/com/anyun/h264/MainActivity.kt
@@ -69,8 +69,8 @@
            h264Encoder?.setEnableFileOutput(true) // 启用文件输出
            
            // 设置UDP服务器地址(可选)
             h264Encoder?.setServerAddress("192.168.1.100", 8888)
             h264Encoder?.setProtocolParams("123456789012", 1)
             h264Encoder?.setServerAddress("58.48.93.67", 11935)
             h264Encoder?.setProtocolParams("013120122580", 1)
            
            // 初始化并启动
            val cameraIdRange = intArrayOf(1, 2)