[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