From cefb6847ac20168d8c9bcd71af47863e75fcfeb2 Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Mon, 27 Nov 2023 20:32:48 +0900 Subject: [PATCH] fix: sound effects stop music playback in iOS This also improves the overall sound performance (including Android PWA) Co-authored-by: naskya --- README.md | 2 ++ packages/client/src/scripts/sound.ts | 37 +++++++++++++++++++--------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index cbdc4097..a4f9031e 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ ## 細かい変更点 +- iOS で効果音と音楽の再生が干渉する問題を修正(Misskey から取り込み) + - 本家にもマージリクエストを出しています ([!10641](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10641)) - HTML のコードに入るコメントアートを削除 - 全ページにこんなの入れなくても…… - デフォルトではバイブレーションを無効に diff --git a/packages/client/src/scripts/sound.ts b/packages/client/src/scripts/sound.ts index 84388b81..289eb9e0 100644 --- a/packages/client/src/scripts/sound.ts +++ b/packages/client/src/scripts/sound.ts @@ -1,16 +1,25 @@ import { ColdDeviceStorage } from "@/store"; +const ctx = new AudioContext(); const cache = new Map(); -export function getAudio(file: string, useCache = true): HTMLAudioElement { - let audio: HTMLAudioElement; +export async function getAudio( + file: string, + useCache = true, +): HTMLAudioElement { if (useCache && cache.has(file)) { - audio = cache.get(file); - } else { - audio = new Audio(`/static-assets/sounds/${file}.mp3`); - if (useCache) cache.set(file, audio); + return cache.get(file); } - return audio; + + const response = await fetch(`/static-assets/sounds/${file}.mp3`); + const arrayBuffer = await response.arrayBuffer(); + const audioBuffer = await ctx.decodeAudioData(arrayBuffer); + + if (useCache) { + cache.set(file, audioBuffer); + } + + return audioBuffer; } export function setVolume( @@ -28,11 +37,17 @@ export function play(type: string) { playFile(sound.type, sound.volume); } -export function playFile(file: string, volume: number) { +export async function playFile(file: string, volume: number) { const masterVolume = ColdDeviceStorage.get("sound_masterVolume"); - if (masterVolume === 0 || volume === 0 || file.toLowerCase().includes("none")) + if (masterVolume === 0 || volume === 0) { return; + } - const audio = setVolume(getAudio(file), volume); - audio.play(); + const gainNode = ctx.createGain(); + gainNode.gain.value = masterVolume * volume; + + const soundSource = ctx.createBufferSource(); + soundSource.buffer = await getAudio(file); + soundSource.connect(gainNode).connect(ctx.destination); + soundSource.start(); }