[xiph-commits] r3690 - in browser_plugin/trunk: . src src/audio
j at svn.annodex.net
j at svn.annodex.net
Tue Aug 5 05:21:33 PDT 2008
Author: j
Date: 2008-08-05 05:21:33 -0700 (Tue, 05 Aug 2008)
New Revision: 3690
Modified:
browser_plugin/trunk/configure.ac
browser_plugin/trunk/src/Makefile.am
browser_plugin/trunk/src/audio/sydney_audio.h
browser_plugin/trunk/src/audio/sydney_audio_oss.c
Log:
* add sydney oss backend ported by Jeremy Lea.
* oss can be forced via configure --with-oss
or will be used if alsa is not found
Modified: browser_plugin/trunk/configure.ac
===================================================================
--- browser_plugin/trunk/configure.ac 2008-08-05 12:09:38 UTC (rev 3689)
+++ browser_plugin/trunk/configure.ac 2008-08-05 12:21:33 UTC (rev 3690)
@@ -59,10 +59,30 @@
dnl
dnl Detect alsa
dnl
-PKG_CHECK_MODULES(ALSA, alsa)
+PKG_CHECK_MODULES(ALSA, alsa, HAVE_ALSA=yes)
AC_SUBST(ALSA_CFLAGS)
AC_SUBST(ALSA_LIBS)
+AC_ARG_WITH(oss,
+[ --with-oss Use OSS audio backend],
+[ case "$withval" in
+ no)
+ ;;
+ *)
+ HAVE_ALSA=no
+ ;;
+ esac],
+AC_MSG_RESULT(no)
+)
+
+if test "x$HAVE_ALSA" = "xyes"; then
+ AUDIO_BACKEND=alsa
+else
+ AUDIO_BACKEND=oss
+fi
+
+AM_CONDITIONAL(HAVE_ALSA, test "x$HAVE_ALSA" = "xyes")
+
dnl
dnl Detect Firefox (needed for the linux plugin)
dnl
@@ -260,6 +280,7 @@
Installation paths:
browser_plugin: .................. ${LIBDIR}
+ audio backend: .................. ${AUDIO_BACKEND}
Building:
Modified: browser_plugin/trunk/src/Makefile.am
===================================================================
--- browser_plugin/trunk/src/Makefile.am 2008-08-05 12:09:38 UTC (rev 3689)
+++ browser_plugin/trunk/src/Makefile.am 2008-08-05 12:21:33 UTC (rev 3690)
@@ -2,6 +2,8 @@
EXTRA_DIST= \
audio/sydney_audio_mac.c \
+ audio/sydney_audio_alsa.c \
+ audio/sydney_audio_oss.c \
support/np_mac.cpp \
plugin_gui_mac.c \
plugin_gui_win32.c \
@@ -40,6 +42,13 @@
# Libraries to build
lib_LTLIBRARIES = libnpoggplugin.la libnpoggplugin_static.la
+if HAVE_ALSA
+audio_sources = audio/sydney_audio_alsa.c
+audio_libs = $(ALSA_LIBS)
+else
+audio_sources = audio/sydney_audio_oss.c
+endif
+
libnpoggplugin_la_SOURCES = \
plugin.cpp \
support/nsScriptablePeer.cpp \
@@ -49,12 +58,13 @@
support/npp_gate.cpp \
support/np_entry.cpp \
support/npn_gate.cpp \
- audio/sydney_audio_alsa.c \
+ $(audio_sources) \
plugin_cmml.c
-libnpoggplugin_la_LIBADD = $(X_LIBS) $(OGGPLAY_LIBS) $(ALSA_LIBS) $(IMLIB2_LIBS) $(PTHREAD_LIBS)
+libnpoggplugin_la_LIBADD = $(X_LIBS) $(OGGPLAY_LIBS) $(audio_libs) $(IMLIB2_LIBS) $(PTHREAD_LIBS)
+
libnpoggplugin_static_la_SOURCES = $(libnpoggplugin_la_SOURCES)
-libnpoggplugin_static_la_LIBADD = $(X_LIBS) $(OGGPLAY_STATICLIBS) $(PTHREAD_LIBS) ${ALSA_LIBS}
+libnpoggplugin_static_la_LIBADD = $(X_LIBS) $(OGGPLAY_STATICLIBS) $(PTHREAD_LIBS) $(audio_libs)
EXTRA_libnpoggplugin_la_SOURCES = nsILibOggPlugin.idl
nodist_libnpoggplugin_la_SOURCES = nsILibOggPlugin.h
Modified: browser_plugin/trunk/src/audio/sydney_audio.h
===================================================================
--- browser_plugin/trunk/src/audio/sydney_audio.h 2008-08-05 12:09:38 UTC (rev 3689)
+++ browser_plugin/trunk/src/audio/sydney_audio.h 2008-08-05 12:21:33 UTC (rev 3690)
@@ -16,6 +16,9 @@
#if !defined (WIN32)
#include <sys/param.h>
#include <inttypes.h>
+#if defined(__FreeBSD__)
+#include <sys/endian.h>
+#endif
#else
#include <stddef.h>
#endif
@@ -30,6 +33,12 @@
# elif __BYTE_ORDER == __BIG_ENDIAN
# define SA_BIG_ENDIAN 1
# endif
+#elif defined(_BYTE_ORDER)
+# if _BYTE_ORDER == _LITTLE_ENDIAN
+# define SA_LITTLE_ENDIAN 1
+# elif _BYTE_ORDER == _BIG_ENDIAN
+# define SA_BIG_ENDIAN 1
+# endif
#elif defined(WIN32)
# define SA_LITTLE_ENDIAN 1
#elif defined(__APPLE__)
Modified: browser_plugin/trunk/src/audio/sydney_audio_oss.c
===================================================================
--- browser_plugin/trunk/src/audio/sydney_audio_oss.c 2008-08-05 12:09:38 UTC (rev 3689)
+++ browser_plugin/trunk/src/audio/sydney_audio_oss.c 2008-08-05 12:21:33 UTC (rev 3690)
@@ -16,7 +16,9 @@
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
- * Contributor(s): Marcin Lubonski
+ * Contributor(s): Michael Martin
+ * Chris Double (chris.double at double.co.nz)
+ * Jeremy D. Lea (reg at openpave.org)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -33,608 +35,674 @@
* ***** END LICENSE BLOCK ***** *
*/
-#include "sydney_audio.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/soundcard.h>
-
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include "sydney_audio.h"
-#define SA_READ_PERIOD 0
-#define SA_WRITE_PERIOD 2560 // 40 ms of 16-bit, stereo, 16kHz
-#define SA_READ_BUFFER 0
-#define SA_WRITE_BUFFER 7680 // 3 periods per buffer
-
// for versions newer than 3.6.1
#define OSS_VERSION(x, y, z) (x << 16 | y << 8 | z)
// support only versions newer than 3.6.1
#define SUPP_OSS_VERSION OSS_VERSION(3,6,1)
-#if (SOUND_VERSION >= SUPP_OSS_VERSION)
+#if (SOUND_VERSION < SUPP_OSS_VERSION)
+#error Unsupported OSS Version
+#else
-struct SAAudioHandle_ {
- char *device_name;
- int channels;
- int read_period;
- int write_period;
- int read_buffer;
- int write_buffer;
- sa_pcm_mode_t rw_mode;
- sa_pcm_format_t format;
- int rate;
- int interleaved;
-
- int capture_handle;
- int playback_handle;
- int readN, writeN;
- char *stored;
- int stored_amount;
- int stored_limit;
- //int read_fd, write_fd;
+typedef struct sa_buf sa_buf;
+struct sa_buf {
+ unsigned int size;
+ unsigned int start;
+ unsigned int end;
+ sa_buf * next;
+ unsigned char data[0];
};
-/* Implemented API functions */
-/** Normal way to open PCM device */
-int sa_device_create_pcm(SAAudioHandle **_dev, const char *client_name, sa_pcm_mode_t rw_mode, sa_pcm_format_t format, int rate, int channels);
-/** Initialise the device */
-int sa_device_open(SAAudioHandle *dev);
-/** Close/destroy everything */
-int sa_device_close(SAAudioHandle *dev);
+struct sa_stream {
+ char* output_unit;
+ int output_fd;
+ pthread_t thread_id;
+ pthread_mutex_t mutex;
+ char playing;
+ int64_t bytes_played;
-/* Soft parameter setup - can only be called before calling open*/
-/** Set write buffer lower mark */
-int sa_device_set_write_lower_watermark(SAAudioHandle *dev, int size);
-/** Set read buffer lower mark */
-int sa_device_set_read_lower_watermark(SAAudioHandle *dev, int size);
-/** Set write buffer upper watermark */
-int sa_device_set_write_upper_watermark(SAAudioHandle *dev, int size);
-/** Set read buffer upper watermark */
-int sa_device_set_read_upper_watermark(SAAudioHandle *dev, int size);
+ /* audio format info */
+ unsigned int rate;
+ unsigned int channels;
+ int format;
-/** volume in hundreths of dB's*/
-int sa_device_change_input_volume(SAAudioHandle *dev, const int *vol);
-/** volume in hundreths of dB's*/
-int sa_device_change_output_volume(SAAudioHandle *dev, const int *vol);
+ /* buffer list */
+ sa_buf * bl_head;
+ sa_buf * bl_tail;
+ int n_bufs;
+};
-/** Read audio playback position */
-int sa_device_get_position(SAAudioHandle *dev, sa_pcm_index_t ref, int64_t *pos);
-/* Blocking I/O calls */
-/** Interleaved playback function */
-int sa_device_write(SAAudioHandle *dev, size_t nbytes, const void *data);
+/*
+ * Use a default buffer size with enough room for one second of audio,
+ * assuming stereo data at 44.1kHz with 32 bits per channel, and impose
+ * a generous limit on the number of buffers.
+ */
+#define BUF_SIZE (2 * 44100 * 4)
+#define BUF_LIMIT 5
+#if BUF_LIMIT < 2
+#error BUF_LIMIT must be at least 2!
+#endif
-/* Implementation-specific functions */
-static int oss_audio_format(sa_pcm_format_t sa_format, int* oss_format);
-//static void sa_print_handle_settings(SAAudioHandle* dev);
+static void audio_callback(void* s);
+static sa_buf *new_buffer(void);
+/** Private functions - implementation specific */
+
/*!
- * \brief fills in the SAAudioHandle struct
- * \param SAAudioHandle - encapsulation of a handle to audio device
- * \param client_name -
- * \param rw_mode - requested device access type as in :: sa_pcm_mode_t
- * \param format - audio format as specified in ::sa_pcm_format_t
- * \return - Sydney API error as in ::sa_pcm_error_t
- */
-int sa_device_create_pcm(SAAudioHandle **_dev, const char *client_name, sa_pcm_mode_t rw_mode, sa_pcm_format_t format, int rate, int channels) {
- SAAudioHandle* dev = NULL;
-
- dev = malloc(sizeof(SAAudioHandle));
-
- if (!dev) {
- return SA_DEVICE_OOM;
- }
- dev->channels = channels;
- dev->format = format;
- dev->rw_mode = rw_mode;
- dev->rate = rate;
- dev->readN = 0;
- dev->readN = 0;
- dev->capture_handle = -1;
- dev->playback_handle = -1;
- dev->interleaved = 1;
- dev->read_period = SA_READ_PERIOD;
- dev->write_period = SA_WRITE_PERIOD;
- dev->read_buffer = SA_READ_BUFFER;
- dev->write_buffer = SA_WRITE_BUFFER;
- dev->device_name = "/dev/dsp";
- dev->stored = NULL;
- dev->stored_amount = 0;
- dev->stored_limit = 0;
-
- *_dev = dev;
- //sa_print_handle_settings(dev);
- return SA_DEVICE_SUCCESS;
+ * \brief private function mapping Sudney Audio format to OSS formats
+ * \param format - Sydney Audio API specific format
+ * \param - filled by the function with a value for corresponding OSS format
+ * \return - Sydney API error value as in ::sa_pcm_format_t
+ * */
+static int oss_audio_format(sa_pcm_format_t sa_format, int *fmt) {
+ *fmt = -1;
+ switch (sa_format) {
+ case SA_PCM_FORMAT_U8:
+ *fmt = AFMT_U8;
+ break;
+ case SA_PCM_FORMAT_ULAW:
+ *fmt = AFMT_MU_LAW;
+ break;
+ case SA_PCM_FORMAT_ALAW:
+ *fmt = AFMT_A_LAW;
+ break;
+ /* 16-bit little endian (LE) format */
+ case SA_PCM_FORMAT_S16_LE:
+ *fmt = AFMT_S16_LE;
+ break;
+ /* 16-bit big endian (BE) format */
+ case SA_PCM_FORMAT_S16_BE:
+ *fmt = AFMT_S16_BE;
+ break;
+#if SOUND_VERSION >= OSS_VERSION(4,0,0)
+ /* 24-bit formats (LSB aligned in 32 bit word) */
+ case SA_PCM_FORMAT_S24_LE:
+ *fmt = AFMT_S24_LE;
+ break;
+ /* 24-bit formats (LSB aligned in 32 bit word) */
+ case SA_PCM_FORMAT_S24_BE:
+ *fmt = AFMT_S24_BE;
+ break;
+ /* 32-bit format little endian */
+ case SA_PCM_FORMAT_S32_LE:
+ *fmt = AFMT_S32_LE;
+ break;
+ /* 32-bit format big endian */
+ case SA_PCM_FORMAT_S32_BE:
+ *fmt = AFMT_S32_BE;
+ break;
+#endif
+ default:
+ return SA_ERROR_NOT_SUPPORTED;
+ break;
+ }
+ return SA_SUCCESS;
}
-/*!
- * \brief creates and opens selected audio device
- * \param dev - encapsulated audio device handle
- * \return - Sydney API error as in ::sa_pcm_error_t
+/*
+ * -----------------------------------------------------------------------------
+ * Startup and shutdown functions
+ * -----------------------------------------------------------------------------
*/
-int sa_device_open(SAAudioHandle *dev) {
- int err;
- int fmt;
- int audio_fd = -1;
- if (dev->rw_mode == SA_PCM_WRONLY) {
- // open the default OSS device
- dev->device_name = "/dev/dsp"; // replace with a function which returns audio ouput device best matching the settings
- audio_fd = open(dev->device_name, O_WRONLY, 0);
- if (audio_fd == -1) {
- fprintf(stderr, "Cannot open device: %s\n", dev->device_name);
- //assert(0);
- return SA_DEVICE_OOM;
- }
+int
+sa_stream_create_pcm(
+ sa_stream_t ** _s,
+ const char * client_name,
+ sa_mode_t mode,
+ sa_pcm_format_t format,
+ unsigned int rate,
+ unsigned int channels
+) {
+ sa_stream_t * s = 0;
+ int fmt = 0;
- // set the playback rate
- if ((err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &(dev->rate))) < 0) {
- fprintf(stderr,
- "Error setting the audio playback rate [%d]\n",
- dev->rate);
- //assert(0);
- return SA_DEVICE_OOM;
- }
- // set the channel numbers
- if ((err = ioctl(audio_fd, SNDCTL_DSP_CHANNELS,
- &(dev->channels)))< 0) {
- fprintf(stderr, "Error setting audio channels\n");
- //assert(0);
- return SA_DEVICE_OOM;
- }
- if ((err = oss_audio_format(dev->format, &fmt)) < 0) {
- fprintf(stderr, "Format unknown\n");
- //assert(0);
- return SA_DEVICE_OOM;
- }
- printf("Setting format with value %d\n", fmt);
- if ((err = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &fmt)) < 0 ) {
- fprintf(stderr, "Error setting audio format\n");
- //assert(0);
- return SA_DEVICE_OOM;
- }
+ /*
+ * Make sure we return a NULL stream pointer on failure.
+ */
+ if (_s == NULL) {
+ return SA_ERROR_INVALID;
+ }
+ *_s = NULL;
- dev->playback_handle = audio_fd;
-
- }
- if (dev->rw_mode == SA_PCM_RDONLY) {
- return SA_DEVICE_NOT_SUPPORTED;
- }
- if (dev->rw_mode == SA_PCM_RW) {
- return SA_DEVICE_NOT_SUPPORTED;
- }
- fprintf(stderr, "Audio device opened successfully\n");
- return SA_DEVICE_SUCCESS;
+ if (mode != SA_MODE_WRONLY) {
+ return SA_ERROR_NOT_SUPPORTED;
+ }
+ if (oss_audio_format(format, &fmt) != SA_SUCCESS) {
+ return SA_ERROR_NOT_SUPPORTED;
+ }
+
+ /*
+ * Allocate the instance and required resources.
+ */
+ if ((s = malloc(sizeof(sa_stream_t))) == NULL) {
+ return SA_ERROR_OOM;
+ }
+ if ((s->bl_head = new_buffer()) == NULL) {
+ free(s);
+ return SA_ERROR_OOM;
+ }
+ if (pthread_mutex_init(&s->mutex, NULL) != 0) {
+ free(s->bl_head);
+ free(s);
+ return SA_ERROR_SYSTEM;
+ }
+
+ s->output_unit = "/dev/dsp";
+ s->output_fd = -1;
+ s->thread_id = 0;
+ s->playing = 0;
+ s->bytes_played = 0;
+ s->rate = rate;
+ s->channels = channels;
+ s->format = fmt;
+ s->bl_tail = s->bl_head;
+ s->n_bufs = 1;
+
+ *_s = s;
+ return SA_SUCCESS;
}
-#define WRITE(data,amt) \
- if ((err = write(dev->playback_handle, data, amt)) < 0) { \
- fprintf(stderr, "Error writing data to audio device\n"); \
- return SA_DEVICE_OOM; \
+
+int
+sa_stream_open(sa_stream_t *s) {
+ if (s == NULL) {
+ return SA_ERROR_NO_INIT;
}
+ if (s->output_unit == NULL || s->output_fd != -1) {
+ return SA_ERROR_INVALID;
+ }
-/*!
- * \brief Interleaved write operation
- * \param dev - device handle
- * \param nbytes - size of the audio buffer to be written to device
- * \param data - pointer to the buffer with audio samples
- * \return
- * */
-int sa_device_write(SAAudioHandle *dev, size_t nbytes, const void *_data) {
- int err;
- audio_buf_info info;
- int bytes;
- char * data = (char *)_data;
- /*
- ioctl(dev->playback_handle, SNDCTL_DSP_GETOSPACE, &info);
- printf("fragment size: %d, nfrags: %d, free: %d wtw: %d\n", info.fragsize,
- info.fragstotal, info.bytes, nbytes);
- */
+ // open the default OSS device
+ if ((s->output_fd = open(s->output_unit, O_WRONLY, 0)) == -1) {
+ return SA_ERROR_NO_DEVICE;
+ }
+ // set the playback rate
+ if (ioctl(s->output_fd, SNDCTL_DSP_SPEED, &(s->rate)) < 0) {
+ close(s->output_fd);
+ s->output_fd = -1;
+ return SA_ERROR_NOT_SUPPORTED;
+ }
+ // set the channel numbers
+ if (ioctl(s->output_fd, SNDCTL_DSP_CHANNELS, &(s->channels)) < 0) {
+ close(s->output_fd);
+ s->output_fd = -1;
+ return SA_ERROR_NOT_SUPPORTED;
+ }
- if ((dev->playback_handle) > 0) {
- ioctl(dev->playback_handle, SNDCTL_DSP_GETOSPACE, &info);
- bytes = info.bytes;
- if (dev->stored_amount > bytes) {
- WRITE(dev->stored, bytes);
- memmove(dev->stored, dev->stored + bytes, dev->stored_amount - bytes);
- dev->stored_amount -= bytes;
- } else if (dev->stored_amount > 0) {
- WRITE(dev->stored, dev->stored_amount);
- bytes -= dev->stored_amount;
- dev->stored_amount = 0;
- if (nbytes < bytes) {
- WRITE(data, nbytes);
- return SA_DEVICE_SUCCESS;
- }
- WRITE(data, bytes);
- data += bytes;
- nbytes -= bytes;
- } else {
- if (nbytes < bytes) {
- WRITE(data, nbytes);
- return SA_DEVICE_SUCCESS;
- }
- WRITE(data, bytes);
- data += bytes;
- nbytes -= bytes;
- }
+ if (ioctl(s->output_fd, SNDCTL_DSP_SETFMT, &(s->format)) < 0 ) {
+ close(s->output_fd);
+ s->output_fd = -1;
+ return SA_ERROR_NOT_SUPPORTED;
+ }
- if (nbytes > 0) {
- if (dev->stored_amount + nbytes > dev->stored_limit) {
- dev->stored = realloc(dev->stored, dev->stored_amount + nbytes);
- }
-
- memcpy(dev->stored + dev->stored_amount, data, nbytes);
- dev->stored_amount += nbytes;
- }
- }
- return SA_DEVICE_SUCCESS;
+ return SA_SUCCESS;
}
-#define CLOSE_HANDLE(x) if (x != -1) close(x);
-/*!
- * \brief Closes and destroys allocated resources
- * \param dev - Sydney Audio device handle
- * \return Sydney API error as in ::sa_pcm_error_t
- **/
-int sa_device_close(SAAudioHandle *dev) {
- int err;
+int
+sa_stream_destroy(sa_stream_t *s) {
+ int result = SA_SUCCESS;
- if (dev != NULL) {
+ if (s == NULL) {
+ return SA_SUCCESS;
+ }
- if (dev->stored_amount > 0) {
- WRITE(dev->stored, dev->stored_amount);
- }
+ pthread_mutex_lock(&s->mutex);
- if (dev->stored != NULL) {
- free(dev->stored);
+ /*
+ * This causes the thread sending data to ALSA to stop
+ */
+ s->thread_id = 0;
+
+ /*
+ * Shut down the audio output device.
+ */
+ if (s->output_fd != -1) {
+ if (s->playing && close(s->output_fd) < 0) {
+ result = SA_ERROR_SYSTEM;
}
+ }
- dev->stored = NULL;
- dev->stored_amount = 0;
- dev->stored_limit = 0;
-
- CLOSE_HANDLE(dev->playback_handle);
- CLOSE_HANDLE(dev->capture_handle);
+ pthread_mutex_unlock(&s->mutex);
- printf("Closing audio device\n");
- free(dev);
- }
- return SA_DEVICE_SUCCESS;
-}
+ /*
+ * Release resources.
+ */
+ if (pthread_mutex_destroy(&s->mutex) != 0) {
+ result = SA_ERROR_SYSTEM;
+ }
+ while (s->bl_head != NULL) {
+ sa_buf * next = s->bl_head->next;
+ free(s->bl_head);
+ s->bl_head = next;
+ }
+ free(s);
-/**
- * \brief
- * \param dev
- * \param size
- * \return Sydney API error as in ::sa_pcm_error_t
- */
-int sa_device_set_write_lower_watermark(SAAudioHandle *dev, int size) {
- dev->write_period = size;
- return SA_DEVICE_SUCCESS;
+ return result;
}
-/**
- * \brief
- * \param dev
- * \param size
- * \return Sydney API error as in ::sa_pcm_error_t
- */
-int sa_device_set_read_lower_watermark(SAAudioHandle *dev, int size) {
- dev->read_period = size;
- return SA_DEVICE_SUCCESS;
-}
-/**
- * \brief
- * \param dev
- * \param size
- * \return Sydney API error as in ::sa_pcm_error_t
- */
-int sa_device_set_write_upper_watermark(SAAudioHandle *dev, int size) {
- dev->write_buffer = size;
- return SA_DEVICE_SUCCESS;
-}
-/**
- * \brief
- * \param dev
- * \param size
- * \return Sydney API error as in ::sa_pcm_error_t
+
+
+/*
+ * -----------------------------------------------------------------------------
+ * Data read and write functions
+ * -----------------------------------------------------------------------------
*/
-int sa_device_set_read_upper_watermark(SAAudioHandle *dev, int size) {
- dev->read_buffer = size;
- return SA_DEVICE_SUCCESS;
-}
+int
+sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) {
+ int result = SA_SUCCESS;
-int sa_device_set_xrun_mode(SAAudioHandle *dev, sa_xrun_mode_t mode) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
+ if (s == NULL || s->output_unit == NULL) {
+ return SA_ERROR_NO_INIT;
+ }
+ if (nbytes == 0) {
+ return SA_SUCCESS;
+ }
+ pthread_mutex_lock(&s->mutex);
-int sa_device_set_ni(SAAudioHandle *dev) {
- dev->interleaved = 1;
- return SA_DEVICE_SUCCESS;
-}
+ /*
+ * Append the new data to the end of our buffer list.
+ */
+ while (1) {
+ unsigned int avail = s->bl_tail->size - s->bl_tail->end;
-int sa_device_start_thread(SAAudioHandle *dev, sa_device_callback *callback) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
+ if (nbytes <= avail) {
-int sa_device_set_channel_map(SAAudioHandle *dev, const sa_channel_def_t *map) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
+ /*
+ * The new data will fit into the current tail buffer, so
+ * just copy it in and we're done.
+ */
+ memcpy(s->bl_tail->data + s->bl_tail->end, data, nbytes);
+ s->bl_tail->end += nbytes;
+ break;
+ } else {
-int sa_device_change_device(SAAudioHandle *dev, const char *device_name) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
+ /*
+ * Copy what we can into the tail and allocate a new buffer
+ * for the rest.
+ */
+ memcpy(s->bl_tail->data + s->bl_tail->end, data, avail);
+ s->bl_tail->end += avail;
+ data = ((unsigned char *)data) + avail;
+ nbytes -= avail;
-/*!
- * \brief volume in hundreths of dB's
- * \param dev - device handle
- * \param vol - volume level
- * \return Sydney API error as in ::sa_pcm_error_t
- * */
-int sa_device_change_input_volume(SAAudioHandle *dev, const int *vol) {
-#if SOUND_VERSION >= OSS_VERSION(4,0,0)
- int err;
- if ((err = ioctl(dev->capture_handle, SNDCTL_DSP_SETRECVOL, vol) < 0) {
- fpritnf(stderr, "Error setting new recording volume level\n");
- //assert(0);
- return SA_DEVICE_OOM;
- }
- return SA_DEVICE_SUCCESS;
-#else
- return SA_DEVICE_NOT_SUPPORTED;
+ /*
+ * If we still have data left to copy but we've hit the limit of
+ * allowable buffer allocations, we need to spin for a bit to allow
+ * the audio callback function to slurp some more data up.
+ */
+ if (nbytes > 0 && s->n_bufs == BUF_LIMIT) {
+#ifdef TIMING_TRACE
+ printf("#"); /* too much audio data */
#endif
+ if (!s->playing) {
+ /*
+ * We haven't even started playing yet! That means the
+ * BUF_SIZE/BUF_LIMIT values are too low... Not much we can
+ * do here; spinning won't help because the audio callback
+ * hasn't been enabled yet. Oh well, error time.
+ */
+ printf("Too much audio data received before audio device enabled!\n");
+ result = SA_ERROR_SYSTEM;
+ break;
+ }
+ while (s->n_bufs == BUF_LIMIT) {
+ struct timespec ts = {0, 1000000};
+ pthread_mutex_unlock(&s->mutex);
+ nanosleep(&ts, NULL);
+ pthread_mutex_lock(&s->mutex);
+ }
+ }
+
+ /*
+ * Allocate a new tail buffer, and go 'round again to fill it up.
+ */
+ if ((s->bl_tail->next = new_buffer()) == NULL) {
+ result = SA_ERROR_OOM;
+ break;
+ }
+ s->n_bufs++;
+ s->bl_tail = s->bl_tail->next;
+
+ } /* if (nbytes <= avail), else */
+
+ } /* while (1) */
+
+ pthread_mutex_unlock(&s->mutex);
+
+ /*
+ * Once we have our first block of audio data, enable the audio callback
+ * function. This doesn't need to be protected by the mutex, because
+ * s->playing is not used in the audio callback thread, and it's probably
+ * better not to be inside the lock when we enable the audio callback.
+ */
+ if (!s->playing) {
+ s->playing = 1;
+ if (pthread_create(&s->thread_id, NULL, (void *)audio_callback, s) != 0) {
+ result = SA_ERROR_SYSTEM;
+ }
+ }
+
+ return result;
}
-/*!
- * \brief volume in hundreths of dB's
- * \param dev - device handle
- * \param vol - volume level
- * \retrun Sydney API error as in ::sa_pcm_error_t
- * */
-int sa_device_change_output_volume(SAAudioHandle *dev, const int *vol) {
-#if SOUND_VERSION >= OSS_VERSION(4,0,0)
- int err;
- if ((err = ioctl(dev->playback_handle, SNDCTL_DSP_SETPLAYVOL, vol) < 0){
- fprintf(stderr, "Error setting new playback volume\n");
- //assert(0);
- return SA_DEVICE_OOM;
- }
- return SA_DEVICE_SUCCESS;
-#else
- return SA_DEVICE_NOT_SUPPORTED;
+static void audio_callback(void* data)
+{
+ sa_stream_t* s = (sa_stream_t*)data;
+ audio_buf_info info;
+ char* buffer = 0;
+ unsigned int avail;
+ int frames;
+
+#ifdef TIMING_TRACE
+ printf("."); /* audio read 'tick' */
#endif
-}
-int sa_device_change_sampling_rate(SAAudioHandle *dev, int rate) {
- dev->rate = rate;
- return SA_DEVICE_SUCCESS;
-}
+ ioctl(s->output_fd, SNDCTL_DSP_GETOSPACE, &info);
+ buffer = malloc(info.bytes);
+
+ while(1) {
+ char* dst = buffer;
+ unsigned int bytes_to_copy = info.bytes;
-int sa_device_change_client_name(SAAudioHandle *dev, const char *client_name) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
+ pthread_mutex_lock(&s->mutex);
+ if (!s->thread_id)
+ break;
-int sa_device_change_stream_name(SAAudioHandle *dev, const char *stream_name) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
+ /*
+ * Consume data from the start of the buffer list.
+ */
+ while (1) {
+ assert(s->bl_head->start <= s->bl_head->end);
+ avail = s->bl_head->end - s->bl_head->start;
-int sa_device_change_user_data(SAAudioHandle *dev, void *val) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
+ if (avail >= bytes_to_copy) {
+ /*
+ * We have all we need in the head buffer, so just grab it and go.
+ */
+ memcpy(dst, s->bl_head->data + s->bl_head->start, bytes_to_copy);
+ s->bl_head->start += bytes_to_copy;
+ s->bytes_played += bytes_to_copy;
+ break;
+ } else {
-/*!
- * \brief
- * \param dev
- * \param rate
- * \param direction
- * \return Sydney API error as in ::sa_pcm_error_t
- * */
-int sa_device_adjust_rate(SAAudioHandle *dev, int rate, int direction) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
-/*!
- * \brief
- * \param dev
- * \param nb_channels
- * \return Sydney API error as in ::sa_pcm_error_t
- * */
-int sa_device_adjust_channels(SAAudioHandle *dev, int nb_channels) { return SA_DEVICE_NOT_SUPPORTED;
-}
-/** Adjust bit sample format */
-int sa_device_adjust_format(SAAudioHandle *dev, sa_pcm_format_t format, int direction) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
+ sa_buf* next = 0;
+ /*
+ * Copy what we can from the head and move on to the next buffer.
+ */
+ memcpy(dst, s->bl_head->data + s->bl_head->start, avail);
+ s->bl_head->start += avail;
+ dst += avail;
+ bytes_to_copy -= avail;
+ s->bytes_played += avail;
-/** Get current state of the audio device */
-int sa_device_get_state(SAAudioHandle *dev, sa_state_t *running) {
- return SA_DEVICE_NOT_SUPPORTED;
+ /*
+ * We want to free the now-empty buffer, but not if it's also the
+ * current tail. If it is the tail, we don't have enough data to fill
+ * the destination buffer, so we'll just zero it out and give up.
+ */
+ next = s->bl_head->next;
+ if (next == NULL) {
+#ifdef TIMING_TRACE
+ printf("!"); /* not enough audio data */
+#endif
+ memset(dst, 0, bytes_to_copy);
+ break;
+ }
+ free(s->bl_head);
+ s->bl_head = next;
+ s->n_bufs--;
+
+ } /* if (avail >= bytes_to_copy), else */
+
+ } /* while (1) */
+
+ pthread_mutex_unlock(&s->mutex);
+
+ frames = write(s->output_fd, buffer, info.bytes);
+ if (frames < 0) {
+ printf("error writing to sound device\n");
+ }
+ if (frames >= 0 && frames != info.bytes) {
+ printf("short write (expected %d, wrote %d)\n", (int)info.bytes, (int)frames);
+ }
+ }
+ free(buffer);
}
-/** Get current sampling rate */
-int sa_device_get_sampling_rate(SAAudioHandle *dev, int *rate) {
- return SA_DEVICE_NOT_SUPPORTED;
-}
-/** Get number of channels */
-int sa_device_get_nb_channels(SAAudioHandle *dev, int *nb_channels) {
- return SA_DEVICE_NOT_SUPPORTED;
+
+/*
+ * -----------------------------------------------------------------------------
+ * General query and support functions
+ * -----------------------------------------------------------------------------
+ */
+
+int
+sa_stream_get_write_size(sa_stream_t *s, size_t *size) {
+ sa_buf * b;
+ size_t used = 0;
+
+ if (s == NULL || s->output_unit == NULL) {
+ return SA_ERROR_NO_INIT;
+ }
+
+ pthread_mutex_lock(&s->mutex);
+
+ /*
+ * Sum up the used portions of our buffers and subtract that from
+ * the pre-defined max allowed allocation.
+ */
+ for (b = s->bl_head; b != NULL; b = b->next) {
+ used += b->end - b->start;
+ }
+ *size = BUF_SIZE * BUF_LIMIT - used;
+
+ pthread_mutex_unlock(&s->mutex);
+ return SA_SUCCESS;
}
-/** Get format being used */
-int sa_device_get_format(SAAudioHandle *dev, sa_pcm_format_t *format) {
- return SA_DEVICE_NOT_SUPPORTED;
+
+int
+sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
+
+ if (s == NULL || s->output_unit == NULL) {
+ return SA_ERROR_NO_INIT;
+ }
+ if (position != SA_POSITION_WRITE_SOFTWARE) {
+ return SA_ERROR_NOT_SUPPORTED;
+ }
+
+ pthread_mutex_lock(&s->mutex);
+ *pos = s->bytes_played;
+ pthread_mutex_unlock(&s->mutex);
+ return SA_SUCCESS;
}
-/** Get opaque pointer associated to the device */
-int sa_device_get_user_data(SAAudioHandle *dev, void **val) {
- return SA_DEVICE_NOT_SUPPORTED;
+
+int
+sa_stream_pause(sa_stream_t *s) {
+
+ if (s == NULL || s->output_unit == NULL) {
+ return SA_ERROR_NO_INIT;
+ }
+
+ pthread_mutex_lock(&s->mutex);
+#if 0 /* TODO */
+ AudioOutputUnitStop(s->output_unit);
+#endif
+ pthread_mutex_unlock(&s->mutex);
+ return SA_SUCCESS;
}
-/** Obtain the error code */
-int sa_device_get_event_error(SAAudioHandle *dev, sa_pcm_error_t *error) {
- return SA_DEVICE_NOT_SUPPORTED;
+
+int
+sa_stream_resume(sa_stream_t *s) {
+
+ if (s == NULL || s->output_unit == NULL) {
+ return SA_ERROR_NO_INIT;
+ }
+
+ pthread_mutex_lock(&s->mutex);
+
+ /*
+ * The audio device resets its mSampleTime counter after pausing,
+ * so we need to clear our tracking value to keep that in sync.
+ */
+ s->bytes_played = 0;
+#if 0 /* TODO */
+ AudioOutputUnitStart(s->output_unit);
+#endif
+ pthread_mutex_unlock(&s->mutex);
+ return SA_SUCCESS;
}
-/** Obtain the notification code */
-int sa_device_get_event_notify(SAAudioHandle *dev, sa_pcm_notification_t *notify) {
- return SA_DEVICE_NOT_SUPPORTED;
+
+static sa_buf *
+new_buffer(void) {
+ sa_buf * b = malloc(sizeof(sa_buf) + BUF_SIZE);
+ if (b != NULL) {
+ b->size = BUF_SIZE;
+ b->start = 0;
+ b->end = 0;
+ b->next = NULL;
+ }
+ return b;
}
-/*!
- * \brief returns the current position of the audio playback capture
- * \param dev - device handle
- * \param ref - type of position to be returned by this function see ::sa_pcm_index_t
- * \param pos - position (in bytes or ms depending on 'ref' value)
- * \return Sydney API error as in ::sa_pcm_error_t
- * */
-int sa_device_get_position(SAAudioHandle *dev, sa_pcm_index_t ref, int64_t *pos)
-{
- int err;
- int64_t _pos;
- int delay;
- count_info ptr;
- switch (ref) {
- case SA_PCM_WRITE_DELAY:
- //int delay;
- if ((err = ioctl(dev->playback_handle,
- SNDCTL_DSP_GETODELAY,
- &delay)) <0) {
- fprintf(stderr, "Error reading playback buffering delay\n");
- return SA_DEVICE_OOM;
- };
- _pos = (int64_t)delay;
- break;
- case SA_PCM_WRITE_SOFTWARE_POS:
- //count_info ptr;
- if ((err = ioctl(dev->playback_handle,
- SNDCTL_DSP_GETOPTR,
- &ptr)) <0) {
- //fprintf(stderr, "Error reading audio playback position\n");
- return SA_DEVICE_OOM;
- };
- _pos = (int64_t)ptr.bytes;
- break;
- case SA_PCM_READ_SOFTWARE_POS:
- //count_info ptr;
- if ((err = ioctl(dev->playback_handle,
- SNDCTL_DSP_GETIPTR,
- &ptr)) <0) {
- fprintf(stderr, "Error reading audio capture position\n");
- return SA_DEVICE_OOM;
- };
- _pos = (int64_t)ptr.bytes;
- break;
- case SA_PCM_READ_DELAY:
- case SA_PCM_READ_HARDWARE_POS:
- case SA_PCM_WRITE_HARDWARE_POS:
- case SA_PCM_DUPLEX_DELAY:
- default:
- return SA_DEVICE_NOT_SUPPORTED;
- break;
- }
- (*pos) = _pos;
- return SA_DEVICE_SUCCESS;
+
+/*
+ * -----------------------------------------------------------------------------
+ * Extension functions
+ * -----------------------------------------------------------------------------
+ */
+
+int
+sa_stream_set_volume_abs(sa_stream_t *s, float vol) {
+ if (s == NULL || s->output_fd == -1) {
+ return SA_ERROR_NO_INIT;
+ }
+#if SOUND_VERSION >= OSS_VERSION(4,0,0)
+ int mvol = ((int)(100*vol)) | ((int)(100*vol) << 8);
+ if (ioctl(s->output_fd, SNDCTL_DSP_SETPLAYVOL, &mvol) < 0){
+ return SA_ERROR_SYSTEM;
+ }
+ return SA_SUCCESS;
+#else
+ return SA_ERROR_NOT_SUPPORTED;
+#endif
}
-/** Private functions - implementation specific */
-/*!
- * \brief private function mapping Sudney Audio format to OSS formats
- * \param format - Sydney Audio API specific format
- * \param - filled by the function with a value for corresponding OSS format
- * \return - Sydney API error value as in ::sa_pcm_format_t
- * */
-static int oss_audio_format(sa_pcm_format_t sa_format, int* oss_format) {
-#if SOUND_VERSION >= OSS_VERSION(4,0,0)
- int fmt = AFMT_UNDEF;
+int
+sa_stream_get_volume_abs(sa_stream_t *s, float *vol) {
+
+ if (vol == NULL) {
+ return SA_ERROR_INVALID;
+ }
+ *vol = 0.0f;
+ if (s == NULL || s->output_fd == -1) {
+ return SA_ERROR_NO_INIT;
+ }
+#if SOUND_VERSION >= OSS_VERSION(4,0,0)
+ int mvol;
+ if (ioctl(s->output_fd, SNDCTL_DSP_SETPLAYVOL, &mvol) < 0){
+ return SA_ERROR_SYSTEM;
+ }
+ *vol = ((mvol & 0xFF) + (mvol >> 8)) / 200.0f;
+ return SA_SUCCESS;
#else
- int fmt = -1;
-#endif
- switch (sa_format) {
- case SA_PCM_UINT8:
- fmt = AFMT_U8;
- break;
- case SA_PCM_ULAW:
- fmt = AFMT_MU_LAW;
- break;
- case SA_PCM_ALAW:
- fmt = AFMT_A_LAW;
- break;
- /* 16-bit little endian (LE) format */
- case SA_PCM_S16_LE:
- fmt = AFMT_S16_LE;
- break;
- /* 16-bit big endian (BE) format */
- case SA_PCM_S16_BE:
- fmt = AFMT_S16_BE;
- break;
-#if SOUND_VERSION >= OSS_VERSION(4,0,0)
- /* 24-bit formats (LSB aligned in 32 bit word) */
- case SA_PCM_S24_LE:
- fmt = AFMT_S24_LE;
- break;
- /* 24-bit formats (LSB aligned in 32 bit word) */
- case SA_PCM_S24_BE:
- fmt = AFMT_S24_BE;
- break;
- /* 32-bit format little endian */
- case SA_PCM_S32_LE:
- fmt = AFMT_S32_LE;
- break;
- /* 32-bit format big endian */
- case SA_PCM_S32_BE:
- fmt = AFMT_S32_BE;
- break;
- case SA_PCM_FLOAT32_NE:
- fmt = AFMT_FLOAT;
- break;
+ return SA_ERROR_NOT_SUPPORTED;
#endif
- default:
- return SA_DEVICE_NOT_SUPPORTED;
- break;
-
- }
- (*oss_format) = fmt;
- return SA_DEVICE_SUCCESS;
}
+
+
/*
-static void sa_print_handle_settings(SAAudioHandle* dev) {
- printf(">>>>>>>>>>>> SA Device Handle <<<<<<<<<<<\n");
- printf("[SA Audio] - Device name %s\n", dev->device_name);
- printf("[SA_Audio] - Number of audio channels %d\n", dev->channels);
- printf("[SA_Audio] - Read period size %d bytes\n", dev->read_period);
- printf("[SA_Audio] - Write period size %d bytes\n", dev->write_period);
- printf("[SA_Audio] - Write buffer size %d bytes\n", dev->write_buffer);
- printf("[SA_Audio] - Read buffer size %d bytes\n", dev->read_buffer);
- printf("[SA_Audio] - Read/write mode value %d\n", dev->rw_mode);
- printf("[SA_Audio] - Audio sample bit format value %d\n", dev->format);
- printf("[SA_Audio] - Audio playback rate %d\n", dev->rate);
- if (dev->interleaved) {
- printf("[SA_Audio] - Processing interleaved audio\n");
- } else {
- printf("[SA_Audio] - Processing non-interleaved audio\n");
- }
- if ((dev->capture_handle) > 0) {
- printf("[SA Audio] - Device opened for capture\n");
- }
- if ((dev->playback_handle) > 0) {
- printf("[SA_Audio] - Device opened for playback\n");
- }
-}
-*/
+ * -----------------------------------------------------------------------------
+ * Unsupported functions
+ * -----------------------------------------------------------------------------
+ */
+#define UNSUPPORTED(func) func { return SA_ERROR_NOT_SUPPORTED; }
-#endif // (SOUND_VERSION > SUPP_OSS_VERSION)
+UNSUPPORTED(int sa_stream_create_opaque(sa_stream_t **s, const char *client_name, sa_mode_t mode, const char *codec))
+UNSUPPORTED(int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size))
+UNSUPPORTED(int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size))
+UNSUPPORTED(int sa_stream_set_write_upper_watermark(sa_stream_t *s, size_t size))
+UNSUPPORTED(int sa_stream_set_read_upper_watermark(sa_stream_t *s, size_t size))
+UNSUPPORTED(int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t map[], unsigned int n))
+UNSUPPORTED(int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode))
+UNSUPPORTED(int sa_stream_set_non_interleaved(sa_stream_t *s, int enable))
+UNSUPPORTED(int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable))
+UNSUPPORTED(int sa_stream_set_driver(sa_stream_t *s, const char *driver))
+UNSUPPORTED(int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t callback))
+UNSUPPORTED(int sa_stream_stop_thread(sa_stream_t *s))
+UNSUPPORTED(int sa_stream_change_device(sa_stream_t *s, const char *device_name))
+UNSUPPORTED(int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned int n))
+UNSUPPORTED(int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned int n))
+UNSUPPORTED(int sa_stream_change_rate(sa_stream_t *s, unsigned int rate))
+UNSUPPORTED(int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size))
+UNSUPPORTED(int sa_stream_change_user_data(sa_stream_t *s, const void *value))
+UNSUPPORTED(int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction))
+UNSUPPORTED(int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction))
+UNSUPPORTED(int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction))
+UNSUPPORTED(int sa_stream_set_adjust_watermarks(sa_stream_t *s, sa_adjust_t direction))
+UNSUPPORTED(int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode))
+UNSUPPORTED(int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size))
+UNSUPPORTED(int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *format))
+UNSUPPORTED(int sa_stream_get_rate(sa_stream_t *s, unsigned int *rate))
+UNSUPPORTED(int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels))
+UNSUPPORTED(int sa_stream_get_user_data(sa_stream_t *s, void **value))
+UNSUPPORTED(int sa_stream_get_write_lower_watermark(sa_stream_t *s, size_t *size))
+UNSUPPORTED(int sa_stream_get_read_lower_watermark(sa_stream_t *s, size_t *size))
+UNSUPPORTED(int sa_stream_get_write_upper_watermark(sa_stream_t *s, size_t *size))
+UNSUPPORTED(int sa_stream_get_read_upper_watermark(sa_stream_t *s, size_t *size))
+UNSUPPORTED(int sa_stream_get_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned int *n))
+UNSUPPORTED(int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode))
+UNSUPPORTED(int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled))
+UNSUPPORTED(int sa_stream_get_dynamic_rate(sa_stream_t *s, int *enabled))
+UNSUPPORTED(int sa_stream_get_driver(sa_stream_t *s, char *driver_name, size_t *size))
+UNSUPPORTED(int sa_stream_get_device(sa_stream_t *s, char *device_name, size_t *size))
+UNSUPPORTED(int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned int *n))
+UNSUPPORTED(int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned int *n))
+UNSUPPORTED(int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void*data, size_t *size))
+UNSUPPORTED(int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction))
+UNSUPPORTED(int sa_stream_get_adjust_nchannels(sa_stream_t *s, sa_adjust_t *direction))
+UNSUPPORTED(int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction))
+UNSUPPORTED(int sa_stream_get_adjust_watermarks(sa_stream_t *s, sa_adjust_t *direction))
+UNSUPPORTED(int sa_stream_get_state(sa_stream_t *s, sa_state_t *state))
+UNSUPPORTED(int sa_stream_get_event_error(sa_stream_t *s, sa_error_t *error))
+UNSUPPORTED(int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify))
+UNSUPPORTED(int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes))
+UNSUPPORTED(int sa_stream_read_ni(sa_stream_t *s, unsigned int channel, void *data, size_t nbytes))
+UNSUPPORTED(int sa_stream_write_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes))
+UNSUPPORTED(int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))
+UNSUPPORTED(int sa_stream_pwrite_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))
+UNSUPPORTED(int sa_stream_get_read_size(sa_stream_t *s, size_t *size))
+UNSUPPORTED(int sa_stream_drain(sa_stream_t *s))
+
+const char *sa_strerror(int code) { return NULL; }
+
+#endif
More information about the commits
mailing list