mirror of https://github.com/jetkvm/kvm.git
fix(audio): improve audio initialization and process termination handling
- Add retry logic for CGO audio initialization - Enhance process termination checks in input supervisor - Skip initialization check in cgo_audio to avoid compilation issues - Add proper error handling for audio system initialization failures
This commit is contained in:
parent
f51f6da2de
commit
dfbf9249b9
|
@ -709,6 +709,9 @@ func cgoAudioReadEncode(buf []byte) (int, error) {
|
|||
return 0, newBufferTooSmallError(len(buf), minRequired)
|
||||
}
|
||||
|
||||
// Skip initialization check for now to avoid CGO compilation issues
|
||||
// TODO: Add proper initialization state checking
|
||||
|
||||
n := C.jetkvm_audio_read_encode(unsafe.Pointer(&buf[0]))
|
||||
if n < 0 {
|
||||
return 0, newAudioReadEncodeError(int(n))
|
||||
|
|
|
@ -141,7 +141,8 @@ func (ais *AudioInputSupervisor) Stop() {
|
|||
|
||||
// Try graceful termination first
|
||||
if ais.cmd != nil && ais.cmd.Process != nil {
|
||||
ais.logger.Info().Int("pid", ais.cmd.Process.Pid).Msg("Stopping audio input server subprocess")
|
||||
pid := ais.cmd.Process.Pid
|
||||
ais.logger.Info().Int("pid", pid).Msg("Stopping audio input server subprocess")
|
||||
|
||||
// Send SIGTERM
|
||||
err := ais.cmd.Process.Signal(syscall.SIGTERM)
|
||||
|
@ -161,9 +162,17 @@ func (ais *AudioInputSupervisor) Stop() {
|
|||
case <-time.After(GetConfig().InputSupervisorTimeout):
|
||||
// Force kill if graceful shutdown failed
|
||||
ais.logger.Warn().Msg("Audio input server subprocess did not stop gracefully, force killing")
|
||||
err := ais.cmd.Process.Kill()
|
||||
if err != nil {
|
||||
ais.logger.Error().Err(err).Msg("Failed to kill audio input server subprocess")
|
||||
// Check if process is still alive before attempting to kill
|
||||
if ais.cmd != nil && ais.cmd.Process != nil {
|
||||
// Check process state to avoid "process already finished" error
|
||||
if ais.cmd.ProcessState == nil {
|
||||
err := ais.cmd.Process.Kill()
|
||||
if err != nil {
|
||||
ais.logger.Error().Err(err).Msg("Failed to kill audio input server subprocess")
|
||||
}
|
||||
} else {
|
||||
ais.logger.Info().Msg("Audio input server subprocess already finished")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
@ -311,10 +312,18 @@ func StartAudioOutputStreaming(send func([]byte)) error {
|
|||
return ErrAudioAlreadyRunning
|
||||
}
|
||||
|
||||
// Initialize CGO audio capture
|
||||
if err := CGOAudioInit(); err != nil {
|
||||
// Initialize CGO audio capture with retry logic
|
||||
var initErr error
|
||||
for attempt := 0; attempt < 3; attempt++ {
|
||||
if initErr = CGOAudioInit(); initErr == nil {
|
||||
break
|
||||
}
|
||||
getOutputStreamingLogger().Warn().Err(initErr).Int("attempt", attempt+1).Msg("Audio initialization failed, retrying")
|
||||
time.Sleep(time.Duration(attempt+1) * 100 * time.Millisecond)
|
||||
}
|
||||
if initErr != nil {
|
||||
atomic.StoreInt32(&outputStreamingRunning, 0)
|
||||
return err
|
||||
return fmt.Errorf("failed to initialize audio after 3 attempts: %w", initErr)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
@ -341,7 +350,7 @@ func StartAudioOutputStreaming(send func([]byte)) error {
|
|||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
// Capture audio frame with enhanced error handling
|
||||
// Capture audio frame with enhanced error handling and initialization checking
|
||||
n, err := CGOAudioReadEncode(buffer)
|
||||
if err != nil {
|
||||
consecutiveErrors++
|
||||
|
@ -350,6 +359,13 @@ func StartAudioOutputStreaming(send func([]byte)) error {
|
|||
Int("consecutive_errors", consecutiveErrors).
|
||||
Msg("Failed to read/encode audio")
|
||||
|
||||
// Check if this is an initialization error (C error code -1)
|
||||
if strings.Contains(err.Error(), "C error code -1") {
|
||||
getOutputStreamingLogger().Error().Msg("Audio system not initialized properly, forcing reinitialization")
|
||||
// Force immediate reinitialization for init errors
|
||||
consecutiveErrors = maxConsecutiveErrors
|
||||
}
|
||||
|
||||
// Implement progressive backoff for consecutive errors
|
||||
if consecutiveErrors >= maxConsecutiveErrors {
|
||||
getOutputStreamingLogger().Error().
|
||||
|
|
Loading…
Reference in New Issue