backgroundaudio

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package backgroundaudio provides the background-audio player shipped by the LiveKit Agents TypeScript SDK, adapted to context-first Go APIs.

The player mixes file, built-in, and caller-provided PCM16 streams at 48 kHz mono. Work is entirely lazy: constructing a player starts no goroutines, opens no files, and extracts no embedded resources. Each active source has a bounded 400 ms mixer-ingress queue and the mixer wakes only on its 100 ms playout clock while streams are active.

The four byte-identical agents-js 1.7.1 Ogg assets add about 970 KiB to a binary that imports this package. BuiltinResolver can redirect decoding to caller-managed paths (it does not remove the embedded bytes); default extraction is lazy, private, and removed by BackgroundAudioPlayer.Close.

Index

Examples

Constants

View Source
const (
	MixerSampleRate         = 48_000
	MixerChannels           = 1
	DefaultBlockDuration    = 100 * time.Millisecond
	DefaultBufferDuration   = 400 * time.Millisecond
	DefaultStreamTimeout    = 2 * time.Second
	DefaultOperationTimeout = 2 * time.Second
	DefaultTaskTimeout      = 500 * time.Millisecond
	DefaultMaxStreams       = 32
)
View Source
const (
	// The pinned agents-js 1.7.1 built-in clip names are part of the public API.
	BuiltinHoldMusic       BuiltinAudioClip = "hold_music.ogg"
	BuiltinOfficeAmbience  BuiltinAudioClip = "office-ambience.ogg"
	BuiltinKeyboardTyping  BuiltinAudioClip = "keyboard-typing.ogg"
	BuiltinKeyboardTyping2 BuiltinAudioClip = "keyboard-typing2.ogg"

	// TypeScript-compatible aliases.
	HOLD_MUSIC       = BuiltinHoldMusic
	OFFICE_AMBIENCE  = BuiltinOfficeAmbience
	KEYBOARD_TYPING  = BuiltinKeyboardTyping
	KEYBOARD_TYPING2 = BuiltinKeyboardTyping2
)
View Source
const BackgroundAudioTrackName = "background_audio"

Variables

View Source
var (
	ErrStreamTimeout    = errors.New("backgroundaudio: audio stream timed out")
	ErrOperationTimeout = errors.New("backgroundaudio: output operation timed out")
	ErrPlayStopped      = errors.New("backgroundaudio: playout stopped")
)
View Source
var (
	ErrNotStarted              = errors.New("backgroundaudio: player is not started")
	ErrAlreadyStarted          = errors.New("backgroundaudio: player is already started")
	ErrClosed                  = errors.New("backgroundaudio: player is closed")
	ErrTooManyStreams          = errors.New("backgroundaudio: maximum concurrent streams reached")
	ErrLiveKitMediaUnavailable = errors.New("backgroundaudio: LiveKit PCM track publishing requires cgo Opus support")
)
View Source
var (
	ErrInvalidSource  = errors.New("backgroundaudio: invalid audio source")
	ErrSourceConsumed = errors.New("backgroundaudio: one-shot stream source was already opened")
)

Functions

func BuiltinResources

func BuiltinResources() fs.FS

BuiltinResources exposes the embedded, read-only files without extraction. Paths are of the form "resources/office-ambience.ogg".

func ExtractBuiltinAudio

func ExtractBuiltinAudio(ctx context.Context, clip BuiltinAudioClip) (path string, cleanup func() error, err error)

ExtractBuiltinAudio writes one clip to a private temporary directory. This is useful for decoders that require a path. Cleanup is idempotent and should be deferred by the caller. BackgroundAudioPlayer performs the same extraction lazily and removes every extracted file from Close.

func Float64

func Float64(value float64) *float64

func GetBuiltinAudioPath

func GetBuiltinAudioPath(ctx context.Context, clip BuiltinAudioClip) (path string, cleanup func() error, err error)

GetBuiltinAudioPath is the agents-js-compatible name for ExtractBuiltinAudio. Unlike JavaScript package resources, Go's embedded files do not inherently have an OS path, so the returned cleanup is explicit.

func IsBuiltinAudioClip

func IsBuiltinAudioClip(clip BuiltinAudioClip) bool

func OpenBuiltinAudio

func OpenBuiltinAudio(clip BuiltinAudioClip) (fs.File, error)

OpenBuiltinAudio opens an embedded clip. The caller must close the file.

Types

type AgentSession

type AgentSession interface {
	Subscribe(voice.EventSubscriptionOptions) (*voice.EventSubscription, error)
}

AgentSession is the narrow state-event surface consumed by the player. Every *voice.AgentSession[T] satisfies it.

type AudioConfig

type AudioConfig struct {
	Source      AudioSource
	Volume      *float64
	Probability *float64
}

AudioConfig configures one selectable source. Nil Volume and Probability fields have the TypeScript defaults of 1.0. Pointers preserve the distinction between an omitted value and an explicit zero.

func Config

func Config(source AudioSource) AudioConfig

func (AudioConfig) WithProbability

func (c AudioConfig) WithProbability(value float64) AudioConfig

func (AudioConfig) WithVolume

func (c AudioConfig) WithVolume(value float64) AudioConfig

type AudioEncryptor

type AudioEncryptor interface {
	EncryptSample([]byte) ([]byte, error)
}

AudioEncryptor matches server-sdk-go media encryptors without importing its cgo-only media package into no-cgo builds.

type AudioSource

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

AudioSource is the Go representation of agents-js's string | BuiltinAudioClip | AsyncIterable<AudioFrame> union. Use File, Builtin, Stream, OwnedStream, or StreamFactorySource to construct one.

func Builtin

func Builtin(clip BuiltinAudioClip) AudioSource

func File

func File(path string) AudioSource

func OwnedStream

func OwnedStream(reader FrameReader) AudioSource

OwnedStream wraps a one-shot async stream that the player closes when it implements io.Closer.

func Stream

func Stream(reader FrameReader) AudioSource

Stream wraps a caller-owned, one-shot async stream. The player never closes it.

func StreamFactorySource

func StreamFactorySource(factory FrameStreamFactory) AudioSource

StreamFactorySource creates a fresh async stream for every play request. Like AsyncIterable sources in agents-js, factory streams are not automatically looped; return an infinite stream when looping is desired.

func (AudioSource) Valid

func (s AudioSource) Valid() bool

type AudioSourceType

type AudioSourceType = AudioSource

AudioSourceType is the agents-js compatibility name.

type BackgroundAudioPlayer

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

BackgroundAudioPlayer owns mixer/source workers and its published track, but never owns the room, publisher, session, or caller-provided stream sources.

func NewBackgroundAudioPlayer

func NewBackgroundAudioPlayer(options BackgroundAudioPlayerOptions) (*BackgroundAudioPlayer, error)
Example
package main

import (
	"context"
	"fmt"

	backgroundaudio "github.com/infinityscroll/livekit-agents-go/voice/backgroundaudio"
)

func main() {
	player, err := backgroundaudio.NewBackgroundAudioPlayer(backgroundaudio.BackgroundAudioPlayerOptions{
		AmbientSound: backgroundaudio.ConfiguredSound(
			backgroundaudio.Config(backgroundaudio.Builtin(backgroundaudio.OFFICE_AMBIENCE)).WithVolume(.8),
		),
		ThinkingSound: backgroundaudio.Choose(
			backgroundaudio.Config(backgroundaudio.Builtin(backgroundaudio.KEYBOARD_TYPING)).WithProbability(.7),
			backgroundaudio.Config(backgroundaudio.Builtin(backgroundaudio.KEYBOARD_TYPING2)).WithProbability(.3),
		),
	})
	if err != nil {
		panic(err)
	}
	defer player.Close(context.Background())

	fmt.Println("background audio configured")
}
Output:
background audio configured

func (*BackgroundAudioPlayer) Close

func (*BackgroundAudioPlayer) Play

func (p *BackgroundAudioPlayer) Play(ctx context.Context, sound Sound, loop bool) (*PlayHandle, error)

Play starts one source or one probability-selected config. Loop repeats file and built-in sources. It is ignored for async streams, matching agents-js; async streams must provide their own looping behavior.

func (*BackgroundAudioPlayer) PlaySource

func (p *BackgroundAudioPlayer) PlaySource(ctx context.Context, source AudioSource, loop bool) (*PlayHandle, error)

func (*BackgroundAudioPlayer) Publication

func (p *BackgroundAudioPlayer) Publication(ctx context.Context) (Publication, bool, error)

func (*BackgroundAudioPlayer) Start

func (*BackgroundAudioPlayer) StartRoom

func (p *BackgroundAudioPlayer) StartRoom(ctx context.Context, room *lksdk.Room, session AgentSession, options LiveKitPublisherOptions) error

StartRoom is the direct room-oriented convenience equivalent of the TypeScript start({room, agentSession, trackPublishOptions}) call.

type BackgroundAudioPlayerOptions

type BackgroundAudioPlayerOptions struct {
	AmbientSound  Sound
	ThinkingSound Sound

	StreamTimeout    time.Duration
	OperationTimeout time.Duration
	// BlockDuration defaults to the agents-js mixer block of 100 ms. It is
	// exposed primarily for deterministic testing and specialized transports.
	BlockDuration  time.Duration
	BufferDuration time.Duration
	TaskTimeout    time.Duration
	MaxStreams     int
	FFmpegPath     string

	BuiltinResolver BuiltinResolver
	// Random returns a value in [0,1). The package-level rand/v2 generator is
	// used by default and no generator is initialized during construction.
	Random  func() float64
	OnError func(error)
}

type BackgroundAudioStartOptions

type BackgroundAudioStartOptions struct {
	Publisher    Publisher
	AgentSession AgentSession
}

type BuiltinAudioClip

type BuiltinAudioClip string

BuiltinAudioClip identifies a package-provided Ogg/Vorbis clip.

type BuiltinResolver

type BuiltinResolver func(context.Context, BuiltinAudioClip) (path string, cleanup func() error, err error)

BuiltinResolver may override where built-in clips are obtained. Resolve must honor ctx. The returned cleanup is called when the player closes; it may be nil. It can replace temporary extraction with an application-managed path or asset store; the embedded fallback remains part of the package binary.

type ClosableFrameSink

type ClosableFrameSink interface {
	FrameSink
	Close(context.Context) error
}

ClosableFrameSink is implemented by publisher-owned sinks that need explicit teardown. A plain voice.AudioOutput is caller-owned and is not closed.

type FrameReader

type FrameReader interface {
	Recv(context.Context) (agents.AudioFrame, error)
}

FrameReader is the context-aware async audio source contract. Recv must unblock when ctx is canceled. Implementations return io.EOF at normal end.

type FrameSink

type FrameSink interface {
	CaptureFrame(context.Context, agents.AudioFrame) error
}

FrameSink consumes fixed-format mixer frames. voice.AudioOutput satisfies this interface directly. CaptureFrame must honor ctx and may retain the frame after returning.

type FrameStreamFactory

type FrameStreamFactory func(context.Context) (FrameReader, error)

FrameStreamFactory constructs a fresh async stream for a play request.

type LiveKitPublisher

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

LiveKitPublisher adapts a connected server-sdk-go Room to Publisher. The room remains caller-owned. server-sdk-go's PublishTrack/UnpublishTrack calls do not accept contexts; this adapter checks cancellation immediately before and after those bounded SDK operations and never creates a potentially leaking wrapper goroutine.

func NewLiveKitPublisher

func NewLiveKitPublisher(room *lksdk.Room, options LiveKitPublisherOptions) (*LiveKitPublisher, error)

func (*LiveKitPublisher) CurrentPublication

func (p *LiveKitPublisher) CurrentPublication(ctx context.Context, name string) (Publication, bool, error)

func (*LiveKitPublisher) Publish

func (*LiveKitPublisher) Unpublish

func (p *LiveKitPublisher) Unpublish(ctx context.Context, sid string) error

type LiveKitPublisherOptions

type LiveKitPublisherOptions struct {
	TrackPublishOptions lksdk.TrackPublicationOptions
	Encryptor           AudioEncryptor
}

type PlayHandle

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

PlayHandle represents one playout. Stop is synchronous and idempotent; WaitForPlayout reports stream/decoder failures while a manual stop succeeds.

func (*PlayHandle) Done

func (h *PlayHandle) Done() bool

func (*PlayHandle) Err

func (h *PlayHandle) Err() error

func (*PlayHandle) Stop

func (h *PlayHandle) Stop()

func (*PlayHandle) Wait

func (h *PlayHandle) Wait(ctx context.Context) error

func (*PlayHandle) WaitForPlayout

func (h *PlayHandle) WaitForPlayout(ctx context.Context) error

type Publication

type Publication struct {
	SID  string
	Name string
}

type PublishRequest

type PublishRequest struct {
	Name       string
	SampleRate int
	Channels   int
}

type Publisher

type Publisher interface {
	Publish(context.Context, PublishRequest) (FrameSink, Publication, error)
	CurrentPublication(context.Context, string) (Publication, bool, error)
	Unpublish(context.Context, string) error
}

Publisher is the narrow room/track surface consumed by the player. Use NewLiveKitPublisher for server-sdk-go rooms or provide an application adapter.

type Sound

type Sound struct {
	Configs []AudioConfig
	// Weighted applies agents-js list selection semantics. Choose sets it.
	// Multiple Configs are also treated as weighted for struct-literal callers.
	Weighted bool
}

Sound is either one configured source or a probability-weighted list. Its zero value means no sound, which is useful for optional player settings.

func Choose

func Choose(configs ...AudioConfig) Sound

func ConfiguredSound

func ConfiguredSound(config AudioConfig) Sound

func SourceSound

func SourceSound(source AudioSource) Sound

func (Sound) Empty

func (s Sound) Empty() bool

Jump to

Keyboard shortcuts

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