Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

录制出的音频中间存在空白间隔和轻微爆破声 #263

Closed
suiyuanccccc opened this issue Feb 3, 2025 · 3 comments
Closed

录制出的音频中间存在空白间隔和轻微爆破声 #263

suiyuanccccc opened this issue Feb 3, 2025 · 3 comments

Comments

@suiyuanccccc
Copy link

如放大图,在每个MP3帧之间有个约5ms的空白,但是并不是音频播放完毕。
录制用的mp3,发送是每15个帧调用一次websocket.send,播放使用的buffer_stream.player。
[这里的空白音频导致音频质量和连贯性下降,而且有的帧最后有轻微的爆破声,有无解决方案。
Image

附上音频文件,AU可看
audio (10).zip

@xiangyuecn
Copy link
Owner

录音可以用 实时转码上传-实时帧回调版 ,采用takeoffEncodeChunk实时mp3音频编码回调,这个实现的mp3帧数据之间没有间隙。如果是用的rec.mock实时转码,每次都是新的mp3文件,就会导致中间有间隙。

BufferStreamPlayer播放mp3这个是会有点问题,效果最好的是传pcm进去,因为每次input mp3都会单独去解码成pcm,导致前后不连贯,可以自行解码mp3成pcm,再input pcm播放效果就会好很多。每次解码时解码3段数据,提取出中间的:第一段是上次解码了的,中间这段是当前要解码的,第三段是最新收到的,这样解码出来的pcm就连贯了

@suiyuanccccc
Copy link
Author

录音可以用 实时转码上传-实时帧回调版 ,采用takeoffEncodeChunk实时mp3音频编码回调,这个实现的mp3帧数据之间没有间隙。如果是用的rec.mock实时转码,每次都是新的mp3文件,就会导致中间有间隙。

BufferStreamPlayer播放mp3这个是会有点问题,效果最好的是传pcm进去,因为每次input mp3都会单独去解码成pcm,导致前后不连贯,可以自行解码mp3成pcm,再input pcm播放效果就会好很多。每次解码时解码3段数据,提取出中间的:第一段是上次解码了的,中间这段是当前要解码的,第三段是最新收到的,这样解码出来的pcm就连贯了

现在是在push之前就提取出pcm测试数组,并最后打包为wav在AU检查。
这是目前解码的部分,输入为多个mp3数据帧数组,在处理后还是存在音频淡入(FadeInOut函数内容已经被注释),发生的频次在每次调用receiveAudioChunk函数时,所以不知是否存在问题。
跳过开头4ms能处理空白音频,但是音量淡入不知从何引入的

Image

let audioCtx;
async function receiveAudioChunk(arrayBuffer) {
if (stream) {
//创建解码
if (!audioCtx) {
audioCtx = new AudioContext();
}
//转码
audioCtx.decodeAudioData(await arrayBuffer, function (raw) {
let src = raw.getChannelData(0);
//var sampleRate = raw.sampleRate;

        //跳过开头
        let skip = 0;
        //skip=raw.sampleRate*0.004;
        //skip = Math.floor(skip);

        const pcm = new Int16Array(src.length - skip);
        //是否需要增益音量
        if (outputVolume != undefined && outputVolume != null && outputVolume != 1) {
            for (var i = 0; i < src.length - skip; i++) {//floatTo16BitPCM
                var s = src[i + skip] * (outputVolume ? outputVolume : 1); // 乘以音量系数;
                var ss = Math.max(-1, Math.min(1, s));//削峰
                pcm[i] = ss < 0 ? ss * 0x8000 : ss * 0x7FFF;
            }
        } else {
            for (let i = 0; i < src.length-skip; i++) {
                pcm[i] = src[i + skip] < 0 ? src[i + skip] * 0x8000 : src[i + skip] * 0x7FFF;
            }
        }

        //传入音频输出
        stream.input(pcm);
        //测试留一份
        testAllPcm.push(pcm);
        console.log(pcm);
    }, function (e) {
        False && False("音频解码失败:" + e.message);
    });
} else {
    confirm.error("解码器错误")
}

}

@suiyuanccccc
Copy link
Author

录音可以用 实时转码上传-实时帧回调版 ,采用takeoffEncodeChunk实时mp3音频编码回调,这个实现的mp3帧数据之间没有间隙。如果是用的rec.mock实时转码,每次都是新的mp3文件,就会导致中间有间隙。
BufferStreamPlayer播放mp3这个是会有点问题,效果最好的是传pcm进去,因为每次input mp3都会单独去解码成pcm,导致前后不连贯,可以自行解码mp3成pcm,再input pcm播放效果就会好很多。每次解码时解码3段数据,提取出中间的:第一段是上次解码了的,中间这段是当前要解码的,第三段是最新收到的,这样解码出来的pcm就连贯了

现在是在push之前就提取出pcm测试数组,并最后打包为wav在AU检查。 这是目前解码的部分,输入为多个mp3数据帧数组,在处理后还是存在音频淡入(FadeInOut函数内容已经被注释),发生的频次在每次调用receiveAudioChunk函数时,所以不知是否存在问题。 跳过开头4ms能处理空白音频,但是音量淡入不知从何引入的

Image

let audioCtx; async function receiveAudioChunk(arrayBuffer) { if (stream) { //创建解码 if (!audioCtx) { audioCtx = new AudioContext(); } //转码 audioCtx.decodeAudioData(await arrayBuffer, function (raw) { let src = raw.getChannelData(0); //var sampleRate = raw.sampleRate;

        //跳过开头
        let skip = 0;
        //skip=raw.sampleRate*0.004;
        //skip = Math.floor(skip);

        const pcm = new Int16Array(src.length - skip);
        //是否需要增益音量
        if (outputVolume != undefined && outputVolume != null && outputVolume != 1) {
            for (var i = 0; i < src.length - skip; i++) {//floatTo16BitPCM
                var s = src[i + skip] * (outputVolume ? outputVolume : 1); // 乘以音量系数;
                var ss = Math.max(-1, Math.min(1, s));//削峰
                pcm[i] = ss < 0 ? ss * 0x8000 : ss * 0x7FFF;
            }
        } else {
            for (let i = 0; i < src.length-skip; i++) {
                pcm[i] = src[i + skip] < 0 ? src[i + skip] * 0x8000 : src[i + skip] * 0x7FFF;
            }
        }

        //传入音频输出
        stream.input(pcm);
        //测试留一份
        testAllPcm.push(pcm);
        console.log(pcm);
    }, function (e) {
        False && False("音频解码失败:" + e.message);
    });
} else {
    confirm.error("解码器错误")
}

}

问题已经解决,保存前一次的数据参与解码,音频连贯性大大改善

Image

附上代码
let audioCtx;
let lastArray = new Uint8Array(0);
let lastPCMLength = 0;

function concatenateArrayBuffers(newArrayBuffer) {
if (!(newArrayBuffer instanceof ArrayBuffer)) {
throw new TypeError('ArrayBuffer输入');
}

if (!lastArray) {
    lastArray = new Uint8Array(newArrayBuffer);
    return newArrayBuffer;
}

let newArray = new Uint8Array(newArrayBuffer);
const totalLength = lastArray.length + newArray.length;
const concatenatedUint8Array = new Uint8Array(totalLength);

concatenatedUint8Array.set(lastArray, 0);
concatenatedUint8Array.set(newArray, lastArray.length);

lastArray = newArray;
return concatenatedUint8Array.buffer;

};

function receiveAudioChunk(newArrayBuffer) {
if (stream) {
//创建解码
if (!audioCtx) {
audioCtx = Recorder.Ctx;
}
//合并mp3数据
let mergedArrayBuffer = concatenateArrayBuffers(newArrayBuffer);

    //转码
    audioCtx.decodeAudioData(mergedArrayBuffer, function (raw) {
        let src = raw.getChannelData(0);
        //var sampleRate = raw.sampleRate;

        //提取有效部分
        let startIndex = lastPCMLength;
        let thisLength = src.length - startIndex;

        const pcm = new Int16Array(thisLength);
        //是否需要增益音量
        if (outputVolume != undefined && outputVolume != null && outputVolume != 1) {
            for (var i = 0; i < thisLength; i++) {//floatTo16BitPCM
                var s = src[i + startIndex] * (outputVolume ? outputVolume : 1); // 乘以音量系数;
                var ss = Math.max(-1, Math.min(1, s));//削峰
                pcm[i] = ss < 0 ? ss * 0x8000 : ss * 0x7FFF;
            }
        } else {
            for (let i = 0; i < thisLength; i++) {
                pcm[i] = src[i + startIndex] < 0 ? src[i + startIndex] * 0x8000 : src[i + startIndex] * 0x7FFF;
            }
        }

        //下次需要减去的长度
        lastPCMLength = pcm.length;
        //传入音频输出
        stream.input(pcm);
        //测试留一份
        testAllPcm.push(pcm);
        console.log(pcm);
    }, function (e) {
        False && False("音频解码失败:" + e.message);
    });
} else {
    confirm.error("解码器错误")
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants