javascripthtmlhtml5-audiogetusermedia

How to convert each audio stream chunk to mp3 or wav or webm? Audio is not playing for all chunks except first one


I have an usecase where each chunk of audio stream is being sent to server for transcription, but except first chunk every other audio chunk(blob) are not working.

So I did a small prototype to see if all chunks are playing fine using audio element by generating blob url

Code Example

import React, { useState, useRef } from 'react'

const RecordAudio: React.FC = () => {
  const [isRecording, setIsRecording] = useState(false)
  const mediaRecorderRef = useRef<MediaRecorder | null>(null)
  const audioChunksRef = useRef<Blob[]>([])

  const startRecording = async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
    const mediaRecorder = new MediaRecorder(stream)
    mediaRecorderRef.current = mediaRecorder
    audioChunksRef.current = []
    mediaRecorder.ondataavailable = async (event) => {
      if (event.data.size > 0) {
        console.log('event.data', event.data)
        audioChunksRef.current.push(event.data)
      }
    }

    mediaRecorder.start(5000) // Capture audio in chunks every 500ms
    setIsRecording(true)
  }

  const stopRecording = () => {
    if (mediaRecorderRef.current) {
      mediaRecorderRef.current.stop()
      setIsRecording(false)
      // sendAudioChunk(audioChunksRef.current)
    }
  }

  const getAudioBlobUrl = (chunk: Blob) => {
    const audioBlob = new Blob([chunk], {
      type: 'audio/wav',
    })
    const blobUrl = URL.createObjectURL(audioBlob)

    return blobUrl
  }
  return (
    <div>
      <button onClick={isRecording ? stopRecording : startRecording}>
        {isRecording ? 'Stop Recording' : 'Start Recording'}
      </button>
      <div>
        {audioChunksRef.current.map((blob) => {
          return (
            <>
              <audio
                style={{ marginLeft: '16px' }}
                src={getAudioBlobUrl(blob)}
                controls
              />
            </>
          )
        })}
      </div>
    </div>
  )
}

export default RecordAudio

However except first audio chunk, every other player is not playing, attaching screenshot for reference enter image description here

What is the issue here? how to make each chunk to be streamed to server?


Solution

  • The individual chunks of data delivered to your ondataavailable handler don't stand alone. You can't "play" any given chunk, but rather you must play the whole stream of data starting with the first chunk.

    And, they have a content-type (FKA MIME type) of 'audio/webm' (in the Chromium and Firefox world) not 'audio/wav'.

    The q&A mentioned in a comment will give you a lot more detail.