mirror of
https://github.com/jetkvm/kvm.git
synced 2025-09-16 08:38:14 +00:00
Introduce MetricsRegistry to serve as single source of truth for audio metrics Remove duplicate metrics collection logic from web endpoints Add callback mechanism for metrics updates
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)
|
|
}
|
|
}()
|
|
}
|