iTranslated by AI
The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🎙️
Implementing iOS-Compatible Web Browser Audio Recording with audio-recorder-polyfill
What I want to do
- Create a recording function in the browser
Issues
- I wanted to use
MediaRecorder, but as of the investigation (February 2021), iOS Safari was not supported...- There seemed to be other methods besides MediaRecorder, but it was the simplest, and considering the future, it seemed better to use a polyfill to make it available.
- When using MediaRecorder purely, it conflicts with React's state management. Audio itself has internal state, and if it becomes double-managed with React's state, one of the states may be lost.
👇 Reference
https://qiita.com/kazumicho/items/086864a9d78121d54aa7
Background
- Introducing it into React (Next.js)
Tools to use this time
Setup polyfill
yarn add audio-recorder-polyfill- Add file:
public/polyfill.js
import AudioRecorder from "audio-recorder-polyfill";
window.MediaRecorder = AudioRecorder;
- Modify file: Add the following script to
_app.tsx
...
<Head>
<script>
{
() => {
// Executed to run the script in CSR
if (!window.MediaRecorder) {
document.write(
decodeURI('%3Cscript defer src="/polyfill.js"%3E%3C/script%3E')
)
}
}
}
</script>
</Head>
...
Install react-media-recorder
By using this library, you can balance the internal state of MediaRecorder with React's state management.
yarn add react-media-recorder
Hooks are provided, so you can declare it as follows:
const {
status,
startRecording,
stopRecording,
resumeRecording,
pauseRecording,
mediaBlobUrl,
} = useReactMediaRecorder({ audio: true });
Fin: Example
The implementation image is as follows.
export default function Home() {
const {
status,
startRecording,
stopRecording,
resumeRecording,
pauseRecording,
mediaBlobUrl,
} = useReactMediaRecorder({ audio: true });
const [isNowRecording, setIsNowRecording] = useState(false);
function onStart() {
startRecording();
setIsNowRecording(true);
}
function onPause() {
pauseRecording();
}
function onResume() {
resumeRecording();
}
function onStop() {
stopRecording();
setIsNowRecording(false);
}
return (
<div className={styles.container}>
<Head>
<script>
{() => {
// Done to execute the script in CSR
if (!window.MediaRecorder) {
document.write(
decodeURI('%3Cscript defer src="/polyfill.js"%3E%3C/script%3E')
);
}
}}
</script>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>
Welcome to <a href="https://nextjs.org">Next.js!</a>
</h1>
<p className={styles.description}>
Get started by editing{" "}
<code className={styles.code}>pages/index.js</code>
</p>
<div className={styles.grid}>
<div className={styles.card}>
<button onClick={onStart} type="button" className="m-1">
Record
</button>
<button onClick={onPause} type="button" className="m-1">
Pause
</button>
<button onClick={onResume} type="button" className="m-1">
Resume
</button>
<button onClick={onStop} type="button" className="m-1">
Stop
</button>
</div>
<div className={styles.card}>
<audio src={mediaBlobUrl} controls />
</div>
<div className={styles.card}>
{isNowRecording ? <p>Recording</p> : <p>Ready to record</p>}
</div>
</div>
</main>
<footer className={styles.footer}>
<a
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Powered by{" "}
<img src="/vercel.svg" alt="Vercel Logo" className={styles.logo} />
</a>
</footer>
</div>
);
}
I have the repository published on GitHub and deployed on Vercel, so please try opening it on iOS for reference.
Discussion
Safari 14.1で開くとAn unexpected error has occurred.となるようです。コンソールにはError: Unsupported Browserと出ていました。