mirror of https://github.com/jetkvm/kvm.git
116 lines
3.2 KiB
Go
116 lines
3.2 KiB
Go
package audio
|
|
|
|
import (
|
|
"sync/atomic"
|
|
"unsafe"
|
|
)
|
|
|
|
var (
|
|
// Use unsafe.Pointer for atomic operations instead of mutex
|
|
globalNonBlockingManager unsafe.Pointer // *NonBlockingAudioManager
|
|
)
|
|
|
|
// loadManager atomically loads the global manager
|
|
func loadManager() *NonBlockingAudioManager {
|
|
ptr := atomic.LoadPointer(&globalNonBlockingManager)
|
|
if ptr == nil {
|
|
return nil
|
|
}
|
|
return (*NonBlockingAudioManager)(ptr)
|
|
}
|
|
|
|
// storeManager atomically stores the global manager
|
|
func storeManager(manager *NonBlockingAudioManager) {
|
|
atomic.StorePointer(&globalNonBlockingManager, unsafe.Pointer(manager))
|
|
}
|
|
|
|
// compareAndSwapManager atomically compares and swaps the global manager
|
|
func compareAndSwapManager(old, new *NonBlockingAudioManager) bool {
|
|
return atomic.CompareAndSwapPointer(&globalNonBlockingManager,
|
|
unsafe.Pointer(old), unsafe.Pointer(new))
|
|
}
|
|
|
|
// StartNonBlockingAudioStreaming starts the non-blocking audio streaming system
|
|
func StartNonBlockingAudioStreaming(send func([]byte)) error {
|
|
manager := loadManager()
|
|
if manager != nil && manager.IsOutputRunning() {
|
|
return nil // Already running, this is not an error
|
|
}
|
|
|
|
if manager == nil {
|
|
newManager := NewNonBlockingAudioManager()
|
|
if !compareAndSwapManager(nil, newManager) {
|
|
// Another goroutine created manager, use it
|
|
manager = loadManager()
|
|
} else {
|
|
manager = newManager
|
|
}
|
|
}
|
|
|
|
return manager.StartAudioOutput(send)
|
|
}
|
|
|
|
// StartNonBlockingAudioInput starts the non-blocking audio input system
|
|
func StartNonBlockingAudioInput(receiveChan <-chan []byte) error {
|
|
manager := loadManager()
|
|
if manager == nil {
|
|
newManager := NewNonBlockingAudioManager()
|
|
if !compareAndSwapManager(nil, newManager) {
|
|
// Another goroutine created manager, use it
|
|
manager = loadManager()
|
|
} else {
|
|
manager = newManager
|
|
}
|
|
}
|
|
|
|
// Check if input is already running to avoid unnecessary operations
|
|
if manager.IsInputRunning() {
|
|
return nil // Already running, this is not an error
|
|
}
|
|
|
|
return manager.StartAudioInput(receiveChan)
|
|
}
|
|
|
|
// StopNonBlockingAudioStreaming stops the non-blocking audio streaming system
|
|
func StopNonBlockingAudioStreaming() {
|
|
manager := loadManager()
|
|
if manager != nil {
|
|
manager.Stop()
|
|
storeManager(nil)
|
|
}
|
|
}
|
|
|
|
// StopNonBlockingAudioInput stops only the audio input without affecting output
|
|
func StopNonBlockingAudioInput() {
|
|
manager := loadManager()
|
|
if manager != nil && manager.IsInputRunning() {
|
|
manager.StopAudioInput()
|
|
|
|
// If both input and output are stopped, recreate manager to ensure clean state
|
|
if !manager.IsRunning() {
|
|
storeManager(nil)
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetNonBlockingAudioStats returns statistics from the non-blocking audio system
|
|
func GetNonBlockingAudioStats() NonBlockingAudioStats {
|
|
manager := loadManager()
|
|
if manager != nil {
|
|
return manager.GetStats()
|
|
}
|
|
return NonBlockingAudioStats{}
|
|
}
|
|
|
|
// IsNonBlockingAudioRunning returns true if the non-blocking audio system is running
|
|
func IsNonBlockingAudioRunning() bool {
|
|
manager := loadManager()
|
|
return manager != nil && manager.IsRunning()
|
|
}
|
|
|
|
// IsNonBlockingAudioInputRunning returns true if the non-blocking audio input is running
|
|
func IsNonBlockingAudioInputRunning() bool {
|
|
manager := loadManager()
|
|
return manager != nil && manager.IsInputRunning()
|
|
}
|