🎙️
audio-recorder-polyfillを使ってiOS対応のWebブラウザ録音機能
やりたいこと
- ブラウザで録音機能を作りたい
問題
-
MediaRecorder
を使いたいが、調査(2021 年 2 月)時点では iOS Safari は未対応だった・・・。
- MediaRecorder 以外にも方法はありそうだったが、一番シンプルであり、今後を考えるとこれを使えるように polyfill した方がよさそうだった。 - 純粋に MediaRecorder を使用した場合、react の状態管理とぶつかる。audio はそれ自体が内部的に状態を持っており、react の state と二重管理になった場合に片方の状態をロストすることが起きる。
👇 参考
https://qiita.com/kazumicho/items/086864a9d78121d54aa7
背景
- React(Next.js)に導入する
今回つかうもの
Setup polyfill
yarn add audio-recorder-polyfill
- ファイル追加:
public/polyfill.js
import AudioRecorder from "audio-recorder-polyfill";
window.MediaRecorder = AudioRecorder;
- ファイル修正:
_app.tsx
に以下のスクリプトを追加
...
<Head>
<script>
{
() => {
// CSRでscriptを実行するために行う
if (!window.MediaRecorder) {
document.write(
decodeURI('%3Cscript defer src="/polyfill.js">%3C/script>')
)
}
}
}
</script>
</Head>
...
Install react-media-recorder
このライブラリを使うことで MediaRecorder の内部状態と react の状態管理を両立させる。
yarn add react-media-recorder
hooks が提供されているので、次のように宣言できる。
const {
status,
startRecording,
stopRecording,
resumeRecording,
pauseRecording,
mediaBlobUrl,
} = useReactMediaRecorder({ audio: true });
Fin: Example
実装イメージは次のような形です。
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>
{() => {
// CSRでscriptを実行するために行う
if (!window.MediaRecorder) {
document.write(
decodeURI('%3Cscript defer src="/polyfill.js">%3C/script>')
);
}
}}
</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>録音中</p> : <p>録音可能</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>
);
}
Github にリポジトリ公開しているのと、Vercel にデプロイしているので参考に iOS で開いてみてください。
Discussion
Safari 14.1で開くとAn unexpected error has occurred.となるようです。コンソールにはError: Unsupported Browserと出ていました。