MediaRecorder iOS 14.6: mimeType not supported
Asked Answered
B

3

8

I am recording and sending audio via a website. For that purpose I use the MediaRecorder API.

There are no issues when using the site on desktop or Android devices and according to the MediaRecorder documentation, since a release in September 2020, iOS 14 should be supported as well.

The MediaRecorder is instantiated like this:

navigator.mediaDevices.getUserMedia({ audio: true, video: false })
  .then((stream) => {
    // Some validation and other processing. Omitted for brevity.

    const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });

    // Using the mediaRecorder. Omitted for brevity.
  });

When doing this on an iPhone 12 with iOS 14.6, i get the following error from that instantiation line:

NotSupportedError: mimeType is not supported

I get the same error when trying other formats (these are the ones I found and tried):

  • audio/webm (as shown in example above)
  • video/webm
  • audio/ogg (also errors on desktop)
  • audio/ogg; codecs=opus (also errors on desktop)

Is there any mimeType for MediaRecorder that lets me use audio on iOS devices?

Am I getting something else entirely wrong?

Besant answered 7/6, 2021 at 15:44 Comment(2)
Hi Felix, I'm using Ionic React and using React-Webcam. I also chose the mimeType: video/mp4, and it led to the "mimeType not supported" error. Are you using Ionic as well? If so, did you find a way to get the camera working on iOS simulator?Nosology
btw, which mime-type is supported by MediaRecorder can be live tested using sitelint.com/lab/media-recoder-supported-mime-typeContracture
G
8

A preferred solution for me is something like this:

if (MediaRecorder.isTypeSupported('video/webm; codecs=vp9')) {
    var options = {mimeType: 'video/webm; codecs=vp9'};
} else  if (MediaRecorder.isTypeSupported('video/webm')) {
    var options = {mimeType: 'video/webm'};
} else if (MediaRecorder.isTypeSupported('video/mp4')) {
    var options = {mimeType: 'video/mp4', videoBitsPerSecond : 100000};
} else {
    console.error("no suitable mimetype found for this device");
}
const mediaRecorder = new MediaRecorder(stream, options);

IOS only allows mp4, so after running this code you will get that option automatically.
All modern browsers have MediaRecorder.isTypeSupported set as compatible so there is no need to try and catch the error.

Garibull answered 30/9, 2022 at 8:14 Comment(0)
B
3

It turns out video/mp4 works with iOS. It can be used for audio-only as well, even though it says video.

Since other browsers don't support video/mp4, a try/catch with the video/mp4 as a fallback can be used, which results in the following solution:

let mediaRecorder;
try {
  mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });
}
catch (err1) {
  try {
    // Fallback for iOS
    mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/mp4' });
  }
  catch (err2) {
    // If fallback doesn't work either. Log / process errors.
    console.error({err1});
    console.error({err2})
  }
}

The code could be made cleaner and more explicit by:

  • catching the NotSupportedError explicitly
  • querying the device / OS and using the according mimeType explicitly, instead of knowingly running into an error.

But for now it works and that's good enough for a personal project.

Besant answered 7/6, 2021 at 17:33 Comment(3)
video/mp4 results in a 1 second audio when recorded on Chrome-iOS. Is this something you ran across during your issue, i have already spent a lot of time on this on getting audio recording to work on Chrome/iOS, any help is appreciated!Urien
@Urien No, using the code above I don't encounter your problem with Chrome on iOS w\ iPhone 12, iOS 14.6. The start function of MediaRecorder has an optional parameter timeslice, if you set this parameter, you get bits of audio of the specified length. I set this to 1000 milliseconds in my project and reassemble the audio later. Maybe you set the timeslice and forgot to reassemble the audio, in that case you would always get a bit of audio of only e.g. 1 second length.Besant
Or related to this: https://mcmap.net/q/1327118/-recording-audio-with-mediarecorder-on-iphone-with-safari-and-chrome-only-1-second-long-mimetype-and-ffmpeg-problem/1066234Wamble
L
0

A more compact answer that uses retries with variable list length

const mimeTypes = ["audio/webm", "video/mp4"];

const genericName = async (mimeIndex = 0) => {
    try {
        //Set the mimeType to the first item in the mimeTypes array

        const mimeType = mimeTypes[mimeIndex];
        MediaRecorder.isTypeSupported(mimeType);

        //create new Media recorder instance using the stream
        const media: MediaRecorder = new MediaRecorder(stream, { mimeType });


    } catch (err: any) {
        console.log("Error recording", err.message);
        
        // Retry with the next mimeType if the first mimeType fails
        const retries = mimeTypes.length;
        if (mimeIndex < retries) {
        startRecording(mimeIndex + 1);
      }
    }
  };
Lockup answered 9/3 at 14:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.