fix(stage-*): incorrect use of useAudioDevices hook
This commit is contained in:
@@ -7,7 +7,7 @@ import { useModsServerChannelStore } from '@proj-airi/stage-ui/stores/mods/api/c
|
||||
import { useContextBridgeStore } from '@proj-airi/stage-ui/stores/mods/api/context-bridge'
|
||||
import { useAiriCardStore } from '@proj-airi/stage-ui/stores/modules/airi-card'
|
||||
import { useOnboardingStore } from '@proj-airi/stage-ui/stores/onboarding'
|
||||
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
|
||||
import { useSettings, useSettingsAudioDevice } from '@proj-airi/stage-ui/stores/settings'
|
||||
import { useTheme } from '@proj-airi/ui'
|
||||
import { StageTransitionGroup } from '@proj-airi/ui-transitions'
|
||||
import { storeToRefs } from 'pinia'
|
||||
@@ -26,6 +26,7 @@ const settings = storeToRefs(settingsStore)
|
||||
const onboardingStore = useOnboardingStore()
|
||||
const serverChannelStore = useModsServerChannelStore()
|
||||
const characterOrchestratorStore = useCharacterOrchestratorStore()
|
||||
const settingsAudioDeviceStore = useSettingsAudioDevice()
|
||||
const { showingSetup } = storeToRefs(onboardingStore)
|
||||
const { isDark } = useTheme()
|
||||
const cardStore = useAiriCardStore()
|
||||
@@ -80,6 +81,7 @@ onMounted(async () => {
|
||||
|
||||
await displayModelsStore.loadDisplayModelsFromIndexedDB()
|
||||
await settingsStore.initializeStageModel()
|
||||
await settingsAudioDeviceStore.initialize()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useContextBridgeStore } from '@proj-airi/stage-ui/stores/mods/api/conte
|
||||
import { useAiriCardStore } from '@proj-airi/stage-ui/stores/modules/airi-card'
|
||||
import { usePerfTracerBridgeStore } from '@proj-airi/stage-ui/stores/perf-tracer-bridge'
|
||||
import { listProvidersForPluginHost, shouldPublishPluginHostCapabilities } from '@proj-airi/stage-ui/stores/plugin-host-capabilities'
|
||||
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
|
||||
import { useSettings, useSettingsAudioDevice } from '@proj-airi/stage-ui/stores/settings'
|
||||
import { useTheme } from '@proj-airi/ui'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { onMounted, onUnmounted, watch } from 'vue'
|
||||
@@ -61,6 +61,7 @@ const characterOrchestratorStore = useCharacterOrchestratorStore()
|
||||
const analyticsStore = useSharedAnalyticsStore()
|
||||
const pluginHostInspectorStore = usePluginHostInspectorStore()
|
||||
const stageWindowLifecycleStore = useStageWindowLifecycleStore()
|
||||
const settingsAudioDeviceStore = useSettingsAudioDevice()
|
||||
const context = useElectronEventaContext()
|
||||
usePerfTracerBridgeStore()
|
||||
initializeStageThreeRuntimeTraceBridge()
|
||||
@@ -123,6 +124,7 @@ onMounted(async () => {
|
||||
await chatSessionStore.initialize()
|
||||
await displayModelsStore.loadDisplayModelsFromIndexedDB()
|
||||
await settingsStore.initializeStageModel()
|
||||
await settingsAudioDeviceStore.initialize()
|
||||
|
||||
const serverChannelConfig = await getServerChannelConfig()
|
||||
serverChannelSettingsStore.websocketTlsConfig = serverChannelConfig.tlsConfig
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useModsServerChannelStore } from '@proj-airi/stage-ui/stores/mods/api/c
|
||||
import { useContextBridgeStore } from '@proj-airi/stage-ui/stores/mods/api/context-bridge'
|
||||
import { useAiriCardStore } from '@proj-airi/stage-ui/stores/modules/airi-card'
|
||||
import { useOnboardingStore } from '@proj-airi/stage-ui/stores/onboarding'
|
||||
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
|
||||
import { useSettings, useSettingsAudioDevice } from '@proj-airi/stage-ui/stores/settings'
|
||||
import { useTheme } from '@proj-airi/ui'
|
||||
import { StageTransitionGroup } from '@proj-airi/ui-transitions'
|
||||
import { storeToRefs } from 'pinia'
|
||||
@@ -32,6 +32,7 @@ const onboardingStore = useOnboardingStore()
|
||||
const chatSessionStore = useChatSessionStore()
|
||||
const serverChannelStore = useModsServerChannelStore()
|
||||
const characterOrchestratorStore = useCharacterOrchestratorStore()
|
||||
const settingsAudioDeviceStore = useSettingsAudioDevice()
|
||||
const { showingSetup } = storeToRefs(onboardingStore)
|
||||
const { isDark } = useTheme()
|
||||
const cardStore = useAiriCardStore()
|
||||
@@ -93,6 +94,7 @@ onMounted(async () => {
|
||||
|
||||
await displayModelsStore.loadDisplayModelsFromIndexedDB()
|
||||
await settingsStore.initializeStageModel()
|
||||
await settingsAudioDeviceStore.initialize()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
@@ -6,9 +6,9 @@ import { until } from '@vueuse/core'
|
||||
import { computed, onUnmounted, ref, shallowRef, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { useAudioDevice } from '../../../composables/audio'
|
||||
import { useAudioAnalyzer } from '../../../composables/audio/audio-analyzer'
|
||||
import { useAudioRecorder } from '../../../composables/audio/audio-recorder'
|
||||
import { useAudioDevice } from '../../../composables/audio/device'
|
||||
import { LevelMeter, TestDummyMarker, ThresholdMeter } from '../../gadgets'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
+14
-12
@@ -1,13 +1,13 @@
|
||||
import { useDevicesList, useUserMedia } from '@vueuse/core'
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
|
||||
export function useAudioDevice() {
|
||||
const devices = useDevicesList({ constraints: { audio: true }, requestPermissions: true })
|
||||
export function useAudioDevice(requestPermission: boolean = false) {
|
||||
const devices = useDevicesList({ constraints: { audio: true }, requestPermissions: requestPermission })
|
||||
const audioInputs = computed(() => devices.audioInputs.value)
|
||||
const selectedAudioInput = ref<string>(devices.audioInputs.value[0]?.deviceId || '')
|
||||
const selectedAudioInput = ref<string>(devices.audioInputs.value.find(device => device.deviceId === 'default')?.deviceId || '')
|
||||
const deviceConstraints = computed<MediaStreamConstraints>(() => ({
|
||||
audio: {
|
||||
...(selectedAudioInput.value ? { deviceId: { exact: selectedAudioInput.value } } : {}),
|
||||
deviceId: { exact: selectedAudioInput.value },
|
||||
autoGainControl: true,
|
||||
echoCancellation: true,
|
||||
noiseSuppression: true,
|
||||
@@ -17,13 +17,12 @@ export function useAudioDevice() {
|
||||
|
||||
watch(audioInputs, () => {
|
||||
if (!selectedAudioInput.value && audioInputs.value.length > 0) {
|
||||
selectedAudioInput.value = audioInputs.value[0]?.deviceId
|
||||
selectedAudioInput.value = audioInputs.value.find(input => input.deviceId === 'default')?.deviceId || audioInputs.value[0].deviceId
|
||||
}
|
||||
})
|
||||
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
devices.ensurePermissions()
|
||||
function askPermission() {
|
||||
return devices.ensurePermissions()
|
||||
.then(() => nextTick())
|
||||
.then(() => {
|
||||
if (audioInputs.value.length > 0 && !selectedAudioInput.value) {
|
||||
@@ -32,15 +31,18 @@ export function useAudioDevice() {
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error ensuring permissions:', error)
|
||||
throw error // Re-throw so callers can handle the error
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
audioInputs,
|
||||
selectedAudioInput,
|
||||
stream,
|
||||
stopStream,
|
||||
startStream,
|
||||
deviceConstraints,
|
||||
|
||||
askPermission,
|
||||
startStream,
|
||||
stopStream,
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from './audio-analyzer'
|
||||
export * from './audio-context'
|
||||
export * from './audio-device'
|
||||
export * from './audio-recorder'
|
||||
export * from './device'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useDevicesList, useUserMedia } from '@vueuse/core'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, nextTick, ref, shallowRef, watch } from 'vue'
|
||||
import { computed, ref, shallowRef } from 'vue'
|
||||
|
||||
function calculateVolumeWithLinearNormalize(analyser: AnalyserNode) {
|
||||
const dataBuffer = new Uint8Array(analyser.frequencyBinCount)
|
||||
@@ -74,45 +73,6 @@ export const useAudioContext = defineStore('audio-context', () => {
|
||||
}
|
||||
})
|
||||
|
||||
export function useAudioDevice(requestPermission: boolean = false) {
|
||||
const devices = useDevicesList({ constraints: { audio: true }, requestPermissions: requestPermission })
|
||||
const audioInputs = computed(() => devices.audioInputs.value)
|
||||
const selectedAudioInput = ref<string>(devices.audioInputs.value.find(device => device.deviceId === 'default')?.deviceId || '')
|
||||
const deviceConstraints = computed<MediaStreamConstraints>(() => ({ audio: { deviceId: { exact: selectedAudioInput.value }, autoGainControl: true, echoCancellation: true, noiseSuppression: true } }))
|
||||
const { stream, stop: stopStream, start: startStream } = useUserMedia({ constraints: deviceConstraints, enabled: false, autoSwitch: true })
|
||||
|
||||
watch(audioInputs, () => {
|
||||
if (!selectedAudioInput.value && audioInputs.value.length > 0) {
|
||||
selectedAudioInput.value = audioInputs.value.find(input => input.deviceId === 'default')?.deviceId || audioInputs.value[0].deviceId
|
||||
}
|
||||
})
|
||||
|
||||
function askPermission() {
|
||||
return devices.ensurePermissions()
|
||||
.then(() => nextTick())
|
||||
.then(() => {
|
||||
if (audioInputs.value.length > 0 && !selectedAudioInput.value) {
|
||||
selectedAudioInput.value = audioInputs.value.find(input => input.deviceId === 'default')?.deviceId || audioInputs.value[0].deviceId
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error ensuring permissions:', error)
|
||||
throw error // Re-throw so callers can handle the error
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
audioInputs,
|
||||
selectedAudioInput,
|
||||
stream,
|
||||
deviceConstraints,
|
||||
|
||||
askPermission,
|
||||
startStream,
|
||||
stopStream,
|
||||
}
|
||||
}
|
||||
|
||||
export const useSpeakingStore = defineStore('character-speaking', () => {
|
||||
const nowSpeakingAvatarBorderOpacityMin = 30
|
||||
const nowSpeakingAvatarBorderOpacityMax = 100
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useLocalStorageManualReset } from '@proj-airi/stage-shared/composables'
|
||||
import { defineStore } from 'pinia'
|
||||
import { onMounted, watch } from 'vue'
|
||||
import { watch } from 'vue'
|
||||
|
||||
import { useAudioDevice } from '../audio'
|
||||
import { useAudioDevice } from '../../composables/audio'
|
||||
|
||||
export const useSettingsAudioDevice = defineStore('settings-audio-devices', () => {
|
||||
const { audioInputs, deviceConstraints, selectedAudioInput: selectedAudioInputNonPersist, startStream, stopStream, stream, askPermission } = useAudioDevice()
|
||||
@@ -23,7 +23,7 @@ export const useSettingsAudioDevice = defineStore('settings-audio-devices', () =
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
function initialize() {
|
||||
const hasSelectedInput = selectedAudioInputPersist.value
|
||||
&& audioInputs.value.some(device => device.deviceId === selectedAudioInputPersist.value)
|
||||
|
||||
@@ -33,7 +33,7 @@ export const useSettingsAudioDevice = defineStore('settings-audio-devices', () =
|
||||
if (selectedAudioInputNonPersist.value && !selectedAudioInputEnabledPersist.value) {
|
||||
selectedAudioInputPersist.value = selectedAudioInputNonPersist.value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function resetState() {
|
||||
selectedAudioInputPersist.reset()
|
||||
@@ -50,6 +50,8 @@ export const useSettingsAudioDevice = defineStore('settings-audio-devices', () =
|
||||
|
||||
stream,
|
||||
|
||||
initialize,
|
||||
|
||||
askPermission,
|
||||
startStream,
|
||||
stopStream,
|
||||
|
||||
Reference in New Issue
Block a user