MediaRecorder录制的wav文件缺少wav文件头

在一个项目中前端使用MediaRecorder录制的wav文件缺少wav文件头,导致后端的语音识别模型报错。后使用recorder解决(原生js实现的web端录音)recorder的gitee地址

期间使用MediaRecorder的时候尝试加入wav头,但是音频出现损坏(音频出现了刺啦声)。我看recorder也是加上wav文件头,为什么下面这种方法不行。希望有大佬解惑

    handleYy() {
      // 检查浏览器是否支持录音功能
      if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia({ audio: true })
          .then((stream) => {
            // 创建一个MediaRecorder实例
            if (this.mediaRecorder === null) {
              this.mediaRecorder = new MediaRecorder(stream)
            }
            let audioTracks = stream.getAudioTracks()
            // let sampleRate = 8000 // 假设的采样率
            // let numChannels = 1 // 单声道
            // let sampleDepth = 16 // 16 位深度
            let sampleRate = null // 假设的采样率
            let numChannels = null // 单声道
            let sampleDepth = null // 16 位深度
            if (audioTracks.length > 0) {
              const settings = audioTracks[0].getSettings()
              sampleRate = settings.sampleRate // 采样率
              numChannels = settings.channelCount // 声道数
              // 采样深度通常固定为16位,但您也可以从settings中获取
              sampleDepth = settings.sampleSize // 采样深度(如果可用)
            }

            // 监听MediaRecorder的状态变化
            this.state = this.mediaRecorder.state
            switch (this.state) {
              case 'inactive':
                this.mediaRecorder.start()
                break
              case 'recording':
                this.mediaRecorder.stop()
                this.mediaRecorder.ondataavailable = async(event) => {
                  if (event.data.size > 0) {
                    // 将录制的音频数据转换为Blob
                    const audioBlob = new Blob([event.data], { type: 'audio/wav' })
                    // 创建一个URL,可以用于下载或播放音频
                    // const audioUrl = URL.createObjectURL(audioBlob);
                    // 创建 WAV 文件头

                    let buffer = new ArrayBuffer(44)
                    let view = new DataView(buffer)
                    // RIFF chunk descriptor
                    this.writeString(view, 0, 'RIFF')
                    view.setUint32(4, 36 + audioBlob.size, true)
                    this.writeString(view, 8, 'WAVE')
                    // FMT sub-chunk
                    this.writeString(view, 12, 'fmt ')
                    view.setUint32(16, 16, true) // Sub-chunk size
                    view.setUint16(20, 1, true) // Audio format (1 = PCM)
                    view.setUint16(22, numChannels, true)
                    view.setUint32(24, sampleRate, true)
                    view.setUint32(28, sampleRate * numChannels * (sampleDepth / 8), true) // Byte rate
                    view.setUint16(32, numChannels * (sampleDepth / 8), true) // Block align
                    view.setUint16(34, sampleDepth, true) // Bits per sample
                    // Data sub-chunk
                    this.writeString(view, 36, 'data')
                    view.setUint32(40, audioBlob.size, true)
                    // 将 WAV 文件头和音频数据合并
                    let wavBlob = new Blob([buffer, audioBlob], { 'type': 'audio/wav' })
                    let wavURL = window.URL.createObjectURL(wavBlob)
                    // let wavAudio = new Audio(wavURL)
                    // 在这里你可以使用audioUrl来做任何事情,比如播放或下载录音
                    //                     console.log('Recorded audio URL:', audioBlob);
                    //                     console.log(audioUrl)
                    //                     const res = await generationVoice({ file:audioBlob })
                    //                     console.log('res',res)
                    // 在这里你可以使用audioUrl来做任何事情,比如播放或下载录音
                    console.log('Recorded audio URL:', wavURL)
                    const res = await generationVoice({ file: wavBlob })
                    console.log('res', res)
                  }
                }
                console.log('Recorder is recording')
                break
              case 'stopped':
                console.log('Recorder is stopped')
                break
              default:
                console.log('Unknown state:', this.state)
            }
            console.log(this.mediaRecorder)
            // 监听数据流事件

            // 自动开始录制
            console.log('Recording started')

            // 当你想停止录制时
            // mediaRecorder.stop();
          })
          .catch(function(err) {
            // 处理错误情况
            console.error('Error accessing media devices:', err)
          })
      } else {
        console.log('Your browser does not support the MediaRecorder API.')
      }
    },
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的录制 WAV 音频文件的示例代码: ```java import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.Environment; import android.util.Log; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class AudioRecorder { private static final String TAG = "AudioRecorder"; private static final int SAMPLE_RATE_IN_HZ = 44100; private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO; private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; private AudioRecord audioRecord; private boolean isRecording; public void startRecording() { int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE_IN_HZ, CHANNEL_CONFIG, AUDIO_FORMAT); audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE_IN_HZ, CHANNEL_CONFIG, AUDIO_FORMAT, minBufferSize); isRecording = true; audioRecord.startRecording(); new Thread(new Runnable() { @Override public void run() { writeDataToFile(); } }).start(); } public void stopRecording() { isRecording = false; audioRecord.stop(); audioRecord.release(); } private void writeDataToFile() { byte[] buffer = new byte[1024]; String filename = Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.wav"; File file = new File(filename); if (file.exists()) { file.delete(); } try { FileOutputStream fos = new FileOutputStream(file); while (isRecording) { int read = audioRecord.read(buffer, 0, buffer.length); fos.write(buffer, 0, read); } fos.close(); } catch (IOException e) { Log.e(TAG, "writeDataToFile: ", e); } } } ``` 将上述代码保存到名为 `AudioRecorder.java` 的文件中,然后在你的 Android 项目中引入该文件。 在你的 Activity 或 Fragment 中,你可以通过以下方法来使用上述代码: ```java private AudioRecorder audioRecorder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); audioRecorder = new AudioRecorder(); } public void startRecording(View view) { audioRecorder.startRecording(); } public void stopRecording(View view) { audioRecorder.stopRecording(); } ``` 这里我们假设你在布局文件中创建了两个按钮,分别用于启动和停止录制。在 `startRecording()` 方法中,我们创建了一个新的线程来执行音频数据写入文件的操作。在 `stopRecording()` 方法中,我们停止录制并释放相关资源。 请注意,上述代码中的文件路径是 `/sdcard/recording.wav`。如果你的设备没有 SD 卡或者你的应用程序没有 SD 卡写入权限,那么你需要修改文件路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值