mirror of https://github.com/jetkvm/kvm.git
152 lines
4.5 KiB
Go
152 lines
4.5 KiB
Go
//go:build cgo
|
|
|
|
package audio
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
// MetricsRegistry provides a centralized source of truth for all audio metrics
|
|
// This eliminates duplication between session-specific and global managers
|
|
type MetricsRegistry struct {
|
|
mu sync.RWMutex
|
|
audioMetrics AudioMetrics
|
|
audioInputMetrics AudioInputMetrics
|
|
audioConfig AudioConfig
|
|
microphoneConfig AudioConfig
|
|
lastUpdate int64 // Unix timestamp
|
|
}
|
|
|
|
var (
|
|
globalMetricsRegistry *MetricsRegistry
|
|
registryOnce sync.Once
|
|
)
|
|
|
|
// GetMetricsRegistry returns the global metrics registry instance
|
|
func GetMetricsRegistry() *MetricsRegistry {
|
|
registryOnce.Do(func() {
|
|
globalMetricsRegistry = &MetricsRegistry{
|
|
lastUpdate: time.Now().Unix(),
|
|
}
|
|
})
|
|
return globalMetricsRegistry
|
|
}
|
|
|
|
// UpdateAudioMetrics updates the centralized audio output metrics
|
|
func (mr *MetricsRegistry) UpdateAudioMetrics(metrics AudioMetrics) {
|
|
mr.mu.Lock()
|
|
mr.audioMetrics = metrics
|
|
mr.lastUpdate = time.Now().Unix()
|
|
mr.mu.Unlock()
|
|
|
|
// Update Prometheus metrics directly to avoid circular dependency
|
|
UpdateAudioMetrics(convertAudioMetricsToUnified(metrics))
|
|
}
|
|
|
|
// UpdateAudioInputMetrics updates the centralized audio input metrics
|
|
func (mr *MetricsRegistry) UpdateAudioInputMetrics(metrics AudioInputMetrics) {
|
|
mr.mu.Lock()
|
|
mr.audioInputMetrics = metrics
|
|
mr.lastUpdate = time.Now().Unix()
|
|
mr.mu.Unlock()
|
|
|
|
// Update Prometheus metrics directly to avoid circular dependency
|
|
UpdateMicrophoneMetrics(convertAudioInputMetricsToUnified(metrics))
|
|
}
|
|
|
|
// UpdateAudioConfig updates the centralized audio configuration
|
|
func (mr *MetricsRegistry) UpdateAudioConfig(config AudioConfig) {
|
|
mr.mu.Lock()
|
|
mr.audioConfig = config
|
|
mr.lastUpdate = time.Now().Unix()
|
|
mr.mu.Unlock()
|
|
|
|
// Update Prometheus metrics directly
|
|
UpdateAudioConfigMetrics(config)
|
|
}
|
|
|
|
// UpdateMicrophoneConfig updates the centralized microphone configuration
|
|
func (mr *MetricsRegistry) UpdateMicrophoneConfig(config AudioConfig) {
|
|
mr.mu.Lock()
|
|
mr.microphoneConfig = config
|
|
mr.lastUpdate = time.Now().Unix()
|
|
mr.mu.Unlock()
|
|
|
|
// Update Prometheus metrics directly
|
|
UpdateMicrophoneConfigMetrics(config)
|
|
}
|
|
|
|
// GetAudioMetrics returns the current audio output metrics
|
|
func (mr *MetricsRegistry) GetAudioMetrics() AudioMetrics {
|
|
mr.mu.RLock()
|
|
defer mr.mu.RUnlock()
|
|
return mr.audioMetrics
|
|
}
|
|
|
|
// GetAudioInputMetrics returns the current audio input metrics
|
|
func (mr *MetricsRegistry) GetAudioInputMetrics() AudioInputMetrics {
|
|
mr.mu.RLock()
|
|
defer mr.mu.RUnlock()
|
|
return mr.audioInputMetrics
|
|
}
|
|
|
|
// GetAudioConfig returns the current audio configuration
|
|
func (mr *MetricsRegistry) GetAudioConfig() AudioConfig {
|
|
mr.mu.RLock()
|
|
defer mr.mu.RUnlock()
|
|
return mr.audioConfig
|
|
}
|
|
|
|
// GetMicrophoneConfig returns the current microphone configuration
|
|
func (mr *MetricsRegistry) GetMicrophoneConfig() AudioConfig {
|
|
mr.mu.RLock()
|
|
defer mr.mu.RUnlock()
|
|
return mr.microphoneConfig
|
|
}
|
|
|
|
// GetLastUpdate returns the timestamp of the last metrics update
|
|
func (mr *MetricsRegistry) GetLastUpdate() time.Time {
|
|
timestamp := atomic.LoadInt64(&mr.lastUpdate)
|
|
return time.Unix(timestamp, 0)
|
|
}
|
|
|
|
// StartMetricsCollector starts a background goroutine to collect metrics
|
|
func (mr *MetricsRegistry) StartMetricsCollector() {
|
|
go func() {
|
|
ticker := time.NewTicker(1 * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
for range ticker.C {
|
|
// Collect from session-specific manager if available
|
|
if sessionProvider := GetSessionProvider(); sessionProvider != nil && sessionProvider.IsSessionActive() {
|
|
if inputManager := sessionProvider.GetAudioInputManager(); inputManager != nil {
|
|
metrics := inputManager.GetMetrics()
|
|
mr.UpdateAudioInputMetrics(metrics)
|
|
}
|
|
} else {
|
|
// Fallback to global manager if no session is active
|
|
globalManager := getAudioInputManager()
|
|
metrics := globalManager.GetMetrics()
|
|
mr.UpdateAudioInputMetrics(metrics)
|
|
}
|
|
|
|
// Collect audio output metrics directly from global metrics variable to avoid circular dependency
|
|
audioMetrics := AudioMetrics{
|
|
FramesReceived: atomic.LoadInt64(&metrics.FramesReceived),
|
|
FramesDropped: atomic.LoadInt64(&metrics.FramesDropped),
|
|
BytesProcessed: atomic.LoadInt64(&metrics.BytesProcessed),
|
|
ConnectionDrops: atomic.LoadInt64(&metrics.ConnectionDrops),
|
|
LastFrameTime: metrics.LastFrameTime,
|
|
AverageLatency: metrics.AverageLatency,
|
|
}
|
|
mr.UpdateAudioMetrics(audioMetrics)
|
|
|
|
// Collect configuration directly from global variables to avoid circular dependency
|
|
mr.UpdateAudioConfig(currentConfig)
|
|
mr.UpdateMicrophoneConfig(currentMicrophoneConfig)
|
|
}
|
|
}()
|
|
}
|