console

package
v2.16.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package console implements the audio pipeline for the lk console command. It connects microphone input and speaker output via PortAudio, applies WebRTC audio processing (echo cancellation, noise suppression), and communicates with an agent over TCP using protobuf-framed SessionMessages.

Architecture (3 goroutines, matching the Python console's PortAudio model):

micLoop     — reads PortAudio input into the capture ring buffer.
speakerLoop — reads both rings, runs ProcessRender + ProcessCapture in
              lockstep, writes to speakers, sends capture to agent.
              Paced by outputStream.Write at the hardware output rate.
tcpReader   — reads TCP messages: audio → playback ring, events → TUI.

All APM calls happen in speakerLoop, so they are single-threaded and guaranteed 1:1.

Index

Constants

View Source
const (
	SampleRate      = 48000
	Channels        = 1
	FrameDurationMs = 30
	SamplesPerFrame = SampleRate * FrameDurationMs / 1000 // 1440
	APMFrameSamples = SampleRate / 100                    // 480 (10ms)
	NumFFTBands     = 14

	CaptureRingFrames  = 50   // ~1.5s — small, just absorbs jitter between mic and speaker loops
	PlaybackRingFrames = 4000 // ~120s — large, TTS pushes faster than real-time
)

Variables

This section is empty.

Functions

func BytesToSamples

func BytesToSamples(data []byte) []int16

func ReadSessionMessage

func ReadSessionMessage(r io.Reader) (*agent.AgentSessionMessage, error)

ReadSessionMessage reads a protobuf-framed AgentSessionMessage.

func SamplesToBytes

func SamplesToBytes(samples []int16) []byte

func WriteSessionMessage

func WriteSessionMessage(w io.Writer, msg *agent.AgentSessionMessage) error

WriteSessionMessage sends a protobuf-framed AgentSessionMessage.

Types

type AudioPipeline

type AudioPipeline struct {

	// Events channel receives AgentSessionEvents from the agent for the TUI.
	Events chan *agent.AgentSessionEvent

	// Responses channel receives SessionResponses (request completions) for the TUI.
	Responses chan *agent.SessionResponse
	// contains filtered or unexported fields
}

func NewPipeline

func NewPipeline(cfg PipelineConfig) (*AudioPipeline, error)

func (*AudioPipeline) AECStats

func (p *AudioPipeline) AECStats() *apm.Stats

func (*AudioPipeline) EnableAudio

func (p *AudioPipeline) EnableAudio() error

EnableAudio lazily initializes audio devices. Returns an error if PortAudio is not available or devices cannot be opened.

func (*AudioPipeline) FFTBands

func (p *AudioPipeline) FFTBands() [NumFFTBands]float64

func (*AudioPipeline) HasAudio

func (p *AudioPipeline) HasAudio() bool

HasAudio reports whether the audio pipeline is active.

func (*AudioPipeline) IsPlaying

func (p *AudioPipeline) IsPlaying() bool

func (*AudioPipeline) Level

func (p *AudioPipeline) Level() float64

func (*AudioPipeline) Muted

func (p *AudioPipeline) Muted() bool

func (*AudioPipeline) SendRequest

func (p *AudioPipeline) SendRequest(req *agent.SessionRequest) error

func (*AudioPipeline) SetMuted

func (p *AudioPipeline) SetMuted(muted bool)

func (*AudioPipeline) SetPaused

func (p *AudioPipeline) SetPaused(paused bool)

SetPaused stops mic frames from being sent to the agent and drops any queued playback. The hardware streams keep running so the pipeline can resume instantly. Used to keep audio off the wire in text mode.

func (*AudioPipeline) Start

func (p *AudioPipeline) Start(ctx context.Context) error

func (*AudioPipeline) Stop

func (p *AudioPipeline) Stop()

type PipelineConfig

type PipelineConfig struct {
	InputDevice  *portaudio.DeviceInfo // nil to skip audio (text-only)
	OutputDevice *portaudio.DeviceInfo // nil to skip audio (text-only)
	NoAEC        bool
	Conn         net.Conn
}

type RingBuffer

type RingBuffer struct {
	// contains filtered or unexported fields
}

RingBuffer is a SPSC ring buffer for int16 audio samples. When the writer outruns the reader, the reader skips ahead to avoid stale data.

func NewRingBuffer

func NewRingBuffer(size int) *RingBuffer

func (*RingBuffer) Available

func (rb *RingBuffer) Available() int

func (*RingBuffer) Read

func (rb *RingBuffer) Read(out []int16) bool

Read blocks until len(out) samples are available, then copies them.

func (*RingBuffer) ReadAvailable

func (rb *RingBuffer) ReadAvailable(out []int16) int

ReadAvailable copies up to len(out) available samples into out (non-blocking). Returns the number of samples actually copied.

func (*RingBuffer) Reset

func (rb *RingBuffer) Reset()

func (*RingBuffer) WaitForData

func (rb *RingBuffer) WaitForData() bool

WaitForData blocks until samples are available in the buffer. Returns true if data is available, false if woken up with no data (e.g., after Reset or Broadcast for shutdown).

func (*RingBuffer) Write

func (rb *RingBuffer) Write(samples []int16) int

type TCPServer

type TCPServer struct {
	// contains filtered or unexported fields
}

func NewTCPServer

func NewTCPServer(addr string) (*TCPServer, error)

func (*TCPServer) Accept

func (s *TCPServer) Accept() (net.Conn, error)

Accept waits for a single agent connection; subsequent connections are rejected.

func (*TCPServer) AcceptConn

func (s *TCPServer) AcceptConn() (net.Conn, error)

AcceptConn returns the next connection without closing the listener, so the server can keep accepting more. Used by the session daemon, which accepts both the agent connection and many CLI control connections on one port.

func (*TCPServer) Addr

func (s *TCPServer) Addr() net.Addr

func (*TCPServer) Close

func (s *TCPServer) Close() error

func (*TCPServer) Conn

func (s *TCPServer) Conn() net.Conn

Conn returns the accepted connection, or nil if none.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL