diff --git a/internal/audio/cgo_source.go b/internal/audio/cgo_source.go index 02cb259f..9cc07a4a 100644 --- a/internal/audio/cgo_source.go +++ b/internal/audio/cgo_source.go @@ -167,17 +167,21 @@ func (c *CgoSource) IsConnected() bool { } func (c *CgoSource) ReadMessage() (uint8, []byte, error) { + // Check connection status with mutex c.mu.Lock() - defer c.mu.Unlock() - if !c.connected { + c.mu.Unlock() return 0, nil, fmt.Errorf("not connected") } if c.direction != "output" { + c.mu.Unlock() return 0, nil, fmt.Errorf("ReadMessage only supported for output direction") } + c.mu.Unlock() + // Call C function without holding mutex to avoid deadlock + // The C layer has its own locking and handles stop requests opusSize := C.jetkvm_audio_read_encode(unsafe.Pointer(&c.opusBuf[0])) if opusSize < 0 { return 0, nil, fmt.Errorf("jetkvm_audio_read_encode failed: %d", opusSize) @@ -195,16 +199,18 @@ func (c *CgoSource) ReadMessage() (uint8, []byte, error) { } func (c *CgoSource) WriteMessage(msgType uint8, payload []byte) error { + // Check connection status and validate parameters with mutex c.mu.Lock() - defer c.mu.Unlock() - if !c.connected { + c.mu.Unlock() return fmt.Errorf("not connected") } if c.direction != "input" { + c.mu.Unlock() return fmt.Errorf("WriteMessage only supported for input direction") } + c.mu.Unlock() if msgType != ipcMsgTypeOpus { return nil @@ -218,6 +224,8 @@ func (c *CgoSource) WriteMessage(msgType uint8, payload []byte) error { return fmt.Errorf("opus packet too large: %d bytes (max 1500)", len(payload)) } + // Call C function without holding mutex to avoid deadlock + // The C layer has its own locking and handles stop requests rc := C.jetkvm_audio_decode_write(unsafe.Pointer(&payload[0]), C.int(len(payload))) if rc < 0 { return fmt.Errorf("jetkvm_audio_decode_write failed: %d", rc)