mirror of https://github.com/jetkvm/kvm.git
410 lines
12 KiB
Go
410 lines
12 KiB
Go
package audio
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
|
)
|
|
|
|
var (
|
|
// Audio output metrics
|
|
audioFramesReceivedTotal = promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "jetkvm_audio_frames_received_total",
|
|
Help: "Total number of audio frames received",
|
|
},
|
|
)
|
|
|
|
audioFramesDroppedTotal = promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "jetkvm_audio_frames_dropped_total",
|
|
Help: "Total number of audio frames dropped",
|
|
},
|
|
)
|
|
|
|
audioBytesProcessedTotal = promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "jetkvm_audio_bytes_processed_total",
|
|
Help: "Total number of audio bytes processed",
|
|
},
|
|
)
|
|
|
|
audioConnectionDropsTotal = promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "jetkvm_audio_connection_drops_total",
|
|
Help: "Total number of audio connection drops",
|
|
},
|
|
)
|
|
|
|
audioAverageLatencySeconds = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_average_latency_seconds",
|
|
Help: "Average audio latency in seconds",
|
|
},
|
|
)
|
|
|
|
audioLastFrameTimestamp = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_last_frame_timestamp_seconds",
|
|
Help: "Timestamp of the last audio frame received",
|
|
},
|
|
)
|
|
|
|
// Microphone input metrics
|
|
microphoneFramesSentTotal = promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "jetkvm_microphone_frames_sent_total",
|
|
Help: "Total number of microphone frames sent",
|
|
},
|
|
)
|
|
|
|
microphoneFramesDroppedTotal = promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "jetkvm_microphone_frames_dropped_total",
|
|
Help: "Total number of microphone frames dropped",
|
|
},
|
|
)
|
|
|
|
microphoneBytesProcessedTotal = promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "jetkvm_microphone_bytes_processed_total",
|
|
Help: "Total number of microphone bytes processed",
|
|
},
|
|
)
|
|
|
|
microphoneConnectionDropsTotal = promauto.NewCounter(
|
|
prometheus.CounterOpts{
|
|
Name: "jetkvm_microphone_connection_drops_total",
|
|
Help: "Total number of microphone connection drops",
|
|
},
|
|
)
|
|
|
|
microphoneAverageLatencySeconds = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_average_latency_seconds",
|
|
Help: "Average microphone latency in seconds",
|
|
},
|
|
)
|
|
|
|
microphoneLastFrameTimestamp = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_last_frame_timestamp_seconds",
|
|
Help: "Timestamp of the last microphone frame sent",
|
|
},
|
|
)
|
|
|
|
// Audio subprocess process metrics
|
|
audioProcessCpuPercent = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_process_cpu_percent",
|
|
Help: "CPU usage percentage of audio output subprocess",
|
|
},
|
|
)
|
|
|
|
audioProcessMemoryPercent = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_process_memory_percent",
|
|
Help: "Memory usage percentage of audio output subprocess",
|
|
},
|
|
)
|
|
|
|
audioProcessMemoryRssBytes = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_process_memory_rss_bytes",
|
|
Help: "RSS memory usage in bytes of audio output subprocess",
|
|
},
|
|
)
|
|
|
|
audioProcessMemoryVmsBytes = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_process_memory_vms_bytes",
|
|
Help: "VMS memory usage in bytes of audio output subprocess",
|
|
},
|
|
)
|
|
|
|
audioProcessRunning = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_process_running",
|
|
Help: "Whether audio output subprocess is running (1=running, 0=stopped)",
|
|
},
|
|
)
|
|
|
|
// Microphone subprocess process metrics
|
|
microphoneProcessCpuPercent = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_process_cpu_percent",
|
|
Help: "CPU usage percentage of microphone input subprocess",
|
|
},
|
|
)
|
|
|
|
microphoneProcessMemoryPercent = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_process_memory_percent",
|
|
Help: "Memory usage percentage of microphone input subprocess",
|
|
},
|
|
)
|
|
|
|
microphoneProcessMemoryRssBytes = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_process_memory_rss_bytes",
|
|
Help: "RSS memory usage in bytes of microphone input subprocess",
|
|
},
|
|
)
|
|
|
|
microphoneProcessMemoryVmsBytes = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_process_memory_vms_bytes",
|
|
Help: "VMS memory usage in bytes of microphone input subprocess",
|
|
},
|
|
)
|
|
|
|
microphoneProcessRunning = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_process_running",
|
|
Help: "Whether microphone input subprocess is running (1=running, 0=stopped)",
|
|
},
|
|
)
|
|
|
|
// Audio configuration metrics
|
|
audioConfigQuality = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_config_quality",
|
|
Help: "Current audio quality setting (0=Low, 1=Medium, 2=High, 3=Ultra)",
|
|
},
|
|
)
|
|
|
|
audioConfigBitrate = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_config_bitrate_kbps",
|
|
Help: "Current audio bitrate in kbps",
|
|
},
|
|
)
|
|
|
|
audioConfigSampleRate = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_config_sample_rate_hz",
|
|
Help: "Current audio sample rate in Hz",
|
|
},
|
|
)
|
|
|
|
audioConfigChannels = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_audio_config_channels",
|
|
Help: "Current audio channel count",
|
|
},
|
|
)
|
|
|
|
microphoneConfigQuality = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_config_quality",
|
|
Help: "Current microphone quality setting (0=Low, 1=Medium, 2=High, 3=Ultra)",
|
|
},
|
|
)
|
|
|
|
microphoneConfigBitrate = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_config_bitrate_kbps",
|
|
Help: "Current microphone bitrate in kbps",
|
|
},
|
|
)
|
|
|
|
microphoneConfigSampleRate = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_config_sample_rate_hz",
|
|
Help: "Current microphone sample rate in Hz",
|
|
},
|
|
)
|
|
|
|
microphoneConfigChannels = promauto.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "jetkvm_microphone_config_channels",
|
|
Help: "Current microphone channel count",
|
|
},
|
|
)
|
|
|
|
// Metrics update tracking
|
|
metricsUpdateMutex sync.RWMutex
|
|
lastMetricsUpdate time.Time
|
|
|
|
// Counter value tracking (since prometheus counters don't have Get() method)
|
|
audioFramesReceivedValue int64
|
|
audioFramesDroppedValue int64
|
|
audioBytesProcessedValue int64
|
|
audioConnectionDropsValue int64
|
|
micFramesSentValue int64
|
|
micFramesDroppedValue int64
|
|
micBytesProcessedValue int64
|
|
micConnectionDropsValue int64
|
|
)
|
|
|
|
// UpdateAudioMetrics updates Prometheus metrics with current audio data
|
|
func UpdateAudioMetrics(metrics AudioMetrics) {
|
|
metricsUpdateMutex.Lock()
|
|
defer metricsUpdateMutex.Unlock()
|
|
|
|
// Update counters with delta values
|
|
if metrics.FramesReceived > audioFramesReceivedValue {
|
|
audioFramesReceivedTotal.Add(float64(metrics.FramesReceived - audioFramesReceivedValue))
|
|
audioFramesReceivedValue = metrics.FramesReceived
|
|
}
|
|
|
|
if metrics.FramesDropped > audioFramesDroppedValue {
|
|
audioFramesDroppedTotal.Add(float64(metrics.FramesDropped - audioFramesDroppedValue))
|
|
audioFramesDroppedValue = metrics.FramesDropped
|
|
}
|
|
|
|
if metrics.BytesProcessed > audioBytesProcessedValue {
|
|
audioBytesProcessedTotal.Add(float64(metrics.BytesProcessed - audioBytesProcessedValue))
|
|
audioBytesProcessedValue = metrics.BytesProcessed
|
|
}
|
|
|
|
if metrics.ConnectionDrops > audioConnectionDropsValue {
|
|
audioConnectionDropsTotal.Add(float64(metrics.ConnectionDrops - audioConnectionDropsValue))
|
|
audioConnectionDropsValue = metrics.ConnectionDrops
|
|
}
|
|
|
|
// Update gauges
|
|
audioAverageLatencySeconds.Set(float64(metrics.AverageLatency.Nanoseconds()) / 1e9)
|
|
if !metrics.LastFrameTime.IsZero() {
|
|
audioLastFrameTimestamp.Set(float64(metrics.LastFrameTime.Unix()))
|
|
}
|
|
|
|
lastMetricsUpdate = time.Now()
|
|
}
|
|
|
|
// UpdateMicrophoneMetrics updates Prometheus metrics with current microphone data
|
|
func UpdateMicrophoneMetrics(metrics AudioInputMetrics) {
|
|
metricsUpdateMutex.Lock()
|
|
defer metricsUpdateMutex.Unlock()
|
|
|
|
// Update counters with delta values
|
|
if metrics.FramesSent > micFramesSentValue {
|
|
microphoneFramesSentTotal.Add(float64(metrics.FramesSent - micFramesSentValue))
|
|
micFramesSentValue = metrics.FramesSent
|
|
}
|
|
|
|
if metrics.FramesDropped > micFramesDroppedValue {
|
|
microphoneFramesDroppedTotal.Add(float64(metrics.FramesDropped - micFramesDroppedValue))
|
|
micFramesDroppedValue = metrics.FramesDropped
|
|
}
|
|
|
|
if metrics.BytesProcessed > micBytesProcessedValue {
|
|
microphoneBytesProcessedTotal.Add(float64(metrics.BytesProcessed - micBytesProcessedValue))
|
|
micBytesProcessedValue = metrics.BytesProcessed
|
|
}
|
|
|
|
if metrics.ConnectionDrops > micConnectionDropsValue {
|
|
microphoneConnectionDropsTotal.Add(float64(metrics.ConnectionDrops - micConnectionDropsValue))
|
|
micConnectionDropsValue = metrics.ConnectionDrops
|
|
}
|
|
|
|
// Update gauges
|
|
microphoneAverageLatencySeconds.Set(float64(metrics.AverageLatency.Nanoseconds()) / 1e9)
|
|
if !metrics.LastFrameTime.IsZero() {
|
|
microphoneLastFrameTimestamp.Set(float64(metrics.LastFrameTime.Unix()))
|
|
}
|
|
|
|
lastMetricsUpdate = time.Now()
|
|
}
|
|
|
|
// UpdateAudioProcessMetrics updates Prometheus metrics with audio subprocess data
|
|
func UpdateAudioProcessMetrics(metrics ProcessMetrics, isRunning bool) {
|
|
metricsUpdateMutex.Lock()
|
|
defer metricsUpdateMutex.Unlock()
|
|
|
|
audioProcessCpuPercent.Set(metrics.CPUPercent)
|
|
audioProcessMemoryPercent.Set(metrics.MemoryPercent)
|
|
audioProcessMemoryRssBytes.Set(float64(metrics.MemoryRSS))
|
|
audioProcessMemoryVmsBytes.Set(float64(metrics.MemoryVMS))
|
|
if isRunning {
|
|
audioProcessRunning.Set(1)
|
|
} else {
|
|
audioProcessRunning.Set(0)
|
|
}
|
|
|
|
lastMetricsUpdate = time.Now()
|
|
}
|
|
|
|
// UpdateMicrophoneProcessMetrics updates Prometheus metrics with microphone subprocess data
|
|
func UpdateMicrophoneProcessMetrics(metrics ProcessMetrics, isRunning bool) {
|
|
metricsUpdateMutex.Lock()
|
|
defer metricsUpdateMutex.Unlock()
|
|
|
|
microphoneProcessCpuPercent.Set(metrics.CPUPercent)
|
|
microphoneProcessMemoryPercent.Set(metrics.MemoryPercent)
|
|
microphoneProcessMemoryRssBytes.Set(float64(metrics.MemoryRSS))
|
|
microphoneProcessMemoryVmsBytes.Set(float64(metrics.MemoryVMS))
|
|
if isRunning {
|
|
microphoneProcessRunning.Set(1)
|
|
} else {
|
|
microphoneProcessRunning.Set(0)
|
|
}
|
|
|
|
lastMetricsUpdate = time.Now()
|
|
}
|
|
|
|
// UpdateAudioConfigMetrics updates Prometheus metrics with audio configuration
|
|
func UpdateAudioConfigMetrics(config AudioConfig) {
|
|
metricsUpdateMutex.Lock()
|
|
defer metricsUpdateMutex.Unlock()
|
|
|
|
audioConfigQuality.Set(float64(config.Quality))
|
|
audioConfigBitrate.Set(float64(config.Bitrate))
|
|
audioConfigSampleRate.Set(float64(config.SampleRate))
|
|
audioConfigChannels.Set(float64(config.Channels))
|
|
|
|
lastMetricsUpdate = time.Now()
|
|
}
|
|
|
|
// UpdateMicrophoneConfigMetrics updates Prometheus metrics with microphone configuration
|
|
func UpdateMicrophoneConfigMetrics(config AudioConfig) {
|
|
metricsUpdateMutex.Lock()
|
|
defer metricsUpdateMutex.Unlock()
|
|
|
|
microphoneConfigQuality.Set(float64(config.Quality))
|
|
microphoneConfigBitrate.Set(float64(config.Bitrate))
|
|
microphoneConfigSampleRate.Set(float64(config.SampleRate))
|
|
microphoneConfigChannels.Set(float64(config.Channels))
|
|
|
|
lastMetricsUpdate = time.Now()
|
|
}
|
|
|
|
// GetLastMetricsUpdate returns the timestamp of the last metrics update
|
|
func GetLastMetricsUpdate() time.Time {
|
|
metricsUpdateMutex.RLock()
|
|
defer metricsUpdateMutex.RUnlock()
|
|
return lastMetricsUpdate
|
|
}
|
|
|
|
// StartMetricsUpdater starts a goroutine that periodically updates Prometheus metrics
|
|
func StartMetricsUpdater() {
|
|
go func() {
|
|
ticker := time.NewTicker(5 * time.Second) // Update every 5 seconds
|
|
defer ticker.Stop()
|
|
|
|
for range ticker.C {
|
|
// Update audio output metrics
|
|
audioMetrics := GetAudioMetrics()
|
|
UpdateAudioMetrics(audioMetrics)
|
|
|
|
// Update microphone input metrics
|
|
micMetrics := GetAudioInputMetrics()
|
|
UpdateMicrophoneMetrics(micMetrics)
|
|
|
|
// Update microphone subprocess process metrics
|
|
if inputSupervisor := GetAudioInputIPCSupervisor(); inputSupervisor != nil {
|
|
if processMetrics := inputSupervisor.GetProcessMetrics(); processMetrics != nil {
|
|
UpdateMicrophoneProcessMetrics(*processMetrics, inputSupervisor.IsRunning())
|
|
}
|
|
}
|
|
|
|
// Update audio configuration metrics
|
|
audioConfig := GetAudioConfig()
|
|
UpdateAudioConfigMetrics(audioConfig)
|
|
micConfig := GetMicrophoneConfig()
|
|
UpdateMicrophoneConfigMetrics(micConfig)
|
|
}
|
|
}()
|
|
} |