mirror of https://github.com/jetkvm/kvm.git
Compare commits
2 Commits
2f2f45ddf0
...
db620b70d7
| Author | SHA1 | Date |
|---|---|---|
|
|
db620b70d7 | |
|
|
f51c372183 |
80
audio.go
80
audio.go
|
|
@ -14,7 +14,7 @@ import (
|
||||||
var (
|
var (
|
||||||
audioMutex sync.Mutex
|
audioMutex sync.Mutex
|
||||||
outputSource audio.AudioSource
|
outputSource audio.AudioSource
|
||||||
inputSource audio.AudioSource
|
inputSource atomic.Pointer[audio.AudioSource]
|
||||||
outputRelay *audio.OutputRelay
|
outputRelay *audio.OutputRelay
|
||||||
inputRelay *audio.InputRelay
|
inputRelay *audio.InputRelay
|
||||||
audioInitialized bool
|
audioInitialized bool
|
||||||
|
|
@ -63,13 +63,14 @@ func startAudio() error {
|
||||||
|
|
||||||
// Start input audio if not running, USB audio enabled, and input enabled
|
// Start input audio if not running, USB audio enabled, and input enabled
|
||||||
ensureConfigLoaded()
|
ensureConfigLoaded()
|
||||||
if inputSource == nil && audioInputEnabled.Load() && config.UsbDevices != nil && config.UsbDevices.Audio {
|
if inputSource.Load() == nil && audioInputEnabled.Load() && config.UsbDevices != nil && config.UsbDevices.Audio {
|
||||||
alsaPlaybackDevice := "hw:1,0" // USB speakers
|
alsaPlaybackDevice := "hw:1,0" // USB speakers
|
||||||
|
|
||||||
// Create CGO audio source
|
// Create CGO audio source
|
||||||
inputSource = audio.NewCgoInputSource(alsaPlaybackDevice)
|
source := audio.NewCgoInputSource(alsaPlaybackDevice)
|
||||||
|
inputSource.Store(&source)
|
||||||
|
|
||||||
inputRelay = audio.NewInputRelay(inputSource)
|
inputRelay = audio.NewInputRelay(source)
|
||||||
if err := inputRelay.Start(); err != nil {
|
if err := inputRelay.Start(); err != nil {
|
||||||
audioLogger.Error().Err(err).Msg("Failed to start input relay")
|
audioLogger.Error().Err(err).Msg("Failed to start input relay")
|
||||||
}
|
}
|
||||||
|
|
@ -78,33 +79,48 @@ func startAudio() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopAudio() {
|
// stopOutputAudio stops output audio (device → browser)
|
||||||
|
func stopOutputAudio() {
|
||||||
audioMutex.Lock()
|
audioMutex.Lock()
|
||||||
outRelay := outputRelay
|
outRelay := outputRelay
|
||||||
outSource := outputSource
|
outSource := outputSource
|
||||||
inRelay := inputRelay
|
|
||||||
inSource := inputSource
|
|
||||||
outputRelay = nil
|
outputRelay = nil
|
||||||
outputSource = nil
|
outputSource = nil
|
||||||
inputRelay = nil
|
|
||||||
inputSource = nil
|
|
||||||
audioMutex.Unlock()
|
audioMutex.Unlock()
|
||||||
|
|
||||||
// Disconnect outside mutex to avoid blocking new sessions during CGO calls
|
// Disconnect outside mutex to avoid blocking during CGO calls
|
||||||
if outRelay != nil {
|
if outRelay != nil {
|
||||||
outRelay.Stop()
|
outRelay.Stop()
|
||||||
}
|
}
|
||||||
if outSource != nil {
|
if outSource != nil {
|
||||||
outSource.Disconnect()
|
outSource.Disconnect()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stopInputAudio stops input audio (browser → device)
|
||||||
|
func stopInputAudio() {
|
||||||
|
audioMutex.Lock()
|
||||||
|
inRelay := inputRelay
|
||||||
|
inputRelay = nil
|
||||||
|
audioMutex.Unlock()
|
||||||
|
|
||||||
|
// Atomically swap and disconnect outside mutex
|
||||||
|
inSource := inputSource.Swap(nil)
|
||||||
|
|
||||||
|
// Disconnect outside mutex to avoid blocking during CGO calls
|
||||||
if inRelay != nil {
|
if inRelay != nil {
|
||||||
inRelay.Stop()
|
inRelay.Stop()
|
||||||
}
|
}
|
||||||
if inSource != nil {
|
if inSource != nil {
|
||||||
inSource.Disconnect()
|
(*inSource).Disconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stopAudio() {
|
||||||
|
stopOutputAudio()
|
||||||
|
stopInputAudio()
|
||||||
|
}
|
||||||
|
|
||||||
func onWebRTCConnect() {
|
func onWebRTCConnect() {
|
||||||
count := activeConnections.Add(1)
|
count := activeConnections.Add(1)
|
||||||
if count == 1 {
|
if count == 1 {
|
||||||
|
|
@ -158,19 +174,7 @@ func SetAudioOutputEnabled(enabled bool) error {
|
||||||
return startAudio()
|
return startAudio()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
audioMutex.Lock()
|
stopOutputAudio()
|
||||||
outRelay := outputRelay
|
|
||||||
outSource := outputSource
|
|
||||||
outputRelay = nil
|
|
||||||
outputSource = nil
|
|
||||||
audioMutex.Unlock()
|
|
||||||
|
|
||||||
if outRelay != nil {
|
|
||||||
outRelay.Stop()
|
|
||||||
}
|
|
||||||
if outSource != nil {
|
|
||||||
outSource.Disconnect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -187,19 +191,7 @@ func SetAudioInputEnabled(enabled bool) error {
|
||||||
return startAudio()
|
return startAudio()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
audioMutex.Lock()
|
stopInputAudio()
|
||||||
inRelay := inputRelay
|
|
||||||
inSource := inputSource
|
|
||||||
inputRelay = nil
|
|
||||||
inputSource = nil
|
|
||||||
audioMutex.Unlock()
|
|
||||||
|
|
||||||
if inRelay != nil {
|
|
||||||
inRelay.Stop()
|
|
||||||
}
|
|
||||||
if inSource != nil {
|
|
||||||
inSource.Disconnect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -248,23 +240,21 @@ func handleInputTrackForSession(track *webrtc.TrackRemote) {
|
||||||
continue // Drop frame but keep reading
|
continue // Drop frame but keep reading
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get source in single mutex operation (hot path optimization)
|
// Lock-free source access (hot path optimization)
|
||||||
audioMutex.Lock()
|
source := inputSource.Load()
|
||||||
source := inputSource
|
|
||||||
audioMutex.Unlock()
|
|
||||||
|
|
||||||
if source == nil {
|
if source == nil {
|
||||||
continue // No relay, drop frame but keep reading
|
continue // No relay, drop frame but keep reading
|
||||||
}
|
}
|
||||||
|
|
||||||
if !source.IsConnected() {
|
if !(*source).IsConnected() {
|
||||||
if err := source.Connect(); err != nil {
|
if err := (*source).Connect(); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := source.WriteMessage(0, opusData); err != nil {
|
if err := (*source).WriteMessage(0, opusData); err != nil {
|
||||||
source.Disconnect()
|
(*source).Disconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue