#lang scribble/manual @(require racket/base (for-label racket/base "../libao.rkt")) @title{libao} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @defmodule["libao.rkt"] This module provides a small high-level interface to an asynchronous audio output backend. It opens a live output device, queues audio buffers for playback, reports playback position, supports pause and buffer clearing, and exposes a small set of validation predicates. The central value is an @racket[ao-handle], created by @racket[ao-open-live]. An @racket[ao-handle] stores the playback configuration together with a native asynchronous player handle. @section{Audio handles} @defproc[(ao-handle? [v any/c]) boolean?]{ Returns @racket[#t] if @racket[v] is an @racket[ao-handle] value, and @racket[#f] otherwise. } @defproc[(ao-valid? [handle ao-handle?]) boolean?]{ Returns @racket[#t] if @racket[handle] still has a native asynchronous player, and @racket[#f] otherwise. A handle becomes invalid after @racket[ao-close], or when @racket[ao-open-live] failed to create the native player. } @section{Validation predicates} @defproc[(ao-valid-bits? [bits any/c]) boolean?]{ Returns @racket[#t] if @racket[bits] is one of @racket[8], @racket[16], @racket[24], or @racket[32], and @racket[#f] otherwise. } @defproc[(ao-valid-rate? [rate any/c]) boolean?]{ Returns @racket[#t] if @racket[rate] is one of the sample rates accepted by this module, and @racket[#f] otherwise. The accepted rates are: @itemlist[#:style 'compact @item{@racket[8000], @racket[11025], @racket[16000], @racket[22050],} @item{@racket[44100], @racket[48000], @racket[88200], @racket[96000],} @item{@racket[176400], @racket[192000], @racket[352800], and} @item{@racket[384000].}] } @defproc[(ao-valid-channels? [channels any/c]) boolean?]{ Returns @racket[#t] if @racket[channels] is an integer greater than or equal to @racket[1], and @racket[#f] otherwise. } @defproc[(ao-valid-format? [format any/c]) boolean?]{ Returns @racket[#t] if @racket[format] is one of @racket['little-endian], @racket['big-endian], or @racket['native-endian], and @racket[#f] otherwise. } @defproc[(ao-supported-music-format? [format any/c]) boolean?]{ Returns @racket[#t] if @racket[format] is one of @racket['flac], @racket['mp3], or @racket['ao], and @racket[#f] otherwise. This value is used by @racket[ao-play] to describe the format of the buffer being queued. } @section{Opening and closing} @defproc[(ao-open-live [bits ao-valid-bits?] [rate ao-valid-rate?] [channels ao-valid-channels?] [byte-format ao-valid-format?]) ao-handle?]{ Creates an audio output handle for live playback. The handle stores the given sample size, sample rate, channel count, and byte format. It then tries to create a native asynchronous player. If the native player is created successfully, the returned handle is valid. If player creation fails, the function still returns an @racket[ao-handle], but that handle is marked closed and is not valid for playback. A finalizer is registered for the handle and calls @racket[ao-close] when the handle is reclaimed. } @defproc[(ao-close [handle ao-handle?]) void?]{ Stops playback for @racket[handle] and releases the native player reference stored in the handle. If the handle already has no native player, this procedure has no effect. } @section{Playback} @defproc[(ao-play [handle ao-handle?] [music-id integer?] [at-time-in-s number?] [music-duration-s number?] [buffer any/c] [buf-len integer?] [buf-type ao-supported-music-format?]) void?]{ Queues audio data for asynchronous playback. The @racket[music-id] argument identifies the music stream associated with the buffer. The arguments @racket[at-time-in-s] and @racket[music-duration-s] describe the position and duration, in seconds, associated with the buffer. The arguments @racket[buffer] and @racket[buf-len] provide the audio data and its length. The @racket[buf-type] argument specifies the buffer format. The buffer description passed to the native layer is completed with the sample size, sample rate, channel count, and byte format stored in @racket[handle]. If @racket[handle] is not valid, this procedure raises an exception. } @defproc[(ao-pause [handle ao-handle?] [pause boolean?]) void?]{ Pauses or resumes asynchronous playback for @racket[handle]. A true value pauses playback. @racket[#f] resumes playback. } @defproc[(ao-clear-async [handle ao-handle?]) void?]{ Clears buffered asynchronous playback data for @racket[handle]. } @section{Playback state} @defproc[(ao-at-second [handle ao-handle?]) number?]{ Returns the current playback position, in seconds, as reported by the native asynchronous player. } @defproc[(ao-at-music-id [handle ao-handle?]) integer?]{ Returns the music identifier currently reported by the native asynchronous player. } @defproc[(ao-music-duration [handle ao-handle?]) number?]{ Returns the duration of the current music stream, in seconds, as reported by the native asynchronous player. } @defproc[(ao-bufsize-async [handle ao-handle?]) integer?]{ Returns the current buffered size in bytes for the asynchronous player. } @section{Volume control} @defproc[(ao-set-volume! [handle ao-handle?] [percentage number?]) void?]{ Sets the playback volume for @racket[handle]. If @racket[percentage] is an exact integer, it is converted to an inexact number before it is passed to the native layer. } @defproc[(ao-volume [handle ao-handle?]) number?]{ Returns the current playback volume as reported by the native asynchronous player. } @section{Notes} This module is a higher-level wrapper around the asynchronous FFI layer. It stores the playback configuration in the handle, and reuses that configuration for each call to @racket[ao-play]. The module does not expose the handle fields directly. The public API is intentionally small: create a handle, queue buffers, inspect position and buffer state, pause or clear playback, adjust volume, and close the handle. A typical usage pattern is to open one live handle for a given stream format, queue decoded buffers with @racket[ao-play], and query the playback position with @racket[ao-at-second] while playback proceeds asynchronously.