概要
ブラウザで音声ファイルを再生する実装をする際に多くの場合は、HTMLMediaElement
ベースのaudioタグやAudio()コンストラクターで事足りると思います。が、iOS Safari16.0
ではClick Event
を都度拾わないと再生ができない状況に出くわしました。そこで本記事では、その回避策としてAudioContextを利用したWebブラウザで音声ファイルを任意のタイミングで再生する実装を以下に記します。(iOS Safari16.0, Android Chrome108で動作確認)
実装方法
// WebKitを使えるように型拡張
declare global {
interface Window {
webkitAudioContext: typeof AudioContext
}
}
/**
* 一度のclickイベントの後なら自由に音声ファイルを操作できるようにするクラス
*/
export default class Sound {
audioArrayBuffer?: ArrayBuffer
soundPath: string
constructor(soundPath: string) {
this.soundPath = soundPath
}
/**
* 音声ファイルをロードするメソッド
*/
async load() {
// audioデータをArrayBufferに詰める。
// XMLHttpRequest, fetch() or FileReaderのどれかを利用すれば良し
const audioResponse = await fetch(this.soundPath)
this.audioArrayBuffer = await audioResponse.arrayBuffer()
}
/**
* 音声ファイルを任意のタイミングで再生するメソッド
*/
async playSound() {
if (!this.audioArrayBuffer)
throw new Error('load メソッドを実行してください。')
const audioContext = new (window.AudioContext ||
window.webkitAudioContext)()
const source = audioContext.createBufferSource()
source.buffer = await audioContext.decodeAudioData(
this.audioArrayBuffer.slice(0)
)
source.loop = false
source.connect(audioContext.destination)
source.start(0)
}
}
使い方
どこかでClick Event
を受けた後に以下のように利用してください。おそらく、複数回playSound
メソッドを叩いても動作するはずです。
const soundPath = 'path'
const sound = new Sound(soundPath)
sound.load()
sound.playSound()
// ...何かの処理(Click Eventを受け取る必要なし)
sound.playSound()