[xiph-commits] r2893 - liboggplay/trunk/plugin/audio
laser13 at svn.annodex.net
laser13 at svn.annodex.net
Tue Jun 12 03:33:07 PDT 2007
Author: laser13
Date: 2007-06-12 03:33:07 -0700 (Tue, 12 Jun 2007)
New Revision: 2893
Modified:
liboggplay/trunk/plugin/audio/sydney_audio_mac.c
liboggplay/trunk/plugin/audio/sydney_audio_new.h
liboggplay/trunk/plugin/audio/sydney_audio_waveapi.c
Log:
Added implementation of the new Sydney audio API on Windows. Small modifications of the API to compile on Win32. Modified all 'unsigned' entries in the API to 'unsigned int'.
Modified: liboggplay/trunk/plugin/audio/sydney_audio_mac.c
===================================================================
--- liboggplay/trunk/plugin/audio/sydney_audio_mac.c 2007-06-12 10:25:40 UTC (rev 2892)
+++ liboggplay/trunk/plugin/audio/sydney_audio_mac.c 2007-06-12 10:33:07 UTC (rev 2893)
@@ -113,8 +113,8 @@
const char * client_name,
sa_mode_t mode,
sa_pcm_format_t format,
- unsigned rate,
- unsigned n_channels
+ unsigned int rate,
+ unsigned int n_channels
) {
/*
@@ -537,7 +537,7 @@
int
-sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned n) {
+sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned int n) {
//!todo
if (s == NULL || s->output_unit == NULL) {
return SA_ERROR_NO_INIT;
@@ -569,7 +569,7 @@
int
-sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned *n) {
+sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned int *n) {
//!todo
if (s == NULL || s->output_unit == NULL) {
return SA_ERROR_NO_INIT;
@@ -648,7 +648,7 @@
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 n))
+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))
@@ -656,8 +656,8 @@
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 n))
-UNSUPPORTED(int sa_stream_change_rate(sa_stream_t *s, unsigned rate))
+UNSUPPORTED(int sa_stream_change_read_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))
@@ -667,20 +667,20 @@
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 *rate))
+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 *n))
+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 *n))
+UNSUPPORTED(int sa_stream_get_read_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))
@@ -690,10 +690,10 @@
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 channel, void *data, size_t nbytes))
-UNSUPPORTED(int sa_stream_write_ni(sa_stream_t *s, unsigned channel, const 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 channel, 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))
Modified: liboggplay/trunk/plugin/audio/sydney_audio_new.h
===================================================================
--- liboggplay/trunk/plugin/audio/sydney_audio_new.h 2007-06-12 10:25:40 UTC (rev 2892)
+++ liboggplay/trunk/plugin/audio/sydney_audio_new.h 2007-06-12 10:33:07 UTC (rev 2893)
@@ -13,8 +13,10 @@
*/
#include <sys/types.h>
+#if !defined (WIN32)
#include <sys/param.h>
#include <inttypes.h>
+#endif
/* Detect byte order, based on sys/param.h */
#undef SA_LITTLE_ENDIAN
@@ -38,10 +40,24 @@
# error "Cannot determine byte order!"
#endif
+#if defined(WIN32)
+#if !defined(int32_t)
+typedef __int32 int32_t;
+#endif
+#if !defined(int64_t)
+typedef __int64 int64_t;
+#endif
+#endif
+
typedef struct sa_stream sa_stream_t;
+#if defined(WIN32)
+// (left << 16 | right) (16 bits per channel)
+#define SA_VOLUME_MUTED ((int32_t) (0x00000000))
+#else
/** Volume that corresponds to muted in/out */
#define SA_VOLUME_MUTED ((int32_t) (-0x80000000))
+#endif
/** Ways to express seek offsets for pread/pwrite */
typedef enum {
@@ -251,7 +267,7 @@
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);
+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 nchannels);
/** Initialise the device */
int sa_stream_open(sa_stream_t *s);
@@ -266,7 +282,7 @@
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);
+int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t map[], unsigned int n);
/** Whether xruns cause the card to reset */
int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode);
@@ -290,13 +306,13 @@
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);
+int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned int n);
/** volume in hundreths of dB*/
-int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned n);
+int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned int n);
/** Change the sampling rate */
-int sa_stream_change_rate(sa_stream_t *s, unsigned rate);
+int sa_stream_change_rate(sa_stream_t *s, unsigned int 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);
@@ -315,21 +331,21 @@
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_rate(sa_stream_t *s, unsigned int *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_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned int *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_read_volume(sa_stream_t *s, int32_t vol[], unsigned int *n);
+int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned int *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);
@@ -354,16 +370,16 @@
/** Interleaved capture function */
int sa_stream_read(sa_stream_t *s, 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);
+int sa_stream_read_ni(sa_stream_t *s, unsigned int channel, void *data, size_t nbytes);
/** Interleaved playback function */
int sa_stream_write(sa_stream_t *s, const 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);
+int sa_stream_write_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes);
/** 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 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);
+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);
/** Query how much can be read without blocking */
Modified: liboggplay/trunk/plugin/audio/sydney_audio_waveapi.c
===================================================================
--- liboggplay/trunk/plugin/audio/sydney_audio_waveapi.c 2007-06-12 10:25:40 UTC (rev 2892)
+++ liboggplay/trunk/plugin/audio/sydney_audio_waveapi.c 2007-06-12 10:33:07 UTC (rev 2893)
@@ -33,158 +33,619 @@
* ***** END LICENSE BLOCK ***** *
*/
-#include "sydney_audio.h"
+#include "sydney_audio_new.h"
#include <stdio.h>
#include <stdlib.h>
-#if (SOUND_VERSION >= SUPP_OSS_VERSION)
+#include <windows.h>
+#include <mmreg.h>
+#include <math.h>
-/** Create an opaque (e.g. AC3) codec stream */
-int sa_device_create_opaque(SAAudioHandle **dev, const char *client_name, sa_pcm_mode_t rw_mode, const char *codec) {
- *dev = NULL;
- return SA_DEVICE_NOT_SUPPORTED;
-}
+// FIX ME: block size and block should be determined based on the OggPlay offset
+// for audio track
+#define BLOCK_SIZE 2560
+#define BLOCK_COUNT 4
+#define DEFAULT_DEVICE_NAME "Default WAVE Device"
+#define DEFAULT_DEVICE WAVE_MAPPER
+
+#define VERBOSE_OUTPUT 1
+
+// INFO: if you get weird compile errors make sure there is no extra chars pass '\'
+#if defined(VERBOSE_OUTPUT)
+#define WAVE_ERROR_VERBOSE(error, message) \
+ switch (error) { \
+ case MMSYSERR_ALLOCATED: \
+ printf("[WAVE API] Device allocation error returned while executing %s\n", message); \
+ break; \
+ case MMSYSERR_BADDEVICEID: \
+ printf("[WAVE API] Wrong device ID error returned while executing %s\n", message); \
+ break; \
+ case MMSYSERR_NODRIVER: \
+ printf("[WAVE API] System driver not present error returned while executing %s\n", message); \
+ break; \
+ case MMSYSERR_INVALHANDLE: \
+ printf("[WAVE API] Invalid device handle error returned while executing %s\n", message); \
+ break; \
+ case MMSYSERR_NOMEM: \
+ printf("[WAVE API] No memory error returned while executing %s\n", message); \
+ break; \
+ case MMSYSERR_NOTSUPPORTED: \
+ printf("[WAVE API] Not supported error returned while executing %s\n", message); \
+ break; \
+ case WAVERR_BADFORMAT: \
+ printf("[WAVE API] Not valid audio format returned while executing %s\n", message); \
+ break; \
+ case WAVERR_SYNC: \
+ printf("[WAVE API] Device synchronous error returned while executing %s\n", message); \
+ break; \
+ default: \
+ printf("[WAVE API] Error while executing %s\n", message); \
+ break; \
+ }
+#else
+#define WAVE_ERROR_VERBOSE(error, message) \
+ do {} while(0)
+#endif
+
+#define HANDLE_WAVE_ERROR(status, location) \
+ if (status != MMSYSERR_NOERROR) { \
+ WAVE_ERROR_VERBOSE(status, location); \
+ return getSAErrorCode(status); \
+ }
+
+#define ERROR_IF_NO_INIT(handle) \
+ if (handle == NULL) { \
+ return SA_ERROR_NO_INIT; \
+ }
+
+/* local implementation of the sa_stream_t type */
+struct sa_stream {
+ char* deviceName;
+ UINT device;
+ UINT channels;
+ UINT rate;
+
+ sa_mode_t rwMode;
+ sa_pcm_format_t format;
+
+ HWAVEOUT hWaveOut;
+ HANDLE callbackEvent;
+ CRITICAL_SECTION waveCriticalSection;
+ WAVEHDR* waveBlocks;
+ volatile int waveFreeBlockCount;
+ int waveCurrentBlock;
+};
+
+
+/** Forward definitions of audio api specific functions */
+int allocateBlocks(int size, int count, WAVEHDR** blocks);
+int freeBlocks(WAVEHDR* blocks);
+int openAudio(sa_stream_t *s);
+int closeAudio(sa_stream_t * s);
+int writeAudio(sa_stream_t *s, LPSTR data, int bytes);
+int getSAErrorCode(int waveErrorCode);
+
+void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
+
+/** Main callback function */
+typedef int (*sa_event_callback_t)(sa_stream_t *s, sa_event_t event);
+
+
/** Normal way to open a 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) {
+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 nchannels) {
+ sa_stream_t * _s = NULL;
+
+ ERROR_IF_NO_INIT(s);
+
+ *s = NULL;
+
+ /* FIX ME: for formats different than PCM extend using WAVEFORMATEXTENSIBLE */
+ if (format != SA_PCM_FORMAT_S16_NE) {
+ return SA_ERROR_NOT_SUPPORTED;
+ }
+
+ if (mode != SA_MODE_WRONLY) {
+ return SA_ERROR_NOT_SUPPORTED;
+ }
+
+ if ((_s = (sa_stream_t*)malloc(sizeof(sa_stream_t))) == NULL) {
+ return SA_ERROR_OOM;
+ }
+
+ _s->rwMode = mode;
+ _s->format = format;
+ _s->rate = rate;
+ _s->channels = nchannels;
+ _s->deviceName = DEFAULT_DEVICE_NAME;
+ _s->device = DEFAULT_DEVICE;
+
+ *s = _s;
+ return SA_SUCCESS;
}
/** Initialise the device */
-int sa_device_open(SAAudioHandle *dev) {
+int sa_stream_open(sa_stream_t *s) {
+ int status = SA_SUCCESS;
+
+ ERROR_IF_NO_INIT(s);
+
+ switch (s->rwMode) {
+ case SA_MODE_WRONLY:
+ status = openAudio(s);
+ break;
+ default:
+ status = SA_ERROR_NOT_SUPPORTED;
+ break;
+ }
+ return status;
}
+/** Interleaved playback function */
+int sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) {
+ int status = SA_SUCCESS;
+
+ ERROR_IF_NO_INIT(s);
+
+ status = writeAudio(s, (LPSTR)data, nbytes);
+
+ return status;
+}
+
/** Close/destroy everything */
-int sa_device_close(SAAudioHandle *dev) {
+int sa_stream_destroy(sa_stream_t *s) {
+ int status;
+
+ ERROR_IF_NO_INIT(s);
+ /* close and release all allocated resources */
+ status = closeAudio(s);
+
+ return status;
}
+/** volume in hundreths of dB*/
+int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned int *n) {
+ ERROR_IF_NO_INIT(s);
-/* Init time "Soft" params (can only be set before calling open)
- * lower_watermark - buffer level, below which the buffer should not
- * the write operations
- * should block
- * */
+ return SA_SUCCESS;
-int sa_device_set_write_lower_watermark(SAAudioHandle *dev, int size);
-int sa_device_set_read_lower_watermark(SAAudioHandle *dev, int size);
+}
-int sa_device_set_write_upper_watermark(SAAudioHandle *dev, int size);
-int sa_device_set_read_upper_watermark(SAAudioHandle *dev, int size);
+/** volume in hundreths of dB*/
+int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned int n) {
+ ERROR_IF_NO_INIT(s);
-/** Whether xruns cause the card to reset */
-int sa_device_set_xrun_mode(SAAudioHandle *dev, sa_xrun_mode_t mode);
+ return SA_SUCCESS;
-/** Set the device to non-interleaved mode */
-int sa_device_set_ni(SAAudioHandle *dev);
+}
-/** Start callback */
-int sa_device_start_thread(SAAudioHandle *dev, sa_device_callback *callback);
+/** sync/timing */
+int sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
+ int status;
+ MMTIME mm;
+ ERROR_IF_NO_INIT(s);
-/** Set the mapping between channels and the loudspeakers */
-int sa_device_set_channel_map(SAAudioHandle *dev, const sa_channel_def_t *map);
+ if (position != SA_POSITION_WRITE_HARDWARE) {
+ return SA_ERROR_NOT_SUPPORTED;
+ }
+ // request playback progress in bytes
+ mm.wType = TIME_BYTES;
+ status = waveOutGetPosition(s->hWaveOut, &mm, sizeof(MMTIME));
+ HANDLE_WAVE_ERROR(status, "reading audio buffer position");
+ *pos = (int64_t)mm.u.cb;
-/* "Soft" params that can be changed at any time */
+ return SA_SUCCESS;
+}
-/** Change the device connected to the stream */
-int sa_device_change_device(SAAudioHandle *dev, const char *device_name);
+/* Control/xrun */
+/** Resume playing after a pause */
+int sa_stream_resume(sa_stream_t *s) {
+ int status;
+
+ ERROR_IF_NO_INIT(s);
+ status = waveOutRestart(s->hWaveOut);
+ HANDLE_WAVE_ERROR(status, "resuming audio playback");
-/** volume in hundreths of dB's*/
-int sa_device_change_input_volume(SAAudioHandle *dev, const int *vol);
+ return SA_SUCCESS;
+}
+/** Pause audio playback (do not empty the buffer) */
+int sa_stream_pause(sa_stream_t *s) {
+ int status;
-/** volume in hundreths of dB's*/
-int sa_device_change_output_volume(SAAudioHandle *dev, const int *vol);
+ ERROR_IF_NO_INIT(s);
+
+ status = waveOutPause(s->hWaveOut);
+ HANDLE_WAVE_ERROR(status, "resuming audio playback");
-/** Change the sampling rate */
-int sa_device_change_sampling_rate(SAAudioHandle *dev, int rate);
+ return SA_SUCCESS;
+}
-/** Change the name of the client application using the device */
-int sa_device_change_client_name(SAAudioHandle *dev, const char *client_name);
+/*
+ * -----------------------------------------------------------------------------
+ * Private WAVE API specific functions
+ * -----------------------------------------------------------------------------
+ */
-/** Change the name of the stream being sent */
-int sa_device_change_stream_name(SAAudioHandle *dev, const char *stream_name);
+/**
+ * \brief - allocate buffer for writing to system WAVE audio device
+ * \param size - size of each audio block
+ * \param cound - number of blocks to be allocated
+ * \param blocks - pointer to the blocks buffer to be allocated
+ * \return - completion status
+ */
+int allocateBlocks(int size, int count, WAVEHDR** blocks)
+{
+ unsigned char* buffer;
+ int i;
+ WAVEHDR* headers;
+ DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;
+
+ /* allocate memory on heap for the entire set in one go */
+ if((buffer = HeapAlloc(
+ GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ totalBufferSize
+ )) == NULL) {
+ printf("Memory allocation error\n");
+ return SA_ERROR_OOM;
+ }
-/** Associate opaque user data */
-int sa_device_change_user_data(SAAudioHandle *dev, void *val);
+ /* and set up the pointers to each bit */
+ headers = *blocks = (WAVEHDR*)buffer;
+ buffer += sizeof(WAVEHDR) * count;
+ for(i = 0; i < count; i++) {
+ headers[i].dwBufferLength = size;
+ headers[i].lpData = buffer;
+ buffer += size;
+ }
+
+ return SA_SUCCESS;
+}
+/**
+ * \brief - free allocated audio buffer
+ * \param blocks - pointer to allocated the buffer of audio bloks
+ * \return - completion status
+ */
+int freeBlocks(WAVEHDR* blocks)
+{
+ if (blocks == NULL)
+ return SA_ERROR_INVALID;
+ /* and this is why allocateBlocks works the way it does */
+ HeapFree(GetProcessHeap(), 0, blocks);
+ blocks = NULL;
-/* Hardware-related. This is implementation-specific and hardware specific. */
-int sa_device_adjust_rate(SAAudioHandle *dev, int rate, int direction);
+ return SA_SUCCESS;
+}
-int sa_device_adjust_channels(SAAudioHandle *dev, int nb_channels);
+/**
+ * \brief - open system default WAVE device
+ * \param s - sydney audio stream handle
+ * \return - completion status
+ */
+int openAudio(sa_stream_t *s) {
+ int status;
+ WAVEFORMATEX wfx;
+ UINT supported = FALSE;
+
+ status = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT, &(s->waveBlocks));
+ HANDLE_WAVE_ERROR(status, "allocating audio buffer blocks");
+
+ s->waveFreeBlockCount = BLOCK_COUNT;
+ s->waveCurrentBlock = 0;
+ wfx.nSamplesPerSec = (DWORD)s->rate; /* sample rate */
+ wfx.wBitsPerSample = 16; /* sample size */
+ wfx.nChannels = s->channels; /* channels */
+ wfx.cbSize = 0; /* size of _extra_ info */
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) >> 3;
+ wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
-int sa_device_adjust_format(SAAudioHandle *dev, sa_pcm_format_t format, int direction);
+ supported = waveOutOpen(NULL, WAVE_MAPPER, &wfx, (DWORD_PTR)0, (DWORD_PTR)0,
+ WAVE_FORMAT_QUERY);
+ if (supported == MMSYSERR_NOERROR) { // audio device opened sucessfully
+ status = waveOutOpen((LPHWAVEOUT)&(s->hWaveOut), WAVE_MAPPER, &wfx,
+ (DWORD_PTR)waveOutProc, (DWORD_PTR)s, CALLBACK_FUNCTION);
+ HANDLE_WAVE_ERROR(status, "opening audio device for playback");
+ printf("Audio device sucessfully opened\n");
+ }
+ else if (supported == WAVERR_BADFORMAT) {
+ printf("Requested format not supported...\n");
+ // clean up the memory
+ freeBlocks(s->waveBlocks);
+ return SA_ERROR_NOT_SUPPORTED;
+ }
+ else {
+ printf("Error opening default audio device. Exiting...\n");
+ // clean up the memory
+ freeBlocks(s->waveBlocks);
+ return SA_ERROR_SYSTEM;
+ }
+ // create notification for data written to a device
+ s->callbackEvent = CreateEvent(0, FALSE, FALSE, 0);
+ // initialise critical section for operations on waveFreeBlockCound variable
+ InitializeCriticalSection(&(s->waveCriticalSection));
+ return SA_SUCCESS;
+}
+/**
+ * \brief - closes opened audio device handle
+ * \param s - sydney audio stream handle
+ * \return - completion status
+ */
+int closeAudio(sa_stream_t * s) {
+ int status, i;
-/* Query functions */
+ /* FIX ME: should the loop below have a timeout option? */
+ /* wait for all blocks to complete */
+ while(s->waveFreeBlockCount < BLOCK_COUNT)
+ Sleep(10);
-/** Get current state of the audio device */
-int sa_device_get_state(SAAudioHandle *dev, sa_state_t *running);
+ /* unprepare any blocks that are still prepared */
+ for(i = 0; i < s->waveFreeBlockCount; i++) {
+ if(s->waveBlocks[i].dwFlags & WHDR_PREPARED) {
+ status = waveOutUnprepareHeader(s->hWaveOut, &(s->waveBlocks[i]), sizeof(WAVEHDR));
+ HANDLE_WAVE_ERROR(status, "closing audio device");
+ }
+ }
+ // reseting audio device and flushing buffers
+ // status = waveOutReset(s->hWaveOut);
+ // HANDLE_WAVE_ERROR(status, "resetting audio device");
-/** Get current sampling rate */
-int sa_device_get_sampling_rate(SAAudioHandle *dev, int *rate);
+ freeBlocks(s->waveBlocks);
+ status = waveOutClose(s->hWaveOut);
+ HANDLE_WAVE_ERROR(status, "closing audio device");
-/** Get number of channels */
-int sa_device_get_nb_channels(SAAudioHandle *dev, int *nb_channels);
+ DeleteCriticalSection(&(s->waveCriticalSection));
+ CloseHandle(s->callbackEvent);
-/** Get format being used */
-int sa_device_get_format(SAAudioHandle *dev, sa_pcm_format_t *format);
+ return SA_SUCCESS;
+}
+/**
+ * \brief - writes PCM audio samples to audio device
+ * \param s - valid handle to opened sydney stream
+ * \param data - pointer to memory storing audio samples to be played
+ * \param nsamples - number of samples in the memory pointed by previous parameter
+ * \return - completion status
+ */
+int writeAudio(sa_stream_t *s, LPSTR data, int bytes) {
+ UINT status;
+ WAVEHDR* current;
+ int remain;
-/** Get opaque pointer associated to the device */
-int sa_device_get_user_data(SAAudioHandle *dev, void **val);
+ current = &(s->waveBlocks[s->waveCurrentBlock]);
+
+ while(bytes > 0) {
+ /* first make sure the header we're going to use is unprepared */
+ if(current->dwFlags & WHDR_PREPARED) {
+ status = waveOutUnprepareHeader(s->hWaveOut, current, sizeof(WAVEHDR));
+ HANDLE_WAVE_ERROR(status, "preparing audio headers for writing");
+ }
+
+ if(bytes < (int)(BLOCK_SIZE - current->dwUser)) {
+ memcpy(current->lpData + current->dwUser, data, bytes);
+ current->dwUser += bytes;
+ break;
+ }
+
+ /* remain is even as BLOCK_SIZE and dwUser are even too */
+ remain = BLOCK_SIZE - current->dwUser;
+ memcpy(current->lpData + current->dwUser, data, remain);
+ bytes -= remain;
+ data += bytes;
+ current->dwBufferLength = BLOCK_SIZE;
+ /* write to audio device */
+ waveOutPrepareHeader(s->hWaveOut, current, sizeof(WAVEHDR));
+ status = waveOutWrite(s->hWaveOut, current, sizeof(WAVEHDR));
+ HANDLE_WAVE_ERROR(status, "writing audio to audio device");
+
+ EnterCriticalSection(&(s->waveCriticalSection));
+ s->waveFreeBlockCount--;
+ LeaveCriticalSection(&(s->waveCriticalSection));
+ /*
+ * wait for a block to become free
+ */
+ while (!(s->waveFreeBlockCount)) {
+ //printf("All audio buffer blocks empty\n");
+ WaitForSingleObject(s->callbackEvent, INFINITE);
+ //Sleep(10);
+ }
+
+ /*
+ * point to the next block
+ */
+ (s->waveCurrentBlock)++;
+ (s->waveCurrentBlock) %= BLOCK_COUNT;
-/** Obtain the error code */
-int sa_device_get_event_error(SAAudioHandle *dev, sa_pcm_error_t *error);
+ current = &(s->waveBlocks[s->waveCurrentBlock]);
+ current->dwUser = 0;
+ }
+ return SA_SUCCESS;
+}
-/** Obtain the notification code */
-int sa_device_get_event_notify(SAAudioHandle *dev, sa_pcm_notification_t *notify);
+/**
+ * \brief - audio callback function called when next WAVE header is played by audio device
+ */
+void CALLBACK waveOutProc(
+ HWAVEOUT hWaveOut,
+ UINT uMsg,
+ DWORD dwInstance,
+ DWORD dwParam1,
+ DWORD dwParam2
+)
+{
+ /*
+ * pointer to free block counter
+ */
+ sa_stream_t* handle = (sa_stream_t*)dwInstance;
+ /*
+ * ignore calls that occur due to openining and closing the
+ * device.
+ */
+ if(uMsg != WOM_DONE)
+ return;
-/** sync/timing */
-int sa_device_get_position(SAAudioHandle *dev, sa_pcm_index_t ref, int64_t *pos);
+ EnterCriticalSection(&(handle->waveCriticalSection));
+ (handle->waveFreeBlockCount)++;
+ if ((handle->waveFreeBlockCount) == 1)
+ SetEvent(handle->callbackEvent);
+ LeaveCriticalSection(&(handle->waveCriticalSection));
+}
+/**
+ * \brief - converts frequently reported WAVE error codes to Sydney audio API codes
+ */
+int getSAErrorCode(int waveErrorCode) {
+ int error = SA_ERROR_NOT_SUPPORTED;
+ switch (waveErrorCode) {
+ case MMSYSERR_NOERROR:
+ error = SA_SUCCESS;
+ break;
+ case MMSYSERR_ALLOCATED:
+ error = SA_ERROR_SYSTEM;
+ break;
+ case MMSYSERR_BADDEVICEID:
+ error = SA_ERROR_INVALID;
+ break;
+ case MMSYSERR_NODRIVER:
+ error = SA_ERROR_NO_DRIVER;
+ break;
+ case MMSYSERR_NOTSUPPORTED:
+ error = SA_ERROR_NOT_SUPPORTED;
+ break;
+ case MMSYSERR_NOMEM:
+ error = SA_ERROR_OOM;
+ break;
+ case MMSYSERR_INVALHANDLE:
+ error = SA_ERROR_INVALID;
+ break;
+ case WAVERR_BADFORMAT:
+ error = SA_ERROR_NOT_SUPPORTED;
+ break;
+ case WAVERR_SYNC:
+ error = SA_ERROR_NOT_SUPPORTED;
+ break;
+ }
+ return error;
+}
-/* Blocking IO calls */
+/*
+ * -----------------------------------------------------------------------------
+ * Functions to be implemented next
+ * -----------------------------------------------------------------------------
+ */
-/** Interleaved capture function */
-int sa_device_read(SAAudioHandle *dev, size_t nbytes, void *data);
-/** Interleaved playback function */
-int sa_device_write(SAAudioHandle *dev, size_t nbytes, const void *data);
+#define NOT_IMPLEMENTED(func) func { return SA_ERROR_NOT_SUPPORTED; }
-/** Non-interleaved capture function */
-int sa_device_read_ni(SAAudioHandle *dev, int channel, size_t nbytes, void *data);
-/** Non-interleaved playback function */
-int sa_device_write_ni(SAAudioHandle *dev, int channel, size_t nbytes, const void *data);
+/* "Soft" params */
+NOT_IMPLEMENTED(int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size))
+NOT_IMPLEMENTED(int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size))
+NOT_IMPLEMENTED(int sa_stream_set_write_upper_watermark(sa_stream_t *s, size_t size))
+NOT_IMPLEMENTED(int sa_stream_set_read_upper_watermark(sa_stream_t *s, size_t size))
-/** Interleaved capture function with seek offset */
-int sa_device_pread(SAAudioHandle *dev, size_t nbytes, void *data, int64_t offset, sa_pcm_seek_whence_t whence);
-/** Interleaved playback function with seek offset */
-int sa_device_pwrite(SAAudioHandle *dev, size_t nbytes, const void *data, int64_t offset, sa_pcm_seek_whence_t whence);
+/** Set the mapping between channels and the loudspeakers */
+NOT_IMPLEMENTED(int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t map[], unsigned int n))
-/** Non-interleaved capture function with seek offset */
-int sa_device_pread_ni(SAAudioHandle *dev, int channel, size_t nbytes, void *data, int64_t offset, sa_pcm_seek_whence_t whence);
-/** Non-interleaved playback function with seek offset */
-int sa_device_pwrite_ni(SAAudioHandle *dev, int channel, size_t nbytes, const void *data, int64_t offset, sa_pcm_seek_whence_t whence);
+/* Query functions */
+NOT_IMPLEMENTED(int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode))
+NOT_IMPLEMENTED(int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *format))
+NOT_IMPLEMENTED(int sa_stream_get_rate(sa_stream_t *s, unsigned int *rate))
+NOT_IMPLEMENTED(int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels))
+NOT_IMPLEMENTED(int sa_stream_get_device(sa_stream_t *s, char *device_name, size_t *size))
+NOT_IMPLEMENTED(int sa_stream_get_write_lower_watermark(sa_stream_t *s, size_t *size))
+NOT_IMPLEMENTED(int sa_stream_get_read_lower_watermark(sa_stream_t *s, size_t *size))
+NOT_IMPLEMENTED(int sa_stream_get_write_upper_watermark(sa_stream_t *s, size_t *size))
+NOT_IMPLEMENTED(int sa_stream_get_read_upper_watermark(sa_stream_t *s, size_t *size))
+NOT_IMPLEMENTED(int sa_stream_get_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned int *n))
+/*
+ * -----------------------------------------------------------------------------
+ * Unsupported functions
+ * -----------------------------------------------------------------------------
+ */
+#define UNSUPPORTED(func) func { return SA_ERROR_NOT_SUPPORTED; }
-/** Query how much can be read without blocking */
-int sa_device_get_read_size(SAAudioHandle *dev, size_t *size);
-/** Query how much can be written without blocking */
-int sa_device_get_write_size(SAAudioHandle *dev, size_t *size);
+/** Create an opaque (e.g. AC3) codec stream */
+UNSUPPORTED(int sa_stream_create_opaque(sa_stream_t **s, const char *client_name, sa_mode_t mode, const char *codec))
+/** Whether xruns cause the card to reset */
+UNSUPPORTED(int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode))
+/** Set the device to non-interleaved mode */
+UNSUPPORTED(int sa_stream_set_non_interleaved(sa_stream_t *s, int enable))
+/** Require dynamic sample rate */
+UNSUPPORTED(int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable))
+/** Select driver */
+UNSUPPORTED(int sa_stream_set_driver(sa_stream_t *s, const char *driver))
+/** Start callback */
+UNSUPPORTED(int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t callback))
+/** Stop callback */
+UNSUPPORTED(int sa_stream_stop_thread(sa_stream_t *s))
+/** Change the device connected to the stream */
+UNSUPPORTED(int sa_stream_change_device(sa_stream_t *s, const char *device_name))
+/** volume in hundreths of dB*/
+UNSUPPORTED(int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned int n))
+/** Change the sampling rate */
+UNSUPPORTED(int sa_stream_change_rate(sa_stream_t *s, unsigned int rate))
+/** Change some meta data that is attached to the stream */
+UNSUPPORTED(int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size))
+/** Associate opaque user data */
+UNSUPPORTED(int sa_stream_change_user_data(sa_stream_t *s, const void *value))
+/* Hardware-related. This is implementation-specific and hardware specific. */
+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))
+/* Query functions */
+UNSUPPORTED(int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size))
+UNSUPPORTED(int sa_stream_get_user_data(sa_stream_t *s, void **value))
+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_read_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))
+/** Get current state of the audio device */
+UNSUPPORTED(int sa_stream_get_state(sa_stream_t *s, sa_state_t *state))
+/** Obtain the error code */
+UNSUPPORTED(int sa_stream_get_event_error(sa_stream_t *s, sa_error_t *error))
+/** Obtain the notification code */
+UNSUPPORTED(int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify))
-/* Control/xrun */
+/* Blocking IO calls */
+/** Interleaved capture function */
+UNSUPPORTED(int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes))
+/** Non-interleaved capture function */
+UNSUPPORTED(int sa_stream_read_ni(sa_stream_t *s, unsigned int channel, void *data, size_t nbytes))
-/** Resume playing after a pause */
-int sa_device_resume(SAAudioHandle *dev);
+/** Non-interleaved playback function */
+UNSUPPORTED(int sa_stream_write_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes))
+/** Interleaved playback function with seek offset */
+UNSUPPORTED(int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))
+/** Non-interleaved playback function with seek offset */
+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))
-/** Pause audio playback (do not empty the buffer) */
-int sa_device_pause(SAAudioHandle *dev);
+/** Query how much can be read without blocking */
+UNSUPPORTED(int sa_stream_get_read_size(sa_stream_t *s, size_t *size))
+/** Query how much can be written without blocking */
+UNSUPPORTED(int sa_stream_get_write_size(sa_stream_t *s, size_t *size))
/** Block until all audio has been played */
-int sa_device_drain(SAAudioHandle *dev);
+UNSUPPORTED(int sa_stream_drain(sa_stream_t *s))
-
-#endif // (SOUND_VERSION > SUPP_OSS_VERSION)
\ No newline at end of file
+/** Return a human readable error */
+const char *sa_strerror(int code);
More information about the commits
mailing list