Reputation: 471
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?
Upvotes: 8
Views: 10140
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
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
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:
NotSupportedError
explicitlyBut for now it works and that's good enough for a personal project.
Upvotes: 3