From 4b13179ff919e4424eb60a37db0e72df4bd12101 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?=
 <46447427+samunohito@users.noreply.github.com>
Date: Tue, 21 Nov 2023 20:05:04 +0900
Subject: [PATCH] =?UTF-8?q?=E3=82=B5=E3=82=A6=E3=83=B3=E3=83=89=E5=86=8D?=
 =?UTF-8?q?=E7=94=9F=E6=96=B9=E6=B3=95=E3=81=AE=E5=A4=89=E6=9B=B4=E3=81=AB?=
 =?UTF-8?q?=E8=BF=BD=E5=BE=93=E3=81=A7=E3=81=8D=E3=81=A6=E3=81=84=E3=81=AA?=
 =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=9F=E6=89=80=E3=82=92=E4=BF=AE=E6=AD=A3?=
 =?UTF-8?q?=20(#12368)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com>
---
 CHANGELOG.md                                  |  1 +
 packages/frontend/src/scripts/sound.ts        | 20 +++++++++----------
 .../frontend/src/widgets/WidgetJobQueue.vue   | 14 ++++++++++---
 3 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 900d042eaf..7feb89b546 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@
 
 ### Client
 - fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正
+- Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367
 
 ### Server
 - Fix: 時間経過により無効化されたアンテナを再有効化したとき、サーバ再起動までその状況が反映されないのを修正 #12303
diff --git a/packages/frontend/src/scripts/sound.ts b/packages/frontend/src/scripts/sound.ts
index 4b0cd0bb39..2b604bd98a 100644
--- a/packages/frontend/src/scripts/sound.ts
+++ b/packages/frontend/src/scripts/sound.ts
@@ -61,7 +61,7 @@ export const soundsTypes = [
 	'noizenecio/kick_gaba7',
 ] as const;
 
-export async function getAudio(file: string, useCache = true) {
+export async function loadAudio(file: string, useCache = true) {
 	if (useCache && cache.has(file)) {
 		return cache.get(file)!;
 	}
@@ -77,12 +77,6 @@ export async function getAudio(file: string, useCache = true) {
 	return audioBuffer;
 }
 
-export function setVolume(audio: HTMLAudioElement, volume: number): HTMLAudioElement {
-	const masterVolume = defaultStore.state.sound_masterVolume;
-	audio.volume = masterVolume - ((1 - volume) * masterVolume);
-	return audio;
-}
-
 export function play(type: 'noteMy' | 'note' | 'antenna' | 'channel' | 'notification') {
 	const sound = defaultStore.state[`sound_${type}`];
 	if (_DEV_) console.log('play', type, sound);
@@ -91,16 +85,22 @@ export function play(type: 'noteMy' | 'note' | 'antenna' | 'channel' | 'notifica
 }
 
 export async function playFile(file: string, volume: number) {
+	const buffer = await loadAudio(file);
+	createSourceNode(buffer, volume)?.start();
+}
+
+export function createSourceNode(buffer: AudioBuffer, volume: number) : AudioBufferSourceNode | null {
 	const masterVolume = defaultStore.state.sound_masterVolume;
 	if (masterVolume === 0 || volume === 0) {
-		return;
+		return null;
 	}
 
 	const gainNode = ctx.createGain();
 	gainNode.gain.value = masterVolume * volume;
 
 	const soundSource = ctx.createBufferSource();
-	soundSource.buffer = await getAudio(file);
+	soundSource.buffer = buffer;
 	soundSource.connect(gainNode).connect(ctx.destination);
-	soundSource.start();
+
+	return soundSource;
 }
diff --git a/packages/frontend/src/widgets/WidgetJobQueue.vue b/packages/frontend/src/widgets/WidgetJobQueue.vue
index 89770b2216..fa82997570 100644
--- a/packages/frontend/src/widgets/WidgetJobQueue.vue
+++ b/packages/frontend/src/widgets/WidgetJobQueue.vue
@@ -99,7 +99,10 @@ const current = reactive({
 	},
 });
 const prev = reactive({} as typeof current);
-const jammedSound = sound.setVolume(sound.getAudio('syuilo/queue-jammed'), 1);
+let jammedAudioBuffer: AudioBuffer | null = $ref(null);
+let jammedSoundNodePlaying: boolean = $ref(false);
+
+sound.loadAudio('syuilo/queue-jammed').then(buf => jammedAudioBuffer = buf);
 
 for (const domain of ['inbox', 'deliver']) {
 	prev[domain] = deepClone(current[domain]);
@@ -113,8 +116,13 @@ const onStats = (stats) => {
 		current[domain].waiting = stats[domain].waiting;
 		current[domain].delayed = stats[domain].delayed;
 
-		if (current[domain].waiting > 0 && widgetProps.sound && jammedSound.paused) {
-			jammedSound.play();
+		if (current[domain].waiting > 0 && widgetProps.sound && jammedAudioBuffer && !jammedSoundNodePlaying) {
+			const soundNode = sound.createSourceNode(jammedAudioBuffer, 1);
+			if (soundNode) {
+				jammedSoundNodePlaying = true;
+				soundNode.onended = () => jammedSoundNodePlaying = false;
+				soundNode.start();
+			}
 		}
 	}
 };