mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-28 10:31:20 -08:00
refactor(mediabunny): [PKG-MB-06] own audio clocks, buffers and context lifecycle
This commit is contained in:
1 parent
9d037dcbf9
commit
ccee9157a7
30 files changed
+16182
-736
No files matched your search
@@ -0,0 +1,92 @@
|
||||
interface ContextHost {
|
||||
audioContext: AudioContext | null
|
||||
gainNode: GainNode | null
|
||||
volume: number
|
||||
muted: boolean
|
||||
}
|
||||
|
||||
export default class ContextOwner {
|
||||
private closed = false
|
||||
private resumes = new WeakMap<AudioContext, Promise<void>>()
|
||||
|
||||
constructor(private host: ContextHost) {}
|
||||
|
||||
ensure(sampleRate?: number): AudioContext | null {
|
||||
if (this.closed)
|
||||
return null
|
||||
if (this.host.audioContext)
|
||||
return this.host.audioContext
|
||||
const Context = window.AudioContext || (window as Window & { webkitAudioContext?: typeof AudioContext }).webkitAudioContext
|
||||
let context: AudioContext
|
||||
try {
|
||||
context = new Context({ sampleRate })
|
||||
}
|
||||
catch {
|
||||
context = new Context()
|
||||
}
|
||||
if (this.closed) {
|
||||
void context.close().catch(error => console.warn('MediaBunny obsolete context cleanup:', error))
|
||||
return null
|
||||
}
|
||||
let gain: GainNode | null = null
|
||||
try {
|
||||
gain = context.createGain()
|
||||
gain.connect(context.destination)
|
||||
const volume = this.host.muted ? 0 : this.host.volume
|
||||
gain.gain.value = volume * volume
|
||||
if (this.closed) {
|
||||
gain.disconnect()
|
||||
void context.close().catch(error => console.warn('MediaBunny obsolete context cleanup:', error))
|
||||
return null
|
||||
}
|
||||
this.host.audioContext = context
|
||||
this.host.gainNode = gain
|
||||
return context
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
gain?.disconnect()
|
||||
}
|
||||
catch (failure) { console.warn('MediaBunny gain setup cleanup:', failure) }
|
||||
void context.close().catch(failure => console.warn('MediaBunny context setup cleanup:', failure))
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
updateGain(): void {
|
||||
if (!this.host.gainNode)
|
||||
return
|
||||
const volume = this.host.muted ? 0 : this.host.volume
|
||||
this.host.gainNode.gain.value = volume * volume
|
||||
}
|
||||
|
||||
resume(context: AudioContext): Promise<void> {
|
||||
const previous = this.resumes.get(context)
|
||||
if (previous)
|
||||
return previous
|
||||
const pending = context.resume()
|
||||
this.resumes.set(context, pending)
|
||||
const clear = () => {
|
||||
if (this.resumes.get(context) === pending)
|
||||
this.resumes.delete(context)
|
||||
}
|
||||
pending.then(clear, clear)
|
||||
return pending
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
if (this.closed)
|
||||
return
|
||||
this.closed = true
|
||||
const { audioContext: context, gainNode: gain } = this.host
|
||||
this.host.audioContext = null
|
||||
this.host.gainNode = null
|
||||
try {
|
||||
gain?.disconnect()
|
||||
}
|
||||
finally {
|
||||
if (context)
|
||||
void context.close().catch(error => console.warn('MediaBunny context close error:', error))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user