From a2b28ddd5aa5e11895aa2a53df4065475c525b68 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Apr 2008 00:10:04 +0000 Subject: some leftover work git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@43 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce --- src/bbuffer.c | 2 +- src/bbuffer.h | 4 +- src/bufferq.c | 18 +++---- src/bufferq.h | 3 +- src/common.c | 2 +- src/converter.c | 58 +++++++++++----------- src/converter.h | 12 +++-- src/oss.c | 57 +++++++++++++++------- src/sydney.h | 147 +++++++++++++++++++++++++++++++++++--------------------- 9 files changed, 185 insertions(+), 118 deletions(-) diff --git a/src/bbuffer.c b/src/bbuffer.c index 86bc5ee..733db4d 100644 --- a/src/bbuffer.c +++ b/src/bbuffer.c @@ -48,7 +48,7 @@ void sa_bbuffer_done(sa_bbuffer_t *b) { b->size = NULL; } -void* sa_bbuffer_get(sa_bbuffer_t *b, unsigned channel, size_t size, int interleave) { +void* sa_bbuffer_get(sa_bbuffer_t *b, unsigned channel, size_t size, sa_bool_t interleave) { sa_assert(b); sa_assert(channel < b->nchannels); sa_assert(size > 0); diff --git a/src/bbuffer.h b/src/bbuffer.h index 6394a11..0c5731b 100644 --- a/src/bbuffer.h +++ b/src/bbuffer.h @@ -3,6 +3,8 @@ #include +#include "macro.h" + /* Simple bounce buffer management routines */ typedef struct sa_bbuffer { @@ -14,6 +16,6 @@ typedef struct sa_bbuffer { int sa_bbuffer_init(sa_bbuffer_t *b, unsigned nchannels, size_t sample_size); void sa_bbuffer_done(sa_bbuffer_t *b); -void* sa_bbuffer_get(sa_bbuffer_t *b, unsigned channel, size_t size, int interleave); +void* sa_bbuffer_get(sa_bbuffer_t *b, unsigned channel, size_t size, sa_bool_t interleave); #endif diff --git a/src/bufferq.c b/src/bufferq.c index bafcaa1..46f9bbc 100644 --- a/src/bufferq.c +++ b/src/bufferq.c @@ -10,13 +10,11 @@ #define SA_BUFFERQ_ITEM_CONCAT_DATA(x) ((void*) ((uint8_t*) (x) + SA_ALIGN(sizeof(sa_bufferq_item_t)))) -int sa_bufferq_init(sa_bufferq_t *q, unsigned nchannels, size_t sample_size) { +int sa_bufferq_init(sa_bufferq_t *q, unsigned nchannels) { sa_assert(q); - sa_assert(sample_size > 0); sa_assert(nchannels > 0); memset(q, 0, sizeof(*q)); - q->sample_size = sample_size; q->nchannels = nchannels; if (!(q->items = sa_new0(sa_bufferq_item_t*, nchannels))) @@ -175,7 +173,7 @@ int sa_bufferq_push(sa_bufferq_t *q, unsigned channel, const void *data, size_t } void sa_bufferq_get(sa_bufferq_t *q, void *i[], size_t *bytes) { - int first = 1; + sa_bool_t first = TRUE; unsigned u; sa_assert(q); @@ -193,7 +191,7 @@ void sa_bufferq_get(sa_bufferq_t *q, void *i[], size_t *bytes) { if (first) { *bytes = l; - first = 0; + first = FALSE; } else *bytes = l < *bytes ? l : *bytes; } else { @@ -205,7 +203,7 @@ void sa_bufferq_get(sa_bufferq_t *q, void *i[], size_t *bytes) { if (first) { *bytes = l; - first = 0; + first = FALSE; } else *bytes = l < *bytes ? l : *bytes; } @@ -215,7 +213,6 @@ void sa_bufferq_get(sa_bufferq_t *q, void *i[], size_t *bytes) { } } - void sa_bufferq_drop(sa_bufferq_t *q, int64_t bytes) { unsigned u; @@ -244,19 +241,22 @@ void sa_bufferq_drop(sa_bufferq_t *q, int64_t bytes) { int sa_bufferq_realloc(sa_bufferq_t *q) { unsigned u; - int fail = 0; + sa_bool_t fail = FALSE; sa_assert(q); for (u = 0; u < q->nchannels; u++) { sa_bufferq_item_t *i; + /* FIXME: This goes through the list linearly. We might need + * to optimize this a little */ + for (i = q->items[u]; i; i = i->bufferq_next) { if (i->type != SA_BUFFERQ_ITEM_STATIC) continue; if (!bufferq_item_make_writable(i)) { - fail = 1; + fail = TRUE; /* Hmm, we couldn't allocate memory, but we can't * return without doing anything, hence let's at least diff --git a/src/bufferq.h b/src/bufferq.h index 2d53a45..0f87fc9 100644 --- a/src/bufferq.h +++ b/src/bufferq.h @@ -25,11 +25,10 @@ typedef struct sa_bufferq { SA_LLIST_HEAD(sa_bufferq_item_t, *items); sa_bufferq_item_t **last; int64_t read_index, write_index, end_index; - size_t sample_size; unsigned nchannels; } sa_bufferq_t; -int sa_bufferq_init(sa_bufferq_t *q, unsigned nchannels, size_t sample_size); +int sa_bufferq_init(sa_bufferq_t *q, unsigned nchannels); void sa_bufferq_done(sa_bufferq_t *q); diff --git a/src/common.c b/src/common.c index b366563..0187990 100644 --- a/src/common.c +++ b/src/common.c @@ -166,7 +166,7 @@ int sa_stream_destroy(sa_stream_t *s) { int ret; unsigned u; - sa_return_val_if_fail_mutex(s->mutex, s, SA_ERROR_INVALID); + sa_return_val_if_fail(s, SA_ERROR_INVALID); ret = driver_destroy(s); diff --git a/src/converter.c b/src/converter.c index d895d83..90dba34 100644 --- a/src/converter.c +++ b/src/converter.c @@ -21,7 +21,7 @@ #include "malloc.h" #include "resample.h" -/* Steps: byteswap -> convert -> volscale -> remap -> resample -> convert -> byteswap -> interleave */ +/* Steps: byteswap -> convert -> volscale -> remap -> resample -> convert -> byteswap -> interleave|serialize */ /* Sample formats we know to process natively */ static int native_pcm_format_process(sa_pcm_format_t f) { @@ -333,6 +333,8 @@ int sa_converter_init( if (sa_bbuffer_init(&c->bb_tmp, 1, 1) < 0) goto fail; + if (c + return 0; fail: @@ -391,8 +393,8 @@ void* sa_converter_get_zero_buffer(sa_converter_t *c, size_t size) { int sa_converter_go( sa_converter_t *c, - const void *const src[], const size_t sstr[], sa_bool_t sinterleave, - void **dst[], size_t *dstr[], sa_bool_t dinterleave, + const void *const src[], const size_t sstr[], sa_interleave_t sinterleave, + void **dst[], size_t *dstr[], sa_interleave_t dinterleave, size_t *size) { size_t* stride; @@ -406,8 +408,6 @@ int sa_converter_go( is_bounce = FALSE; stride = (size_t*) sstr; process_data = (void**) src; - interleave = !!sinterleave; - dinterleave = !!dinterleave; if (c->no_volume && !c->remap_required && @@ -422,12 +422,12 @@ int sa_converter_go( if (c->pre_byteswap_func) { size_t k; - k = dinterleave ? c->from_sample_size*c->from_nchannels : c->from_sample_size; + k = dinterleave == SA_INTERLEAVE_YES ? c->from_sample_size*c->from_nchannels : c->from_sample_size; for (i = 0; i < c->from_nchannels; i++) { void *b; - if (!(b = sa_bbuffer_get(&c->bb_pre_byteswap, i, *size, dinterleave))) + if (!(b = sa_bbuffer_get(&c->bb_pre_byteswap, i, *size, dinterleave == SA_INTERLEAVE_YES))) return SA_ERROR_OOM; c->pre_byteswap_func(b, k, process_data[i], stride[i], *size); @@ -455,12 +455,12 @@ int sa_converter_go( size_t k, new_size; new_size = *size / c->from_sample_size * c->work_sample_size; - k = dinterleave ? c->work_sample_size*c->from_nchannels : c->work_sample_size; + k = dinterleave == SA_INTERLEAVE_YES ? c->work_sample_size*c->from_nchannels : c->work_sample_size; for (i = 0; i < c->from_nchannels; i++) { void *b; - if (!(b = sa_bbuffer_get(&c->bb_pre_format, i, new_size, dinterleave))) + if (!(b = sa_bbuffer_get(&c->bb_pre_format, i, new_size, dinterleave == SA_INTERLEAVE_YES))) return SA_ERROR_OOM; c->pre_format_func(&c->bb_tmp, b, k, process_data[i], stride[i], *size); @@ -491,12 +491,12 @@ int sa_converter_go( } else { size_t k; - k = dinterleave ? c->work_sample_size*c->from_nchannels : c->work_sample_size; + k = dinterleave == SA_INTERLEAVE_YES ? c->work_sample_size*c->from_nchannels : c->work_sample_size; for (i = 0; i < c->from_nchannels; i++) { void *b; - if (!(b = sa_bbuffer_get(&c->bb_volscale, i, *size, dinterleave))) + if (!(b = sa_bbuffer_get(&c->bb_volscale, i, *size, dinterleave == SA_INTERLEAVE_YES))) return SA_ERROR_OOM; c->volscale_func(b, k, process_data[i], stride[i], c->volume_factor[i], c->volume_divisor[i], *size); @@ -513,9 +513,9 @@ int sa_converter_go( if (c->remap_required) { size_t k; - int need_proper_interleave = 0; + sa_bool_t need_proper_interleave = FALSE; - k = dinterleave ? c->work_sample_size*c->to_nchannels : c->work_sample_size; + k = dinterleave == SA_INTERLEAVE_YES ? c->work_sample_size*c->to_nchannels : c->work_sample_size; for (i = 0; i < c->to_nchannels; i++) { void *b; @@ -530,20 +530,20 @@ int sa_converter_go( c->to_process_data[i] = b; c->to_stride[i] = c->work_sample_size; - need_proper_interleave = 1; + need_proper_interleave = TRUE; } else if (p[1] == -1) { /* Just one channel, nothing to mix */ c->to_process_data[i] = process_data[p[0]]; c->to_stride[i] = stride[p[0]]; - need_proper_interleave = 1; + need_proper_interleave = TRUE; } else { int j; /* We have to mix two or more channels */ - if (!(b = sa_bbuffer_get(&c->bb_remap, i, *size, dinterleave))) + if (!(b = sa_bbuffer_get(&c->bb_remap, i, *size, dinterleave == SA_INTERLEAVE_YES))) return SA_ERROR_OOM; c->add_func(b, k, process_data[p[0]], stride[p[0]], process_data[p[1]], stride[p[1]], *size); @@ -558,7 +558,7 @@ int sa_converter_go( process_data = c->to_process_data; stride = c->to_stride; - interleave = need_proper_interleave ? -1 : dinterleave; + interleave = need_proper_interleave ? SA_INTERLEAVE_ANY : dinterleave; is_bounce = TRUE; } @@ -566,14 +566,14 @@ int sa_converter_go( size_t k; size_t new_size; - k = dinterleave ? c->work_sample_size*c->to_nchannels : c->work_sample_size; + k = dinterleave == SA_INTERLEAVE_YES ? c->work_sample_size*c->to_nchannels : c->work_sample_size; new_size = (size_t) (((((uint64_t) *size+c->work_sample_size-1)/c->work_sample_size)*c->to_rate)/c->from_rate+1)*c->work_sample_size; /* FIXME */ for (i = 0; i < c->to_nchannels; i++) { void *b; - if (!(b = sa_bbuffer_get(&c->bb_resample, i, new_size, dinterleave))) + if (!(b = sa_bbuffer_get(&c->bb_resample, i, new_size, dinterleave == SA_INTERLEAVE_YES))) return SA_ERROR_OOM; c->resample_func(c->speex, i, b, k, process_data[i], stride[i], *size, &new_size); @@ -601,13 +601,13 @@ int sa_converter_go( } else { size_t k, new_size; - k = dinterleave ? c->to_sample_size*c->to_nchannels : c->to_sample_size; + k = dinterleave == SA_INTERLEAVE_YES ? c->to_sample_size*c->to_nchannels : c->to_sample_size; new_size = *size / c->work_sample_size * c->to_sample_size; for (i = 0; i < c->to_nchannels; i++) { void *b; - if (!(b = sa_bbuffer_get(&c->bb_post_format, i, new_size, dinterleave))) + if (!(b = sa_bbuffer_get(&c->bb_post_format, i, new_size, dinterleave == SA_INTERLEAVE_YES))) return SA_ERROR_OOM; c->post_format_func(&c->bb_tmp, b, k, process_data[i], stride[i], *size); @@ -636,12 +636,12 @@ int sa_converter_go( } else { size_t k; - k = dinterleave ? c->to_sample_size*c->to_nchannels : c->to_sample_size; + k = dinterleave == SA_INTERLEAVE_YES ? c->to_sample_size*c->to_nchannels : c->to_sample_size; for (i = 0; i < c->to_nchannels; i++) { void *b; - if (!(b = sa_bbuffer_get(&c->bb_post_byteswap, i, *size, dinterleave))) + if (!(b = sa_bbuffer_get(&c->bb_post_byteswap, i, *size, dinterleave == SA_INTERLEAVE_YES))) return SA_ERROR_OOM; c->post_byteswap_func(b, k, process_data[i], stride[i], *size); @@ -659,15 +659,15 @@ int sa_converter_go( do_interleave: - if (interleave != dinterleave) { + if (dinterleave != SA_INTERLEAVE_ANY && interleave != dinterleave) { size_t k; - k = dinterleave ? c->to_sample_size*c->to_nchannels : c->to_sample_size; + k = dinterleave == SA_INTERLEAVE_YES ? c->to_sample_size*c->to_nchannels : c->to_sample_size; for (i = 0; i < c->to_nchannels; i++) { void *b; - if (!(b = sa_bbuffer_get(&c->bb_interleave, i, *size, dinterleave))) + if (!(b = sa_bbuffer_get(&c->bb_interleave, i, *size, dinterleave == SA_INTERLEAVE_ANY))) return SA_ERROR_OOM; c->interleave_func(b, k, process_data[i], stride[i], *size); @@ -723,7 +723,7 @@ void sa_converter_set_volume(sa_converter_t *c, const int32_t vol[]) { int sa_converter_go_interleaved( sa_converter_t *c, const void *const data, - void **dst[], size_t *dstr[], int dinterleave, + void **dst[], size_t *dstr[], sa_bool_t dinterleave, size_t *size) { unsigned i; @@ -731,12 +731,12 @@ int sa_converter_go_interleaved( unsigned stride = c->from_nchannels * c->from_sample_size; for (i = 0; i < c->from_nchannels; i++) { - c->from_process_data[i] = (void*) data; + c->from_process_data[i] = (void*) d; d += c->from_sample_size; c->from_stride[i] = stride; } - return sa_converter_go(c, (const void *const*) c->from_process_data, c->from_stride, 1, dst, dstr, dinterleave, size); + return sa_converter_go(c, (const void *const*) c->from_process_data, c->from_stride, SA_INTERLEAVE_YES, dst, dstr, dinterleave, size); } void sa_converter_set_ratio(sa_converter_t *c, unsigned rate1, unsigned rate2) { diff --git a/src/converter.h b/src/converter.h index 39338c2..a3ec182 100644 --- a/src/converter.h +++ b/src/converter.h @@ -14,6 +14,12 @@ typedef struct sa_converter sa_converter_t; +typedef enum { + SA_INTERLEAVE_YES, /* samples are interleaved; left, right, left, right */ + SA_INTERLEAVE_NO, /* samples are managed in seperate blocks */ + SA_INTERLEAVE_ANY /* we don't care or don't know if the samples are interleaved or not */ +} sa_interleave_t; + struct sa_converter { sa_pcm_format_t from_pcm_format, to_pcm_format; unsigned from_nchannels, to_nchannels; @@ -63,14 +69,14 @@ void sa_converter_done(sa_converter_t *c); int sa_converter_go( sa_converter_t *c, - const void *const src[], const size_t sstr[], int sinterleave, - void **dst[], size_t *dstr[], int dinterleave, + const void *const src[], const size_t sstr[], sa_interleave_t sinterleave, + void **dst[], size_t *dstr[], sa_interleave_t dinterleave, size_t *size); int sa_converter_go_interleaved( sa_converter_t *c, const void *const data, - void **dst[], size_t *dstr[], int dinterleave, + void **dst[], size_t *dstr[], sa_interleave_t dinterleave, size_t *size); void sa_converter_set_volume(sa_converter_t *c, const int32_t vol[]); diff --git a/src/oss.c b/src/oss.c index 4e9cf4e..410fa45 100644 --- a/src/oss.c +++ b/src/oss.c @@ -38,6 +38,8 @@ struct oss_stream { sa_thread *thread; int socket_fds[2]; sa_bufferq_t bufferq; + + void *cdata; }; static int simple_log2(int v) { @@ -558,7 +560,10 @@ int driver_open(sa_stream_t *s) { if (s->mode & SA_MODE_WRONLY) printf("Chosen for write: %u fragments, %u fragsize\n", oss->write_nfragments, oss->write_fragment_size); - if (sa_bufferq_init(&oss->bufferq, s->pcm_attrs.nchannels, s->pcm_sample_size) < 0) + if (sa_bufferq_init(&oss->bufferq, s->ni_enabled ? s->pcm_attrs.nchannels : 1) < 0) + goto fail; + + if ((oss->cdata = pa_new(void*, s->ni_enabled ? s->pcm_attrs.nchannels : 1) < 0) goto fail; return SA_SUCCESS; @@ -585,6 +590,8 @@ int driver_destroy(sa_stream_t *s) { sa_converter_done(&oss->converter_read); sa_converter_done(&oss->converter_write); + sa_free(oss->cdata); + sa_free(oss); } @@ -603,30 +610,37 @@ static int feed(sa_stream_t *s) { return ret; while (w > 0) { - void* i[1]; size_t nbytes; uint8_t *d; - int drop; + sa_bool_t drop; - sa_bufferq_get(&oss->bufferq, i, &nbytes); + sa_bufferq_get(&oss->bufferq, cdata, &nbytes); - if (nbytes) { + if (nbytes > 0) { void **dst; size_t *stride; - if ((ret = sa_converter_go_interleaved(&oss->converter_write, i[0], &dst, &stride, 1, &nbytes))) - return ret; + if (s->ni_enabled) { + + if ((ret = sa_converter_go(&oss->converter_write, cdata, &dst, &stride, - d = dst[0]; - drop = 1; + } else { + + if ((ret = sa_converter_go_interleaved(&oss->converter_write, cdata, &dst, &stride, 1, &nbytes))) + goto fail; + + d = dst[0]; + } + drop = TRUE; s->state = SA_STATE_RUNNING; } else { nbytes = w > oss->write_fragment_size ? oss->write_fragment_size : w; - if (!(d = sa_converter_get_zero_buffer(&oss->converter_write, nbytes))) - return SA_ERROR_OOM; + if (!(d = sa_converter_get_zero_buffer(&oss->converter_write, nbytes))) { + ret = SA_ERROR_OOM; + goto fail; drop = s->xrun_mode == SA_XRUN_MODE_SPIN; @@ -637,8 +651,10 @@ static int feed(sa_stream_t *s) { while (nbytes > 0) { ssize_t l; - if ((l = write(oss->fd, d, nbytes)) < 0) - return SA_ERROR_SYSTEM; + if ((l = write(oss->fd, d, nbytes)) < 0) { + ret = SA_ERROR_SYSTEM; + goto fail; + } sa_assert(l > 0); @@ -653,12 +669,18 @@ static int feed(sa_stream_t *s) { } } - return SA_SUCCESS; + ret = SA_SUCCESS; + +fail: + + sa_free(i); + + return ret; } enum { POLLFD_OSS_FD, - POLLFD_SOCKET_FD, + POLLFD_PIPE_FD, POLLFD_MAX }; @@ -668,8 +690,8 @@ static void thread_func(void *data) { oss_stream_t *oss = OSS_STREAM(s); sigset_t mask; - sigfillset(&mask); - pthread_sigmask(SIG_BLOCK, &mask, NULL); + sa_assert_se(sigfillset(&mask) == 0); + sa_assert_se(pthread_sigmask(SIG_BLOCK, &mask, NULL) == 0); if (s->callback) { s->event = SA_EVENT_INIT_THREAD; @@ -687,6 +709,7 @@ static void thread_func(void *data) { for (;;) { int ret; + if (poll(pollfds, POLLFD_MAX, -1) < 0) { if (errno == EINTR) continue; diff --git a/src/sydney.h b/src/sydney.h index eb1a7ec..58324ca 100644 --- a/src/sydney.h +++ b/src/sydney.h @@ -5,15 +5,23 @@ extern "C" { #endif -/* Requirements: +/* + Requirements & General observations + + - In sync mode, the device will automatically write data so that an + initial read causes writes of zeros to be issued to that one can + do "while (1); {read(); write()} + - All functions are thread-safe and can be called in any thread + context. None of the functions is async-signal safe. + - It is assumed that duplex streams have a single clock (synchronised) + - Property set extensible. To be kept in sync with PulseAudio and libsydney. + - Property keys need to be valid UTF-8, text values, too. + - Will warn if application.name or application.id not set. + - Error codes are returned immediately, as negative integers + - application.process.* will be filled in automatically but may be overwritten by the client. + They thus should not be used for authentication purposes. + - It is recommended to set most properties before the _open() call. -- In sync mode, the device will automatically write data so that an initial read causes writes -of zeros to be issued to that one can do "while (1); {read(); write()} - -- All functions are thread-safe and can be called in any thread context. None of the functions is -async-signal safe. - -- It is assumed that duplex streams have a single clock (synchronised) */ #include @@ -22,15 +30,16 @@ async-signal safe. /* Detect byte order, based on sys/param.h */ #if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || defined(WIN32) -# define SA_LITTLE_ENDIAN 1 -# undef SA_BIG_ENDIAN +#define SA_LITTLE_ENDIAN 1 +#undef SA_BIG_ENDIAN #elif (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) -# undef SA_LITTLE_ENDIAN -# define SA_BIG_ENDIAN 1 +#undef SA_LITTLE_ENDIAN +#define SA_BIG_ENDIAN 1 #else -# error "Cannot determine byte order!" +#error "Cannot determine byte order!" #endif +/** Stream object */ typedef struct sa_stream sa_stream_t; /** Volume that corresponds to muted in/out */ @@ -96,7 +105,7 @@ typedef enum { } sa_mode_t; /** Error codes */ -typedef enum { +enum { SA_SUCCESS = 0, SA_ERROR_NOT_SUPPORTED = -1, SA_ERROR_INVALID = -2, @@ -112,7 +121,7 @@ typedef enum { SA_ERROR_NO_DATA = -11, SA_ERROR_NO_SPACE = -12, _SA_ERROR_MAX = -13 -} sa_error_t; +}; /** Possible events for notifications */ typedef enum { @@ -130,6 +139,7 @@ typedef enum { SA_EVENT_INIT_THREAD, SA_EVENT_NOTIFY, SA_EVENT_ERROR, + SA_EVENT_XRUN, _SA_EVENT_MAX } sa_event_t; @@ -208,6 +218,7 @@ typedef enum { SA_STATE_INIT, SA_STATE_RUNNING, SA_STATE_STOPPED, + SA_STATE_DRAINING, /* put more stuff */ _SA_STATE_MAX } sa_state_t; @@ -215,6 +226,7 @@ typedef enum { typedef enum { SA_XRUN_MODE_STOP, SA_XRUN_MODE_SPIN, + SA_XRUN_MODE_FILL, _SA_XRUN_MODE_MAX } sa_xrun_mode_t; @@ -224,18 +236,31 @@ typedef enum { SA_ADJUST_NONE = 0 } sa_adjust_t; -/* Some kind of meta information. */ -#define SA_META_CLIENT_NAME "sydney.client-name" /* utf-8 */ -#define SA_META_PROCESS_ID "sydney.process-id" /* getpid() */ -#define SA_META_LANGUAGE "sydney.language" /* de_DE and similar */ - -/* Some kind of meta information. Not filled in */ -#define SA_META_STREAM_NAME "sydney.stream-name" /* utf-8 */ -#define SA_META_ICON_NAME "sydney.icon-name" /* file name (no slashes) */ -#define SA_META_ICON_PNG "sydney.icon-png" /* PNG blob */ -#define SA_META_ROLE "sydney.role" /* one of: "music", "phone", "game", "event" */ -#define SA_META_X11_DISPLAY "sydney.x11-display" /* X11 display */ -#define SA_META_X11_WINDOW "sydney.x11-window" /* X11 window id */ +/** Stream properties */ +#define SA_PROP_MEDIA_NAME "media.name" +#define SA_PROP_MEDIA_TITLE "media.title" +#define SA_PROP_MEDIA_ARTIST "media.artist" +#define SA_PROP_MEDIA_LANGUAGE "media.language" +#define SA_PROP_MEDIA_FILENAME "media.filename" +#define SA_PROP_MEDIA_ICON "media.icon" +#define SA_PROP_MEDIA_ICON_NAME "media.icon_name" +#define SA_PROP_MEDIA_ROLE "media.role" +#define SA_PROP_EVENT_ID "event.id" +#define SA_PROP_EVENT_X11_DISPLAY "event.x11.display" +#define SA_PROP_EVENT_X11_XID "event.x11.xid" +#define SA_PROP_EVENT_MOUSE_X "event.mouse.x" +#define SA_PROP_EVENT_MOUSE_Y "event.mouse.y" +#define SA_PROP_EVENT_MOUSE_BUTTON "event.mouse.button" +#define SA_PROP_APPLICATION_NAME "application.name" +#define SA_PROP_APPLICATION_ID "application.id" +#define SA_PROP_APPLICATION_VERSION "application.version" +#define SA_PROP_APPLICATION_ICON "application.icon" +#define SA_PROP_APPLICATION_ICON_NAME "application.icon_name" +#define SA_PROP_APPLICATION_LANGUAGE "application.language" +#define SA_PROP_APPLICATION_PROCESS_ID "application.process.id" +#define SA_PROP_APPLICATION_PROCESS_BINARY "application.process.binary" +#define SA_PROP_APPLICATION_PROCESS_USER "application.process.user" +#define SA_PROP_APPLICATION_PROCESS_HOST "application.process.host" /** Main callback function */ typedef int (*sa_event_callback_t)(sa_stream_t *s, sa_event_t event); @@ -252,11 +277,11 @@ int sa_stream_open(sa_stream_t *s); /** Close/destroy everything */ int sa_stream_destroy(sa_stream_t *s); -/* "Soft" params */ -/* int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size); */ -/* int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size); */ -/* int sa_stream_set_write_user_size(sa_stream_t *s, size_t size); */ -/* int sa_stream_set_read_user_size(sa_stream_t *s, size_t size); */ +/* Buffer params */ +int sa_stream_set_write_latency(sa_stream_t *s, size_t nbytes); +int sa_stream_set_write_wakeup(sa_stream_t *s, size_t nbytes); +int sa_stream_set_read_latency(sa_stream_t *s, size_t nbytes); +int sa_stream_set_read_wakeup(sa_stream_t *s, size_t nbytes); /** 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); @@ -270,13 +295,19 @@ int sa_stream_set_non_interleaved(sa_stream_t *s, int enable); /** Allow that the sample rate may be changed during runtime */ int sa_stream_set_dynamic_rate(sa_stream_t *s, int enabled); +/** Set the number of PCM channels for input */ +int sa_stream_set_read_pcm_nchannels(sa_stream *s, unsigned nchannels); + +/** Set the number of PCM channels for output */ +int sa_stream_set_write_pcm_nchannels(sa_stream *s, unsigned nchannels); + /** Select driver */ int sa_stream_set_driver(sa_stream_t *s, const char *driver); -/** Start callback */ +/** Start callback thread */ int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t callback); -/** Start callback */ +/** Start callback thread */ int sa_stream_stop_thread(sa_stream_t *s); /** Change the device connected to the stream */ @@ -291,9 +322,6 @@ int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned /** Change the sampling rate */ int sa_stream_change_rate(sa_stream_t *s, unsigned rate); -/** Change some meta data that is attached to the stream */ -int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size); - /** Associate opaque user data */ int sa_stream_change_user_data(sa_stream_t *s, const void *value); @@ -301,39 +329,37 @@ int sa_stream_change_user_data(sa_stream_t *s, const void *value); int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction); int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction); int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction); -/* int sa_stream_set_adjust_watermarks(sa_stream_t *s, sa_adjust_t direction); */ /* Query functions */ - int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode); int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size); int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *format); -int sa_stream_get_rate(sa_stream_t *s, unsigned *rate); -int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels); +int sa_stream_get_pcm_rate(sa_stream_t *s, unsigned *rate); +int sa_stream_get_pcm_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_write_latency(sa_stream_t *s, size_t *nbytes); +int sa_stream_get_write_wakeup(sa_stream_t *s, size_t *nbytes); +int sa_stream_get_read_latency(sa_stream_t *s, size_t *nbytes); +int sa_stream_get_read_wakeup(sa_stream_t *s, size_t *nbytes); +int sa_stream_get_pcm_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned *n); int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode); int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled); -int sa_stream_get_dynamic_rate(sa_stream_t *s, int *enabled); +int sa_stream_get_pcm_dynamic_rate(sa_stream_t *s, int *enabled); int sa_stream_get_driver(sa_stream_t *s, char *driver_name, size_t *size); int sa_stream_get_device(sa_stream_t *s, char *device_name, size_t *size); int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned *n); int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned *n); int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void*data, size_t *size); -int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction); -int sa_stream_get_adjust_nchannels(sa_stream_t *s, sa_adjust_t *direction); +int sa_stream_get_adjust_pcm_rate(sa_stream_t *s, sa_adjust_t *direction); +int sa_stream_get_adjust_pcm_nchannels(sa_stream_t *s, sa_adjust_t *direction); int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction); -/* int sa_stream_get_adjust_watermarks(sa_stream_t *s, sa_adjust_t *direction); */ + /** Get current state of the audio device */ int sa_stream_get_state(sa_stream_t *s, sa_state_t *state); /** Obtain the error code */ -int sa_stream_get_event_error(sa_stream_t *s, sa_error_t *error); +int sa_stream_get_event_error(sa_stream_t *s, int *error); /** Obtain the notification code */ int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify); @@ -360,18 +386,18 @@ int sa_stream_pwrite_ni(sa_stream_t *s, unsigned channel, const void *data, size /** Query how much can be read without blocking */ -int sa_stream_get_read_size(sa_stream_t *s, size_t *size); +int sa_stream_get_read_size(sa_stream_t *s, size_t *nbytes); /** Query how much can be written without blocking */ -int sa_stream_get_write_size(sa_stream_t *s, size_t *size); +int sa_stream_get_write_size(sa_stream_t *s, size_t *nbytes); /* Control/xrun */ /** Resume playing after a pause */ -int sa_stream_resume(sa_stream_t *s); +int sa_stream_start(sa_stream_t *s); /** Pause audio playback (do not empty the buffer) */ -int sa_stream_pause(sa_stream_t *s); +int sa_stream_stop(sa_stream_t *s); /** Block until all audio has been played */ int sa_stream_drain(sa_stream_t *s); @@ -379,6 +405,17 @@ int sa_stream_drain(sa_stream_t *s); /** Return a human readable error */ const char *sa_strerror(int code); +/* Stream properties */ + +/** Update meta data string properties that are attached to this stream. Takes a NULL terminated list of string key/value pairs. */ +int sa_stream_change_props(sa_stream_t *s, ...) SA_GCC_SENTINEL; + +/** Update abritrary meta data properties that are attached to this stream */ +int sa_stream_change_prop(sa_stream_t *s, const char *key, const void *data, size_t nbytes); + +/** Remove abritrary meta data properties that are attached to this stream */ +int sa_stream_remove_prop(sa_stream_t *s, ...) SA_GCC_SENTINEL; + #ifdef __cplusplus } #endif -- cgit