Facing web browser differences when playing audio

31 Views Asked by At

I am working on a small web app written using Next.JS.

The app works but still exhibits some issues. The user can record his own voice and then play it back once or more. And then make a new voice recording and play it back one or several times ... an so on.

For the time being I am developing and running locally (http://localhost:3000).

When I point my web browser to this address: http://localhost:3000

In Safari I see these, showing that there is some kind of error:

enter image description here

enter image description here

In Firefox I see this, showing nothing wrong:

enter image description here

Similarly in Brave I see this, apparently normal:

enter image description here

But when I try the app, making a few voice recordings and playing them back a few times on the way. Things happen as expected in Safari and in Brave, but in Firefox at times (fairly regularly) I get a 16~20 seconds delay before a playback happens (usually not at the first playback).

My problem is to get rid of the error messages in Safari as well as get rid of the weird behaviour in Firefox.

This is the current version of my code:

'use client'

import {useState,useRef,useEffect} from "react";


const AudioRecorderPlayer = () => {
  const [permission, setPermission] = useState(false);
  const [recordComplete, setRcdComplete] = useState(false);
  const [stream, setStream] = useState<MediaStream>();
  const [recordingStatus, setRecordingStatus] = useState("inactive");
  const mrRef = useRef<MediaRecorder | null>(null);
  const audioRef = useRef<HTMLAudioElement | null>(null);

  const [oldAudioRef,setOldAudioRef] = useState<HTMLAudioElement | null>(null);

  const audioChunksRef = useRef<Blob[]>([]);
  const blobRef = useRef<Blob | null>(null);
  const [audio, setAudio] = useState('');

    const getDataType = () => {
        // This function aims at providing a proper mymetype for each web browser.
        // It has been written using trials and errors.
        // There is no guaranty it will always work.
        const referStr = window.navigator.userAgent
        if (referStr.includes('Safari')) {
            if (!referStr.includes('Chrome')) return 'video/mp4'
            // We are using Brave.
        }
  
        return 'video/webm'
    }; /* End of getDataType */

    const dataType = getDataType()

    const experim = false;


    const getMicrophonePermission = async () => {
    if ("MediaRecorder" in window) {
      try {
        const streamData = await navigator.mediaDevices.getUserMedia({
            audio: true,
            video: false,
        });
        setPermission(true);
        setStream(streamData);
      } catch (err) {
        alert("err.message");
      }
    } else {
      alert("The MediaRecorder API is not supported in your browser.");
    }
  }; /* End of getMicrophonePermission */


  const startRecording = async () => {
    URL.revokeObjectURL(audio);
    setAudio('')
  
        mrRef.current = null
        audioChunksRef.current = []
  
        setRecordingStatus("recording");
        const mediaRecorder = new MediaRecorder(stream!, {
            mimeType: dataType,
            audioBitsPerSecond: 16*44100
        });
        mrRef.current = mediaRecorder;
  
        mediaRecorder.start()
        mediaRecorder.ondataavailable = (event) => {
            if (typeof event.data === "undefined") return;
            if (event.data.size === 0) return;
            audioChunksRef.current.push(event.data);
        };
    }; /* End of startRecording */


    const stopRecording = () => {
        setRecordingStatus("inactive");
        if (!mrRef.current) return
        mrRef.current?.stop();
        mrRef.current.onstop = async () => {
            const audioBlob = new Blob(audioChunksRef.current, {
                                                                 type: dataType});
            const audioUrl = URL.createObjectURL(audioBlob);
            setAudio(audioUrl);
            setRcdComplete(true);
        };
    }; /* End of stopRecording */


  const handlePlay = () => {
  }; /* End of handlePlay */


  const handleEnd = () => {
  }; /* End of handleEnd */




    const getObjectDiff = (obj1: { [x: string]: any; },
                                                 obj2: { [x: string]: any; hasOwnProperty?: any; }, 
                                                 compareRef = false) => {
        return Object.keys(obj1).reduce((result, key) => {
            if (!obj2.hasOwnProperty(key)) {
                result.push(key);
            } else if (_.isEqual(obj1[key], obj2[key])) {
                const resultKeyIndex = result.indexOf(key);
      
                if (compareRef && obj1[key] !== obj2[key]) {
                    result[resultKeyIndex] = `${key} (ref)`;
                } else {
                    result.splice(resultKeyIndex, 1);
                }
            }
            return result;
        }, Object.keys(obj2));
    } /* End of getObjectDiff */


    return (
    <div>
      <main>
                {!permission ? (
                    <button onClick={getMicrophonePermission} type="button">
                        Get Microphone
                    </button>
                ): null}
                {permission && recordingStatus === "inactive" ? (
          <button onClick={startRecording} type="button">
            Start Recording
                    </button>
                ) : null}
                {recordingStatus === "recording" ? (
            <button onClick={stopRecording} type="button">
                        Stop Recording
                    </button>
                ) : null}
        <audio src={audio}
                    ref={audioRef}
                    id="audio-player"
                    onPlay={handlePlay}
                    onEnded={handleEnd}
                    onEmptied = {(event) => {console.log('--onEmptied--')}}
                    onCanPlayThrough = {(event) => {console.log('--onCanPlayThrough--')}}
                    controls />
      </main>
    </div>
  );
        
}; /* End of AudioRecorderPlayer */

export default AudioRecorderPlayer;
0

There are 0 best solutions below