From 23039af8427140bafa92dce3021c1f2a14bcfbad Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jul 2009 15:49:33 +0100 Subject: client: allow zero-copy writing to the stream --- src/pulse/internal.h | 5 ++ src/pulse/stream.c | 145 ++++++++++++++++++++++++++++++++++++++------------- src/pulse/stream.h | 70 ++++++++++++++++++++++--- 3 files changed, 176 insertions(+), 44 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/internal.h b/src/pulse/internal.h index ec2da85b..e069c9e9 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -151,6 +151,11 @@ struct pa_stream { uint32_t device_index; char *device_name; + /* playback */ + pa_memblock *write_memblock; + void *write_data; + + /* recording */ pa_memchunk peek_memchunk; void *peek_data; pa_memblockq *record_memblockq; diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 40556329..5baf5c2c 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -144,12 +144,13 @@ pa_stream *pa_stream_new_with_proplist( s->suspended = FALSE; s->corked = FALSE; + s->write_memblock = NULL; + s->write_data = NULL; + pa_memchunk_reset(&s->peek_memchunk); s->peek_data = NULL; - s->record_memblockq = NULL; - memset(&s->timing_info, 0, sizeof(s->timing_info)); s->timing_info_valid = FALSE; @@ -221,6 +222,11 @@ static void stream_free(pa_stream *s) { stream_unlink(s); + if (s->write_memblock) { + pa_memblock_release(s->write_memblock); + pa_memblock_unref(s->write_data); + } + if (s->peek_memchunk.memblock) { if (s->peek_data) pa_memblock_release(s->peek_memchunk.memblock); @@ -1187,20 +1193,60 @@ int pa_stream_connect_record( return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL); } +int pa_stream_begin_write( + pa_stream *s, + void **data, + size_t *nbytes) { + + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, data, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, nbytes && *nbytes != 0, PA_ERR_INVALID); + + if (!s->write_memblock) { + s->write_memblock = pa_memblock_new(s->context->mempool, *nbytes); + s->write_data = pa_memblock_acquire(s->write_memblock); + } + + *data = s->write_data; + *nbytes = pa_memblock_get_length(s->write_memblock); + + return 0; +} + +int pa_stream_cancel_write( + pa_stream *s) { + + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->write_memblock, PA_ERR_BADSTATE); + + pa_assert(s->write_data); + + pa_memblock_release(s->write_memblock); + pa_memblock_unref(s->write_memblock); + s->write_memblock = NULL; + s->write_data = NULL; + + return 0; +} + int pa_stream_write( pa_stream *s, const void *data, size_t length, - void (*free_cb)(void *p), + pa_free_cb_t free_cb, int64_t offset, pa_seek_mode_t seek) { - pa_memchunk chunk; - pa_seek_mode_t t_seek; - int64_t t_offset; - size_t t_length; - const void *t_data; - pa_assert(s); pa_assert(PA_REFCNT_VALUE(s) >= 1); pa_assert(data); @@ -1210,46 +1256,71 @@ int pa_stream_write( PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, seek <= PA_SEEK_RELATIVE_END, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || (seek == PA_SEEK_RELATIVE && offset == 0), PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, + !s->write_memblock || + ((data >= s->write_data) && + ((const char*) data + length <= (const char*) s->write_data + pa_memblock_get_length(s->write_memblock))), + PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, !free_cb || !s->write_memblock, PA_ERR_INVALID); - if (length <= 0) - return 0; + if (s->write_memblock) { + pa_memchunk chunk; - t_seek = seek; - t_offset = offset; - t_length = length; - t_data = data; + /* pa_stream_write_begin() was called before */ - while (t_length > 0) { + pa_memblock_release(s->write_memblock); - chunk.index = 0; + chunk.memblock = s->write_memblock; + chunk.index = (const char *) data - (const char *) s->write_data; + chunk.length = length; - if (free_cb && !pa_pstream_get_shm(s->context->pstream)) { - chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) t_data, t_length, free_cb, 1); - chunk.length = t_length; - } else { - void *d; + s->write_memblock = NULL; + s->write_data = NULL; - chunk.length = PA_MIN(t_length, pa_mempool_block_size_max(s->context->mempool)); - chunk.memblock = pa_memblock_new(s->context->mempool, chunk.length); + pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk); + pa_memblock_unref(chunk.memblock); - d = pa_memblock_acquire(chunk.memblock); - memcpy(d, t_data, chunk.length); - pa_memblock_release(chunk.memblock); - } + } else { + pa_seek_mode_t t_seek = seek; + int64_t t_offset = offset; + size_t t_length = length; + const void *t_data = data; - pa_pstream_send_memblock(s->context->pstream, s->channel, t_offset, t_seek, &chunk); + /* pa_stream_write_begin() was not called before */ - t_offset = 0; - t_seek = PA_SEEK_RELATIVE; + while (t_length > 0) { + pa_memchunk chunk; - t_data = (const uint8_t*) t_data + chunk.length; - t_length -= chunk.length; + chunk.index = 0; - pa_memblock_unref(chunk.memblock); - } + if (free_cb && !pa_pstream_get_shm(s->context->pstream)) { + chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) t_data, t_length, free_cb, 1); + chunk.length = t_length; + } else { + void *d; + + chunk.length = PA_MIN(t_length, pa_mempool_block_size_max(s->context->mempool)); + chunk.memblock = pa_memblock_new(s->context->mempool, chunk.length); + + d = pa_memblock_acquire(chunk.memblock); + memcpy(d, t_data, chunk.length); + pa_memblock_release(chunk.memblock); + } - if (free_cb && pa_pstream_get_shm(s->context->pstream)) - free_cb((void*) data); + pa_pstream_send_memblock(s->context->pstream, s->channel, t_offset, t_seek, &chunk); + + t_offset = 0; + t_seek = PA_SEEK_RELATIVE; + + t_data = (const uint8_t*) t_data + chunk.length; + t_length -= chunk.length; + + pa_memblock_unref(chunk.memblock); + } + + if (free_cb && pa_pstream_get_shm(s->context->pstream)) + free_cb((void*) data); + } /* This is obviously wrong since we ignore the seeking index . But * that's OK, the server side applies the same error */ diff --git a/src/pulse/stream.h b/src/pulse/stream.h index 49c132a2..fecc5870 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -418,15 +418,71 @@ int pa_stream_connect_record( /** Disconnect a stream from a source/sink */ int pa_stream_disconnect(pa_stream *s); -/** Write some data to the server (for playback sinks), if free_cb is - * non-NULL this routine is called when all data has been written out - * and an internal reference to the specified data is kept, the data - * is not copied. If NULL, the data is copied into an internal - * buffer. The client my freely seek around in the output buffer. For +/** Prepare writing data to the server (for playback streams). This + * function may be used to optimize the number of memory copies when + * doing playback ("zero-copy"). It is recommended to call this + * function before each call to pa_stream_write(). Pass in the address + * to a pointer and an address of the number of bytes you want to + * write. On return the two values will contain a pointer where you + * can place the data to write and the maximum number of bytes you can + * write. On return *nbytes can be larger or have the same value as + * you passed in. You need to be able to handle both cases. Accessing + * memory beyond the returned *nbytes value is invalid. Acessing the + * memory returned after the following pa_stream_write() or + * pa_stream_cancel_write() is invalid. On invocation only *nbytes + * needs to be initialized, on return both *data and *nbytes will be + * valid. If you place (size_t) -1 in *nbytes on invocation the memory + * size will be chosen automatically (which is recommended to + * do). After placing your data in the memory area returned call + * pa_stream_write() with data set to an address within this memory + * area and an nbytes value that is smaller or equal to what was + * returned by this function to actually execute the write. An + * invocation of pa_stream_write() should follow "quickly" on + * pa_stream_begin_write(). It is not recommended letting an unbounded + * amount of time pass after calling pa_stream_begin_write() and + * before calling pa_stream_write(). If you want to cancel a + * previously called pa_stream_begin_write() without calling + * pa_stream_write() use pa_stream_cancel_write() instead. Calling + * pa_stream_begin_write() twice without calling pa_stream_write() or + * pa_stream_cancel_write() in between will return exactly the same + * pointer/nbytes values.\since 0.9.16 */ +int pa_stream_begin_write( + pa_stream *p, + void **data, + size_t *nbytes); + +/** Reverses the effect of pa_stream_begin_write() dropping all data + * that has already been placed in the memory area returned by + * pa_stream_begin_write(). Only valid to call if + * pa_stream_begin_write() was called before and neither + * pa_stream_cancel_write() nor pa_stream_write() have been called + * yet. Accessing the memory previously returned by + * pa_stream_begin_write() after this call is invalid. Any further + * explicit freeing of the memory area is not necessary. \since + * 0.9.16 */ +int pa_stream_cancel_write( + pa_stream *p); + +/** Write some data to the server (for playback streams), if free_cb + * is non-NULL this routine is called when all data has been written + * out and an internal reference to the specified data is kept, the + * data is not copied. If NULL, the data is copied into an internal + * buffer. The client may freely seek around in the output buffer. For * most applications passing 0 and PA_SEEK_RELATIVE as arguments for * offset and seek should be useful. Afte ther write call succeeded * the write index will be a the position after where this chunk of - * data has been written to. */ + * data has been written to. + * + * As an optimization for avoiding needless memory copies you may call + * pa_stream_begin_write() before this call and then place your audio + * data directly in the memory area returned by that call. Then, pass + * a pointer to that memory area to pa_stream_write(). After the + * invocation of pa_stream_write() the memory area may no longer be + * accessed. Any further explicit freeing of the memory area is not + * necessary. It is OK to write the memory area returned by + * pa_stream_begin_write() only partially with this call, skipping + * bytes both at the end and at the beginning of the reserved memory + * area.*/ int pa_stream_write( pa_stream *p /**< The stream to use */, const void *data /**< The data to write */, @@ -435,7 +491,7 @@ int pa_stream_write( int64_t offset, /**< Offset for seeking, must be 0 for upload streams */ pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); -/** Read the next fragment from the buffer (for recording). +/** Read the next fragment from the buffer (for recording streams). * data will point to the actual data and length will contain the size * of the data in bytes (which can be less than a complete framgnet). * Use pa_stream_drop() to actually remove the data from the -- cgit From f6763917ee757845e2c52e36975d948bc93d8b6e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 18:22:13 +0200 Subject: autospawn: refuse autospawning if process disabled waitpid() --- src/pulse/context.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/context.c b/src/pulse/context.c index 4ded5565..ab1c1638 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -668,11 +668,24 @@ static pa_strlist *prepend_per_user(pa_strlist *l) { static int context_autospawn(pa_context *c) { pid_t pid; int status, r; - - pa_log_debug("Trying to autospawn..."); + struct sigaction sa; pa_context_ref(c); + if (sigaction(SIGCHLD, NULL, &sa) < 0) { + pa_log_debug("sigaction() failed: %s", pa_cstrerror(errno)); + pa_context_fail(c, PA_ERR_INTERNAL); + goto fail; + } + + if ((sa.sa_flags & SA_NOCLDWAIT) || sa.sa_handler == SIG_IGN) { + pa_log_debug("Process disabled waitpid(), cannot autospawn."); + pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); + goto fail; + } + + pa_log_debug("Trying to autospawn..."); + if (c->spawn_api.prefork) c->spawn_api.prefork(); -- cgit From 5efb07281d5be1cddaed5b0610325fedd7f599ec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 20:13:52 +0200 Subject: alsa: throw timing data away after device resume --- src/pulse/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 5baf5c2c..a22816ae 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -827,7 +827,7 @@ static void create_stream_complete(pa_stream *s) { if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC; pa_assert(!s->auto_timing_update_event); - s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s); + s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s); request_auto_timing_update(s, TRUE); } -- cgit From e7ca058427e795b9c2b436c4a819e8d8354ee9de Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 20:20:34 +0200 Subject: client: make volume struct const --- src/pulse/stream.c | 2 +- src/pulse/stream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.c b/src/pulse/stream.c index a22816ae..bbd01499 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -1172,7 +1172,7 @@ int pa_stream_connect_playback( const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, - pa_cvolume *volume, + const pa_cvolume *volume, pa_stream *sync_stream) { pa_assert(s); diff --git a/src/pulse/stream.h b/src/pulse/stream.h index fecc5870..eeffc0c9 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -405,7 +405,7 @@ int pa_stream_connect_playback( const char *dev /**< Name of the sink to connect to, or NULL for default */ , const pa_buffer_attr *attr /**< Buffering attributes, or NULL for default */, pa_stream_flags_t flags /**< Additional flags, or 0 for default */, - pa_cvolume *volume /**< Initial volume, or NULL for default */, + const pa_cvolume *volume /**< Initial volume, or NULL for default */, pa_stream *sync_stream /**< Synchronize this stream with the specified one, or NULL for a standalone stream*/); /** Connect the stream to a source */ -- cgit From 211d0f3dcb23c6d63dd6a212826a872ce972e4ee Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 20:21:30 +0200 Subject: client: limit block size for zero-copy operations to mempool block size --- src/pulse/stream.c | 11 +++++++++++ src/pulse/stream.h | 13 +++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.c b/src/pulse/stream.c index bbd01499..72d49e11 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -1207,6 +1207,17 @@ int pa_stream_begin_write( PA_CHECK_VALIDITY(s->context, data, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, nbytes && *nbytes != 0, PA_ERR_INVALID); + if (*nbytes != (size_t) -1) { + size_t m, fs; + + m = pa_mempool_block_size_max(s->context->mempool); + fs = pa_frame_size(&s->sample_spec); + + m = (m / fs) * fs; + if (*nbytes > m) + *nbytes = m; + } + if (!s->write_memblock) { s->write_memblock = pa_memblock_new(s->context->mempool, *nbytes); s->write_data = pa_memblock_acquire(s->write_memblock); diff --git a/src/pulse/stream.h b/src/pulse/stream.h index eeffc0c9..cb8b74dc 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -425,7 +425,7 @@ int pa_stream_disconnect(pa_stream *s); * to a pointer and an address of the number of bytes you want to * write. On return the two values will contain a pointer where you * can place the data to write and the maximum number of bytes you can - * write. On return *nbytes can be larger or have the same value as + * write. On return *nbytes can be smaller or have the same value as * you passed in. You need to be able to handle both cases. Accessing * memory beyond the returned *nbytes value is invalid. Acessing the * memory returned after the following pa_stream_write() or @@ -442,7 +442,7 @@ int pa_stream_disconnect(pa_stream *s); * amount of time pass after calling pa_stream_begin_write() and * before calling pa_stream_write(). If you want to cancel a * previously called pa_stream_begin_write() without calling - * pa_stream_write() use pa_stream_cancel_write() instead. Calling + * pa_stream_write() use pa_stream_cancel_write(). Calling * pa_stream_begin_write() twice without calling pa_stream_write() or * pa_stream_cancel_write() in between will return exactly the same * pointer/nbytes values.\since 0.9.16 */ @@ -492,10 +492,11 @@ int pa_stream_write( pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); /** Read the next fragment from the buffer (for recording streams). - * data will point to the actual data and length will contain the size - * of the data in bytes (which can be less than a complete framgnet). - * Use pa_stream_drop() to actually remove the data from the - * buffer. If no data is available will return a NULL pointer */ + * data will point to the actual data and nbytes will contain the size + * of the data in bytes (which can be less or more than a complete + * fragment). Use pa_stream_drop() to actually remove the data from + * the buffer. If no data is available this will return a NULL + * pointer */ int pa_stream_peek( pa_stream *p /**< The stream to use */, const void **data /**< Pointer to pointer that will point to data */, -- cgit From 6ce7d208f066f02ee837686e81faa1463a5e2945 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 25 Jul 2009 01:29:36 +0200 Subject: client: if a child we created was already reaped, assume that it was successful --- src/pulse/context.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/context.c b/src/pulse/context.c index ab1c1638..7ba33249 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -743,9 +743,16 @@ static int context_autospawn(pa_context *c) { } while (r < 0 && errno == EINTR); if (r < 0) { - pa_log(_("waitpid(): %s"), pa_cstrerror(errno)); - pa_context_fail(c, PA_ERR_INTERNAL); - goto fail; + + if (errno != ESRCH) { + pa_log(_("waitpid(): %s"), pa_cstrerror(errno)); + pa_context_fail(c, PA_ERR_INTERNAL); + goto fail; + } + + /* hmm, something already reaped our child, so we assume + * startup worked, even if we cannot know */ + } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); goto fail; -- cgit From 8343360da1d8d93e8e3818ab91e7f764a1c8c99e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 25 Jul 2009 03:11:09 +0200 Subject: client: minor modernizations --- src/pulse/context.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/context.c b/src/pulse/context.c index 7ba33249..7c3717fa 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -701,9 +701,8 @@ static int context_autospawn(pa_context *c) { /* Child */ const char *state = NULL; -#define MAX_ARGS 64 - const char * argv[MAX_ARGS+1]; - int n; + const char * argv[32]; + unsigned n = 0; if (c->spawn_api.atfork) c->spawn_api.atfork(); @@ -712,12 +711,10 @@ static int context_autospawn(pa_context *c) { /* Setup argv */ - n = 0; - argv[n++] = c->conf->daemon_binary; argv[n++] = "--start"; - while (n < MAX_ARGS) { + while (n < PA_ELEMENTSOF(argv)-1) { char *a; if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) @@ -727,10 +724,10 @@ static int context_autospawn(pa_context *c) { } argv[n++] = NULL; + pa_assert(n <= PA_ELEMENTSOF(argv)); execv(argv[0], (char * const *) argv); _exit(1); -#undef MAX_ARGS } /* Parent */ -- cgit From 4f5e2b745ea357e2b5c815ff33a556505a7d1f18 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Jul 2009 23:46:25 +0200 Subject: threaded-mainloop: loop around pa_cond_wait() invocation in pa_threaded_mainloop_signal() --- src/pulse/thread-mainloop.c | 13 ++++++++++--- src/pulse/thread-mainloop.h | 4 +++- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index 6916d867..a2b98ce1 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -51,7 +51,7 @@ struct pa_threaded_mainloop { pa_mainloop *real_mainloop; - int n_waiting; + int n_waiting, n_waiting_for_accept; pa_thread* thread; pa_mutex* mutex; @@ -190,8 +190,12 @@ void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { pa_cond_signal(m->cond, 1); - if (wait_for_accept && m->n_waiting > 0) - pa_cond_wait(m->accept_cond, m->mutex); + if (wait_for_accept) { + m->n_waiting_for_accept ++; + + while (m->n_waiting_for_accept > 0) + pa_cond_wait(m->accept_cond, m->mutex); + } } void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { @@ -214,6 +218,9 @@ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { /* Make sure that this function is not called from the helper thread */ pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); + pa_assert(m->n_waiting_for_accept > 0); + m->n_waiting_for_accept --; + pa_cond_signal(m->accept_cond, 0); } diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h index 8eddce4c..41159d98 100644 --- a/src/pulse/thread-mainloop.h +++ b/src/pulse/thread-mainloop.h @@ -274,7 +274,9 @@ void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m); * inside the event loop thread. Prior to this call the event loop * object needs to be locked using pa_threaded_mainloop_lock(). While * waiting the lock will be released, immediately before returning it - * will be acquired again. */ + * will be acquired again. This function may spuriously wake up even + * without _signal() being called. You need to make sure to handle + * that! */ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); /** Signal all threads waiting for a signalling event in -- cgit From 2952f28c06b254f358ec9b3354dfc05c17a7b871 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 31 Jul 2009 23:07:07 +0200 Subject: client: fix documentation for threaded mainloop Closes #553 --- src/pulse/thread-mainloop.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h index 41159d98..e847070d 100644 --- a/src/pulse/thread-mainloop.h +++ b/src/pulse/thread-mainloop.h @@ -137,15 +137,19 @@ PA_C_DECL_BEGIN * The main function, my_drain_stream_func(), will wait for the callback to * be called using pa_threaded_mainloop_wait(). * - * If your application is multi-threaded, then this waiting must be done - * inside a while loop. The reason for this is that multiple threads might be - * using pa_threaded_mainloop_wait() at the same time. Each thread must - * therefore verify that it was its callback that was invoked. + * If your application is multi-threaded, then this waiting must be + * done inside a while loop. The reason for this is that multiple + * threads might be using pa_threaded_mainloop_wait() at the same + * time. Each thread must therefore verify that it was its callback + * that was invoked. Also the underlying OS synchronization primitives + * are usually not free of spurious wake-ups, so a + * pa_threaded_mainloop_wait() must be called within a loop even if + * you have only one thread waiting. * * The callback, my_drain_callback(), indicates to the main function that it * has been called using pa_threaded_mainloop_signal(). * - * As you can see, both pa_threaded_mainloop_wait() may only be called with + * As you can see, pa_threaded_mainloop_wait() may only be called with * the lock held. The same thing is true for pa_threaded_mainloop_signal(), * but as the lock is held before the callback is invoked, you do not have to * deal with that. -- cgit From 478f3254b36f9f4281d58bb048a002096b8d0bb9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 31 Jul 2009 23:09:16 +0200 Subject: client: documented that pa_stream_drain() may only have a single operation active at a time Closes #552. --- src/pulse/stream.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.h b/src/pulse/stream.h index cb8b74dc..8a08421f 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -512,7 +512,9 @@ size_t pa_stream_writable_size(pa_stream *p); /** Return the number of bytes that may be read using pa_stream_peek()*/ size_t pa_stream_readable_size(pa_stream *p); -/** Drain a playback stream. Use this for notification when the buffer is empty */ +/** Drain a playback stream. Use this for notification when the buffer + * is empty. Please note that only one drain operation per stream may + * be issued at a time. */ pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); /** Request a timing info structure update for a stream. Use -- cgit From 3e2ab9b22ed95bab3c69b1ea32cf2b8449fe3427 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 3 Aug 2009 23:07:59 +0200 Subject: client: extend documentation on pa_operation_cancel() a bit --- src/pulse/operation.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/operation.h b/src/pulse/operation.h index 7b0dabdd..b6b5691d 100644 --- a/src/pulse/operation.h +++ b/src/pulse/operation.h @@ -40,7 +40,11 @@ pa_operation *pa_operation_ref(pa_operation *o); /** Decrease the reference count by one */ void pa_operation_unref(pa_operation *o); -/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ +/** Cancel the operation. Beware! This will not necessarily cancel the + * execution of the operation on the server side. However it will make + * sure that the callback associated with this operation will not be + * called anymore, effectively disabling the operation from the client + * side's view. */ void pa_operation_cancel(pa_operation *o); /** Return the current status of the operation */ -- cgit From a4bc41a7a505c3acfe329d1a64cd82e7538a1e8f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:03:49 +0200 Subject: simple: use PA_xxx_IS_GOOD for state checks --- src/pulse/simple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index f4481fc3..bd11cb37 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -70,8 +70,8 @@ struct pa_simple { #define CHECK_DEAD_GOTO(p, rerror, label) \ do { \ - if (!(p)->context || pa_context_get_state((p)->context) != PA_CONTEXT_READY || \ - !(p)->stream || pa_stream_get_state((p)->stream) != PA_STREAM_READY) { \ + if (!(p)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((p)->context)) || \ + !(p)->stream || !PA_STREAM_IS_GOOD(pa_stream_get_state((p)->stream))) { \ if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \ ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \ if (rerror) \ -- cgit From b553e7283d3ec38080d6544672b920b9811c1a89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:04:08 +0200 Subject: simple: use pa_xnew0 instead of manual reset to 0 --- src/pulse/simple.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index bd11cb37..7fd7cce7 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -157,12 +157,8 @@ pa_simple* pa_simple_new( CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) - p = pa_xnew(pa_simple, 1); - p->context = NULL; - p->stream = NULL; + p = pa_xnew0(pa_simple, 1); p->direction = dir; - p->read_data = NULL; - p->read_index = p->read_length = 0; if (!(p->mainloop = pa_threaded_mainloop_new())) goto fail; -- cgit From a73c615b7480f59991dc37bc838fd16dcbc0175b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:04:36 +0200 Subject: simple: always loop around pa_threaded_mainloop_wait() to handle spurious wakeups properly --- src/pulse/simple.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index 7fd7cce7..c2014c5c 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -178,12 +178,21 @@ pa_simple* pa_simple_new( if (pa_threaded_mainloop_start(p->mainloop) < 0) goto unlock_and_fail; - /* Wait until the context is ready */ - pa_threaded_mainloop_wait(p->mainloop); + for (;;) { + pa_context_state_t state; - if (pa_context_get_state(p->context) != PA_CONTEXT_READY) { - error = pa_context_errno(p->context); - goto unlock_and_fail; + state = pa_context_get_state(p->context); + + if (state == PA_CONTEXT_READY) + break; + + if (!PA_CONTEXT_IS_GOOD(state)) { + error = pa_context_errno(p->context); + goto unlock_and_fail; + } + + /* Wait until the context is ready */ + pa_threaded_mainloop_wait(p->mainloop); } if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) { @@ -212,13 +221,21 @@ pa_simple* pa_simple_new( goto unlock_and_fail; } - /* Wait until the stream is ready */ - pa_threaded_mainloop_wait(p->mainloop); + for (;;) { + pa_stream_state_t state; - /* Wait until the stream is ready */ - if (pa_stream_get_state(p->stream) != PA_STREAM_READY) { - error = pa_context_errno(p->context); - goto unlock_and_fail; + state = pa_stream_get_state(p->stream); + + if (state == PA_STREAM_READY) + break; + + if (!PA_STREAM_IS_GOOD(state)) { + error = pa_context_errno(p->context); + goto unlock_and_fail; + } + + /* Wait until the stream is ready */ + pa_threaded_mainloop_wait(p->mainloop); } pa_threaded_mainloop_unlock(p->mainloop); -- cgit From 53fcf3add0521b83e8b5226e6660d2ec9548f48c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:04:50 +0200 Subject: simple: call pa_context_disconnect() just to be sure --- src/pulse/simple.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index c2014c5c..b5e108fb 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -261,8 +261,10 @@ void pa_simple_free(pa_simple *s) { if (s->stream) pa_stream_unref(s->stream); - if (s->context) + if (s->context) { + pa_context_disconnect(s->context); pa_context_unref(s->context); + } if (s->mainloop) pa_threaded_mainloop_free(s->mainloop); -- cgit From 5bbeb516aa3539e30fccf228d5ac31381209a578 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:05:08 +0200 Subject: simple: split data/length validity checks into two --- src/pulse/simple.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index b5e108fb..1e0f3e18 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -276,7 +276,8 @@ int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); pa_threaded_mainloop_lock(p->mainloop); @@ -315,7 +316,8 @@ int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); pa_threaded_mainloop_lock(p->mainloop); -- cgit From 2cab6a256ca99c20c7f39e330640df6854d35cc8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:05:35 +0200 Subject: simple: check for == RUNNING instead of != DONE when waiting for operations --- src/pulse/simple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index 1e0f3e18..9ed7a653 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -392,7 +392,7 @@ int pa_simple_drain(pa_simple *p, int *rerror) { CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); p->operation_success = 0; - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } @@ -428,7 +428,7 @@ int pa_simple_flush(pa_simple *p, int *rerror) { CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); p->operation_success = 0; - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } -- cgit From 23a294c97e62e0bee9b17b1f8ad20a39e1ba15da Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sun, 9 Aug 2009 03:01:08 +0300 Subject: Correctly deal with events in the past in calc_next_timeout pa_usec_t is unsigned, thus it will always be >= 0 This makes gstreamer pulse mixer work again This fixes a gstreamer mixer regression, when it can't control the volume, after few changes. --- src/pulse/mainloop.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index c418d108..93a4742d 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -765,23 +765,22 @@ static pa_time_event* find_next_time_event(pa_mainloop *m) { static int calc_next_timeout(pa_mainloop *m) { pa_time_event *t; - pa_usec_t usec; + pa_usec_t clock_now; if (!m->n_enabled_time_events) return -1; - t = find_next_time_event(m); - pa_assert(t); + pa_assert_se(t = find_next_time_event(m)); - if (t->time == 0) + if (t->time <= 0) return 0; - usec = t->time - pa_rtclock_now(); + clock_now = pa_rtclock_now(); - if (usec <= 0) + if (t->time <= clock_now) return 0; - return (int) (usec / 1000); /* in milliseconds */ + return (int) ((t->time - clock_now) / 1000); /* in milliseconds */ } static int dispatch_timeout(pa_mainloop *m) { -- cgit From facae1f27504983d7eff7c7c3ffa864f7e002272 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 20:15:28 +0200 Subject: conf: invert all negative boolean configuration option --- src/pulse/client-conf.c | 21 +++++++++++---------- src/pulse/client.conf.in | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 940d0b67..4aa4ba1f 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -92,16 +92,17 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { /* Prepare the configuration parse table */ pa_config_item table[] = { - { "daemon-binary", pa_config_parse_string, &c->daemon_binary, NULL }, - { "extra-arguments", pa_config_parse_string, &c->extra_arguments, NULL }, - { "default-sink", pa_config_parse_string, &c->default_sink, NULL }, - { "default-source", pa_config_parse_string, &c->default_source, NULL }, - { "default-server", pa_config_parse_string, &c->default_server, NULL }, - { "autospawn", pa_config_parse_bool, &c->autospawn, NULL }, - { "cookie-file", pa_config_parse_string, &c->cookie_file, NULL }, - { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, - { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, - { NULL, NULL, NULL, NULL }, + { "daemon-binary", pa_config_parse_string, &c->daemon_binary, NULL }, + { "extra-arguments", pa_config_parse_string, &c->extra_arguments, NULL }, + { "default-sink", pa_config_parse_string, &c->default_sink, NULL }, + { "default-source", pa_config_parse_string, &c->default_source, NULL }, + { "default-server", pa_config_parse_string, &c->default_server, NULL }, + { "autospawn", pa_config_parse_bool, &c->autospawn, NULL }, + { "cookie-file", pa_config_parse_string, &c->cookie_file, NULL }, + { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, + { "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL }, + { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, + { NULL, NULL, NULL, NULL }, }; if (filename) { diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in index 579bcc20..6c8d371c 100644 --- a/src/pulse/client.conf.in +++ b/src/pulse/client.conf.in @@ -29,5 +29,5 @@ ; cookie-file = -; disable-shm = no +; enable-shm = yes ; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB -- cgit From 5921324fd3c16e2b3d38d07b200febd90835f169 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:40:12 +0200 Subject: context: document why we only do minimal cleanups before the autospawn exec() --- src/pulse/context.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/context.c b/src/pulse/context.c index 7c3717fa..894ab2e0 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -707,10 +707,13 @@ static int context_autospawn(pa_context *c) { if (c->spawn_api.atfork) c->spawn_api.atfork(); + /* We leave most of the cleaning up of the process environment + * to the executable. We only clean up the file descriptors to + * make sure the executable can actually be loaded + * correctly. */ pa_close_all(-1); /* Setup argv */ - argv[n++] = c->conf->daemon_binary; argv[n++] = "--start"; -- cgit From 0f2a4ed422530b56b3744efe8055540644c0e774 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 20:03:30 +0200 Subject: volume: guarantee dB/linear conversion is reversible --- src/pulse/volume.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 42cde5b9..c23f360b 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -205,9 +205,12 @@ pa_volume_t pa_sw_volume_from_linear(double v) { * * http://www.robotplanet.dk/audio/audio_gui_design/ * http://lists.linuxaudio.org/pipermail/linux-audio-dev/2009-May/thread.html#23151 + * + * We make sure that the conversion to linear and back yields the + * same volume value! That's why we need the lround() below! */ - return (pa_volume_t) (cbrt(v) * PA_VOLUME_NORM); + return (pa_volume_t) lround(cbrt(v) * PA_VOLUME_NORM); } double pa_sw_volume_to_linear(pa_volume_t v) { -- cgit From d8a90a390041b5603a7caacaaea8296fa76363bc Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Mon, 20 Jul 2009 13:53:17 +0300 Subject: pulse: even in case of record stream, let's initialize req_bytes to 0 --- src/pulse/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 72d49e11..2bc2b1e4 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -867,7 +867,7 @@ static void automatic_buffer_attr(pa_stream *s, pa_buffer_attr *attr, const pa_s void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; - uint32_t requested_bytes; + uint32_t requested_bytes = 0; pa_assert(pd); pa_assert(s); -- cgit From 82082148821d5ebe05fea12fd57d68b31740e04b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 03:40:36 +0200 Subject: volume: add pa_cvolume_merge() call --- src/pulse/volume.c | 18 ++++++++++++++++++ src/pulse/volume.h | 5 +++++ 2 files changed, 23 insertions(+) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index c23f360b..e816d679 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -815,3 +815,21 @@ pa_volume_t pa_cvolume_get_position( return v; } + +pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { + unsigned i; + + pa_assert(dest); + pa_assert(a); + pa_assert(b); + + pa_return_val_if_fail(pa_cvolume_valid(a), NULL); + pa_return_val_if_fail(pa_cvolume_valid(b), NULL); + + for (i = 0; i < a->channels && i < b->channels; i++) + dest->values[i] = PA_MAX(a->values[i], b->values[i]); + + dest->channels = (uint8_t) i; + + return dest; +} diff --git a/src/pulse/volume.h b/src/pulse/volume.h index 05b7ebb4..14692b8d 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -326,6 +326,11 @@ pa_cvolume* pa_cvolume_set_position(pa_cvolume *cv, const pa_channel_map *map, p * position by calling pa_channel_map_has_position(). \since 0.9.16 */ pa_volume_t pa_cvolume_get_position(pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) PA_GCC_PURE; +/** This goes through all channels in a and b and sets the + * corresponding channel in dest to the greater volume of both. a, b + * and dest may point to the same structure. \since 0.9.16 */ +pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); + PA_C_DECL_END #endif -- cgit From 32a1ef311effac8cf792fc7d536f6e1e85dec805 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 03:42:34 +0200 Subject: channelmap: adjust RFC3551 channel maps to follow spec more closely --- src/pulse/channelmap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c index 88823012..18053ec2 100644 --- a/src/pulse/channelmap.c +++ b/src/pulse/channelmap.c @@ -219,11 +219,11 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p case 6: m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_REAR_LEFT; + m->map[1] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT; - m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; - m->map[5] = PA_CHANNEL_POSITION_LFE; + m->map[4] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; + m->map[5] = PA_CHANNEL_POSITION_REAR_CENTER; return m; case 5: @@ -247,7 +247,7 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p m->map[0] = PA_CHANNEL_POSITION_LEFT; m->map[1] = PA_CHANNEL_POSITION_CENTER; m->map[2] = PA_CHANNEL_POSITION_RIGHT; - m->map[3] = PA_CHANNEL_POSITION_LFE; + m->map[3] = PA_CHANNEL_POSITION_REAR_CENTER; return m; default: -- cgit From 6dd580d465cd91c2d32bc897c0eb20fc638e446e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 03:43:05 +0200 Subject: channelmap: document where the WAVEX channelmap is documented --- src/pulse/channelmap.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/pulse') diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c index 18053ec2..98f79b43 100644 --- a/src/pulse/channelmap.c +++ b/src/pulse/channelmap.c @@ -299,6 +299,8 @@ pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, p case PA_CHANNEL_MAP_WAVEEX: + /* Following http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EKLAC */ + switch (channels) { case 1: m->map[0] = PA_CHANNEL_POSITION_MONO; -- cgit From 50de2d85f955d06cf2c4b88270674c72a974bf71 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 03:48:51 +0200 Subject: channelmap: minor doxygen fix --- src/pulse/channelmap.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h index d7901ac2..469effc8 100644 --- a/src/pulse/channelmap.h +++ b/src/pulse/channelmap.h @@ -216,17 +216,27 @@ typedef enum pa_channel_map_def { PA_CHANNEL_MAP_AIFF, /**< The mapping from RFC3551, which is based on AIFF-C */ +/** \cond fulldocs */ PA_CHANNEL_MAP_ALSA, - /**< The default mapping used by ALSA */ + /**< The default mapping used by ALSA. This mapping is probably + * not too useful since ALSA's default channel mapping depends on + * the device string used. */ +/** \endcond */ PA_CHANNEL_MAP_AUX, /**< Only aux channels */ PA_CHANNEL_MAP_WAVEEX, - /**< Microsoft's WAVEFORMATEXTENSIBLE mapping */ + /**< Microsoft's WAVEFORMATEXTENSIBLE mapping. This mapping works + * as if all LSBs of dwChannelMask are set. */ +/** \cond fulldocs */ PA_CHANNEL_MAP_OSS, - /**< The default channel mapping used by OSS as defined in the OSS 4.0 API specs */ + /**< The default channel mapping used by OSS as defined in the OSS + * 4.0 API specs. This mapping is probably not too useful since + * the OSS API has changed in this respect and no longer knows a + * default channel mapping based on the number of channels. */ +/** \endcond */ /**< Upper limit of valid channel mapping definitions */ PA_CHANNEL_MAP_DEF_MAX, @@ -282,7 +292,7 @@ pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, /** Return a text label for the specified channel position */ const char* pa_channel_position_to_string(pa_channel_position_t pos) PA_GCC_PURE; -/* The inverse of pa_channel_position_to_string(). \since 0.9.16 */ +/** The inverse of pa_channel_position_to_string(). \since 0.9.16 */ pa_channel_position_t pa_channel_position_from_string(const char *s) PA_GCC_PURE; /** Return a human readable text label for the specified channel position. \since 0.9.7 */ -- cgit From caa792897296f0b03b364ec64ce9065b010e1305 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 03:50:04 +0200 Subject: libpulse: some minor optimizations when checking equality --- src/pulse/channelmap.c | 8 ++++++++ src/pulse/sample.c | 4 ++++ src/pulse/volume.c | 4 ++++ 3 files changed, 16 insertions(+) (limited to 'src/pulse') diff --git a/src/pulse/channelmap.c b/src/pulse/channelmap.c index 98f79b43..9b516262 100644 --- a/src/pulse/channelmap.c +++ b/src/pulse/channelmap.c @@ -453,6 +453,10 @@ int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { pa_assert(b); pa_return_val_if_fail(pa_channel_map_valid(a), 0); + + if (PA_UNLIKELY(a == b)) + return 1; + pa_return_val_if_fail(pa_channel_map_valid(b), 0); if (a->channels != b->channels) @@ -641,6 +645,10 @@ int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) { pa_assert(b); pa_return_val_if_fail(pa_channel_map_valid(a), 0); + + if (PA_UNLIKELY(a == b)) + return 1; + pa_return_val_if_fail(pa_channel_map_valid(b), 0); am = pa_channel_map_mask(a); diff --git a/src/pulse/sample.c b/src/pulse/sample.c index 0f19f8eb..d5d38eda 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -125,6 +125,10 @@ int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { pa_assert(b); pa_return_val_if_fail(pa_sample_spec_valid(a), 0); + + if (PA_UNLIKELY(a == b)) + return 1; + pa_return_val_if_fail(pa_sample_spec_valid(b), 0); return diff --git a/src/pulse/volume.c b/src/pulse/volume.c index e816d679..d7fb2477 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -40,6 +40,10 @@ int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { pa_assert(b); pa_return_val_if_fail(pa_cvolume_valid(a), 0); + + if (PA_UNLIKELY(a == b)) + return 1; + pa_return_val_if_fail(pa_cvolume_valid(b), 0); if (a->channels != b->channels) -- cgit From ffeb1b81ba2ce01ba3ed73fcd9ce0977861ee7ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 03:50:43 +0200 Subject: volume: document when arguments of certain functions may overlap --- src/pulse/volume.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.h b/src/pulse/volume.h index 14692b8d..3881da2f 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -213,11 +213,13 @@ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) PA_GCC_PURE pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) PA_GCC_CONST; /** Multiply two per-channel volumes and return the result in - * *dest. This is only valid for software volumes! */ + * *dest. This is only valid for software volumes! a, b and dest may + * point to the same structure. */ pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); /** Multiply a per-channel volume with a scalar volume and return the - * result in *dest. This is only valid for software volumes! \since + * result in *dest. This is only valid for software volumes! a + * and dest may point to the same structure. \since * 0.9.16 */ pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b); @@ -228,11 +230,13 @@ pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) PA_GCC_CONST; /** Divide two per-channel volumes and return the result in - * *dest. This is only valid for software volumes! \since 0.9.13 */ + * *dest. This is only valid for software volumes! a, b + * and dest may point to the same structure. \since 0.9.13 */ pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); /** Divide a per-channel volume by a scalar volume and return the - * result in *dest. This is only valid for software volumes! \since + * result in *dest. This is only valid for software volumes! a + * and dest may point to the same structure. \since * 0.9.16 */ pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b); -- cgit From d634555a3e3e2e35d95da6bca9464c02627d02fd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 00:56:16 +0200 Subject: volume: introduce pa_cvolume_min() and pa_cvolume_min_mask() --- src/pulse/volume.c | 41 +++++++++++++++++++++++++++++++++++++++-- src/pulse/volume.h | 10 ++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index d7fb2477..e3535726 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -126,7 +126,7 @@ pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, p } pa_volume_t pa_cvolume_max(const pa_cvolume *a) { - pa_volume_t m = 0; + pa_volume_t m = PA_VOLUME_MUTED; unsigned c; pa_assert(a); @@ -139,8 +139,22 @@ pa_volume_t pa_cvolume_max(const pa_cvolume *a) { return m; } +pa_volume_t pa_cvolume_min(const pa_cvolume *a) { + pa_volume_t m = (pa_volume_t) -1; + unsigned c; + + pa_assert(a); + pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); + + for (c = 0; c < a->channels; c++) + if (m == (pa_volume_t) -1 || a->values[c] < m) + m = a->values[c]; + + return m; +} + pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { - pa_volume_t m = 0; + pa_volume_t m = PA_VOLUME_MUTED; unsigned c, n; pa_assert(a); @@ -162,6 +176,29 @@ pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, p return m; } +pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { + pa_volume_t m = (pa_volume_t) -1; + unsigned c, n; + + pa_assert(a); + + if (!cm) + return pa_cvolume_min(a); + + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); + + for (c = n = 0; c < a->channels; c++) { + + if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) + continue; + + if (m == (pa_volume_t) -1 || a->values[c] < m) + m = a->values[c]; + } + + return m; +} + pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a) * pa_sw_volume_to_linear(b)); } diff --git a/src/pulse/volume.h b/src/pulse/volume.h index 3881da2f..349ca49f 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -195,6 +195,16 @@ pa_volume_t pa_cvolume_max(const pa_cvolume *a) PA_GCC_PURE; * \since 0.9.16 */ pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) PA_GCC_PURE; +/** Return the minimum volume of all channels. \since 0.9.16 */ +pa_volume_t pa_cvolume_min(const pa_cvolume *a) PA_GCC_PURE; + +/** Return the minimum volume of all channels that are included in the + * specified channel map with the specified channel position mask. If + * cm is NULL this call is identical to pa_cvolume_min(). If no + * channel is selected the returned value will be PA_VOLUME_MUTED. + * \since 0.9.16 */ +pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) PA_GCC_PURE; + /** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */ int pa_cvolume_valid(const pa_cvolume *v) PA_GCC_PURE; -- cgit From 96f01b822a9be366ac45dc963b5b0b3b852aa236 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 00:57:58 +0200 Subject: volume: simplify volume multiplifactions, do them in integer only --- src/pulse/volume.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index e3535726..0d402371 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -200,16 +200,18 @@ pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, p } pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { - return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a) * pa_sw_volume_to_linear(b)); + + /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */ + + return (pa_volume_t) (((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM); } pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) { - double v = pa_sw_volume_to_linear(b); - if (v <= 0) + if (b <= PA_VOLUME_MUTED) return 0; - return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a) / v); + return (pa_volume_t) (((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b); } /* Amplitude, not power */ -- cgit From ef01baf613b5f2cedd1a64b883a79d93965dc219 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 00:58:20 +0200 Subject: volume: round properly when showing human readable volume percentages --- src/pulse/volume.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 0d402371..ee869384 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -292,7 +292,7 @@ char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { l -= pa_snprintf(e, l, "%s%u: %3u%%", first ? "" : " ", channel, - (c->values[channel]*100)/PA_VOLUME_NORM); + (c->values[channel]*100+PA_VOLUME_NORM/2)/PA_VOLUME_NORM); e = strchr(e, 0); first = FALSE; @@ -312,7 +312,7 @@ char *pa_volume_snprint(char *s, size_t l, pa_volume_t v) { return s; } - pa_snprintf(s, l, "%3u%%", (v*100)/PA_VOLUME_NORM); + pa_snprintf(s, l, "%3u%%", (v*100+PA_VOLUME_NORM/2)/PA_VOLUME_NORM); return s; } -- cgit From 1421eff0b69f6b0173835afe6b857d39e719d1d0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 02:31:11 +0200 Subject: volume: use PA_VOLUME_MAX instead of (pa_volume_t) -1 --- src/pulse/volume.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index ee869384..3dcf3157 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -140,14 +140,14 @@ pa_volume_t pa_cvolume_max(const pa_cvolume *a) { } pa_volume_t pa_cvolume_min(const pa_cvolume *a) { - pa_volume_t m = (pa_volume_t) -1; + pa_volume_t m = PA_VOLUME_MAX; unsigned c; pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); for (c = 0; c < a->channels; c++) - if (m == (pa_volume_t) -1 || a->values[c] < m) + if (a->values[c] < m) m = a->values[c]; return m; @@ -177,7 +177,7 @@ pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, p } pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { - pa_volume_t m = (pa_volume_t) -1; + pa_volume_t m = PA_VOLUME_MAX; unsigned c, n; pa_assert(a); @@ -192,7 +192,7 @@ pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, p if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) continue; - if (m == (pa_volume_t) -1 || a->values[c] < m) + if (a->values[c] < m) m = a->values[c]; } -- cgit From cfef930036572e2770a4c17e57f139737a99444a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 02:32:36 +0200 Subject: volume: introduce pa_cvolume_{inc|dec}() --- src/pulse/volume.c | 34 ++++++++++++++++++++++++++++++++++ src/pulse/volume.h | 8 ++++++++ 2 files changed, 42 insertions(+) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 3dcf3157..234c3f72 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -876,3 +876,37 @@ pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvo return dest; } + +pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) { + pa_volume_t m; + + pa_assert(v); + + pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + + m = pa_cvolume_max(v); + + if (m >= PA_VOLUME_MAX - inc) + m = PA_VOLUME_MAX; + else + m += inc; + + return pa_cvolume_scale(v, m); +} + +pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { + pa_volume_t m; + + pa_assert(v); + + pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + + m = pa_cvolume_max(v); + + if (m <= PA_VOLUME_MUTED + dec) + m = PA_VOLUME_MUTED; + else + m -= dec; + + return pa_cvolume_scale(v, m); +} diff --git a/src/pulse/volume.h b/src/pulse/volume.h index 349ca49f..543b0af1 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -345,6 +345,14 @@ pa_volume_t pa_cvolume_get_position(pa_cvolume *cv, const pa_channel_map *map, p * and dest may point to the same structure. \since 0.9.16 */ pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); +/** Increase the volume passed in by 'inc'. The proportions between + * the channels are kept. \since 0.9.16 */ +pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc); + +/** Increase the volume passed in by 'inc'. The proportions between + * the channels are kept. \since 0.9.16 */ +pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec); + PA_C_DECL_END #endif -- cgit From 30ba9030efea782779cac6f107b8917572150d16 Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Tue, 30 Jun 2009 18:20:03 +0200 Subject: Modification of the glib-mainloop doc to ensure that nobody frees the api as it is owned by the loop. --- src/pulse/glib-mainloop.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/glib-mainloop.h b/src/pulse/glib-mainloop.h index 189513a8..67aba27d 100644 --- a/src/pulse/glib-mainloop.h +++ b/src/pulse/glib-mainloop.h @@ -56,7 +56,9 @@ pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); /** Free the GLIB main loop object */ void pa_glib_mainloop_free(pa_glib_mainloop* g); -/** Return the abstract main loop API vtable for the GLIB main loop object */ +/** Return the abstract main loop API vtable for the GLIB main loop + object. No need of freeing the API as it is owned by the loop and + it is destroyed when this dies */ pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g); PA_C_DECL_END -- cgit From 65f86ef7d43983cdcea3211705866384404b20cc Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Tue, 30 Jun 2009 18:22:44 +0200 Subject: Modification of the mainloop doc to ensure that nobody frees the api as it is owned by the loop. --- src/pulse/mainloop.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/mainloop.h b/src/pulse/mainloop.h index 4a83ebe8..63abd588 100644 --- a/src/pulse/mainloop.h +++ b/src/pulse/mainloop.h @@ -108,7 +108,9 @@ int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); /** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ int pa_mainloop_run(pa_mainloop *m, int *retval); -/** Return the abstract main loop abstraction layer vtable for this main loop. */ +/** Return the abstract main loop abstraction layer vtable for this + main loop. No need of freeing the API as it is owned by the loop + and it is destroyed when this dies */ pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m); /** Shutdown the main loop */ -- cgit From 52e5d4b1d24db4f4f9ff6e70ddf8c9a6b80cdc6a Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Tue, 30 Jun 2009 18:23:17 +0200 Subject: Modification of the thread-mainloop doc to ensure that nobody frees the api as it is owned by the loop. --- src/pulse/thread-mainloop.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h index e847070d..2cf496e1 100644 --- a/src/pulse/thread-mainloop.h +++ b/src/pulse/thread-mainloop.h @@ -299,7 +299,9 @@ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m); /** Return the return value as specified with the main loop's quit() routine. */ int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m); -/** Return the abstract main loop abstraction layer vtable for this main loop. */ +/** Return the abstract main loop abstraction layer vtable for this + main loop. No need of freeing the API as it is owned by the loop + and it is destroyed when this dies */ pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m); /** Returns non-zero when called from withing the event loop thread. \since 0.9.7 */ -- cgit From d2389ef96e21825bb4e945f6c71b5bd27c5fa2b4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 17:27:17 +0200 Subject: sample: manually inline table lookups Manually inline some table lookups to avoid excessive calls to pa_sample_spec_valid(). --- src/pulse/sample.c | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/sample.c b/src/pulse/sample.c index d5d38eda..9698d8a5 100644 --- a/src/pulse/sample.c +++ b/src/pulse/sample.c @@ -36,28 +36,27 @@ #include "sample.h" -size_t pa_sample_size_of_format(pa_sample_format_t f) { - - static const size_t table[] = { - [PA_SAMPLE_U8] = 1, - [PA_SAMPLE_ULAW] = 1, - [PA_SAMPLE_ALAW] = 1, - [PA_SAMPLE_S16LE] = 2, - [PA_SAMPLE_S16BE] = 2, - [PA_SAMPLE_FLOAT32LE] = 4, - [PA_SAMPLE_FLOAT32BE] = 4, - [PA_SAMPLE_S32LE] = 4, - [PA_SAMPLE_S32BE] = 4, - [PA_SAMPLE_S24LE] = 3, - [PA_SAMPLE_S24BE] = 3, - [PA_SAMPLE_S24_32LE] = 4, - [PA_SAMPLE_S24_32BE] = 4 - }; +static const size_t size_table[] = { + [PA_SAMPLE_U8] = 1, + [PA_SAMPLE_ULAW] = 1, + [PA_SAMPLE_ALAW] = 1, + [PA_SAMPLE_S16LE] = 2, + [PA_SAMPLE_S16BE] = 2, + [PA_SAMPLE_FLOAT32LE] = 4, + [PA_SAMPLE_FLOAT32BE] = 4, + [PA_SAMPLE_S32LE] = 4, + [PA_SAMPLE_S32BE] = 4, + [PA_SAMPLE_S24LE] = 3, + [PA_SAMPLE_S24BE] = 3, + [PA_SAMPLE_S24_32LE] = 4, + [PA_SAMPLE_S24_32BE] = 4 +}; +size_t pa_sample_size_of_format(pa_sample_format_t f) { pa_assert(f >= 0); pa_assert(f < PA_SAMPLE_MAX); - return table[f]; + return size_table[f]; } size_t pa_sample_size(const pa_sample_spec *spec) { @@ -65,35 +64,35 @@ size_t pa_sample_size(const pa_sample_spec *spec) { pa_assert(spec); pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); - return pa_sample_size_of_format(spec->format); + return size_table[spec->format]; } size_t pa_frame_size(const pa_sample_spec *spec) { pa_assert(spec); pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); - return pa_sample_size(spec) * spec->channels; + return size_table[spec->format] * spec->channels; } size_t pa_bytes_per_second(const pa_sample_spec *spec) { pa_assert(spec); pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); - return spec->rate*pa_frame_size(spec); + return spec->rate * size_table[spec->format] * spec->channels; } pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { pa_assert(spec); pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); - return (((pa_usec_t) (length / pa_frame_size(spec)) * PA_USEC_PER_SEC) / spec->rate); + return (((pa_usec_t) (length / (size_table[spec->format] * spec->channels)) * PA_USEC_PER_SEC) / spec->rate); } size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { pa_assert(spec); pa_return_val_if_fail(pa_sample_spec_valid(spec), 0); - return (size_t) (((t * spec->rate) / PA_USEC_PER_SEC)) * pa_frame_size(spec); + return (size_t) (((t * spec->rate) / PA_USEC_PER_SEC)) * (size_table[spec->format] * spec->channels); } pa_sample_spec* pa_sample_spec_init(pa_sample_spec *spec) { @@ -109,12 +108,12 @@ pa_sample_spec* pa_sample_spec_init(pa_sample_spec *spec) { int pa_sample_spec_valid(const pa_sample_spec *spec) { pa_assert(spec); - if (spec->rate <= 0 || + if (PA_UNLIKELY (spec->rate <= 0 || spec->rate > PA_RATE_MAX || spec->channels <= 0 || spec->channels > PA_CHANNELS_MAX || spec->format >= PA_SAMPLE_MAX || - spec->format < 0) + spec->format < 0)) return 0; return 1; -- cgit From 15eb03a5b39f8c54328caa7516a7870bf977db40 Mon Sep 17 00:00:00 2001 From: Ted Percival Date: Fri, 21 Aug 2009 16:02:57 -0600 Subject: core: Add thread-safe group info functions with dynamic buffers Provides getgrgid, getgrnam, getpwuid & getpwnam replacements that are thread safe (a la getgrgid_r() and friends) that internally handle allocating big-enough buffers to avoid ERANGE errors on large users or groups. --- src/pulse/util.c | 52 +++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/util.c b/src/pulse/util.c index 6f1e40a9..9440f5de 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -61,38 +61,40 @@ #include #include #include +#include #include "util.h" char *pa_get_user_name(char *s, size_t l) { const char *p; + char *name = NULL; +#ifdef OS_IS_WIN32 char buf[1024]; +#endif #ifdef HAVE_PWD_H - struct passwd pw, *r; + struct passwd *r; #endif pa_assert(s); pa_assert(l > 0); - if (!(p = (getuid() == 0 ? "root" : NULL)) && - !(p = getenv("USER")) && - !(p = getenv("LOGNAME")) && - !(p = getenv("USERNAME"))) { + if ((p = (getuid() == 0 ? "root" : NULL)) || + (p = getenv("USER")) || + (p = getenv("LOGNAME")) || + (p = getenv("USERNAME"))) + { + name = pa_strlcpy(s, p, l); + } else { #ifdef HAVE_PWD_H -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { -#endif + if ((r = pa_getpwuid_malloc(getuid())) == NULL) { pa_snprintf(s, l, "%lu", (unsigned long) getuid()); return s; } - p = r->pw_name; + name = pa_strlcpy(s, r->pw_name, l); + pa_getpwuid_free(r); #elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ DWORD size = sizeof(buf); @@ -102,7 +104,7 @@ char *pa_get_user_name(char *s, size_t l) { return NULL; } - p = buf; + name = pa_strlcpy(s, buf, l); #else /* HAVE_PWD_H */ @@ -110,7 +112,7 @@ char *pa_get_user_name(char *s, size_t l) { #endif /* HAVE_PWD_H */ } - return pa_strlcpy(s, p, l); + return name; } char *pa_get_host_name(char *s, size_t l) { @@ -126,11 +128,10 @@ char *pa_get_host_name(char *s, size_t l) { } char *pa_get_home_dir(char *s, size_t l) { - char *e; + char *e, *dir; #ifdef HAVE_PWD_H - char buf[1024]; - struct passwd pw, *r; + struct passwd *r; #endif pa_assert(s); @@ -143,22 +144,19 @@ char *pa_get_home_dir(char *s, size_t l) { return pa_strlcpy(s, e, l); #ifdef HAVE_PWD_H - errno = 0; -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { -#endif + if ((r = pa_getpwuid_malloc(getuid())) == NULL) { if (!errno) errno = ENOENT; return NULL; } - return pa_strlcpy(s, r->pw_dir, l); + dir = pa_strlcpy(s, r->pw_dir, l); + + pa_getpwuid_free(r); + + return dir; #else /* HAVE_PWD_H */ errno = ENOENT; -- cgit From 35fcb27a81b35ca0ef2b01f19c140271970d87fe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Aug 2009 05:33:45 +0200 Subject: proplist: allow setting of zero-length data properties --- src/pulse/proplist.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/proplist.c b/src/pulse/proplist.c index c904f533..048b241a 100644 --- a/src/pulse/proplist.c +++ b/src/pulse/proplist.c @@ -251,7 +251,7 @@ int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nb pa_assert(p); pa_assert(key); - pa_assert(data); + pa_assert(data || nbytes == 0); if (!property_name_valid(key)) return -1; @@ -264,7 +264,8 @@ int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nb pa_xfree(prop->value); prop->value = pa_xmalloc(nbytes+1); - memcpy(prop->value, data, nbytes); + if (nbytes > 0) + memcpy(prop->value, data, nbytes); ((char*) prop->value)[nbytes] = 0; prop->nbytes = nbytes; -- cgit From 300384ce0aa79bd86cdafa88848c6e944c0353b5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 28 Aug 2009 15:16:54 +0300 Subject: Fix checking for NULL after usage The pa_xmalloc calls oom() in case of NULL pointer returned by malloc() on one hand and dereferencing of pointer is happen early than actual check on other hand. Thus, just remove useless checks. --- src/pulse/ext-stream-restore.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/ext-stream-restore.c b/src/pulse/ext-stream-restore.c index 63c911f8..10e9fd5d 100644 --- a/src/pulse/ext-stream-restore.c +++ b/src/pulse/ext-stream-restore.c @@ -239,13 +239,10 @@ pa_operation *pa_ext_stream_restore_write( return o; fail: - if (o) { - pa_operation_cancel(o); - pa_operation_unref(o); - } + pa_operation_cancel(o); + pa_operation_unref(o); - if (t) - pa_tagstruct_free(t); + pa_tagstruct_free(t); pa_context_set_error(c, PA_ERR_INVALID); return NULL; @@ -290,13 +287,10 @@ pa_operation *pa_ext_stream_restore_delete( return o; fail: - if (o) { - pa_operation_cancel(o); - pa_operation_unref(o); - } + pa_operation_cancel(o); + pa_operation_unref(o); - if (t) - pa_tagstruct_free(t); + pa_tagstruct_free(t); pa_context_set_error(c, PA_ERR_INVALID); return NULL; -- cgit From e6a666d8d5fffbc9847b51b35349b88d74970079 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 6 Sep 2009 22:33:04 +0200 Subject: libpulse: introduce PA_BYTES_SNPRINT_MAX and make use of it wherever applicable --- src/pulse/context.h | 1 - src/pulse/sample.h | 7 +++++++ src/pulse/stream.h | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/context.h b/src/pulse/context.h index cd129313..670b23e8 100644 --- a/src/pulse/context.h +++ b/src/pulse/context.h @@ -267,7 +267,6 @@ pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_even for mainloop->time_restart). \since 0.9.16 */ void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec); - PA_C_DECL_END #endif diff --git a/src/pulse/sample.h b/src/pulse/sample.h index 53d7dea3..7a4a55a0 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -302,6 +302,13 @@ pa_sample_format_t pa_parse_sample_format(const char *format) PA_GCC_PURE; /** Pretty print a sample type specification to a string */ char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); +/** Maximum required string length for pa_bytes_snprint(). Please note + * that this value can change with any release without warning and + * without being considered API or ABI breakage. You should not use + * this definition anywhere where it might become part of an + * ABI. \since 0.9.16 */ +#define PA_BYTES_SNPRINT_MAX 11 + /** Pretty print a byte size value. (i.e. "2.5 MiB") */ char* pa_bytes_snprint(char *s, size_t l, unsigned v); diff --git a/src/pulse/stream.h b/src/pulse/stream.h index 8a08421f..21dd0a85 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -319,7 +319,7 @@ typedef struct pa_stream pa_stream; typedef void (*pa_stream_success_cb_t) (pa_stream*s, int success, void *userdata); /** A generic request callback */ -typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t bytes, void *userdata); +typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t nbytes, void *userdata); /** A generic notification callback */ typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata); -- cgit From 5cf0c1e544a5fce97d514c793256b2e301277136 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 6 Sep 2009 23:14:15 +0200 Subject: introspect: rearrange order of functions a bit --- src/pulse/introspect.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index ee982100..68cfc874 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -331,6 +331,12 @@ pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, i /** Set the mute switch of a source device specified by its name */ pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); +/** Suspend/Resume a source. \since 0.9.7 */ +pa_operation* pa_context_suspend_source_by_name(pa_context *c, const char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata); + +/** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */ +pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); + /** Change the profile of a source. \since 0.9.16 */ pa_operation* pa_context_set_source_port_by_index(pa_context *c, uint32_t idx, const char*port, pa_context_success_cb_t cb, void *userdata); @@ -557,12 +563,6 @@ pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, /** Move the specified source output to a different source. \since 0.9.5 */ pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata); -/** Suspend/Resume a source. \since 0.9.7 */ -pa_operation* pa_context_suspend_source_by_name(pa_context *c, const char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata); - -/** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */ -pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); - /** Kill a source output. */ pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); -- cgit From 3bbc5e6a4d0211d8cedd2fe6698c2e2c07d1c4b9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2009 19:53:39 +0200 Subject: volume: fix definition of PA_VOLUME_MAX and introduce PA_VOLUME_INVALID and use it wherever applicable --- src/pulse/scache.c | 4 ++-- src/pulse/scache.h | 4 ++-- src/pulse/volume.c | 10 +++++----- src/pulse/volume.h | 9 ++++++--- 4 files changed, 15 insertions(+), 12 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/scache.c b/src/pulse/scache.c index 77f60d72..43dc5296 100644 --- a/src/pulse/scache.c +++ b/src/pulse/scache.c @@ -187,7 +187,7 @@ pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev); - if (volume == (pa_volume_t) -1 && c->version < 15) + if (volume == PA_VOLUME_INVALID && c->version < 15) volume = PA_VOLUME_NORM; pa_tagstruct_putu32(t, volume); @@ -228,7 +228,7 @@ pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *na pa_tagstruct_putu32(t, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev); - if (volume == (pa_volume_t) -1 && c->version < 15) + if (volume == PA_VOLUME_INVALID && c->version < 15) volume = PA_VOLUME_NORM; pa_tagstruct_putu32(t, volume); diff --git a/src/pulse/scache.h b/src/pulse/scache.h index cd579d2e..31cf7b01 100644 --- a/src/pulse/scache.h +++ b/src/pulse/scache.h @@ -101,7 +101,7 @@ pa_operation* pa_context_play_sample( pa_context *c /**< Context */, const char *name /**< Name of the sample to play */, const char *dev /**< Sink to play this sample on */, - pa_volume_t volume /**< Volume to play this sample with. Starting with 0.9.15 you may pass here (pa_volume_t) -1 which will leave the decision about the volume to the server side which is a good idea. */ , + pa_volume_t volume /**< Volume to play this sample with. Starting with 0.9.15 you may pass here PA_VOLUME_INVALID which will leave the decision about the volume to the server side which is a good idea. */ , pa_context_success_cb_t cb /**< Call this function after successfully starting playback, or NULL */, void *userdata /**< Userdata to pass to the callback */); @@ -113,7 +113,7 @@ pa_operation* pa_context_play_sample_with_proplist( pa_context *c /**< Context */, const char *name /**< Name of the sample to play */, const char *dev /**< Sink to play this sample on */, - pa_volume_t volume /**< Volume to play this sample with. Starting with 0.9.15 you may pass here (pa_volume_t) -1 which will leave the decision about the volume to the server side which is a good idea. */ , + pa_volume_t volume /**< Volume to play this sample with. Starting with 0.9.15 you may pass here PA_VOLUME_INVALID which will leave the decision about the volume to the server side which is a good idea. */ , pa_proplist *proplist /**< Property list for this sound. The property list of the cached entry will be merged into this property list */, pa_context_play_sample_cb_t cb /**< Call this function after successfully starting playback, or NULL */, void *userdata /**< Userdata to pass to the callback */); diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 234c3f72..4991e5c8 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -64,7 +64,7 @@ pa_cvolume* pa_cvolume_init(pa_cvolume *a) { a->channels = 0; for (c = 0; c < PA_CHANNELS_MAX; c++) - a->values[c] = (pa_volume_t) -1; + a->values[c] = PA_VOLUME_INVALID; return a; } @@ -307,7 +307,7 @@ char *pa_volume_snprint(char *s, size_t l, pa_volume_t v) { pa_init_i18n(); - if (v == (pa_volume_t) -1) { + if (v == PA_VOLUME_INVALID) { pa_snprintf(s, l, _("(invalid)")); return s; } @@ -357,7 +357,7 @@ char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) { pa_init_i18n(); - if (v == (pa_volume_t) -1) { + if (v == PA_VOLUME_INVALID) { pa_snprintf(s, l, _("(invalid)")); return s; } @@ -459,7 +459,7 @@ int pa_cvolume_valid(const pa_cvolume *v) { return 0; for (c = 0; c < v->channels; c++) - if (v->values[c] == (pa_volume_t) -1) + if (v->values[c] == PA_VOLUME_INVALID) return 0; return 1; @@ -679,7 +679,7 @@ pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) { pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); - pa_return_val_if_fail(max != (pa_volume_t) -1, NULL); + pa_return_val_if_fail(max != PA_VOLUME_INVALID, NULL); t = pa_cvolume_max(v); diff --git a/src/pulse/volume.h b/src/pulse/volume.h index 543b0af1..c964020a 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -106,11 +106,14 @@ typedef uint32_t pa_volume_t; /** Normal volume (100%, 0 dB) */ #define PA_VOLUME_NORM ((pa_volume_t) 0x10000U) -/** Muted volume (0%, -inf dB) */ +/** Muted (minimal valid) volume (0%, -inf dB) */ #define PA_VOLUME_MUTED ((pa_volume_t) 0U) -/** Maximum volume we can store. \since 0.9.15 */ -#define PA_VOLUME_MAX ((pa_volume_t) UINT32_MAX) +/** Maximum valid volume we can store. \since 0.9.15 */ +#define PA_VOLUME_MAX ((pa_volume_t) UINT32_MAX-1) + +/** Special 'invalid' volume. \since 0.9.16 */ +#define PA_VOLUME_INVALID ((pa_volume_t) UINT32_MAX) /** A structure encapsulating a per-channel volume */ typedef struct pa_cvolume { -- cgit From cc6c4fe91f916451bbea9073619c11a6b122b684 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2009 19:59:18 +0200 Subject: volume: add a couple of validity checks for pa_volume_t arguments --- src/pulse/volume.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 4991e5c8..1bbb07f2 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -201,6 +201,9 @@ pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, p pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { + pa_return_val_if_fail(a != PA_VOLUME_INVALID, PA_VOLUME_INVALID); + pa_return_val_if_fail(b != PA_VOLUME_INVALID, PA_VOLUME_INVALID); + /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */ return (pa_volume_t) (((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM); @@ -208,6 +211,9 @@ pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) { + pa_return_val_if_fail(a != PA_VOLUME_INVALID, PA_VOLUME_INVALID); + pa_return_val_if_fail(b != PA_VOLUME_INVALID, PA_VOLUME_INVALID); + if (b <= PA_VOLUME_MUTED) return 0; @@ -232,6 +238,8 @@ pa_volume_t pa_sw_volume_from_dB(double dB) { double pa_sw_volume_to_dB(pa_volume_t v) { + pa_return_val_if_fail(v != PA_VOLUME_INVALID, PA_DECIBEL_MININFTY); + if (v <= PA_VOLUME_MUTED) return PA_DECIBEL_MININFTY; @@ -259,6 +267,8 @@ pa_volume_t pa_sw_volume_from_linear(double v) { double pa_sw_volume_to_linear(pa_volume_t v) { double f; + pa_return_val_if_fail(v != PA_VOLUME_INVALID, 0.0); + if (v <= PA_VOLUME_MUTED) return 0.0; @@ -374,6 +384,7 @@ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), 0); + pa_return_val_if_fail(v != PA_VOLUME_INVALID, 0); for (c = 0; c < a->channels; c++) if (a->values[c] != v) @@ -407,6 +418,7 @@ pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), NULL); + pa_return_val_if_fail(b != PA_VOLUME_INVALID, NULL); for (i = 0; i < a->channels; i++) dest->values[i] = pa_sw_volume_multiply(a->values[i], b); @@ -441,6 +453,7 @@ pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, p pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), NULL); + pa_return_val_if_fail(b != PA_VOLUME_INVALID, NULL); for (i = 0; i < a->channels; i++) dest->values[i] = pa_sw_volume_divide(a->values[i], b); @@ -827,6 +840,7 @@ pa_cvolume* pa_cvolume_set_position( pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL); pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL); + pa_return_val_if_fail(v != PA_VOLUME_INVALID, NULL); for (c = 0; c < map->channels; c++) if (map->map[c] == t) { @@ -883,6 +897,7 @@ pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) { pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + pa_return_val_if_fail(inc != PA_VOLUME_INVALID, NULL); m = pa_cvolume_max(v); @@ -900,6 +915,7 @@ pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); + pa_return_val_if_fail(dec != PA_VOLUME_INVALID, NULL); m = pa_cvolume_max(v); -- cgit From 9755bfa58af0c27b478d5d8cc56013527a6f660b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2009 20:00:02 +0200 Subject: volume: drop some redundant but expensive validity checks --- src/pulse/volume.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 1bbb07f2..1b26cc78 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -510,8 +510,6 @@ pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa pa_assert(from); pa_assert(to); - pa_return_val_if_fail(pa_cvolume_valid(v), NULL); - pa_return_val_if_fail(pa_channel_map_valid(from), NULL); pa_return_val_if_fail(pa_channel_map_valid(to), NULL); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL); @@ -613,8 +611,6 @@ float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) { pa_assert(v); pa_assert(map); - pa_return_val_if_fail(pa_cvolume_valid(v), 0.0f); - pa_return_val_if_fail(pa_channel_map_valid(map), 0.0f); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); if (!pa_channel_map_can_balance(map)) @@ -711,8 +707,8 @@ pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map pa_assert(v); - pa_return_val_if_fail(pa_cvolume_valid(v), NULL); pa_return_val_if_fail(max != (pa_volume_t) -1, NULL); + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL); t = pa_cvolume_max_mask(v, cm, mask); @@ -763,8 +759,6 @@ float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) { pa_assert(v); pa_assert(map); - pa_return_val_if_fail(pa_cvolume_valid(v), 0.0f); - pa_return_val_if_fail(pa_channel_map_valid(map), 0.0f); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); if (!pa_channel_map_can_fade(map)) -- cgit From d000dd6f4b976894558613f69bdad2974cce7d1e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2009 20:00:58 +0200 Subject: volume: when passing NULL as channel map to pa_cvolume_scale_mask() handle this the same way as pa_cvolume_scale() --- src/pulse/volume.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 1b26cc78..8a28b334 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -707,7 +707,11 @@ pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map pa_assert(v); - pa_return_val_if_fail(max != (pa_volume_t) -1, NULL); + pa_return_val_if_fail(max != PA_VOLUME_INVALID, NULL); + + if (!cm) + return pa_cvolume_scale(v, max); + pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL); t = pa_cvolume_max_mask(v, cm, mask); -- cgit From 41a0dc1e9987ae00b605fd88bf887becbdf097d5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2009 20:08:07 +0200 Subject: volume: if pa_cvolume_set_{balance|fade}() is called with invalid fade/balance value log, but don't assert --- src/pulse/volume.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 8a28b334..47bccad2 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -642,12 +642,10 @@ pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, flo pa_assert(map); pa_assert(v); - pa_assert(new_balance >= -1.0f); - pa_assert(new_balance <= 1.0f); - pa_return_val_if_fail(pa_cvolume_valid(v), NULL); - pa_return_val_if_fail(pa_channel_map_valid(map), NULL); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); + pa_return_val_if_fail(new_balance >= -1.0f, NULL); + pa_return_val_if_fail(new_balance <= 1.0f, NULL); if (!pa_channel_map_can_balance(map)) return v; @@ -785,12 +783,10 @@ pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float pa_assert(map); pa_assert(v); - pa_assert(new_fade >= -1.0f); - pa_assert(new_fade <= 1.0f); - pa_return_val_if_fail(pa_cvolume_valid(v), NULL); - pa_return_val_if_fail(pa_channel_map_valid(map), NULL); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); + pa_return_val_if_fail(new_fade >= -1.0f, NULL); + pa_return_val_if_fail(new_fade <= 1.0f, NULL); if (!pa_channel_map_can_fade(map)) return v; -- cgit From 08a4d57ce2f20173ea8a90e597a3ebcd28398242 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2009 22:43:35 +0200 Subject: libpulse: allow invocation of pa_context_play_sample_with_proplist() with NULL proplist --- src/pulse/scache.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/scache.c b/src/pulse/scache.c index 43dc5296..27da6887 100644 --- a/src/pulse/scache.c +++ b/src/pulse/scache.c @@ -216,7 +216,6 @@ pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *na PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, !dev || *dev, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, p, PA_ERR_INVALID); PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED); o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); @@ -233,7 +232,14 @@ pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *na pa_tagstruct_putu32(t, volume); pa_tagstruct_puts(t, name); - pa_tagstruct_put_proplist(t, p); + + if (p) + pa_tagstruct_put_proplist(t, p); + else { + p = pa_proplist_new(); + pa_tagstruct_put_proplist(t, p); + pa_proplist_free(p); + } pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, play_sample_with_proplist_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); -- cgit From f5046759cdd72daf5ba3b31c9dfc7b8d5be6bc9b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:46:23 +0200 Subject: llvm-clang-analyzer: drop a few unnecessary assignments and other trivial fixes --- src/pulse/utf8.c | 4 +--- src/pulse/volume.c | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/utf8.c b/src/pulse/utf8.c index 6b58bde3..9dddf4a3 100644 --- a/src/pulse/utf8.c +++ b/src/pulse/utf8.c @@ -120,10 +120,8 @@ static char* utf8_validate(const char *str, char *output) { size = 4; min = (1 << 16); val = (uint32_t) (*p & 0x07); - } else { - size = 1; + } else goto error; - } p++; if (!is_continuation_char(*p)) diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 47bccad2..2d2bba25 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -155,7 +155,7 @@ pa_volume_t pa_cvolume_min(const pa_cvolume *a) { pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { pa_volume_t m = PA_VOLUME_MUTED; - unsigned c, n; + unsigned c; pa_assert(a); @@ -164,7 +164,7 @@ pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, p pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); - for (c = n = 0; c < a->channels; c++) { + for (c = 0; c < a->channels; c++) { if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) continue; @@ -178,7 +178,7 @@ pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, p pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { pa_volume_t m = PA_VOLUME_MAX; - unsigned c, n; + unsigned c; pa_assert(a); @@ -187,7 +187,7 @@ pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, p pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); - for (c = n = 0; c < a->channels; c++) { + for (c = 0; c < a->channels; c++) { if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) continue; -- cgit From 05506d7dc228f83d3ad0fccc831c493aec7f62be Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:49:42 +0200 Subject: utf8: minor simplification --- src/pulse/utf8.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/utf8.c b/src/pulse/utf8.c index 9dddf4a3..fe7bcd26 100644 --- a/src/pulse/utf8.c +++ b/src/pulse/utf8.c @@ -148,12 +148,9 @@ ONE_REMAINING: if (o) { memcpy(o, last, (size_t) size); - o += size - 1; + o += size; } - if (o) - o++; - continue; error: -- cgit From 12c7460e404c94a364a23434ca28ec2bcc698431 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 10 Sep 2009 02:16:00 +0200 Subject: libpulse: don't support pa_context_get_card_info_list() on servers that cannot handle it --- src/pulse/introspect.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/pulse') diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index 27a587cb..100413ee 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -834,6 +834,8 @@ pa_operation* pa_context_get_card_info_by_name(pa_context *c, const char*name, p } pa_operation* pa_context_get_card_info_list(pa_context *c, pa_card_info_cb_t cb, void *userdata) { + PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 15, PA_ERR_NOTSUPPORTED); + return pa_context_send_simple_command(c, PA_COMMAND_GET_CARD_INFO_LIST, context_get_card_info_callback, (pa_operation_cb_t) cb, userdata); } -- cgit From 54609675e5bf50eaf405c8259129d074135de20a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 01:20:45 +0200 Subject: libpulse: add new error code PA_ERR_BUSY --- src/pulse/def.h | 1 + src/pulse/error.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/def.h b/src/pulse/def.h index 08399ca8..1a7da974 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -394,6 +394,7 @@ enum { PA_ERR_NOTIMPLEMENTED, /**< Missing implementation. \since 0.9.15 */ PA_ERR_FORKED, /**< The caller forked without calling execve() and tried to reuse the context. \since 0.9.15 */ PA_ERR_IO, /**< An IO error happened. \since 0.9.16 */ + PA_ERR_BUSY, /**< Device or resource busy. \since 0.9.17 */ PA_ERR_MAX /**< Not really an error but the first invalid error code */ }; diff --git a/src/pulse/error.c b/src/pulse/error.c index 93a13fc6..e8276990 100644 --- a/src/pulse/error.c +++ b/src/pulse/error.c @@ -64,7 +64,9 @@ const char*pa_strerror(int error) { [PA_ERR_NOEXTENSION] = N_("No such extension"), [PA_ERR_OBSOLETE] = N_("Obsolete functionality"), [PA_ERR_NOTIMPLEMENTED] = N_("Missing implementation"), - [PA_ERR_FORKED] = N_("Client forked") + [PA_ERR_FORKED] = N_("Client forked"), + [PA_ERR_IO] = N_("Input/Output error"), + [PA_ERR_BUSY] = N_("Device or resource busy") }; pa_init_i18n(); -- cgit From 297f31820617a22091764485f4dec2eabf3c74c5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 01:49:16 +0200 Subject: doxygen: drop references to pacat.c and paplay.c as examples since tehy are not useful as such and in the case of paplay not even existant anymore --- src/pulse/context.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/context.h b/src/pulse/context.h index 670b23e8..ecff58df 100644 --- a/src/pulse/context.h +++ b/src/pulse/context.h @@ -147,12 +147,6 @@ * server. A pa_context object wraps a connection to a PulseAudio * server using its native protocol. */ -/** \example pacat.c - * A playback and recording tool using the asynchronous API */ - -/** \example paplay.c - * A sound file playback tool using the asynchronous API, based on libsndfile */ - PA_C_DECL_BEGIN /** An opaque connection context to a daemon */ -- cgit From 4e3f7d5577577729d95d249ba05a931a05487583 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 01:49:39 +0200 Subject: doxygen: add rtclock.h to documentation --- src/pulse/pulseaudio.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h index aa369e69..793ba9b1 100644 --- a/src/pulse/pulseaudio.h +++ b/src/pulse/pulseaudio.h @@ -44,15 +44,17 @@ #include #include #include +#include /** \file - * Include all libpulse header files at once. The following - * files are included: \ref mainloop-api.h, \ref sample.h, \ref def.h, - * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, - * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, - * \ref operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref - * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref proplist.h, \ref timeval.h and - * \ref mainloop-signal.h at once */ + * Include all libpulse header files at once. The following files are + * included: \ref mainloop-api.h, \ref sample.h, \ref def.h, \ref + * context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, \ref + * scache.h, \ref version.h, \ref error.h, \ref channelmap.h, \ref + * operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref + * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref proplist.h, + * \ref timeval.h, \ref rtclock.h and \ref mainloop-signal.h at + * once */ /** \mainpage * -- cgit From 42b795b408925b13c9cc9db362b3f2d48d498449 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 01:49:55 +0200 Subject: doxygen: don't confuse doxygen with spurious .. --- src/pulse/proplist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h index bc4dbd8a..260c26c8 100644 --- a/src/pulse/proplist.h +++ b/src/pulse/proplist.h @@ -197,7 +197,7 @@ PA_C_DECL_BEGIN /** For filter devices: master device id if applicable. */ #define PA_PROP_DEVICE_MASTER_DEVICE "device.master_device" -/** For devices: buffer size in bytes, integer formatted as string.. */ +/** For devices: buffer size in bytes, integer formatted as string. */ #define PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE "device.buffering.buffer_size" /** For devices: fragment size in bytes, integer formatted as string. */ -- cgit From 5919337433e97c36be904c4f7839f22045aa7947 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 02:16:17 +0200 Subject: proplist: define properties for storing window position --- src/pulse/proplist.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/pulse') diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h index 260c26c8..8bf9c482 100644 --- a/src/pulse/proplist.h +++ b/src/pulse/proplist.h @@ -97,6 +97,24 @@ PA_C_DECL_BEGIN /** For streams that belong to a window on the screen: an XDG icon name for the window. e.g. "totem" */ #define PA_PROP_WINDOW_ICON_NAME "window.icon_name" +/** For streams that belong to a window on the screen: absolute horizontal window position on the screen, integer formatted as text string. e.g. "865". \since 0.9.17 */ +#define PA_PROP_WINDOW_X "window.x" + +/** For streams that belong to a window on the screen: absolute vertical window position on the screen, integer formatted as text string. e.g. "343". \since 0.9.17 */ +#define PA_PROP_WINDOW_Y "window.y" + +/** For streams that belong to a window on the screen: window width on the screen, integer formatted as text string. e.g. "365". \since 0.9.17 */ +#define PA_PROP_WINDOW_WIDTH "window.width" + +/** For streams that belong to a window on the screen: window height on the screen, integer formatted as text string. e.g. "643". \since 0.9.17 */ +#define PA_PROP_WINDOW_HEIGHT "window.height" + +/** For streams that belong to a window on the screen: relative position of the window center on the screen, float formatted as text string, ranging from 0.0 (left side of the screen) to 1.0 (right side of the screen). e.g. "0.65". \since 0.9.17 */ +#define PA_PROP_WINDOW_HPOS "window.hpos" + +/** For streams that belong to a window on the screen: relative position of the window center on the screen, float formatted as text string, ranging from 0.0 (top of the screen) to 1.0 (bottom of the screen). e.g. "0.43". \since 0.9.17 */ +#define PA_PROP_WINDOW_VPOS "window.vpos" + /** For streams that belong to an X11 window on the screen: the X11 display string. e.g. ":0.0" */ #define PA_PROP_WINDOW_X11_DISPLAY "window.x11.display" -- cgit