#ifndef foosydneyhfoo #define foosydneyhfoo /* Requirements: - In sync mode, the device will automatically write data so that an initial read causes writes of zeros to be issued to that one can do "while (1); {read(); write()} - All functions are thread-safe and can be called in any thread context. None of the functions is async-signal safe. - It is assumed that duplex streams have a single clock (synchronised) */ #include #include #include /* Detect byte order, based on sys/param.h */ #if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || defined(WIN32) # define SA_LITTLE_ENDIAN 1 # undef SA_BIG_ENDIAN #elif (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) # undef SA_LITTLE_ENDIAN # define SA_BIG_ENDIAN 1 #else # error "Cannot determine byte order!" #endif typedef struct sa_stream sa_stream_t; /** Volume that corresponds to muted in/out */ #define SA_VOLUME_MUTED ((int32_t) (-0x80000000)) /** Ways to express seek offsets for pread/pwrite */ typedef enum { SA_SEEK_RELATIVE, SA_SEEK_ABSOLUTE, SA_SEEK_RELATIVE_END, _SA_SEEK_MAX } sa_seek_t; /** Supported formats */ typedef enum { SA_PCM_FORMAT_U8, SA_PCM_FORMAT_ULAW, SA_PCM_FORMAT_ALAW, SA_PCM_FORMAT_S16_LE, SA_PCM_FORMAT_S16_BE, SA_PCM_FORMAT_S24_LE, SA_PCM_FORMAT_S24_BE, SA_PCM_FORMAT_S32_LE, SA_PCM_FORMAT_S32_BE, SA_PCM_FORMAT_FLOAT32_LE, SA_PCM_FORMAT_FLOAT32_BE, _SA_PCM_FORMAT_MAX } sa_pcm_format_t; /* Native/reverse endianness definitions for PCM */ #ifdef SA_LITTLE_ENDIAN #define SA_PCM_FORMAT_S16_NE SA_PCM_FORMAT_S16_LE #define SA_PCM_FORMAT_S24_NE SA_PCM_FORMAT_S24_LE #define SA_PCM_FORMAT_S32_NE SA_PCM_FORMAT_S32_LE #define SA_PCM_FORMAT_FLOAT32_NE SA_PCM_FORMAT_FLOAT32_LE #define SA_PCM_FORMAT_S16_RE SA_PCM_FORMAT_S16_BE #define SA_PCM_FORMAT_S24_RE SA_PCM_FORMAT_S24_BE #define SA_PCM_FORMAT_S32_RE SA_PCM_FORMAT_S32_BE #define SA_PCM_FORMAT_FLOAT32_RE SA_PCM_FORMAT_FLOAT32_BE #else #define SA_PCM_FORMAT_S16_NE SA_PCM_FORMAT_S16_BE #define SA_PCM_FORMAT_S24_NE SA_PCM_FORMAT_S24_BE #define SA_PCM_FORMAT_S32_NE SA_PCM_FORMAT_S32_BE #define SA_PCM_FORMAT_FLOAT32_NE SA_PCM_FORMAT_FLOAT32_BE #define SA_PCM_FORMAT_S16_RE SA_PCM_FORMAT_S16_LE #define SA_PCM_FORMAT_S24_RE SA_PCM_FORMAT_S24_LE #define SA_PCM_FORMAT_S32_RE SA_PCM_FORMAT_S32_LE #define SA_PCM_FORMAT_FLOAT32_RE SA_PCM_FORMAT_FLOAT32_LE #endif #define SA_CODEC_MPEG "mpeg" #define SA_CODEC_AC3 "ac3" #define SA_CODEC_GSM "gsm" #define SA_CODEC_VORBIS "vorbis" #define SA_CODEC_SPEEX "speex" /** Device opening modes */ typedef enum { SA_MODE_WRONLY = 1, SA_MODE_RDONLY = 2, SA_MODE_RDWR = 3, _SA_MODE_MAX = 4, } sa_mode_t; /** Error codes */ typedef enum { SA_SUCCESS = 0, SA_ERROR_NOT_SUPPORTED = -1, SA_ERROR_INVALID = -2, SA_ERROR_STATE = -3, SA_ERROR_OOM = -4, SA_ERROR_NO_DEVICE = -5, SA_ERROR_NO_DRIVER = -6, SA_ERROR_NO_CODEC = -7, SA_ERROR_NO_PCM_FORMAT = -7, SA_ERROR_SYSTEM = -8, SA_ERROR_NO_INIT = -9, SA_ERROR_NO_META = -10, SA_ERROR_NO_DATA = -11, SA_ERROR_NO_SPACE = -12, _SA_ERROR_MAX = -13 } sa_error_t; /** Possible events for notifications */ typedef enum { SA_NOTIFY_REQUEST_START, SA_NOTIFY_REQUEST_STOP, SA_NOTIFY_CHANGED_READ_VOLUME, SA_NOTIFY_CHANGED_WRITE_VOLUME, SA_NOTIFY_CHANGED_DEVICE, _SA_NOTIFY_MAX } sa_notify_t; /** Classes of events */ typedef enum { SA_EVENT_REQUEST_IO, SA_EVENT_INIT_THREAD, SA_EVENT_NOTIFY, SA_EVENT_ERROR, _SA_EVENT_MAX } sa_event_t; /** List of sample position queries */ typedef enum { SA_POSITION_WRITE_DELAY, SA_POSITION_WRITE_HARDWARE, SA_POSITION_WRITE_SOFTWARE, SA_POSITION_READ_DELAY, SA_POSITION_READ_HARDWARE, SA_POSITION_READ_SOFTWARE, SA_POSITION_DUPLEX_DELAY, _SA_POSITION_MAX } sa_position_t; /* Channel positions */ typedef enum { SA_CHANNEL_MONO, SA_CHANNEL_LEFT, SA_CHANNEL_RIGHT, SA_CHANNEL_CENTER, SA_CHANNEL_FRONT_LEFT, SA_CHANNEL_FRONT_RIGHT, SA_CHANNEL_FRONT_CENTER, SA_CHANNEL_REAR_LEFT, SA_CHANNEL_REAR_RIGHT, SA_CHANNEL_REAR_CENTER, SA_CHANNEL_LFE, SA_CHANNEL_FRONT_LEFT_OF_CENTER, SA_CHANNEL_FRONT_RIGHT_OF_CENTER, SA_CHANNEL_SIDE_LEFT, SA_CHANNEL_SIDE_RIGHT, SA_CHANNEL_TOP_CENTER, SA_CHANNEL_TOP_FRONT_LEFT, SA_CHANNEL_TOP_FRONT_RIGHT, SA_CHANNEL_TOP_FRONT_CENTER, SA_CHANNEL_TOP_REAR_LEFT, SA_CHANNEL_TOP_REAR_RIGHT, SA_CHANNEL_TOP_REAR_CENTER, SA_CHANNEL_AUX0, SA_CHANNEL_AUX1, SA_CHANNEL_AUX2, SA_CHANNEL_AUX3, SA_CHANNEL_AUX4, SA_CHANNEL_AUX5, SA_CHANNEL_AUX6, SA_CHANNEL_AUX7, SA_CHANNEL_AUX8, SA_CHANNEL_AUX9, SA_CHANNEL_AUX10, SA_CHANNEL_AUX11, SA_CHANNEL_AUX12, SA_CHANNEL_AUX13, SA_CHANNEL_AUX14, SA_CHANNEL_AUX15, SA_CHANNEL_AUX16, SA_CHANNEL_AUX17, SA_CHANNEL_AUX18, SA_CHANNEL_AUX19, SA_CHANNEL_AUX20, SA_CHANNEL_AUX21, SA_CHANNEL_AUX22, SA_CHANNEL_AUX23, SA_CHANNEL_AUX24, SA_CHANNEL_AUX25, SA_CHANNEL_AUX26, SA_CHANNEL_AUX27, SA_CHANNEL_AUX28, SA_CHANNEL_AUX29, SA_CHANNEL_AUX30, SA_CHANNEL_AUX31, _SA_CHANNEL_MAX } sa_channel_t; typedef enum { SA_STATE_INIT, SA_STATE_RUNNING, SA_STATE_STOPPED, /* put more stuff */ _SA_STATE_MAX, } sa_state_t; typedef enum { SA_XRUN_MODE_STOP, SA_XRUN_MODE_SPIN, _SA_XRUN_MODE_MAX } sa_xrun_mode_t; typedef enum { SA_ADJUST_UP = 1, SA_ADJUST_DOWN = -1, SA_ADJUST_NONE = 0, } sa_adjust_t; /* Some kind of meta information. */ #define SA_META_CLIENT_NAME "sydney.client-name" /* utf-8 */ #define SA_META_PROCESS_ID "sydney.process-id" /* getpid() */ #define SA_META_LANGUAGE "sydney.language" /* de_DE and similar */ /* Some kind of meta information. Not filled in */ #define SA_META_STREAM_NAME "sydney.stream-name" /* utf-8 */ #define SA_META_ICON_NAME "sydney.icon-name" /* file name (no slashes) */ #define SA_META_ICON_PNG "sydney.icon-png" /* PNG blob */ #define SA_META_ROLE "sydney.role" /* one of: "music", "phone", "game", "event" */ #define SA_META_X11_DISPLAY "sydney.x11-display" /* X11 display */ #define SA_META_X11_WINDOW "sydney.x11-window" /* X11 window id */ /** Main callback function */ typedef int (*sa_event_callback_t)(sa_stream_t *s, sa_event_t event); /** Create an opaque (e.g. AC3) codec stream */ int sa_stream_create_opaque(sa_stream_t **s, const char *client_name, sa_mode_t mode, const char *codec); /** Normal way to open a PCM device */ int sa_stream_create_pcm(sa_stream_t **s, const char *client_name, sa_mode_t mode, sa_pcm_format_t format, unsigned rate, unsigned nchannels); /** Initialise the device */ int sa_stream_open(sa_stream_t *s); /** Close/destroy everything */ int sa_stream_destroy(sa_stream_t *s); /* "Soft" params */ int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size); int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size); int sa_stream_set_write_upper_watermark(sa_stream_t *s, size_t size); int sa_stream_set_read_upper_watermark(sa_stream_t *s, size_t size); /** Set the mapping between channels and the loudspeakers */ int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t map[], unsigned n); /** Whether xruns cause the card to reset */ int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode); /** Set the device to non-interleaved mode */ int sa_stream_set_non_interleaved(sa_stream_t *s, int enable); /** Require dynamic sample rate */ int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable); /** Select driver */ int sa_stream_set_driver(sa_stream_t *s, const char *driver); /** Start callback */ int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t callback); /** Start callback */ int sa_stream_stop_thread(sa_stream_t *s); /** Change the device connected to the stream */ int sa_stream_change_device(sa_stream_t *s, const char *device_name); /** volume in hundreths of dB*/ int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned n); /** volume in hundreths of dB*/ int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned n); /** Change the sampling rate */ int sa_stream_change_rate(sa_stream_t *s, unsigned rate); /** Change some meta data that is attached to the stream */ int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size); /** Associate opaque user data */ int sa_stream_change_user_data(sa_stream_t *s, const void *value); /* Hardware-related. This is implementation-specific and hardware specific. */ int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction); int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction); int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction); int sa_stream_set_adjust_watermarks(sa_stream_t *s, sa_adjust_t direction); /* Query functions */ int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode); int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size); int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *format); int sa_stream_get_rate(sa_stream_t *s, unsigned *rate); int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels); int sa_stream_get_user_data(sa_stream_t *s, void **value); int sa_stream_get_write_lower_watermark(sa_stream_t *s, size_t *size); int sa_stream_get_read_lower_watermark(sa_stream_t *s, size_t *size); int sa_stream_get_write_upper_watermark(sa_stream_t *s, size_t *size); int sa_stream_get_read_upper_watermark(sa_stream_t *s, size_t *size); int sa_stream_get_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned *n); int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode); int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled); int sa_stream_get_dynamic_rate(sa_stream_t *s, int *enabled); int sa_stream_get_driver(sa_stream_t *s, char *driver_name, size_t *size); int sa_stream_get_device(sa_stream_t *s, char *device_name, size_t *size); int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned *n); int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned *n); int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void*data, size_t *size); int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction); int sa_stream_get_adjust_nchannels(sa_stream_t *s, sa_adjust_t *direction); int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction); int sa_stream_get_adjust_watermarks(sa_stream_t *s, sa_adjust_t *direction); /** Get current state of the audio device */ int sa_stream_get_state(sa_stream_t *s, sa_state_t *state); /** Obtain the error code */ int sa_stream_get_event_error(sa_stream_t *s, sa_error_t *error); /** Obtain the notification code */ int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify); /** sync/timing */ int sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos); /* Blocking IO calls */ /** Interleaved capture function */ int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes); /** Interleaved playback function */ int sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes); /** Non-interleaved capture function */ int sa_stream_read_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes); /** Non-interleaved playback function */ int sa_stream_write_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes); /** Interleaved capture function with seek offset */ int sa_stream_pread(sa_stream_t *s, void *data, size_t nbytes, int64_t offset, sa_seek_t whence); /** Interleaved playback function with seek offset */ int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence); /** Non-interleaved capture function with seek offset */ int sa_stream_pread_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes, int64_t offset, sa_seek_t whence); /** Non-interleaved playback function with seek offset */ int sa_stream_pwrite_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence); /** Query how much can be read without blocking */ int sa_stream_get_read_size(sa_stream_t *s, size_t *size); /** Query how much can be written without blocking */ int sa_stream_get_write_size(sa_stream_t *s, size_t *size); /* Control/xrun */ /** Resume playing after a pause */ int sa_stream_resume(sa_stream_t *s); /** Pause audio playback (do not empty the buffer) */ int sa_stream_pause(sa_stream_t *s); /** Block until all audio has been played */ int sa_stream_drain(sa_stream_t *s); /** Return a human readable error */ const char *sa_strerror(int code); #endif