当前位置: 代码网 > it编程>编程语言>Javascript > 如何使用JavaScript将录音的Blob流切分成多个5秒的WAV文件并确保其正常播放?

如何使用JavaScript将录音的Blob流切分成多个5秒的WAV文件并确保其正常播放?

2025年03月30日 Javascript 我要评论
使用javascript切分录音的blob流并生成5秒的wav文件在使用react-mic进行录音时,遇到一个需求:需要将录音的blob流切分成多个5秒的wav文件。然而,尝试之后发现只有第一个切分的

使用javascript切分录音的blob流并生成5秒的wav文件

在使用react-mic进行录音时,遇到一个需求:需要将录音的blob流切分成多个5秒的wav文件。然而,尝试之后发现只有第一个切分的wav文件能够正常播放,其余文件均提示文件损坏。

在前端实现这个需求时,主要面临两个挑战:一是如何正确切分blob流,二是如何确保每个切分后的片段能够正确生成并播放wav文件。以下是代码示例和解决思路:

import react, { useref, usestate } from 'react'
import { reactmic, reactmicstopevent } from 'react-mic'
import { button } from 'antd'

const audiorecorder = () => {
    const [record, setrecord] = usestate(false)
    const resref = useref<blob[]>([])
    const audiochunksref = useref<blob[]>([])
    const intervalref = useref<nodejs.timer | null>(null)
    const firstblob = useref<blob | undefined>(undefined)

    const createwavheader = (numchannels, samplerate, bytelength) => {
        const header = new arraybuffer(44);
        const view = new dataview(header);

        view.setuint32(0, 1380533830, false); // "riff"
        view.setuint32(4, bytelength + 36, false);
        view.setuint32(8, 1718449184, false); // "wave"
        view.setuint32(12, 1684108385, false); // "fmt "
        view.setuint32(16, 16, true); // 16 for pcm
        view.setuint16(20, 1, true); // pcm
        view.setuint16(22, numchannels, true);
        view.setuint32(24, samplerate, true);
        view.setuint32(28, samplerate * numchannels * 2, true);
        view.setuint16(32, numchannels * 2, true);
        view.setuint16(34, 16, true); // 16 bits
        view.setuint32(36, 1684108385, false); // "data"
        view.setuint32(40, bytelength, true);

        return header;
    };

    const savefile = async () => {
        const chunkslist = resref.current;
        for (let i = 0; i < chunkslist.length; i++) {
            const audiobuffer = new uint8array(await chunkslist[i].arraybuffer());
            const header = createwavheader(1, 44100, audiobuffer.length); // 假设单声道和 44100hz
            const wavblob = new blob([header, audiobuffer], { type: 'audio/wav' });

            const url = url.createobjecturl(wavblob);
            const a = document.createelement('a');
            a.href = url;
            a.download = `recording${i}.wav`;
            a.click();
            url.revokeobjecturl(url);
        }
    };

    const startrecording = () => {
        setrecord(true)
        audiochunksref.current = [] // 清空之前的录音数据

        // 每5秒分割一次录音
        intervalref.current = setinterval(() => {
            const curblob = new blob(audiochunksref.current, { type: 'audio/wav' })
            const startindex = audiochunksref.current.indexof(firstblob.current as blob)
            const blob = curblob.slice(startindex === -1 ? 0 : startindex, -1, 'audio/wav')
            firstblob.current = audiochunksref.current.at(-1)
            // 处理当前录音数据
            console.log('分割当前录音数据:', blob)
            resref.current.push(blob)
        }, 5000)
    }

    const stoprecording = () => {
        setrecord(false)
        intervalref.current && clearinterval(intervalref.current) // 清除定时器
    }

    const ondata = (recordedblob: blob) => {
        audiochunksref.current.push(recordedblob) // 保存录音数据
    }

    const onstop = (recordedblob: reactmicstopevent) => {
        console.log('录音完成:', recordedblob)
    }

    const savefile1 = () => {
        const chunkslist = resref.current
        chunkslist.map(async (v, i) => {
            const filename = 'aaa.wav'
            const file: file = new file([v], filename, { type: 'audio/wav' })
            const filesize = file.size

            console.log('filesize', filesize)
            // 创建下载链接
            const url = url.createobjecturl(file)
            const a = document.createelement('a')
            a.href = url
            a.download = `recording${i}.wav` // 设置下载文件的名称

            a.click() // 触发下载
            // 释放url资源
            url.revokeobjecturl(url)
        })
    }

    const savefinalresult = () => {
        const filename = 'aaa.wav'
        const file: file = new file(audiochunksref.current, filename, { type: 'audio/wav' })
        const filesize = file.size

        console.log('filesize', filesize)
        // 创建下载链接
        const url = url.createobjecturl(file)
        const a = document.createelement('a')
        a.href = url
        a.download = `recording${date.now()}.wav` // 设置下载文件的名称

        a.click() // 触发下载
        // 释放url资源
        url.revokeobjecturl(url)
    }

    return (
        <div>
            <reactmic record={record} onstop={onstop} ondata={ondata} mimetype="audio/wav" />
            <button onclick={startrecording}>开始录音</button>
            <button onclick={stoprecording}>停止录音</button>
            <button onclick={savefile}>下载</button>
            <button onclick={savefinalresult}>下载final</button>
        </div>
    )
}

export default audiorecorder
登录后复制

在尝试切分blob流和生成wav文件的过程中,发现手动添加wav头信息并不能解决问题。其原因在于wav文件的结构比较严格,切分后如果不正确地添加头部信息,文件可能会损坏。

解决这个问题的一个建议是使用ffmpeg的wasm版本,这是一个可以在浏览器中运行的音视频处理库。通过它,你可以轻松地对音频进行切分并生成正确的wav文件格式。可以考虑使用ffmpeg.wasm项目来实现这个功能。

以上就是如何使用javascript将录音的blob流切分成多个5秒的wav文件并确保其正常播放?的详细内容,更多请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com