网站备案成功然后怎么做,类似淘宝网站建设有哪些模板,阿里巴巴网站网络营销的平台,wordpress七牛cdnpcm介绍#xff1a;PCM#xff08;Puls Code Modulation#xff09;全称脉码调制录音#xff0c;PCM录音就是将声音的模拟信号表示成0,1标识的数字信号#xff0c;未经任何编码和压缩处理#xff0c;所以可以认为PCM是未经压缩的音频原始格式。PCM格式文件中不包含头部信…pcm介绍PCMPuls Code Modulation全称脉码调制录音PCM录音就是将声音的模拟信号表示成0,1标识的数字信号未经任何编码和压缩处理所以可以认为PCM是未经压缩的音频原始格式。PCM格式文件中不包含头部信息播放器无法知道采样率声道数采样位数音频数据大小等信息导致无法播放。
需求我需要在websoket中接收实时的pcm音频流原始数据16位16k单通道意思就是pcm 的参数采样率16000采样位数16声道数1
重要千万不要去运用什么所谓的插件因为它会使你绕很大一圈的弯路实时播放的pcm浏览器是支持的使用插件很可能还会被迫读什么源码也很容易将你带偏再多的播放插件底层大部分也是基于AudioContext去开发的。
首先是拿音频文件试但是却不了解mp3和wav的区别就首选拿了mp3这是我的第一个深坑因为mp3经过多层的处理压缩已经距离原始的文件很远了通过ajax拿回来的arraybuffer是可以直接塞进去CreateBufferSource.buffer中就能直接播放原因就是decodeAdioData就直接能处理接口返回的arraybuffer数据
mp3示例
useEffect(() {axios.request({url: require(/assets/wholeWorld.mp3), // 假如这是我们从后端请求回来的音乐文件responseType: arraybuffer, // 必须需要这个method: get}).then(res {// 创建AudioBufferSourceNodeconst arrayBuffer res.dataconst context new AudioContext()const source context.createBufferSource();context.decodeAudioData(arrayBuffer).then(audioBuffer {// 设置buffer属性source.buffer audioBuffer;// 连接到音频上下文并播放source.connect(context.destination);})source.start(0);})}, [])我处理wav的音频去播放也是可以的使用decodeAudioData去进行播放
wav音频播放示例
useEffect(() {axios.request({url: require(/assets/sample.wav), // 假如这是我们从后端请求回来的音乐文件responseType: arraybuffer, // 必须需要这个method: get}).then(res {// 创建AudioBufferSourceNodeconst arrayBuffer res.dataconst context new AudioContext()const source context.createBufferSource();context.decodeAudioData(arrayBuffer).then(audioBuffer {// 设置buffer属性source.buffer audioBuffer;// 连接到音频上下文并播放source.connect(context.destination);})source.start(0);})}, [])但是都不支持pcm文件所以我最开始的思路是通过获取到的pcm去处理成wav的文件一样去搜了很多资料都说wav的文件比pcm只是多了44字节文件头我没从深度验证但是我通过加字节文件头去进行pcm的播放因为decodeAudioData可以运行其他处理过的音频文件尽管加了字节文件头是不能解决根本问题的这段路我绕了很大一个圈。 mp3文件和wav文件的区别示例 mp3和wav的区别说明
其实浏览器是可以直接播放pcm数据的无论是文件还是socket返回来的原始数据这过程涉及了Uint8转换Uint16Uint16转成Float32了解decodeAudioData和getChannelData究竟处理什么问题等知识。 首先找一个pcm文件进行播放调试pcm的文件能播放成功那socket就不是问题
PCM播放代码示例
仅播放出声音的调试自行调整代码规范
// 解析PCM数据到AudioBuffer
function decodePCM(arrayBuffer: ArrayBufferLike,sampleBits: number, channelCount: number, sampleRate: number,audioContext: any) {return new Promise((resolve, reject) {const dataView new DataView(arrayBuffer);const length (arrayBuffer.byteLength / (sampleBits / 8) / channelCount);const buffer audioContext.createBuffer(channelCount, length, sampleRate);let offset 0;for (let channel 0; channel channelCount; channel) {const channelBuffer buffer.getChannelData(channel);for (let i 0; i length; i) {const sample dataView.getInt16(offset, true); // 假设PCM数据是16位有符号整数channelBuffer[i] sample / 32768; // 标准化到-1到1的范围offset 2; // 16位 2字节}}resolve(buffer);});
}
let sourceNode: any null;useEffect(() {// 加载音频文件axios.request({method: get,url: require(/assets/recorder.pcm),responseType: arraybuffer,}).then(res {const arraybuffer res.dataconst audioContext new window.AudioContext();decodePCM(arraybuffer, 16, 1, 16000, audioContext).then(buffer {sourceNode audioContext.createBufferSource();sourceNode.buffer buffer;sourceNode.connect(audioContext.destination);sourceNode.start(); // 开始播放}).catch(error {console.error(Error decoding PCM:, error);});})}, [])注 当声音有杂音一直是一个杂音就说明数据错了 当声音没有声音数据很可能都是0 当声音隐隐有正常但是杂音很重一定是需要它getChannelData和DataView 后端从TCP给我实时的pcm是压缩Uint8Array前端将Uint8Array的数据解码为Uint16Array然后合并Uint16Array的所有音频数据还需要将Uint16Array通过DataView处理成AudioContext可播放的Float32Array所以不了解AudioCotext API是很难解决这些问题的更何况仅仅是播放的功能我后面还要处理更多复杂的应用场景持续更新实时播放pcm的处理应用场景。
最终在和蔼可亲的同事帮助和自己不辞辛苦的研究下搞出来了感谢我的同事。
值得参考 张鑫旭https://www.zhangxinxu.com/wordpress/2023/10/js-audio-audiobuffer-concat-merge/ MDNhttps://developer.mozilla.org/zh-CN/docs/Web/API/BaseAudioContext/createBuffer
推荐工具 MEIDAINFOhttps://mediaarea.net/MediaInfoOnline