audio

package
v0.0.14 Latest Latest
Warning

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

Go to latest
Published: Nov 10, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package audio is the phone's microphone and speaker: one spoken turn at a time, for talking to an assistant. Listen opens the microphone with the phone's noise suppression and echo cancelling, and waits for someone close to it to say something and stop; Play plays a clip back. Both report how loud it is, 0…1, for something to move with the voice.

if ok, err := audio.RequestMicrophone(ctx); err != nil || !ok {
	return // not allowed
}
l := &audio.Listener{OnLevel: setLevel}
wav, err := l.Listen(ctx) // a WAV, 16 kHz mono; nil if nothing was said
…
audio.Play(ctx, reply, setLevel)
audio.Release()           // other apps' audio comes back

Add it to a project with `nimbus native plugin add audio`, which also asks for the microphone in the app's Info.plist and manifest. On the web the browser's microphone (with its own noise suppression and echo cancelling) and speaker stand in; Release isn't needed there.

Index

Constants

View Source
const Rate = 16000

Rate is the microphone's sample rate: 16-bit mono at 16 kHz.

Variables

This section is empty.

Functions

func Play

func Play(ctx context.Context, clip []byte, onLevel func(level float32)) error

Play plays a clip (WAV, MP3 or M4A) through the speaker and returns when it has finished. A cancelled ctx stops it, returning ctx's error. onLevel (may be nil) gets how loud it is, 0…1.

func Release

func Release()

Release stops everything and lets go of the microphone and speaker, so other apps' audio comes back. Call it when the conversation ends.

func RequestMicrophone

func RequestMicrophone(ctx context.Context) (bool, error)

RequestMicrophone asks for the microphone, once: later calls answer at once with what the person chose.

func WAV

func WAV(samples []int16) []byte

WAV wraps 16 kHz mono samples in a RIFF header.

Types

type Listener

type Listener struct {
	OnLevel  func(level float32) // how loud, 0…1, a few dozen times a second
	OnSpeech func()              // someone started talking
	// contains filtered or unexported fields
}

Listener listens for one spoken turn at a time. Its callbacks run on Listen's goroutine.

func (*Listener) Finish

func (l *Listener) Finish()

Finish ends the turn now, with what has been said so far. Safe from any goroutine.

func (*Listener) Listen

func (l *Listener) Listen(ctx context.Context) ([]byte, error)

Listen opens the microphone, waits for one turn and closes it again. It returns the turn as a WAV, or nil if nothing was said; a cancelled ctx stops it with ctx's error.

type Turn

type Turn int

Turn is what a TurnDetector saw in the frame it was fed.

const (
	Nothing       Turn = iota
	SpeechStarted      // someone started talking
	TurnEnded          // they stopped; the clip comes with it
	NothingSaid        // the wait ran out, or the turn was too short to send
)

type TurnDetector

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

TurnDetector decides when a spoken turn starts and ends, against the room's own noise and the speaker's own voice.

The noise floor is a low percentile of the last few seconds' loudness, so it follows a room that gets louder and quieter again, and steady noise sinks below it. Speech is sound clearly above the floor and loud enough to be close to the phone, for long enough that a clatter does not count. Once someone is talking the detector learns how loud they are: a turn ends after a short quiet for them (the room may still be chattering well below), or at a hard limit. The clip keeps a little of the moment before speech began, and what is well below the speaker between their words is turned down. Feed it short frames (Listener uses 20 ms).

func NewTurnDetector

func NewTurnDetector() *TurnDetector

NewTurnDetector starts listening for one turn.

func (*TurnDetector) Feed

func (d *TurnDetector) Feed(samples []int16) (turn Turn, level float32, clip []byte)

Feed takes the next frame and reports what it brought, with how loud it was, 0…1. With TurnEnded comes the clip, a WAV.

func (*TurnDetector) Finish

func (d *TurnDetector) Finish() []byte

Finish ends the turn now and returns it as a WAV, trailing silence trimmed; nil if nothing was said.

Jump to

Keyboard shortcuts

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