diff --git a/src/components/App.vue b/src/components/App.vue index e1cc5c9a42..0b19444554 100644 --- a/src/components/App.vue +++ b/src/components/App.vue @@ -97,6 +97,13 @@ watchEffect(() => { setThemeToCss(theme); }); +// 再生デバイスの初期化と変更の監視 +watchEffect(() => { + void store.actions.APPLY_DEVICE_ID_TO_AUDIO_CONTEXT({ + device: store.state.savingSetting.audioOutputDevice, + }); +}); + // ソフトウェアを初期化 const { hotkeyManager } = useHotkeyManager(); const isEnginesReady = ref(false); diff --git a/src/store/singing.ts b/src/store/singing.ts index 611fe2ce22..8fc34c76fa 100644 --- a/src/store/singing.ts +++ b/src/store/singing.ts @@ -106,6 +106,7 @@ import { uuid4 } from "@/helpers/random"; import { convertToWavFileData } from "@/sing/convertToWavFileData"; import { generateWriteErrorMessage } from "@/helpers/fileHelper"; import path from "@/helpers/path"; +import { showAlertDialog } from "@/components/Dialog/Dialog"; const logger = createLogger("store/singing"); @@ -1682,6 +1683,22 @@ export const singingStore = createPartialStore({ }, }, + APPLY_DEVICE_ID_TO_AUDIO_CONTEXT: { + action(_, { device }) { + if (audioContext) { + const sinkId = device === "default" ? "" : device; + audioContext.setSinkId(sinkId).catch((err: unknown) => { + void showAlertDialog({ + type: "error", + title: "エラー", + message: "再生デバイスが見つかりません", + }); + throw err; + }); + } + }, + }, + /** * レンダリングを行う。レンダリング中だった場合は停止して再レンダリングする。 */ diff --git a/src/store/type.ts b/src/store/type.ts index fae93613da..50c523d22a 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -1326,6 +1326,10 @@ export type SingingStoreTypes = { SYNC_TRACKS_AND_TRACK_CHANNEL_STRIPS: { action(): void; }; + + APPLY_DEVICE_ID_TO_AUDIO_CONTEXT: { + action(payload: { device: string }): void; + }; }; export type SingingCommandStoreState = { diff --git a/src/type/globals.d.ts b/src/type/globals.d.ts index 6c761fa17f..9708bb15e5 100644 --- a/src/type/globals.d.ts +++ b/src/type/globals.d.ts @@ -9,6 +9,10 @@ declare global { setSinkId(deviceID: string): Promise; // setSinkIdを認識してくれないため } + interface AudioContext { + setSinkId: (sinkId: string) => Promise; + } + interface Window { readonly [SandboxKey]: import("./preload").Sandbox; }