Initial commit
This commit is contained in:
225
stores/audio.ts
Normal file
225
stores/audio.ts
Normal file
@@ -0,0 +1,225 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import type { Logger } from 'pino'
|
||||
|
||||
interface State {
|
||||
audioContext: AudioContext | null,
|
||||
masterGainNoise: GainNode | null,
|
||||
masterGainMusic: GainNode | null,
|
||||
audioSink: typeof Audio | null,
|
||||
showOverlay: boolean,
|
||||
monitoringInterval: NodeJS.Timeout | null,
|
||||
playing: boolean,
|
||||
scene: string,
|
||||
state: string | null,
|
||||
volume: number,
|
||||
noiseVolume: number
|
||||
}
|
||||
|
||||
function createOverlay (audioContext: AudioContext) {
|
||||
const logger = useNuxtApp().$logger as Logger
|
||||
logger.info('Create Overlay')
|
||||
const overlay = document.createElement('div')
|
||||
overlay.className = 'overlay'
|
||||
|
||||
// Erstelle den Button
|
||||
const button = document.createElement('button')
|
||||
button.className = 'btn btn-primary btn-lg'
|
||||
button.style.backgroundColor = '#e9c046'
|
||||
button.style.border = 'none'
|
||||
button.style.color = 'black'
|
||||
button.innerText = 'Ready'
|
||||
|
||||
// Füge Event-Listener hinzu, um den AudioContext zu entsperren
|
||||
button.addEventListener('click', async () => {
|
||||
try {
|
||||
await audioContext.resume()
|
||||
logger.info('AudioContext resumed.')
|
||||
overlay.remove() // Entferne das Overlay nach der Interaktion
|
||||
} catch (error) {
|
||||
useAudioStore().resetAudioContext()
|
||||
useAudioStore().initializeAudioContext()
|
||||
logger.error('Error resuming AudioContext:', error)
|
||||
}
|
||||
})
|
||||
|
||||
// Füge Button dem Overlay hinzu
|
||||
overlay.appendChild(button)
|
||||
|
||||
// Füge Overlay zum DOM hinzu
|
||||
document.body.appendChild(overlay)
|
||||
}
|
||||
|
||||
export const useAudioStore = defineStore('audio', {
|
||||
state: (): State => ({
|
||||
audioContext: null as AudioContext | null,
|
||||
masterGainNoise: null as GainNode | null,
|
||||
masterGainMusic: null as GainNode | null,
|
||||
audioSink: null as typeof Audio | null,
|
||||
showOverlay: false,
|
||||
monitoringInterval: null as NodeJS.Timeout | null,
|
||||
playing: false,
|
||||
scene: 'Lagoon',
|
||||
state: null as string | null,
|
||||
volume: parseFloat(localStorage.getItem('volume') || '1'),
|
||||
noiseVolume: parseFloat(localStorage.getItem('noiseVolume') || '1')
|
||||
}),
|
||||
actions: {
|
||||
getNewAudioElement (newTrack: string) {
|
||||
const logger = useNuxtApp().$logger as Logger
|
||||
logger.info(`Current track changed to: ${newTrack}`)
|
||||
return useMediaProvider().getAudioElementForTitle(newTrack)
|
||||
// Additional logic for changing tracks can be added here
|
||||
// For example, you might want to stop the current audio, load the new track, etc.
|
||||
// This depends on how your audio playback is implemented
|
||||
},
|
||||
async ensureAudioContextRunning () {
|
||||
if (!this.audioContext) {
|
||||
this.initializeAudioContext()
|
||||
}
|
||||
if (this.audioContext?.state === 'suspended') {
|
||||
try {
|
||||
await this.audioContext.resume()
|
||||
} catch (error) {
|
||||
const logger = useNuxtApp().$logger as Logger
|
||||
logger.error('Error resuming AudioContext:', error)
|
||||
this.showOverlay = true
|
||||
}
|
||||
}
|
||||
},
|
||||
initializeAudioContext () {
|
||||
const logger = useNuxtApp().$logger as Logger
|
||||
if (!this.audioContext) {
|
||||
this.audioContext = new AudioContext()
|
||||
this.prepareGains(this.audioContext)
|
||||
logger.info('AudioContext initialized and Gains prepared.')
|
||||
// Attach some error handling, to ensure audiocontext is running all the time.
|
||||
this.startAudioContextMonitor()
|
||||
this.addStateMonitor()
|
||||
}
|
||||
},
|
||||
prepareGains(audioContext: AudioContext){
|
||||
this.masterGainNoise = null
|
||||
this.masterGainMusic = null
|
||||
this.masterGainNoise = audioContext.createGain()
|
||||
this.masterGainMusic = audioContext.createGain()
|
||||
this.masterGainNoise.connect(audioContext.destination)
|
||||
this.masterGainMusic.connect(audioContext.destination)
|
||||
},
|
||||
addStateMonitor () {
|
||||
const logger = useNuxtApp().$logger as Logger
|
||||
if (!this.audioContext) {
|
||||
this.initializeAudioContext()
|
||||
return
|
||||
}
|
||||
// Überwache Änderungen im AudioContext-State
|
||||
this.audioContext.onstatechange = () => {
|
||||
const currentState = this.audioContext?.state
|
||||
logger.info('AudioContext state changed:', currentState)
|
||||
if (currentState === 'suspended') {
|
||||
createOverlay(this.getContext())
|
||||
}
|
||||
}
|
||||
// Optional: Überwache Änderungen in den Audioausgabe-Sinks
|
||||
if ('onsinkchange' in this.audioContext) {
|
||||
|
||||
this.audioContext.onsinkchange = () => {
|
||||
logger.info('Audio sink configuration has changed.')
|
||||
// Füge hier zusätzliche Logik hinzu, falls erforderlich
|
||||
}
|
||||
}
|
||||
},
|
||||
getMasterGainNoise (): GainNode {
|
||||
if(this.masterGainNoise) {
|
||||
return this.masterGainNoise
|
||||
} else {
|
||||
const context = this.getContext()
|
||||
this.masterGainNoise = context.createGain()
|
||||
this.masterGainNoise.connect(context.destination)
|
||||
return this.masterGainNoise
|
||||
}
|
||||
|
||||
},
|
||||
getContext (): AudioContext {
|
||||
if (!this.audioContext ) {
|
||||
this.audioContext ||= new AudioContext()
|
||||
}
|
||||
return this.audioContext
|
||||
},
|
||||
async resumeAudioContext () {
|
||||
const logger = useNuxtApp().$logger as Logger
|
||||
if (this.audioContext?.state === 'suspended') {
|
||||
try {
|
||||
await this.audioContext.resume()
|
||||
this.state = this.audioContext.state
|
||||
const state = this.state
|
||||
logger.info('AudioContext resumed. ', { state })
|
||||
this.stopAudioContextMonitor()
|
||||
} catch (error) {
|
||||
logger.error('Error resuming AudioContext:', error)
|
||||
this.resetAudioContext()
|
||||
this.initializeAudioContext()
|
||||
await this.ensureAudioContextRunning()
|
||||
}
|
||||
}
|
||||
},
|
||||
togglePlaying (): void {
|
||||
this.playing = !this.playing
|
||||
},
|
||||
isPlaying (): boolean {
|
||||
return this.playing
|
||||
},
|
||||
setPlaying (stateChange: boolean): void {
|
||||
this.playing = stateChange
|
||||
},
|
||||
setVolume (newVolume: number) {
|
||||
this.volume = newVolume
|
||||
localStorage.setItem('volume', newVolume.toString())
|
||||
},
|
||||
setNoiseVolume (newVolume: number) {
|
||||
this.noiseVolume = newVolume
|
||||
localStorage.setItem('noiseVolume', newVolume.toString())
|
||||
},
|
||||
startAudioContextMonitor () {
|
||||
const logger = useNuxtApp().$logger as Logger
|
||||
// Starte ein Intervall, wenn keines aktiv ist
|
||||
if (!this.monitoringInterval) {
|
||||
this.monitoringInterval = setInterval(() => {
|
||||
if (this.audioContext?.state === 'suspended') {
|
||||
logger.info('AudioContext is suspended. Attempting to resume...')
|
||||
this.audioContext.resume()
|
||||
}
|
||||
}, 500) // Überprüft alle 500ms
|
||||
logger.info('AudioContext monitoring started.')
|
||||
|
||||
}
|
||||
},
|
||||
stopAudioContextMonitor () {
|
||||
const logger = useNuxtApp().$logger as Logger
|
||||
// Stoppe das Intervall, falls es läuft
|
||||
if (this.monitoringInterval) {
|
||||
clearInterval(this.monitoringInterval)
|
||||
this.monitoringInterval = null
|
||||
logger.info('AudioContext monitoring stopped.')
|
||||
}
|
||||
},
|
||||
resetAudioContext () {
|
||||
const logger = useNuxtApp().$logger as Logger
|
||||
if (this.audioContext) {
|
||||
this.audioContext.close()
|
||||
this.audioContext = null
|
||||
logger.info('AudioContext has been closed.')
|
||||
}
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getPlaying: state => state.playing,
|
||||
getVolume: state => state.volume,
|
||||
getNoiseVolume: state => state.noiseVolume
|
||||
}
|
||||
})
|
||||
|
||||
// Provide a method to ensure audio context is running
|
||||
export const ensureAudio = async () => {
|
||||
const audioStore = useAudioStore()
|
||||
await audioStore.ensureAudioContextRunning()
|
||||
}
|
Reference in New Issue
Block a user