ブラウザでは、ユーザーが明示的に操作しない限り、音声の自動再生が制限 されています。
これは、ユーザーエクスペリエンスを考慮したブラウザのポリシーによるもの。
この制限を回避するには、適切な AudioContext
の管理とイベント処理が必要。
本記事では、ReactアプリケーションでWeb Audio APIを用いて音声を適切に再生する方法を解説します。
公式ドキュメント
https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
https://developer.chrome.com/blog/autoplay/
ブラウザの自動再生ポリシー
ポリシーの概要
- ユーザーが操作しない限り、音声の自動再生は不可
- 無音の音声 (muted) であれば自動再生可能(そりゃそう)
- クリック、タップ等のユーザーインタラクション後に
AudioContext
を起動すれば良い
実装のポイント
1. AudioContext
の状態管理
AudioContext
には以下の3つの状態があります。
状態 | 説明 |
---|---|
suspended |
音声の再生が一時停止された状態(初期状態) |
running |
音声を再生できる状態 |
closed |
完全に閉じられた状態 |
2. ユーザーインタラクションの検知
ユーザーがクリックやタップなどの操作をした際に AudioContext
を running
状態に変更する。
document.addEventListener("click", () => {
// AudioContextがsuspended(停止状態)の場合はresume()を呼び出して再生を許可
if (audioContext.state === "suspended") {
audioContext.resume().then(() => {
console.log("AudioContext is now running");
});
}
});
3. 音声再生の制御
AudioBufferSourceNode を用いて音声をロードし、再生する。
ユーザー操作後に AudioContext.resume() を実行して再生を許可する。
Reactでの実装例
1. AudioContextの初期化
import { useEffect, useState } from "react";
const useAudio = (url) => {
const [audioContext, setAudioContext] = useState(null);
const [audioBuffer, setAudioBuffer] = useState(null);
useEffect(() => {
const context = new (window.AudioContext || window.webkitAudioContext)();
setAudioContext(context);
// 音声をロード
fetch(url)
.then((res) => res.arrayBuffer())
.then((data) => context.decodeAudioData(data))
.then((buffer) => setAudioBuffer(buffer));
return () => context.close();
}, [url]);
const playSound = () => {
if (audioContext.state === "suspended") {
audioContext.resume();
}
if (audioBuffer) {
const source = audioContext.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioContext.destination);
source.start(0);
}
};
return playSound;
};
2. Reactコンポーネントでの使用例
const AudioPlayer = () => {
const playSound = useAudio("/audio/sample.mp3");
return (
<button onClick={playSound}>
音声を再生
</button>
);
};
export default AudioPlayer;
実装の流れ
-
ページ読み込み時
AudioContext
はsuspended
(一時停止) 状態 -
ユーザーがクリックやタップを行う
AudioContext.resume()
を実行し、running
状態にする -
音声の再生
AudioBufferSourceNode
を作成し、音声を再生
注意点
-
ブラウザの自動再生ポリシーへの対応
初回のクリック・タップでAudioContext.resume()
を呼び出す
音声ファイルはプリロードせず、ユーザー操作後にロード -
モバイルデバイスでの挙動の違い
SafariはAudioContext
をページ遷移時に自動で閉じるため、適切な管理が必要
Chrome は、バックグラウンドに回るとsuspended
状態に戻る -
音声ファイルの非同期ロード
音声データは fetch() でロードし、decodeAudioData()
でデコードする
ネットワーク遅延が発生するため、ローディング状態を管理
まとめ
Web Audio API を使った音声再生には、以下の3つのポイントが重要。
- ユーザーインタラクションを適切に検知
初回クリックやタップ時にAudioContext.resume()
を呼び出す -
AudioContext
の状態を適切に管理
suspended
→running
の遷移を考慮する - 音声データのロードと再生
AudioBufferSourceNode
を用いた正しい再生処理を実装する