如何实现语音中常用的环形缓冲区

392 阅读1分钟
背景

在语音开发中经常需要补偿音频,使用普通的队列来保存音频如果没有停止写的话很容易内存被撑爆,然后普通队列取最新的一段数据也不方便,这时候环形缓冲区就派上用场了。

实际上org.apache.commons.collections4提供了环形缓冲区实现CircularFifoQueue.java

因为开始也不知道有三方库实现了,所以算自己写了个,比较简单的实现。

代码实现
/**
 * 环形缓冲区
 */
public class CycleQueue {
    private VoiceByte[] arr;
    private int maxSize;// 最大空间
    private int len;// 有效长度
    private int end;// 队尾
    private boolean isFull;
​
    public CycleQueue(int size) {
        this.maxSize = size;
        this.arr = new VoiceByte[maxSize];
        this.len = 0;
        this.end = -1;
        this.isFull = false;
    }
​
    /**
     * 生产数据
     *
     * @param voiceBytes
     */
    public synchronized void produce(VoiceByte voiceBytes) {
        //如果满了
        if (end == maxSize - 1) {
            isFull = true;
            end = -1;
        }
        arr[++end] = voiceBytes;
        if (len < maxSize) {
            len++;
        } else {
            len = maxSize;
        }
    }
​
    /**
     * 生产数据
     *
     * @param bytes
     */
    public synchronized void produce(byte[] bytes) {
        VoiceByte voiceByte = new VoiceByte(bytes);
        produce(voiceByte);
    }
​
    /**
     * 消费所有数据
     *
     * @return
     */
    public synchronized List<VoiceByte> consumeAll() {
        List<VoiceByte> list = getAllVoiceBytes();
        this.len = 0;
        this.end = -1;
        this.isFull = false;
        return list;
    }
​
    private List<VoiceByte> getAllVoiceBytes() {
        List<VoiceByte> list = new ArrayList<>();
        List<VoiceByte> queueData = Arrays.asList(arr);
        if (isFull) {
            list.addAll(queueData.subList(end + 1, maxSize));
            list.addAll(queueData.subList(0, end + 1));
        } else {
            if (len > 0) {
                list.addAll(queueData.subList(0, len));
            }
        }
        return list;
    }
​
    /**
     * 判断是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return (len == 0);
    }
​
    /**
     * 判断是否满了
     *
     * @return
     */
    public boolean isFull() {
        return (len == maxSize);
    }
​
    /**
     * 获得队列的有效长度
     *
     * @return
     */
    public int size() {
        return len;
    }
​
    public synchronized void clear() {
        Arrays.fill(arr, null);
        this.len = 0;
        this.end = -1;
        this.isFull = false;
    }
}
​
/**
 * byte数组封装类
 */
public static class VoiceByte {
    public byte[] localBytes;
​
    public VoiceByte(byte[] bytes) {
        localBytes = bytes;
    }
​
    public int size() {
        return localBytes.length;
    }
}