kvm/audio_handlers.go

151 lines
4.9 KiB
Go

package kvm
import (
"context"
"github.com/coder/websocket"
"github.com/jetkvm/kvm/internal/audio"
"github.com/pion/webrtc/v4"
"github.com/rs/zerolog"
)
var audioControlService *audio.AudioControlService
func ensureAudioControlService() *audio.AudioControlService {
if audioControlService == nil {
sessionProvider := &SessionProviderImpl{}
audioControlService = audio.NewAudioControlService(sessionProvider, logger)
// Set up callback for audio relay to get current session's audio track
audio.SetCurrentSessionCallback(func() audio.AudioTrackWriter {
return GetCurrentSessionAudioTrack()
})
// Set up callback for audio relay to replace WebRTC audio track
audio.SetTrackReplacementCallback(func(newTrack audio.AudioTrackWriter) error {
if track, ok := newTrack.(*webrtc.TrackLocalStaticSample); ok {
return ReplaceCurrentSessionAudioTrack(track)
}
return nil
})
// Set up RPC callback functions for the audio package
audio.SetRPCCallbacks(
func() *audio.AudioControlService { return audioControlService },
func() audio.AudioConfig { return audioControlService.GetCurrentAudioQuality() },
func(quality audio.AudioQuality) error {
audioControlService.SetAudioQuality(quality)
return nil
},
)
}
return audioControlService
}
// --- Global Convenience Functions for Audio Control ---
// MuteAudioOutput is a global helper to mute audio output
func MuteAudioOutput() error {
return ensureAudioControlService().MuteAudio(true)
}
// UnmuteAudioOutput is a global helper to unmute audio output
func UnmuteAudioOutput() error {
return ensureAudioControlService().MuteAudio(false)
}
// StopMicrophone is a global helper to stop microphone subprocess
func StopMicrophone() error {
return ensureAudioControlService().StopMicrophone()
}
// StartMicrophone is a global helper to start microphone subprocess
func StartMicrophone() error {
return ensureAudioControlService().StartMicrophone()
}
// IsAudioOutputActive is a global helper to check if audio output subprocess is running
func IsAudioOutputActive() bool {
return ensureAudioControlService().IsAudioOutputActive()
}
// IsMicrophoneActive is a global helper to check if microphone subprocess is running
func IsMicrophoneActive() bool {
return ensureAudioControlService().IsMicrophoneActive()
}
// ResetMicrophone is a global helper to reset the microphone
func ResetMicrophone() error {
return ensureAudioControlService().ResetMicrophone()
}
// GetCurrentSessionAudioTrack returns the current session's audio track for audio relay
func GetCurrentSessionAudioTrack() *webrtc.TrackLocalStaticSample {
if currentSession != nil {
return currentSession.AudioTrack
}
return nil
}
// ConnectRelayToCurrentSession connects the audio relay to the current WebRTC session
func ConnectRelayToCurrentSession() error {
if currentTrack := GetCurrentSessionAudioTrack(); currentTrack != nil {
err := audio.UpdateAudioRelayTrack(currentTrack)
if err != nil {
logger.Error().Err(err).Msg("failed to connect current session's audio track to relay")
return err
}
logger.Info().Msg("connected current session's audio track to relay")
return nil
}
logger.Warn().Msg("no current session audio track found")
return nil
}
// ReplaceCurrentSessionAudioTrack replaces the audio track in the current WebRTC session
func ReplaceCurrentSessionAudioTrack(newTrack *webrtc.TrackLocalStaticSample) error {
if currentSession == nil {
return nil // No session to update
}
err := currentSession.ReplaceAudioTrack(newTrack)
if err != nil {
logger.Error().Err(err).Msg("failed to replace audio track in current session")
return err
}
logger.Info().Msg("successfully replaced audio track in current session")
return nil
}
// SetAudioQuality is a global helper to set audio output quality
func SetAudioQuality(quality audio.AudioQuality) error {
ensureAudioControlService()
audioControlService.SetAudioQuality(quality)
return nil
}
// GetAudioQualityPresets is a global helper to get available audio quality presets
func GetAudioQualityPresets() map[audio.AudioQuality]audio.AudioConfig {
ensureAudioControlService()
return audioControlService.GetAudioQualityPresets()
}
// GetCurrentAudioQuality is a global helper to get current audio quality configuration
func GetCurrentAudioQuality() audio.AudioConfig {
ensureAudioControlService()
return audioControlService.GetCurrentAudioQuality()
}
// handleSubscribeAudioEvents handles WebSocket audio event subscription
func handleSubscribeAudioEvents(connectionID string, wsCon *websocket.Conn, runCtx context.Context, l *zerolog.Logger) {
ensureAudioControlService()
audioControlService.SubscribeToAudioEvents(connectionID, wsCon, runCtx, l)
}
// handleUnsubscribeAudioEvents handles WebSocket audio event unsubscription
func handleUnsubscribeAudioEvents(connectionID string, l *zerolog.Logger) {
ensureAudioControlService()
audioControlService.UnsubscribeFromAudioEvents(connectionID, l)
}