diff --git a/input_rpc_test.go b/input_rpc_test.go deleted file mode 100644 index bab7209d..00000000 --- a/input_rpc_test.go +++ /dev/null @@ -1,560 +0,0 @@ -package kvm - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -// Test validateFloat64Param function -func TestValidateFloat64Param(t *testing.T) { - tests := []struct { - name string - params map[string]interface{} - paramName string - methodName string - min float64 - max float64 - expected float64 - expectError bool - }{ - { - name: "valid parameter", - params: map[string]interface{}{"test": 50.0}, - paramName: "test", - methodName: "testMethod", - min: 0, - max: 100, - expected: 50.0, - expectError: false, - }, - { - name: "parameter at minimum boundary", - params: map[string]interface{}{"test": 0.0}, - paramName: "test", - methodName: "testMethod", - min: 0, - max: 100, - expected: 0.0, - expectError: false, - }, - { - name: "parameter at maximum boundary", - params: map[string]interface{}{"test": 100.0}, - paramName: "test", - methodName: "testMethod", - min: 0, - max: 100, - expected: 100.0, - expectError: false, - }, - { - name: "parameter below minimum", - params: map[string]interface{}{"test": -1.0}, - paramName: "test", - methodName: "testMethod", - min: 0, - max: 100, - expected: 0, - expectError: true, - }, - { - name: "parameter above maximum", - params: map[string]interface{}{"test": 101.0}, - paramName: "test", - methodName: "testMethod", - min: 0, - max: 100, - expected: 0, - expectError: true, - }, - { - name: "wrong parameter type", - params: map[string]interface{}{"test": "not a number"}, - paramName: "test", - methodName: "testMethod", - min: 0, - max: 100, - expected: 0, - expectError: true, - }, - { - name: "missing parameter", - params: map[string]interface{}{}, - paramName: "test", - methodName: "testMethod", - min: 0, - max: 100, - expected: 0, - expectError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result, err := validateFloat64Param(tt.params, tt.paramName, tt.methodName, tt.min, tt.max) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, tt.expected, result) - } - }) - } -} - -// Test validateKeysArray function -func TestValidateKeysArray(t *testing.T) { - tests := []struct { - name string - params map[string]interface{} - methodName string - expected []uint8 - expectError bool - }{ - { - name: "valid keys array", - params: map[string]interface{}{"keys": []interface{}{65.0, 66.0, 67.0}}, - methodName: "testMethod", - expected: []uint8{65, 66, 67}, - expectError: false, - }, - { - name: "empty keys array", - params: map[string]interface{}{"keys": []interface{}{}}, - methodName: "testMethod", - expected: []uint8{}, - expectError: false, - }, - { - name: "maximum keys array", - params: map[string]interface{}{"keys": []interface{}{1.0, 2.0, 3.0, 4.0, 5.0, 6.0}}, - methodName: "testMethod", - expected: []uint8{1, 2, 3, 4, 5, 6}, - expectError: false, - }, - { - name: "too many keys", - params: map[string]interface{}{"keys": []interface{}{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}}, - methodName: "testMethod", - expected: nil, - expectError: true, - }, - { - name: "invalid key type", - params: map[string]interface{}{"keys": []interface{}{"not a number"}}, - methodName: "testMethod", - expected: nil, - expectError: true, - }, - { - name: "key value out of range (negative)", - params: map[string]interface{}{"keys": []interface{}{-1.0}}, - methodName: "testMethod", - expected: nil, - expectError: true, - }, - { - name: "key value out of range (too high)", - params: map[string]interface{}{"keys": []interface{}{256.0}}, - methodName: "testMethod", - expected: nil, - expectError: true, - }, - { - name: "wrong parameter type", - params: map[string]interface{}{"keys": "not an array"}, - methodName: "testMethod", - expected: nil, - expectError: true, - }, - { - name: "missing keys parameter", - params: map[string]interface{}{}, - methodName: "testMethod", - expected: nil, - expectError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result, err := validateKeysArray(tt.params, tt.methodName) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, tt.expected, result) - } - }) - } -} - -// Test handleKeyboardReportDirect function -func TestHandleKeyboardReportDirect(t *testing.T) { - tests := []struct { - name string - params map[string]interface{} - expectError bool - }{ - { - name: "valid keyboard report", - params: map[string]interface{}{ - "modifier": 2.0, // Shift key - "keys": []interface{}{65.0, 66.0}, // A, B keys - }, - expectError: false, - }, - { - name: "empty keys array", - params: map[string]interface{}{ - "modifier": 0.0, - "keys": []interface{}{}, - }, - expectError: false, - }, - { - name: "invalid modifier", - params: map[string]interface{}{ - "modifier": 256.0, // Out of range - "keys": []interface{}{65.0}, - }, - expectError: true, - }, - { - name: "invalid keys", - params: map[string]interface{}{ - "modifier": 0.0, - "keys": []interface{}{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}, // Too many keys - }, - expectError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := handleKeyboardReportDirect(tt.params) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -// Test handleAbsMouseReportDirect function -func TestHandleAbsMouseReportDirect(t *testing.T) { - tests := []struct { - name string - params map[string]interface{} - expectError bool - }{ - { - name: "valid absolute mouse report", - params: map[string]interface{}{ - "x": 1000.0, - "y": 500.0, - "buttons": 1.0, // Left button - }, - expectError: false, - }, - { - name: "boundary values", - params: map[string]interface{}{ - "x": 0.0, - "y": 32767.0, - "buttons": 255.0, - }, - expectError: false, - }, - { - name: "invalid x coordinate", - params: map[string]interface{}{ - "x": -1.0, // Out of range - "y": 500.0, - "buttons": 0.0, - }, - expectError: true, - }, - { - name: "invalid y coordinate", - params: map[string]interface{}{ - "x": 1000.0, - "y": 32768.0, // Out of range - "buttons": 0.0, - }, - expectError: true, - }, - { - name: "invalid buttons", - params: map[string]interface{}{ - "x": 1000.0, - "y": 500.0, - "buttons": 256.0, // Out of range - }, - expectError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := handleAbsMouseReportDirect(tt.params) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -// Test handleRelMouseReportDirect function -func TestHandleRelMouseReportDirect(t *testing.T) { - tests := []struct { - name string - params map[string]interface{} - expectError bool - }{ - { - name: "valid relative mouse report", - params: map[string]interface{}{ - "dx": 10.0, - "dy": -5.0, - "buttons": 2.0, // Right button - }, - expectError: false, - }, - { - name: "boundary values", - params: map[string]interface{}{ - "dx": -127.0, - "dy": 127.0, - "buttons": 0.0, - }, - expectError: false, - }, - { - name: "invalid dx", - params: map[string]interface{}{ - "dx": -128.0, // Out of range - "dy": 0.0, - "buttons": 0.0, - }, - expectError: true, - }, - { - name: "invalid dy", - params: map[string]interface{}{ - "dx": 0.0, - "dy": 128.0, // Out of range - "buttons": 0.0, - }, - expectError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := handleRelMouseReportDirect(tt.params) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -// Test handleWheelReportDirect function -func TestHandleWheelReportDirect(t *testing.T) { - tests := []struct { - name string - params map[string]interface{} - expectError bool - }{ - { - name: "valid wheel report", - params: map[string]interface{}{ - "wheelY": 3.0, - }, - expectError: false, - }, - { - name: "boundary values", - params: map[string]interface{}{ - "wheelY": -127.0, - }, - expectError: false, - }, - { - name: "invalid wheelY", - params: map[string]interface{}{ - "wheelY": 128.0, // Out of range - }, - expectError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := handleWheelReportDirect(tt.params) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -// Test handleInputRPCDirect function -func TestHandleInputRPCDirect(t *testing.T) { - tests := []struct { - name string - method string - params map[string]interface{} - expectError bool - }{ - { - name: "keyboard report", - method: "keyboardReport", - params: map[string]interface{}{ - "modifier": 0.0, - "keys": []interface{}{65.0}, - }, - expectError: false, - }, - { - name: "absolute mouse report", - method: "absMouseReport", - params: map[string]interface{}{ - "x": 1000.0, - "y": 500.0, - "buttons": 1.0, - }, - expectError: false, - }, - { - name: "relative mouse report", - method: "relMouseReport", - params: map[string]interface{}{ - "dx": 10.0, - "dy": -5.0, - "buttons": 2.0, - }, - expectError: false, - }, - { - name: "wheel report", - method: "wheelReport", - params: map[string]interface{}{ - "wheelY": 3.0, - }, - expectError: false, - }, - { - name: "unknown method", - method: "unknownMethod", - params: map[string]interface{}{}, - expectError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := handleInputRPCDirect(tt.method, tt.params) - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} - -// Test isInputMethod function -func TestIsInputMethod(t *testing.T) { - tests := []struct { - name string - method string - expected bool - }{ - { - name: "keyboard report method", - method: "keyboardReport", - expected: true, - }, - { - name: "absolute mouse report method", - method: "absMouseReport", - expected: true, - }, - { - name: "relative mouse report method", - method: "relMouseReport", - expected: true, - }, - { - name: "wheel report method", - method: "wheelReport", - expected: true, - }, - { - name: "non-input method", - method: "someOtherMethod", - expected: false, - }, - { - name: "empty method", - method: "", - expected: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := isInputMethod(tt.method) - assert.Equal(t, tt.expected, result) - }) - } -} - -// Benchmark tests to verify performance improvements -func BenchmarkValidateFloat64Param(b *testing.B) { - params := map[string]interface{}{"test": 50.0} - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = validateFloat64Param(params, "test", "benchmarkMethod", 0, 100) - } -} - -func BenchmarkValidateKeysArray(b *testing.B) { - params := map[string]interface{}{"keys": []interface{}{65.0, 66.0, 67.0}} - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = validateKeysArray(params, "benchmarkMethod") - } -} - -func BenchmarkHandleKeyboardReportDirect(b *testing.B) { - params := map[string]interface{}{ - "modifier": 2.0, - "keys": []interface{}{65.0, 66.0}, - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = handleKeyboardReportDirect(params) - } -} - -func BenchmarkHandleInputRPCDirect(b *testing.B) { - params := map[string]interface{}{ - "modifier": 2.0, - "keys": []interface{}{65.0, 66.0}, - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = handleInputRPCDirect("keyboardReport", params) - } -} diff --git a/internal/audio/audio.go b/internal/audio/audio.go index e382483c..1a381feb 100644 --- a/internal/audio/audio.go +++ b/internal/audio/audio.go @@ -23,8 +23,6 @@ // SetAudioQuality(AudioQualityHigh) // // // Audio output will automatically start when frames are received -// metrics := GetAudioMetrics() -// fmt.Printf("Latency: %v, Frames: %d\n", metrics.AverageLatency, metrics.FramesReceived) package audio import ( @@ -332,29 +330,6 @@ func GetMicrophoneConfig() AudioConfig { return currentMicrophoneConfig } -// GetAudioMetrics returns current audio metrics -func GetAudioMetrics() AudioMetrics { - // Get base metrics - framesReceived := atomic.LoadInt64(&metrics.FramesReceived) - framesDropped := atomic.LoadInt64(&metrics.FramesDropped) - - // If audio relay is running, use relay stats instead - if IsAudioRelayRunning() { - relayReceived, relayDropped := GetAudioRelayStats() - framesReceived = relayReceived - framesDropped = relayDropped - } - - return AudioMetrics{ - FramesReceived: framesReceived, - FramesDropped: framesDropped, - BytesProcessed: atomic.LoadInt64(&metrics.BytesProcessed), - LastFrameTime: metrics.LastFrameTime, - ConnectionDrops: atomic.LoadInt64(&metrics.ConnectionDrops), - AverageLatency: metrics.AverageLatency, - } -} - // Batched metrics to reduce atomic operations frequency var ( batchedFramesReceived int64 diff --git a/internal/audio/base_supervisor.go b/internal/audio/base_supervisor.go index 00dc46ac..3a8c499d 100644 --- a/internal/audio/base_supervisor.go +++ b/internal/audio/base_supervisor.go @@ -71,45 +71,6 @@ func (bs *BaseSupervisor) GetLastExitInfo() (exitCode int, exitTime time.Time) { return bs.lastExitCode, bs.lastExitTime } -// GetProcessMetrics returns process metrics if available -func (bs *BaseSupervisor) GetProcessMetrics() *ProcessMetrics { - bs.mutex.RLock() - defer bs.mutex.RUnlock() - - if bs.cmd == nil || bs.cmd.Process == nil { - return &ProcessMetrics{ - PID: 0, - CPUPercent: 0.0, - MemoryRSS: 0, - MemoryVMS: 0, - MemoryPercent: 0.0, - Timestamp: time.Now(), - ProcessName: "audio-server", - } - } - - pid := bs.cmd.Process.Pid - if bs.processMonitor != nil { - metrics := bs.processMonitor.GetCurrentMetrics() - for _, metric := range metrics { - if metric.PID == pid { - return &metric - } - } - } - - // Return default metrics if process not found in monitor - return &ProcessMetrics{ - PID: pid, - CPUPercent: 0.0, - MemoryRSS: 0, - MemoryVMS: 0, - MemoryPercent: 0.0, - Timestamp: time.Now(), - ProcessName: "audio-server", - } -} - // logSupervisorStart logs supervisor start event func (bs *BaseSupervisor) logSupervisorStart() { bs.logger.Info().Msg("Supervisor starting") diff --git a/internal/audio/input.go b/internal/audio/input.go index 8bbade51..08bb09cc 100644 --- a/internal/audio/input.go +++ b/internal/audio/input.go @@ -195,26 +195,6 @@ func (aim *AudioInputManager) GetComprehensiveMetrics() map[string]interface{} { return comprehensiveMetrics } -// LogPerformanceStats logs current performance statistics -func (aim *AudioInputManager) LogPerformanceStats() { - metrics := aim.GetComprehensiveMetrics() - - managerStats := metrics["manager"].(map[string]interface{}) - ipcStats := metrics["ipc"].(map[string]interface{}) - detailedStats := metrics["detailed"].(map[string]interface{}) - - aim.logger.Info(). - Int64("manager_frames_sent", managerStats["frames_sent"].(int64)). - Int64("manager_frames_dropped", managerStats["frames_dropped"].(int64)). - Float64("manager_latency_ms", managerStats["average_latency_ms"].(float64)). - Int64("ipc_frames_sent", ipcStats["frames_sent"].(int64)). - Int64("ipc_frames_dropped", ipcStats["frames_dropped"].(int64)). - Float64("ipc_latency_ms", ipcStats["average_latency_ms"].(float64)). - Float64("client_drop_rate", detailedStats["client_drop_rate"].(float64)). - Float64("frames_per_second", detailedStats["frames_per_second"].(float64)). - Msg("Audio input performance metrics") -} - // IsRunning returns whether the audio input manager is running // This checks both the internal state and existing system processes func (aim *AudioInputManager) IsRunning() bool { diff --git a/internal/audio/input_supervisor.go b/internal/audio/input_supervisor.go index 3aa95840..fcb71b21 100644 --- a/internal/audio/input_supervisor.go +++ b/internal/audio/input_supervisor.go @@ -319,13 +319,6 @@ func (ais *AudioInputSupervisor) GetClient() *AudioInputClient { return ais.client } -// GetProcessMetrics returns current process metrics with audio-input-server name -func (ais *AudioInputSupervisor) GetProcessMetrics() *ProcessMetrics { - metrics := ais.BaseSupervisor.GetProcessMetrics() - metrics.ProcessName = "audio-input-server" - return metrics -} - // monitorSubprocess monitors the subprocess and handles unexpected exits func (ais *AudioInputSupervisor) monitorSubprocess() { if ais.cmd == nil || ais.cmd.Process == nil { diff --git a/internal/audio/naming_standards.go b/internal/audio/naming_standards.go index 21e2c95c..2e5be5b6 100644 --- a/internal/audio/naming_standards.go +++ b/internal/audio/naming_standards.go @@ -97,7 +97,6 @@ type AudioSupervisorInterface interface { Stop() error IsRunning() bool GetProcessPID() int - GetProcessMetrics() *ProcessMetrics } type AudioServerInterface interface { diff --git a/internal/audio/output_manager.go b/internal/audio/output_manager.go index fbf302df..883cb47d 100644 --- a/internal/audio/output_manager.go +++ b/internal/audio/output_manager.go @@ -145,20 +145,6 @@ func (aom *AudioOutputManager) GetComprehensiveMetrics() map[string]interface{} return comprehensiveMetrics } -// LogPerformanceStats logs current performance statistics -func (aom *AudioOutputManager) LogPerformanceStats() { - metrics := aom.GetMetrics() - aom.logger.Info(). - Int64("frames_received", metrics.FramesReceived). - Int64("frames_dropped", metrics.FramesDropped). - Int64("bytes_processed", metrics.BytesProcessed). - Int64("connection_drops", metrics.ConnectionDrops). - Float64("average_latency_ms", float64(metrics.AverageLatency.Nanoseconds())/1e6). - Bool("running", aom.IsRunning()). - Bool("ready", aom.IsReady()). - Msg("Audio output manager performance stats") -} - // GetStreamer returns the streamer for advanced operations func (aom *AudioOutputManager) GetStreamer() *AudioOutputStreamer { return aom.streamer diff --git a/internal/audio/supervisor.go b/internal/audio/supervisor.go index 775d4586..b8ca599a 100644 --- a/internal/audio/supervisor.go +++ b/internal/audio/supervisor.go @@ -150,13 +150,6 @@ func (s *AudioOutputSupervisor) Stop() { s.logger.Info().Str("component", AudioOutputSupervisorComponent).Msg("component stopped") } -// GetProcessMetrics returns current process metrics with audio-output-server name -func (s *AudioOutputSupervisor) GetProcessMetrics() *ProcessMetrics { - metrics := s.BaseSupervisor.GetProcessMetrics() - metrics.ProcessName = "audio-output-server" - return metrics -} - // supervisionLoop is the main supervision loop func (s *AudioOutputSupervisor) supervisionLoop() { defer func() { diff --git a/ui/src/components/popovers/AudioControlPopover.tsx b/ui/src/components/popovers/AudioControlPopover.tsx index 1d633dde..bebcc236 100644 --- a/ui/src/components/popovers/AudioControlPopover.tsx +++ b/ui/src/components/popovers/AudioControlPopover.tsx @@ -1,6 +1,5 @@ import { useEffect, useState } from "react"; import { MdVolumeOff, MdVolumeUp, MdGraphicEq, MdMic, MdMicOff, MdRefresh } from "react-icons/md"; -import { LuActivity } from "react-icons/lu"; import { Button } from "@components/Button"; import { cx } from "@/cva.config"; @@ -71,7 +70,6 @@ export default function AudioControlPopover({ microphone }: AudioControlPopoverP const { isMicrophoneActive, isMicrophoneMuted, - microphoneStream, startMicrophone, stopMicrophone, toggleMicrophoneMute, @@ -86,9 +84,7 @@ export default function AudioControlPopover({ microphone }: AudioControlPopoverP const isMuted = audioMuted ?? false; const isConnected = wsConnected; - // Simple audio level placeholder - const audioLevel = 0; - const isAnalyzing = isMicrophoneActive && !isMicrophoneMuted; + // Audio devices const { @@ -362,44 +358,7 @@ export default function AudioControlPopover({ microphone }: AudioControlPopoverP - {/* Audio Level Display */} - {isMicrophoneActive && ( -