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 ¶
- Constants
- Variables
- func BuiltinResources() fs.FS
- func ExtractBuiltinAudio(ctx context.Context, clip BuiltinAudioClip) (path string, cleanup func() error, err error)
- func Float64(value float64) *float64
- func GetBuiltinAudioPath(ctx context.Context, clip BuiltinAudioClip) (path string, cleanup func() error, err error)
- func IsBuiltinAudioClip(clip BuiltinAudioClip) bool
- func OpenBuiltinAudio(clip BuiltinAudioClip) (fs.File, error)
- type AgentSession
- type AudioConfig
- type AudioEncryptor
- type AudioSource
- type AudioSourceType
- type BackgroundAudioPlayer
- func (p *BackgroundAudioPlayer) Close(ctx context.Context) error
- func (p *BackgroundAudioPlayer) Play(ctx context.Context, sound Sound, loop bool) (*PlayHandle, error)
- func (p *BackgroundAudioPlayer) PlaySource(ctx context.Context, source AudioSource, loop bool) (*PlayHandle, error)
- func (p *BackgroundAudioPlayer) Publication(ctx context.Context) (Publication, bool, error)
- func (p *BackgroundAudioPlayer) Start(ctx context.Context, options BackgroundAudioStartOptions) error
- func (p *BackgroundAudioPlayer) StartRoom(ctx context.Context, room *lksdk.Room, session AgentSession, ...) error
- type BackgroundAudioPlayerOptions
- type BackgroundAudioStartOptions
- type BuiltinAudioClip
- type BuiltinResolver
- type ClosableFrameSink
- type FrameReader
- type FrameSink
- type FrameStreamFactory
- type LiveKitPublisher
- type LiveKitPublisherOptions
- type PlayHandle
- type Publication
- type PublishRequest
- type Publisher
- type Sound
Examples ¶
Constants ¶
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 )
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 )
const BackgroundAudioTrackName = "background_audio"
Variables ¶
var ( ErrStreamTimeout = errors.New("backgroundaudio: audio stream timed out") ErrOperationTimeout = errors.New("backgroundaudio: output operation timed out") ErrPlayStopped = errors.New("backgroundaudio: playout stopped") )
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") )
var ( ErrInvalidSource = errors.New("backgroundaudio: invalid audio source") ErrSourceConsumed = errors.New("backgroundaudio: one-shot stream source was already opened") )
Functions ¶
func BuiltinResources ¶
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 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 ¶
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 (p *BackgroundAudioPlayer) Close(ctx context.Context) error
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 (p *BackgroundAudioPlayer) Start(ctx context.Context, options BackgroundAudioStartOptions) error
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 ¶
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 (p *LiveKitPublisher) Publish(ctx context.Context, request PublishRequest) (FrameSink, Publication, 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) WaitForPlayout ¶
func (h *PlayHandle) WaitForPlayout(ctx context.Context) error
type Publication ¶
type PublishRequest ¶
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