Help us shape the future of Go! Take the 2026 Go Developer Survey

alsa

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package alsa captures PCM audio by driving the /dev/snd ioctl interface directly.

This exists instead of binding tinyalsa through cgo. The kernel ioctl ABI is stable and the subset a capture-only client needs is small, so the whole thing is a few hundred lines of Go and echod stays a static, cgo-free binary — no NDK image, no C toolchain.

Several of these structures embed the kernel's unsigned long, so their size — and with it the ioctl number, which encodes that size — depends on the word size. The layouts below derive from it rather than assuming one, because a mismatch is not a subtle bug: the kernel rejects the call outright, or worse, reads the wrong bytes.

Index

Constants

View Source
const (
	TypeBoolean    = 1
	TypeInteger    = 2
	TypeEnumerated = 3
	TypeBytes      = 4
	TypeInteger64  = 5
)

Control types.

View Source
const FormatS16_LE = 2

FormatS16_LE is 16-bit little endian, the only format the playback codec accepts.

View Source
const (

	// FormatS24_3LE is 24 bits packed into 3 bytes — the only format the Echo Dot's
	// capture codec accepts.
	FormatS24_3LE = 32
)

Variables

View Source
var ErrBusy = errors.New("alsa: device busy")

ErrBusy means another process holds the device.

View Source
var ErrOverrun = fmt.Errorf("alsa: capture overrun")

ErrOverrun means the hardware ring wrapped before we read it; audio was lost.

View Source
var ErrUnderrun = fmt.Errorf("alsa: playback underrun")

ErrUnderrun means the hardware ran out of samples; playback gapped.

Functions

This section is empty.

Types

type Capture

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

Capture is an open PCM capture stream.

func Open

func Open(card, device int, cfg Config) (*Capture, error)

Open configures and starts a capture stream. The open is non-blocking so a device someone else holds returns ErrBusy instead of waiting; reads block normally once it is ours.

func (*Capture) Close

func (c *Capture) Close() error

func (*Capture) FrameBytes

func (c *Capture) FrameBytes() int

FrameBytes is the size of one interleaved frame across all channels.

func (*Capture) Read

func (c *Capture) Read(buf []byte) (int, error)

Read fills buf with whole frames and returns the number of bytes read. On overrun the stream is re-prepared and restarted, and the call reports how many bytes were lost.

type Config

type Config struct {
	Channels   int
	Rate       int
	Format     int
	Bits       int // physical bits per sample: 24 for S24_3LE
	PeriodSize int
	Periods    int
}

type Control

type Control struct {
	Numid uint32
	Name  string
	Type  uint32
	Count uint32
	Items []string

	// The range of an integer control, zero for any other type.
	Min, Max, Step int64
}

Control is one mixer control.

type Mixer

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

Mixer is an open control device.

func OpenMixer

func OpenMixer(card int) (*Mixer, error)

OpenMixer opens a card's control device. Enumeration happens on first use and is cached: it costs over a second, so callers should not do it on a path where something is waiting.

func (*Mixer) Close

func (m *Mixer) Close() error

func (*Mixer) Controls

func (m *Mixer) Controls() ([]Control, error)

Controls lists the card's controls. There is no cheap way to ask how many there are, so this walks numids until the kernel stops recognising them.

The walk costs one ioctl per control plus one per item name of every enumerated control, which is over a second on this card, so the result is kept: the set does not change while the card is open.

func (*Mixer) Find

func (m *Mixer) Find(name string) (Control, error)

Find looks a control up by name.

func (*Mixer) Get

func (m *Mixer) Get(c Control) ([]uint32, error)

Get reads a control's values.

func (*Mixer) GetEnum

func (m *Mixer) GetEnum(name string) (string, error)

GetEnum reports an enumerated control's current item.

func (*Mixer) Set

func (m *Mixer) Set(c Control, v uint32) error

Set writes the same value to every channel of a control.

func (*Mixer) SetAll

func (m *Mixer) SetAll(c Control, values []uint32) error

SetAll writes one value per channel, for controls that carry a different value in each: a coefficient blob rather than a level.

func (*Mixer) SetBytes

func (m *Mixer) SetBytes(name string, data []byte) error

SetBytes writes a byte-typed control, by name.

func (*Mixer) SetEnum

func (m *Mixer) SetEnum(name, item string) error

SetEnum picks an enumerated control's item by name.

func (*Mixer) SetInt

func (m *Mixer) SetInt(name string, v uint32) error

SetInt writes a value to an integer control, by name.

type Playback

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

Playback is an open PCM playback stream.

func OpenPlayback

func OpenPlayback(card, device int, cfg Config) (*Playback, error)

OpenPlayback configures a playback stream. The hardware starts itself once the buffer is full.

The open is non-blocking: mediaserver holds this device, and a blocking open waits forever. A held device returns ErrBusy. Writes block normally once the device is ours.

func (*Playback) Close

func (p *Playback) Close() error

func (*Playback) Drain

func (p *Playback) Drain() error

Drain waits for buffered audio to finish playing.

func (*Playback) FrameBytes

func (p *Playback) FrameBytes() int

FrameBytes is the size of one interleaved frame across all channels.

func (*Playback) Write

func (p *Playback) Write(buf []byte) (int, error)

Write plays whole frames, blocking until the hardware has room. On underrun the stream is re-prepared and the call reports it, since a gap in playback is worth knowing about.

Jump to

Keyboard shortcuts

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