AudioCodecUtil.java 3.18 KB
package com.genersoft.iot.vmp.jtt1078.util;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.util.Arrays;

/**
 * 音频转换与封包工具 (修复版)
 */
public class AudioCodecUtil {

    // G.711A (byte) -> PCM (byte[])
    public static byte[] g711aToPcm(byte[] g711Data) {
        if (g711Data == null) return new byte[0];
        byte[] pcmData = new byte[g711Data.length * 2];
        for (int i = 0; i < g711Data.length; i++) {
            short s = ALaw.decode(g711Data[i]);
            pcmData[2 * i] = (byte) (s & 0xff);
            pcmData[2 * i + 1] = (byte) ((s >> 8) & 0xff);
        }
        return pcmData;
    }

    // PCM -> G.711A (byte[])
    public static byte[] pcmToG711a(byte[] pcmData) {
        if (pcmData == null) return new byte[0];
        byte[] g711Data = new byte[pcmData.length / 2];
        for (int i = 0; i < g711Data.length; i++) {
            int low = pcmData[2 * i] & 0xff;
            int high = pcmData[2 * i + 1] & 0xff;
            short s = (short) (low | (high << 8));
            g711Data[i] = ALaw.encode(s);
        }
        return g711Data;
    }

    /**
     * 【核心修复】更安全的封包逻辑
     */
    public static ByteBuf encodeJt1078AudioPacket(String sim, int channel, int sequence, byte[] audioBody) {
        // 计算总长度:30字节头 + 音频体长度
        int totalLen = 30 + (audioBody != null ? audioBody.length : 0);

        // 创建 HeapBuffer
        ByteBuf buffer = Unpooled.buffer(totalLen);

        // --- 30字节头 ---
        buffer.writeInt(0x30316364); // 0-3: Frame Header
        buffer.writeByte(0x80);      // 4: RTP V=2, P=0, X=0, CC=0
        buffer.writeByte(0x88);      // 5: M=1, PT=8 (PCMA)
        buffer.writeShort(sequence); // 6-7: Sequence

        // 8-13: SIM卡号 (BCD)
        byte[] bcdSim = str2Bcd(sim);
        buffer.writeBytes(bcdSim); // 写入6字节

        buffer.writeByte(channel);   // 14: Channel
        buffer.writeByte(0x30);      // 15: DataType (0011 0000 -> 音频I帧)

        buffer.writeLong(System.currentTimeMillis()); // 16-23: Timestamp

        // 24-27: Intervals
        buffer.writeShort(0);
        buffer.writeShort(0);

        // 28-29: Body Length
        int bodyLen = (audioBody != null ? audioBody.length : 0);
        buffer.writeShort(bodyLen);

        // --- 写入音频数据 ---
        if (bodyLen > 0) {
            buffer.writeBytes(audioBody);
        }

        return buffer;
    }

    /**
     * 【修复】更健壮的 BCD 转码
     * 确保必须返回 6 字节,不足补0,超过截断
     */
    public static byte[] str2Bcd(String asc) {
        if (asc == null) return new byte[6];

        // 1. 预处理:只保留数字,不足12位补0
        String num = asc.replaceAll("[^0-9]", "");
        if (num.length() > 12) num = num.substring(0, 12);
        else while (num.length() < 12) num = "0" + num; // 左补0

        // 2. 转换
        byte[] bbt = new byte[6];
        char[] chars = num.toCharArray();

        for (int p = 0; p < 6; p++) {
            int high = chars[2 * p] - '0';
            int low = chars[2 * p + 1] - '0';
            bbt[p] = (byte) ((high << 4) | low);
        }
        return bbt;
    }
}