🎤
ブラウザだけで「録音して保存する」
個人開発でブラウザだけで完結する録音→保存が必要になったので、その実装をまとめます。
方針(結論)
- getUserMedia でマイク権限&音声ストリーム取得
- MediaRecorder で録音開始/停止と Blob 生成
- URL.createObjectURL で即時プレビュー/ダウンロード
最小コード
// 1) マイクからストリーム取得(ヒント付き)
const stream = await navigator.mediaDevices.getUserMedia({
audio: { echoCancellation: true, noiseSuppression: true },
});
// 2) とりあえず無難な既定(詳細は後述のTIPSで最適化)
const mimeType = MediaRecorder.isTypeSupported("audio/webm;codecs=opus")
? "audio/webm;codecs=opus"
: "audio/webm";
const recorder = new MediaRecorder(stream, { mimeType });
const chunks: Blob[] = [];
recorder.ondataavailable = (e) => {
if (e.data.size) chunks.push(e.data);
};
const start = () => recorder.start();
const stop = () =>
new Promise<Blob>((resolve) => {
recorder.onstop = () => {
stream.getTracks().forEach((t) => t.stop()); // マイク解放
resolve(new Blob(chunks, { type: mimeType }));
};
recorder.stop();
});
// 使用例:
// start();
// …ユーザー操作で停止…
// const blob = await stop();
ダウンロード
function downloadBlob(blob: Blob, filename: string) {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename; // 例: "recording.webm" / "recording.m4a"
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
}
生成した
blob
を<audio src={URL.createObjectURL(blob)} controls>
に入れれば、その場で確認再生も可能です。
TIPS:スマホ対応のための「MIME 総当たり」
モバイルはブラウザ/OS差が大きく、audio/webm;codecs=opus
が弾かれることが普通にあります。
複数の MIME 候補を用意し、MediaRecorder.isTypeSupported
で動くものを選ぶと成功率が一気に上がります。実際、audio/mp4
や audio/wav
を候補に加えるだけで「録音が始まらない/すぐ止まる」症状が解消するケースが多いです。
const CANDIDATES = [
"audio/webm;codecs=opus",
"audio/ogg;codecs=opus",
"audio/mp4", // iOS Safari で効くことが多い
"audio/wav", // 最終手段(サイズ大)
"audio/webm",
];
const mimeType =
CANDIDATES.find((t) => MediaRecorder.isTypeSupported(t)) ?? "";
if (!mimeType) throw new Error("対応MIMEが見つかりません");
Discussion