faad2

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jan 22, 2026 License: GPL-2.0 Imports: 11 Imported by: 0

README

go-faad2

Pure Go AAC audio decoder using FAAD2 compiled to WebAssembly.

Features

  • Pure Go - No CGO dependencies, cross-compiles easily
  • M4A/MP4 support - Built-in demuxer for M4A files with seeking and metadata
  • ADTS support - Decode raw AAC streams (ADTS format)
  • Low-level API - Decode raw AAC frames directly

Installation

go get github.com/llehouerou/go-faad2

Usage

Decode M4A file
ctx := context.Background()

file, _ := os.Open("audio.m4a")
defer file.Close()

reader, _ := faad2.OpenM4A(ctx, file)
defer reader.Close(ctx)

fmt.Printf("Sample rate: %d, Channels: %d, Duration: %v\n",
    reader.SampleRate(), reader.Channels(), reader.Duration())

pcm := make([]int16, 4096)
for {
    n, err := reader.Read(ctx, pcm)
    if err == io.EOF {
        break
    }
    // Process pcm[:n]
}
Seeking and position
reader, _ := faad2.OpenM4A(ctx, file)
defer reader.Close(ctx)

// Seek to 30 seconds
reader.Seek(30 * time.Second)

// Get current position
fmt.Printf("Position: %v\n", reader.Position())
Extract metadata
reader, _ := faad2.OpenM4A(ctx, file)
defer reader.Close(ctx)

meta := reader.Metadata()
fmt.Printf("Title: %s\n", meta.Title)
fmt.Printf("Artist: %s\n", meta.Artist)
fmt.Printf("Album: %s\n", meta.Album)
Decode ADTS stream (raw AAC)
ctx := context.Background()

file, _ := os.Open("audio.aac")
reader, _ := faad2.OpenADTS(ctx, file)
defer reader.Close(ctx)

pcm := make([]int16, 4096)
for {
    n, err := reader.Read(ctx, pcm)
    if err == io.EOF {
        break
    }
    // Process pcm[:n]
}
Decode raw AAC frames (low-level)
ctx := context.Background()

decoder, _ := faad2.NewDecoder(ctx)
defer decoder.Close(ctx)

// Initialize with AAC codec config (from ADTS or MP4 esds)
decoder.Init(ctx, codecConfig)

// Decode frames
pcm, _ := decoder.Decode(ctx, aacFrame)

Building the WASM binary

The WASM binary is pre-built and embedded in the library. To rebuild it:

# Requires Emscripten (available in nix devShell)
make wasm

Development

# Enter development shell (requires Nix with flakes)
nix develop

# Run checks (format, lint, test)
make check

# Install git hooks
make install-hooks

License

GPL-2.0-or-later (required by FAAD2)

Credits

Documentation

Overview

Package faad2 provides AAC audio decoding using the FAAD2 library compiled to WebAssembly.

The package supports decoding AAC audio from:

Basic usage with M4A files:

reader, err := faad2.OpenM4A(ctx, file)
if err != nil {
    log.Fatal(err)
}
defer reader.Close(ctx)

pcm := make([]int16, 4096)
for {
    n, err := reader.Read(ctx, pcm)
    if err != nil {
        break
    }
    // Process pcm[:n] samples...
}

The package uses a global WASM runtime that is lazily initialized on first use. Call Shutdown to release WASM resources when done.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidADTS is returned when the ADTS stream is invalid.
	ErrInvalidADTS = errors.New("faad2: invalid ADTS stream")

	// ErrADTSSyncNotFound is returned when no ADTS sync word is found.
	ErrADTSSyncNotFound = errors.New("faad2: ADTS sync word not found")
)
View Source
var (
	// ErrInvalidConfig is returned when the AAC codec configuration is invalid.
	ErrInvalidConfig = errors.New("faad2: invalid codec configuration")

	// ErrDecodeFailed is returned when AAC frame decoding fails.
	ErrDecodeFailed = errors.New("faad2: decode failed")

	// ErrOutOfMemory is returned when WASM memory allocation fails.
	ErrOutOfMemory = errors.New("faad2: out of memory")

	// ErrNotInitialized is returned when trying to decode without initialization.
	ErrNotInitialized = errors.New("faad2: decoder not initialized")

	// ErrNotM4A is returned when the input is not a valid M4A/MP4 file.
	ErrNotM4A = errors.New("faad2: not an M4A/MP4 file")

	// ErrNoAudioTrack is returned when no AAC audio track is found.
	ErrNoAudioTrack = errors.New("faad2: no AAC audio track found")

	// ErrUnsupportedCodec is returned when the audio codec is not AAC.
	ErrUnsupportedCodec = errors.New("faad2: unsupported audio codec (not AAC)")

	// ErrDecoderClosed is returned when trying to use a closed decoder.
	ErrDecoderClosed = errors.New("faad2: decoder is closed")

	// ErrEmptyFrame is returned when trying to decode an empty AAC frame.
	ErrEmptyFrame = errors.New("faad2: empty AAC frame")

	// ErrSeekUnavailable is returned when seeking is not available (e.g., no timescale info).
	ErrSeekUnavailable = errors.New("faad2: seek not available")
)

Functions

func ParseADTSHeader

func ParseADTSHeader(data []byte) (sampleRate uint32, channels uint8, frameLength uint16, err error)

ParseADTSHeader parses an ADTS header from raw bytes without creating a reader.

This is useful for inspecting ADTS streams or extracting metadata. The data slice must contain at least 7 bytes (the minimum ADTS header size).

Returns the sample rate in Hz, channel count, and frame length in bytes (including the header). Returns ErrADTSSyncNotFound if the sync word is not found, or ErrInvalidADTS if the header is too short or malformed.

func Shutdown added in v0.2.0

func Shutdown(ctx context.Context) error

Shutdown releases the global WASM runtime and all associated resources.

After calling Shutdown:

  • All existing Decoder, M4AReader, and ADTSReader instances become invalid
  • Calling methods on closed instances will return errors or panic
  • New instances can be created, which will lazily reinitialize the runtime

Shutdown is optional but recommended when the application no longer needs AAC decoding, as it frees significant memory used by the WASM runtime.

Types

type ADTSReader

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

ADTSReader reads and decodes audio from ADTS (Audio Data Transport Stream) format.

ADTS is a streaming format for AAC audio, commonly used for raw AAC files (.aac) and streaming applications. Unlike M4A, ADTS does not support seeking.

Create an ADTSReader using OpenADTS and release resources with ADTSReader.Close.

func OpenADTS

func OpenADTS(ctx context.Context, r io.Reader) (*ADTSReader, error)

OpenADTS opens an ADTS stream for audio decoding.

The reader should provide raw ADTS data starting with a valid ADTS sync word (0xFFF). The function reads and decodes the first frame to initialize the decoder.

Returns ErrADTSSyncNotFound if no valid ADTS header is found, or ErrInvalidADTS if the header is malformed.

func (*ADTSReader) Channels

func (ar *ADTSReader) Channels() uint8

Channels returns the number of audio channels (1 for mono, 2 for stereo).

func (*ADTSReader) Close

func (ar *ADTSReader) Close(ctx context.Context) error

Close releases all resources associated with the reader.

After Close is called, the reader cannot be reused. It is safe to call Close multiple times; subsequent calls are no-ops.

Note: Close does not close the underlying io.Reader passed to OpenADTS.

func (*ADTSReader) FramesRead

func (ar *ADTSReader) FramesRead() int64

FramesRead returns the number of AAC frames decoded so far.

This can be used to estimate playback position when the frame duration is known (typically 1024 samples per frame for AAC-LC).

func (*ADTSReader) Read

func (ar *ADTSReader) Read(ctx context.Context, pcm []int16) (int, error)

Read reads decoded PCM samples into the provided buffer.

Returns the number of samples read into pcm. For stereo audio, each sample pair (L, R) counts as 2 samples. Returns io.EOF when the stream ends.

The buffer can be any size; the reader handles internal buffering.

func (*ADTSReader) SampleRate

func (ar *ADTSReader) SampleRate() uint32

SampleRate returns the audio sample rate in Hz (e.g., 44100, 48000).

type Decoder

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

Decoder is a low-level AAC decoder that decodes individual AAC frames.

For most use cases, prefer OpenM4A or OpenADTS which handle container parsing and provide a simpler streaming interface.

A Decoder must be initialized with Decoder.Init before calling Decoder.Decode. The decoder is safe for concurrent use after initialization.

func NewDecoder

func NewDecoder(ctx context.Context) (*Decoder, error)

NewDecoder creates a new AAC decoder instance.

The decoder must be initialized with Decoder.Init before use. Call Decoder.Close when done to release resources.

func (*Decoder) Channels

func (d *Decoder) Channels() uint8

Channels returns the number of audio channels (1 for mono, 2 for stereo).

Returns 0 if the decoder has not been initialized.

func (*Decoder) Close

func (d *Decoder) Close(ctx context.Context) error

Close releases decoder resources.

After Close is called, the decoder cannot be reused. It is safe to call Close multiple times; subsequent calls are no-ops.

func (*Decoder) Decode

func (d *Decoder) Decode(ctx context.Context, aacFrame []byte) ([]int16, error)

Decode decodes a single AAC frame and returns interleaved PCM samples.

The returned slice contains 16-bit signed PCM samples. For stereo audio, samples are interleaved (L, R, L, R, ...). The number of samples per frame is typically 1024 or 2048 per channel, depending on the AAC profile.

Returns ErrNotInitialized if Decoder.Init has not been called, ErrEmptyFrame if aacFrame is empty, or ErrDecodeFailed on decode error.

func (*Decoder) Init

func (d *Decoder) Init(ctx context.Context, config []byte) error

Init initializes the decoder with an AudioSpecificConfig.

The config parameter is the AAC AudioSpecificConfig, typically extracted from:

  • The esds box in M4A/MP4 files
  • ADTS frame headers (converted via internal helper)

Init must be called exactly once before Decoder.Decode. Returns ErrInvalidConfig if the configuration is nil, empty, or invalid.

func (*Decoder) SampleRate

func (d *Decoder) SampleRate() uint32

SampleRate returns the audio sample rate in Hz (e.g., 44100, 48000).

Returns 0 if the decoder has not been initialized.

type M4AReader

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

M4AReader reads and decodes audio from M4A/MP4 container files.

It provides streaming access to decoded PCM audio along with metadata, duration, seeking, and position tracking.

Create an M4AReader using OpenM4A and release resources with M4AReader.Close.

func OpenM4A

func OpenM4A(ctx context.Context, r io.ReadSeeker) (*M4AReader, error)

OpenM4A opens an M4A/MP4 file for audio decoding.

The reader must support seeking as M4A files require random access to read audio samples from various positions.

Note: This function reads the entire file into memory for container parsing. For very large files (hundreds of MB), consider memory constraints.

Returns ErrNotM4A if the file is not a valid MP4 container, ErrNoAudioTrack if no AAC audio track is found, or ErrUnsupportedCodec if the audio codec is not AAC.

func (*M4AReader) Channels

func (m *M4AReader) Channels() uint8

Channels returns the number of audio channels (1 for mono, 2 for stereo).

func (*M4AReader) Close

func (m *M4AReader) Close(ctx context.Context) error

Close releases all resources associated with the reader.

After Close is called, the reader cannot be reused. It is safe to call Close multiple times; subsequent calls are no-ops.

Note: Close does not close the underlying io.ReadSeeker passed to OpenM4A.

func (*M4AReader) Duration

func (m *M4AReader) Duration() time.Duration

Duration returns the total duration of the audio track.

func (*M4AReader) Metadata

func (m *M4AReader) Metadata() Metadata

Metadata returns the file's metadata (title, artist, album, etc.).

Fields may be empty if the file does not contain the corresponding metadata.

func (*M4AReader) Position

func (m *M4AReader) Position() time.Duration

Position returns the current playback position based on samples read so far.

func (*M4AReader) Read

func (m *M4AReader) Read(ctx context.Context, pcm []int16) (int, error)

Read reads decoded PCM samples into the provided buffer.

Returns the number of samples read into pcm. For stereo audio, each sample pair (L, R) counts as 2 samples. Returns io.EOF when all audio has been read.

The buffer can be any size; the reader handles internal buffering. Smaller buffers result in more Read calls but use less memory.

func (*M4AReader) SampleRate

func (m *M4AReader) SampleRate() uint32

SampleRate returns the audio sample rate in Hz (e.g., 44100, 48000).

func (*M4AReader) Seek

func (m *M4AReader) Seek(position time.Duration) error

Seek moves the playback position to the specified time.

The actual position after seeking may differ slightly from the requested position due to AAC frame boundaries. Use M4AReader.Position to get the actual position after seeking.

Seeking past the end of the file positions at EOF; the next M4AReader.Read will return io.EOF.

Returns ErrSeekUnavailable if the file lacks timing information.

type Metadata

type Metadata struct {
	Title       string // Track title (©nam)
	Artist      string // Artist name (©ART)
	Album       string // Album name (©alb)
	Year        int    // Release year (©day)
	TrackNumber int    // Track number (trkn)
	Genre       string // Genre (©gen)
}

Metadata contains M4A/MP4 file metadata tags.

All fields are optional and may be empty if not present in the file.

Jump to

Keyboard shortcuts

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