Felix Dolderer
Felix Dolderer

Reputation: 471

MediaRecorder iOS 14.6: mimeType not supported

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):

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

Am I getting something else entirely wrong?

Upvotes: 8

Views: 10140

Answers (3)

The Blind Hawk
The Blind Hawk

Reputation: 1666

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.

Upvotes: 8

Tunji Abioye
Tunji Abioye

Reputation: 69

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);
      }
    }
  };

Upvotes: 0

Felix Dolderer
Felix Dolderer

Reputation: 471

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.

Upvotes: 3

Related Questions