diff --git a/audio/drivers/rsound.c b/audio/drivers/rsound.c index f3fcd4bb86..1f13e5cf41 100644 --- a/audio/drivers/rsound.c +++ b/audio/drivers/rsound.c @@ -55,6 +55,7 @@ static void err_cb(void *userdata) static void *rs_init(const char *device, unsigned rate, unsigned latency) { + int channels, format; rsd_t *rsd = (rsd_t*)calloc(1, sizeof(rsd_t)); if (!rsd) return NULL; @@ -72,8 +73,8 @@ static void *rs_init(const char *device, unsigned rate, unsigned latency) rsd->buffer = fifo_new(1024 * 4); - int channels = 2; - int format = RSD_S16_NE; + channels = 2; + format = RSD_S16_NE; rsd_set_param(rd, RSD_CHANNELS, &channels); rsd_set_param(rd, RSD_SAMPLERATE, &rate); @@ -106,9 +107,13 @@ static ssize_t rs_write(void *data, const void *buf, size_t size) if (rsd->nonblock) { + size_t avail, write_amt; + rsd_callback_lock(rsd->rd); - size_t avail = fifo_write_avail(rsd->buffer); - size_t write_amt = avail > size ? size : avail; + + avail = fifo_write_avail(rsd->buffer); + write_amt = avail > size ? size : avail; + fifo_write(rsd->buffer, buf, write_amt); rsd_callback_unlock(rsd->rd); return write_amt; @@ -118,8 +123,10 @@ static ssize_t rs_write(void *data, const void *buf, size_t size) size_t written = 0; while (written < size && !rsd->has_error) { + size_t avail; rsd_callback_lock(rsd->rd); - size_t avail = fifo_write_avail(rsd->buffer); + + avail = fifo_write_avail(rsd->buffer); if (avail == 0) { diff --git a/audio/drivers/rsound.h b/audio/drivers/rsound.h index 5395c137aa..21755c0053 100644 --- a/audio/drivers/rsound.h +++ b/audio/drivers/rsound.h @@ -87,247 +87,239 @@ extern "C" { #define RSD_SET_CALLBACK RSD_SET_CALLBACK #define RSD_CALLBACK_LOCK RSD_CALLBACK_LOCK #define RSD_CALLBACK_UNLOCK RSD_CALLBACK_UNLOCK + /* End feature tests */ +/* Defines sample formats available. Defaults to S16_LE should it never be set. */ +enum rsd_format +{ + RSD_NO_FMT = 0x0000, + RSD_S16_LE = 0x0001, + RSD_S16_BE = 0x0002, + RSD_U16_LE = 0x0004, + RSD_U16_BE = 0x0008, + RSD_U8 = 0x0010, + RSD_S8 = 0x0020, + RSD_S16_NE = 0x0040, + RSD_U16_NE = 0x0080, + RSD_ALAW = 0x0100, + RSD_MULAW = 0x0200, + RSD_S32_LE = 0x0400, + RSD_S32_BE = 0x0800, + RSD_S32_NE = 0x1000, + RSD_U32_LE = 0x2000, + RSD_U32_BE = 0x4000, + RSD_U32_NE = 0x8000, +}; +/* Defines operations that can be used with rsd_set_param() */ +enum rsd_settings +{ + RSD_SAMPLERATE = 0, + RSD_CHANNELS, + RSD_HOST, + RSD_PORT, + RSD_BUFSIZE, + RSD_LATENCY, + RSD_FORMAT, + RSD_IDENTITY +}; - /* Defines sample formats available. Defaults to S16_LE should it never be set. */ - enum rsd_format +/* Audio callback for rsd_set_callback. Return -1 to trigger an error in the stream. */ +typedef ssize_t (*rsd_audio_callback_t)(void *data, size_t bytes, void *userdata); + +/* Error callback. Signals caller that stream has been stopped, + * either by audio callback returning -1 or stream was hung up. */ +typedef void (*rsd_error_callback_t)(void *userdata); + +/* Defines the main structure for use with the API. */ +typedef struct rsound +{ + struct { - RSD_NO_FMT = 0x0000, - RSD_S16_LE = 0x0001, - RSD_S16_BE = 0x0002, - RSD_U16_LE = 0x0004, - RSD_U16_BE = 0x0008, - RSD_U8 = 0x0010, - RSD_S8 = 0x0020, - RSD_S16_NE = 0x0040, - RSD_U16_NE = 0x0080, - RSD_ALAW = 0x0100, - RSD_MULAW = 0x0200, - RSD_S32_LE = 0x0400, - RSD_S32_BE = 0x0800, - RSD_S32_NE = 0x1000, - RSD_U32_LE = 0x2000, - RSD_U32_BE = 0x4000, - RSD_U32_NE = 0x8000, - }; + volatile int socket; + volatile int ctl_socket; + } conn; - /* Defines operations that can be used with rsd_set_param() */ - enum rsd_settings + char *host; + char *port; + char *buffer; /* Obsolete, but kept for backwards header compatibility. */ + int conn_type; + + volatile int buffer_pointer; /* Obsolete, but kept for backwards header compatibility. */ + size_t buffer_size; + fifo_buffer_t *fifo_buffer; + + volatile int thread_active; + + int64_t total_written; + int64_t start_time; + volatile int has_written; + int bytes_in_buffer; + int delay_offset; + int max_latency; + + struct { - RSD_SAMPLERATE = 0, - RSD_CHANNELS, - RSD_HOST, - RSD_PORT, - RSD_BUFSIZE, - RSD_LATENCY, - RSD_FORMAT, - RSD_IDENTITY - }; + uint32_t latency; + uint32_t chunk_size; + } backend_info; - /* Audio callback for rsd_set_callback. Return -1 to trigger an error in the stream. */ - typedef ssize_t (*rsd_audio_callback_t)(void *data, size_t bytes, void *userdata); + volatile int ready_for_data; - /* Error callback. Signals caller that stream has been stopped, either by audio callback returning -1 or stream was hung up. */ - typedef void (*rsd_error_callback_t)(void *userdata); + uint32_t rate; + uint32_t channels; + uint16_t format; + int samplesize; - /* Defines the main structure for use with the API. */ - typedef struct rsound + struct { - struct { - volatile int socket; - volatile int ctl_socket; - } conn; + sthread_t *thread; + slock_t *mutex; + slock_t *cond_mutex; + scond_t *cond; + } thread; - char *host; - char *port; - char *buffer; /* Obsolete, but kept for backwards header compatibility. */ - int conn_type; + char identity[256]; - volatile int buffer_pointer; /* Obsolete, but kept for backwards header compatibility. */ - size_t buffer_size; - fifo_buffer_t *fifo_buffer; + rsd_audio_callback_t audio_callback; + rsd_error_callback_t error_callback; + size_t cb_max_size; + void *cb_data; + slock_t *cb_lock; +} rsound_t; - volatile int thread_active; +/* -- API -- + All functions (except for rsd_write() return 0 for success, and -1 for error. errno is currently not set. */ - int64_t total_written; - int64_t start_time; - volatile int has_written; - int bytes_in_buffer; - int delay_offset; - int max_latency; - - struct { - uint32_t latency; - uint32_t chunk_size; - } backend_info; - - volatile int ready_for_data; - - uint32_t rate; - uint32_t channels; - uint16_t format; - int samplesize; - - struct { - sthread_t *thread; - slock_t *mutex; - slock_t *cond_mutex; - scond_t *cond; - } thread; - - char identity[256]; - - rsd_audio_callback_t audio_callback; - rsd_error_callback_t error_callback; - size_t cb_max_size; - void *cb_data; - slock_t *cb_lock; - } rsound_t; - - /* -- API -- - All functions (except for rsd_write() return 0 for success, and -1 for error. errno is currently not set. */ - - /* Initializes an rsound_t structure. To make sure no memory leaks occur, you need to rsd_free() it after use. +/* Initializes an rsound_t structure. To make sure no memory leaks occur, you need to rsd_free() it after use. A typical use of the API is as follows: - rsound_t *rd; - rsd_init(&rd); - rsd_set_param(rd, RSD_HOST, "foohost"); - *sets more params* - rsd_start(rd); - rsd_write(rd, buf, size); - rsd_stop(rd); - rsd_free(rd); - */ - int rsd_init (rsound_t **rd); + rsound_t *rd; + rsd_init(&rd); + rsd_set_param(rd, RSD_HOST, "foohost"); + *sets more params* + rsd_start(rd); + rsd_write(rd, buf, size); + rsd_stop(rd); + rsd_free(rd); + */ +int rsd_init (rsound_t **rd); +/* This is a simpler function that initializes an rsound struct, sets params as given, + and starts the stream. Should this function fail, the structure will stay uninitialized. + Should NULL be passed in either host, port or ident, defaults will be used. */ - /* This is a simpler function that initializes an rsound struct, sets params as given, - and starts the stream. Should this function fail, the structure will stay uninitialized. - Should NULL be passed in either host, port or ident, defaults will be used. */ +int rsd_simple_start (rsound_t **rd, const char* host, const char* port, const char* ident, + int rate, int channels, enum rsd_format format); - int rsd_simple_start (rsound_t **rd, const char* host, const char* port, const char* ident, - int rate, int channels, enum rsd_format format); +/* Sets params associated with an rsound_t. These options (int options) include: +RSD_HOST: Server to connect to. Expects (char *) in param. +If not set, will default to environmental variable RSD_SERVER or "localhost". - /* Sets params associated with an rsound_t. These options (int options) include: +RSD_PORT: Set port. Expects (char *) in param. +If not set, will default to environmental variable RSD_PORT or "12345". - RSD_HOST: Server to connect to. Expects (char *) in param. - If not set, will default to environmental variable RSD_SERVER or "localhost". +RSD_CHANNELS: Set number of audio channels. Expects (int *) in param. Mandatory. - RSD_PORT: Set port. Expects (char *) in param. - If not set, will default to environmental variable RSD_PORT or "12345". +RSD_SAMPLERATE: Set samplerate of audio stream. Expects (int *) in param. Mandatory. - RSD_CHANNELS: Set number of audio channels. Expects (int *) in param. Mandatory. +RSD_BUFSIZE: Sets internal buffersize for the stream. +Might be overridden if too small. +Expects (int *) in param. Optional. - RSD_SAMPLERATE: Set samplerate of audio stream. Expects (int *) in param. Mandatory. +RSD_LATENCY: Sets maximum audio latency in milliseconds, +(must be used with rsd_delay_wait() or this will have no effect). +Most applications do not need this. +Might be overridden if too small. +Expects (int *) in param. Optional. - RSD_BUFSIZE: Sets internal buffersize for the stream. - Might be overridden if too small. - Expects (int *) in param. Optional. +RSD_FORMAT: Sets sample format. +It defaults to S16_LE, so you probably will not use this. +Expects (int *) in param, with available values found in the format enum. +If invalid format is given, param might be changed to reflect the sample format the library will use. - RSD_LATENCY: Sets maximum audio latency in milliseconds, - (must be used with rsd_delay_wait() or this will have no effect). - Most applications do not need this. - Might be overridden if too small. - Expects (int *) in param. Optional. +RSD_IDENTITY: Sets an identity string associated with the client. +Takes a (char *) parameter with the stream name. +Will be truncated if longer than 256 bytes. - RSD_FORMAT: Sets sample format. - It defaults to S16_LE, so you probably will not use this. - Expects (int *) in param, with available values found in the format enum. - If invalid format is given, param might be changed to reflect the sample format the library will use. +*/ - RSD_IDENTITY: Sets an identity string associated with the client. - Takes a (char *) parameter with the stream name. - Will be truncated if longer than 256 bytes. +int rsd_set_param (rsound_t *rd, enum rsd_settings option, void* param); - */ +/* Enables use of the callback interface. This must be set when stream is not active. + When callback is active, use of the blocking interface is disabled. + Only valid functions to call after rsd_start() is stopping the stream with either rsd_pause() or rsd_stop(). Calling any other function is undefined. + The callback is called at regular intervals and is asynchronous, so thread safety must be ensured by the caller. + If not enough data can be given to the callback, librsound will fill the rest of the callback data with silence. + librsound will attempt to obey latency information given with RSD_LATENCY as given before calling rsd_start(). + max_size signifies the maximum size that will ever be requested by librsound. Set this to 0 to let librsound decide the maximum size. + Should an error occur to the stream, err_callback will be called, and the stream will be stopped. The stream can be started again. - int rsd_set_param (rsound_t *rd, enum rsd_settings option, void* param); + Callbacks can be disabled by setting callbacks to NULL. */ - /* Enables use of the callback interface. This must be set when stream is not active. - When callback is active, use of the blocking interface is disabled. - Only valid functions to call after rsd_start() is stopping the stream with either rsd_pause() or rsd_stop(). Calling any other function is undefined. - The callback is called at regular intervals and is asynchronous, so thread safety must be ensured by the caller. - If not enough data can be given to the callback, librsound will fill the rest of the callback data with silence. - librsound will attempt to obey latency information given with RSD_LATENCY as given before calling rsd_start(). - max_size signifies the maximum size that will ever be requested by librsound. Set this to 0 to let librsound decide the maximum size. - Should an error occur to the stream, err_callback will be called, and the stream will be stopped. The stream can be started again. +void rsd_set_callback (rsound_t *rd, rsd_audio_callback_t callback, rsd_error_callback_t err_callback, size_t max_size, void *userdata); - Callbacks can be disabled by setting callbacks to NULL. */ +/* Lock and unlock the callback. When the callback lock is aquired, the callback is guaranteed to not be executing. + The lock has to be unlocked afterwards. + Attemping to call several rsd_callback_lock() in succession might cause a deadlock. + The lock should be held for as short period as possible. + Try to avoid calling code that may block when holding the lock. */ +void rsd_callback_lock (rsound_t *rd); - void rsd_set_callback (rsound_t *rd, rsd_audio_callback_t callback, rsd_error_callback_t err_callback, size_t max_size, void *userdata); +void rsd_callback_unlock (rsound_t *rd); - /* Lock and unlock the callback. When the callback lock is aquired, the callback is guaranteed to not be executing. - The lock has to be unlocked afterwards. - Attemping to call several rsd_callback_lock() in succession might cause a deadlock. - The lock should be held for as short period as possible. - Try to avoid calling code that may block when holding the lock. */ - void rsd_callback_lock (rsound_t *rd); - void rsd_callback_unlock (rsound_t *rd); +/* Establishes connection to server. Might fail if connection can't be established or that one of + the mandatory options isn't set in rsd_set_param(). This needs to be called after params have been set + with rsd_set_param(), and before rsd_write(). */ +int rsd_start (rsound_t *rd); - /* Establishes connection to server. Might fail if connection can't be established or that one of - the mandatory options isn't set in rsd_set_param(). This needs to be called after params have been set - with rsd_set_param(), and before rsd_write(). */ - int rsd_start (rsound_t *rd); +/* Shuts down the rsound data structures, but returns the file descriptor associated with the connection. + The control socket will be shut down. If this function returns a negative number, the exec failed, + but the data structures will not be teared down. + Should a valid file descriptor be returned, it will always be blocking. + This call will block until all internal buffers have been sent to the network. */ +int rsd_exec (rsound_t *rd); - /* Shuts down the rsound data structures, but returns the file descriptor associated with the connection. - The control socket will be shut down. If this function returns a negative number, the exec failed, - but the data structures will not be teared down. - Should a valid file descriptor be returned, it will always be blocking. - This call will block until all internal buffers have been sent to the network. */ - int rsd_exec (rsound_t *rd); +/* Disconnects from server. All audio data still in network buffer and other buffers will be dropped. + To continue playing, you will need to rsd_start() again. */ +int rsd_stop (rsound_t *rd); - /* Disconnects from server. All audio data still in network buffer and other buffers will be dropped. - To continue playing, you will need to rsd_start() again. */ - int rsd_stop (rsound_t *rd); +/* Writes from buf to the internal buffer. Might fail if no connection is established, + or there was an unexpected error. This function will block until all data has + been written to the buffer. This function will return the number of bytes written to the buffer, + or 0 should it fail (disconnection from server). You will have to restart the stream again should this occur. */ +size_t rsd_write (rsound_t *rd, const void* buf, size_t size); - /* Writes from buf to the internal buffer. Might fail if no connection is established, - or there was an unexpected error. This function will block until all data has - been written to the buffer. This function will return the number of bytes written to the buffer, - or 0 should it fail (disconnection from server). You will have to restart the stream again should this occur. */ - size_t rsd_write (rsound_t *rd, const void* buf, size_t size); +/* Gets the position of the buffer pointer. + Not really interesting for normal applications. + Might be useful for implementing rsound on top of other blocking APIs. + *NOTE* This function is deprecated, it should not be used in new applications. */ +size_t rsd_pointer (rsound_t *rd); - /* Gets the position of the buffer pointer. - Not really interesting for normal applications. - Might be useful for implementing rsound on top of other blocking APIs. - *NOTE* This function is deprecated, it should not be used in new applications. */ - size_t rsd_pointer (rsound_t *rd); +/* Aquires how much data can be written to the buffer without blocking */ +size_t rsd_get_avail (rsound_t *rd); - /* Aquires how much data can be written to the buffer without blocking */ - size_t rsd_get_avail (rsound_t *rd); +/* Aquires the latency at the moment for the audio stream. It is measured in bytes. Useful for syncing video and audio. */ +size_t rsd_delay (rsound_t *rd); - /* Aquires the latency at the moment for the audio stream. It is measured in bytes. Useful for syncing video and audio. */ - size_t rsd_delay (rsound_t *rd); +/* Utility for returning latency in milliseconds. */ +size_t rsd_delay_ms (rsound_t *rd); - /* Utility for returning latency in milliseconds. */ - size_t rsd_delay_ms (rsound_t *rd); +/* Returns bytes per sample */ +int rsd_samplesize(rsound_t *rd); - /* Returns bytes per sample */ - int rsd_samplesize(rsound_t *rd); +/* Will sleep until latency of stream reaches maximum allowed latency defined earlier by rsd_set_param - RSD_LATENCY + Useful for hard headed blocking I/O design where user defined latency is needed. If rsd_set_param hasn't been set + with RSD_LATENCY, this function will do nothing. */ +void rsd_delay_wait(rsound_t *rd); - /* Will sleep until latency of stream reaches maximum allowed latency defined earlier by rsd_set_param - RSD_LATENCY - Useful for hard headed blocking I/O design where user defined latency is needed. If rsd_set_param hasn't been set - with RSD_LATENCY, this function will do nothing. */ - void rsd_delay_wait(rsound_t *rd); +/* Pauses or unpauses a stream. pause -> enable = 1 + This function essentially calls on start() and stop(). This behavior might be changed later. */ +int rsd_pause (rsound_t *rd, int enable); - - /* Pauses or unpauses a stream. pause -> enable = 1 - This function essentially calls on start() and stop(). This behavior might be changed later. */ - int rsd_pause (rsound_t *rd, int enable); - - /* Frees an rsound_t struct. Make sure that the stream is properly closed down with rsd_stop() before calling rsd_free(). */ - int rsd_free (rsound_t *rd); - -#ifndef HAVE_STRL -// Avoid possible naming collisions during link since we prefer to use the actual name. -#define strlcpy(dst, src, size) strlcpy_rarch__(dst, src, size) -#define strlcat(dst, src, size) strlcat_rarch__(dst, src, size) - -size_t strlcpy(char *dest, const char *source, size_t size); -size_t strlcat(char *dest, const char *source, size_t size); -#endif +/* Frees an rsound_t struct. Make sure that the stream is properly closed down with rsd_stop() before calling rsd_free(). */ +int rsd_free (rsound_t *rd); #ifdef __cplusplus } diff --git a/audio/librsound.c b/audio/librsound.c index abd6b78e44..bf4abf3fcf 100644 --- a/audio/librsound.c +++ b/audio/librsound.c @@ -69,6 +69,7 @@ #include #include +#include #include /*