From a2b207e38ac35ffc048351f76d83f7f9db37bb6c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jul 2009 15:47:57 +0100 Subject: daemon: before exec'ing ourselves, make sure nobody plays games with /proc/self/exe --- src/daemon/main.c | 16 ++++++++++++---- src/tests/mix-test.c | 6 ++++-- 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/daemon/main.c b/src/daemon/main.c index eb378d24..07439675 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -405,7 +405,8 @@ int main(int argc, char *argv[]) { /* Disable lazy relocations to make usage of external libraries more deterministic for our RT threads. We abuse __OPTIMIZE__ as - a check whether we are a debug build or not. + a check whether we are a debug build or not. This all is + admittedly a bit snake-oilish. */ if (!getenv("LD_BIND_NOW")) { @@ -416,9 +417,16 @@ int main(int argc, char *argv[]) { pa_set_env("LD_BIND_NOW", "1"); - if ((rp = pa_readlink("/proc/self/exe"))) - pa_assert_se(execv(rp, argv) == 0); - else + if ((rp = pa_readlink("/proc/self/exe"))) { + + if (pa_streq(rp, PA_BINARY)) + pa_assert_se(execv(rp, argv) == 0); + else + pa_log_warn("/proc/self/exe does not point to " PA_BINARY ", cannot self execute. Are you playing games?"); + + pa_xfree(rp); + + } else pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?"); } #endif diff --git a/src/tests/mix-test.c b/src/tests/mix-test.c index c7a30d67..3f65cbac 100644 --- a/src/tests/mix-test.c +++ b/src/tests/mix-test.c @@ -83,8 +83,10 @@ static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) { case PA_SAMPLE_S24RE: { uint8_t *u = d; - for (i = 0; i < chunk->length / pa_frame_size(ss); i++) - printf("0x%02x%02x%02xx ", *(u++), *(u++), *(u++)); + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) { + printf("0x%02x%02x%02xx ", *u, *(u+1), *(u+2)); + u += 3; + } break; } -- cgit 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') 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 0225ef68f2876bebd14977882db313fd7f3f6d64 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jul 2009 15:50:02 +0100 Subject: memtrap: clarify that we are not interested in the return value of write() --- src/pulsecore/memtrap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/memtrap.c b/src/pulsecore/memtrap.c index 7d917450..c647e507 100644 --- a/src/pulsecore/memtrap.c +++ b/src/pulsecore/memtrap.c @@ -65,7 +65,7 @@ pa_bool_t pa_memtrap_is_good(pa_memtrap *m) { } static void sigsafe_error(const char *s) { - write(STDERR_FILENO, s, strlen(s)); + (void) write(STDERR_FILENO, s, strlen(s)); } static void signal_handler(int sig, siginfo_t* si, void *data) { -- cgit From 7e2afffb81ab8b495d4f769858a855c2df2c0610 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jul 2009 22:38:38 +0200 Subject: alsa: deal properly with IO functions asking us to write 0 bytes --- src/modules/alsa/alsa-sink.c | 6 +++++- src/modules/alsa/alsa-source.c | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 0cde694c..e7925902 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -494,6 +494,9 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle if (frames > pa_mempool_block_size_max(u->sink->core->mempool)/u->frame_size) frames = pa_mempool_block_size_max(u->sink->core->mempool)/u->frame_size; + if (frames == 0) + break; + /* Check these are multiples of 8 bit */ pa_assert((areas[0].first & 7) == 0); pa_assert((areas[0].step & 7)== 0); @@ -631,7 +634,8 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle frames = snd_pcm_writei(u->pcm_handle, (const uint8_t*) p + u->memchunk.index, (snd_pcm_uframes_t) frames); pa_memblock_release(u->memchunk.memblock); - pa_assert(frames != 0); + if (frames == 0) + break; if (PA_UNLIKELY(frames < 0)) { diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index a6760e1e..41bb768b 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -473,6 +473,9 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled if (frames > pa_mempool_block_size_max(u->source->core->mempool)/u->frame_size) frames = pa_mempool_block_size_max(u->source->core->mempool)/u->frame_size; + if (frames == 0) + break; + /* Check these are multiples of 8 bit */ pa_assert((areas[0].first & 7) == 0); pa_assert((areas[0].step & 7)== 0); @@ -599,7 +602,10 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) p, (snd_pcm_uframes_t) frames); pa_memblock_release(chunk.memblock); - pa_assert(frames != 0); + if (frames == 0) { + pa_memblock_unref(chunk.memblock); + break; + } if (PA_UNLIKELY(frames < 0)) { pa_memblock_unref(chunk.memblock); -- cgit From 2f54b5df183630bb284a16ed9be88279c8f0f0e4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jul 2009 22:47:51 +0200 Subject: daemon: reset personality, to make the autospawn env cleaup complete --- src/daemon/main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/daemon/main.c b/src/daemon/main.c index eb378d24..c759df53 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -65,6 +65,10 @@ #include #endif +#ifdef __linux__ +#include +#endif + #include #include #include @@ -433,6 +437,12 @@ int main(int argc, char *argv[]) { /* We might be autospawned, in which case have no idea in which * context we have been started. Let's cleanup our execution * context as good as possible */ + +#ifdef __linux__ + if (personality(PER_LINUX) < 0) + pa_log_warn("Uh, personality() failed: %s", pa_cstrerror(errno)); +#endif + pa_drop_root(); pa_close_all(passed_fd, -1); pa_reset_sigs(-1); -- cgit From e3b0ce57e0f44790bd75412778cce8129e3945eb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jul 2009 22:48:54 +0200 Subject: udev: don't fail if /dev/snd is not available right-away --- src/modules/module-udev-detect.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index 1ad6fa2d..c8ec2bf9 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -65,6 +65,8 @@ static const char* const valid_modargs[] = { NULL }; +static int setup_inotify(struct userdata *u); + static void device_free(struct device *d) { pa_assert(d); @@ -117,6 +119,9 @@ static void card_changed(struct userdata *u, struct udev_device *dev) { pa_assert(u); pa_assert(dev); + /* Maybe /dev/snd is now available? */ + setup_inotify(u); + path = udev_device_get_devpath(dev); if ((d = pa_hashmap_get(u->devices, path))) { @@ -262,7 +267,7 @@ static void inotify_cb( } buf; struct userdata *u = userdata; static int type = 0; - pa_bool_t verify = FALSE; + pa_bool_t verify = FALSE, deleted = FALSE; for (;;) { ssize_t r; @@ -279,6 +284,9 @@ static void inotify_cb( if ((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC")) verify = TRUE; + + if ((buf.e.mask & (IN_DELETE_SELF|IN_MOVE_SELF))) + deleted = TRUE; } if (verify) { @@ -291,11 +299,14 @@ static void inotify_cb( verify_access(u, d); } - return; + if (!deleted) + return; fail: - a->io_free(u->inotify_io); - u->inotify_io = NULL; + if (u->inotify_io) { + a->io_free(u->inotify_io); + u->inotify_io = NULL; + } if (u->inotify_fd >= 0) { pa_close(u->inotify_fd); @@ -307,17 +318,28 @@ static int setup_inotify(struct userdata *u) { char *dev_snd; int r; + if (u->inotify_fd >= 0) + return 0; + if ((u->inotify_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { pa_log("inotify_init1() failed: %s", pa_cstrerror(errno)); return -1; } dev_snd = pa_sprintf_malloc("%s/snd", udev_get_dev_path(u->udev)); - r = inotify_add_watch(u->inotify_fd, dev_snd, IN_CLOSE_WRITE); + r = inotify_add_watch(u->inotify_fd, dev_snd, IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF); pa_xfree(dev_snd); if (r < 0) { - pa_log("inotify_add_watch() failed: %s", pa_cstrerror(errno)); + int saved_errno = errno; + + pa_close(u->inotify_fd); + u->inotify_fd = -1; + + if (saved_errno == ENOENT) + return 0; + + pa_log("inotify_add_watch() failed: %s", pa_cstrerror(saved_errno)); return -1; } -- cgit From 3b01d3a53f3b9261b30c1f7e5fe28d269c28cdf0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 23 Jul 2009 13:40:23 +0200 Subject: protocol-native: use the right samplerate The render_memblockq is expressed in the sample_spec of the sink, not of the particular stream before resampling. --- src/pulsecore/protocol-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 96184bd2..9a37c565 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2550,7 +2550,7 @@ static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uin reply = reply_new(tag); pa_tagstruct_put_usec(reply, s->current_sink_latency + - pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sample_spec)); + pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec)); pa_tagstruct_put_usec(reply, 0); pa_tagstruct_put_boolean(reply, s->playing_for > 0 && -- cgit From 1160cad9c3f87659e810ebdb9c4a20626e8a4eed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jul 2009 18:44:26 +0200 Subject: alsa: control 'Speaker' element as well --- src/modules/alsa/mixer/paths/analog-output-headphones.conf | 4 ++++ src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf | 6 ++++++ src/modules/alsa/mixer/paths/analog-output-mono.conf | 6 ++++++ src/modules/alsa/mixer/paths/analog-output.conf | 6 ++++++ 4 files changed, 22 insertions(+) (limited to 'src') diff --git a/src/modules/alsa/mixer/paths/analog-output-headphones.conf b/src/modules/alsa/mixer/paths/analog-output-headphones.conf index c018e0eb..691cb3f2 100644 --- a/src/modules/alsa/mixer/paths/analog-output-headphones.conf +++ b/src/modules/alsa/mixer/paths/analog-output-headphones.conf @@ -44,6 +44,10 @@ volume = merge override-map.1 = all override-map.2 = all-left,all-right +[Element Speaker] +switch = off +volume = off + [Element Front] switch = off volume = off diff --git a/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf b/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf index 7a267890..2db976a5 100644 --- a/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf +++ b/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf @@ -45,6 +45,12 @@ override-map.2 = lfe,lfe switch = off volume = off +[Element Speaker] +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + [Element Front] switch = off volume = off diff --git a/src/modules/alsa/mixer/paths/analog-output-mono.conf b/src/modules/alsa/mixer/paths/analog-output-mono.conf index f6cb9f8a..a58cc970 100644 --- a/src/modules/alsa/mixer/paths/analog-output-mono.conf +++ b/src/modules/alsa/mixer/paths/analog-output-mono.conf @@ -42,6 +42,12 @@ override-map.2 = all-left,all-right switch = off volume = off +[Element Speaker] +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + [Element Front] switch = off volume = off diff --git a/src/modules/alsa/mixer/paths/analog-output.conf b/src/modules/alsa/mixer/paths/analog-output.conf index ea108aaf..b412a437 100644 --- a/src/modules/alsa/mixer/paths/analog-output.conf +++ b/src/modules/alsa/mixer/paths/analog-output.conf @@ -41,6 +41,12 @@ volume = off switch = off volume = off +[Element Speaker] +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + [Element Front] switch = mute volume = merge -- cgit From ac38c4d89845237cd5d19c29d8d3ef55f0374dca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jul 2009 18:49:28 +0200 Subject: build-sys: add a couple of stub Makefiles --- src/modules/alsa/mixer/Makefile | 1 + src/modules/alsa/mixer/paths/Makefile | 1 + src/modules/alsa/mixer/profile-sets/Makefile | 1 + 3 files changed, 3 insertions(+) create mode 120000 src/modules/alsa/mixer/Makefile create mode 120000 src/modules/alsa/mixer/paths/Makefile create mode 120000 src/modules/alsa/mixer/profile-sets/Makefile (limited to 'src') diff --git a/src/modules/alsa/mixer/Makefile b/src/modules/alsa/mixer/Makefile new file mode 120000 index 00000000..b4955194 --- /dev/null +++ b/src/modules/alsa/mixer/Makefile @@ -0,0 +1 @@ +../../../pulse/Makefile \ No newline at end of file diff --git a/src/modules/alsa/mixer/paths/Makefile b/src/modules/alsa/mixer/paths/Makefile new file mode 120000 index 00000000..dc23aaa2 --- /dev/null +++ b/src/modules/alsa/mixer/paths/Makefile @@ -0,0 +1 @@ +../../../../pulse/Makefile \ No newline at end of file diff --git a/src/modules/alsa/mixer/profile-sets/Makefile b/src/modules/alsa/mixer/profile-sets/Makefile new file mode 120000 index 00000000..dc23aaa2 --- /dev/null +++ b/src/modules/alsa/mixer/profile-sets/Makefile @@ -0,0 +1 @@ +../../../../pulse/Makefile \ No newline at end of file -- cgit From 5a0ef5fd139151b285720f2c9edf3b559556c86d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jul 2009 19:12:53 +0200 Subject: daemon: replace colons by dash in per-machine directory names for compat with weird filesystems --- src/pulsecore/core-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 04e7eb24..5f777d5b 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -1481,7 +1481,7 @@ char *pa_get_runtime_dir(void) { goto fail; } - k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:runtime", d, mid); + k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-runtime", d, mid); pa_xfree(d); pa_xfree(mid); @@ -1904,7 +1904,7 @@ static char *get_path(const char *fn, pa_bool_t prependmid, pa_bool_t rt) { return NULL; } - r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:%s", rtp, mid, fn); + r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-%s", rtp, mid, fn); pa_xfree(mid); } else r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", rtp, fn); -- cgit From c325b93c01c5973db659aead6b66f753aa719168 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jul 2009 19:24:26 +0200 Subject: alsa: don't reset volume/mute when selecting path --- src/modules/alsa/alsa-mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index a5515e1b..6a0b4ab7 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -940,7 +940,6 @@ int pa_alsa_path_select(pa_alsa_path *p, snd_mixer_t *m) { PA_LLIST_FOREACH(e, p->elements) { switch (e->switch_use) { - case PA_ALSA_SWITCH_MUTE: case PA_ALSA_SWITCH_OFF: r = element_set_switch(e, m, FALSE); break; @@ -949,6 +948,7 @@ int pa_alsa_path_select(pa_alsa_path *p, snd_mixer_t *m) { r = element_set_switch(e, m, TRUE); break; + case PA_ALSA_SWITCH_MUTE: case PA_ALSA_SWITCH_IGNORE: case PA_ALSA_SWITCH_SELECT: r = 0; @@ -960,7 +960,6 @@ int pa_alsa_path_select(pa_alsa_path *p, snd_mixer_t *m) { switch (e->volume_use) { case PA_ALSA_VOLUME_OFF: - case PA_ALSA_VOLUME_MERGE: r = element_mute_volume(e, m); break; @@ -968,6 +967,7 @@ int pa_alsa_path_select(pa_alsa_path *p, snd_mixer_t *m) { r = element_zero_volume(e, m); break; + case PA_ALSA_VOLUME_MERGE: case PA_ALSA_VOLUME_IGNORE: r = 0; break; -- cgit From e02e0259e5e0c22ff7fd598cfaf70f03e82c957a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jul 2009 20:00:08 +0200 Subject: client: include zerocopy write calls in map file --- src/map-file | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/map-file b/src/map-file index a1d0a061..c6c8acca 100644 --- a/src/map-file +++ b/src/map-file @@ -219,6 +219,8 @@ pa_simple_get_latency; pa_simple_new; pa_simple_read; pa_simple_write; +pa_stream_begin_write; +pa_stream_cancel_write; pa_stream_connect_playback; pa_stream_connect_record; pa_stream_connect_upload; -- cgit From a81244a726b28fb7e3ccf5fd1d1d823023602c30 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jul 2009 20:01:40 +0200 Subject: pacat: use zero-copy write calls when playing audio file --- src/utils/pacat.c | 126 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/utils/pacat.c b/src/utils/pacat.c index f00a32eb..9264a062 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -105,12 +105,12 @@ static void context_drain_complete(pa_context*c, void *userdata) { static void stream_drain_complete(pa_stream*s, int success, void *userdata) { if (!success) { - pa_log(_("Failed to drain stream: %s\n"), pa_strerror(pa_context_errno(context))); + pa_log(_("Failed to drain stream: %s"), pa_strerror(pa_context_errno(context))); quit(1); } if (verbose) - pa_log(_("Playback stream drained.\n")); + pa_log(_("Playback stream drained.")); pa_stream_disconnect(stream); pa_stream_unref(stream); @@ -120,7 +120,7 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { pa_context_disconnect(context); else { if (verbose) - pa_log(_("Draining connection to server.\n")); + pa_log(_("Draining connection to server.")); } } @@ -133,7 +133,7 @@ static void start_drain(void) { pa_stream_set_write_callback(stream, NULL, NULL); if (!(o = pa_stream_drain(stream, stream_drain_complete, NULL))) { - pa_log(_("pa_stream_drain(): %s\n"), pa_strerror(pa_context_errno(context))); + pa_log(_("pa_stream_drain(): %s"), pa_strerror(pa_context_errno(context))); quit(1); return; } @@ -156,7 +156,7 @@ static void do_stream_write(size_t length) { l = buffer_length; if (pa_stream_write(stream, (uint8_t*) buffer + buffer_index, l, NULL, 0, PA_SEEK_RELATIVE) < 0) { - pa_log(_("pa_stream_write() failed: %s\n"), pa_strerror(pa_context_errno(context))); + pa_log(_("pa_stream_write() failed: %s"), pa_strerror(pa_context_errno(context))); quit(1); return; } @@ -193,7 +193,11 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { pa_assert(sndfile); - data = pa_xmalloc(length); + if (pa_stream_begin_write(s, &data, &length) < 0) { + pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context))); + quit(1); + return; + } if (readf_function) { size_t k = pa_frame_size(&sample_spec); @@ -205,9 +209,9 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { bytes = sf_read_raw(sndfile, data, (sf_count_t) length); if (bytes > 0) - pa_stream_write(s, data, (size_t) bytes, pa_xfree, 0, PA_SEEK_RELATIVE); + pa_stream_write(s, data, (size_t) bytes, NULL, 0, PA_SEEK_RELATIVE); else - pa_xfree(data); + pa_stream_cancel_write(s); if (bytes < (sf_count_t) length) start_drain(); @@ -226,12 +230,11 @@ static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { if (stdio_event) mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT); - while (pa_stream_readable_size(s) > 0) { const void *data; if (pa_stream_peek(s, &data, &length) < 0) { - pa_log(_("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context))); + pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context))); quit(1); return; } @@ -249,6 +252,7 @@ static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { buffer_length = length; buffer_index = 0; } + pa_stream_drop(s); } @@ -260,7 +264,7 @@ static void stream_read_callback(pa_stream *s, size_t length, void *userdata) { const void *data; if (pa_stream_peek(s, &data, &length) < 0) { - pa_log(_("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(context))); + pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context))); quit(1); return; } @@ -300,25 +304,25 @@ static void stream_state_callback(pa_stream *s, void *userdata) { const pa_buffer_attr *a; char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX]; - pa_log(_("Stream successfully created.\n")); + pa_log(_("Stream successfully created.")); if (!(a = pa_stream_get_buffer_attr(s))) - pa_log(_("pa_stream_get_buffer_attr() failed: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + pa_log(_("pa_stream_get_buffer_attr() failed: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s)))); else { if (mode == PLAYBACK) - pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n"), a->maxlength, a->tlength, a->prebuf, a->minreq); + pa_log(_("Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u"), a->maxlength, a->tlength, a->prebuf, a->minreq); else { pa_assert(mode == RECORD); - pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u\n"), a->maxlength, a->fragsize); + pa_log(_("Buffer metrics: maxlength=%u, fragsize=%u"), a->maxlength, a->fragsize); } } - pa_log(_("Using sample spec '%s', channel map '%s'.\n"), + pa_log(_("Using sample spec '%s', channel map '%s'."), pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(s)), pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(s))); - pa_log(_("Connected to device %s (%u, %ssuspended).\n"), + pa_log(_("Connected to device %s (%u, %ssuspended)."), pa_stream_get_device_name(s), pa_stream_get_device_index(s), pa_stream_is_suspended(s) ? "" : "not "); @@ -328,7 +332,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) { case PA_STREAM_FAILED: default: - pa_log(_("Stream error: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + pa_log(_("Stream error: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s)))); quit(1); } } @@ -338,9 +342,9 @@ static void stream_suspended_callback(pa_stream *s, void *userdata) { if (verbose) { if (pa_stream_is_suspended(s)) - pa_log(_("Stream device suspended.%s \n"), CLEAR_LINE); + pa_log(_("Stream device suspended.%s"), CLEAR_LINE); else - pa_log(_("Stream device resumed.%s \n"), CLEAR_LINE); + pa_log(_("Stream device resumed.%s"), CLEAR_LINE); } } @@ -348,35 +352,35 @@ static void stream_underflow_callback(pa_stream *s, void *userdata) { pa_assert(s); if (verbose) - pa_log(_("Stream underrun.%s \n"), CLEAR_LINE); + pa_log(_("Stream underrun.%s"), CLEAR_LINE); } static void stream_overflow_callback(pa_stream *s, void *userdata) { pa_assert(s); if (verbose) - pa_log(_("Stream overrun.%s \n"), CLEAR_LINE); + pa_log(_("Stream overrun.%s"), CLEAR_LINE); } static void stream_started_callback(pa_stream *s, void *userdata) { pa_assert(s); if (verbose) - pa_log(_("Stream started.%s \n"), CLEAR_LINE); + pa_log(_("Stream started.%s"), CLEAR_LINE); } static void stream_moved_callback(pa_stream *s, void *userdata) { pa_assert(s); if (verbose) - pa_log(_("Stream moved to device %s (%u, %ssuspended).%s \n"), pa_stream_get_device_name(s), pa_stream_get_device_index(s), pa_stream_is_suspended(s) ? "" : _("not "), CLEAR_LINE); + pa_log(_("Stream moved to device %s (%u, %ssuspended).%s"), pa_stream_get_device_name(s), pa_stream_get_device_index(s), pa_stream_is_suspended(s) ? "" : _("not "), CLEAR_LINE); } static void stream_buffer_attr_callback(pa_stream *s, void *userdata) { pa_assert(s); if (verbose) - pa_log(_("Stream buffer attributes changed.%s \n"), CLEAR_LINE); + pa_log(_("Stream buffer attributes changed.%s"), CLEAR_LINE); } static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) { @@ -387,7 +391,7 @@ static void stream_event_callback(pa_stream *s, const char *name, pa_proplist *p pa_assert(pl); t = pa_proplist_to_string_sep(pl, ", "); - pa_log("Got event '%s', properties '%s'\n", name, t); + pa_log("Got event '%s', properties '%s'", name, t); pa_xfree(t); } @@ -409,10 +413,10 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_assert(!stream); if (verbose) - pa_log(_("Connection established.%s \n"), CLEAR_LINE); + pa_log(_("Connection established.%s"), CLEAR_LINE); if (!(stream = pa_stream_new_with_proplist(c, NULL, &sample_spec, &channel_map, proplist))) { - pa_log(_("pa_stream_new() failed: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("pa_stream_new() failed: %s"), pa_strerror(pa_context_errno(c))); goto fail; } @@ -440,13 +444,13 @@ static void context_state_callback(pa_context *c, void *userdata) { if (mode == PLAYBACK) { pa_cvolume cv; if ((r = pa_stream_connect_playback(stream, device, latency > 0 ? &buffer_attr : NULL, flags, volume_is_set ? pa_cvolume_set(&cv, sample_spec.channels, volume) : NULL, NULL)) < 0) { - pa_log(_("pa_stream_connect_playback() failed: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c))); goto fail; } } else { if ((r = pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags)) < 0) { - pa_log(_("pa_stream_connect_record() failed: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c))); goto fail; } } @@ -460,7 +464,7 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_FAILED: default: - pa_log(_("Connection failure: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c))); goto fail; } @@ -493,12 +497,12 @@ static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_even if ((r = read(fd, buffer, l)) <= 0) { if (r == 0) { if (verbose) - pa_log(_("Got EOF.\n")); + pa_log(_("Got EOF.")); start_drain(); } else { - pa_log(_("read() failed: %s\n"), strerror(errno)); + pa_log(_("read() failed: %s"), strerror(errno)); quit(1); } @@ -530,7 +534,7 @@ static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_eve pa_assert(buffer_length); if ((r = write(fd, (uint8_t*) buffer+buffer_index, buffer_length)) <= 0) { - pa_log(_("write() failed: %s\n"), strerror(errno)); + pa_log(_("write() failed: %s"), strerror(errno)); quit(1); mainloop_api->io_free(stdio_event); @@ -551,7 +555,7 @@ static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_eve /* UNIX signal to quit recieved */ static void exit_signal_callback(pa_mainloop_api*m, pa_signal_event *e, int sig, void *userdata) { if (verbose) - pa_log(_("Got signal, exiting.\n")); + pa_log(_("Got signal, exiting.")); quit(0); } @@ -565,7 +569,7 @@ static void stream_update_timing_callback(pa_stream *s, int success, void *userd if (!success || pa_stream_get_time(s, &usec) < 0 || pa_stream_get_latency(s, &l, &negative) < 0) { - pa_log(_("Failed to get latency: %s\n"), pa_strerror(pa_context_errno(context))); + pa_log(_("Failed to get latency: %s"), pa_strerror(pa_context_errno(context))); quit(1); return; } @@ -588,7 +592,7 @@ static void time_event_callback(pa_mainloop_api *m, pa_time_event *e, const stru if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) { pa_operation *o; if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL))) - pa_log(_("pa_stream_update_timing_info() failed: %s\n"), pa_strerror(pa_context_errno(context))); + pa_log(_("pa_stream_update_timing_info() failed: %s"), pa_strerror(pa_context_errno(context))); else pa_operation_unref(o); } @@ -753,7 +757,7 @@ int main(int argc, char *argv[]) { if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) { - pa_log(_("Invalid client name '%s'\n"), t ? t : optarg); + pa_log(_("Invalid client name '%s'"), t ? t : optarg); pa_xfree(t); goto quit; } @@ -769,7 +773,7 @@ int main(int argc, char *argv[]) { if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) { - pa_log(_("Invalid stream name '%s'\n"), t ? t : optarg); + pa_log(_("Invalid stream name '%s'"), t ? t : optarg); pa_xfree(t); goto quit; } @@ -806,7 +810,7 @@ int main(int argc, char *argv[]) { case ARG_CHANNELMAP: if (!pa_channel_map_parse(&channel_map, optarg)) { - pa_log(_("Invalid channel map '%s'\n"), optarg); + pa_log(_("Invalid channel map '%s'"), optarg); goto quit; } @@ -835,14 +839,14 @@ int main(int argc, char *argv[]) { case ARG_LATENCY: if (((latency = (size_t) atoi(optarg))) <= 0) { - pa_log(_("Invalid latency specification '%s'\n"), optarg); + pa_log(_("Invalid latency specification '%s'"), optarg); goto quit; } break; case ARG_PROCESS_TIME: if (((process_time = (size_t) atoi(optarg))) <= 0) { - pa_log(_("Invalid process time specification '%s'\n"), optarg); + pa_log(_("Invalid process time specification '%s'"), optarg); goto quit; } break; @@ -854,7 +858,7 @@ int main(int argc, char *argv[]) { pa_proplist_setp(proplist, t) < 0) { pa_xfree(t); - pa_log(_("Invalid property '%s'\n"), optarg); + pa_log(_("Invalid property '%s'"), optarg); goto quit; } @@ -890,7 +894,7 @@ int main(int argc, char *argv[]) { } if (!pa_sample_spec_valid(&sample_spec)) { - pa_log(_("Invalid sample specification\n")); + pa_log(_("Invalid sample specification")); goto quit; } @@ -900,19 +904,19 @@ int main(int argc, char *argv[]) { filename = argv[optind]; if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { - pa_log(_("open(): %s\n"), strerror(errno)); + pa_log(_("open(): %s"), strerror(errno)); goto quit; } if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) { - pa_log(_("dup2(): %s\n"), strerror(errno)); + pa_log(_("dup2(): %s"), strerror(errno)); goto quit; } pa_close(fd); } else if (optind+1 <= argc) { - pa_log(_("Too many arguments.\n")); + pa_log(_("Too many arguments.")); goto quit; } @@ -923,7 +927,7 @@ int main(int argc, char *argv[]) { if (mode == RECORD) { /* This might patch up the sample spec */ if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) { - pa_log(_("Failed to generate sample specification for file.\n")); + pa_log(_("Failed to generate sample specification for file.")); goto quit; } @@ -943,16 +947,16 @@ int main(int argc, char *argv[]) { if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO, mode == RECORD ? SFM_WRITE : SFM_READ, &sfi, 0))) { - pa_log(_("Failed to open audio file.\n")); + pa_log(_("Failed to open audio file.")); goto quit; } if (mode == PLAYBACK) { if (sample_spec_set) - pa_log(_("Warning: specified sample specification will be overwritten with specification from file.\n")); + pa_log(_("Warning: specified sample specification will be overwritten with specification from file.")); if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) { - pa_log(_("Failed to determine sample specification from file.\n")); + pa_log(_("Failed to determine sample specification from file.")); goto quit; } sample_spec_set = TRUE; @@ -961,7 +965,7 @@ int main(int argc, char *argv[]) { /* Allow the user to overwrite the channel map on the command line */ if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) { if (sample_spec.channels > 2) - pa_log(_("Warning: Failed to determine channel map from file.\n")); + pa_log(_("Warning: Failed to determine channel map from file.")); } else channel_map_set = TRUE; } @@ -972,7 +976,7 @@ int main(int argc, char *argv[]) { pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); if (!pa_channel_map_compatible(&channel_map, &sample_spec)) { - pa_log(_("Channel map doesn't match sample specification\n")); + pa_log(_("Channel map doesn't match sample specification")); goto quit; } @@ -983,7 +987,7 @@ int main(int argc, char *argv[]) { readf_function = pa_sndfile_readf_function(&sample_spec); else { if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0) - pa_log(_("Warning: failed to write channel map to file.\n")); + pa_log(_("Warning: failed to write channel map to file.")); writef_function = pa_sndfile_writef_function(&sample_spec); } @@ -998,7 +1002,7 @@ int main(int argc, char *argv[]) { if (verbose) { char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX]; - pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'.\n"), + pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."), mode == RECORD ? _("recording") : _("playback"), pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec), pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map)); @@ -1025,7 +1029,7 @@ int main(int argc, char *argv[]) { /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { - pa_log(_("pa_mainloop_new() failed.\n")); + pa_log(_("pa_mainloop_new() failed.")); goto quit; } @@ -1044,14 +1048,14 @@ int main(int argc, char *argv[]) { mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT, mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { - pa_log(_("io_new() failed.\n")); + pa_log(_("io_new() failed.")); goto quit; } } /* Create a new connection context */ if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) { - pa_log(_("pa_context_new() failed.\n")); + pa_log(_("pa_context_new() failed.")); goto quit; } @@ -1059,20 +1063,20 @@ int main(int argc, char *argv[]) { /* Connect the context */ if (pa_context_connect(context, server, 0, NULL) < 0) { - pa_log(_("pa_context_connect() failed: %s\n"), pa_strerror(pa_context_errno(context))); + pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context))); goto quit; } if (verbose) { if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) { - pa_log(_("pa_context_rttime_new() failed.\n")); + pa_log(_("pa_context_rttime_new() failed.")); goto quit; } } /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { - pa_log(_("pa_mainloop_run() failed.\n")); + pa_log(_("pa_mainloop_run() failed.")); goto quit; } -- cgit From 18433c19b690432179e9a0ed83eff611f5cecc67 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 13:45:59 +0200 Subject: alsa: handle correctly if alsa returns us 0 or EAGAIN on snd_pcm_mmap_begin if we didn't call snd_pcm_avail immediately before --- src/modules/alsa/alsa-sink.c | 22 ++++++++++++++++++---- src/modules/alsa/alsa-source.c | 28 +++++++++++++++++++++------- 2 files changed, 39 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index e7925902..46562cbd 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -401,6 +401,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle snd_pcm_sframes_t n; size_t n_bytes; int r; + pa_bool_t after_avail = TRUE; /* First we determine how many samples are missing to fill the * buffer up to 100% */ @@ -484,6 +485,9 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle if (PA_UNLIKELY((err = pa_alsa_safe_mmap_begin(u->pcm_handle, &areas, &offset, &frames, u->hwbuf_size, &u->sink->sample_spec)) < 0)) { + if (!after_avail && err == -EAGAIN) + break; + if ((r = try_recover(u, "snd_pcm_mmap_begin", err)) == 0) continue; @@ -494,9 +498,12 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle if (frames > pa_mempool_block_size_max(u->sink->core->mempool)/u->frame_size) frames = pa_mempool_block_size_max(u->sink->core->mempool)/u->frame_size; - if (frames == 0) + if (!after_avail && frames == 0) break; + pa_assert(frames > 0); + after_avail = FALSE; + /* Check these are multiples of 8 bit */ pa_assert((areas[0].first & 7) == 0); pa_assert((areas[0].step & 7)== 0); @@ -617,6 +624,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle for (;;) { snd_pcm_sframes_t frames; void *p; + pa_bool_t after_avail = TRUE; /* pa_log_debug("%lu frames to write", (unsigned long) frames); */ @@ -634,17 +642,23 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle frames = snd_pcm_writei(u->pcm_handle, (const uint8_t*) p + u->memchunk.index, (snd_pcm_uframes_t) frames); pa_memblock_release(u->memchunk.memblock); - if (frames == 0) - break; - if (PA_UNLIKELY(frames < 0)) { + if (!after_avail && (int) frames == -EAGAIN) + break; + if ((r = try_recover(u, "snd_pcm_writei", (int) frames)) == 0) continue; return r; } + if (!after_avail && frames == 0) + break; + + pa_assert(frames > 0); + after_avail = FALSE; + u->memchunk.index += (size_t) frames * u->frame_size; u->memchunk.length -= (size_t) frames * u->frame_size; diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 41bb768b..8a1fbe5f 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -391,6 +391,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled snd_pcm_sframes_t n; size_t n_bytes; int r; + pa_bool_t after_avail = TRUE; if (PA_UNLIKELY((n = pa_alsa_safe_avail(u->pcm_handle, u->hwbuf_size, &u->source->sample_spec)) < 0)) { @@ -463,6 +464,9 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled if (PA_UNLIKELY((err = pa_alsa_safe_mmap_begin(u->pcm_handle, &areas, &offset, &frames, u->hwbuf_size, &u->source->sample_spec)) < 0)) { + if (!after_avail && err == -EAGAIN) + break; + if ((r = try_recover(u, "snd_pcm_mmap_begin", err)) == 0) continue; @@ -473,9 +477,12 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled if (frames > pa_mempool_block_size_max(u->source->core->mempool)/u->frame_size) frames = pa_mempool_block_size_max(u->source->core->mempool)/u->frame_size; - if (frames == 0) + if (!after_avail && frames == 0) break; + pa_assert(frames > 0); + after_avail = FALSE; + /* Check these are multiples of 8 bit */ pa_assert((areas[0].first & 7) == 0); pa_assert((areas[0].step & 7)== 0); @@ -542,6 +549,7 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled snd_pcm_sframes_t n; size_t n_bytes; int r; + pa_bool_t after_avail = TRUE; if (PA_UNLIKELY((n = pa_alsa_safe_avail(u->pcm_handle, u->hwbuf_size, &u->source->sample_spec)) < 0)) { @@ -602,20 +610,26 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) p, (snd_pcm_uframes_t) frames); pa_memblock_release(chunk.memblock); - if (frames == 0) { - pa_memblock_unref(chunk.memblock); - break; - } - if (PA_UNLIKELY(frames < 0)) { pa_memblock_unref(chunk.memblock); - if ((r = try_recover(u, "snd_pcm_readi", (int) (frames))) == 0) + if (!after_avail && (int) frames == -EAGAIN) + break; + + if ((r = try_recover(u, "snd_pcm_readi", (int) frames)) == 0) continue; return r; } + if (!after_avail && frames == 0) { + pa_memblock_unref(chunk.memblock); + break; + } + + pa_assert(frames > 0); + after_avail = FALSE; + chunk.index = 0; chunk.length = (size_t) frames * u->frame_size; -- cgit From 2bbdf631f8ef1029558be19bcf8a9176a5932b8b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 13:58:22 +0200 Subject: udev: explain what happened when inotify_add_watch() returned ENOSPC, rhbz #513571 --- src/modules/module-udev-detect.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index c8ec2bf9..11de1ccb 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -336,8 +336,18 @@ static int setup_inotify(struct userdata *u) { pa_close(u->inotify_fd); u->inotify_fd = -1; - if (saved_errno == ENOENT) + if (saved_errno == ENOENT) { + pa_log_debug("/dev/snd/ is apparently not existing yet, retrying to create inotify watch later."); return 0; + } + + if (saved_errno == ENOSPC) { + pa_log("You apparently ran out of inotify watches, probably because Tracker/Beagle took them all away. " + "I wished people would do their homework first and fix inotify before using it for watching whole " + "directory trees which is something the current inotify is certainly not useful for. " + "Please make sure to drop the Tracker/Beagle guys a line complaining about their broken use of inotify."); + return 0; + } pa_log("inotify_add_watch() failed: %s", pa_cstrerror(saved_errno)); return -1; -- cgit From 5e24b6dff532ef82e028a78f020a826032493b2e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 15:49:22 +0200 Subject: memblock: try to hit an assert earlier when ref counting doesn't work --- src/pulsecore/memblock.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 2c3f98a5..3bc10de5 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -96,6 +96,7 @@ struct pa_memimport_segment { unsigned n_blocks; }; +/* A collection of multiple segments */ struct pa_memimport { pa_mutex *mutex; @@ -514,9 +515,9 @@ static void memblock_free(pa_memblock *b) { pa_mutex_lock(import->mutex); - pa_hashmap_remove( - import->blocks, - PA_UINT32_TO_PTR(b->per_type.imported.id)); + pa_assert_se(pa_hashmap_remove( + import->blocks, + PA_UINT32_TO_PTR(b->per_type.imported.id))); pa_assert(segment->n_blocks >= 1); if (-- segment->n_blocks <= 0) @@ -677,9 +678,9 @@ static void memblock_replace_import(pa_memblock *b) { pa_mutex_lock(import->mutex); - pa_hashmap_remove( - import->blocks, - PA_UINT32_TO_PTR(b->per_type.imported.id)); + pa_assert_se(pa_hashmap_remove( + import->blocks, + PA_UINT32_TO_PTR(b->per_type.imported.id))); memblock_make_local(b); @@ -960,6 +961,11 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i pa_mutex_lock(i->mutex); + if ((b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(block_id)))) { + pa_memblock_ref(b); + goto finish; + } + if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX) goto finish; @@ -989,12 +995,11 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i seg->n_blocks++; + stat_add(b); + finish: pa_mutex_unlock(i->mutex); - if (b) - stat_add(b); - return b; } -- 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') 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/modules/alsa/alsa-sink.c | 6 +++++- src/modules/alsa/alsa-source.c | 4 +++- src/pulse/stream.c | 2 +- src/pulsecore/time-smoother.c | 41 ++++++++++++++++++++--------------------- src/pulsecore/time-smoother.h | 2 +- 5 files changed, 30 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 46562cbd..7fc602be 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -899,9 +899,13 @@ static int unsuspend(struct userdata *u) { if (build_pollfd(u) < 0) goto fail; + u->write_count = 0; + pa_smoother_reset(u->smoother, pa_rtclock_now(), TRUE); + u->first = TRUE; u->since_start = 0; + pa_log_info("Resumed successfully..."); return 0; @@ -1204,7 +1208,7 @@ static int process_rewind(struct userdata *u) { if (rewind_nbytes <= 0) pa_log_info("Tried rewind, but was apparently not possible."); else { - u->write_count -= out_frames * u->frame_size; + u->write_count -= rewind_nbytes; pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes); pa_sink_process_rewind(u->sink, rewind_nbytes); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 8a1fbe5f..ed9c1480 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -854,7 +854,9 @@ static int unsuspend(struct userdata *u) { /* FIXME: We need to reload the volume somehow */ snd_pcm_start(u->pcm_handle); - pa_smoother_resume(u->smoother, pa_rtclock_now(), TRUE); + + u->read_count = 0; + pa_smoother_reset(u->smoother, pa_rtclock_now(), TRUE); pa_log_info("Resumed successfully..."); 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); } diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index 9d5a0705..1289f2b6 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -108,29 +108,11 @@ pa_smoother* pa_smoother_new( s = pa_xnew(pa_smoother, 1); s->adjust_time = adjust_time; s->history_time = history_time; - s->time_offset = 0; + s->min_history = min_history; s->monotonic = monotonic; - - s->px = s->py = 0; - s->dp = 1; - - s->ex = s->ey = s->ry = 0; - s->de = 1; - - s->history_idx = 0; - s->n_history = 0; - - s->last_y = s->last_x = 0; - - s->abc_valid = FALSE; - - s->paused = FALSE; s->smoothing = smoothing; - s->min_history = min_history; - - s->paused = paused; - s->time_offset = s->pause_time = time_offset; + pa_smoother_reset(s, time_offset, paused); return s; } @@ -514,9 +496,26 @@ pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay) return (pa_usec_t) llrint((double) y_delay / nde); } -void pa_smoother_reset(pa_smoother *s) { +void pa_smoother_reset(pa_smoother *s, pa_usec_t time_offset, pa_bool_t paused) { pa_assert(s); + s->px = s->py = 0; + s->dp = 1; + + s->ex = s->ey = s->ry = 0; + s->de = 1; + + s->history_idx = 0; s->n_history = 0; + + s->last_y = s->last_x = 0; + s->abc_valid = FALSE; + + s->paused = paused; + s->time_offset = s->pause_time = time_offset; + + /* #ifdef DEBUG_DATA */ + pa_log_debug("reset()"); +/* #endif */ } diff --git a/src/pulsecore/time-smoother.h b/src/pulsecore/time-smoother.h index 5244a7e7..63d33e48 100644 --- a/src/pulsecore/time-smoother.h +++ b/src/pulsecore/time-smoother.h @@ -52,7 +52,7 @@ void pa_smoother_set_time_offset(pa_smoother *s, pa_usec_t x_offset); void pa_smoother_pause(pa_smoother *s, pa_usec_t x); void pa_smoother_resume(pa_smoother *s, pa_usec_t x, pa_bool_t abrupt); -void pa_smoother_reset(pa_smoother *s); +void pa_smoother_reset(pa_smoother *s, pa_usec_t time_offset, pa_bool_t paused); void pa_smoother_fix_now(pa_smoother *s); -- 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') 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') 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 59659e1db64d2a88787943da75cf6c510d0ad98f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 20:22:19 +0200 Subject: interpol-test: allow configuration of latency --- src/tests/interpol-test.c | 81 +++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index 0c906d3e..007555c3 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -43,20 +43,37 @@ static pa_context *context = NULL; static pa_stream *stream = NULL; static pa_mainloop_api *mainloop_api = NULL; static pa_bool_t playback = TRUE; +static pa_usec_t latency = 0; static void stream_write_cb(pa_stream *p, size_t nbytes, void *userdata) { /* Just some silence */ - pa_assert_se(pa_stream_write(p, pa_xmalloc0(nbytes), nbytes, pa_xfree, 0, PA_SEEK_RELATIVE) == 0); + + for (;;) { + void *data; + + pa_assert_se((nbytes = pa_stream_writable_size(p)) != (size_t) -1); + + if (nbytes <= 0) + break; + + pa_assert_se(pa_stream_begin_write(p, &data, &nbytes) == 0); + pa_memzero(data, nbytes); + pa_assert_se(pa_stream_write(p, data, nbytes, NULL, 0, PA_SEEK_RELATIVE) == 0); + } } static void stream_read_cb(pa_stream *p, size_t nbytes, void *userdata) { - /* We don't care, just drop the data */ + /* We don't care about the data, just drop it */ - while (pa_stream_readable_size(p) > 0) { - const void *d; - size_t b; + for (;;) { + const void *data; - pa_assert_se(pa_stream_peek(p, &d, &b) == 0); + pa_assert_se((nbytes = pa_stream_readable_size(p)) != (size_t) -1); + + if (nbytes <= 0) + break; + + pa_assert_se(pa_stream_peek(p, &data, &nbytes) == 0); pa_assert_se(pa_stream_drop(p) == 0); } } @@ -82,27 +99,36 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_READY: { pa_stream_flags_t flags = PA_STREAM_AUTO_TIMING_UPDATE; - + pa_buffer_attr attr; static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; + pa_zero(attr); + attr.maxlength = (uint32_t) -1; + attr.tlength = latency > 0 ? (uint32_t) pa_usec_to_bytes(latency, &ss) : (uint32_t) -1; + attr.prebuf = (uint32_t) -1; + attr.minreq = (uint32_t) -1; + attr.fragsize = (uint32_t) -1; + #ifdef INTERPOLATE flags |= PA_STREAM_INTERPOLATE_TIMING; #endif + if (latency > 0) + flags |= PA_STREAM_ADJUST_LATENCY; + fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, "interpol-test", &ss, NULL); - assert(stream); + pa_assert_se(stream = pa_stream_new(c, "interpol-test", &ss, NULL)); if (playback) { - pa_assert_se(pa_stream_connect_playback(stream, NULL, NULL, flags, NULL, NULL) == 0); + pa_assert_se(pa_stream_connect_playback(stream, NULL, &attr, flags, NULL, NULL) == 0); pa_stream_set_write_callback(stream, stream_write_cb, NULL); } else { - pa_assert_se(pa_stream_connect_record(stream, NULL, NULL, flags) == 0); + pa_assert_se(pa_stream_connect_record(stream, NULL, &attr, flags) == 0); pa_stream_set_read_callback(stream, stream_read_cb, NULL); } @@ -123,7 +149,7 @@ static void context_state_callback(pa_context *c, void *userdata) { int main(int argc, char *argv[]) { pa_threaded_mainloop* m = NULL; - int k, r; + int k; struct timeval start, last_info = { 0, 0 }; pa_usec_t old_t = 0, old_rtc = 0; #ifdef CORK @@ -134,24 +160,22 @@ int main(int argc, char *argv[]) { playback = argc <= 1 || !pa_streq(argv[1], "-r"); - /* Set up a new main loop */ - m = pa_threaded_mainloop_new(); - assert(m); - - mainloop_api = pa_threaded_mainloop_get_api(m); + latency = + (argc >= 2 && !pa_streq(argv[1], "-r")) ? atoi(argv[1]) : + (argc >= 3 ? atoi(argv[2]) : 0); - context = pa_context_new(mainloop_api, argv[0]); - assert(context); + /* Set up a new main loop */ + pa_assert_se(m = pa_threaded_mainloop_new()); + pa_assert_se(mainloop_api = pa_threaded_mainloop_get_api(m)); + pa_assert_se(context = pa_context_new(mainloop_api, argv[0])); pa_context_set_state_callback(context, context_state_callback, NULL); - r = pa_context_connect(context, NULL, 0, NULL); - assert(r >= 0); + pa_assert_se(pa_context_connect(context, NULL, 0, NULL) >= 0); pa_gettimeofday(&start); - r = pa_threaded_mainloop_start(m); - assert(r >= 0); + pa_assert_se(pa_threaded_mainloop_start(m) >= 0); /* #ifdef CORK */ for (k = 0; k < 20000; k++) @@ -160,7 +184,7 @@ int main(int argc, char *argv[]) { /* #endif */ { pa_bool_t success = FALSE, changed = FALSE; - pa_usec_t t, rtc; + pa_usec_t t, rtc, d; struct timeval now, tv; pa_bool_t playing = FALSE; @@ -169,7 +193,8 @@ int main(int argc, char *argv[]) { if (stream) { const pa_timing_info *info; - if (pa_stream_get_time(stream, &t) >= 0) + if (pa_stream_get_time(stream, &t) >= 0 && + pa_stream_get_latency(stream, &d, NULL) >= 0) success = TRUE; if ((info = pa_stream_get_timing_info(stream))) { @@ -191,14 +216,16 @@ int main(int argc, char *argv[]) { pa_bool_t cork_now; #endif rtc = pa_timeval_diff(&now, &start); - printf("%i\t%llu\t%llu\t%llu\t%llu\t%lli\t%u\t%u\n", k, + printf("%i\t%llu\t%llu\t%llu\t%llu\t%lli\t%u\t%u\t%llu\t%llu\n", k, (unsigned long long) rtc, (unsigned long long) t, (unsigned long long) (rtc-old_rtc), (unsigned long long) (t-old_t), (signed long long) rtc - (signed long long) t, changed, - playing); + playing, + (unsigned long long) latency, + (unsigned long long) d); fflush(stdout); old_t = t; -- 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') 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') 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') 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 c14f6c179fb3a52219f2796d20a1c6f5648aa8a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 31 Jul 2009 00:50:19 +0200 Subject: tunnel: don't assert on misaligned reads, closes #597 and rhbz #496310 --- src/modules/module-tunnel.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index d1153829..f788f660 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -55,6 +55,7 @@ #include #include #include +#include #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" @@ -194,6 +195,7 @@ struct userdata { #else char *source_name; pa_source *source; + pa_mcalign *mcalign; #endif pa_auth_cookie *auth_cookie; @@ -614,14 +616,23 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off return 0; } - case SOURCE_MESSAGE_POST: + case SOURCE_MESSAGE_POST: { + pa_memchunk c; - if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) - pa_source_post(u->source, chunk); + pa_mcalign_push(u->mcalign, chunk); - u->counter += (int64_t) chunk->length; + while (pa_mcalign_pop(u->mcalign, &c) >= 0) { + + if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) + pa_source_post(u->source, &c); + + pa_memblock_unref(c.memblock); + + u->counter += (int64_t) c.length; + } return 0; + } case SOURCE_MESSAGE_REMOTE_SUSPEND: @@ -1937,6 +1948,8 @@ int pa__init(pa_module*m) { pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); pa_source_set_rtpoll(u->source, u->rtpoll); + + u->mcalign = pa_mcalign_new(pa_frame_size(&u->source->sample_spec)); #endif pa_xfree(dn); @@ -2030,6 +2043,11 @@ void pa__done(pa_module*m) { if (u->time_event) u->core->mainloop->time_free(u->time_event); +#ifndef TUNNEL_SINK + if (u->mcalign) + pa_mcalign_free(u->mcalign); +#endif + #ifdef TUNNEL_SINK pa_xfree(u->sink_name); #else -- cgit From 39aa1cf94d43efaa80571b3f9d3dc56297f2f5be Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 31 Jul 2009 02:07:24 +0200 Subject: alsa: revert to first set number of periods, then set buffer size Apparently some ALSA drivers aren't happy with getting the buffer size configured first followed the period size. So swap the order again and document this for future reference so that we don't turn that around again. --- src/modules/alsa/alsa-util.c | 55 +++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 1f3e5dcd..a47a8958 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -233,14 +233,16 @@ int pa_alsa_set_hw_params( goto finish; } - if (_period_size && tsched_size && _periods) { + if (_period_size > 0 && tsched_size > 0 && _periods > 0) { + snd_pcm_uframes_t buffer_size; + unsigned int p; /* Adjust the buffer sizes, if we didn't get the rate we were asking for */ _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate); tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate); if (_use_tsched) { - snd_pcm_uframes_t buffer_size = 0; + buffer_size = 0; if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size)) < 0) pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret)); @@ -251,32 +253,33 @@ int pa_alsa_set_hw_params( _periods = 1; } - if (_period_size > 0 && _periods > 0) { - snd_pcm_uframes_t buffer_size; - - buffer_size = _periods * _period_size; - - if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) - pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret)); - } - - if (_periods > 0) { - - /* First we pass 0 as direction to get exactly what we - * asked for. That this is necessary is presumably a bug - * in ALSA. All in all this is mostly a hint to ALSA, so - * we don't care if this fails. */ - - dir = 0; - if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir) < 0) { - dir = 1; - if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir) < 0) { - dir = -1; - if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) - pa_log_info("snd_pcm_hw_params_set_periods_near() failed: %s", pa_alsa_strerror(ret)); - } + /* Some ALSA drivers really don't like if we set the buffer + * size first and the number of periods second. (which would + * make a lot more sense to me) So, follow this rule and + * adjust the periods first and the buffer size second */ + + /* First we pass 0 as direction to get exactly what we + * asked for. That this is necessary is presumably a bug + * in ALSA. All in all this is mostly a hint to ALSA, so + * we don't care if this fails. */ + + p = _periods; + dir = 0; + if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) { + p = _periods; + dir = 1; + if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) { + p = _periods; + dir = -1; + if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir)) < 0) + pa_log_info("snd_pcm_hw_params_set_periods_near() failed: %s", pa_alsa_strerror(ret)); } } + + /* Now set the buffer size */ + buffer_size = _periods * _period_size; + if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) + pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret)); } if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) -- 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') 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') 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 0113e7282cc5c0131f9f681b84459fcdf2e806c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 31 Jul 2009 23:13:21 +0200 Subject: hal: add option to initialize all subdevices of an OSS device Patch from 'cmt', closes ticket #544 --- src/modules/module-hal-detect.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 658b3e55..79758b92 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -57,12 +57,14 @@ PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(TRUE); #if defined(HAVE_ALSA) && defined(HAVE_OSS) PA_MODULE_USAGE("api= " - "tsched="); + "tsched=" + "subdevs="); #elif defined(HAVE_ALSA) PA_MODULE_USAGE("api= " "tsched="); #elif defined(HAVE_OSS) -PA_MODULE_USAGE("api="); +PA_MODULE_USAGE("api=" + "subdevs="); #endif PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-hal-detect!"); @@ -82,6 +84,9 @@ struct userdata { #ifdef HAVE_ALSA pa_bool_t use_tsched; #endif +#ifdef HAVE_OSS + pa_bool_t init_subdevs; +#endif }; #define CAPABILITY_ALSA "alsa" @@ -91,6 +96,9 @@ static const char* const valid_modargs[] = { "api", #ifdef HAVE_ALSA "tsched", +#endif +#ifdef HAVE_OSS + "subdevs", #endif NULL }; @@ -264,7 +272,7 @@ fail: #ifdef HAVE_OSS -static pa_bool_t hal_oss_device_is_pcm(LibHalContext *context, const char *udi) { +static pa_bool_t hal_oss_device_is_pcm(LibHalContext *context, const char *udi, pa_bool_t init_subdevices) { char *class = NULL, *dev = NULL, *e; int device; pa_bool_t r = FALSE; @@ -294,7 +302,7 @@ static pa_bool_t hal_oss_device_is_pcm(LibHalContext *context, const char *udi) /* We only care for the main device */ device = libhal_device_get_property_int(context, udi, "oss.device", &error); - if (dbus_error_is_set(&error) || device != 0) + if (dbus_error_is_set(&error) || (device != 0 && init_subdevices == FALSE)) goto finish; r = TRUE; @@ -324,7 +332,7 @@ static int hal_device_load_oss(struct userdata *u, const char *udi, struct devic pa_assert(d); /* We only care for OSS PCM devices */ - if (!hal_oss_device_is_pcm(u->context, udi)) + if (!hal_oss_device_is_pcm(u->context, udi, u->init_subdevs)) goto fail; /* We store only one entry per card, hence we look for the originating device */ @@ -763,6 +771,13 @@ int pa__init(pa_module*m) { goto fail; } +#ifdef HAVE_OSS + if (pa_modargs_get_value_boolean(ma, "subdevs", &u->init_subdevs) < 0) { + pa_log("Failed to parse subdevs argument."); + goto fail; + } +#endif + if (!(u->connection = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) { pa_log_error("Unable to contact DBUS system bus: %s: %s", error.name, error.message); goto fail; -- cgit From e5c2256e360df3662295b8cc0594568e425e8679 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 1 Aug 2009 01:59:58 +0200 Subject: pipe: replace PIPE_BUF macro pa pa_pipe_buf call This should help portability to platforms that lack PIPE_BUF. Based on a patch from Samuel Thibault. See ticket #546 --- src/modules/module-pipe-sink.c | 6 +++--- src/modules/module-pipe-source.c | 2 +- src/pulsecore/core-util.c | 16 ++++++++++++++++ src/pulsecore/core-util.h | 3 +++ 4 files changed, 23 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 8a7dc846..9c169327 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -122,7 +122,7 @@ static int process_render(struct userdata *u) { pa_assert(u); if (u->memchunk.length <= 0) - pa_sink_render(u->sink, PIPE_BUF, &u->memchunk); + pa_sink_render(u->sink, pa_pipe_buf(u->fd), &u->memchunk); pa_assert(u->memchunk.length > 0); @@ -299,8 +299,8 @@ int pa__init(pa_module*m) { pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); - pa_sink_set_max_request(u->sink, PIPE_BUF); - pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(PIPE_BUF, &u->sink->sample_spec)); + pa_sink_set_max_request(u->sink, pa_pipe_buf(u->fd)); + pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(pa_pipe_buf(u->fd), &u->sink->sample_spec)); u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index e5609fb5..49104f8d 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -142,7 +142,7 @@ static void thread_func(void *userdata) { void *p; if (!u->memchunk.memblock) { - u->memchunk.memblock = pa_memblock_new(u->core->mempool, PIPE_BUF); + u->memchunk.memblock = pa_memblock_new(u->core->mempool, pa_pipe_buf(u->fd)); u->memchunk.index = u->memchunk.length = 0; } diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 5f777d5b..d01efa23 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2779,3 +2779,19 @@ char* pa_maybe_prefix_path(const char *path, const char *prefix) { return pa_sprintf_malloc("%s" PA_PATH_SEP "%s", prefix, path); } + +size_t pa_pipe_buf(int fd) { + +#ifdef _PC_PIPE_BUF + long n; + + if ((n = fpathconf(fd, _PC_PIPE_BUF)) >= 0) + return (size_t) n; +#endif + +#ifdef PIPE_BUF + return PIPE_BUF; +#else + return 4096; +#endif +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 96a0480a..b5e8453b 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -236,4 +236,7 @@ char **pa_split_spaces_strv(const char *s); char* pa_maybe_prefix_path(const char *path, const char *prefix); +/* Returns size of the specified pipe or 4096 on failure */ +size_t pa_pipe_buf(int fd); + #endif -- cgit From c6ea9fecc9acd70642ae45b01300484f6b900c6b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 1 Aug 2009 02:01:58 +0200 Subject: core-util: rework pa_strlcpy() to not rely on strncpy() strncpy() is very slow since it resets the entire destination buffer. Replace usage of strncpy by memcpy(). --- src/pulsecore/core-util.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index d01efa23..99644d7c 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -552,12 +552,20 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { /* Similar to OpenBSD's strlcpy() function */ char *pa_strlcpy(char *b, const char *s, size_t l) { + size_t k; + pa_assert(b); pa_assert(s); pa_assert(l > 0); - strncpy(b, s, l); - b[l-1] = 0; + k = strlen(s); + + if (k > l-1) + k = l-1; + + memcpy(b, s, k); + b[k] = 0; + return b; } -- cgit From 49fd8ee72e76cd27a978a843ecc58ad10fe077bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 1 Aug 2009 02:03:22 +0200 Subject: core-util: replace remaining fixed size destination string functions by _malloc() versions This helps portability to GNU/Hurd. Patch originally from Samuel Thibault but modified. Closes ticket #546 --- src/pulsecore/authkey.c | 37 ++++++++++---------- src/pulsecore/core-scache.c | 5 +-- src/pulsecore/core-util.c | 74 ++++++++++++++++++++++++++++++++++------ src/pulsecore/core-util.h | 2 ++ src/pulsecore/proplist-util.c | 6 ++-- src/tests/get-binary-name-test.c | 25 ++++++++++++-- src/utils/padsp.c | 8 +++-- 7 files changed, 119 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index 1e31d076..15613e27 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -147,47 +148,46 @@ int pa_authkey_load(const char *path, void *data, size_t length) { /* If the specified file path starts with / return it, otherwise * return path prepended with home directory */ -static const char *normalize_path(const char *fn, char *s, size_t l) { +static char *normalize_path(const char *fn) { pa_assert(fn); - pa_assert(s); - pa_assert(l > 0); #ifndef OS_IS_WIN32 if (fn[0] != '/') { #else if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') { #endif - char homedir[PATH_MAX]; + char *homedir, *s; - if (!pa_get_home_dir(homedir, sizeof(homedir))) + if (!(homedir = pa_get_home_dir_malloc())) return NULL; -#ifndef OS_IS_WIN32 - pa_snprintf(s, l, "%s/%s", homedir, fn); -#else - pa_snprintf(s, l, "%s\\%s", homedir, fn); -#endif + s = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", homedir, fn); + pa_xfree(homedir); + return s; } - return fn; + return pa_xstrdup(fn); } /* Load a cookie from a file in the home directory. If the specified * path starts with /, use it as absolute path instead. */ int pa_authkey_load_auto(const char *fn, void *data, size_t length) { - char path[PATH_MAX]; - const char *p; + char *p; + int ret; pa_assert(fn); pa_assert(data); pa_assert(length > 0); - if (!(p = normalize_path(fn, path, sizeof(path)))) + if (!(p = normalize_path(fn))) return -2; - return pa_authkey_load(p, data, length); + ret = pa_authkey_load(p, data, length); + pa_xfree(p); + + return ret; } /* Store the specified cookie in the specified cookie file */ @@ -195,14 +195,13 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) { int fd = -1; int unlock = 0, ret = -1; ssize_t r; - char path[PATH_MAX]; - const char *p; + char *p; pa_assert(fn); pa_assert(data); pa_assert(length > 0); - if (!(p = normalize_path(fn, path, sizeof(path)))) + if (!(p = normalize_path(fn))) return -2; if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) { @@ -232,5 +231,7 @@ finish: } } + pa_xfree(p); + return ret; } diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index 4c5a4b26..fde12ecf 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -494,13 +494,14 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { struct dirent *e; while ((e = readdir(dir))) { - char p[PATH_MAX]; + char *p; if (e->d_name[0] == '.') continue; - pa_snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name); + p = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", pathname, e->d_name); add_file(c, p); + pa_xfree(p); } closedir(dir); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 99644d7c..d4baf697 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -1336,26 +1336,32 @@ int pa_unlock_lockfile(const char *fn, int fd) { } static char *get_pulse_home(void) { - char h[PATH_MAX]; + char *h; struct stat st; + char *ret = NULL; - if (!pa_get_home_dir(h, sizeof(h))) { + if (!(h = pa_get_home_dir_malloc())) { pa_log_error("Failed to get home directory."); return NULL; } if (stat(h, &st) < 0) { pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno)); - return NULL; + goto finish; } if (st.st_uid != getuid()) { pa_log_error("Home directory %s not ours.", h); errno = EACCES; - return NULL; + goto finish; } - return pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h); + ret = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h); + +finish: + pa_xfree(h); + + return ret; } char *pa_get_state_dir(void) { @@ -1380,6 +1386,50 @@ char *pa_get_state_dir(void) { return d; } +char *pa_get_home_dir_malloc(void) { + char *homedir; + size_t allocated = 128; + + for (;;) { + homedir = pa_xmalloc(allocated); + + if (!pa_get_home_dir(homedir, allocated)) { + pa_xfree(homedir); + return NULL; + } + + if (strlen(homedir) < allocated - 1) + break; + + pa_xfree(homedir); + allocated *= 2; + } + + return homedir; +} + +char *pa_get_binary_name_malloc(void) { + char *t; + size_t allocated = 128; + + for (;;) { + t = pa_xmalloc(allocated); + + if (!pa_get_binary_name(t, allocated)) { + pa_xfree(t); + return NULL; + } + + if (strlen(t) < allocated - 1) + break; + + pa_xfree(t); + allocated *= 2; + } + + return t; +} + static char* make_random_dir(mode_t m) { static const char table[] = "abcdefghijklmnopqrstuvwxyz" @@ -1634,14 +1684,15 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env if (local) { const char *e; char *lfn; - char h[PATH_MAX]; + char *h; FILE *f; if ((e = getenv("PULSE_CONFIG_PATH"))) fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local); - else if (pa_get_home_dir(h, sizeof(h))) + else if ((h = pa_get_home_dir_malloc())) { fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local); - else + pa_xfree(h); + } else return NULL; #ifdef OS_IS_WIN32 @@ -1721,13 +1772,14 @@ char *pa_find_config_file(const char *global, const char *local, const char *env if (local) { const char *e; char *lfn; - char h[PATH_MAX]; + char *h; if ((e = getenv("PULSE_CONFIG_PATH"))) fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local); - else if (pa_get_home_dir(h, sizeof(h))) + else if ((h = pa_get_home_dir_malloc())) { fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local); - else + pa_xfree(h); + } else return NULL; #ifdef OS_IS_WIN32 diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index b5e8453b..6de4b771 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -126,6 +126,8 @@ char* pa_find_config_file(const char *global, const char *local, const char *env char *pa_get_runtime_dir(void); char *pa_get_state_dir(void); +char *pa_get_home_dir_malloc(void); +char *pa_get_binary_name_malloc(void); char *pa_runtime_path(const char *fn); char *pa_state_path(const char *fn, pa_bool_t prepend_machine_id); diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c index d9769bc7..23864bcb 100644 --- a/src/pulsecore/proplist-util.c +++ b/src/pulsecore/proplist-util.c @@ -186,10 +186,12 @@ void pa_init_proplist(pa_proplist *p) { } if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_BINARY)) { - char t[PATH_MAX]; - if (pa_get_binary_name(t, sizeof(t))) { + char *t; + + if ((t = pa_get_binary_name_malloc())) { char *c = pa_utf8_filter(t); pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_BINARY, c); + pa_xfree(t); pa_xfree(c); } } diff --git a/src/tests/get-binary-name-test.c b/src/tests/get-binary-name-test.c index a34e38fd..e49f2eff 100644 --- a/src/tests/get-binary-name-test.c +++ b/src/tests/get-binary-name-test.c @@ -23,12 +23,33 @@ #include #include +#include #include +#include int main(int argc, char *argv[]) { - char exename[PATH_MAX]; + char *exename; + size_t allocated = 128; + + for (;;) { + exename = pa_xmalloc(allocated); + + if (!pa_get_binary_name(exename, allocated)) { + printf("failed to read binary name\n"); + pa_xfree(exename); + break; + } + + if (strlen(exename) < allocated - 1) { + printf("%s\n", exename); + pa_xfree(exename); + break; + } + + pa_xfree(exename); + allocated *= 2; + } - printf("%s\n", pa_get_binary_name(exename, sizeof(exename))); return 0; } diff --git a/src/utils/padsp.c b/src/utils/padsp.c index dfa5aac2..882522c4 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -53,6 +53,7 @@ #include #include #include +#include /* On some systems SIOCINQ isn't defined, but FIONREAD is just an alias */ #if !defined(SIOCINQ) && defined(FIONREAD) @@ -459,15 +460,16 @@ static void reset_params(fd_info *i) { } static const char *client_name(char *buf, size_t n) { - char p[PATH_MAX]; + char *p; const char *e; if ((e = getenv("PADSP_CLIENT_NAME"))) return e; - if (pa_get_binary_name(p, sizeof(p))) + if ((p = pa_get_binary_name_malloc())) { snprintf(buf, n, "OSS Emulation[%s]", p); - else + pa_xfree(p); + } else snprintf(buf, n, "OSS"); return buf; -- cgit From 277822053c2f070940e5a996b9a6d95645d74590 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 1 Aug 2009 03:10:19 +0200 Subject: autospawn: if creating the lock file fails, pass error code cleanly back to main process This makes sure PA clients don't hang if $HOME is for some reason unsuitable for autospawn lockfiles. Closes #539 --- src/pulsecore/lock-autospawn.c | 66 ++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c index 4436974d..c0df7938 100644 --- a/src/pulsecore/lock-autospawn.c +++ b/src/pulsecore/lock-autospawn.c @@ -55,10 +55,16 @@ static pa_mutex *mutex; static unsigned n_ref = 0; static int lock_fd = -1; static pa_mutex *lock_fd_mutex = NULL; -static pa_bool_t taken = FALSE; -static pa_thread *thread; +static pa_thread *thread = NULL; static int pipe_fd[2] = { -1, -1 }; +static enum { + STATE_IDLE, + STATE_OWNING, + STATE_TAKEN, + STATE_FAILED +} state = STATE_IDLE; + static void destroy_mutex(void) PA_GCC_DESTRUCTOR; static int ref(void) { @@ -67,15 +73,16 @@ static int ref(void) { pa_assert(pipe_fd[0] >= 0); pa_assert(pipe_fd[1] >= 0); + pa_assert(lock_fd_mutex); n_ref++; return 0; } - pa_assert(lock_fd < 0); pa_assert(!lock_fd_mutex); - pa_assert(!taken); + pa_assert(state == STATE_IDLE); + pa_assert(lock_fd < 0); pa_assert(!thread); pa_assert(pipe_fd[0] < 0); pa_assert(pipe_fd[1] < 0); @@ -83,14 +90,14 @@ static int ref(void) { if (pipe(pipe_fd) < 0) return -1; - lock_fd_mutex = pa_mutex_new(FALSE, FALSE); - pa_make_fd_cloexec(pipe_fd[0]); pa_make_fd_cloexec(pipe_fd[1]); pa_make_fd_nonblock(pipe_fd[1]); pa_make_fd_nonblock(pipe_fd[0]); + lock_fd_mutex = pa_mutex_new(FALSE, FALSE); + n_ref = 1; return 0; } @@ -107,15 +114,18 @@ static void unref(pa_bool_t after_fork) { if (n_ref > 0) return; - pa_assert(!taken); - if (thread) { pa_thread_free(thread); thread = NULL; } pa_mutex_lock(lock_fd_mutex); - if (lock_fd >= 0) { + + pa_assert(state != STATE_TAKEN); + + if (state == STATE_OWNING) { + + pa_assert(lock_fd >= 0); if (after_fork) pa_close(lock_fd); @@ -127,10 +137,12 @@ static void unref(pa_bool_t after_fork) { pa_unlock_lockfile(lf, lock_fd); pa_xfree(lf); - - lock_fd = -1; } } + + lock_fd = -1; + state = STATE_IDLE; + pa_mutex_unlock(lock_fd_mutex); pa_mutex_free(lock_fd_mutex); @@ -205,15 +217,24 @@ static void thread_func(void *u) { if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) { pa_log_warn(_("Cannot access autospawn lock.")); - goto finish; + goto fail; } if ((fd = pa_lock_lockfile(lf)) < 0) - goto finish; + goto fail; pa_mutex_lock(lock_fd_mutex); - pa_assert(lock_fd < 0); + pa_assert(state == STATE_IDLE); lock_fd = fd; + state = STATE_OWNING; + pa_mutex_unlock(lock_fd_mutex); + + goto finish; + +fail: + pa_mutex_lock(lock_fd_mutex); + pa_assert(state == STATE_IDLE); + state = STATE_FAILED; pa_mutex_unlock(lock_fd_mutex); finish: @@ -238,12 +259,10 @@ static void create_mutex(void) { } static void destroy_mutex(void) { - if (mutex) pa_mutex_free(mutex); } - int pa_autospawn_lock_init(void) { int ret = -1; @@ -273,13 +292,18 @@ int pa_autospawn_lock_acquire(pa_bool_t block) { empty_pipe(); - if (lock_fd >= 0 && !taken) { - taken = TRUE; + if (state == STATE_OWNING) { + state = STATE_TAKEN; ret = 1; break; } - if (lock_fd < 0) + if (state == STATE_FAILED) { + ret = -1; + break; + } + + if (state == STATE_IDLE) if (start_thread() < 0) break; @@ -310,8 +334,8 @@ void pa_autospawn_lock_release(void) { pa_mutex_lock(mutex); pa_assert(n_ref >= 1); - pa_assert(taken); - taken = FALSE; + pa_assert(state == STATE_TAKEN); + state = STATE_OWNING; ping(); -- cgit From 34f31f666e2a2c301e0735e48e48da44ff503acc Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sun, 2 Aug 2009 17:52:05 +0200 Subject: Recover stream when it's suspended upon rewind Error from snd_pcm_rewind() might mean we just woke up from suspend and didn't have a chance to try to recover the stream since we didn't write to it in between. Call try_recover() in such cases. Note that for this to work kernel must return ESTRPIPE instead of EBADF for rewind/forward attempts on suspended streams, so that snd_pcm_recover() can recognize it should snd_pcm_resume() the stream. This is not the case yet (2.6.31-rc5), patch is available. Signed-off-by: Lubomir Rintel --- src/modules/alsa/alsa-sink.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 7fc602be..2a734e35 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -340,6 +340,9 @@ static int try_recover(struct userdata *u, const char *call, int err) { if (err == -EPIPE) pa_log_debug("%s: Buffer underrun!", call); + if (err == -EBADFD) + pa_log_debug("%s: Stream suspended!", call); + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) < 0) { pa_log("%s: %s", call, pa_alsa_strerror(err)); return -1; @@ -1199,8 +1202,11 @@ static int process_rewind(struct userdata *u) { pa_log_debug("before: %lu", (unsigned long) in_frames); if ((out_frames = snd_pcm_rewind(u->pcm_handle, (snd_pcm_uframes_t) in_frames)) < 0) { pa_log("snd_pcm_rewind() failed: %s", pa_alsa_strerror((int) out_frames)); - return -1; + if (try_recover(u, "process_rewind", out_frames) < 0) + return -1; + out_frames = 0; } + pa_log_debug("after: %lu", (unsigned long) out_frames); rewind_nbytes = (size_t) out_frames * u->frame_size; -- 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') 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 9b2534b6d0667589f69bf36702f9b998841d3d80 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 4 Aug 2009 00:23:43 +0200 Subject: alsa: properly treat ESTRPIPE as system suspend --- src/modules/alsa/alsa-sink.c | 4 ++-- src/modules/alsa/alsa-source.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 2a734e35..1c38430f 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -340,8 +340,8 @@ static int try_recover(struct userdata *u, const char *call, int err) { if (err == -EPIPE) pa_log_debug("%s: Buffer underrun!", call); - if (err == -EBADFD) - pa_log_debug("%s: Stream suspended!", call); + if (err == -ESTRPIPE) + pa_log_debug("%s: System suspended!", call); if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) < 0) { pa_log("%s: %s", call, pa_alsa_strerror(err)); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index ed9c1480..9a51f857 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -333,6 +333,9 @@ static int try_recover(struct userdata *u, const char *call, int err) { if (err == -EPIPE) pa_log_debug("%s: Buffer overrun!", call); + if (err == -ESTRPIPE) + pa_log_debug("%s: System suspended!", call); + if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) < 0) { pa_log("%s: %s", call, pa_alsa_strerror(err)); return -1; -- 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') 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') 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') 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') 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') 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') 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 ff52588c7b1353542e44633f366b3fda2ba49269 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 03:52:15 +0200 Subject: smoother: readd #ifdef protection --- src/pulsecore/time-smoother.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index 1289f2b6..d6c37878 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -515,7 +515,7 @@ void pa_smoother_reset(pa_smoother *s, pa_usec_t time_offset, pa_bool_t paused) s->paused = paused; s->time_offset = s->pause_time = time_offset; - /* #ifdef DEBUG_DATA */ +#ifdef DEBUG_DATA pa_log_debug("reset()"); -/* #endif */ +#endif } -- cgit From 51b3899348bf29dd88b56691aeea9f57895dfd14 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Aug 2009 23:55:06 +0200 Subject: core: save volume/mute changes coming from the hardware automatically Volume changes coming from the lower layers are most likely changes triggered by the user, so let's save them automatically. --- src/modules/bluetooth/module-bluetooth-device.c | 4 ++-- src/modules/module-tunnel.c | 4 ++-- src/pulsecore/sink.c | 25 +++++++++++++++---------- src/pulsecore/sink.h | 4 ++-- src/pulsecore/source.c | 22 +++++++++++----------- src/pulsecore/source.h | 4 ++-- 6 files changed, 34 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 0560ef32..e682997f 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -1446,12 +1446,12 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us if (u->sink && dbus_message_is_signal(m, "org.bluez.Headset", "SpeakerGainChanged")) { pa_cvolume_set(&v, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15)); - pa_sink_volume_changed(u->sink, &v, TRUE); + pa_sink_volume_changed(u->sink, &v); } else if (u->source && dbus_message_is_signal(m, "org.bluez.Headset", "MicrophoneGainChanged")) { pa_cvolume_set(&v, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15)); - pa_source_volume_changed(u->source, &v, TRUE); + pa_source_volume_changed(u->source, &v); } } } diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index f788f660..eaccea4e 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1165,10 +1165,10 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag pa_cvolume_equal(&volume, &u->sink->virtual_volume)) return; - pa_sink_volume_changed(u->sink, &volume, FALSE); + pa_sink_volume_changed(u->sink, &volume); if (u->version >= 11) - pa_sink_mute_changed(u->sink, mute, FALSE); + pa_sink_mute_changed(u->sink, mute); return; diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index d8f3c7d1..73a70625 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1386,6 +1386,12 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_boo s->reference_volume = s->virtual_volume; + /* Something got changed in the hardware. It probably + * makes sense to save changed hw settings given that hw + * volume changes not triggered by PA are almost certainly + * done by the user. */ + s->save_volume = TRUE; + if (s->flags & PA_SINK_FLAT_VOLUME) pa_sink_propagate_flat_volume(s); @@ -1397,17 +1403,15 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_boo } /* Called from main thread */ -void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume, pa_bool_t save) { +void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) { pa_sink_assert_ref(s); /* The sink implementor may call this if the volume changed to make sure everyone is notified */ - if (pa_cvolume_equal(&s->virtual_volume, new_volume)) { - s->save_volume = s->save_volume || save; + if (pa_cvolume_equal(&s->virtual_volume, new_volume)) return; - } s->reference_volume = s->virtual_volume = *new_volume; - s->save_volume = save; + s->save_volume = TRUE; if (s->flags & PA_SINK_FLAT_VOLUME) pa_sink_propagate_flat_volume(s); @@ -1449,6 +1453,8 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) { pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0); if (old_muted != s->muted) { + s->save_muted = TRUE; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); /* Make sure the soft mute status stays in sync */ @@ -1456,22 +1462,21 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) { } } + return s->muted; } /* Called from main thread */ -void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted, pa_bool_t save) { +void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) { pa_sink_assert_ref(s); /* The sink implementor may call this if the volume changed to make sure everyone is notified */ - if (s->muted == new_muted) { - s->save_muted = s->save_muted || save; + if (s->muted == new_muted) return; - } s->muted = new_muted; - s->save_muted = save; + s->save_muted = TRUE; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index d16fcc01..7a8cdaf1 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -267,8 +267,8 @@ void pa_sink_detach(pa_sink *s); void pa_sink_attach(pa_sink *s); void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume); -void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume, pa_bool_t save); -void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted, pa_bool_t save); +void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume); +void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted); pa_bool_t pa_device_init_description(pa_proplist *p); pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 74f38bc5..ad7462b1 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -773,26 +773,26 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) { pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0); - if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) + if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) { + s->save_volume = TRUE; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + } } return &s->virtual_volume; } /* Called from main thread */ -void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume, pa_bool_t save) { +void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) { pa_source_assert_ref(s); /* The source implementor may call this if the volume changed to make sure everyone is notified */ - if (pa_cvolume_equal(&s->virtual_volume, new_volume)) { - s->save_volume = s->save_volume || save; + if (pa_cvolume_equal(&s->virtual_volume, new_volume)) return; - } s->virtual_volume = *new_volume; - s->save_volume = save; + s->save_volume = TRUE; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } @@ -831,6 +831,8 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) { pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0); if (old_muted != s->muted) { + s->save_muted = TRUE; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); /* Make sure the soft mute status stays in sync */ @@ -842,18 +844,16 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) { } /* Called from main thread */ -void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted, pa_bool_t save) { +void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) { pa_source_assert_ref(s); /* The source implementor may call this if the mute state changed to make sure everyone is notified */ - if (s->muted == new_muted) { - s->save_muted = s->save_muted || save; + if (s->muted == new_muted) return; - } s->muted = new_muted; - s->save_muted = save; + s->save_muted = TRUE; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 7e9fd8b7..d22e7ca5 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -237,8 +237,8 @@ void pa_source_detach(pa_source *s); void pa_source_attach(pa_source *s); void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume); -void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume, pa_bool_t save); -void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted, pa_bool_t save); +void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume); +void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted); int pa_source_sync_suspend(pa_source *s); -- cgit From 7d4916379bbf05384ad199004949cc220822aa5f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Aug 2009 23:58:45 +0200 Subject: ladspa/remap: make sure we process all requested rewinds unconditionally In some situations a rewind request travelling downstream might be optimized away on its way and an upstream rewind processing might never come back. Hence, call _process_rewind() before each _render()just to make sure we processed them all. --- src/modules/module-ladspa-sink.c | 3 +++ src/modules/module-remap-sink.c | 3 +++ src/pulsecore/sink.c | 7 +++++-- src/pulsecore/source.c | 6 +++--- 4 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 21f4a8f1..b26330c8 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -178,6 +178,9 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state)) return -1; + /* Hmm, process any rewind request that might be queued up */ + pa_sink_process_rewind(u->sink, 0); + while (pa_memblockq_peek(u->memblockq, &tchunk) < 0) { pa_memchunk nchunk; diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 119f5b9f..0b7b9b8f 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -148,6 +148,9 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state)) return -1; + /* Hmm, process any rewind request that might be queued up */ + pa_sink_process_rewind(u->sink, 0); + pa_sink_render(u->sink, nbytes, chunk); return 0; } diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 73a70625..5e9662c2 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -665,11 +665,14 @@ void pa_sink_move_all_fail(pa_queue *q) { void pa_sink_process_rewind(pa_sink *s, size_t nbytes) { pa_sink_input *i; void *state = NULL; + pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); /* If nobody requested this and this is actually no real rewind - * then we can short cut this */ + * then we can short cut this. Please note that this means that + * not all rewind requests triggered upstream will always be + * translated in actual requests! */ if (!s->thread_info.rewind_requested && nbytes <= 0) return; @@ -682,7 +685,7 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) { if (nbytes > 0) pa_log_debug("Processing rewind..."); - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) { + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) { pa_sink_input_assert_ref(i); pa_sink_input_process_rewind(i, nbytes); } diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index ad7462b1..b8af148f 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -592,15 +592,15 @@ void pa_source_process_rewind(pa_source *s, size_t nbytes) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); - if (s->thread_info.state == PA_SOURCE_SUSPENDED) + if (nbytes <= 0) return; - if (nbytes <= 0) + if (s->thread_info.state == PA_SOURCE_SUSPENDED) return; pa_log_debug("Processing rewind..."); - while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) { + PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state) { pa_source_output_assert_ref(o); pa_source_output_process_rewind(o, nbytes); } -- cgit From 4c1511500759c7701b407227e907c0e5c8e38763 Mon Sep 17 00:00:00 2001 From: Diego Elio 'Flameeyes' Pettenò Date: Sat, 8 Aug 2009 01:53:15 +0200 Subject: Split OSS support in output and wrapper. Since Fedora does not enable OSS output support at all, but still uses padsp, and in Gentoo we could also make use of padsp without OSS output support, split the two things in two parameters, although they both check for sys/soundcard.h once. --- src/Makefile.am | 4 ++-- src/daemon/main.c | 2 +- src/modules/module-detect.c | 4 ++-- src/modules/module-hal-detect.c | 16 ++++++++-------- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index c022fa7c..5d711577 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -776,7 +776,7 @@ libpulse_mainloop_glib_la_LDFLAGS = $(AM_LDFLAGS) $(VERSIONING_LDFLAGS) -version # OSS emulation # ################################### -if HAVE_OSS +if HAVE_OSS_WRAPPER lib_LTLIBRARIES += libpulsedsp.la bin_SCRIPTS += utils/padsp endif @@ -1031,7 +1031,7 @@ modlibexec_LTLIBRARIES += \ module-x11-cork-request.la endif -if HAVE_OSS +if HAVE_OSS_OUTPUT modlibexec_LTLIBRARIES += \ liboss-util.la \ module-oss.la diff --git a/src/daemon/main.c b/src/daemon/main.c index b209c514..7a951954 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -113,7 +113,7 @@ int allow_severity = LOG_INFO; int deny_severity = LOG_WARNING; #endif -#ifdef HAVE_OSS +#ifdef HAVE_OSS_WRAPPER /* padsp looks for this symbol in the running process and disables * itself if it finds it and it is set to 7 (which is actually a bit * mask). For details see padsp. */ diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 18479df3..956fe4c5 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -119,7 +119,7 @@ static int detect_alsa(pa_core *c, int just_one) { } #endif -#ifdef HAVE_OSS +#ifdef HAVE_OSS_OUTPUT static int detect_oss(pa_core *c, int just_one) { FILE *f; int n = 0, b = 0; @@ -240,7 +240,7 @@ int pa__init(pa_module*m) { #ifdef HAVE_ALSA if ((n = detect_alsa(m->core, just_one)) <= 0) #endif -#ifdef HAVE_OSS +#ifdef HAVE_OSS_OUTPUT if ((n = detect_oss(m->core, just_one)) <= 0) #endif #ifdef HAVE_SOLARIS diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 79758b92..b5b2aaf0 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -55,14 +55,14 @@ PA_MODULE_AUTHOR("Shahms King"); PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(TRUE); -#if defined(HAVE_ALSA) && defined(HAVE_OSS) +#if defined(HAVE_ALSA) && defined(HAVE_OSS_OUTPUT) PA_MODULE_USAGE("api= " "tsched=" "subdevs="); #elif defined(HAVE_ALSA) PA_MODULE_USAGE("api= " "tsched="); -#elif defined(HAVE_OSS) +#elif defined(HAVE_OSS_OUTPUT) PA_MODULE_USAGE("api=" "subdevs="); #endif @@ -84,7 +84,7 @@ struct userdata { #ifdef HAVE_ALSA pa_bool_t use_tsched; #endif -#ifdef HAVE_OSS +#ifdef HAVE_OSS_OUTPUT pa_bool_t init_subdevs; #endif }; @@ -97,7 +97,7 @@ static const char* const valid_modargs[] = { #ifdef HAVE_ALSA "tsched", #endif -#ifdef HAVE_OSS +#ifdef HAVE_OSS_OUTPUT "subdevs", #endif NULL @@ -270,7 +270,7 @@ fail: #endif -#ifdef HAVE_OSS +#ifdef HAVE_OSS_OUTPUT static pa_bool_t hal_oss_device_is_pcm(LibHalContext *context, const char *udi, pa_bool_t init_subdevices) { char *class = NULL, *dev = NULL, *e; @@ -402,7 +402,7 @@ static struct device* hal_device_add(struct userdata *u, const char *udi) { if (pa_streq(u->capability, CAPABILITY_ALSA)) r = hal_device_load_alsa(u, udi, d); #endif -#ifdef HAVE_OSS +#ifdef HAVE_OSS_OUTPUT if (pa_streq(u->capability, CAPABILITY_OSS)) r = hal_device_load_oss(u, udi, d); #endif @@ -761,7 +761,7 @@ int pa__init(pa_module*m) { api = pa_modargs_get_value(ma, "api", "oss"); #endif -#ifdef HAVE_OSS +#ifdef HAVE_OSS_OUTPUT if (pa_streq(api, "oss")) u->capability = CAPABILITY_OSS; #endif @@ -771,7 +771,7 @@ int pa__init(pa_module*m) { goto fail; } -#ifdef HAVE_OSS +#ifdef HAVE_OSS_OUTPUT if (pa_modargs_get_value_boolean(ma, "subdevs", &u->init_subdevs) < 0) { pa_log("Failed to parse subdevs argument."); goto fail; -- cgit From 9bd3398f94114387dc91bf930bdad90d58711e88 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Aug 2009 04:30:42 +0200 Subject: mix-test: fix test for s24-32 samples --- src/tests/mix-test.c | 74 +++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/tests/mix-test.c b/src/tests/mix-test.c index 3f65cbac..f9f76da3 100644 --- a/src/tests/mix-test.c +++ b/src/tests/mix-test.c @@ -69,6 +69,8 @@ static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) { break; } + case PA_SAMPLE_S24_32NE: + case PA_SAMPLE_S24_32RE: case PA_SAMPLE_S32NE: case PA_SAMPLE_S32RE: { uint32_t *u = d; @@ -84,7 +86,7 @@ static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) { uint8_t *u = d; for (i = 0; i < chunk->length / pa_frame_size(ss); i++) { - printf("0x%02x%02x%02xx ", *u, *(u+1), *(u+2)); + printf("0x%02x%02x%02xx ", *u, *(u+1), *(u+2)); u += 3; } @@ -125,66 +127,72 @@ static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) { case PA_SAMPLE_U8: case PA_SAMPLE_ULAW: case PA_SAMPLE_ALAW: { - static const uint8_t u8_samples[] = - { 0x00, 0xFF, 0x7F, 0x80, 0x9f, - 0x3f, 0x01, 0xF0, 0x20, 0x21 }; + static const uint8_t u8_samples[] = { + 0x00, 0xFF, 0x7F, 0x80, 0x9f, + 0x3f, 0x01, 0xF0, 0x20, 0x21 + }; - memcpy(d, &u8_samples[0], sizeof(u8_samples)); + memcpy(d, u8_samples, sizeof(u8_samples)); break; } case PA_SAMPLE_S16NE: case PA_SAMPLE_S16RE: { - static const uint16_t u16_samples[] = - { 0x0000, 0xFFFF, 0x7FFF, 0x8000, 0x9fff, - 0x3fff, 0x0001, 0xF000, 0x0020, 0x0021 }; + static const uint16_t u16_samples[] = { + 0x0000, 0xFFFF, 0x7FFF, 0x8000, 0x9fff, + 0x3fff, 0x0001, 0xF000, 0x0020, 0x0021 + }; - memcpy(d, &u16_samples[0], sizeof(u16_samples)); + memcpy(d, u16_samples, sizeof(u16_samples)); break; } + case PA_SAMPLE_S24_32NE: + case PA_SAMPLE_S24_32RE: case PA_SAMPLE_S32NE: case PA_SAMPLE_S32RE: { - static const uint32_t u32_samples[] = - { 0x00000001, 0xFFFF0002, 0x7FFF0003, 0x80000004, 0x9fff0005, - 0x3fff0006, 0x00010007, 0xF0000008, 0x00200009, 0x0021000A }; + static const uint32_t u32_samples[] = { + 0x00000001, 0xFFFF0002, 0x7FFF0003, 0x80000004, 0x9fff0005, + 0x3fff0006, 0x00010007, 0xF0000008, 0x00200009, 0x0021000A + }; - memcpy(d, &u32_samples[0], sizeof(u32_samples)); + memcpy(d, u32_samples, sizeof(u32_samples)); break; } case PA_SAMPLE_S24NE: case PA_SAMPLE_S24RE: { - /* Need to be on a byte array because they are not aligned */ - static const uint8_t u24_samples[] = - { 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0x02, - 0x7F, 0xFF, 0x03, - 0x80, 0x00, 0x04, - 0x9f, 0xff, 0x05, - 0x3f, 0xff, 0x06, - 0x01, 0x00, 0x07, - 0xF0, 0x00, 0x08, - 0x20, 0x00, 0x09, - 0x21, 0x00, 0x0A }; - - memcpy(d, &u24_samples[0], sizeof(u24_samples)); + /* Need to be on a byte array because they are not aligned */ + static const uint8_t u24_samples[] = { + 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0x02, + 0x7F, 0xFF, 0x03, + 0x80, 0x00, 0x04, + 0x9f, 0xff, 0x05, + 0x3f, 0xff, 0x06, + 0x01, 0x00, 0x07, + 0xF0, 0x00, 0x08, + 0x20, 0x00, 0x09, + 0x21, 0x00, 0x0A + }; + + memcpy(d, u24_samples, sizeof(u24_samples)); break; } case PA_SAMPLE_FLOAT32NE: case PA_SAMPLE_FLOAT32RE: { float *u = d; - static const float float_samples[] = - { 0.0f, -1.0f, 1.0f, 4711.0f, 0.222f, - 0.33f, -.3f, 99.0f, -0.555f, -.123f }; + static const float float_samples[] = { + 0.0f, -1.0f, 1.0f, 4711.0f, 0.222f, + 0.33f, -.3f, 99.0f, -0.555f, -.123f + }; if (ss->format == PA_SAMPLE_FLOAT32RE) { for (i = 0; i < 10; i++) u[i] = swap_float(float_samples[i]); - } else { - memcpy(d, &float_samples[0], sizeof(float_samples)); - } + } else + memcpy(d, float_samples, sizeof(float_samples)); break; } -- 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') 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 c904f97e2d77bac298130de55621fa2498b5aa51 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 11 Aug 2009 23:04:35 +0200 Subject: hal: add stub module that loads module-udev-detect instead of module-hal-detect This adds module-hal-detect-compat.c which when enabled will be compiled into a module module-hal-detect which simply loads module-udev-detect. The purpose of this is to allow easy upgrading without breaking default.pa. Distributions are recommended to enable this to easy upgrades from HAL versions of PA to udev versions. --- src/Makefile.am | 13 +++++- src/modules/module-hal-detect-compat.c | 84 ++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/modules/module-hal-detect-compat.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 5d711577..2add80ef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1120,6 +1120,11 @@ modlibexec_LTLIBRARIES += \ module-hal-detect.la endif +if HAVE_HAL_COMPAT +modlibexec_LTLIBRARIES += \ + module-hal-detect.la +endif + if HAVE_UDEV modlibexec_LTLIBRARIES += \ module-udev-detect.la @@ -1576,10 +1581,16 @@ module_jack_source_la_LDFLAGS = $(MODULE_LDFLAGS) module_jack_source_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la $(JACK_LIBS) libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la module_jack_source_la_CFLAGS = $(AM_CFLAGS) $(JACK_CFLAGS) +if HAVE_HAL_COMPAT +module_hal_detect_la_SOURCES = modules/module-hal-detect-compat.c +module_hal_detect_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la +module_hal_detect_la_CFLAGS = $(AM_CFLAGS) +else module_hal_detect_la_SOURCES = modules/module-hal-detect.c -module_hal_detect_la_LDFLAGS = $(MODULE_LDFLAGS) module_hal_detect_la_LIBADD = $(AM_LIBADD) $(HAL_LIBS) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la module_hal_detect_la_CFLAGS = $(AM_CFLAGS) $(HAL_CFLAGS) +endif +module_hal_detect_la_LDFLAGS = $(MODULE_LDFLAGS) module_udev_detect_la_SOURCES = modules/module-udev-detect.c module_udev_detect_la_LDFLAGS = $(MODULE_LDFLAGS) diff --git a/src/modules/module-hal-detect-compat.c b/src/modules/module-hal-detect-compat.c new file mode 100644 index 00000000..14cf8143 --- /dev/null +++ b/src/modules/module-hal-detect-compat.c @@ -0,0 +1,84 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include "module-hal-detect-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Compatibility module"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-hal-detect!"); + +static const char* const valid_modargs[] = { + "api", + "tsched", + "subdevices", + NULL, +}; + +int pa__init(pa_module*m) { + pa_modargs *ma = NULL; + pa_bool_t tsched = TRUE; + pa_module *n; + char *t; + + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "tsched", &tsched) < 0) { + pa_log("tsched= expects boolean arguments"); + goto fail; + } + + pa_log_warn("We will now load module-udev-detect. Please make sure to remove module-hal-detect from your configuration."); + + t = pa_sprintf_malloc("tsched=%s", pa_yes_no(tsched)); + n = pa_module_load(m->core, "module-udev-detect", t); + pa_xfree(t); + + if (n) + pa_module_unload_request(m, TRUE); + + pa_modargs_free(ma); + + return n ? 0 : -1; + +fail: + if (ma) + pa_modargs_free(ma); + + return -1; +} -- cgit From c117febbe4a92864a7214da2dd8a5c9dae432925 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 11 Aug 2009 23:18:01 +0200 Subject: hal: replace subdevs= parameter by subdevices= parameter Abbreviating tsched like this was bad enough, so let's not add another option here. --- src/modules/module-hal-detect.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index b5b2aaf0..ec370d61 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -58,13 +58,13 @@ PA_MODULE_LOAD_ONCE(TRUE); #if defined(HAVE_ALSA) && defined(HAVE_OSS_OUTPUT) PA_MODULE_USAGE("api= " "tsched=" - "subdevs="); + "subdevices="); #elif defined(HAVE_ALSA) PA_MODULE_USAGE("api= " "tsched="); #elif defined(HAVE_OSS_OUTPUT) PA_MODULE_USAGE("api=" - "subdevs="); + "subdevices="); #endif PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-hal-detect!"); @@ -98,7 +98,7 @@ static const char* const valid_modargs[] = { "tsched", #endif #ifdef HAVE_OSS_OUTPUT - "subdevs", + "subdevices", #endif NULL }; @@ -772,8 +772,8 @@ int pa__init(pa_module*m) { } #ifdef HAVE_OSS_OUTPUT - if (pa_modargs_get_value_boolean(ma, "subdevs", &u->init_subdevs) < 0) { - pa_log("Failed to parse subdevs argument."); + if (pa_modargs_get_value_boolean(ma, "subdevices", &u->init_subdevs) < 0) { + pa_log("Failed to parse subdevices= argument."); goto fail; } #endif -- cgit From d27e26dca0b492b1906b42b2d0f7decd38ed8ae3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 11 Aug 2009 23:19:28 +0200 Subject: volume-restore: forward module load return value of stream-restore back to caller --- src/modules/module-volume-restore.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 91da598e..6e484eae 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -48,6 +48,7 @@ static const char* const valid_modargs[] = { int pa__init(pa_module*m) { pa_modargs *ma = NULL; pa_bool_t restore_device = TRUE, restore_volume = TRUE; + pa_module *n; char *t; pa_assert(m); @@ -66,13 +67,15 @@ int pa__init(pa_module*m) { pa_log_warn("We will now load module-stream-restore. Please make sure to remove module-volume-restore from your configuration."); t = pa_sprintf_malloc("restore_volume=%s restore_device=%s", pa_yes_no(restore_volume), pa_yes_no(restore_device)); - pa_module_load(m->core, "module-stream-restore", t); + n = pa_module_load(m->core, "module-stream-restore", t); pa_xfree(t); - pa_module_unload_request(m, TRUE); + if (n) + pa_module_unload_request(m, TRUE); pa_modargs_free(ma); - return 0; + + return n ? 0 : -1; fail: if (ma) -- cgit From 462cdf44b7fe36768c836c90761f6b8153290517 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 00:53:38 +0200 Subject: alsa: adjust priority bonus of mappings that match the configured default channel map We need to make sure that having both input and output weighs more for selecting the default profile than a channel map that matches the default channel map has. https://bugzilla.redhat.com/show_bug.cgi?id=496320 --- src/modules/alsa/alsa-mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 6a0b4ab7..a4c2ee0f 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -2838,9 +2838,9 @@ static int mapping_verify(pa_alsa_mapping *m, const pa_channel_map *bonus) { if (bonus) { if (pa_channel_map_equal(&m->channel_map, bonus)) - m->priority += 5000; + m->priority += 50; else if (m->channel_map.channels == bonus->channels) - m->priority += 4000; + m->priority += 30; } return 0; -- cgit From e8340345f6a102cd03b6676576bcd3879ead7aad Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 00:56:10 +0200 Subject: alsa: enable ext. amplifier by default --- src/modules/alsa/mixer/paths/analog-output.conf.common | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/mixer/paths/analog-output.conf.common b/src/modules/alsa/mixer/paths/analog-output.conf.common index cc1185f4..3c6ce803 100644 --- a/src/modules/alsa/mixer/paths/analog-output.conf.common +++ b/src/modules/alsa/mixer/paths/analog-output.conf.common @@ -104,8 +104,8 @@ switch = select [Option External Amplifier:on] name = output-amplifier-on -priority = 0 +priority = 10 [Option External Amplifier:off] name = output-amplifier-off -priority = 10 +priority = 0 -- cgit From eb40da25d666b2dce9b69ae21cd36513eb885f61 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 01:50:24 +0200 Subject: daemon: install D-Bus system policy file for PA system instances Original patch from 'mgrela'. http://pulseaudio.org/ticket/582 --- src/Makefile.am | 5 +++++ src/daemon/pulseaudio-system.conf | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/daemon/pulseaudio-system.conf (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 2add80ef..aa82d794 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -32,6 +32,7 @@ xdgautostartdir=$(sysconfdir)/xdg/autostart alsaprofilesetsdir=$(datadir)/pulseaudio/alsa-mixer/profile-sets alsapathsdir=$(datadir)/pulseaudio/alsa-mixer/paths udevrulesdir=/lib/udev/rules.d +dbuspolicydir=$(sysconfdir)/dbus-1/system.d ################################### # Defines # @@ -119,6 +120,7 @@ EXTRA_DIST = \ modules/module-defs.h.m4 \ daemon/pulseaudio.desktop.in \ map-file \ + daemon/pulseaudio-system.conf \ modules/alsa/mixer/profile-sets/default.conf \ modules/alsa/mixer/profile-sets/native-instruments-audio4dj.conf \ modules/alsa/mixer/profile-sets/native-instruments-audio8dj.conf \ @@ -145,6 +147,9 @@ pulseconf_DATA = \ daemon.conf \ client.conf +dbuspolicy_DATA = \ + daemon/pulseaudio-system.conf + if HAVE_X11 xdgautostart_in_files = \ daemon/pulseaudio.desktop.in diff --git a/src/daemon/pulseaudio-system.conf b/src/daemon/pulseaudio-system.conf new file mode 100644 index 00000000..edddaf93 --- /dev/null +++ b/src/daemon/pulseaudio-system.conf @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + -- cgit From 8998cba6839a46f11daec411c83a1b35723c5117 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 20:14:31 +0200 Subject: conf: add pa_config_parse_not_bool() for parsing inverse boolean configuration options --- src/pulsecore/conf-parser.c | 24 ++++++++++++++++++++++++ src/pulsecore/conf-parser.h | 1 + 2 files changed, 25 insertions(+) (limited to 'src') diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index 2dc9a223..b4ab23cc 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -278,6 +278,30 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *sectio return 0; } +int pa_config_parse_not_bool( + const char *filename, unsigned line, + const char *section, + const char *lvalue, const char *rvalue, + void *data, void *userdata) { + + int k; + pa_bool_t *b = data; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if ((k = pa_parse_boolean(rvalue)) < 0) { + pa_log("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); + return -1; + } + + *b = !k; + + return 0; +} + int pa_config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { char **s = data; diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h index 08e17ca7..c6c8a148 100644 --- a/src/pulsecore/conf-parser.h +++ b/src/pulsecore/conf-parser.h @@ -47,6 +47,7 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *section int pa_config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_not_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); #endif -- 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/daemon/daemon-conf.c | 18 ++++++++++++------ src/daemon/daemon.conf.in | 12 ++++++------ src/pulse/client-conf.c | 21 +++++++++++---------- src/pulse/client.conf.in | 2 +- 4 files changed, 30 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 9010f2f6..9a87b555 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -441,11 +441,15 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "high-priority", pa_config_parse_bool, &c->high_priority, NULL }, { "realtime-scheduling", pa_config_parse_bool, &c->realtime_scheduling, NULL }, { "disallow-module-loading", pa_config_parse_bool, &c->disallow_module_loading, NULL }, + { "allow-module-loading", pa_config_parse_not_bool, &c->disallow_module_loading, NULL }, { "disallow-exit", pa_config_parse_bool, &c->disallow_exit, NULL }, + { "allow-exit", pa_config_parse_not_bool, &c->disallow_exit, NULL }, { "use-pid-file", pa_config_parse_bool, &c->use_pid_file, NULL }, { "system-instance", pa_config_parse_bool, &c->system_instance, NULL }, { "no-cpu-limit", pa_config_parse_bool, &c->no_cpu_limit, NULL }, + { "cpu-limit", pa_config_parse_not_bool, &c->no_cpu_limit, NULL }, { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, + { "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL }, { "flat-volumes", pa_config_parse_bool, &c->flat_volumes, NULL }, { "lock-memory", pa_config_parse_bool, &c->lock_memory, NULL }, { "exit-idle-time", pa_config_parse_int, &c->exit_idle_time, NULL }, @@ -465,7 +469,9 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "default-fragment-size-msec", parse_fragment_size_msec, c, NULL }, { "nice-level", parse_nice_level, c, NULL }, { "disable-remixing", pa_config_parse_bool, &c->disable_remixing, NULL }, + { "enable-remixing", pa_config_parse_not_bool, &c->disable_remixing, NULL }, { "disable-lfe-remixing", pa_config_parse_bool, &c->disable_lfe_remixing, NULL }, + { "enable-lfe-remixing", pa_config_parse_not_bool, &c->disable_lfe_remixing, NULL }, { "load-default-script-file", pa_config_parse_bool, &c->load_default_script_file, NULL }, { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, { "log-meta", pa_config_parse_bool, &c->log_meta, NULL }, @@ -623,12 +629,12 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "nice-level = %i\n", c->nice_level); pa_strbuf_printf(s, "realtime-scheduling = %s\n", pa_yes_no(c->realtime_scheduling)); pa_strbuf_printf(s, "realtime-priority = %i\n", c->realtime_priority); - pa_strbuf_printf(s, "disallow-module-loading = %s\n", pa_yes_no(c->disallow_module_loading)); - pa_strbuf_printf(s, "disallow-exit = %s\n", pa_yes_no(c->disallow_exit)); + pa_strbuf_printf(s, "allow-module-loading = %s\n", pa_yes_no(!c->disallow_module_loading)); + pa_strbuf_printf(s, "allow-exit = %s\n", pa_yes_no(!c->disallow_exit)); pa_strbuf_printf(s, "use-pid-file = %s\n", pa_yes_no(c->use_pid_file)); pa_strbuf_printf(s, "system-instance = %s\n", pa_yes_no(c->system_instance)); - pa_strbuf_printf(s, "no-cpu-limit = %s\n", pa_yes_no(c->no_cpu_limit)); - pa_strbuf_printf(s, "disable-shm = %s\n", pa_yes_no(c->disable_shm)); + pa_strbuf_printf(s, "cpu-limit = %s\n", pa_yes_no(!c->no_cpu_limit)); + pa_strbuf_printf(s, "enable-shm = %s\n", pa_yes_no(!c->disable_shm)); pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes)); pa_strbuf_printf(s, "lock-memory = %s\n", pa_yes_no(c->lock_memory)); pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); @@ -639,8 +645,8 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); - pa_strbuf_printf(s, "disable-remixing = %s\n", pa_yes_no(c->disable_remixing)); - pa_strbuf_printf(s, "disable-lfe-remixing = %s\n", pa_yes_no(c->disable_lfe_remixing)); + pa_strbuf_printf(s, "enable-remixing = %s\n", pa_yes_no(!c->disable_remixing)); + pa_strbuf_printf(s, "enable-lfe-remixing = %s\n", pa_yes_no(!c->disable_lfe_remixing)); pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format)); pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate); pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels); diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index 6931359c..d8b58d8a 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -21,14 +21,14 @@ ; daemonize = no ; fail = yes -; disallow-module-loading = no -; disallow-exit = no +; allow-module-loading = yes +; allow-exit = yes ; use-pid-file = yes ; system-instance = no -; disable-shm = no +; enable-shm = yes ; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB ; lock-memory = no -; no-cpu-limit = no +; cpu-limit = yes ; high-priority = yes ; nice-level = -11 @@ -51,8 +51,8 @@ ; log-backtrace = 0 ; resample-method = speex-float-3 -; disable-remixing = no -; disable-lfe-remixing = yes +; enable-remixing = yes +; enable-lfe-remixing = no ; flat-volumes = yes 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 9f53aa5546e7bf9246546c6dda5637d50679483c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:35:48 +0200 Subject: daemon: unconditionally clean up priviliges --- src/daemon/caps.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 294be494..69e58cc0 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -58,11 +58,8 @@ void pa_drop_root(void) { #ifdef HAVE_GETUID uid_t uid; + pa_log_debug(_("Cleaning up privileges.")); uid = getuid(); - if (uid == 0 || geteuid() != 0) - return; - - pa_log_info(_("Dropping root privileges.")); #if defined(HAVE_SETRESUID) pa_assert_se(setresuid(uid, uid, uid) >= 0); @@ -82,7 +79,7 @@ void pa_drop_root(void) { #endif #ifdef HAVE_SYS_CAPABILITY_H - { + if (uid != 0) { cap_t caps; pa_assert_se(caps = cap_init()); pa_assert_se(cap_clear(caps) == 0); -- cgit From ef176ecb62a8f04bd14ca37e7c2a40469f0bb8ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:36:52 +0200 Subject: core-util: move personality resetting into core-util --- src/daemon/main.c | 10 +--------- src/pulsecore/core-util.c | 13 +++++++++++++ src/pulsecore/core-util.h | 2 ++ 3 files changed, 16 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/daemon/main.c b/src/daemon/main.c index 7a951954..355b0d5c 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -65,10 +65,6 @@ #include #endif -#ifdef __linux__ -#include -#endif - #include #include #include @@ -446,11 +442,7 @@ int main(int argc, char *argv[]) { * context we have been started. Let's cleanup our execution * context as good as possible */ -#ifdef __linux__ - if (personality(PER_LINUX) < 0) - pa_log_warn("Uh, personality() failed: %s", pa_cstrerror(errno)); -#endif - + pa_reset_personality(); pa_drop_root(); pa_close_all(passed_fd, -1); pa_reset_sigs(-1); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index d4baf697..6494244e 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -101,6 +101,10 @@ #include "rtkit.h" #endif +#ifdef __linux__ +#include +#endif + #include #include #include @@ -2855,3 +2859,12 @@ size_t pa_pipe_buf(int fd) { return 4096; #endif } + +void pa_reset_personality(void) { + +#ifdef __linux__ + if (personality(PER_LINUX) < 0) + pa_log_warn("Uh, personality() failed: %s", pa_cstrerror(errno)); +#endif + +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 6de4b771..3d3aec71 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -241,4 +241,6 @@ char* pa_maybe_prefix_path(const char *path, const char *prefix); /* Returns size of the specified pipe or 4096 on failure */ size_t pa_pipe_buf(int fd); +void pa_reset_personality(void); + #endif -- cgit From 27b8cd783c2aedb23af8f88fc88632d5c4f387fd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:37:40 +0200 Subject: daemon: reset scheduling priority on startup, too --- src/daemon/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/daemon/main.c b/src/daemon/main.c index 355b0d5c..8521e720 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -447,6 +447,7 @@ int main(int argc, char *argv[]) { pa_close_all(passed_fd, -1); pa_reset_sigs(-1); pa_unblock_sigs(-1); + pa_reset_priority(); setlocale(LC_ALL, ""); pa_init_i18n(); -- 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') 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 286ab2f19370c7a0041897435614b2c6aadc8e70 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:40:38 +0200 Subject: memblock: rate limit 'Pool full' message --- src/pulsecore/memblock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 3bc10de5..441b397b 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -258,7 +258,8 @@ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * (size_t) idx)); if (!slot) { - pa_log_debug("Pool full"); + if (pa_log_ratelimit()) + pa_log_debug("Pool full"); pa_atomic_inc(&p->stat.n_pool_full); return NULL; } -- cgit From 5fcb8a3c0838a4ecdb00a0af09b6e1a358b114d0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:42:02 +0200 Subject: pacmd: port pacmd from select() to poll() so that we notice writer side hangups --- src/utils/pacmd.c | 60 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index ac60a0bc..e4d054b8 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -45,6 +45,13 @@ int main(int argc, char*argv[]) { + enum { + WATCH_STDIN, + WATCH_STDOUT, + WATCH_SOCKET, + N_WATCH + }; + pid_t pid ; int fd = -1; int ret = 1, i; @@ -53,6 +60,7 @@ int main(int argc, char*argv[]) { size_t ibuf_index, ibuf_length, obuf_index, obuf_length; char *cli; pa_bool_t ibuf_eof, obuf_eof, ibuf_closed, obuf_closed; + struct pollfd pollfd[N_WATCH]; setlocale(LC_ALL, ""); bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); @@ -120,38 +128,45 @@ int main(int argc, char*argv[]) { ibuf_eof = TRUE; } - for (;;) { - fd_set ifds, ofds; + pa_zero(pollfd); + pollfd[WATCH_STDIN].fd = STDIN_FILENO; + pollfd[WATCH_STDOUT].fd = STDOUT_FILENO; + pollfd[WATCH_SOCKET].fd = fd; + + for (;;) { if (ibuf_eof && obuf_eof && ibuf_length <= 0 && obuf_length <= 0) break; - FD_ZERO(&ifds); - FD_ZERO(&ofds); + pollfd[WATCH_STDIN].events = pollfd[WATCH_STDOUT].events = pollfd[WATCH_SOCKET].events = 0; if (obuf_length > 0) - FD_SET(1, &ofds); + pollfd[WATCH_STDOUT].events |= POLLOUT; else if (!obuf_eof) - FD_SET(fd, &ifds); + pollfd[WATCH_SOCKET].events |= POLLIN; if (ibuf_length > 0) - FD_SET(fd, &ofds); + pollfd[WATCH_SOCKET].events |= POLLOUT; else if (!ibuf_eof) - FD_SET(0, &ifds); + pollfd[WATCH_STDIN].events |= POLLIN; - if (select(FD_SETSIZE, &ifds, &ofds, NULL, NULL) < 0) { - pa_log(_("select(): %s"), strerror(errno)); + if (poll(pollfd, N_WATCH, -1) < 0) { + + if (errno == EINTR) + continue; + + pa_log(_("poll(): %s"), strerror(errno)); goto fail; } - if (FD_ISSET(0, &ifds)) { + if (pollfd[WATCH_STDIN].revents & POLLIN) { ssize_t r; pa_assert(!ibuf_length); - if ((r = pa_read(0, ibuf, sizeof(ibuf), NULL)) <= 0) { + if ((r = pa_read(STDIN_FILENO, ibuf, sizeof(ibuf), NULL)) <= 0) { if (r < 0) { pa_log(_("read(): %s"), strerror(errno)); goto fail; @@ -164,7 +179,7 @@ int main(int argc, char*argv[]) { } } - if (FD_ISSET(fd, &ifds)) { + if (pollfd[WATCH_SOCKET].revents & POLLIN) { ssize_t r; pa_assert(!obuf_length); @@ -181,21 +196,26 @@ int main(int argc, char*argv[]) { } } - if (FD_ISSET(1, &ofds)) { + if (pollfd[WATCH_STDOUT].revents & POLLHUP) { + obuf_eof = TRUE; + obuf_length = 0; + } else if (pollfd[WATCH_STDOUT].revents & POLLOUT) { ssize_t r; pa_assert(obuf_length); - if ((r = pa_write(1, obuf + obuf_index, obuf_length, NULL)) < 0) { + if ((r = pa_write(STDOUT_FILENO, obuf + obuf_index, obuf_length, NULL)) < 0) { pa_log(_("write(): %s"), strerror(errno)); goto fail; } obuf_length -= (size_t) r; obuf_index += obuf_index; - } - if (FD_ISSET(fd, &ofds)) { + if (pollfd[WATCH_SOCKET].revents & POLLHUP) { + ibuf_eof = TRUE; + ibuf_length = 0; + } if (pollfd[WATCH_SOCKET].revents & POLLOUT) { ssize_t r; pa_assert(ibuf_length); @@ -209,14 +229,14 @@ int main(int argc, char*argv[]) { } if (ibuf_length <= 0 && ibuf_eof && !ibuf_closed) { - pa_close(0); + pa_close(STDIN_FILENO); shutdown(fd, SHUT_WR); ibuf_closed = TRUE; } if (obuf_length <= 0 && obuf_eof && !obuf_closed) { shutdown(fd, SHUT_RD); - pa_close(1); + pa_close(STDOUT_FILENO); obuf_closed = TRUE; } } -- cgit From 17d57415f5abad5b7c30301227054b4c899bc705 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:43:06 +0200 Subject: start-child: clean up child environment a bit better --- src/pulsecore/start-child.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/pulsecore/start-child.c b/src/pulsecore/start-child.c index 7774bde6..b3bce131 100644 --- a/src/pulsecore/start-child.c +++ b/src/pulsecore/start-child.c @@ -68,23 +68,24 @@ int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) { } else { /* child */ - pa_reset_priority(); + pa_reset_personality(); pa_assert_se(pa_close(pipe_fds[0]) == 0); - pa_assert_se(dup2(pipe_fds[1], 1) == 1); + pa_assert_se(dup2(pipe_fds[1], STDOUT_FILENO) == STDOUT_FILENO); - if (pipe_fds[1] != 1) + if (pipe_fds[1] != STDOUT_FILENO) pa_assert_se(pa_close(pipe_fds[1]) == 0); - pa_close(0); - pa_assert_se(open("/dev/null", O_RDONLY) == 0); + pa_close(STDIN_FILENO); + pa_assert_se(open("/dev/null", O_RDONLY) == STDIN_FILENO); - pa_close(2); - pa_assert_se(open("/dev/null", O_WRONLY) == 2); + pa_close(STDERR_FILENO); + pa_assert_se(open("/dev/null", O_WRONLY) == STDERR_FILENO); pa_close_all(-1); pa_reset_sigs(-1); pa_unblock_sigs(-1); + pa_reset_priority(); #ifdef PR_SET_PDEATHSIG /* On Linux we can use PR_SET_PDEATHSIG to have the helper -- cgit From 9a95fe49c848d2711dcdcf4c407e626e41e4657f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Aug 2009 02:14:19 +0200 Subject: core: add assert macros for verifying calling context This adds pa_assert_io_context() and pa_assert_ctl_context() in addition to a few related macros. When called they will fail when the current execution context is not IO resp. not control context. (aka 'thread' context vs. 'main' context) --- src/pulsecore/sink-input.c | 52 ++++++++++++++++++++++--- src/pulsecore/sink-input.h | 3 ++ src/pulsecore/sink.c | 89 +++++++++++++++++++++++++++++++++++-------- src/pulsecore/sink.h | 7 ++++ src/pulsecore/source-output.c | 33 ++++++++++++++-- src/pulsecore/source-output.h | 3 ++ src/pulsecore/source.c | 66 ++++++++++++++++++++++++++++---- src/pulsecore/source.h | 4 ++ src/pulsecore/thread-mq.h | 8 ++++ 9 files changed, 234 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index a5f96351..c7837298 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -51,7 +51,7 @@ static void sink_input_free(pa_object *o); pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) { pa_assert(data); - memset(data, 0, sizeof(*data)); + pa_zero(*data); data->resample_method = PA_RESAMPLER_INVALID; data->proplist = pa_proplist_new(); @@ -142,6 +142,7 @@ int pa_sink_input_new( pa_assert(_i); pa_assert(core); pa_assert(data); + pa_assert_ctl_context(); if (data->client) pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); @@ -348,6 +349,7 @@ int pa_sink_input_new( /* Called from main context */ static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) { pa_assert(i); + pa_assert_ctl_context(); if (!i->sink) return; @@ -362,6 +364,7 @@ static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) { static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { pa_sink_input *ssync; pa_assert(i); + pa_assert_ctl_context(); if (state == PA_SINK_INPUT_DRAINED) state = PA_SINK_INPUT_RUNNING; @@ -400,7 +403,9 @@ static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) void pa_sink_input_unlink(pa_sink_input *i) { pa_bool_t linked; pa_source_output *o, *p = NULL; + pa_assert(i); + pa_assert_ctl_context(); /* See pa_sink_unlink() for a couple of comments how this function * works */ @@ -471,6 +476,7 @@ static void sink_input_free(pa_object *o) { pa_sink_input* i = PA_SINK_INPUT(o); pa_assert(i); + pa_assert_ctl_context(); pa_assert(pa_sink_input_refcnt(i) == 0); if (PA_SINK_INPUT_IS_LINKED(i->state)) @@ -502,7 +508,9 @@ static void sink_input_free(pa_object *o) { /* Called from main context */ void pa_sink_input_put(pa_sink_input *i) { pa_sink_input_state_t state; + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(i->state == PA_SINK_INPUT_INIT); @@ -538,6 +546,7 @@ void pa_sink_input_put(pa_sink_input *i) { /* Called from main context */ void pa_sink_input_kill(pa_sink_input*i) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); i->kill(i); @@ -548,6 +557,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) { pa_usec_t r[2] = { 0, 0 }; pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0); @@ -569,6 +579,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p size_t ilength; pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state)); pa_assert(pa_frame_aligned(slength, &i->sink->sample_spec)); pa_assert(chunk); @@ -706,8 +717,9 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p /* Called from thread context */ void pa_sink_input_drop(pa_sink_input *i, size_t nbytes /* in sink sample spec */) { - pa_sink_input_assert_ref(i); + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state)); pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec)); pa_assert(nbytes > 0); @@ -721,8 +733,9 @@ void pa_sink_input_drop(pa_sink_input *i, size_t nbytes /* in sink sample spec * void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sample spec */) { size_t lbq; pa_bool_t called = FALSE; - pa_sink_input_assert_ref(i); + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state)); pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec)); @@ -792,6 +805,7 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam /* Called from thread context */ void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */) { pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state)); pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec)); @@ -804,6 +818,7 @@ void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the /* Called from thread context */ void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */) { pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state)); pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec)); @@ -814,6 +829,7 @@ void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the /* Called from thread context */ pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) { pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY)) usec = i->sink->fixed_latency; @@ -830,6 +846,7 @@ pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa /* Called from main context */ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) { pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); @@ -858,6 +875,7 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) /* Called from main context */ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) { pa_usec_t usec = 0; @@ -876,6 +894,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo pa_cvolume v; pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(volume); pa_assert(pa_cvolume_valid(volume)); @@ -922,6 +941,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo /* Called from main context */ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) { @@ -939,6 +959,7 @@ pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) { unsigned c; pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(v); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); @@ -959,6 +980,7 @@ void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v) { pa_cvolume _v; pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(!v || pa_cvolume_compatible(v, &i->sample_spec)); @@ -985,8 +1007,8 @@ void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v) { /* Called from main context */ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) { - pa_assert(i); pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); if (!i->muted == !mute) @@ -1002,6 +1024,7 @@ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) { /* Called from main context */ pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); return i->muted; @@ -1010,6 +1033,7 @@ pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) { /* Called from main thread */ void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); if (p) pa_proplist_update(i->proplist, mode, p); @@ -1023,6 +1047,7 @@ void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_p /* Called from main context */ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING); @@ -1031,6 +1056,7 @@ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) { /* Called from main context */ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_return_val_if_fail(i->thread_info.resampler, -PA_ERR_BADSTATE); @@ -1049,13 +1075,14 @@ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { void pa_sink_input_set_name(pa_sink_input *i, const char *name) { const char *old; pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); if (!name && !pa_proplist_contains(i->proplist, PA_PROP_MEDIA_NAME)) return; old = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME); - if (old && name && !strcmp(old, name)) + if (old && name && pa_streq(old, name)) return; if (name) @@ -1072,6 +1099,7 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) { /* Called from main context */ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); return i->actual_resample_method; } @@ -1079,6 +1107,7 @@ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { /* Called from main context */ pa_bool_t pa_sink_input_may_move(pa_sink_input *i) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); if (i->flags & PA_SINK_INPUT_DONT_MOVE) @@ -1095,6 +1124,7 @@ pa_bool_t pa_sink_input_may_move(pa_sink_input *i) { /* Called from main context */ pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_sink_assert_ref(dest); @@ -1123,6 +1153,7 @@ int pa_sink_input_start_move(pa_sink_input *i) { int r; pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(i->sink); @@ -1177,6 +1208,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { pa_resampler *new_resampler; pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(!i->sink); pa_sink_assert_ref(dest); @@ -1271,6 +1303,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { int r; pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(i->sink); pa_sink_assert_ref(dest); @@ -1301,7 +1334,9 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { /* Called from IO thread context */ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state) { pa_bool_t corking, uncorking; + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); if (state == i->thread_info.state) return; @@ -1411,6 +1446,7 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t /* Called from main thread */ pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); if (i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED) return pa_atomic_load(&i->thread_info.drained) ? PA_SINK_INPUT_DRAINED : PA_SINK_INPUT_RUNNING; @@ -1421,6 +1457,7 @@ pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) { /* Called from IO context */ pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i) { pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); if (PA_SINK_INPUT_IS_LINKED(i->thread_info.state)) return pa_memblockq_is_empty(i->thread_info.render_memblockq); @@ -1445,6 +1482,7 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam * rewound. */ pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); nbytes = PA_MAX(i->thread_info.rewrite_nbytes, nbytes); @@ -1511,8 +1549,11 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam /* Called from main context */ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) { pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(ret); + /* FIXME: Shouldn't access resampler object from main context! */ + pa_silence_memchunk_get( &i->core->silence_cache, i->core->mempool, @@ -1529,6 +1570,7 @@ void pa_sink_input_send_event(pa_sink_input *i, const char *event, pa_proplist * pa_sink_input_send_event_hook_data hook_data; pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); pa_assert(event); if (!i->send_event) diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 98144d41..5ede1ca8 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -359,4 +359,7 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret); /* To be used by sink.c only */ void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v); +#define pa_sink_input_assert_io_context(s) \ + pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state)) + #endif diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 5e9662c2..edcf5bdd 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -59,7 +59,7 @@ static void sink_free(pa_object *s); pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) { pa_assert(data); - memset(data, 0, sizeof(*data)); + pa_zero(*data); data->proplist = pa_proplist_new(); return data; @@ -177,6 +177,7 @@ pa_sink* pa_sink_new( pa_assert(core); pa_assert(data); pa_assert(data->name); + pa_assert_ctl_context(); s = pa_msgobject_new(pa_sink); @@ -360,6 +361,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { pa_sink_state_t original_state; pa_assert(s); + pa_assert_ctl_context(); if (s->state == state) return 0; @@ -413,6 +415,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { /* Called from main context */ void pa_sink_put(pa_sink* s) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(s->state == PA_SINK_INIT); @@ -458,6 +461,7 @@ void pa_sink_unlink(pa_sink* s) { pa_sink_input *i, *j = NULL; pa_assert(s); + pa_assert_ctl_context(); /* Please note that pa_sink_unlink() does more than simply * reversing pa_sink_put(). It also undoes the registrations @@ -507,6 +511,7 @@ static void sink_free(pa_object *o) { pa_sink_input *i; pa_assert(s); + pa_assert_ctl_context(); pa_assert(pa_sink_refcnt(s) == 0); if (PA_SINK_IS_LINKED(s->state)) @@ -550,6 +555,7 @@ static void sink_free(pa_object *o) { /* Called from main context */ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); s->asyncmsgq = q; @@ -560,6 +566,7 @@ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { /* Called from main context */ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); s->rtpoll = p; @@ -570,6 +577,7 @@ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) { /* Called from main context */ int pa_sink_update_status(pa_sink*s) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); if (s->state == PA_SINK_SUSPENDED) @@ -581,6 +589,7 @@ int pa_sink_update_status(pa_sink*s) { /* Called from main context */ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(cause != 0); @@ -609,6 +618,7 @@ pa_queue *pa_sink_move_all_start(pa_sink *s, pa_queue *q) { uint32_t idx; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); if (!q) @@ -633,6 +643,7 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) { pa_sink_input *i; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(q); @@ -649,6 +660,8 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) { /* Called from main context */ void pa_sink_move_all_fail(pa_queue *q) { pa_sink_input *i; + + pa_assert_ctl_context(); pa_assert(q); while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) { @@ -667,6 +680,7 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) { void *state = NULL; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); /* If nobody requested this and this is actually no real rewind @@ -703,6 +717,7 @@ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, uns size_t mixlength = *length; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(info); while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) { @@ -742,6 +757,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk * unsigned n_unreffed = 0; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(result); pa_assert(result->memblock); pa_assert(result->length > 0); @@ -837,6 +853,7 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { size_t block_size_max; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); pa_assert(pa_frame_aligned(length, &s->sample_spec)); pa_assert(result); @@ -923,6 +940,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { size_t length, block_size_max; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); pa_assert(target); pa_assert(target->memblock); @@ -1006,6 +1024,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { size_t l, d; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); pa_assert(target); pa_assert(target->memblock); @@ -1040,6 +1059,7 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { unsigned n; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); pa_assert(length > 0); pa_assert(pa_frame_aligned(length, &s->sample_spec)); @@ -1131,6 +1151,7 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) { pa_usec_t usec = 0; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); /* The returned value is supposed to be in the time domain of the sound card! */ @@ -1152,6 +1173,7 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) { pa_msgobject *o; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); /* The returned value is supposed to be in the time domain of the sound card! */ @@ -1218,6 +1240,7 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) { uint32_t idx; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(new_volume); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(s->flags & PA_SINK_FLAT_VOLUME); @@ -1274,6 +1297,7 @@ void pa_sink_propagate_flat_volume(pa_sink *s) { uint32_t idx; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(s->flags & PA_SINK_FLAT_VOLUME); @@ -1322,6 +1346,7 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat pa_bool_t virtual_volume_changed; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(volume); pa_assert(pa_cvolume_valid(volume)); @@ -1363,6 +1388,7 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat /* Called from main thread. Only to be called by sink implementor */ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(volume); s->soft_volume = *volume; @@ -1376,6 +1402,8 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) { /* Called from main thread */ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_bool_t reference) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); + pa_assert(PA_SINK_IS_LINKED(s->state)); if (s->refresh_volume || force_refresh) { struct pa_cvolume old_virtual_volume = s->virtual_volume; @@ -1408,6 +1436,8 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_boo /* Called from main thread */ void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); + pa_assert(PA_SINK_IS_LINKED(s->state)); /* The sink implementor may call this if the volume changed to make sure everyone is notified */ if (pa_cvolume_equal(&s->virtual_volume, new_volume)) @@ -1427,6 +1457,7 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute, pa_bool_t save) { pa_bool_t old_muted; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); old_muted = s->muted; @@ -1446,6 +1477,8 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute, pa_bool_t save) { pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); + pa_assert(PA_SINK_IS_LINKED(s->state)); if (s->refresh_muted || force_refresh) { pa_bool_t old_muted = s->muted; @@ -1472,6 +1505,8 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) { /* Called from main thread */ void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); + pa_assert(PA_SINK_IS_LINKED(s->state)); /* The sink implementor may call this if the volume changed to make sure everyone is notified */ @@ -1487,6 +1522,7 @@ void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) { /* Called from main thread */ pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); if (p) pa_proplist_update(s->proplist, mode, p); @@ -1500,16 +1536,18 @@ pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist } /* Called from main thread */ +/* FIXME -- this should be dropped and be merged into pa_sink_update_proplist() */ void pa_sink_set_description(pa_sink *s, const char *description) { const char *old; pa_sink_assert_ref(s); + pa_assert_ctl_context(); if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION)) return; old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION); - if (old && description && !strcmp(old, description)) + if (old && description && pa_streq(old, description)) return; if (description) @@ -1536,6 +1574,7 @@ unsigned pa_sink_linked_by(pa_sink *s) { unsigned ret; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); ret = pa_idxset_size(s->inputs); @@ -1554,6 +1593,7 @@ unsigned pa_sink_used_by(pa_sink *s) { unsigned ret; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); ret = pa_idxset_size(s->inputs); @@ -1572,6 +1612,7 @@ unsigned pa_sink_check_suspend(pa_sink *s) { uint32_t idx; pa_sink_assert_ref(s); + pa_assert_ctl_context(); if (!PA_SINK_IS_LINKED(s->state)) return 0; @@ -1605,8 +1646,9 @@ static void sync_input_volumes_within_thread(pa_sink *s) { void *state = NULL; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); - while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) { + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) { if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume)) continue; @@ -1942,9 +1984,10 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) int ret = 0; pa_core_assert_ref(c); + pa_assert_ctl_context(); pa_assert(cause != 0); - for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) { + PA_IDXSET_FOREACH(sink, c->sinks, idx) { int r; if ((r = pa_sink_suspend(sink, suspend, cause)) < 0) @@ -1957,6 +2000,7 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) /* Called from main thread */ void pa_sink_detach(pa_sink *s) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0); @@ -1965,6 +2009,7 @@ void pa_sink_detach(pa_sink *s) { /* Called from main thread */ void pa_sink_attach(pa_sink *s) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0); @@ -1976,9 +2021,10 @@ void pa_sink_detach_within_thread(pa_sink *s) { void *state = NULL; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) if (i->detach) i->detach(i); @@ -1992,9 +2038,10 @@ void pa_sink_attach_within_thread(pa_sink *s) { void *state = NULL; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) if (i->attach) i->attach(i); @@ -2005,6 +2052,7 @@ void pa_sink_attach_within_thread(pa_sink *s) { /* Called from IO thread */ void pa_sink_request_rewind(pa_sink*s, size_t nbytes) { pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); if (s->thread_info.state == PA_SINK_SUSPENDED) @@ -2034,6 +2082,7 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) { pa_usec_t monitor_latency; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); if (!(s->flags & PA_SINK_DYNAMIC_LATENCY)) return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency); @@ -2070,6 +2119,7 @@ pa_usec_t pa_sink_get_requested_latency(pa_sink *s) { pa_usec_t usec = 0; pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); if (s->state == PA_SINK_SUSPENDED) @@ -2085,16 +2135,16 @@ void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) { void *state = NULL; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); if (max_rewind == s->thread_info.max_rewind) return; s->thread_info.max_rewind = max_rewind; - if (PA_SINK_IS_LINKED(s->thread_info.state)) { - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + if (PA_SINK_IS_LINKED(s->thread_info.state)) + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind); - } if (s->monitor_source) pa_source_set_max_rewind_within_thread(s->monitor_source, s->thread_info.max_rewind); @@ -2103,6 +2153,7 @@ void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) { /* Called from main thread */ void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); if (PA_SINK_IS_LINKED(s->state)) pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0); @@ -2115,6 +2166,7 @@ void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) { void *state = NULL; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); if (max_request == s->thread_info.max_request) return; @@ -2124,7 +2176,7 @@ void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) { if (PA_SINK_IS_LINKED(s->thread_info.state)) { pa_sink_input *i; - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) pa_sink_input_update_max_request(i, s->thread_info.max_request); } } @@ -2132,6 +2184,7 @@ void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) { /* Called from main thread */ void pa_sink_set_max_request(pa_sink *s, size_t max_request) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); if (PA_SINK_IS_LINKED(s->state)) pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REQUEST, NULL, max_request, NULL) == 0); @@ -2145,6 +2198,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) { void *state = NULL; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); if (!(s->flags & PA_SINK_DYNAMIC_LATENCY)) return; @@ -2156,7 +2210,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) { if (s->update_requested_latency) s->update_requested_latency(s); - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) if (i->update_sink_requested_latency) i->update_sink_requested_latency(i); } @@ -2165,6 +2219,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) { /* Called from main thread */ void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); /* min_latency == 0: no limit * min_latency anything else: specified limit @@ -2199,6 +2254,7 @@ void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_ /* Called from main thread */ void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); pa_assert(min_latency); pa_assert(max_latency); @@ -2220,6 +2276,7 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, void *state = NULL; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY); pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY); @@ -2236,7 +2293,7 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, if (PA_SINK_IS_LINKED(s->thread_info.state)) { pa_sink_input *i; - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) if (i->update_sink_latency_range) i->update_sink_latency_range(i); } @@ -2249,7 +2306,7 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, /* Called from main thread, before the sink is put */ void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) { pa_sink_assert_ref(s); - + pa_assert_ctl_context(); pa_assert(pa_sink_get_state(s) == PA_SINK_INIT); if (latency < ABSOLUTE_MIN_LATENCY) @@ -2266,6 +2323,7 @@ void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) { size_t pa_sink_get_max_rewind(pa_sink *s) { size_t r; pa_sink_assert_ref(s); + pa_assert_ctl_context(); if (!PA_SINK_IS_LINKED(s->state)) return s->thread_info.max_rewind; @@ -2279,6 +2337,7 @@ size_t pa_sink_get_max_rewind(pa_sink *s) { size_t pa_sink_get_max_request(pa_sink *s) { size_t r; pa_sink_assert_ref(s); + pa_assert_ctl_context(); if (!PA_SINK_IS_LINKED(s->state)) return s->thread_info.max_request; @@ -2292,7 +2351,8 @@ size_t pa_sink_get_max_request(pa_sink *s) { int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) { pa_device_port *port; - pa_assert(s); + pa_sink_assert_ref(s); + pa_assert_ctl_context(); if (!s->set_port) { pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name); @@ -2323,7 +2383,6 @@ int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) { return 0; } -/* Called from main context */ pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) { const char *ff, *c, *t = NULL, *s = "", *profile, *bus; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 7a8cdaf1..13033960 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -42,6 +42,7 @@ typedef struct pa_device_port pa_device_port; #include #include #include +#include #define PA_MAX_INPUTS_PER_SINK 32 @@ -343,4 +344,10 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s); pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra); void pa_device_port_free(pa_device_port *p); +/* Verify that we called in IO context (aka 'thread context), or that + * the sink is not yet set up, i.e. the thread not set up yet. See + * pa_assert_io_context() in thread-mq.h for more information. */ +#define pa_sink_assert_io_context(s) \ + pa_assert(pa_thread_mq_get() || !PA_SINK_IS_LINKED((s)->state)) + #endif diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 4ba25ae4..fdc00e15 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -48,7 +48,7 @@ static void source_output_free(pa_object* mo); pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) { pa_assert(data); - memset(data, 0, sizeof(*data)); + pa_zero(*data); data->resample_method = PA_RESAMPLER_INVALID; data->proplist = pa_proplist_new(); @@ -111,6 +111,7 @@ int pa_source_output_new( pa_assert(_o); pa_assert(core); pa_assert(data); + pa_assert_ctl_context(); if (data->client) pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); @@ -262,6 +263,7 @@ int pa_source_output_new( /* Called from main context */ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) { pa_assert(o); + pa_assert_ctl_context(); if (!o->source) return; @@ -275,6 +277,7 @@ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) /* Called from main context */ static void source_output_set_state(pa_source_output *o, pa_source_output_state_t state) { pa_assert(o); + pa_assert_ctl_context(); if (o->state == state) return; @@ -294,6 +297,7 @@ static void source_output_set_state(pa_source_output *o, pa_source_output_state_ void pa_source_output_unlink(pa_source_output*o) { pa_bool_t linked; pa_assert(o); + pa_assert_ctl_context(); /* See pa_sink_unlink() for a couple of comments how this function * works */ @@ -346,6 +350,7 @@ static void source_output_free(pa_object* mo) { pa_source_output *o = PA_SOURCE_OUTPUT(mo); pa_assert(o); + pa_assert_ctl_context(); pa_assert(pa_source_output_refcnt(o) == 0); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) @@ -371,7 +376,9 @@ static void source_output_free(pa_object* mo) { /* Called from main context */ void pa_source_output_put(pa_source_output *o) { pa_source_output_state_t state; + pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(o->state == PA_SOURCE_OUTPUT_INIT); @@ -395,6 +402,7 @@ void pa_source_output_put(pa_source_output *o) { /* Called from main context */ void pa_source_output_kill(pa_source_output*o) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); o->kill(o); @@ -405,6 +413,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o, pa_usec_t *source_la pa_usec_t r[2] = { 0, 0 }; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0); @@ -424,6 +433,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { size_t limit, mbs = 0; pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state)); pa_assert(chunk); pa_assert(pa_frame_aligned(chunk->length, &o->source->sample_spec)); @@ -499,8 +509,9 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { /* Called from thread context */ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in source sample spec */) { - pa_source_output_assert_ref(o); + pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state)); pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec)); @@ -528,6 +539,7 @@ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in so /* Called from thread context */ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* in the source's sample spec */) { pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state)); pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec)); @@ -538,6 +550,7 @@ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* i /* Called from thread context */ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) { pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY)) usec = o->source->fixed_latency; @@ -554,6 +567,7 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output /* Called from main context */ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) { pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); @@ -582,6 +596,7 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t /* Called from main context */ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) { pa_usec_t usec = 0; @@ -598,6 +613,7 @@ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) { /* Called from main context */ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING); @@ -606,6 +622,7 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { /* Called from main context */ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_return_val_if_fail(o->thread_info.resampler, -PA_ERR_BADSTATE); @@ -623,6 +640,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) { /* Called from main context */ void pa_source_output_set_name(pa_source_output *o, const char *name) { const char *old; + pa_assert_ctl_context(); pa_source_output_assert_ref(o); if (!name && !pa_proplist_contains(o->proplist, PA_PROP_MEDIA_NAME)) @@ -647,11 +665,12 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { /* Called from main thread */ void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); if (p) pa_proplist_update(o->proplist, mode, p); - if (PA_SINK_IS_LINKED(o->state)) { + if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) { pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o); pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); } @@ -660,6 +679,7 @@ void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode /* Called from main context */ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); return o->actual_resample_method; } @@ -667,6 +687,7 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { /* Called from main context */ pa_bool_t pa_source_output_may_move(pa_source_output *o) { pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE) @@ -708,6 +729,7 @@ int pa_source_output_start_move(pa_source_output *o) { int r; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert(o->source); @@ -739,6 +761,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t pa_resampler *new_resampler; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert(!o->source); pa_source_assert_ref(dest); @@ -820,6 +843,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav int r; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert(o->source); pa_source_assert_ref(dest); @@ -850,6 +874,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav /* Called from IO thread context */ void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_output_state_t state) { pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); if (state == o->thread_info.state) return; @@ -906,11 +931,13 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int return -PA_ERR_NOTIMPLEMENTED; } +/* Called from main context */ void pa_source_output_send_event(pa_source_output *o, const char *event, pa_proplist *data) { pa_proplist *pl = NULL; pa_source_output_send_event_hook_data hook_data; pa_source_output_assert_ref(o); + pa_assert_ctl_context(); pa_assert(event); if (!o->send_event) diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 9824e160..7b32c866 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -277,4 +277,7 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec); +#define pa_source_output_assert_io_context(s) \ + pa_assert(pa_thread_mq_get() || !PA_SOURCE_OUTPUT_IS_LINKED((s)->state)) + #endif diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index b8af148f..97a20b91 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -52,7 +53,7 @@ static void source_free(pa_object *o); pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data) { pa_assert(data); - memset(data, 0, sizeof(*data)); + pa_zero(*data); data->proplist = pa_proplist_new(); return data; @@ -145,6 +146,7 @@ pa_source* pa_source_new( pa_assert(core); pa_assert(data); pa_assert(data->name); + pa_assert_ctl_context(); s = pa_msgobject_new(pa_source); @@ -297,6 +299,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { pa_source_state_t original_state; pa_assert(s); + pa_assert_ctl_context(); if (s->state == state) return 0; @@ -348,6 +351,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { /* Called from main context */ void pa_source_put(pa_source *s) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(s->state == PA_SOURCE_INIT); @@ -382,6 +386,7 @@ void pa_source_unlink(pa_source *s) { pa_source_output *o, *j = NULL; pa_assert(s); + pa_assert_ctl_context(); /* See pa_sink_unlink() for a couple of comments how this function * works. */ @@ -423,6 +428,7 @@ static void source_free(pa_object *o) { pa_source *s = PA_SOURCE(o); pa_assert(s); + pa_assert_ctl_context(); pa_assert(pa_source_refcnt(s) == 0); if (PA_SOURCE_IS_LINKED(s->state)) @@ -460,6 +466,7 @@ static void source_free(pa_object *o) { /* Called from main context */ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { + pa_assert_ctl_context(); pa_source_assert_ref(s); s->asyncmsgq = q; @@ -467,6 +474,7 @@ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { /* Called from main context */ void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) { + pa_assert_ctl_context(); pa_source_assert_ref(s); s->rtpoll = p; @@ -475,6 +483,7 @@ void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) { /* Called from main context */ int pa_source_update_status(pa_source*s) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); if (s->state == PA_SOURCE_SUSPENDED) @@ -486,6 +495,7 @@ int pa_source_update_status(pa_source*s) { /* Called from main context */ int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); pa_assert(cause != 0); @@ -513,6 +523,7 @@ int pa_source_sync_suspend(pa_source *s) { pa_sink_state_t state; pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); pa_assert(s->monitor_of); @@ -532,6 +543,7 @@ pa_queue *pa_source_move_all_start(pa_source *s, pa_queue *q) { uint32_t idx; pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); if (!q) @@ -556,6 +568,7 @@ void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) { pa_source_output *o; pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); pa_assert(q); @@ -572,6 +585,8 @@ void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) { /* Called from main context */ void pa_source_move_all_fail(pa_queue *q) { pa_source_output *o; + + pa_assert_ctl_context(); pa_assert(q); while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) { @@ -590,6 +605,7 @@ void pa_source_process_rewind(pa_source *s, size_t nbytes) { void *state = NULL; pa_source_assert_ref(s); + pa_source_assert_io_context(s); pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); if (nbytes <= 0) @@ -612,6 +628,7 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { void *state = NULL; pa_source_assert_ref(s); + pa_source_assert_io_context(s); pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); pa_assert(chunk); @@ -651,6 +668,7 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { /* Called from IO thread context */ void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) { pa_source_assert_ref(s); + pa_source_assert_io_context(s); pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); pa_source_output_assert_ref(o); pa_assert(o->thread_info.direct_on_input); @@ -682,6 +700,7 @@ pa_usec_t pa_source_get_latency(pa_source *s) { pa_usec_t usec; pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); if (s->state == PA_SOURCE_SUSPENDED) @@ -701,6 +720,7 @@ pa_usec_t pa_source_get_latency_within_thread(pa_source *s) { pa_msgobject *o; pa_source_assert_ref(s); + pa_source_assert_io_context(s); pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); /* The returned value is supposed to be in the time domain of the sound card! */ @@ -727,6 +747,7 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save pa_bool_t virtual_volume_changed; pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); pa_assert(volume); pa_assert(pa_cvolume_valid(volume)); @@ -752,6 +773,7 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save /* Called from main thread. Only to be called by source implementor */ void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(volume); if (PA_SOURCE_IS_LINKED(s->state)) @@ -763,6 +785,7 @@ void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) { /* Called from main thread */ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); if (s->refresh_volume || force_refresh) { @@ -785,6 +808,8 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) { /* Called from main thread */ void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) { pa_source_assert_ref(s); + pa_assert_ctl_context(); + pa_assert(PA_SOURCE_IS_LINKED(s->state)); /* The source implementor may call this if the volume changed to make sure everyone is notified */ @@ -802,6 +827,7 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) { pa_bool_t old_muted; pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); old_muted = s->muted; @@ -820,6 +846,7 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) { /* Called from main thread */ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); if (s->refresh_muted || force_refresh) { @@ -846,6 +873,8 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) { /* Called from main thread */ void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) { pa_source_assert_ref(s); + pa_assert_ctl_context(); + pa_assert(PA_SOURCE_IS_LINKED(s->state)); /* The source implementor may call this if the mute state changed to make sure everyone is notified */ @@ -861,6 +890,7 @@ void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) { /* Called from main thread */ pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) { pa_source_assert_ref(s); + pa_assert_ctl_context(); if (p) pa_proplist_update(s->proplist, mode, p); @@ -874,16 +904,18 @@ pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_prop } /* Called from main thread */ +/* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */ void pa_source_set_description(pa_source *s, const char *description) { const char *old; pa_source_assert_ref(s); + pa_assert_ctl_context(); if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION)) return; old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION); - if (old && description && !strcmp(old, description)) + if (old && description && pa_streq(old, description)) return; if (description) @@ -901,6 +933,7 @@ void pa_source_set_description(pa_source *s, const char *description) { unsigned pa_source_linked_by(pa_source *s) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); + pa_assert_ctl_context(); return pa_idxset_size(s->outputs); } @@ -911,6 +944,7 @@ unsigned pa_source_used_by(pa_source *s) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); + pa_assert_ctl_context(); ret = pa_idxset_size(s->outputs); pa_assert(ret >= s->n_corked); @@ -925,6 +959,7 @@ unsigned pa_source_check_suspend(pa_source *s) { uint32_t idx; pa_source_assert_ref(s); + pa_assert_ctl_context(); if (!PA_SOURCE_IS_LINKED(s->state)) return 0; @@ -1120,6 +1155,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus int ret = 0; pa_core_assert_ref(c); + pa_assert_ctl_context(); pa_assert(cause != 0); for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) { @@ -1138,6 +1174,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus /* Called from main thread */ void pa_source_detach(pa_source *s) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0); @@ -1146,6 +1183,7 @@ void pa_source_detach(pa_source *s) { /* Called from main thread */ void pa_source_attach(pa_source *s) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0); @@ -1157,9 +1195,10 @@ void pa_source_detach_within_thread(pa_source *s) { void *state = NULL; pa_source_assert_ref(s); + pa_source_assert_io_context(s); pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); - while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state) if (o->detach) o->detach(o); } @@ -1170,9 +1209,10 @@ void pa_source_attach_within_thread(pa_source *s) { void *state = NULL; pa_source_assert_ref(s); + pa_source_assert_io_context(s); pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); - while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state) if (o->attach) o->attach(o); } @@ -1184,6 +1224,7 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) { void *state = NULL; pa_source_assert_ref(s); + pa_source_assert_io_context(s); if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY)) return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency); @@ -1214,6 +1255,7 @@ pa_usec_t pa_source_get_requested_latency(pa_source *s) { pa_usec_t usec = 0; pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); if (s->state == PA_SOURCE_SUSPENDED) @@ -1230,21 +1272,22 @@ void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) { void *state = NULL; pa_source_assert_ref(s); + pa_source_assert_io_context(s); if (max_rewind == s->thread_info.max_rewind) return; s->thread_info.max_rewind = max_rewind; - if (PA_SOURCE_IS_LINKED(s->thread_info.state)) { - while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + if (PA_SOURCE_IS_LINKED(s->thread_info.state)) + PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state) pa_source_output_update_max_rewind(o, s->thread_info.max_rewind); - } } /* Called from main thread */ void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) { pa_source_assert_ref(s); + pa_assert_ctl_context(); if (PA_SOURCE_IS_LINKED(s->state)) pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0); @@ -1258,6 +1301,7 @@ void pa_source_invalidate_requested_latency(pa_source *s) { void *state = NULL; pa_source_assert_ref(s); + pa_source_assert_io_context(s); if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY)) return; @@ -1281,6 +1325,7 @@ void pa_source_invalidate_requested_latency(pa_source *s) { /* Called from main thread */ void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) { pa_source_assert_ref(s); + pa_assert_ctl_context(); /* min_latency == 0: no limit * min_latency anything else: specified limit @@ -1315,6 +1360,7 @@ void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t /* Called from main thread */ void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(min_latency); pa_assert(max_latency); @@ -1336,6 +1382,7 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten void *state = NULL; pa_source_assert_ref(s); + pa_source_assert_io_context(s); pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY); pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY); @@ -1364,6 +1411,7 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten /* Called from main thread, before the source is put */ void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) { pa_source_assert_ref(s); + pa_assert_ctl_context(); pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT); @@ -1379,6 +1427,7 @@ void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) { /* Called from main thread */ size_t pa_source_get_max_rewind(pa_source *s) { size_t r; + pa_assert_ctl_context(); pa_source_assert_ref(s); if (!PA_SOURCE_IS_LINKED(s->state)) @@ -1394,9 +1443,10 @@ int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) { pa_device_port *port; pa_assert(s); + pa_assert_ctl_context(); if (!s->set_port) { - pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name); + pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s->index, s->name); return -PA_ERR_NOTIMPLEMENTED; } diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index d22e7ca5..001122bc 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -43,6 +43,7 @@ typedef struct pa_source pa_source; #include #include #include +#include #define PA_MAX_OUTPUTS_PER_SOURCE 32 @@ -295,4 +296,7 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten void pa_source_invalidate_requested_latency(pa_source *s); pa_usec_t pa_source_get_latency_within_thread(pa_source *s); +#define pa_source_assert_io_context(s) \ + pa_assert(pa_thread_mq_get() || !PA_SOURCE_IS_LINKED((s)->state)) + #endif diff --git a/src/pulsecore/thread-mq.h b/src/pulsecore/thread-mq.h index 3b5e0e78..96839d25 100644 --- a/src/pulsecore/thread-mq.h +++ b/src/pulsecore/thread-mq.h @@ -45,4 +45,12 @@ void pa_thread_mq_install(pa_thread_mq *q); /* Return the pa_thread_mq object that is set for the current thread */ pa_thread_mq *pa_thread_mq_get(void); +/* Verify that we are in control context (aka 'main context'). */ +#define pa_assert_ctl_context(s) \ + pa_assert(!pa_thread_mq_get()) + +/* Verify that we are in IO context (aka 'thread context'). */ +#define pa_assert_io_context(s) \ + pa_assert(pa_thread_mq_get()) + #endif -- cgit From 5ee4069e9e68f81a71d208bb720d0c6bc6112fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Aug 2009 02:17:24 +0200 Subject: core: add functions to query max_rewind/max_request values from streams --- src/pulsecore/sink-input.c | 19 +++++++++++++++++++ src/pulsecore/sink-input.h | 4 ++++ src/pulsecore/source-output.c | 8 ++++++++ src/pulsecore/source-output.h | 2 ++ 4 files changed, 33 insertions(+) (limited to 'src') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index c7837298..1f67d0fb 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -802,6 +802,25 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam i->thread_info.dont_rewind_render = FALSE; } +/* Called from thread context */ +size_t pa_sink_input_get_max_rewind(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); + + return i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, i->sink->thread_info.max_rewind) : i->sink->thread_info.max_rewind; +} + +/* Called from thread context */ +size_t pa_sink_input_get_max_request(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); + + /* We're not verifying the status here, to allow this to be called + * in the state change handler between _INIT and _RUNNING */ + + return i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, i->sink->thread_info.max_request) : i->sink->thread_info.max_request; +} + /* Called from thread context */ void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */) { pa_sink_input_assert_ref(i); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 5ede1ca8..cd424e87 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -303,6 +303,10 @@ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b); int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); +/* This returns the sink's fields converted into out sample type */ +size_t pa_sink_input_get_max_rewind(pa_sink_input *i); +size_t pa_sink_input_get_max_request(pa_sink_input *i); + /* Callable by everyone from main thread*/ /* External code may request disconnection with this function */ diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index fdc00e15..5d79dbbb 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -536,6 +536,14 @@ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in so pa_memblockq_rewind(o->thread_info.delay_memblockq, nbytes); } +/* Called from thread context */ +size_t pa_source_output_get_max_rewind(pa_source_output *o) { + pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); + + return o->thread_info.resampler ? pa_resampler_request(o->thread_info.resampler, o->source->thread_info.max_rewind) : o->source->thread_info.max_rewind; +} + /* Called from thread context */ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* in the source's sample spec */) { pa_source_output_assert_ref(o); diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 7b32c866..4bf88ca4 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -238,6 +238,8 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b); int pa_source_output_set_rate(pa_source_output *o, uint32_t rate); +size_t pa_source_output_get_max_rewind(pa_source_output *o); + /* Callable by everyone */ /* External code may request disconnection with this funcion */ -- cgit From aae7054b1c442e62cc1154d15a4b7a569d60d8f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:12:36 +0200 Subject: pacmd: handle multi word commands in argv[] properly --- src/utils/pacmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c index e4d054b8..5ef57e3b 100644 --- a/src/utils/pacmd.c +++ b/src/utils/pacmd.c @@ -116,7 +116,7 @@ int main(int argc, char*argv[]) { size_t k; k = PA_MIN(sizeof(ibuf) - ibuf_length, strlen(argv[i])); - memcpy(ibuf + ibuf_length, argv[1], k); + memcpy(ibuf + ibuf_length, argv[i], k); ibuf_length += k; if (ibuf_length < sizeof(ibuf)) { -- cgit From b0cabfe16b5e44ec44828ad342ae5a48dedcc6e6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:14:35 +0200 Subject: shm: bump shm size limit to 1GB --- src/pulsecore/shm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 6e428426..fbf777a4 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -60,7 +60,8 @@ #define MADV_REMOVE 9 #endif -#define MAX_SHM_SIZE (PA_ALIGN(1024*1024*64)) +/* 1 GiB at max */ +#define MAX_SHM_SIZE (PA_ALIGN(1024*1024*1024)) #ifdef __linux__ /* On Linux we know that the shared memory blocks are files in -- cgit From a42c597f0aef863ee38065c52fbe60d382f9d5e8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:16:28 +0200 Subject: memblockq: add pa_memblockq_get_maxrewind() API --- src/pulsecore/memblockq.c | 6 ++++++ src/pulsecore/memblockq.h | 3 +++ 2 files changed, 9 insertions(+) (limited to 'src') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 77f9efc9..32758be3 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -692,6 +692,12 @@ size_t pa_memblockq_get_minreq(pa_memblockq *bq) { return bq->minreq; } +size_t pa_memblockq_get_maxrewind(pa_memblockq *bq) { + pa_assert(bq); + + return bq->maxrewind; +} + int64_t pa_memblockq_get_read_index(pa_memblockq *bq) { pa_assert(bq); diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index 146d261b..587c364b 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -141,6 +141,9 @@ size_t pa_memblockq_get_prebuf(pa_memblockq *bq); /* Returns the minimal request value */ size_t pa_memblockq_get_minreq(pa_memblockq *bq); +/* Returns the maximal rewind value */ +size_t pa_memblockq_get_maxrewind(pa_memblockq *bq); + /* Return the base unit in bytes */ size_t pa_memblockq_get_base(pa_memblockq *bq); -- cgit From 446fb2c9fea4f9c3f268868547f5f11c287ecba0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:17:48 +0200 Subject: asyncmsgq: add pa_asyncmsgq_flush() call --- src/pulsecore/asyncmsgq.c | 36 ++++++++++++++++++++++++++++++++---- src/pulsecore/asyncmsgq.h | 2 ++ 2 files changed, 34 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c index 083d9de2..36721406 100644 --- a/src/pulsecore/asyncmsgq.c +++ b/src/pulsecore/asyncmsgq.c @@ -26,14 +26,16 @@ #include #include +#include + #include +#include #include #include #include #include #include #include -#include #include "asyncmsgq.h" @@ -76,7 +78,7 @@ static void asyncmsgq_free(pa_asyncmsgq *a) { struct asyncmsgq_item *i; pa_assert(a); - while ((i = pa_asyncq_pop(a->asyncq, 0))) { + while ((i = pa_asyncq_pop(a->asyncq, FALSE))) { pa_assert(!i->semaphore); @@ -246,7 +248,7 @@ int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) { pa_memchunk chunk; int ret; - if (pa_asyncmsgq_get(a, &o, &c, &data, &offset, &chunk, 1) < 0) + if (pa_asyncmsgq_get(a, &o, &c, &data, &offset, &chunk, TRUE) < 0) return -1; ret = pa_asyncmsgq_dispatch(o, c, data, offset, &chunk); @@ -269,7 +271,7 @@ int pa_asyncmsgq_process_one(pa_asyncmsgq *a) { pa_assert(PA_REFCNT_VALUE(a) > 0); - if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, 0) < 0) + if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, FALSE) < 0) return 0; pa_asyncmsgq_ref(a); @@ -323,3 +325,29 @@ int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, int64_ return 0; } + +void pa_asyncmsgq_flush(pa_asyncmsgq *a, pa_bool_t run) { + pa_assert(PA_REFCNT_VALUE(a) > 0); + + for (;;) { + pa_msgobject *object; + int code; + void *data; + int64_t offset; + pa_memchunk chunk; + int ret; + + if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, FALSE) < 0) + return; + + if (!run) { + pa_asyncmsgq_done(a, -1); + continue; + } + + pa_asyncmsgq_ref(a); + ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk); + pa_asyncmsgq_done(a, ret); + pa_asyncmsgq_unref(a); + } +} diff --git a/src/pulsecore/asyncmsgq.h b/src/pulsecore/asyncmsgq.h index 1f38207a..26f528f6 100644 --- a/src/pulsecore/asyncmsgq.h +++ b/src/pulsecore/asyncmsgq.h @@ -66,6 +66,8 @@ void pa_asyncmsgq_done(pa_asyncmsgq *q, int ret); int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code); int pa_asyncmsgq_process_one(pa_asyncmsgq *a); +void pa_asyncmsgq_flush(pa_asyncmsgq *a, pa_bool_t run); + /* For the reading side */ int pa_asyncmsgq_read_fd(pa_asyncmsgq *q); int pa_asyncmsgq_read_before_poll(pa_asyncmsgq *a); -- cgit From 9e21182e018db8755dea6368eed93a1a2b93f6f7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:18:23 +0200 Subject: thread-mq: never drop queued messages for the main loop Previously we might have dropped messages from IO trheads to the main thread. This tuend out to be problematic since this cause SHM release messages to be lost. More visibly however this could cause playback freezing when moving streams between sinks and removing the old sink right away. --- src/pulsecore/thread-mq.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c index 34f92a7e..ec67ae87 100644 --- a/src/pulsecore/thread-mq.c +++ b/src/pulsecore/thread-mq.c @@ -104,6 +104,13 @@ void pa_thread_mq_init(pa_thread_mq *q, pa_mainloop_api *mainloop, pa_rtpoll *rt void pa_thread_mq_done(pa_thread_mq *q) { pa_assert(q); + /* Since we are called from main context we can be sure that the + * inq is empty. However, the outq might still contain messages + * for the main loop, which we need to dispatch (e.g. release + * msgs, other stuff). Hence do so. */ + + pa_asyncmsgq_flush(q->outq, TRUE); + q->mainloop->io_free(q->read_event); q->mainloop->io_free(q->write_event); q->read_event = q->write_event = NULL; -- cgit From fecd0dc801b0f4c9a929fb7ef00f4bd7f0e3d06c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:21:09 +0200 Subject: resampler: round up when estimating input/output sizes --- src/pulsecore/resampler.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 17fb8480..59e0a0c1 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -347,13 +347,17 @@ void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) { size_t pa_resampler_request(pa_resampler *r, size_t out_length) { pa_assert(r); - return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; + /* Let's round up here */ + + return (((((out_length + r->o_fz-1) / r->o_fz) * r->i_ss.rate) + r->o_ss.rate-1) / r->o_ss.rate) * r->i_fz; } size_t pa_resampler_result(pa_resampler *r, size_t in_length) { pa_assert(r); - return (((in_length / r->i_fz)*r->o_ss.rate)/r->i_ss.rate) * r->o_fz; + /* Let's round up here */ + + return (((((in_length + r->i_fz-1) / r->i_fz) * r->o_ss.rate) + r->i_ss.rate-1) / r->i_ss.rate) * r->o_fz; } size_t pa_resampler_max_block_size(pa_resampler *r) { -- cgit From a1598c742e999cc96a9ccf743c2eb6af8c444c73 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 19:28:18 +0200 Subject: daemon: reset gids too, not just uids --- src/daemon/caps.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/daemon/caps.c b/src/daemon/caps.c index 69e58cc0..76b62e03 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -57,21 +57,29 @@ void pa_drop_root(void) { #ifdef HAVE_GETUID uid_t uid; + gid_t gid; pa_log_debug(_("Cleaning up privileges.")); uid = getuid(); + gid = getgid(); #if defined(HAVE_SETRESUID) pa_assert_se(setresuid(uid, uid, uid) >= 0); + pa_assert_se(setresgid(gid, gid, gid) >= 0); #elif defined(HAVE_SETREUID) pa_assert_se(setreuid(uid, uid) >= 0); + pa_assert_se(setregid(gid, gid) >= 0); #else pa_assert_se(setuid(uid) >= 0); pa_assert_se(seteuid(uid) >= 0); + pa_assert_se(setgid(gid) >= 0); + pa_assert_se(setegid(gid) >= 0); #endif pa_assert_se(getuid() == uid); pa_assert_se(geteuid() == uid); + pa_assert_se(getgid() == gid); + pa_assert_se(getegid() == gid); #endif #ifdef HAVE_SYS_PRCTL_H -- cgit From 72d2540e8dc47e101ac9d5ae24eee1b95e8dbcfa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 19:31:05 +0200 Subject: protocol-native: log explicitly each time a client triggers a volume change --- src/pulsecore/protocol-native.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 9a37c565..03372204 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -3323,6 +3323,7 @@ static void command_set_volume( pa_source *source = NULL; pa_sink_input *si = NULL; const char *name = NULL; + const char *client_name; pa_native_connection_assert_ref(c); pa_assert(t); @@ -3369,12 +3370,20 @@ static void command_set_volume( CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY); - if (sink) + client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); + + if (sink) { + pa_log("Client %s changes volume of sink %s.", client_name, sink->name); pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE, TRUE); - else if (source) + } else if (source) { + pa_log("Client %s changes volume of sink %s.", client_name, source->name); pa_source_set_volume(source, &volume, TRUE); - else if (si) + } else if (si) { + pa_log("Client %s changes volume of sink %s.", + client_name, + pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME))); pa_sink_input_set_volume(si, &volume, TRUE, TRUE); + } pa_pstream_send_simple_ack(c->pstream, tag); } -- 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 ++++- src/tests/voltest.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) (limited to 'src') 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) { diff --git a/src/tests/voltest.c b/src/tests/voltest.c index 2dcfa53c..64aec5c6 100644 --- a/src/tests/voltest.c +++ b/src/tests/voltest.c @@ -1,8 +1,33 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include +#include + int main(int argc, char *argv[]) { pa_volume_t v; pa_cvolume cv; @@ -60,5 +85,16 @@ int main(int argc, char *argv[]) { printf("After: volume: [%s]; balance: %2.1f (intended: %2.1f) %s\n", pa_cvolume_snprint(s, sizeof(s), &r), k, b, k < b-.05 || k > b+.5 ? "MISMATCH" : ""); } + for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 1) { + + double l = pa_sw_volume_to_linear(v); + pa_volume_t k = pa_sw_volume_from_linear(l); + double db = pa_sw_volume_to_dB(v); + pa_volume_t r = pa_sw_volume_from_dB(db); + + pa_assert(k == v); + pa_assert(r == v); + } + return 0; } -- cgit From 7891f964e4a1858ccae744ddff5d33b78f00b4d2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 23:55:32 +0200 Subject: module-stream-restore: don't fiddle with sinks/sources/streams that are not fully set up yet --- src/modules/module-stream-restore.c | 112 +++++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 8c0bb6b0..727a5275 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -102,15 +102,16 @@ struct userdata { pa_idxset *subscribed; }; -#define ENTRY_VERSION 2 +#define ENTRY_VERSION 3 struct entry { uint8_t version; - pa_bool_t muted_valid:1, volume_valid:1, device_valid:1; + pa_bool_t muted_valid:1, volume_valid:1, device_valid:1, card_valid:1; pa_bool_t muted:1; pa_channel_map channel_map; pa_cvolume volume; char device[PA_NAME_MAX]; + char card[PA_NAME_MAX]; } PA_GCC_PACKED; enum { @@ -196,11 +197,21 @@ static struct entry* read_entry(struct userdata *u, const char *name) { goto fail; } + if (!memchr(e->card, 0, sizeof(e->card))) { + pa_log_warn("Database contains entry for stream %s with missing NUL byte in card name", name); + goto fail; + } + if (e->device_valid && !pa_namereg_is_valid_name(e->device)) { pa_log_warn("Invalid device name stored in database for stream %s", name); goto fail; } + if (e->card_valid && !pa_namereg_is_valid_name(e->card)) { + pa_log_warn("Invalid card name stored in database for stream %s", name); + goto fail; + } + if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) { pa_log_warn("Invalid channel map stored in database for stream %s", name); goto fail; @@ -252,6 +263,10 @@ static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) { (a->device_valid && strncmp(a->device, b->device, sizeof(a->device)))) return FALSE; + if (a->card_valid != b->card_valid || + (a->card_valid && strncmp(a->card, b->card, sizeof(a->card)))) + return FALSE; + if (a->muted_valid != b->muted_valid || (a->muted_valid && (a->muted != b->muted))) return FALSE; @@ -308,6 +323,11 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (sink_input->save_sink) { pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device)); entry.device_valid = TRUE; + + if (sink_input->sink->card) { + pa_strlcpy(entry.card, sink_input->sink->card->name, sizeof(entry.card)); + entry.card_valid = TRUE; + } } } else { @@ -327,6 +347,11 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (source_output->save_source) { pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device)); entry.device_valid = source_output->save_source; + + if (source_output->source->card) { + pa_strlcpy(entry.card, source_output->source->card->name, sizeof(entry.card)); + entry.card_valid = TRUE; + } } } @@ -368,19 +393,28 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n if (!(name = get_name(new_data->proplist, "sink-input"))) return PA_HOOK_OK; - if ((e = read_entry(u, name))) { + if (new_data->sink) + pa_log_debug("Not restoring device for stream %s, because already set.", name); + else if ((e = read_entry(u, name))) { + pa_sink *s = NULL; - if (e->device_valid) { - pa_sink *s; + if (e->device_valid) + s = pa_namereg_get(c, e->device, PA_NAMEREG_SINK); - if ((s = pa_namereg_get(c, e->device, PA_NAMEREG_SINK))) { - if (!new_data->sink) { - pa_log_info("Restoring device for stream %s.", name); - new_data->sink = s; - new_data->save_sink = TRUE; - } else - pa_log_debug("Not restoring device for stream %s, because already set.", name); - } + if (!s && e->card_valid) { + pa_card *card; + + if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD))) + s = pa_idxset_first(card->sinks, NULL); + } + + /* It might happen that a stream and a sink are set up at the + same time, in which case we want to make sure we don't + interfere with that */ + if (s && PA_SINK_IS_LINKED(pa_sink_get_state(s))) { + pa_log_info("Restoring device for stream %s.", name); + new_data->sink = s; + new_data->save_sink = TRUE; } pa_xfree(e); @@ -455,18 +489,28 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou if (!(name = get_name(new_data->proplist, "source-output"))) return PA_HOOK_OK; - if ((e = read_entry(u, name))) { - pa_source *s; + if (new_data->source) + pa_log_debug("Not restoring device for stream %s, because already set", name); + else if ((e = read_entry(u, name))) { + pa_source *s = NULL; - if (e->device_valid) { - if ((s = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE))) { - if (!new_data->source) { - pa_log_info("Restoring device for stream %s.", name); - new_data->source = s; - new_data->save_source = TRUE; - } else - pa_log_debug("Not restoring device for stream %s, because already set", name); - } + if (e->device_valid) + s = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE); + + if (!s && e->card_valid) { + pa_card *card; + + if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD))) + s = pa_idxset_first(card->sources, NULL); + } + + /* It might happen that a stream and a sink are set up at the + same time, in which case we want to make sure we don't + interfere with that */ + if (s && PA_SOURCE_IS_LINKED(pa_source_get_state(s))) { + pa_log_info("Restoring device for stream %s.", name); + new_data->source = s; + new_data->save_source = TRUE; } pa_xfree(e); @@ -496,6 +540,12 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->save_sink) continue; + /* It might happen that a stream and a sink are set up at the + same time, in which case we want to make sure we don't + interfere with that */ + if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si))) + continue; + if (!(name = get_name(si->proplist, "sink-input"))) continue; @@ -534,6 +584,12 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, if (so->direct_on_input) continue; + /* It might happen that a stream and a sink are set up at the + same time, in which case we want to make sure we don't + interfere with that */ + if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so))) + continue; + if (!(name = get_name(so->proplist, "source-input"))) continue; @@ -575,7 +631,9 @@ static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, str if (e->device_valid) { pa_sink *d; - if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) && d != sink) + if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) && + d != sink && + PA_SINK_IS_LINKED(pa_sink_get_state(d))) pa_sink_input_move_to(si, d, TRUE); } @@ -613,7 +671,9 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc if (e->device_valid) { pa_source *d; - if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE)) && d != source) + if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE)) && + d != source && + PA_SOURCE_IS_LINKED(pa_source_get_state(d))) pa_source_output_move_to(so, d, TRUE); } -- cgit From 0989be13f6b5f71872f381fe2b5a7379702f20bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:03:50 +0200 Subject: core: introduce pa_{sink_input|source_output}_fail_move() --- src/pulsecore/sink-input.c | 19 +++++++++++++++++++ src/pulsecore/sink-input.h | 5 ++++- src/pulsecore/sink.c | 8 +++----- src/pulsecore/source-output.c | 19 +++++++++++++++++++ src/pulsecore/source-output.h | 5 ++++- src/pulsecore/source.c | 8 +++----- 6 files changed, 52 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 1f67d0fb..3a9915f0 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -1317,6 +1317,24 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { return 0; } +/* Called from main context */ +void pa_sink_input_fail_move(pa_sink_input *i) { + + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); + pa_assert(!i->sink); + + /* Check if someone wants this sink input? */ + if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_STOP) + return; + + if (i->moving) + i->moving(i, NULL); + + pa_sink_input_kill(i); +} + /* Called from main context */ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { int r; @@ -1341,6 +1359,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { } if ((r = pa_sink_input_finish_move(i, dest, save)) < 0) { + pa_sink_input_fail_move(i); pa_sink_input_unref(i); return r; } diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index cd424e87..9088d6a1 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -159,7 +159,9 @@ struct pa_sink_input { /* If non-NULL called whenever the sink input is moved to a new * sink. Called from main context after the sink input has been * detached from the old sink and before it has been attached to - * the new sink. */ + * the new sink. If dest is NULL the move was executed in two + * phases and the second one failed; the stream will be destroyed + * after this call. */ void (*moving) (pa_sink_input *i, pa_sink *dest); /* may be NULL */ /* Supposed to unlink and destroy this stream. Called from main @@ -337,6 +339,7 @@ pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest); /* may thi * new sink */ int pa_sink_input_start_move(pa_sink_input *i); int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save); +void pa_sink_input_fail_move(pa_sink_input *i); pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index edcf5bdd..65c6374b 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -649,7 +649,7 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) { while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) { if (pa_sink_input_finish_move(i, s, save) < 0) - pa_sink_input_kill(i); + pa_sink_input_fail_move(i); pa_sink_input_unref(i); } @@ -665,10 +665,8 @@ void pa_sink_move_all_fail(pa_queue *q) { pa_assert(q); while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) { - if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_OK) { - pa_sink_input_kill(i); - pa_sink_input_unref(i); - } + pa_sink_input_fail_move(i); + pa_sink_input_unref(i); } pa_queue_free(q, NULL, NULL); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 5d79dbbb..8cb361c9 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -846,6 +846,24 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t return 0; } +/* Called from main context */ +void pa_source_output_fail_move(pa_source_output *o) { + + pa_source_output_assert_ref(o); + pa_assert_ctl_context(); + pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); + pa_assert(!o->source); + + /* Check if someone wants this source output? */ + if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_STOP) + return; + + if (o->moving) + o->moving(o, NULL); + + pa_source_output_kill(o); +} + /* Called from main context */ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t save) { int r; @@ -870,6 +888,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav } if ((r = pa_source_output_finish_move(o, dest, save)) < 0) { + pa_source_output_fail_move(o); pa_source_output_unref(o); return r; } diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 4bf88ca4..6e3475a6 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -127,7 +127,9 @@ struct pa_source_output { /* If non-NULL called whenever the source output is moved to a new * source. Called from main context after the stream was detached * from the old source and before it is attached to the new - * source. */ + * source. If dest is NULL the move was executed in two + * phases and the second one failed; the stream will be destroyed + * after this call. */ void (*moving) (pa_source_output *o, pa_source *dest); /* may be NULL */ /* Supposed to unlink and destroy this stream. Called from main @@ -262,6 +264,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav * new source */ int pa_source_output_start_move(pa_source_output *o); int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t save); +void pa_source_output_fail_move(pa_source_output *o); #define pa_source_output_get_state(o) ((o)->state) diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 97a20b91..5731663b 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -574,7 +574,7 @@ void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) { while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) { if (pa_source_output_finish_move(o, s, save) < 0) - pa_source_output_kill(o); + pa_source_output_fail_move(o); pa_source_output_unref(o); } @@ -590,10 +590,8 @@ void pa_source_move_all_fail(pa_queue *q) { pa_assert(q); while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) { - if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) { - pa_source_output_kill(o); - pa_source_output_unref(o); - } + pa_source_output_fail_move(o); + pa_source_output_unref(o); } pa_queue_free(q, NULL, NULL); -- cgit From e53d2fc6b57f90d937f2680fa56461d4042de87a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:05:17 +0200 Subject: native: handle moving() callback with NULL destination properly --- src/pulsecore/protocol-native.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 03372204..a6124788 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -762,6 +762,7 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, return -1; switch (code) { + case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: { pa_tagstruct *t; int l = 0; @@ -1143,7 +1144,6 @@ static void playback_stream_request_bytes(playback_stream *s) { pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); } - /* Called from main context */ static void playback_stream_send_killed(playback_stream *p) { pa_tagstruct *t; @@ -1617,6 +1617,9 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { s = PLAYBACK_STREAM(i->userdata); playback_stream_assert_ref(s); + if (!dest) + return; + fix_playback_buffer_attr(s); pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr); pa_memblockq_get_attr(s->memblockq, &s->buffer_attr); @@ -1752,6 +1755,9 @@ static void source_output_moving_cb(pa_source_output *o, pa_source *dest) { s = RECORD_STREAM(o->userdata); record_stream_assert_ref(s); + if (!dest) + return; + fix_record_buffer_attr_pre(s); pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength); pa_memblockq_get_attr(s->memblockq, &s->buffer_attr); -- cgit From e4db56bf0763abaaa34796f5b0234b3cd2cf4d3c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:12:53 +0200 Subject: core: split of FAIL_ON_SUSPEND into KILL_ON_SUSPEND and NO_CREATE_ON_SUSPEND --- src/pulsecore/cli-text.c | 10 ++++++---- src/pulsecore/protocol-native.c | 4 ++-- src/pulsecore/sink-input.c | 2 +- src/pulsecore/sink-input.h | 3 ++- src/pulsecore/sink.c | 4 ++-- src/pulsecore/source-output.c | 2 +- src/pulsecore/source-output.h | 3 ++- src/pulsecore/source.c | 5 ++--- 8 files changed, 18 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index 9395513d..ace5e719 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -482,7 +482,7 @@ char *pa_source_output_list_to_string(pa_core *c) { s, " index: %u\n" "\tdriver: <%s>\n" - "\tflags: %s%s%s%s%s%s%s%s%s%s\n" + "\tflags: %s%s%s%s%s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsource: %u <%s>\n" "\tcurrent latency: %0.2f ms\n" @@ -501,7 +501,8 @@ char *pa_source_output_list_to_string(pa_core *c) { o->flags & PA_SOURCE_OUTPUT_FIX_RATE ? "FIX_RATE " : "", o->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "", o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "", - o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND ? "FAIL_ON_SUSPEND " : "", + o->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND ? "NO_CREATE_ON_SUSPEND " : "", + o->flags & PA_SOURCE_OUTPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "", state_table[pa_source_output_get_state(o)], o->source->index, o->source->name, (double) pa_source_output_get_latency(o, NULL) / PA_USEC_PER_MSEC, @@ -564,7 +565,7 @@ char *pa_sink_input_list_to_string(pa_core *c) { s, " index: %u\n" "\tdriver: <%s>\n" - "\tflags: %s%s%s%s%s%s%s%s%s%s\n" + "\tflags: %s%s%s%s%s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsink: %u <%s>\n" "\tvolume: %s\n" @@ -587,7 +588,8 @@ char *pa_sink_input_list_to_string(pa_core *c) { i->flags & PA_SINK_INPUT_FIX_RATE ? "FIX_RATE " : "", i->flags & PA_SINK_INPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "", i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "", - i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND ? "FAIL_ON_SUSPEND " : "", + i->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND ? "NO_CREATE_SUSPEND " : "", + i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "", state_table[pa_sink_input_get_state(i)], i->sink->index, i->sink->name, pa_cvolume_snprint(cv, sizeof(cv), &v), diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index a6124788..b6989aec 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1957,7 +1957,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) | (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) | (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) | - (fail_on_suspend ? PA_SINK_INPUT_FAIL_ON_SUSPEND : 0); + (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0); /* Only since protocol version 15 there's a seperate muted_set * flag. For older versions we synthesize it here */ @@ -2213,7 +2213,7 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) | (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) | (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) | - (fail_on_suspend ? PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND : 0); + (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0); s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret); pa_proplist_free(p); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 3a9915f0..1b3ea92d 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -221,7 +221,7 @@ int pa_sink_input_new( if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0) return r; - if ((flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) && + if ((flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND) && pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) { pa_log_warn("Failed to create sink input: sink is suspended."); return -PA_ERR_BADSTATE; diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 9088d6a1..c1f8082c 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -58,7 +58,8 @@ typedef enum pa_sink_input_flags { PA_SINK_INPUT_FIX_RATE = 64, PA_SINK_INPUT_FIX_CHANNELS = 128, PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256, - PA_SINK_INPUT_FAIL_ON_SUSPEND = 512 + PA_SINK_INPUT_NO_CREATE_ON_SUSPEND = 512, + PA_SINK_INPUT_KILL_ON_SUSPEND = 1024 } pa_sink_input_flags_t; struct pa_sink_input { diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 65c6374b..90c9d85d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -398,9 +398,9 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { /* We're suspending or resuming, tell everyone about it */ - for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) + PA_IDXSET_FOREACH(i, s->inputs, idx) if (s->state == PA_SINK_SUSPENDED && - (i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND)) + (i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND)) pa_sink_input_kill(i); else if (i->suspend) i->suspend(i, state == PA_SINK_SUSPENDED); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 8cb361c9..2b3a0c58 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -167,7 +167,7 @@ int pa_source_output_new( if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0) return r; - if ((flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND) && + if ((flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) && pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) { pa_log("Failed to create source output: source is suspended."); return -PA_ERR_BADSTATE; diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 6e3475a6..b78a02b9 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -55,7 +55,8 @@ typedef enum pa_source_output_flags { PA_SOURCE_OUTPUT_FIX_RATE = 64, PA_SOURCE_OUTPUT_FIX_CHANNELS = 128, PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND = 256, - PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND = 512 + PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND = 512, + PA_SOURCE_OUTPUT_KILL_ON_SUSPEND = 1024 } pa_source_output_flags_t; struct pa_source_output { diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 5731663b..a44275c0 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -336,15 +336,14 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { /* We're suspending or resuming, tell everyone about it */ - for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) + PA_IDXSET_FOREACH(o, s->outputs, idx) if (s->state == PA_SOURCE_SUSPENDED && - (o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND)) + (o->flags & PA_SOURCE_OUTPUT_KILL_ON_SUSPEND)) pa_source_output_kill(o); else if (o->suspend) o->suspend(o, state == PA_SOURCE_SUSPENDED); } - return 0; } -- cgit From fd1266c666f62f1c19bff6c1ab3397300e25ffed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:15:18 +0200 Subject: rescure-stream: handle failed moves as well as dying sinks/sources --- src/modules/module-rescue-streams.c | 173 ++++++++++++++++++++++++++++-------- 1 file changed, 136 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index c23feceb..82f693f9 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -45,13 +45,43 @@ static const char* const valid_modargs[] = { }; struct userdata { - pa_hook_slot *sink_slot, *source_slot; + pa_hook_slot + *sink_unlink_slot, + *source_unlink_slot, + *sink_input_move_fail_slot, + *source_output_move_fail_slot; }; -static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { +static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip) { + pa_sink *target, *def; + uint32_t idx; + + pa_assert(c); + pa_assert(i); + + def = pa_namereg_get_default_sink(c); + + if (def && def != skip && pa_sink_input_may_move_to(i, def)) + return def; + + PA_IDXSET_FOREACH(target, c->sinks, idx) { + if (target == def) + continue; + + if (target == skip) + continue; + + if (pa_sink_input_may_move_to(i, target)) + return target; + } + + pa_log_debug("No evacuation sink found."); + return NULL; +} + +static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { pa_sink_input *i; uint32_t idx; - pa_sink *target; pa_assert(c); pa_assert(sink); @@ -65,21 +95,12 @@ static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* user return PA_HOOK_OK; } - if (!(target = pa_namereg_get_default_sink(c)) || target == sink) { - - PA_IDXSET_FOREACH(target, c->sinks, idx) - if (target != sink) - break; - - if (!target) { - pa_log_debug("No evacuation sink found."); - return PA_HOOK_OK; - } - } + PA_IDXSET_FOREACH(i, sink->inputs, idx) { + pa_sink *target; - pa_assert(target != sink); + if (!(target = find_evacuation_sink(c, i, sink))) + continue; - PA_IDXSET_FOREACH(i, sink->inputs, idx) { if (pa_sink_input_move_to(i, target, FALSE) < 0) pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), target->name); @@ -91,9 +112,63 @@ static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* user return PA_HOOK_OK; } -static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void* userdata) { +static pa_hook_result_t sink_input_move_fail_hook_callback(pa_core *c, pa_sink_input *i, void *userdata) { + pa_sink *target; + + pa_assert(c); + pa_assert(i); + + /* There's no point in doing anything if the core is shut down anyway */ + if (c->state == PA_CORE_SHUTDOWN) + return PA_HOOK_OK; + + if (!(target = find_evacuation_sink(c, i, NULL))) + return PA_HOOK_OK; + + if (pa_sink_input_finish_move(i, target, FALSE) < 0) { + pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), target->name); + return PA_HOOK_OK; + + } else { + pa_log_info("Sucessfully moved sink input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), target->name); + return PA_HOOK_STOP; + } +} + +static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_source *skip) { + pa_source *target, *def; + uint32_t idx; + + pa_assert(c); + pa_assert(o); + + def = pa_namereg_get_default_source(c); + + if (def && def != skip && pa_source_output_may_move_to(o, def)) + return def; + + PA_IDXSET_FOREACH(target, c->sources, idx) { + if (target == def) + continue; + + if (target == skip) + continue; + + if (!target->monitor_of != !skip->monitor_of) + continue; + + if (pa_source_output_may_move_to(o, target)) + return target; + } + + pa_log_debug("No evacuation source found."); + return NULL; +} + +static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, void* userdata) { pa_source_output *o; - pa_source *target; uint32_t idx; pa_assert(c); @@ -108,21 +183,12 @@ static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void return PA_HOOK_OK; } - if (!(target = pa_namereg_get_default_source(c)) || target == source) { - - PA_IDXSET_FOREACH(target, c->sources, idx) - if (target != source && !target->monitor_of == !source->monitor_of) - break; - - if (!target) { - pa_log_info("No evacuation source found."); - return PA_HOOK_OK; - } - } + PA_IDXSET_FOREACH(o, source->outputs, idx) { + pa_source *target; - pa_assert(target != source); + if (!(target = find_evacuation_source(c, o, source))) + continue; - PA_IDXSET_FOREACH(o, source->outputs, idx) { if (pa_source_output_move_to(o, target, FALSE) < 0) pa_log_info("Failed to move source output %u \"%s\" to %s.", o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), target->name); @@ -134,6 +200,31 @@ static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void return PA_HOOK_OK; } +static pa_hook_result_t source_output_move_fail_hook_callback(pa_core *c, pa_source_output *i, void *userdata) { + pa_source *target; + + pa_assert(c); + pa_assert(i); + + /* There's no point in doing anything if the core is shut down anyway */ + if (c->state == PA_CORE_SHUTDOWN) + return PA_HOOK_OK; + + if (!(target = find_evacuation_source(c, i, NULL))) + return PA_HOOK_OK; + + if (pa_source_output_finish_move(i, target, FALSE) < 0) { + pa_log_info("Failed to move source input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), target->name); + return PA_HOOK_OK; + + } else { + pa_log_info("Sucessfully moved source input %u \"%s\" to %s.", i->index, + pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), target->name); + return PA_HOOK_STOP; + } +} + int pa__init(pa_module*m) { pa_modargs *ma; struct userdata *u; @@ -148,8 +239,11 @@ int pa__init(pa_module*m) { m->userdata = u = pa_xnew(struct userdata, 1); /* A little bit later than module-stream-restore, module-intended-roles... */ - u->sink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE+20, (pa_hook_cb_t) sink_hook_callback, u); - u->source_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+20, (pa_hook_cb_t) source_hook_callback, u); + u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE+20, (pa_hook_cb_t) sink_unlink_hook_callback, u); + u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+20, (pa_hook_cb_t) source_unlink_hook_callback, u); + + u->sink_input_move_fail_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], PA_HOOK_LATE+20, (pa_hook_cb_t) sink_input_move_fail_hook_callback, u); + u->source_output_move_fail_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], PA_HOOK_LATE+20, (pa_hook_cb_t) source_output_move_fail_hook_callback, u); pa_modargs_free(ma); return 0; @@ -163,10 +257,15 @@ void pa__done(pa_module*m) { if (!(u = m->userdata)) return; - if (u->sink_slot) - pa_hook_slot_free(u->sink_slot); - if (u->source_slot) - pa_hook_slot_free(u->source_slot); + if (u->sink_unlink_slot) + pa_hook_slot_free(u->sink_unlink_slot); + if (u->source_unlink_slot) + pa_hook_slot_free(u->source_unlink_slot); + + if (u->sink_input_move_fail_slot) + pa_hook_slot_free(u->sink_input_move_fail_slot); + if (u->source_output_move_fail_slot) + pa_hook_slot_free(u->source_output_move_fail_slot); pa_xfree(u); } -- cgit From 58d441f7ea7994d5a0e8bc5397e2986707eb466b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:16:25 +0200 Subject: log: place more rate limit invocations --- src/modules/alsa/alsa-sink.c | 3 ++- src/pulsecore/protocol-native.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 1c38430f..a91b4b8a 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1292,7 +1292,8 @@ static void thread_func(void *userdata) { * we have filled the buffer at least once * completely.*/ - pa_log_debug("Cutting sleep time for the initial iterations by half."); + if (pa_log_ratelimit()) + pa_log_debug("Cutting sleep time for the initial iterations by half."); sleep_usec /= 2; } diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index b6989aec..b578746e 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1345,7 +1345,9 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */ if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { - pa_log_warn("Failed to push data into queue"); + + if (pa_log_ratelimit()) + pa_log_warn("Failed to push data into queue"); pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL); pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE); } -- cgit From 4eb59fb90e474a81f2d626bc4fc7db083fafed7a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:26:00 +0200 Subject: core: move rtpoll to thread_info sub structure --- src/modules/module-combine.c | 4 ++-- src/modules/rtp/module-rtp-recv.c | 2 +- src/pulsecore/sink.c | 11 +++++------ src/pulsecore/sink.h | 3 ++- src/pulsecore/source.c | 9 ++++----- src/pulsecore/source.h | 3 ++- 6 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 16de6890..92716552 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -455,12 +455,12 @@ static void sink_input_attach_cb(pa_sink_input *i) { pa_assert(!o->inq_rtpoll_item_read && !o->outq_rtpoll_item_write); o->inq_rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read( - i->sink->rtpoll, + i->sink->thread_info.rtpoll, PA_RTPOLL_LATE, /* This one is not that important, since we check for data in _peek() anyway. */ o->inq); o->outq_rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write( - i->sink->rtpoll, + i->sink->thread_info.rtpoll, PA_RTPOLL_EARLY, o->outq); } diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 5caf8272..c195c045 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -361,7 +361,7 @@ static void sink_input_attach(pa_sink_input *i) { pa_assert_se(s = i->userdata); pa_assert(!s->rtpoll_item); - s->rtpoll_item = pa_rtpoll_item_new(i->sink->rtpoll, PA_RTPOLL_LATE, 1); + s->rtpoll_item = pa_rtpoll_item_new(i->sink->thread_info.rtpoll, PA_RTPOLL_LATE, 1); p = pa_rtpoll_item_get_pollfd(s->rtpoll_item, NULL); p->fd = s->rtp_context.fd; diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 90c9d85d..1f9a9797 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -262,7 +262,6 @@ pa_sink* pa_sink_new( s->userdata = NULL; s->asyncmsgq = NULL; - s->rtpoll = NULL; /* As a minor optimization we just steal the list instead of * copying it here */ @@ -295,6 +294,7 @@ pa_sink* pa_sink_new( &s->sample_spec, 0); + s->thread_info.rtpoll = NULL; s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); s->thread_info.soft_volume = s->soft_volume; s->thread_info.soft_muted = s->muted; @@ -421,7 +421,6 @@ void pa_sink_put(pa_sink* s) { /* The following fields must be initialized properly when calling _put() */ pa_assert(s->asyncmsgq); - pa_assert(s->rtpoll); pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency); /* Generally, flags should be initialized via pa_sink_new(). As a @@ -563,12 +562,12 @@ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { pa_source_set_asyncmsgq(s->monitor_source, q); } -/* Called from main context */ +/* Called from IO context, or before _put() from main context */ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) { pa_sink_assert_ref(s); - pa_assert_ctl_context(); + pa_sink_assert_io_context(s); - s->rtpoll = p; + s->thread_info.rtpoll = p; if (s->monitor_source) pa_source_set_rtpoll(s->monitor_source, p); @@ -1184,7 +1183,7 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) { o = PA_MSGOBJECT(s); - /* We probably should make this a proper vtable callback instead of going through process_msg() */ + /* FIXME: We probably should make this a proper vtable callback instead of going through process_msg() */ if (o->process_msg(o, PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) return -1; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 13033960..33145df3 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -102,7 +102,6 @@ struct pa_sink { pa_bool_t save_muted:1; pa_asyncmsgq *asyncmsgq; - pa_rtpoll *rtpoll; pa_memchunk silence; @@ -156,6 +155,8 @@ struct pa_sink { pa_sink_state_t state; pa_hashmap *inputs; + pa_rtpoll *rtpoll; + pa_cvolume soft_volume; pa_bool_t soft_muted:1; diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index a44275c0..028d6795 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -232,7 +232,6 @@ pa_source* pa_source_new( s->userdata = NULL; s->asyncmsgq = NULL; - s->rtpoll = NULL; /* As a minor optimization we just steal the list instead of * copying it here */ @@ -265,6 +264,7 @@ pa_source* pa_source_new( &s->sample_spec, 0); + s->thread_info.rtpoll = NULL; s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); s->thread_info.soft_volume = s->soft_volume; s->thread_info.soft_muted = s->muted; @@ -356,7 +356,6 @@ void pa_source_put(pa_source *s) { /* The following fields must be initialized properly when calling _put() */ pa_assert(s->asyncmsgq); - pa_assert(s->rtpoll); pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency); /* Generally, flags should be initialized via pa_source_new(). As @@ -465,18 +464,18 @@ static void source_free(pa_object *o) { /* Called from main context */ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { - pa_assert_ctl_context(); pa_source_assert_ref(s); + pa_assert_ctl_context(); s->asyncmsgq = q; } /* Called from main context */ void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) { - pa_assert_ctl_context(); pa_source_assert_ref(s); + pa_source_assert_io_context(s); - s->rtpoll = p; + s->thread_info.rtpoll = p; } /* Called from main context */ diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 001122bc..6c0a2903 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -90,7 +90,6 @@ struct pa_source { pa_bool_t save_muted:1; pa_asyncmsgq *asyncmsgq; - pa_rtpoll *rtpoll; pa_memchunk silence; @@ -140,6 +139,8 @@ struct pa_source { pa_source_state_t state; pa_hashmap *outputs; + pa_rtpoll *rtpoll; + pa_cvolume soft_volume; pa_bool_t soft_muted:1; -- cgit From 350a2bc846559bb274ba70f928bb42a9472050bf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:48:14 +0200 Subject: core: make fixed latency dynamically changeable This of course makes the name 'fixed' a bit of a misnomer. However the definitions are now like this: fixed latency: the latency may change during runtime, but is solely controlled by the backend, the client has no influence. dynamic latency: the latency may change during runtime, influenced by the requests of the clients. i.e. fixed vs. dynamic is from the perspective of the client. --- src/modules/bluetooth/module-bluetooth-device.c | 4 +- src/pulsecore/cli-text.c | 4 +- src/pulsecore/sink-input.c | 7 +- src/pulsecore/sink-input.h | 4 + src/pulsecore/sink.c | 101 ++++++++++++++++++++---- src/pulsecore/sink.h | 18 ++++- src/pulsecore/source-output.c | 7 +- src/pulsecore/source-output.h | 4 + src/pulsecore/source.c | 101 +++++++++++++++++++----- src/pulsecore/source.h | 14 +++- 10 files changed, 212 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index e682997f..93b14a12 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -881,7 +881,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse *((pa_usec_t*) data) = wi > ri ? wi - ri : 0; } - *((pa_usec_t*) data) += u->sink->fixed_latency; + *((pa_usec_t*) data) += u->sink->thread_info.fixed_latency; return 0; } } @@ -943,7 +943,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off wi = pa_smoother_get(u->read_smoother, pa_rtclock_now()); ri = pa_bytes_to_usec(u->read_index, &u->sample_spec); - *((pa_usec_t*) data) = (wi > ri ? wi - ri : 0) + u->source->fixed_latency; + *((pa_usec_t*) data) = (wi > ri ? wi - ri : 0) + u->source->thread_info.fixed_latency; return 0; } diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index ace5e719..a5530991 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -296,7 +296,7 @@ char *pa_sink_list_to_string(pa_core *c) { pa_strbuf_printf( s, "\tfixed latency: %0.2f ms\n", - (double) pa_sink_get_requested_latency(sink) / PA_USEC_PER_MSEC); + (double) pa_sink_get_fixed_latency(sink) / PA_USEC_PER_MSEC); if (sink->card) pa_strbuf_printf(s, "\tcard: %u <%s>\n", sink->card->index, sink->card->name); @@ -415,7 +415,7 @@ char *pa_source_list_to_string(pa_core *c) { pa_strbuf_printf( s, "\tfixed latency: %0.2f ms\n", - (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC); + (double) pa_source_get_fixed_latency(source) / PA_USEC_PER_MSEC); if (source->monitor_of) pa_strbuf_printf(s, "\tmonitor_of: %u\n", source->monitor_of->index); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 1b3ea92d..f6d9ac73 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -114,6 +114,7 @@ static void reset_callbacks(pa_sink_input *i) { i->update_max_request = NULL; i->update_sink_requested_latency = NULL; i->update_sink_latency_range = NULL; + i->update_sink_fixed_latency = NULL; i->attach = NULL; i->detach = NULL; i->suspend = NULL; @@ -851,13 +852,13 @@ pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa pa_sink_input_assert_io_context(i); if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY)) - usec = i->sink->fixed_latency; + usec = i->sink->thread_info.fixed_latency; if (usec != (pa_usec_t) -1) usec = PA_CLAMP(usec, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency); i->thread_info.requested_sink_latency = usec; - pa_sink_invalidate_requested_latency(i->sink); + pa_sink_invalidate_requested_latency(i->sink, TRUE); return usec; } @@ -877,7 +878,7 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) if (i->sink) { if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY)) - usec = i->sink->fixed_latency; + usec = pa_sink_get_fixed_latency(i->sink); if (usec != (pa_usec_t) -1) { pa_usec_t min_latency, max_latency; diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index c1f8082c..c1820830 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -138,6 +138,10 @@ struct pa_sink_input { * from IO context. */ void (*update_sink_latency_range) (pa_sink_input *i); /* may be NULL */ + /* Called whenver the fixed latency of the sink changes, if there + * is one. Called from IO context. */ + void (*update_sink_fixed_latency) (pa_sink_input *i); /* may be NULL */ + /* If non-NULL this function is called when the input is first * connected to a sink or when the rtpoll/asyncmsgq fields * change. You usually don't need to implement this function diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 1f9a9797..fd95f75d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -256,8 +256,6 @@ pa_sink* pa_sink_new( s->muted = data->muted; s->refresh_volume = s->refresh_muted = FALSE; - s->fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY; - reset_callbacks(s); s->userdata = NULL; @@ -307,6 +305,7 @@ pa_sink* pa_sink_new( s->thread_info.requested_latency = 0; s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY; s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY; + s->thread_info.fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY; pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0); @@ -349,6 +348,7 @@ pa_sink* pa_sink_new( s->monitor_source->monitor_of = s; pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency); + pa_source_set_fixed_latency(s->monitor_source, s->thread_info.fixed_latency); pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind); return s; @@ -438,11 +438,11 @@ void pa_sink_put(pa_sink* s) { pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SINK_DECIBEL_VOLUME)); pa_assert(!(s->flags & PA_SINK_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1); - pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->fixed_latency != 0)); + pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0)); pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY)); pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_DYNAMIC_LATENCY)); - pa_assert(s->monitor_source->fixed_latency == s->fixed_latency); + pa_assert(s->monitor_source->thread_info.fixed_latency == s->thread_info.fixed_latency); pa_assert(s->monitor_source->thread_info.min_latency == s->thread_info.min_latency); pa_assert(s->monitor_source->thread_info.max_latency == s->thread_info.max_latency); @@ -1748,7 +1748,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index))) pa_sink_input_unref(i); - pa_sink_invalidate_requested_latency(s); + pa_sink_invalidate_requested_latency(s, TRUE); pa_sink_request_rewind(s, (size_t) -1); /* In flat volume mode we need to update the volume as @@ -1794,7 +1794,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index))) pa_sink_input_unref(i); - pa_sink_invalidate_requested_latency(s); + pa_sink_invalidate_requested_latency(s, TRUE); pa_log_debug("Requesting rewind due to started move"); pa_sink_request_rewind(s, (size_t) -1); @@ -1946,6 +1946,16 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse return 0; } + case PA_SINK_MESSAGE_GET_FIXED_LATENCY: + + *((pa_usec_t*) userdata) = s->thread_info.fixed_latency; + return 0; + + case PA_SINK_MESSAGE_SET_FIXED_LATENCY: + + pa_sink_set_fixed_latency_within_thread(s, (pa_usec_t) offset); + return 0; + case PA_SINK_MESSAGE_GET_MAX_REWIND: *((size_t*) userdata) = s->thread_info.max_rewind; @@ -2082,13 +2092,12 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) { pa_sink_assert_io_context(s); if (!(s->flags & PA_SINK_DYNAMIC_LATENCY)) - return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency); + return PA_CLAMP(s->thread_info.fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency); if (s->thread_info.requested_latency_valid) return s->thread_info.requested_latency; - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) - + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 && (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency)) result = i->thread_info.requested_sink_latency; @@ -2190,18 +2199,18 @@ void pa_sink_set_max_request(pa_sink *s, size_t max_request) { } /* Called from IO thread */ -void pa_sink_invalidate_requested_latency(pa_sink *s) { +void pa_sink_invalidate_requested_latency(pa_sink *s, pa_bool_t dynamic) { pa_sink_input *i; void *state = NULL; pa_sink_assert_ref(s); pa_sink_assert_io_context(s); - if (!(s->flags & PA_SINK_DYNAMIC_LATENCY)) + if ((s->flags & PA_SINK_DYNAMIC_LATENCY)) + s->thread_info.requested_latency_valid = FALSE; + else if (dynamic) return; - s->thread_info.requested_latency_valid = FALSE; - if (PA_SINK_IS_LINKED(s->thread_info.state)) { if (s->update_requested_latency) @@ -2295,16 +2304,20 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, i->update_sink_latency_range(i); } - pa_sink_invalidate_requested_latency(s); + pa_sink_invalidate_requested_latency(s, FALSE); pa_source_set_latency_range_within_thread(s->monitor_source, min_latency, max_latency); } -/* Called from main thread, before the sink is put */ +/* Called from main thread */ void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) { pa_sink_assert_ref(s); pa_assert_ctl_context(); - pa_assert(pa_sink_get_state(s) == PA_SINK_INIT); + + if (s->flags & PA_SINK_DYNAMIC_LATENCY) { + pa_assert(latency == 0); + return; + } if (latency < ABSOLUTE_MIN_LATENCY) latency = ABSOLUTE_MIN_LATENCY; @@ -2312,10 +2325,64 @@ void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) { if (latency > ABSOLUTE_MAX_LATENCY) latency = ABSOLUTE_MAX_LATENCY; - s->fixed_latency = latency; + if (PA_SINK_IS_LINKED(s->state)) + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_FIXED_LATENCY, NULL, (int64_t) latency, NULL) == 0); + else + s->thread_info.fixed_latency = latency; + pa_source_set_fixed_latency(s->monitor_source, latency); } +/* Called from main thread */ +pa_usec_t pa_sink_get_fixed_latency(pa_sink *s) { + pa_usec_t latency; + + pa_sink_assert_ref(s); + pa_assert_ctl_context(); + + if (s->flags & PA_SINK_DYNAMIC_LATENCY) + return 0; + + if (PA_SINK_IS_LINKED(s->state)) + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_FIXED_LATENCY, &latency, 0, NULL) == 0); + else + latency = s->thread_info.fixed_latency; + + return latency; +} + +/* Called from IO thread */ +void pa_sink_set_fixed_latency_within_thread(pa_sink *s, pa_usec_t latency) { + pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); + + if (s->flags & PA_SINK_DYNAMIC_LATENCY) { + pa_assert(latency == 0); + return; + } + + pa_assert(latency >= ABSOLUTE_MIN_LATENCY); + pa_assert(latency <= ABSOLUTE_MAX_LATENCY); + + if (s->thread_info.fixed_latency == latency) + return; + + s->thread_info.fixed_latency = latency; + + if (PA_SINK_IS_LINKED(s->thread_info.state)) { + pa_sink_input *i; + void *state = NULL; + + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) + if (i->update_sink_fixed_latency) + i->update_sink_fixed_latency(i); + } + + pa_sink_invalidate_requested_latency(s, FALSE); + + pa_source_set_fixed_latency_within_thread(s->monitor_source, latency); +} + /* Called from main context */ size_t pa_sink_get_max_rewind(pa_sink *s) { size_t r; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 33145df3..55bca7f4 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -105,8 +105,6 @@ struct pa_sink { pa_memchunk silence; - pa_usec_t fixed_latency; /* for sinks with PA_SINK_DYNAMIC_LATENCY this is 0 */ - pa_hashmap *ports; pa_device_port *active_port; @@ -160,6 +158,9 @@ struct pa_sink { pa_cvolume soft_volume; pa_bool_t soft_muted:1; + /* The requested latency is used for dynamic latency + * sinks. For fixed latency sinks it is always identical to + * the fixed_latency. See below. */ pa_bool_t requested_latency_valid:1; pa_usec_t requested_latency; @@ -175,8 +176,15 @@ struct pa_sink { size_t rewind_nbytes; pa_bool_t rewind_requested; + /* Both dynamic and fixed latencies will be clamped to this + * range. */ pa_usec_t min_latency; /* we won't go below this latency */ pa_usec_t max_latency; /* An upper limit for the latencies */ + + /* 'Fixed' simply means that the latency is exclusively + * decided on by the sink, and the clients have no influence + * in changing it */ + pa_usec_t fixed_latency; /* for sinks with PA_SINK_DYNAMIC_LATENCY this is 0 */ } thread_info; void *userdata; @@ -202,6 +210,8 @@ typedef enum pa_sink_message { PA_SINK_MESSAGE_DETACH, PA_SINK_MESSAGE_SET_LATENCY_RANGE, PA_SINK_MESSAGE_GET_LATENCY_RANGE, + PA_SINK_MESSAGE_SET_FIXED_LATENCY, + PA_SINK_MESSAGE_GET_FIXED_LATENCY, PA_SINK_MESSAGE_GET_MAX_REWIND, PA_SINK_MESSAGE_GET_MAX_REQUEST, PA_SINK_MESSAGE_SET_MAX_REWIND, @@ -282,6 +292,7 @@ pa_bool_t pa_device_init_intended_roles(pa_proplist *p); pa_usec_t pa_sink_get_latency(pa_sink *s); pa_usec_t pa_sink_get_requested_latency(pa_sink *s); void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency); +pa_usec_t pa_sink_get_fixed_latency(pa_sink *s); size_t pa_sink_get_max_rewind(pa_sink *s); size_t pa_sink_get_max_request(pa_sink *s); @@ -333,12 +344,13 @@ void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind); void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request); void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency); +void pa_sink_set_fixed_latency_within_thread(pa_sink *s, pa_usec_t latency); /*** To be called exclusively by sink input drivers, from IO context */ void pa_sink_request_rewind(pa_sink*s, size_t nbytes); -void pa_sink_invalidate_requested_latency(pa_sink *s); +void pa_sink_invalidate_requested_latency(pa_sink *s, pa_bool_t dynamic); pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 2b3a0c58..3803a6cc 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -84,6 +84,7 @@ static void reset_callbacks(pa_source_output *o) { o->update_max_rewind = NULL; o->update_source_requested_latency = NULL; o->update_source_latency_range = NULL; + o->update_source_fixed_latency = NULL; o->attach = NULL; o->detach = NULL; o->suspend = NULL; @@ -561,13 +562,13 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output pa_source_output_assert_io_context(o); if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY)) - usec = o->source->fixed_latency; + usec = o->source->thread_info.fixed_latency; if (usec != (pa_usec_t) -1) usec = PA_CLAMP(usec, o->source->thread_info.min_latency, o->source->thread_info.max_latency); o->thread_info.requested_source_latency = usec; - pa_source_invalidate_requested_latency(o->source); + pa_source_invalidate_requested_latency(o->source, TRUE); return usec; } @@ -587,7 +588,7 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t if (o->source) { if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY)) - usec = o->source->fixed_latency; + usec = pa_source_get_fixed_latency(o->source); if (usec != (pa_usec_t) -1) { pa_usec_t min_latency, max_latency; diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index b78a02b9..a70a3fdb 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -109,6 +109,10 @@ struct pa_source_output { * from IO context. */ void (*update_source_latency_range) (pa_source_output *o); /* may be NULL */ + /* Called whenver the fixed latency of the source changes, if there + * is one. Called from IO context. */ + void (*update_source_fixed_latency) (pa_source_output *i); /* may be NULL */ + /* If non-NULL this function is called when the output is first * connected to a source. Called from IO thread context */ void (*attach) (pa_source_output *o); /* may be NULL */ diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 028d6795..8970d8e4 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -226,8 +226,6 @@ pa_source* pa_source_new( s->muted = data->muted; s->refresh_volume = s->refresh_muted = FALSE; - s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY; - reset_callbacks(s); s->userdata = NULL; @@ -274,6 +272,7 @@ pa_source* pa_source_new( s->thread_info.requested_latency = 0; s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY; s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY; + s->thread_info.fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY; pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0); @@ -370,7 +369,7 @@ void pa_source_put(pa_source *s) { pa_assert((s->flags & PA_SOURCE_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SOURCE_DECIBEL_VOLUME)); pa_assert(!(s->flags & PA_SOURCE_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1); - pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->fixed_latency != 0)); + pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0)); pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0); @@ -1037,7 +1036,7 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index))) pa_source_output_unref(o); - pa_source_invalidate_requested_latency(s); + pa_source_invalidate_requested_latency(s, TRUE); return 0; } @@ -1117,6 +1116,16 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ return 0; } + case PA_SOURCE_MESSAGE_GET_FIXED_LATENCY: + + *((pa_usec_t*) userdata) = s->thread_info.fixed_latency; + return 0; + + case PA_SOURCE_MESSAGE_SET_FIXED_LATENCY: + + pa_source_set_fixed_latency_within_thread(s, (pa_usec_t) offset); + return 0; + case PA_SOURCE_MESSAGE_GET_MAX_REWIND: *((size_t*) userdata) = s->thread_info.max_rewind; @@ -1223,13 +1232,12 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) { pa_source_assert_io_context(s); if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY)) - return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency); + return PA_CLAMP(s->thread_info.fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency); if (s->thread_info.requested_latency_valid) return s->thread_info.requested_latency; - while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) - + PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state) if (o->thread_info.requested_source_latency != (pa_usec_t) -1 && (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency)) result = o->thread_info.requested_source_latency; @@ -1292,18 +1300,18 @@ void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) { } /* Called from IO thread */ -void pa_source_invalidate_requested_latency(pa_source *s) { +void pa_source_invalidate_requested_latency(pa_source *s, pa_bool_t dynamic) { pa_source_output *o; void *state = NULL; pa_source_assert_ref(s); pa_source_assert_io_context(s); - if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY)) + if ((s->flags & PA_SOURCE_DYNAMIC_LATENCY)) + s->thread_info.requested_latency_valid = FALSE; + else if (dynamic) return; - s->thread_info.requested_latency_valid = FALSE; - if (PA_SOURCE_IS_LINKED(s->thread_info.state)) { if (s->update_requested_latency) @@ -1315,7 +1323,7 @@ void pa_source_invalidate_requested_latency(pa_source *s) { } if (s->monitor_of) - pa_sink_invalidate_requested_latency(s->monitor_of); + pa_sink_invalidate_requested_latency(s->monitor_of, dynamic); } /* Called from main thread */ @@ -1375,8 +1383,6 @@ void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t /* Called from IO thread, and from main thread before pa_source_put() is called */ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) { - void *state = NULL; - pa_source_assert_ref(s); pa_source_assert_io_context(s); @@ -1390,18 +1396,23 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten (s->flags & PA_SOURCE_DYNAMIC_LATENCY) || s->monitor_of); + if (s->thread_info.min_latency == min_latency && + s->thread_info.max_latency == max_latency) + return; + s->thread_info.min_latency = min_latency; s->thread_info.max_latency = max_latency; if (PA_SOURCE_IS_LINKED(s->thread_info.state)) { pa_source_output *o; + void *state = NULL; - while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) + PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state) if (o->update_source_latency_range) o->update_source_latency_range(o); } - pa_source_invalidate_requested_latency(s); + pa_source_invalidate_requested_latency(s, FALSE); } /* Called from main thread, before the source is put */ @@ -1409,7 +1420,10 @@ void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) { pa_source_assert_ref(s); pa_assert_ctl_context(); - pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT); + if (s->flags & PA_SOURCE_DYNAMIC_LATENCY) { + pa_assert(latency == 0); + return; + } if (latency < ABSOLUTE_MIN_LATENCY) latency = ABSOLUTE_MIN_LATENCY; @@ -1417,7 +1431,58 @@ void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) { if (latency > ABSOLUTE_MAX_LATENCY) latency = ABSOLUTE_MAX_LATENCY; - s->fixed_latency = latency; + if (PA_SOURCE_IS_LINKED(s->state)) + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_FIXED_LATENCY, NULL, (int64_t) latency, NULL) == 0); + else + s->thread_info.fixed_latency = latency; +} + +/* Called from main thread */ +pa_usec_t pa_source_get_fixed_latency(pa_source *s) { + pa_usec_t latency; + + pa_source_assert_ref(s); + pa_assert_ctl_context(); + + if (s->flags & PA_SOURCE_DYNAMIC_LATENCY) + return 0; + + if (PA_SOURCE_IS_LINKED(s->state)) + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_FIXED_LATENCY, &latency, 0, NULL) == 0); + else + latency = s->thread_info.fixed_latency; + + return latency; +} + +/* Called from IO thread */ +void pa_source_set_fixed_latency_within_thread(pa_source *s, pa_usec_t latency) { + pa_source_assert_ref(s); + pa_source_assert_io_context(s); + + if (s->flags & PA_SOURCE_DYNAMIC_LATENCY) { + pa_assert(latency == 0); + return; + } + + pa_assert(latency >= ABSOLUTE_MIN_LATENCY); + pa_assert(latency <= ABSOLUTE_MAX_LATENCY); + + if (s->thread_info.fixed_latency == latency) + return; + + s->thread_info.fixed_latency = latency; + + if (PA_SOURCE_IS_LINKED(s->thread_info.state)) { + pa_source_output *o; + void *state = NULL; + + PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state) + if (o->update_source_fixed_latency) + o->update_source_fixed_latency(o); + } + + pa_source_invalidate_requested_latency(s, FALSE); } /* Called from main thread */ diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 6c0a2903..bb085a0b 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -93,8 +93,6 @@ struct pa_source { pa_memchunk silence; - pa_usec_t fixed_latency; /* for sources with PA_SOURCE_DYNAMIC_LATENCY this is 0 */ - pa_hashmap *ports; pa_device_port *active_port; @@ -153,7 +151,9 @@ struct pa_source { pa_usec_t min_latency; /* we won't go below this latency */ pa_usec_t max_latency; /* An upper limit for the latencies */ - } thread_info; + + pa_usec_t fixed_latency; /* for sources with PA_SOURCE_DYNAMIC_LATENCY this is 0 */ + } thread_info; void *userdata; }; @@ -175,6 +175,8 @@ typedef enum pa_source_message { PA_SOURCE_MESSAGE_DETACH, PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, + PA_SOURCE_MESSAGE_SET_FIXED_LATENCY, + PA_SOURCE_MESSAGE_GET_FIXED_LATENCY, PA_SOURCE_MESSAGE_GET_MAX_REWIND, PA_SOURCE_MESSAGE_SET_MAX_REWIND, PA_SOURCE_MESSAGE_MAX @@ -250,6 +252,7 @@ int pa_source_sync_suspend(pa_source *s); pa_usec_t pa_source_get_latency(pa_source *s); pa_usec_t pa_source_get_requested_latency(pa_source *s); void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency); +pa_usec_t pa_source_get_fixed_latency(pa_source *s); size_t pa_source_get_max_rewind(pa_source *s); @@ -259,6 +262,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus void pa_source_set_volume(pa_source *source, const pa_cvolume *volume, pa_bool_t save); const pa_cvolume *pa_source_get_volume(pa_source *source, pa_bool_t force_refresh); + void pa_source_set_mute(pa_source *source, pa_bool_t mute, pa_bool_t save); pa_bool_t pa_source_get_mute(pa_source *source, pa_bool_t force_refresh); @@ -290,11 +294,13 @@ void pa_source_detach_within_thread(pa_source *s); pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s); void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind); + void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency); +void pa_source_set_fixed_latency_within_thread(pa_source *s, pa_usec_t latency); /*** To be called exclusively by source output drivers, from IO context */ -void pa_source_invalidate_requested_latency(pa_source *s); +void pa_source_invalidate_requested_latency(pa_source *s, pa_bool_t dynamic); pa_usec_t pa_source_get_latency_within_thread(pa_source *s); #define pa_source_assert_io_context(s) \ -- cgit From 3f9c67a7fb959acd35228f1e7455baf2aacc793b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:52:50 +0200 Subject: core: call pa_sink_get_latency_within_thread() instead of going directly via process_msg() --- src/pulsecore/sink.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index fd95f75d..e8268892 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1770,10 +1770,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse size_t sink_nbytes, total_nbytes; /* Get the latency of the sink */ - if (!(s->flags & PA_SINK_LATENCY) || - PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) - usec = 0; - + usec = pa_sink_get_latency_within_thread(s); sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec); total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq); @@ -1832,10 +1829,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse size_t nbytes; /* Get the latency of the sink */ - if (!(s->flags & PA_SINK_LATENCY) || - PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) - usec = 0; - + usec = pa_sink_get_latency_within_thread(s); nbytes = pa_usec_to_bytes(usec, &s->sample_spec); if (nbytes > 0) -- cgit From c6080d8c61df4991b96f4f144e58848f6c440440 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:54:02 +0200 Subject: core: don't update latency range if not changed --- src/pulsecore/sink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index e8268892..77908c9a 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -2273,8 +2273,6 @@ void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *ma /* Called from IO thread */ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) { - void *state = NULL; - pa_sink_assert_ref(s); pa_sink_assert_io_context(s); @@ -2287,11 +2285,16 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, max_latency == ABSOLUTE_MAX_LATENCY) || (s->flags & PA_SINK_DYNAMIC_LATENCY)); + if (s->thread_info.min_latency == min_latency && + s->thread_info.max_latency == max_latency) + return; + s->thread_info.min_latency = min_latency; s->thread_info.max_latency = max_latency; if (PA_SINK_IS_LINKED(s->thread_info.state)) { pa_sink_input *i; + void *state = NULL; PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) if (i->update_sink_latency_range) -- cgit From 3c271ae0605fcf1b6ca9ddfb21bda54a783e9926 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:54:25 +0200 Subject: core: document difference between IO and main thread view on requested latency --- src/pulsecore/sink.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 77908c9a..c1589f2d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1917,6 +1917,9 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse pa_usec_t *usec = userdata; *usec = pa_sink_get_requested_latency_within_thread(s); + /* Yes, that's right, the IO thread will see -1 when no + * explicit requested latency is configured, the main + * thread will see max_latency */ if (*usec == (pa_usec_t) -1) *usec = s->thread_info.max_latency; -- cgit From d7d86e32ddea61e93e39f55a9f7e91b8d696dfab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:54:51 +0200 Subject: native-protocol: downgrade volume change log messages --- src/pulsecore/protocol-native.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index b578746e..280707e2 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1131,6 +1131,12 @@ static void playback_stream_request_bytes(playback_stream *s) { m = pa_memblockq_pop_missing(s->memblockq); + /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu)", */ + /* (unsigned long) m, */ + /* pa_memblockq_get_tlength(s->memblockq), */ + /* pa_memblockq_get_minreq(s->memblockq), */ + /* pa_memblockq_get_length(s->memblockq)); */ + if (m <= 0) return; @@ -3381,13 +3387,13 @@ static void command_set_volume( client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); if (sink) { - pa_log("Client %s changes volume of sink %s.", client_name, sink->name); + pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name); pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE, TRUE); } else if (source) { - pa_log("Client %s changes volume of sink %s.", client_name, source->name); + pa_log_debug("Client %s changes volume of sink %s.", client_name, source->name); pa_source_set_volume(source, &volume, TRUE); } else if (si) { - pa_log("Client %s changes volume of sink %s.", + pa_log_debug("Client %s changes volume of sink %s.", client_name, pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME))); pa_sink_input_set_volume(si, &volume, TRUE, TRUE); -- cgit From d9e4605e09e01cc64e3d37452ea0b5c2783a0085 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:55:31 +0200 Subject: hook-list: make use of PA_LLIST_FOREACH --- src/pulsecore/hook-list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c index a00116d1..d9b9917d 100644 --- a/src/pulsecore/hook-list.c +++ b/src/pulsecore/hook-list.c @@ -97,7 +97,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { hook->n_firing ++; - for (slot = hook->slots; slot; slot = slot->next) { + PA_LLIST_FOREACH(slot, hook->slots) { if (slot->dead) continue; -- cgit From fb5205daac937e98736db1448fe7c8d84f3e78c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:57:36 +0200 Subject: remap: unify argument order with other modules --- src/modules/module-remap-sink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 0b7b9b8f..45f4e2af 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -1,7 +1,7 @@ /*** This file is part of PulseAudio. - Copyright 2004-2008 Lennart Poettering + Copyright 2004-2009 Lennart Poettering PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -48,8 +48,8 @@ PA_MODULE_USAGE( "master= " "master_channel_map= " "format= " - "channels= " "rate= " + "channels= " "channel_map= " "remix="); -- cgit From c44f518eb9d36fd73ada6d49d51bbb6de389e7b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:58:19 +0200 Subject: ladspa: move LADSPA_Data size check to compile time --- src/modules/module-ladspa-sink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index b26330c8..24334995 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -395,7 +395,7 @@ int pa__init(pa_module*m) { pa_assert(m); - pa_assert(sizeof(LADSPA_Data) == sizeof(float)); + pa_assert_cc(sizeof(LADSPA_Data) == sizeof(float)); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments."); -- cgit From 1b3848ebd768632f8ca8baedeb53feaf381847c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:59:26 +0200 Subject: module-remap: allow moving of sink, forward fixed latency This is a bigger change reworking a number of things: - We now allow moving of the remap sink betwween backend sinks like any other stream. - We forward the fixed latency parameter of the underlying sinks the same way as the dynamic latency. --- src/modules/module-remap-sink.c | 134 +++++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 45f4e2af..7b4c9bbb 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -54,10 +54,9 @@ PA_MODULE_USAGE( "remix="); struct userdata { - pa_core *core; pa_module *module; - pa_sink *sink, *master; + pa_sink *sink; pa_sink_input *sink_input; }; @@ -80,19 +79,24 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse switch (code) { - case PA_SINK_MESSAGE_GET_LATENCY: { - pa_usec_t usec = 0; + case PA_SINK_MESSAGE_GET_LATENCY: - /* Get the latency of the master sink */ - if (PA_MSGOBJECT(u->master)->process_msg(PA_MSGOBJECT(u->master), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) - usec = 0; + /* The sink is _put() before the sink input is, so let's + * make sure we don't access it yet */ + if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || + !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) { + *((pa_usec_t*) data) = 0; + return 0; + } - /* Add the latency internal to our sink input on top */ - usec += pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->master->sample_spec); + *((pa_usec_t*) data) = + /* Get the latency of the master sink */ + pa_sink_get_latency_within_thread(u->sink_input->sink) + + + /* Add the latency internal to our sink input on top */ + pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec); - *((pa_usec_t*) data) = usec; return 0; - } } return pa_sink_process_msg(o, code, data, offset, chunk); @@ -105,12 +109,11 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { pa_sink_assert_ref(s); pa_assert_se(u = s->userdata); - if (PA_SINK_IS_LINKED(state) && - u->sink_input && - PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input))) - - pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED); + if (!PA_SINK_IS_LINKED(state) || + !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input))) + return 0; + pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED); return 0; } @@ -121,6 +124,10 @@ static void sink_request_rewind(pa_sink *s) { pa_sink_assert_ref(s); pa_assert_se(u = s->userdata); + if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || + !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) + return; + pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes, TRUE, FALSE, FALSE); } @@ -131,6 +138,10 @@ static void sink_update_requested_latency(pa_sink *s) { pa_sink_assert_ref(s); pa_assert_se(u = s->userdata); + if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || + !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) + return; + /* Just hand this one over to the master sink */ pa_sink_input_set_requested_latency_within_thread( u->sink_input, @@ -145,9 +156,6 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk pa_assert(chunk); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state)) - return -1; - /* Hmm, process any rewind request that might be queued up */ pa_sink_process_rewind(u->sink, 0); @@ -163,9 +171,6 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state)) - return; - if (u->sink->thread_info.rewind_nbytes > 0) { amount = PA_MIN(u->sink->thread_info.rewind_nbytes, nbytes); u->sink->thread_info.rewind_nbytes = 0; @@ -181,9 +186,6 @@ static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; - pa_sink_set_max_rewind_within_thread(u->sink, nbytes); } @@ -194,9 +196,6 @@ static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; - pa_sink_set_max_request_within_thread(u->sink, nbytes); } @@ -207,24 +206,28 @@ static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; - pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency); } /* Called from I/O thread context */ -static void sink_input_detach_cb(pa_sink_input *i) { +static void sink_input_update_sink_fixed_latency_cb(pa_sink_input *i) { struct userdata *u; pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; + pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency); +} + +/* Called from I/O thread context */ +static void sink_input_detach_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); pa_sink_detach_within_thread(u->sink); - pa_sink_set_asyncmsgq(u->sink, NULL); + pa_sink_set_rtpoll(u->sink, NULL); } @@ -235,14 +238,13 @@ static void sink_input_attach_cb(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; + pa_sink_set_rtpoll(u->sink, i->sink->thread_info.rtpoll); + pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency); + pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency); + pa_sink_set_max_request_within_thread(u->sink, pa_sink_input_get_max_request(i)); + pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i)); - pa_sink_set_asyncmsgq(u->sink, i->sink->asyncmsgq); - pa_sink_set_rtpoll(u->sink, i->sink->rtpoll); pa_sink_attach_within_thread(u->sink); - - pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->master->thread_info.max_latency); } /* Called from main context */ @@ -252,14 +254,18 @@ static void sink_input_kill_cb(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - pa_sink_unlink(u->sink); + /* The order here matters! We first kill the sink input, followed + * by the sink. That means the sink callbacks must be protected + * against an unconnected sink input! */ pa_sink_input_unlink(u->sink_input); + pa_sink_unlink(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; pa_sink_input_unref(u->sink_input); u->sink_input = NULL; + pa_sink_unref(u->sink); + u->sink = NULL; + pa_module_unload_request(u->module, TRUE); } @@ -289,6 +295,16 @@ static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) { return u->sink != dest; } +/* Called from main context */ +static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); +} + int pa__init(pa_module*m) { struct userdata *u; pa_sample_spec ss; @@ -339,12 +355,8 @@ int pa__init(pa_module*m) { } u = pa_xnew0(struct userdata, 1); - u->core = m->core; u->module = m; m->userdata = u; - u->master = master; - u->sink = NULL; - u->sink_input = NULL; /* Create sink */ pa_sink_new_data_init(&sink_data); @@ -365,7 +377,7 @@ int pa__init(pa_module*m) { goto fail; } - u->sink = pa_sink_new(m->core, &sink_data, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY); + u->sink = pa_sink_new(m->core, &sink_data, master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY)); pa_sink_new_data_done(&sink_data); if (!u->sink) { @@ -380,19 +392,18 @@ int pa__init(pa_module*m) { u->sink->userdata = u; pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq); - pa_sink_set_rtpoll(u->sink, master->rtpoll); /* Create sink input */ pa_sink_input_new_data_init(&sink_input_data); sink_input_data.driver = __FILE__; sink_input_data.module = m; - sink_input_data.sink = u->master; + sink_input_data.sink = master; pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Remapped Stream"); pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &stream_map); - pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, PA_SINK_INPUT_DONT_MOVE | (remix ? 0 : PA_SINK_INPUT_NO_REMIX)); + pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, (remix ? 0 : PA_SINK_INPUT_NO_REMIX)); pa_sink_input_new_data_done(&sink_input_data); if (!u->sink_input) @@ -403,11 +414,13 @@ int pa__init(pa_module*m) { u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; u->sink_input->update_max_request = sink_input_update_max_request_cb; u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; + u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; u->sink_input->kill = sink_input_kill_cb; u->sink_input->state_change = sink_input_state_change_cb; u->sink_input->may_move_to = sink_input_may_move_to_cb; + u->sink_input->moving = sink_input_moving_cb; u->sink_input->userdata = u; pa_sink_put(u->sink); @@ -443,15 +456,20 @@ void pa__done(pa_module*m) { if (!(u = m->userdata)) return; - if (u->sink) { - pa_sink_unlink(u->sink); - pa_sink_unref(u->sink); - } + /* See comments in sink_input_kill_cb() above regarding + * destruction order! */ - if (u->sink_input) { + if (u->sink_input) pa_sink_input_unlink(u->sink_input); + + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->sink_input) pa_sink_input_unref(u->sink_input); - } + + if (u->sink) + pa_sink_unref(u->sink); pa_xfree(u); } -- cgit From 763866280adf3bd50463b0e316af7a7c4fa5aaf9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 01:01:52 +0200 Subject: module-ladspa: allow moving of sink, forward fixed latency --- src/modules/module-ladspa-sink.c | 136 ++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 24334995..e838be3e 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -64,10 +64,9 @@ PA_MODULE_USAGE( #define MEMBLOCKQ_MAXLENGTH (16*1024*1024) struct userdata { - pa_core *core; pa_module *module; - pa_sink *sink, *master; + pa_sink *sink; pa_sink_input *sink_input; const LADSPA_Descriptor *descriptor; @@ -105,19 +104,26 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse switch (code) { - case PA_SINK_MESSAGE_GET_LATENCY: { - pa_usec_t usec = 0; + case PA_SINK_MESSAGE_GET_LATENCY: - /* Get the latency of the master sink */ - if (PA_MSGOBJECT(u->master)->process_msg(PA_MSGOBJECT(u->master), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) - usec = 0; + /* The sink is _put() before the sink input is, so let's + * make sure we don't access it in that time. Also, the + * sink input is first shut down, the sink second. */ + if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || + !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) { + *((pa_usec_t*) data) = 0; + return 0; + } + + *((pa_usec_t*) data) = - /* Add the latency internal to our sink input on top */ - usec += pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->master->sample_spec); + /* Get the latency of the master sink */ + pa_sink_get_latency_within_thread(u->sink_input->sink) + + + /* Add the latency internal to our sink input on top */ + pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec); - *((pa_usec_t*) data) = usec; return 0; - } } return pa_sink_process_msg(o, code, data, offset, chunk); @@ -130,12 +136,11 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { pa_sink_assert_ref(s); pa_assert_se(u = s->userdata); - if (PA_SINK_IS_LINKED(state) && - u->sink_input && - PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input))) - - pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED); + if (!PA_SINK_IS_LINKED(state) || + !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input))) + return 0; + pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED); return 0; } @@ -146,6 +151,10 @@ static void sink_request_rewind(pa_sink *s) { pa_sink_assert_ref(s); pa_assert_se(u = s->userdata); + if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || + !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) + return; + /* Just hand this one over to the master sink */ pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes + pa_memblockq_get_length(u->memblockq), TRUE, FALSE, FALSE); } @@ -157,6 +166,10 @@ static void sink_update_requested_latency(pa_sink *s) { pa_sink_assert_ref(s); pa_assert_se(u = s->userdata); + if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || + !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) + return; + /* Just hand this one over to the master sink */ pa_sink_input_set_requested_latency_within_thread( u->sink_input, @@ -175,9 +188,6 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk pa_assert(chunk); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state)) - return -1; - /* Hmm, process any rewind request that might be queued up */ pa_sink_process_rewind(u->sink, 0); @@ -228,9 +238,6 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state)) - return; - if (u->sink->thread_info.rewind_nbytes > 0) { size_t max_rewrite; @@ -266,9 +273,6 @@ static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; - pa_memblockq_set_maxrewind(u->memblockq, nbytes); pa_sink_set_max_rewind_within_thread(u->sink, nbytes); } @@ -280,9 +284,6 @@ static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; - pa_sink_set_max_request_within_thread(u->sink, nbytes); } @@ -293,24 +294,28 @@ static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; - pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency); } /* Called from I/O thread context */ -static void sink_input_detach_cb(pa_sink_input *i) { +static void sink_input_update_sink_fixed_latency_cb(pa_sink_input *i) { struct userdata *u; pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; + pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency); +} + +/* Called from I/O thread context */ +static void sink_input_detach_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); pa_sink_detach_within_thread(u->sink); - pa_sink_set_asyncmsgq(u->sink, NULL); + pa_sink_set_rtpoll(u->sink, NULL); } @@ -321,14 +326,13 @@ static void sink_input_attach_cb(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - if (!u->sink || !PA_SINK_IS_LINKED(u->sink->thread_info.state)) - return; + pa_sink_set_rtpoll(u->sink, i->sink->thread_info.rtpoll); + pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency); + pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency); + pa_sink_set_max_request_within_thread(u->sink, pa_sink_input_get_max_request(i)); + pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i)); - pa_sink_set_asyncmsgq(u->sink, i->sink->asyncmsgq); - pa_sink_set_rtpoll(u->sink, i->sink->rtpoll); pa_sink_attach_within_thread(u->sink); - - pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->master->thread_info.max_latency); } /* Called from main context */ @@ -338,14 +342,18 @@ static void sink_input_kill_cb(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - pa_sink_unlink(u->sink); + /* The order here matters! We first kill the sink input, followed + * by the sink. That means the sink callbacks must be protected + * against an unconnected sink input! */ pa_sink_input_unlink(u->sink_input); + pa_sink_unlink(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; pa_sink_input_unref(u->sink_input); u->sink_input = NULL; + pa_sink_unref(u->sink); + u->sink = NULL; + pa_module_unload_request(u->module, TRUE); } @@ -375,6 +383,16 @@ static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) { return u->sink != dest; } +/* Called from main context */ +static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); +} + int pa__init(pa_module*m) { struct userdata *u; pa_sample_spec ss; @@ -428,12 +446,8 @@ int pa__init(pa_module*m) { cdata = pa_modargs_get_value(ma, "control", NULL); u = pa_xnew0(struct userdata, 1); - u->core = m->core; u->module = m; m->userdata = u; - u->master = master; - u->sink = NULL; - u->sink_input = NULL; u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL); if (!(e = getenv("LADSPA_PATH"))) @@ -717,7 +731,7 @@ int pa__init(pa_module*m) { goto fail; } - u->sink = pa_sink_new(m->core, &sink_data, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY); + u->sink = pa_sink_new(m->core, &sink_data, master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY)); pa_sink_new_data_done(&sink_data); if (!u->sink) { @@ -732,19 +746,18 @@ int pa__init(pa_module*m) { u->sink->userdata = u; pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq); - pa_sink_set_rtpoll(u->sink, master->rtpoll); /* Create sink input */ pa_sink_input_new_data_init(&sink_input_data); sink_input_data.driver = __FILE__; sink_input_data.module = m; - sink_input_data.sink = u->master; + sink_input_data.sink = master; pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "LADSPA Stream"); pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); - pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, PA_SINK_INPUT_DONT_MOVE); + pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, 0); pa_sink_input_new_data_done(&sink_input_data); if (!u->sink_input) @@ -755,11 +768,13 @@ int pa__init(pa_module*m) { u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; u->sink_input->update_max_request = sink_input_update_max_request_cb; u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; + u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; u->sink_input->kill = sink_input_kill_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; u->sink_input->state_change = sink_input_state_change_cb; u->sink_input->may_move_to = sink_input_may_move_to_cb; + u->sink_input->moving = sink_input_moving_cb; u->sink_input->userdata = u; pa_sink_put(u->sink); @@ -800,15 +815,20 @@ void pa__done(pa_module*m) { if (!(u = m->userdata)) return; - if (u->sink) { - pa_sink_unlink(u->sink); - pa_sink_unref(u->sink); - } + /* See comments in sink_input_kill_cb() above regarding + * destruction order! */ - if (u->sink_input) { + if (u->sink_input) pa_sink_input_unlink(u->sink_input); + + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->sink_input) pa_sink_input_unref(u->sink_input); - } + + if (u->sink) + pa_sink_unref(u->sink); for (c = 0; c < u->channels; c++) if (u->handle[c]) { -- cgit From a5b2dee03c08b72f4b7d27d9c7ac304d98e0513c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 01:02:16 +0200 Subject: ladspa: name sink after human readable plugin name, not the id string --- src/modules/module-ladspa-sink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index e838be3e..3c6e3495 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -711,11 +711,10 @@ int pa__init(pa_module*m) { sink_data.module = m; if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)))) sink_data.name = pa_sprintf_malloc("%s.ladspa", master->name); - sink_data.namereg_fail = FALSE; pa_sink_new_data_set_sample_spec(&sink_data, &ss); pa_sink_new_data_set_channel_map(&sink_data, &map); z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); - pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "LADSPA Plugin %s on %s", label, z ? z : master->name); + pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "LADSPA Plugin %s on %s", d->Name, z ? z : master->name); pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name); pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter"); pa_proplist_sets(sink_data.proplist, "device.ladspa.module", plugin); -- cgit From 8947d6551586d239be206f90adca2f6dace667a2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 01:04:21 +0200 Subject: combine: drop adjust_timestamp variable because it is unused --- src/modules/module-combine.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 92716552..325b8988 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -125,8 +125,6 @@ struct userdata { pa_resample_method_t resample_method; - struct timeval adjust_timestamp; - pa_usec_t block_usec; pa_idxset* outputs; /* managed in main context */ @@ -833,14 +831,11 @@ static struct output *output_new(struct userdata *u, pa_sink *sink) { pa_assert(sink); pa_assert(u->sink); - o = pa_xnew(struct output, 1); + o = pa_xnew0(struct output, 1); o->userdata = u; o->inq = pa_asyncmsgq_new(0); o->outq = pa_asyncmsgq_new(0); - o->inq_rtpoll_item_write = o->inq_rtpoll_item_read = NULL; - o->outq_rtpoll_item_write = o->outq_rtpoll_item_read = NULL; o->sink = sink; - o->sink_input = NULL; o->memblockq = pa_memblockq_new( 0, MEMBLOCKQ_MAXLENGTH, @@ -1029,18 +1024,14 @@ int pa__init(pa_module*m) { } } - m->userdata = u = pa_xnew(struct userdata, 1); + m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; - u->sink = NULL; - u->time_event = NULL; u->adjust_time = DEFAULT_ADJUST_TIME; u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); - u->thread = NULL; u->resample_method = resample_method; u->outputs = pa_idxset_new(NULL, NULL); - memset(&u->adjust_timestamp, 0, sizeof(u->adjust_timestamp)); u->sink_put_slot = u->sink_unlink_slot = u->sink_state_changed_slot = NULL; PA_LLIST_HEAD_INIT(struct output, u->thread_info.active_outputs); pa_atomic_store(&u->thread_info.running, FALSE); @@ -1095,7 +1086,6 @@ int pa__init(pa_module*m) { pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Simultaneous Output"); } - u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY); pa_sink_new_data_done(&data); -- cgit From e1f3f5e0bf3d788ff69d24cd40c465eaaf6e9385 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 01:07:37 +0200 Subject: combine: big rework --- src/modules/module-combine.c | 471 ++++++++++++++++++++++++------------------- 1 file changed, 266 insertions(+), 205 deletions(-) (limited to 'src') diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 325b8988..04c0d4db 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -92,6 +92,8 @@ struct output { pa_sink *sink; pa_sink_input *sink_input; + pa_bool_t ignore_state_change; + pa_asyncmsgq *inq, /* Message queue from the sink thread to this sink input */ *outq; /* Message queue from this sink input to the sink thread */ pa_rtpoll_item *inq_rtpoll_item_read, *inq_rtpoll_item_write; @@ -99,9 +101,12 @@ struct output { pa_memblockq *memblockq; + /* For communication of the stream latencies to the main thread */ pa_usec_t total_latency; + /* For coomunication of the stream parameters to the sink thread */ pa_atomic_t max_request; + pa_atomic_t requested_latency; PA_LLIST_FIELDS(struct output); }; @@ -144,13 +149,16 @@ enum { SINK_MESSAGE_REMOVE_OUTPUT, SINK_MESSAGE_NEED, SINK_MESSAGE_UPDATE_LATENCY, - SINK_MESSAGE_UPDATE_MAX_REQUEST + SINK_MESSAGE_UPDATE_MAX_REQUEST, + SINK_MESSAGE_UPDATE_REQUESTED_LATENCY }; enum { SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX, }; +static void output_disable(struct output *o); +static void output_enable(struct output *o); static void output_free(struct output *o); static int output_create_sink_input(struct output *o); @@ -170,7 +178,7 @@ static void adjust_rates(struct userdata *u) { if (!PA_SINK_IS_OPENED(pa_sink_get_state(u->sink))) return; - for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) { + PA_IDXSET_FOREACH(o, u->outputs, idx) { pa_usec_t sink_latency; if (!o->sink_input || !PA_SINK_IS_OPENED(pa_sink_get_state(o->sink))) @@ -187,6 +195,8 @@ static void adjust_rates(struct userdata *u) { avg_total_latency += o->total_latency; n++; + + pa_log_debug("[%s] total=%0.2fms sink=%0.2fms ", o->sink->name, (double) o->total_latency / PA_USEC_PER_MSEC, (double) sink_latency / PA_USEC_PER_MSEC); } if (min_total_latency == (pa_usec_t) -1) @@ -201,7 +211,7 @@ static void adjust_rates(struct userdata *u) { base_rate = u->sink->sample_spec.rate; - for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) { + PA_IDXSET_FOREACH(o, u->outputs, idx) { uint32_t r = base_rate; if (!o->sink_input || !PA_SINK_IS_OPENED(pa_sink_get_state(o->sink))) @@ -213,10 +223,10 @@ static void adjust_rates(struct userdata *u) { r += (uint32_t) ((((double) (o->total_latency - target_latency))/(double)u->adjust_time)*(double)r/PA_USEC_PER_SEC); if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) { - pa_log_warn("[%s] sample rates too different, not adjusting (%u vs. %u).", pa_proplist_gets(o->sink_input->proplist, PA_PROP_MEDIA_NAME), base_rate, r); + pa_log_warn("[%s] sample rates too different, not adjusting (%u vs. %u).", o->sink_input->sink->name, base_rate, r); pa_sink_input_set_rate(o->sink_input, base_rate); } else { - pa_log_info("[%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.", pa_proplist_gets(o->sink_input->proplist, PA_PROP_MEDIA_NAME), r, (double) r / base_rate, (float) o->total_latency); + pa_log_info("[%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.", o->sink_input->sink->name, r, (double) r / base_rate, (float) o->total_latency); pa_sink_input_set_rate(o->sink_input, r); } } @@ -353,18 +363,15 @@ static void render_memblock(struct userdata *u, struct output *o, size_t length) u->thread_info.counter += chunk.length; /* OK, let's send this data to the other threads */ - for (j = u->thread_info.active_outputs; j; j = j->next) - - /* Send to other outputs, which are not the requesting - * one */ + PA_LLIST_FOREACH(j, u->thread_info.active_outputs) { + if (j == o) + continue; - if (j != o) - pa_asyncmsgq_post(j->inq, PA_MSGOBJECT(j->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, &chunk, NULL); + pa_asyncmsgq_post(j->inq, PA_MSGOBJECT(j->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, &chunk, NULL); + } /* And place it directly into the requesting output's queue */ - if (o) - pa_memblockq_push_align(o->memblockq, &chunk); - + pa_memblockq_push_align(o->memblockq, &chunk); pa_memblock_unref(chunk.memblock); } } @@ -400,10 +407,18 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk /* If necessary, get some new data */ request_memblock(o, nbytes); + /* pa_log("%s q size is %u + %u (%u/%u)", */ + /* i->sink->name, */ + /* pa_memblockq_get_nblocks(o->memblockq), */ + /* pa_memblockq_get_nblocks(i->thread_info.render_memblockq), */ + /* pa_memblockq_get_maxrewind(o->memblockq), */ + /* pa_memblockq_get_maxrewind(i->thread_info.render_memblockq)); */ + if (pa_memblockq_peek(o->memblockq, chunk) < 0) return -1; pa_memblockq_drop(o->memblockq, chunk->length); + return 0; } @@ -438,13 +453,35 @@ static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) { return; pa_atomic_store(&o->max_request, (int) nbytes); - pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_UPDATE_MAX_REQUEST, NULL, 0, NULL, NULL); } +/* Called from thread context */ +static void sink_input_update_sink_requested_latency_cb(pa_sink_input *i) { + struct output *o; + pa_usec_t c; + + pa_assert(i); + + pa_sink_input_assert_ref(i); + pa_assert_se(o = i->userdata); + + c = pa_sink_get_requested_latency_within_thread(i->sink); + + if (c == (pa_usec_t) -1) + c = i->sink->thread_info.max_latency; + + if (pa_atomic_load(&o->requested_latency) == (int) c) + return; + + pa_atomic_store(&o->requested_latency, (int) c); + pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_UPDATE_REQUESTED_LATENCY, NULL, 0, NULL, NULL); +} + /* Called from I/O thread context */ static void sink_input_attach_cb(pa_sink_input *i) { struct output *o; + pa_usec_t c; pa_sink_input_assert_ref(i); pa_assert_se(o = i->userdata); @@ -461,6 +498,16 @@ static void sink_input_attach_cb(pa_sink_input *i) { i->sink->thread_info.rtpoll, PA_RTPOLL_EARLY, o->outq); + + pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE); + + pa_atomic_store(&o->max_request, (int) pa_sink_input_get_max_request(i)); + + c = pa_sink_get_requested_latency_within_thread(i->sink); + pa_atomic_store(&o->requested_latency, (int) (c == (pa_usec_t) -1 ? 0 : c)); + + pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_UPDATE_MAX_REQUEST, NULL, 0, NULL, NULL); + pa_asyncmsgq_post(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_UPDATE_REQUESTED_LATENCY, NULL, 0, NULL, NULL); } /* Called from I/O thread context */ @@ -470,14 +517,15 @@ static void sink_input_detach_cb(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert_se(o = i->userdata); - /* Shut down the queue from the sink thread to us */ - pa_assert(o->inq_rtpoll_item_read && o->outq_rtpoll_item_write); - - pa_rtpoll_item_free(o->inq_rtpoll_item_read); - o->inq_rtpoll_item_read = NULL; + if (o->inq_rtpoll_item_read) { + pa_rtpoll_item_free(o->inq_rtpoll_item_read); + o->inq_rtpoll_item_read = NULL; + } - pa_rtpoll_item_free(o->outq_rtpoll_item_write); - o->outq_rtpoll_item_write = NULL; + if (o->outq_rtpoll_item_write) { + pa_rtpoll_item_free(o->outq_rtpoll_item_write); + o->outq_rtpoll_item_write = NULL; + } } /* Called from main context */ @@ -491,20 +539,6 @@ static void sink_input_kill_cb(pa_sink_input *i) { output_free(o); } -/* Called from IO thread context */ -static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t state) { - struct userdata *u; - - pa_sink_input_assert_ref(i); - pa_assert_se(u = i->userdata); - - /* If we are added for the first time, ask for a rewinding so that - * we are heard right-away. */ - if (PA_SINK_INPUT_IS_LINKED(state) && - i->thread_info.state == PA_SINK_INPUT_INIT) - pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE); -} - /* Called from thread context */ static int sink_input_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct output *o = PA_SINK_INPUT(obj)->userdata; @@ -534,37 +568,6 @@ static int sink_input_process_msg(pa_msgobject *obj, int code, void *data, int64 return pa_sink_input_process_msg(obj, code, data, offset, chunk); } -/* Called from main context */ -static void disable_output(struct output *o) { - pa_assert(o); - - if (!o->sink_input) - return; - - pa_sink_input_unlink(o->sink_input); - pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); - pa_sink_input_unref(o->sink_input); - o->sink_input = NULL; -} - -/* Called from main context */ -static void enable_output(struct output *o) { - pa_assert(o); - - if (o->sink_input) - return; - - if (output_create_sink_input(o) >= 0) { - - pa_memblockq_flush_write(o->memblockq); - - pa_sink_input_put(o->sink_input); - - if (o->userdata->sink && PA_SINK_IS_LINKED(pa_sink_get_state(o->userdata->sink))) - pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL); - } -} - /* Called from main context */ static void suspend(struct userdata *u) { struct output *o; @@ -573,8 +576,8 @@ static void suspend(struct userdata *u) { pa_assert(u); /* Let's suspend by unlinking all streams */ - for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) - disable_output(o); + PA_IDXSET_FOREACH(o, u->outputs, idx) + output_disable(o); pa_log_info("Device suspended..."); } @@ -587,13 +590,8 @@ static void unsuspend(struct userdata *u) { pa_assert(u); /* Let's resume */ - for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) { - - pa_sink_suspend(o->sink, FALSE, PA_SUSPEND_IDLE); - - if (PA_SINK_IS_OPENED(pa_sink_get_state(o->sink))) - enable_output(o); - } + PA_IDXSET_FOREACH(o, u->outputs, idx) + output_enable(o); pa_log_info("Resumed successfully..."); } @@ -637,7 +635,13 @@ static void update_max_request(struct userdata *u) { size_t max_request = 0; struct output *o; - for (o = u->thread_info.active_outputs; o; o = o->next) { + pa_assert(u); + pa_sink_assert_io_context(u->sink); + + /* Collects the max_request values of all streams and sets the + * largest one locally */ + + PA_LLIST_FOREACH(o, u->thread_info.active_outputs) { size_t mr = (size_t) pa_atomic_load(&o->max_request); if (mr > max_request) @@ -650,6 +654,67 @@ static void update_max_request(struct userdata *u) { pa_sink_set_max_request_within_thread(u->sink, max_request); } +/* Called from IO context */ +static void update_fixed_latency(struct userdata *u) { + pa_usec_t fixed_latency = 0; + struct output *o; + + pa_assert(u); + pa_sink_assert_io_context(u->sink); + + /* Collects the requested_latency values of all streams and sets + * the largest one as fixed_latency locally */ + + PA_LLIST_FOREACH(o, u->thread_info.active_outputs) { + pa_usec_t rl = (size_t) pa_atomic_load(&o->requested_latency); + + if (rl > fixed_latency) + fixed_latency = rl; + } + + if (fixed_latency <= 0) + fixed_latency = u->block_usec; + + pa_sink_set_fixed_latency_within_thread(u->sink, fixed_latency); +} + +/* Called from thread context of the io thread */ +static void output_add_within_thread(struct output *o) { + pa_assert(o); + pa_sink_assert_io_context(o->sink); + + PA_LLIST_PREPEND(struct output, o->userdata->thread_info.active_outputs, o); + + pa_assert(!o->outq_rtpoll_item_read && !o->inq_rtpoll_item_write); + + o->outq_rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read( + o->userdata->rtpoll, + PA_RTPOLL_EARLY-1, /* This item is very important */ + o->outq); + o->inq_rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write( + o->userdata->rtpoll, + PA_RTPOLL_EARLY, + o->inq); +} + +/* Called from thread context of the io thread */ +static void output_remove_within_thread(struct output *o) { + pa_assert(o); + pa_sink_assert_io_context(o->sink); + + PA_LLIST_REMOVE(struct output, o->userdata->thread_info.active_outputs, o); + + if (o->outq_rtpoll_item_read) { + pa_rtpoll_item_free(o->outq_rtpoll_item_read); + o->outq_rtpoll_item_read = NULL; + } + + if (o->inq_rtpoll_item_write) { + pa_rtpoll_item_free(o->inq_rtpoll_item_write); + o->inq_rtpoll_item_write = NULL; + } +} + /* Called from thread context of the io thread */ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; @@ -682,42 +747,17 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse return 0; } - case SINK_MESSAGE_ADD_OUTPUT: { - struct output *op = data; - - PA_LLIST_PREPEND(struct output, u->thread_info.active_outputs, op); - - pa_assert(!op->outq_rtpoll_item_read && !op->inq_rtpoll_item_write); - - op->outq_rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read( - u->rtpoll, - PA_RTPOLL_EARLY-1, /* This item is very important */ - op->outq); - op->inq_rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write( - u->rtpoll, - PA_RTPOLL_EARLY, - op->inq); - + case SINK_MESSAGE_ADD_OUTPUT: + output_add_within_thread(data); update_max_request(u); + update_fixed_latency(u); return 0; - } - - case SINK_MESSAGE_REMOVE_OUTPUT: { - struct output *op = data; - - PA_LLIST_REMOVE(struct output, u->thread_info.active_outputs, op); - - pa_assert(op->outq_rtpoll_item_read && op->inq_rtpoll_item_write); - - pa_rtpoll_item_free(op->outq_rtpoll_item_read); - op->outq_rtpoll_item_read = NULL; - - pa_rtpoll_item_free(op->inq_rtpoll_item_write); - op->inq_rtpoll_item_write = NULL; + case SINK_MESSAGE_REMOVE_OUTPUT: + output_remove_within_thread(data); update_max_request(u); + update_fixed_latency(u); return 0; - } case SINK_MESSAGE_NEED: render_memblock(u, (struct output*) data, (size_t) offset); @@ -739,10 +779,13 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse } case SINK_MESSAGE_UPDATE_MAX_REQUEST: - update_max_request(u); break; - } + + case SINK_MESSAGE_UPDATE_REQUESTED_LATENCY: + update_fixed_latency(u); + break; +} return pa_sink_process_msg(o, code, data, offset, chunk); } @@ -765,7 +808,7 @@ static void update_description(struct userdata *u) { t = pa_xstrdup("Simultaneous output to"); - for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) { + PA_IDXSET_FOREACH(o, u->outputs, idx) { char *e; if (first) { @@ -800,7 +843,7 @@ static int output_create_sink_input(struct output *o) { data.module = o->userdata->module; data.resample_method = o->userdata->resample_method; - pa_sink_input_new(&o->sink_input, o->userdata->core, &data, PA_SINK_INPUT_VARIABLE_RATE|PA_SINK_INPUT_DONT_MOVE); + pa_sink_input_new(&o->sink_input, o->userdata->core, &data, PA_SINK_INPUT_VARIABLE_RATE|PA_SINK_INPUT_DONT_MOVE|PA_SINK_INPUT_NO_CREATE_ON_SUSPEND); pa_sink_input_new_data_done(&data); @@ -810,9 +853,9 @@ static int output_create_sink_input(struct output *o) { o->sink_input->parent.process_msg = sink_input_process_msg; o->sink_input->pop = sink_input_pop_cb; o->sink_input->process_rewind = sink_input_process_rewind_cb; - o->sink_input->state_change = sink_input_state_change_cb; o->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; o->sink_input->update_max_request = sink_input_update_max_request_cb; + o->sink_input->update_sink_requested_latency = sink_input_update_sink_requested_latency_cb; o->sink_input->attach = sink_input_attach_cb; o->sink_input->detach = sink_input_detach_cb; o->sink_input->kill = sink_input_kill_cb; @@ -823,9 +866,9 @@ static int output_create_sink_input(struct output *o) { return 0; } +/* Called from main context */ static struct output *output_new(struct userdata *u, pa_sink *sink) { struct output *o; - pa_sink_state_t state; pa_assert(u); pa_assert(sink); @@ -845,84 +888,135 @@ static struct output *output_new(struct userdata *u, pa_sink *sink) { 0, 0, NULL); - pa_atomic_store(&o->max_request, 0); - PA_LLIST_INIT(struct output, o); pa_assert_se(pa_idxset_put(u->outputs, o, NULL) == 0); + update_description(u); - state = pa_sink_get_state(u->sink); - - if (state != PA_SINK_INIT) - pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL); - else { - /* If the sink is not yet started, we need to do the activation ourselves */ - PA_LLIST_PREPEND(struct output, u->thread_info.active_outputs, o); - - o->outq_rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read( - u->rtpoll, - PA_RTPOLL_EARLY-1, /* This item is very important */ - o->outq); - o->inq_rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write( - u->rtpoll, - PA_RTPOLL_EARLY, - o->inq); - } + return o; +} - if (PA_SINK_IS_OPENED(state) || state == PA_SINK_INIT) { - pa_sink_suspend(sink, FALSE, PA_SUSPEND_IDLE); +/* Called from main context */ +static void output_free(struct output *o) { + pa_assert(o); - if (PA_SINK_IS_OPENED(pa_sink_get_state(sink))) - if (output_create_sink_input(o) < 0) - goto fail; - } + output_disable(o); - update_description(u); + pa_assert_se(pa_idxset_remove_by_data(o->userdata->outputs, o, NULL)); + update_description(o->userdata); - return o; + if (o->inq_rtpoll_item_read) + pa_rtpoll_item_free(o->inq_rtpoll_item_read); + if (o->inq_rtpoll_item_write) + pa_rtpoll_item_free(o->inq_rtpoll_item_write); -fail: + if (o->outq_rtpoll_item_read) + pa_rtpoll_item_free(o->outq_rtpoll_item_read); + if (o->outq_rtpoll_item_write) + pa_rtpoll_item_free(o->outq_rtpoll_item_write); - if (o) { - pa_idxset_remove_by_data(u->outputs, o, NULL); + if (o->inq) + pa_asyncmsgq_unref(o->inq); - if (o->sink_input) { - pa_sink_input_unlink(o->sink_input); - pa_sink_input_unref(o->sink_input); - } + if (o->outq) + pa_asyncmsgq_unref(o->outq); + + if (o->memblockq) + pa_memblockq_free(o->memblockq); - if (o->memblockq) - pa_memblockq_free(o->memblockq); + pa_xfree(o); +} - if (o->inq) - pa_asyncmsgq_unref(o->inq); +/* Called from main context */ +static void output_enable(struct output *o) { + pa_assert(o); + + if (o->sink_input) + return; + + /* This might cause the sink to be resumed. The state change hook + * of the sink might hence be called from here, which might then + * cause us to be called in a loop. Make sure that state changes + * for this output don't cause this loop by setting a flag here */ + o->ignore_state_change = TRUE; + + if (output_create_sink_input(o) >= 0) { - if (o->outq) - pa_asyncmsgq_unref(o->outq); + if (pa_sink_get_state(o->sink) != PA_SINK_INIT) { - pa_xfree(o); + /* First we register the output. That means that the sink + * will start to pass data to this output. */ + pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL); + + /* Then we enable the sink input. That means that the sink + * is now asked for new data. */ + pa_sink_input_put(o->sink_input); + + } else + /* Hmm the sink is not yet started, do things right here */ + output_add_within_thread(o); } - return NULL; + o->ignore_state_change = FALSE; } +/* Called from main context */ +static void output_disable(struct output *o) { + pa_assert(o); + + if (!o->sink_input) + return; + + /* First we disable the sink input. That means that the sink is + * not asked for new data anymore */ + pa_sink_input_unlink(o->sink_input); + + /* Then we unregister the output. That means that the sink doesn't + * pass any further data to this output */ + pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_REMOVE_OUTPUT, o, 0, NULL); + + /* Now dellocate the stream */ + pa_sink_input_unref(o->sink_input); + o->sink_input = NULL; + + /* Finally, drop all queued data */ + pa_memblockq_flush_write(o->memblockq); + pa_asyncmsgq_flush(o->inq, FALSE); + pa_asyncmsgq_flush(o->outq, FALSE); +} + +/* Called from main context */ +static void output_verify(struct output *o) { + pa_assert(o); + + if (PA_SINK_IS_OPENED(pa_sink_get_state(o->userdata->sink))) + output_enable(o); + else + output_disable(o); +} + +/* Called from main context */ static pa_bool_t is_suitable_sink(struct userdata *u, pa_sink *s) { const char *t; pa_sink_assert_ref(s); + if (s == u->sink) + return FALSE; + if (!(s->flags & PA_SINK_HARDWARE)) return FALSE; - if (s == u->sink) + if (!(s->flags & PA_SINK_LATENCY)) return FALSE; if ((t = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_CLASS))) - if (strcmp(t, "sound")) + if (!pa_streq(t, "sound")) return FALSE; return TRUE; } +/* Called from main context */ static pa_hook_result_t sink_put_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) { struct output *o; @@ -935,18 +1029,17 @@ static pa_hook_result_t sink_put_hook_cb(pa_core *c, pa_sink *s, struct userdata return PA_HOOK_OK; pa_log_info("Configuring new sink: %s", s->name); - if (!(o = output_new(u, s))) { pa_log("Failed to create sink input on sink '%s'.", s->name); return PA_HOOK_OK; } - if (o->sink_input) - pa_sink_input_put(o->sink_input); + output_verify(o); return PA_HOOK_OK; } +/* Called from main context */ static struct output* find_output(struct userdata *u, pa_sink *s) { struct output *o; uint32_t idx; @@ -957,13 +1050,14 @@ static struct output* find_output(struct userdata *u, pa_sink *s) { if (u->sink == s) return NULL; - for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) + PA_IDXSET_FOREACH(o, u->outputs, idx) if (o->sink == s) return o; return NULL; } +/* Called from main context */ static pa_hook_result_t sink_unlink_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) { struct output *o; @@ -975,26 +1069,25 @@ static pa_hook_result_t sink_unlink_hook_cb(pa_core *c, pa_sink *s, struct userd return PA_HOOK_OK; pa_log_info("Unconfiguring sink: %s", s->name); - output_free(o); return PA_HOOK_OK; } +/* Called from main context */ static pa_hook_result_t sink_state_changed_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) { struct output *o; - pa_sink_state_t state; if (!(o = find_output(u, s))) return PA_HOOK_OK; - state = pa_sink_get_state(s); - - if (PA_SINK_IS_OPENED(state) && PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)) && !o->sink_input) - enable_output(o); + /* This state change might be triggered because we are creating a + * stream here, in that case we don't want to create it a second + * time here and enter a loop */ + if (o->ignore_state_change) + return PA_HOOK_OK; - if (state == PA_SINK_SUSPENDED && o->sink_input) - disable_output(o); + output_verify(o); return PA_HOOK_OK; } @@ -1139,7 +1232,7 @@ int pa__init(pa_module*m) { /* We're in automatic mode, we add every sink that matches our needs */ - for (s = pa_idxset_first(m->core->sinks, &idx); s; s = pa_idxset_next(m->core->sinks, &idx)) { + PA_IDXSET_FOREACH(s, m->core->sinks, idx) { if (!is_suitable_sink(u, s)) continue; @@ -1164,9 +1257,8 @@ int pa__init(pa_module*m) { /* Activate the sink and the sink inputs */ pa_sink_put(u->sink); - for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) - if (o->sink_input) - pa_sink_input_put(o->sink_input); + PA_IDXSET_FOREACH(o, u->outputs, idx) + output_verify(o); if (u->adjust_time > 0) u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time * PA_USEC_PER_SEC, time_callback, u); @@ -1185,37 +1277,6 @@ fail: return -1; } -static void output_free(struct output *o) { - pa_assert(o); - - disable_output(o); - - pa_assert_se(pa_idxset_remove_by_data(o->userdata->outputs, o, NULL)); - - update_description(o->userdata); - - if (o->inq_rtpoll_item_read) - pa_rtpoll_item_free(o->inq_rtpoll_item_read); - if (o->inq_rtpoll_item_write) - pa_rtpoll_item_free(o->inq_rtpoll_item_write); - - if (o->outq_rtpoll_item_read) - pa_rtpoll_item_free(o->outq_rtpoll_item_read); - if (o->outq_rtpoll_item_write) - pa_rtpoll_item_free(o->outq_rtpoll_item_write); - - if (o->inq) - pa_asyncmsgq_unref(o->inq); - - if (o->outq) - pa_asyncmsgq_unref(o->outq); - - if (o->memblockq) - pa_memblockq_free(o->memblockq); - - pa_xfree(o); -} - void pa__done(pa_module*m) { struct userdata *u; struct output *o; -- cgit From 1eeddd84d2ff2482dd4a6d2dd43dc8a315ba72a4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 01:16:57 +0200 Subject: combine: warn when the latency of a stream gets too high --- src/modules/module-combine.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 04c0d4db..155b928a 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -197,6 +197,9 @@ static void adjust_rates(struct userdata *u) { n++; pa_log_debug("[%s] total=%0.2fms sink=%0.2fms ", o->sink->name, (double) o->total_latency / PA_USEC_PER_MSEC, (double) sink_latency / PA_USEC_PER_MSEC); + + if (o->total_latency > 10*PA_USEC_PER_SEC) + pa_log_warn("[%s] Total latency of output is very high (%0.2fms), most likely the audio timing in one of your drivers is broken.", o->sink->name, (double) o->total_latency / PA_USEC_PER_MSEC); } if (min_total_latency == (pa_usec_t) -1) -- cgit From 61105df13b423b100394639cf7850856efbad767 Mon Sep 17 00:00:00 2001 From: Maarten Bosmans Date: Sat, 15 Aug 2009 01:35:53 +0200 Subject: combine: determine sample parameters of combined sink from underlying sinks http://pulseaudio.org/ticket/521 --- src/modules/module-combine.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'src') diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 155b928a..582cbce1 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -1152,6 +1152,55 @@ int pa__init(pa_module*m) { ss = m->core->default_sample_spec; map = m->core->default_channel_map; + + /* Check the specified slave sinks for sample_spec and channel_map to use for the combined sink */ + if (!u->automatic) { + const char*split_state = NULL; + char *n = NULL; + pa_sample_spec slaves_spec; + pa_channel_map slaves_map; + pa_bool_t is_first_slave = TRUE; + + while ((n = pa_split(slaves, ",", &split_state))) { + pa_sink *slave_sink; + + if (!(slave_sink = pa_namereg_get(m->core, n, PA_NAMEREG_SINK))) { + pa_log("Invalid slave sink '%s'", n); + pa_xfree(n); + goto fail; + } + + pa_xfree(n); + + if (is_first_slave) { + slaves_spec = slave_sink->sample_spec; + slaves_map = slave_sink->channel_map; + is_first_slave = FALSE; + } else { + if (slaves_spec.format != slave_sink->sample_spec.format) + slaves_spec.format = PA_SAMPLE_INVALID; + + if (slaves_spec.rate < slave_sink->sample_spec.rate) + slaves_spec.rate = slave_sink->sample_spec.rate; + + if (!pa_channel_map_equal(&slaves_map, &slave_sink->channel_map)) + slaves_spec.channels = 0; + } + } + + if (!is_first_slave) { + if (slaves_spec.format != PA_SAMPLE_INVALID) + ss.format = slaves_spec.format; + + ss.rate = slaves_spec.rate; + + if (slaves_spec.channels > 0) { + map = slaves_map; + ss.channels = slaves_map.channels; + } + } + } + if ((pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0)) { pa_log("Invalid sample specification."); goto fail; -- cgit From ea5cdcbe52e3e1ac6189fb6472fafe61fbfdd73c Mon Sep 17 00:00:00 2001 From: Juho Hämäläinen Date: Wed, 12 Aug 2009 18:30:14 +0300 Subject: database: simple hashmap based database implementation --- src/Makefile.am | 3 + src/pulsecore/database-simple.c | 510 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 513 insertions(+) create mode 100644 src/pulsecore/database-simple.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index aa82d794..17011cd3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -870,6 +870,9 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_CFLAGS += $(TDB_CFLAGS) libpulsecore_@PA_MAJORMINORMICRO@_la_LIBADD += $(TDB_LIBS) endif +if HAVE_SIMPLEDB +libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES += pulsecore/database-simple.c +endif # We split the foreign code off to not be annoyed by warnings we don't care about noinst_LTLIBRARIES = libpulsecore-foreign.la diff --git a/src/pulsecore/database-simple.c b/src/pulsecore/database-simple.c new file mode 100644 index 00000000..1f4caf71 --- /dev/null +++ b/src/pulsecore/database-simple.c @@ -0,0 +1,510 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Nokia Corporation + Contact: Maemo Multimedia + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "database.h" + + +typedef struct simple_data { + char *filename; + char *tmp_filename; + pa_hashmap *map; + pa_bool_t read_only; +} simple_data; + +typedef struct entry { + pa_datum key; + pa_datum data; +} entry; + +void pa_datum_free(pa_datum *d) { + pa_assert(d); + + pa_xfree(d->data); + d->data = NULL; + d->size = 0; +} + +static int compare_func(const void *a, const void *b) { + const pa_datum *aa, *bb; + + aa = (const pa_datum*)a; + bb = (const pa_datum*)b; + + if (aa->size != bb->size) + return aa->size > bb->size ? 1 : -1; + + return memcmp(aa->data, bb->data, aa->size); +} + +/* pa_idxset_string_hash_func modified for our use */ +static unsigned hash_func(const void *p) { + const pa_datum *d; + unsigned hash = 0; + const char *c; + unsigned i; + + d = (const pa_datum*)p; + c = d->data; + + for (i = 0; i < d->size; i++) { + hash = 31 * hash + (unsigned) *c; + c++; + } + + return hash; +} + +static entry* new_entry(const pa_datum *key, const pa_datum *data) { + entry *e; + + pa_assert(key); + pa_assert(data); + + e = pa_xnew0(entry, 1); + e->key.data = key->size > 0 ? pa_xmemdup(key->data, key->size) : NULL; + e->key.size = key->size; + e->data.data = data->size > 0 ? pa_xmemdup(data->data, data->size) : NULL; + e->data.size = data->size; + return e; +} + +static void free_entry(entry *e) { + if (e) { + if (e->key.data) + pa_xfree(e->key.data); + if (e->data.data) + pa_xfree(e->data.data); + pa_xfree(e); + } +} + +static int read_uint(FILE *f, uint32_t *res) { + size_t items = 0; + uint8_t values[4]; + uint32_t tmp; + int i; + + items = fread(&values, sizeof(values), sizeof(uint8_t), f); + + if (feof(f)) /* EOF */ + return 0; + + if (ferror(f)) + return -1; + + for (i = 0; i < 4; ++i) { + tmp = values[i]; + *res += (tmp << (i*8)); + } + + return items; +} + +static int read_data(FILE *f, void **data, ssize_t *length) { + size_t items = 0; + uint32_t data_len = 0; + + pa_assert(f); + + *data = NULL; + *length = 0; + + if ((items = read_uint(f, &data_len)) <= 0) + return -1; + + if (data_len > 0) { + *data = pa_xmalloc0(data_len); + items = fread(*data, data_len, 1, f); + + if (feof(f)) /* EOF */ + goto reset; + + if (ferror(f)) + goto reset; + + *length = data_len; + + } else { /* no data? */ + return -1; + } + + return 0; + +reset: + pa_xfree(*data); + *data = NULL; + *length = 0; + return -1; +} + +static int fill_data(simple_data *db, FILE *f) { + pa_datum key; + pa_datum data; + void *d = NULL; + ssize_t l = 0; + pa_bool_t append = FALSE; + enum { FIELD_KEY = 0, FIELD_DATA } field = FIELD_KEY; + + pa_assert(db); + pa_assert(db->map); + + errno = 0; + + key.size = 0; + key.data = NULL; + + while (!read_data(f, &d, &l)) { + + switch (field) { + case FIELD_KEY: + key.data = d; + key.size = l; + field = FIELD_DATA; + break; + case FIELD_DATA: + data.data = d; + data.size = l; + append = TRUE; + break; + } + + if (append) { + entry *e = pa_xnew0(entry, 1); + e->key.data = key.data; + e->key.size = key.size; + e->data.data = data.data; + e->data.size = data.size; + pa_hashmap_put(db->map, &e->key, e); + append = FALSE; + field = FIELD_KEY; + } + } + + if (ferror(f)) { + pa_log_warn("read error. %s", pa_cstrerror(errno)); + pa_database_clear((pa_database*)db); + } + + if (field == FIELD_DATA && d) + pa_xfree(d); + + return pa_hashmap_size(db->map); +} + +pa_database* pa_database_open(const char *fn, pa_bool_t for_write) { + FILE *f; + char *path; + simple_data *db; + + pa_assert(fn); + + path = pa_sprintf_malloc("%s."CANONICAL_HOST".simple", fn); + errno = 0; + + f = fopen(path, "r"); + + if (f || errno == ENOENT) { /* file not found is ok */ + db = pa_xnew0(simple_data, 1); + db->map = pa_hashmap_new(hash_func, compare_func); + db->filename = pa_xstrdup(path); + db->tmp_filename = pa_sprintf_malloc(".%s.tmp", db->filename); + db->read_only = !for_write; + + if (f) { + fill_data(db, f); + fclose(f); + } + } else { + if (errno == 0) + errno = EIO; + db = NULL; + } + + pa_xfree(path); + + return (pa_database*) db; +} + +void pa_database_close(pa_database *database) { + simple_data *db = (simple_data*)database; + pa_assert(db); + + pa_database_sync(database); + pa_database_clear(database); + pa_xfree(db->filename); + pa_xfree(db->tmp_filename); + pa_hashmap_free(db->map, NULL, NULL); + pa_xfree(db); +} + +pa_datum* pa_database_get(pa_database *database, const pa_datum *key, pa_datum* data) { + simple_data *db = (simple_data*)database; + entry *e; + + pa_assert(db); + pa_assert(key); + pa_assert(data); + + e = pa_hashmap_get(db->map, key); + + if (!e) + return NULL; + + data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL; + data->size = e->data.size; + + return data; +} + +int pa_database_set(pa_database *database, const pa_datum *key, const pa_datum* data, pa_bool_t overwrite) { + simple_data *db = (simple_data*)database; + entry *e; + int ret = 0; + + pa_assert(db); + pa_assert(key); + pa_assert(data); + + if (db->read_only) + return -1; + + e = new_entry(key, data); + + if (pa_hashmap_put(db->map, &e->key, e) < 0) { + /* entry with same key exists in hashmap */ + entry *r; + if (overwrite) { + r = pa_hashmap_remove(db->map, key); + pa_hashmap_put(db->map, &e->key, e); + } else { + /* wont't overwrite, so clean new entry */ + r = e; + ret = -1; + } + + free_entry(r); + } + + return ret; +} + +int pa_database_unset(pa_database *database, const pa_datum *key) { + simple_data *db = (simple_data*)database; + entry *e; + + pa_assert(db); + pa_assert(key); + + e = pa_hashmap_remove(db->map, key); + if (!e) + return -1; + + free_entry(e); + + return 0; +} + +int pa_database_clear(pa_database *database) { + simple_data *db = (simple_data*)database; + entry *e; + + pa_assert(db); + + while ((e = pa_hashmap_steal_first(db->map))) + free_entry(e); + + return 0; +} + +signed pa_database_size(pa_database *database) { + simple_data *db = (simple_data*)database; + pa_assert(db); + + return (signed) pa_hashmap_size(db->map); +} + +pa_datum* pa_database_first(pa_database *database, pa_datum *key, pa_datum *data) { + simple_data *db = (simple_data*)database; + entry *e; + + pa_assert(db); + pa_assert(key); + + e = pa_hashmap_first(db->map); + + if (!e) + return NULL; + + key->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL; + key->size = e->key.size; + + if (data) { + data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL; + data->size = e->data.size; + } + + return key; +} + +pa_datum* pa_database_next(pa_database *database, const pa_datum *key, pa_datum *next, pa_datum *data) { + simple_data *db = (simple_data*)database; + entry *e; + entry *search; + void *state; + pa_bool_t pick_now; + + pa_assert(db); + pa_assert(next); + + if (!key) + return pa_database_first(database, next, data); + + search = pa_hashmap_get(db->map, key); + + state = NULL; + pick_now = FALSE; + + while ((e = pa_hashmap_iterate(db->map, &state, NULL))) { + if (pick_now) + break; + + if (search == e) + pick_now = TRUE; + } + + if (!pick_now || !e) + return NULL; + + next->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL; + next->size = e->key.size; + + if (data) { + data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL; + data->size = e->data.size; + } + + return next; +} + +static int write_uint(FILE *f, const uint32_t num) { + size_t items; + uint8_t values[4]; + int i; + errno = 0; + + for (i = 0; i < 4; i++) + values[i] = (num >> (i*8)) & 0xFF; + + items = fwrite(&values, sizeof(values), sizeof(uint8_t), f); + + if (ferror(f)) + return -1; + + return items; +} + +static int write_data(FILE *f, void *data, const size_t length) { + size_t items; + uint32_t len; + + len = length; + if ((items = write_uint(f, len)) <= 0) + return -1; + + items = fwrite(data, length, 1, f); + + if (ferror(f) || items != 1) + return -1; + + return 0; +} + +static int write_entry(FILE *f, const entry *e) { + pa_assert(f); + pa_assert(e); + + if (write_data(f, e->key.data, e->key.size) < 0) + return -1; + if (write_data(f, e->data.data, e->data.size) < 0) + return -1; + + return 0; +} + +int pa_database_sync(pa_database *database) { + simple_data *db = (simple_data*)database; + FILE *f; + void *state; + entry *e; + + pa_assert(db); + + if (db->read_only) + return 0; + + errno = 0; + + f = fopen(db->tmp_filename, "w"); + + if (!f) + goto fail; + + state = NULL; + while((e = pa_hashmap_iterate(db->map, &state, NULL))) { + if (write_entry(f, e) < 0) { + pa_log_warn("error while writing to file. %s", pa_cstrerror(errno)); + goto fail; + } + } + + fclose(f); + f = NULL; + + if (rename(db->tmp_filename, db->filename) < 0) { + pa_log_warn("error while renaming file. %s", pa_cstrerror(errno)); + goto fail; + } + + return 0; + +fail: + if (f) + fclose(f); + return -1; +} -- cgit From fd32fee4488b1e06d0a64079485aa77f0c87164b Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Mon, 6 Jul 2009 17:50:51 +0300 Subject: bluetooth: don't call pa_sink_render with 0 bytes request --- src/modules/bluetooth/module-bluetooth-device.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 93b14a12..d9831854 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -1319,18 +1319,21 @@ static void thread_func(void *userdata) { if (u->write_index > 0 && audio_to_send > MAX_PLAYBACK_CATCH_UP_USEC) { pa_usec_t skip_usec; uint64_t skip_bytes; - pa_memchunk tmp; skip_usec = audio_to_send - MAX_PLAYBACK_CATCH_UP_USEC; skip_bytes = pa_usec_to_bytes(skip_usec, &u->sample_spec); - pa_log_warn("Skipping %llu us (= %llu bytes) in audio stream", - (unsigned long long) skip_usec, - (unsigned long long) skip_bytes); + if (skip_bytes > 0) { + pa_memchunk tmp; - pa_sink_render_full(u->sink, skip_bytes, &tmp); - pa_memblock_unref(tmp.memblock); - u->write_index += skip_bytes; + pa_log_warn("Skipping %llu us (= %llu bytes) in audio stream", + (unsigned long long) skip_usec, + (unsigned long long) skip_bytes); + + pa_sink_render_full(u->sink, skip_bytes, &tmp); + pa_memblock_unref(tmp.memblock); + u->write_index += skip_bytes; + } } do_write = 1; -- cgit From 3ecb80e19ab9aa678b7db6a5068553d956d707fa Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Mon, 20 Jul 2009 13:44:27 +0300 Subject: bluetooth: fix typo with service_{read,write}_type --- src/modules/bluetooth/module-bluetooth-device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index d9831854..5f119c7a 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -1739,7 +1739,8 @@ static void shutdown_bt(struct userdata *u) { if (u->service_fd >= 0) { pa_close(u->service_fd); u->service_fd = -1; - u->service_write_type = u->service_write_type = 0; + u->service_write_type = 0; + u->service_read_type = 0; } if (u->write_memchunk.memblock) { @@ -1755,7 +1756,8 @@ static int init_bt(struct userdata *u) { shutdown_bt(u); u->stream_write_type = 0; - u->service_write_type = u->service_write_type = 0; + u->service_write_type = 0; + u->service_read_type = 0; if ((u->service_fd = bt_audio_service_open()) < 0) { pa_log_error("Couldn't connect to bluetooth audio service"); -- 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') 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 0c08dbd9b926ec94084dd47069627ed6eda1c1d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 03:41:13 +0200 Subject: core: introduce pa_{sink|source}_update_flags() --- src/pulsecore/sink.c | 22 +++++++++++++++++++++- src/pulsecore/sink.h | 2 ++ src/pulsecore/source.c | 18 ++++++++++++++++-- src/pulsecore/source.h | 2 ++ 4 files changed, 41 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index c1589f2d..c79aa79d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -551,7 +551,7 @@ static void sink_free(pa_object *o) { pa_xfree(s); } -/* Called from main context */ +/* Called from main context, and not while the IO thread is active, please */ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { pa_sink_assert_ref(s); pa_assert_ctl_context(); @@ -562,6 +562,26 @@ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { pa_source_set_asyncmsgq(s->monitor_source, q); } +/* Called from main context, and not while the IO thread is active, please */ +void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t value) { + pa_sink_assert_ref(s); + pa_assert_ctl_context(); + + if (mask == 0) + return; + + /* For now, allow only a minimal set of flags to be changed. */ + pa_assert((mask & ~(PA_SINK_DYNAMIC_LATENCY|PA_SINK_LATENCY)) == 0); + + s->flags = (s->flags & ~mask) | (value & mask); + + pa_source_update_flags(s->monitor_source, + ((mask & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) | + ((mask & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0), + ((value & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) | + ((value & PA_SINK_DYNAMIC_LATENCY) ? PA_SINK_DYNAMIC_LATENCY : 0)); +} + /* Called from IO context, or before _put() from main context */ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) { pa_sink_assert_ref(s); diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 55bca7f4..3cd7e59d 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -282,6 +282,8 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume); void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume); void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted); +void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t value); + pa_bool_t pa_device_init_description(pa_proplist *p); pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink); pa_bool_t pa_device_init_intended_roles(pa_proplist *p); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 8970d8e4..46f049ef 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -461,7 +461,7 @@ static void source_free(pa_object *o) { pa_xfree(s); } -/* Called from main context */ +/* Called from main context, and not while the IO thread is active, please */ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { pa_source_assert_ref(s); pa_assert_ctl_context(); @@ -469,7 +469,21 @@ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { s->asyncmsgq = q; } -/* Called from main context */ +/* Called from main context, and not while the IO thread is active, please */ +void pa_source_update_flags(pa_source *s, pa_source_flags_t mask, pa_source_flags_t value) { + pa_source_assert_ref(s); + pa_assert_ctl_context(); + + if (mask == 0) + return; + + /* For now, allow only a minimal set of flags to be changed. */ + pa_assert((mask & ~(PA_SOURCE_DYNAMIC_LATENCY|PA_SOURCE_LATENCY)) == 0); + + s->flags = (s->flags & ~mask) | (value & mask); +} + +/* Called from IO context, or before _put() from main context */ void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) { pa_source_assert_ref(s); pa_source_assert_io_context(s); diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index bb085a0b..6f33de06 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -246,6 +246,8 @@ void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted); int pa_source_sync_suspend(pa_source *s); +void pa_source_update_flags(pa_source *s, pa_source_flags_t mask, pa_source_flags_t value); + /*** May be called by everyone, from main context */ /* The returned value is supposed to be in the time domain of the sound card! */ -- cgit From e5b08a81d23d94c668fdfabc4c6c196e14640869 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 03:42:16 +0200 Subject: ladspa/remap: sync latency flags from master sink when moving between sinks --- src/modules/module-ladspa-sink.c | 1 + src/modules/module-remap-sink.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 3c6e3495..f2d53d00 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -391,6 +391,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { pa_assert_se(u = i->userdata); pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); + pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); } int pa__init(pa_module*m) { diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 7b4c9bbb..0b4fdc9b 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -303,6 +303,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { pa_assert_se(u = i->userdata); pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); + pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); } int pa__init(pa_module*m) { -- cgit From 0c20e740f64bac462463552c0b7e056848b78836 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 22:22:57 +0200 Subject: asyncmsgq: introduce pa_asyncmsgq_dispatching() --- src/pulsecore/asyncmsgq.c | 6 ++++++ src/pulsecore/asyncmsgq.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'src') diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c index 36721406..b0804f79 100644 --- a/src/pulsecore/asyncmsgq.c +++ b/src/pulsecore/asyncmsgq.c @@ -351,3 +351,9 @@ void pa_asyncmsgq_flush(pa_asyncmsgq *a, pa_bool_t run) { pa_asyncmsgq_unref(a); } } + +pa_bool_t pa_asyncmsgq_dispatching(pa_asyncmsgq *a) { + pa_assert(PA_REFCNT_VALUE(a) > 0); + + return !!a->current; +} diff --git a/src/pulsecore/asyncmsgq.h b/src/pulsecore/asyncmsgq.h index 26f528f6..1085c2f0 100644 --- a/src/pulsecore/asyncmsgq.h +++ b/src/pulsecore/asyncmsgq.h @@ -78,4 +78,6 @@ int pa_asyncmsgq_write_fd(pa_asyncmsgq *q); void pa_asyncmsgq_write_before_poll(pa_asyncmsgq *a); void pa_asyncmsgq_write_after_poll(pa_asyncmsgq *a); +pa_bool_t pa_asyncmsgq_dispatching(pa_asyncmsgq *a); + #endif -- cgit From 011add1c838f65e87a7abaec2792f510d3b0bb20 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 22:23:42 +0200 Subject: thread-mq: do final q flush only when we aren't dispatching anyway --- src/pulsecore/thread-mq.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c index ec67ae87..73997a74 100644 --- a/src/pulsecore/thread-mq.c +++ b/src/pulsecore/thread-mq.c @@ -59,7 +59,7 @@ static void asyncmsgq_read_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io pa_memchunk chunk; /* Check whether there is a message for us to process */ - while (pa_asyncmsgq_get(aq, &object, &code, &data, &offset, &chunk, 0) == 0) { + while (pa_asyncmsgq_get(aq, &object, &code, &data, &offset, &chunk, 0) >= 0) { int ret; ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk); @@ -107,9 +107,11 @@ void pa_thread_mq_done(pa_thread_mq *q) { /* Since we are called from main context we can be sure that the * inq is empty. However, the outq might still contain messages * for the main loop, which we need to dispatch (e.g. release - * msgs, other stuff). Hence do so. */ + * msgs, other stuff). Hence do so if we aren't currently + * dispatching anyway. */ - pa_asyncmsgq_flush(q->outq, TRUE); + if (!pa_asyncmsgq_dispatching(q->outq)) + pa_asyncmsgq_flush(q->outq, TRUE); q->mainloop->io_free(q->read_event); q->mainloop->io_free(q->write_event); -- cgit From 5c90cf2d6a148d5450b4d05edfc98d32ae83a854 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 22:24:13 +0200 Subject: bluetooth: drop PA_BT_AUDIO_STATE_LAST since it is unused and we normally call that _MAX anyway --- src/modules/bluetooth/bluetooth-util.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h index 265caf40..f15f2170 100644 --- a/src/modules/bluetooth/bluetooth-util.h +++ b/src/modules/bluetooth/bluetooth-util.h @@ -59,8 +59,7 @@ typedef enum pa_bt_audio_state { PA_BT_AUDIO_STATE_DISCONNECTED, PA_BT_AUDIO_STATE_CONNECTING, PA_BT_AUDIO_STATE_CONNECTED, - PA_BT_AUDIO_STATE_PLAYING, - PA_BT_AUDIO_STATE_LAST + PA_BT_AUDIO_STATE_PLAYING } pa_bt_audio_state_t; struct pa_bluetooth_device { -- cgit From fa52a91b1a1d89e0a99faeea821d3e1a3597eb9a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 22:25:21 +0200 Subject: bluetooth: recognize only those BT devices that implement both the Audio and either AudioSink or Headset interfaces --- src/modules/bluetooth/bluetooth-util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index 66e1c31e..d5806b96 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -122,9 +122,9 @@ static pa_bool_t device_is_audio(pa_bluetooth_device *d) { return d->device_info_valid && - (d->audio_state != PA_BT_AUDIO_STATE_INVALID || - d->audio_sink_state != PA_BT_AUDIO_STATE_INVALID || - d->headset_state != PA_BT_AUDIO_STATE_INVALID); + (d->audio_state != PA_BT_AUDIO_STATE_INVALID && + (d->audio_sink_state != PA_BT_AUDIO_STATE_INVALID || + d->headset_state != PA_BT_AUDIO_STATE_INVALID)); } static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessageIter *i) { -- cgit From de4968cdded8d78fe2e59b4487a21937b843c570 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 22:25:53 +0200 Subject: bluetooth: ask first for Headset and AudioSink properties, followed by Audio --- src/modules/bluetooth/bluetooth-util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index d5806b96..16c29248 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -226,10 +226,6 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device node = uuid_new(value); PA_LLIST_PREPEND(pa_bluetooth_uuid, d->uuids, node); - /* this might eventually be racy if .Audio is not there yet, but the State change will come anyway later, so this call is for cold-detection mostly */ - pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Audio", "GetProperties")); - send_and_add_to_pending(y, d, m, get_properties_reply); - /* Vudentz said the interfaces are here when the UUIDs are announced */ if (strcasecmp(HSP_HS_UUID, value) == 0 || strcasecmp(HFP_HS_UUID, value) == 0) { pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Headset", "GetProperties")); @@ -239,6 +235,10 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device send_and_add_to_pending(y, d, m, get_properties_reply); } + /* this might eventually be racy if .Audio is not there yet, but the State change will come anyway later, so this call is for cold-detection mostly */ + pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Audio", "GetProperties")); + send_and_add_to_pending(y, d, m, get_properties_reply); + if (!dbus_message_iter_next(&ai)) break; } -- cgit From 2a39663ab61614982c52e244bde596dcc1a08f37 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Aug 2009 00:43:22 +0200 Subject: bluetooth: move installation of mq's earlier to avoid context asserts to be triggered --- src/modules/bluetooth/module-bluetooth-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 5f119c7a..d6321fc4 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -1262,11 +1262,11 @@ static void thread_func(void *userdata) { if (u->core->realtime_scheduling) pa_make_realtime(u->core->realtime_priority); + pa_thread_mq_install(&u->thread_mq); + if (start_stream_fd(u) < 0) goto fail; - pa_thread_mq_install(&u->thread_mq); - for (;;) { struct pollfd *pollfd; int ret; -- cgit From 4c29ba9c332dd682ced5ed668aede16aa5861128 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Aug 2009 00:45:23 +0200 Subject: modules: add various checks to avoid selecting objects that are not linked or in another unclear state --- src/modules/module-intended-roles.c | 54 +++++++++++++++++++++++++++++++------ src/modules/module-rescue-streams.c | 6 +++++ src/modules/module-stream-restore.c | 18 +++++++++++++ src/pulsecore/namereg.c | 30 +++++++++++++++------ 4 files changed, 92 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/modules/module-intended-roles.c b/src/modules/module-intended-roles.c index c697209a..b9924dfd 100644 --- a/src/modules/module-intended-roles.c +++ b/src/modules/module-intended-roles.c @@ -127,6 +127,9 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n if (s == def) continue; + if (!PA_SINK_IS_LINKED(pa_sink_get_state(s))) + continue; + if (role_match(s->proplist, role)) { new_data->sink = s; new_data->save_sink = FALSE; @@ -173,6 +176,9 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou if (s == def) continue; + if (!PA_SOURCE_IS_LINKED(pa_source_get_state(s))) + continue; + if (role_match(s->proplist, role)) { new_data->source = s; new_data->save_source = FALSE; @@ -201,6 +207,17 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->save_sink) continue; + /* Skip this if it is already in the process of being moved + * anyway */ + if (!si->sink) + continue; + + /* It might happen that a stream and a sink are set up at the + same time, in which case we want to make sure we don't + interfere with that */ + if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si))) + continue; + if (!(role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE))) continue; @@ -237,6 +254,17 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, if (so->direct_on_input) continue; + /* Skip this if it is already in the process of being moved + * anyway */ + if (!so->source) + continue; + + /* It might happen that a stream and a source are set up at the + same time, in which case we want to make sure we don't + interfere with that */ + if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so))) + continue; + if (!(role = pa_proplist_gets(so->proplist, PA_PROP_MEDIA_ROLE))) continue; @@ -275,24 +303,28 @@ static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, str uint32_t jdx; pa_sink *d; + if (!si->sink) + continue; + if (!(role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE))) continue; /* Would the default sink fit? If so, let's use it */ - if (def != sink && role_match(def->proplist, role)) { - pa_sink_input_move_to(si, def, FALSE); - continue; - } + if (def != sink && role_match(def->proplist, role)) + if (pa_sink_input_move_to(si, def, FALSE) >= 0) + continue; /* Try to find some other fitting sink */ PA_IDXSET_FOREACH(d, c->sinks, jdx) { if (d == def || d == sink) continue; - if (role_match(d->proplist, role)) { - pa_sink_input_move_to(si, d, FALSE); - break; - } + if (!PA_SINK_IS_LINKED(pa_sink_get_state(d))) + continue; + + if (role_match(d->proplist, role)) + if (pa_sink_input_move_to(si, d, FALSE) >= 0) + break; } } @@ -325,6 +357,9 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc if (so->direct_on_input) continue; + if (!so->source) + continue; + if (!(role = pa_proplist_gets(so->proplist, PA_PROP_MEDIA_ROLE))) continue; @@ -339,6 +374,9 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc if (d == def || d == source) continue; + if (!PA_SOURCE_IS_LINKED(pa_source_get_state(d))) + continue; + if (role_match(d->proplist, role) && !source->monitor_of == !d->monitor_of) { pa_source_output_move_to(so, d, FALSE); break; diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 82f693f9..722d84b2 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -71,6 +71,9 @@ static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip if (target == skip) continue; + if (!PA_SINK_IS_LINKED(pa_sink_get_state(target))) + continue; + if (pa_sink_input_may_move_to(i, target)) return target; } @@ -159,6 +162,9 @@ static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_sou if (!target->monitor_of != !skip->monitor_of) continue; + if (!PA_SOURCE_IS_LINKED(pa_source_get_state(target))) + continue; + if (pa_source_output_may_move_to(o, target)) return target; } diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 727a5275..e560bd28 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -540,6 +540,11 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct if (si->save_sink) continue; + /* Skip this if it is already in the process of being moved + * anyway */ + if (!si->sink) + continue; + /* It might happen that a stream and a sink are set up at the same time, in which case we want to make sure we don't interfere with that */ @@ -584,6 +589,10 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, if (so->direct_on_input) continue; + /* Skip this if it is already in the process of being moved anyway */ + if (!so->source) + continue; + /* It might happen that a stream and a sink are set up at the same time, in which case we want to make sure we don't interfere with that */ @@ -623,6 +632,9 @@ static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, str char *name; struct entry *e; + if (!si->sink) + continue; + if (!(name = get_name(si->proplist, "sink-input"))) continue; @@ -663,6 +675,12 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc char *name; struct entry *e; + if (so->direct_on_input) + continue; + + if (!so->source) + continue; + if (!(name = get_name(so->proplist, "source-output"))) continue; diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index 9df2f583..e26923d4 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -223,6 +223,9 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type) { pa_sink* pa_namereg_set_default_sink(pa_core*c, pa_sink *s) { pa_assert(c); + if (s && !PA_SINK_IS_LINKED(pa_sink_get_state(s))) + return NULL; + if (c->default_sink != s) { c->default_sink = s; pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); @@ -234,6 +237,9 @@ pa_sink* pa_namereg_set_default_sink(pa_core*c, pa_sink *s) { pa_source* pa_namereg_set_default_source(pa_core*c, pa_source *s) { pa_assert(c); + if (s && !PA_SOURCE_IS_LINKED(pa_source_get_state(s))) + return NULL; + if (c->default_source != s) { c->default_source = s; pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); @@ -244,14 +250,19 @@ pa_source* pa_namereg_set_default_source(pa_core*c, pa_source *s) { pa_sink *pa_namereg_get_default_sink(pa_core *c) { pa_sink *s; + uint32_t idx; pa_assert(c); - if (c->default_sink) + if (c->default_sink && PA_SINK_IS_LINKED(pa_sink_get_state(c->default_sink))) return c->default_sink; - if ((s = pa_idxset_first(c->sinks, NULL))) - return pa_namereg_set_default_sink(c, s); + /* FIXME: the selection here should be based priority values on + * the sinks */ + + PA_IDXSET_FOREACH(s, c->sinks, idx) + if (PA_SINK_IS_LINKED(pa_sink_get_state(s))) + return pa_namereg_set_default_sink(c, s); return NULL; } @@ -262,15 +273,18 @@ pa_source *pa_namereg_get_default_source(pa_core *c) { pa_assert(c); - if (c->default_source) + if (c->default_source && PA_SOURCE_IS_LINKED(pa_source_get_state(c->default_source))) return c->default_source; - for (s = PA_SOURCE(pa_idxset_first(c->sources, &idx)); s; s = PA_SOURCE(pa_idxset_next(c->sources, &idx))) - if (!s->monitor_of) + /* First, try to find one that isn't a monitor */ + PA_IDXSET_FOREACH(s, c->sources, idx) + if (!s->monitor_of && PA_SOURCE_IS_LINKED(pa_source_get_state(s))) return pa_namereg_set_default_source(c, s); - if ((s = pa_idxset_first(c->sources, NULL))) - return pa_namereg_set_default_source(c, s); + /* Then, fallback to a monitor */ + PA_IDXSET_FOREACH(s, c->sources, idx) + if (PA_SOURCE_IS_LINKED(pa_source_get_state(s))) + return pa_namereg_set_default_source(c, s); return NULL; } -- cgit From 8dd0d871a7dd2d97c63ec8e38e1b408637d1b639 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Aug 2009 00:45:56 +0200 Subject: core: add to FIXMEs --- src/pulsecore/sink-input.h | 1 + src/pulsecore/sink.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index c1820830..b5502c45 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -42,6 +42,7 @@ typedef enum pa_sink_input_state { PA_SINK_INPUT_RUNNING, /*< The stream is alive and kicking */ PA_SINK_INPUT_CORKED, /*< The stream was corked on user request */ PA_SINK_INPUT_UNLINKED /*< The stream is dead */ + /* FIXME: we need a state for MOVING here */ } pa_sink_input_state_t; static inline pa_bool_t PA_SINK_INPUT_IS_LINKED(pa_sink_input_state_t x) { diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index c79aa79d..717584f2 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -307,6 +307,7 @@ pa_sink* pa_sink_new( s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY; s->thread_info.fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY; + /* FIXME: This should probably be moved to pa_sink_put() */ pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0); if (s->card) -- cgit From 01e4b61a910afdd21f860fadbe98075735c2bf51 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Aug 2009 02:02:51 +0200 Subject: aupdate: implicitly call _write_swap() if it wasn't called explicitly --- src/pulsecore/aupdate.c | 8 ++++++++ src/pulsecore/aupdate.h | 4 ++++ 2 files changed, 12 insertions(+) (limited to 'src') diff --git a/src/pulsecore/aupdate.c b/src/pulsecore/aupdate.c index 56ebb8e5..85b6e00e 100644 --- a/src/pulsecore/aupdate.c +++ b/src/pulsecore/aupdate.c @@ -39,6 +39,7 @@ struct pa_aupdate { pa_atomic_t read_lock; pa_mutex *write_lock; pa_semaphore *semaphore; + pa_bool_t swapped; }; pa_aupdate *pa_aupdate_new(void) { @@ -101,6 +102,8 @@ unsigned pa_aupdate_write_begin(pa_aupdate *a) { n = (unsigned) pa_atomic_load(&a->read_lock); + a->swapped = FALSE; + return !WHICH(n); } @@ -119,11 +122,16 @@ unsigned pa_aupdate_write_swap(pa_aupdate *a) { break; } + a->swapped = TRUE; + return WHICH(n); } void pa_aupdate_write_end(pa_aupdate *a) { pa_assert(a); + if (!a->swapped) + pa_aupdate_write_swap(a); + pa_mutex_unlock(a->write_lock); } diff --git a/src/pulsecore/aupdate.h b/src/pulsecore/aupdate.h index 072e382d..fb38ffa2 100644 --- a/src/pulsecore/aupdate.h +++ b/src/pulsecore/aupdate.h @@ -93,6 +93,10 @@ unsigned pa_aupdate_write_swap(pa_aupdate *a); * pa_update_write_end(a) * } * + * In some cases keeping both structures up-to-date might not be + * necessary, since they are fully rebuilt on each iteration + * anyway. In that case you may leave the _write_swap() call out, it + * will then be done implicitly in the _write_end() invocation. */ #endif -- 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/map-file | 1 + src/pulse/volume.c | 18 ++++++++++++++++++ src/pulse/volume.h | 5 +++++ 3 files changed, 24 insertions(+) (limited to 'src') diff --git a/src/map-file b/src/map-file index c6c8acca..4f20c48f 100644 --- a/src/map-file +++ b/src/map-file @@ -130,6 +130,7 @@ pa_cvolume_get_position; pa_cvolume_init; pa_cvolume_max; pa_cvolume_max_mask; +pa_cvolume_merge; pa_cvolume_remap; pa_cvolume_scale; pa_cvolume_scale_mask; 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 c579cb56e941e759b71b393eae1bc98d5deb8a1b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 03:41:14 +0200 Subject: reserver: update from upstream git --- src/modules/reserve-monitor.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/modules/reserve-monitor.c b/src/modules/reserve-monitor.c index 13ecde2b..97cb9b9e 100644 --- a/src/modules/reserve-monitor.c +++ b/src/modules/reserve-monitor.c @@ -38,6 +38,7 @@ struct rm_monitor { char *device_name; char *service_name; + char *match; DBusConnection *connection; @@ -51,6 +52,13 @@ struct rm_monitor { #define SERVICE_PREFIX "org.freedesktop.ReserveDevice1." +#define SERVICE_FILTER \ + "type='signal'," \ + "sender='" DBUS_SERVICE_DBUS "'," \ + "interface='" DBUS_INTERFACE_DBUS "'," \ + "member='NameOwnerChanged'," \ + "arg0='%s'" + static DBusHandlerResult filter_handler( DBusConnection *c, DBusMessage *s, @@ -175,11 +183,13 @@ int rm_watch( m->filtering = 1; - dbus_bus_add_match(m->connection, - "type='signal'," - "sender='" DBUS_SERVICE_DBUS "'," - "interface='" DBUS_INTERFACE_DBUS "'," - "member='NameOwnerChanged'", error); + if (!(m->match = malloc(sizeof(SERVICE_FILTER) - 2 + strlen(m->service_name)))) { + r = -ENOMEM; + goto fail; + } + + sprintf(m->match, SERVICE_FILTER, m->service_name); + dbus_bus_add_match(m->connection, m->match, error); if (dbus_error_is_set(error)) { r = -EIO; @@ -220,10 +230,8 @@ void rm_release(rm_monitor *m) { if (m->matching) dbus_bus_remove_match( m->connection, - "type='signal'," - "sender='" DBUS_SERVICE_DBUS "'," - "interface='" DBUS_INTERFACE_DBUS "'," - "member='NameOwnerChanged'", NULL); + m->match, + NULL); if (m->filtering) dbus_connection_remove_filter( @@ -233,6 +241,7 @@ void rm_release(rm_monitor *m) { free(m->device_name); free(m->service_name); + free(m->match); if (m->connection) dbus_connection_unref(m->connection); -- 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') 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') 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') 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') 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') 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 90a07435d3a1c5660ebb4bac571267a62187ea2e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 03:51:17 +0200 Subject: bluetooth: make NameOwnerChanged filter matches more focussed --- src/modules/bluetooth/bluetooth-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index 16c29248..b8eb5c9d 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -758,7 +758,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) { if (pa_dbus_add_matches( pa_dbus_connection_get(y->connection), &err, - "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'", + "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg='org.bluez'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'", @@ -809,7 +809,7 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) { if (y->connection) { pa_dbus_remove_matches(pa_dbus_connection_get(y->connection), - "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'", + "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg='org.bluez'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", -- cgit From 319d187972f792568e37af92726b3f25e708cbbc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 19:14:35 +0200 Subject: bluetooth: fix match syntax --- src/modules/bluetooth/bluetooth-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index b8eb5c9d..f576823d 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -758,7 +758,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) { if (pa_dbus_add_matches( pa_dbus_connection_get(y->connection), &err, - "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg='org.bluez'", + "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='org.bluez'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'", @@ -809,7 +809,7 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) { if (y->connection) { pa_dbus_remove_matches(pa_dbus_connection_get(y->connection), - "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg='org.bluez'", + "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='org.bluez'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", -- cgit From fe3a21f6a5958a6e54d5bcf7c162767cfdf5f9db Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 19:15:33 +0200 Subject: macro: add PA_ROUND_UP/PA_ROUND_DOWN macros --- src/pulsecore/macro.h | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index cf662510..aa06359a 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -91,7 +91,8 @@ static inline size_t pa_page_align(size_t l) { #ifdef __GNUC__ #define PA_MAX(a,b) \ - __extension__ ({ typeof(a) _a = (a); \ + __extension__ ({ \ + typeof(a) _a = (a); \ typeof(b) _b = (b); \ _a > _b ? _a : _b; \ }) @@ -101,7 +102,8 @@ static inline size_t pa_page_align(size_t l) { #ifdef __GNUC__ #define PA_MIN(a,b) \ - __extension__ ({ typeof(a) _a = (a); \ + __extension__ ({ \ + typeof(a) _a = (a); \ typeof(b) _b = (b); \ _a < _b ? _a : _b; \ }) @@ -111,7 +113,8 @@ static inline size_t pa_page_align(size_t l) { #ifdef __GNUC__ #define PA_CLAMP(x, low, high) \ - __extension__ ({ typeof(x) _x = (x); \ + __extension__ ({ \ + typeof(x) _x = (x); \ typeof(low) _low = (low); \ typeof(high) _high = (high); \ ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \ @@ -122,7 +125,8 @@ static inline size_t pa_page_align(size_t l) { #ifdef __GNUC__ #define PA_CLAMP_UNLIKELY(x, low, high) \ - __extension__ ({ typeof(x) _x = (x); \ + __extension__ ({ \ + typeof(x) _x = (x); \ typeof(low) _low = (low); \ typeof(high) _high = (high); \ (PA_UNLIKELY(_x > _high) ? _high : (PA_UNLIKELY(_x < _low) ? _low : _x)); \ @@ -135,6 +139,28 @@ static inline size_t pa_page_align(size_t l) { * make sense: we cannot know if it is more likely that the values is * lower or greater than the boundaries.*/ +#ifdef __GNUC__ +#define PA_ROUND_UP(a, b) \ + __extension__ ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + ((_a + _b - 1) / _b) * _b; \ + }) +#else +#define PA_ROUND_UP(a, b) ((((a) + (b) - 1) / (b)) * (b)) +#endif + +#ifdef __GNUC__ +#define PA_ROUND_DOWN(a, b) \ + __extension__ ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + (_a / _b) * _b; \ + }) +#else +#define PA_ROUND_DOWN(a, b) (((a) / (b)) * (b)) +#endif + /* This type is not intended to be used in exported APIs! Use classic "int" there! */ #ifdef HAVE_STD_BOOL typedef _Bool pa_bool_t; -- cgit From 8f928b2e572cd7bf26517afddd62ceecb78edfdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 17 Aug 2009 19:17:10 +0200 Subject: macro: simplify page/word alignment macros a bit --- src/pulsecore/macro.h | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index aa06359a..3c560bc6 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -59,28 +59,24 @@ #endif /* Rounds down */ -static inline void* pa_align_ptr(const void *p) { - return (void*) (((size_t) p) & ~(sizeof(void*)-1)); +static inline void* PA_ALIGN_PTR(const void *p) { + return (void*) (((size_t) p) & ~(sizeof(void*) - 1)); } -#define PA_ALIGN_PTR(x) (pa_align_ptr(x)) /* Rounds up */ -static inline size_t pa_align(size_t l) { - return (((l + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*)); +static inline size_t PA_ALIGN(size_t l) { + return ((l + sizeof(void*) - 1) & ~(sizeof(void*) - 1)); } -#define PA_ALIGN(x) (pa_align(x)) /* Rounds down */ -static inline void* pa_page_align_ptr(const void *p) { - return (void*) (((size_t) p) & ~(PA_PAGE_SIZE-1)); +static inline void* PA_PAGE_ALIGN_PTR(const void *p) { + return (void*) (((size_t) p) & ~(PA_PAGE_SIZE - 1)); } -#define PA_PAGE_ALIGN_PTR(x) (pa_page_align_ptr(x)) /* Rounds up */ -static inline size_t pa_page_align(size_t l) { - return ((l + PA_PAGE_SIZE - 1) / PA_PAGE_SIZE) * PA_PAGE_SIZE; +static inline size_t PA_PAGE_ALIGN(size_t l) { + return (l + PA_PAGE_SIZE - 1) & ~(PA_PAGE_SIZE - 1); } -#define PA_PAGE_ALIGN(x) (pa_page_align(x)) #define PA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) -- 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/map-file | 2 ++ src/pulse/volume.c | 41 +++++++++++++++++++++++++++++++++++++++-- src/pulse/volume.h | 10 ++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/map-file b/src/map-file index 4f20c48f..d6122a4a 100644 --- a/src/map-file +++ b/src/map-file @@ -131,6 +131,8 @@ pa_cvolume_init; pa_cvolume_max; pa_cvolume_max_mask; pa_cvolume_merge; +pa_cvolume_min; +pa_cvolume_min_mask; pa_cvolume_remap; pa_cvolume_scale; pa_cvolume_scale_mask; 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') 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') 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 2223a9f9384ca76691f85d0faf4cdd72924f0976 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 00:59:23 +0200 Subject: dbus: never return DBUS_HANDLER_RESULT_HANDLED in filter callbacks, since other callbacks might stell want to have the messages --- src/modules/module-console-kit.c | 2 -- src/modules/module-hal-detect.c | 3 --- 2 files changed, 5 deletions(-) (limited to 'src') diff --git a/src/modules/module-console-kit.c b/src/modules/module-console-kit.c index a666073c..103f5c48 100644 --- a/src/modules/module-console-kit.c +++ b/src/modules/module-console-kit.c @@ -187,7 +187,6 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo } add_session(u, path); - return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_signal(message, "org.freedesktop.ConsoleKit.Seat", "SessionRemoved")) { @@ -202,7 +201,6 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo } remove_session(u, path); - return DBUS_HANDLER_RESULT_HANDLED; } finish: diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index ec370d61..6034d0ee 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -623,8 +623,6 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo } - return DBUS_HANDLER_RESULT_HANDLED; - } else if (dbus_message_is_signal(message, "org.pulseaudio.Server", "DirtyGiveUpMessage")) { /* We use this message to avoid a dirty race condition when we get an ACLAdded message before the previously owning PA @@ -668,7 +666,6 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo /* Yes, we don't check the UDI for validity, but hopefully HAL will */ device_added_cb(u->context, udi); - return DBUS_HANDLER_RESULT_HANDLED; } finish: -- cgit From a69b7294145e7dfed6ede8e3d8aa01d7e8509142 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 01:02:32 +0200 Subject: voltest: extend test to verify correctness of _multiply() and _divide() --- src/modules/reserve-monitor.c | 24 +----------------------- src/modules/reserve.c | 25 +------------------------ src/tests/voltest.c | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/modules/reserve-monitor.c b/src/modules/reserve-monitor.c index 97cb9b9e..ab453e61 100644 --- a/src/modules/reserve-monitor.c +++ b/src/modules/reserve-monitor.c @@ -64,7 +64,6 @@ static DBusHandlerResult filter_handler( DBusMessage *s, void *userdata) { - DBusMessage *reply; rm_monitor *m; DBusError error; @@ -105,31 +104,10 @@ static DBusHandlerResult filter_handler( } } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - invalid: - if (!(reply = dbus_message_new_error( - s, - DBUS_ERROR_INVALID_ARGS, - "Invalid arguments"))) - goto oom; - - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - dbus_error_free(&error); - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } int rm_watch( diff --git a/src/modules/reserve.c b/src/modules/reserve.c index 5597f177..b4c168cf 100644 --- a/src/modules/reserve.c +++ b/src/modules/reserve.c @@ -291,7 +291,6 @@ static DBusHandlerResult filter_handler( DBusMessage *m, void *userdata) { - DBusMessage *reply; rd_device *d; DBusError error; @@ -323,35 +322,13 @@ static DBusHandlerResult filter_handler( rd_release(d); } - return DBUS_HANDLER_RESULT_HANDLED; } } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - invalid: - if (!(reply = dbus_message_new_error( - m, - DBUS_ERROR_INVALID_ARGS, - "Invalid arguments"))) - goto oom; - - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } diff --git a/src/tests/voltest.c b/src/tests/voltest.c index 64aec5c6..551f7ecd 100644 --- a/src/tests/voltest.c +++ b/src/tests/voltest.c @@ -33,6 +33,8 @@ int main(int argc, char *argv[]) { pa_cvolume cv; float b; pa_channel_map map; + pa_volume_t md = 0; + unsigned mdn = 0; printf("Attenuation of sample 1 against 32767: %g dB\n", 20.0*log10(1.0/32767.0)); printf("Smallest possible attenutation > 0 applied to 32767: %li\n", lrint(32767.0*pa_sw_volume_to_linear(1))); @@ -85,16 +87,48 @@ int main(int argc, char *argv[]) { printf("After: volume: [%s]; balance: %2.1f (intended: %2.1f) %s\n", pa_cvolume_snprint(s, sizeof(s), &r), k, b, k < b-.05 || k > b+.5 ? "MISMATCH" : ""); } - for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 1) { + for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 51) { double l = pa_sw_volume_to_linear(v); pa_volume_t k = pa_sw_volume_from_linear(l); double db = pa_sw_volume_to_dB(v); pa_volume_t r = pa_sw_volume_from_dB(db); + pa_volume_t w; pa_assert(k == v); pa_assert(r == v); + + for (w = PA_VOLUME_MUTED; w < PA_VOLUME_NORM*2; w += 37) { + + double t = pa_sw_volume_to_linear(w); + double db2 = pa_sw_volume_to_dB(w); + pa_volume_t p, p1, p2; + double q, qq; + + p = pa_sw_volume_multiply(v, w); + qq = db + db2; + p2 = pa_sw_volume_from_dB(qq); + q = l*t; + p1 = pa_sw_volume_from_linear(q); + + if (p2 > p && p2 - p > md) + md = p2 - p; + if (p2 < p && p - p2 > md) + md = p - p2; + if (p1 > p && p1 - p > md) + md = p1 - p; + if (p1 < p && p - p1 > md) + md = p - p1; + + if (p1 != p || p2 != p) + mdn++; + } } + printf("max deviation: %lu n=%lu\n", (unsigned long) md, (unsigned long) mdn); + + pa_assert(md <= 1); + pa_assert(mdn <= 251); + return 0; } -- cgit From 2838b78e59ee7c8ea42fec6880cc4c2b2a2c9485 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 01:03:09 +0200 Subject: macro: extend comments a bit --- src/pulsecore/macro.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index 3c560bc6..ce88c1b9 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -80,10 +80,10 @@ static inline size_t PA_PAGE_ALIGN(size_t l) { #define PA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) -/* The users of PA_MIN and PA_MAX should be aware that these macros on - * non-GCC executed code with side effects twice. It is thus - * considered misuse to use code with side effects as arguments to MIN - * and MAX. */ +/* The users of PA_MIN and PA_MAX, PA_CLAMP, PA_ROUND_UP should be + * aware that these macros on non-GCC executed code with side effects + * twice. It is thus considered misuse to use code with side effects + * as arguments to MIN and MAX. */ #ifdef __GNUC__ #define PA_MAX(a,b) \ -- cgit From 24e582808c18d6866d8c10f8f0320b1af0ab758b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 01:35:43 +0200 Subject: source: rework volume handling - drop the 'virtual_' prefix from s->virtual_volume since we don't distuingish between reference and real volumes for sources - introduce an accuracy for source volumes: if the hardware can control the volume "close enough" don't necessarily adjust the rest in software unless it is beyond a certain threshold. This should save a little bit of CPU at the expensive of a bit of accuracy in volume handling. - other minor cleanups --- src/modules/alsa/alsa-source.c | 37 +++++++++++++------- src/modules/bluetooth/module-bluetooth-device.c | 4 +-- src/modules/oss/module-oss.c | 8 ++--- src/pulsecore/source.c | 45 ++++++++++++++----------- src/pulsecore/source.h | 2 +- 5 files changed, 57 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 9a51f857..7da37553 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -65,6 +65,8 @@ #define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */ #define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms */ +#define VOLUME_ACCURACY (PA_VOLUME_NORM/100) + struct userdata { pa_core *core; pa_module *module; @@ -987,15 +989,11 @@ static void source_get_volume_cb(pa_source *s) { if (pa_cvolume_equal(&u->hardware_volume, &r)) return; - s->virtual_volume = u->hardware_volume = r; - - if (u->mixer_path->has_dB) { - pa_cvolume reset; + s->volume = u->hardware_volume = r; - /* Hmm, so the hardware volume changed, let's reset our software volume */ - pa_cvolume_reset(&reset, s->sample_spec.channels); - pa_source_set_soft_volume(s, &reset); - } + /* Hmm, so the hardware volume changed, let's reset our software volume */ + if (u->mixer_path->has_dB) + pa_source_set_soft_volume(s, NULL); } static void source_set_volume_cb(pa_source *s) { @@ -1008,7 +1006,7 @@ static void source_set_volume_cb(pa_source *s) { pa_assert(u->mixer_handle); /* Shift up by the base volume */ - pa_sw_cvolume_divide_scalar(&r, &s->virtual_volume, s->base_volume); + pa_sw_cvolume_divide_scalar(&r, &s->volume, s->base_volume); if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &r) < 0) return; @@ -1019,13 +1017,26 @@ static void source_set_volume_cb(pa_source *s) { u->hardware_volume = r; if (u->mixer_path->has_dB) { + pa_cvolume new_soft_volume; + pa_bool_t accurate_enough; /* Match exactly what the user requested by software */ - pa_sw_cvolume_divide(&s->soft_volume, &s->virtual_volume, &u->hardware_volume); + pa_sw_cvolume_divide(&new_soft_volume, &s->volume, &u->hardware_volume); + + /* If the adjustment to do in software is only minimal we + * can skip it. That saves us CPU at the expense of a bit of + * accuracy */ + accurate_enough = + (pa_cvolume_min(&new_soft_volume) >= (PA_VOLUME_NORM - VOLUME_ACCURACY)) && + (pa_cvolume_max(&new_soft_volume) <= (PA_VOLUME_NORM + VOLUME_ACCURACY)); - pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->virtual_volume)); + pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->volume)); pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &u->hardware_volume)); - pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->soft_volume)); + pa_log_debug("Calculated software volume: %s (accurate-enough=%s)", pa_cvolume_snprint(t, sizeof(t), &new_soft_volume), + pa_yes_no(accurate_enough)); + + if (!accurate_enough) + s->soft_volume = new_soft_volume; } else { pa_log_debug("Wrote hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &r)); @@ -1033,7 +1044,7 @@ static void source_set_volume_cb(pa_source *s) { /* We can't match exactly what the user requested, hence let's * at least tell the user about it */ - s->virtual_volume = r; + s->volume = r; } } diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index d6321fc4..395ec838 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -1500,12 +1500,12 @@ static void source_set_volume_cb(pa_source *s) { if (u->profile != PROFILE_HSP) return; - gain = (pa_cvolume_max(&s->virtual_volume) * 15) / PA_VOLUME_NORM; + gain = (pa_cvolume_max(&s->volume) * 15) / PA_VOLUME_NORM; if (gain > 15) gain = 15; - pa_cvolume_set(&s->virtual_volume, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15)); + pa_cvolume_set(&s->volume, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15)); pa_assert_se(m = dbus_message_new_method_call("org.bluez", u->path, "org.bluez.Headset", "SetMicrophoneGain")); pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID)); diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c index c44b882b..0848d43b 100644 --- a/src/modules/oss/module-oss.c +++ b/src/modules/oss/module-oss.c @@ -848,11 +848,11 @@ static void source_get_volume(pa_source *s) { pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); if (u->mixer_devmask & SOUND_MASK_IGAIN) - if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->virtual_volume) >= 0) + if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume) >= 0) return; if (u->mixer_devmask & SOUND_MASK_RECLEV) - if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->virtual_volume) >= 0) + if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume) >= 0) return; pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); @@ -866,11 +866,11 @@ static void source_set_volume(pa_source *s) { pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); if (u->mixer_devmask & SOUND_MASK_IGAIN) - if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->virtual_volume) >= 0) + if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume) >= 0) return; if (u->mixer_devmask & SOUND_MASK_RECLEV) - if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->virtual_volume) >= 0) + if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume) >= 0) return; pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 46f049ef..8aa07f5e 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -181,7 +181,7 @@ pa_source* pa_source_new( pa_cvolume_reset(&data->volume, data->sample_spec.channels); pa_return_null_if_fail(pa_cvolume_valid(&data->volume)); - pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec)); if (!data->muted_is_set) data->muted = FALSE; @@ -219,7 +219,7 @@ pa_source* pa_source_new( s->n_corked = 0; s->monitor_of = NULL; - s->virtual_volume = data->volume; + s->volume = data->volume; pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels); s->base_volume = PA_VOLUME_NORM; s->n_volume_steps = PA_VOLUME_NORM+1; @@ -751,31 +751,32 @@ pa_usec_t pa_source_get_latency_within_thread(pa_source *s) { } /* Called from main thread */ -void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save) { - pa_cvolume old_virtual_volume; - pa_bool_t virtual_volume_changed; +void pa_source_set_volume( + pa_source *s, + const pa_cvolume *volume, + pa_bool_t save) { + + pa_bool_t real_changed; pa_source_assert_ref(s); pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); - pa_assert(volume); pa_assert(pa_cvolume_valid(volume)); pa_assert(pa_cvolume_compatible(volume, &s->sample_spec)); - old_virtual_volume = s->virtual_volume; - s->virtual_volume = *volume; - virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume); - s->save_volume = (!virtual_volume_changed && s->save_volume) || save; + real_changed = !pa_cvolume_equal(volume, &s->volume); + s->volume = *volume; + s->save_volume = (!real_changed && s->save_volume) || save; if (s->set_volume) { pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels); s->set_volume(s); } else - s->soft_volume = s->virtual_volume; + s->soft_volume = s->volume; pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0); - if (virtual_volume_changed) + if (real_changed) pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } @@ -783,12 +784,16 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) { pa_source_assert_ref(s); pa_assert_ctl_context(); - pa_assert(volume); + + if (!volume) + pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels); + else + s->soft_volume = *volume; if (PA_SOURCE_IS_LINKED(s->state)) pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0); else - s->thread_info.soft_volume = *volume; + s->thread_info.soft_volume = s->soft_volume; } /* Called from main thread */ @@ -798,20 +803,22 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) { pa_assert(PA_SOURCE_IS_LINKED(s->state)); if (s->refresh_volume || force_refresh) { - pa_cvolume old_virtual_volume = s->virtual_volume; + pa_cvolume old_volume; + + old_volume = s->volume; if (s->get_volume) s->get_volume(s); pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0); - if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) { + if (!pa_cvolume_equal(&old_volume, &s->volume)) { s->save_volume = TRUE; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } } - return &s->virtual_volume; + return &s->volume; } /* Called from main thread */ @@ -822,10 +829,10 @@ void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) { /* The source implementor may call this if the volume changed to make sure everyone is notified */ - if (pa_cvolume_equal(&s->virtual_volume, new_volume)) + if (pa_cvolume_equal(&s->volume, new_volume)) return; - s->virtual_volume = *new_volume; + s->volume = *new_volume; s->save_volume = TRUE; pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 6f33de06..7b3e4953 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -79,7 +79,7 @@ struct pa_source { pa_volume_t base_volume; /* shall be constant */ unsigned n_volume_steps; /* shall be constant */ - pa_cvolume virtual_volume, soft_volume; + pa_cvolume volume, soft_volume; pa_bool_t muted:1; pa_bool_t refresh_volume:1; -- cgit From d6f598ab3e1cdb71dc3b408592d06bba23f53a71 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 02:29:59 +0200 Subject: udev: allow passing of ignore_dB= parameter to alsa modules --- src/modules/alsa/alsa-sink.c | 37 ++++++++++++++++--------- src/modules/bluetooth/module-bluetooth-device.c | 4 +-- src/modules/module-lirc.c | 4 +-- src/modules/module-udev-detect.c | 27 ++++++++++++++---- 4 files changed, 49 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index a91b4b8a..12538368 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -68,6 +68,8 @@ #define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- Sleep at least 10ms on each iteration */ #define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms -- Wakeup at least this long before the buffer runs empty*/ +#define VOLUME_ACCURACY (PA_VOLUME_NORM/100) /* don't require volume adjustments to be perfectly correct. don't necessarily extend granularity in software unless the differences get greater than this level */ + struct userdata { pa_core *core; pa_module *module; @@ -1034,15 +1036,11 @@ static void sink_get_volume_cb(pa_sink *s) { if (pa_cvolume_equal(&u->hardware_volume, &r)) return; - s->virtual_volume = u->hardware_volume = r; - - if (u->mixer_path->has_dB) { - pa_cvolume reset; + s->real_volume = u->hardware_volume = r; - /* Hmm, so the hardware volume changed, let's reset our software volume */ - pa_cvolume_reset(&reset, s->sample_spec.channels); - pa_sink_set_soft_volume(s, &reset); - } + /* Hmm, so the hardware volume changed, let's reset our software volume */ + if (u->mixer_path->has_dB) + pa_sink_set_soft_volume(s, NULL); } static void sink_set_volume_cb(pa_sink *s) { @@ -1055,7 +1053,7 @@ static void sink_set_volume_cb(pa_sink *s) { pa_assert(u->mixer_handle); /* Shift up by the base volume */ - pa_sw_cvolume_divide_scalar(&r, &s->virtual_volume, s->base_volume); + pa_sw_cvolume_divide_scalar(&r, &s->real_volume, s->base_volume); if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &r) < 0) return; @@ -1066,13 +1064,26 @@ static void sink_set_volume_cb(pa_sink *s) { u->hardware_volume = r; if (u->mixer_path->has_dB) { + pa_cvolume new_soft_volume; + pa_bool_t accurate_enough; /* Match exactly what the user requested by software */ - pa_sw_cvolume_divide(&s->soft_volume, &s->virtual_volume, &u->hardware_volume); + pa_sw_cvolume_divide(&new_soft_volume, &s->real_volume, &u->hardware_volume); + + /* If the adjustment to do in software is only minimal we + * can skip it. That saves us CPU at the expense of a bit of + * accuracy */ + accurate_enough = + (pa_cvolume_min(&new_soft_volume) >= (PA_VOLUME_NORM - VOLUME_ACCURACY)) && + (pa_cvolume_max(&new_soft_volume) <= (PA_VOLUME_NORM + VOLUME_ACCURACY)); - pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->virtual_volume)); + pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->real_volume)); pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &u->hardware_volume)); - pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->soft_volume)); + pa_log_debug("Calculated software volume: %s (accurate-enough=%s)", pa_cvolume_snprint(t, sizeof(t), &new_soft_volume), + pa_yes_no(accurate_enough)); + + if (!accurate_enough) + s->soft_volume = new_soft_volume; } else { pa_log_debug("Wrote hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &r)); @@ -1080,7 +1091,7 @@ static void sink_set_volume_cb(pa_sink *s) { /* We can't match exactly what the user requested, hence let's * at least tell the user about it */ - s->virtual_volume = r; + s->real_volume = r; } } diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 395ec838..4e23862c 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -1476,12 +1476,12 @@ static void sink_set_volume_cb(pa_sink *s) { if (u->profile != PROFILE_HSP) return; - gain = (pa_cvolume_max(&s->virtual_volume) * 15) / PA_VOLUME_NORM; + gain = (pa_cvolume_max(&s->real_volume) * 15) / PA_VOLUME_NORM; if (gain > 15) gain = 15; - pa_cvolume_set(&s->virtual_volume, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15)); + pa_cvolume_set(&s->real_volume, u->sample_spec.channels, (pa_volume_t) (gain * PA_VOLUME_NORM / 15)); pa_assert_se(m = dbus_message_new_method_call("org.bluez", u->path, "org.bluez.Headset", "SetSpeakerGain")); pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID)); diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index 06efeb8f..2bb8014d 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -133,7 +133,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event cv.values[i] = PA_VOLUME_MAX; } - pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE, TRUE); + pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case DOWN: @@ -144,7 +144,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event cv.values[i] = PA_VOLUME_MUTED; } - pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE, TRUE); + pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case MUTE: diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index 11de1ccb..0b30fd54 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -39,6 +39,9 @@ PA_MODULE_AUTHOR("Lennart Poettering"); PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE( + "tsched= " + "ignore_dB="); struct device { char *path; @@ -50,7 +53,9 @@ struct device { struct userdata { pa_core *core; pa_hashmap *devices; - pa_bool_t use_tsched; + + pa_bool_t use_tsched:1; + pa_bool_t ignore_dB:1; struct udev* udev; struct udev_monitor *monitor; @@ -62,6 +67,7 @@ struct userdata { static const char* const valid_modargs[] = { "tsched", + "ignore_dB", NULL }; @@ -140,12 +146,14 @@ static void card_changed(struct userdata *u, struct udev_device *dev) { args = pa_sprintf_malloc("device_id=\"%s\" " "name=\"%s\" " "card_name=\"%s\" " - "tsched=%i " + "tsched=%s " + "ignore_dB=%s " "card_properties=\"module-udev-detect.discovered=1\"", path_get_card_id(path), n, card_name, - (int) u->use_tsched); + pa_yes_no(u->use_tsched), + pa_yes_no(u->ignore_dB)); pa_log_debug("Loading module-alsa-card with arguments '%s'", args); m = pa_module_load(u->core, "module-alsa-card", args); @@ -364,6 +372,7 @@ int pa__init(pa_module *m) { struct udev_enumerate *enumerate = NULL; struct udev_list_entry *item = NULL, *first = NULL; int fd; + pa_bool_t use_tsched = TRUE, ignore_dB = FALSE; pa_assert(m); @@ -375,13 +384,19 @@ int pa__init(pa_module *m) { m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - u->use_tsched = TRUE; u->inotify_fd = -1; - if (pa_modargs_get_value_boolean(ma, "tsched", &u->use_tsched) < 0) { - pa_log("Failed to parse tsched argument."); + if (pa_modargs_get_value_boolean(ma, "tsched", &use_tsched) < 0) { + pa_log("Failed to parse tsched= argument."); + goto fail; + } + u->use_tsched = use_tsched; + + if (pa_modargs_get_value_boolean(ma, "ignore_dB", &ignore_dB) < 0) { + pa_log("Failed to parse ignore_dB= argument."); goto fail; } + u->ignore_dB = ignore_dB; if (!(u->udev = udev_new())) { pa_log("Failed to initialize udev library."); -- 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') 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/map-file | 2 ++ src/pulse/volume.c | 34 ++++++++++++++++++++++++++++++++++ src/pulse/volume.h | 8 ++++++++ 3 files changed, 44 insertions(+) (limited to 'src') diff --git a/src/map-file b/src/map-file index d6122a4a..95b2803a 100644 --- a/src/map-file +++ b/src/map-file @@ -123,10 +123,12 @@ pa_cvolume_avg_mask; pa_cvolume_channels_equal_to; pa_cvolume_compatible; pa_cvolume_compatible_with_channel_map; +pa_cvolume_dec; pa_cvolume_equal; pa_cvolume_get_balance; pa_cvolume_get_fade; pa_cvolume_get_position; +pa_cvolume_inc; pa_cvolume_init; pa_cvolume_max; pa_cvolume_max_mask; 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 5207e191424675df74059aaf30f9b1292a05cb5d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 02:37:35 +0200 Subject: match: document how broken the module-match logic is --- src/modules/module-match.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 625f2a8b..14e01127 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -243,6 +243,9 @@ int pa__init(pa_module*m) { if (load_rules(u, pa_modargs_get_value(ma, "table", NULL)) < 0) goto fail; + /* FIXME: Doing this asynchronously is just broken. This needs to + * use a hook! */ + u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); pa_modargs_free(ma); -- cgit From 8c31974f56ebbbfc1a4978150026acf77c32689e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 02:55:02 +0200 Subject: sink: volume handling rework, new flat volume logic - We now implement a logic where the sink maintains two distinct volumes: the 'reference' volume which is shown to the users, and the 'real' volume, which is configured to the hardware. The latter is configured to the max of all streams. Volume changes on sinks are propagated back to the streams proportional to the reference volume change. Volume changes on sink inputs are forwarded to the sink by 'pushing' the volume if necessary. This renames the old 'virtual_volume' to 'real_volume'. The 'reference_volume' is now the one exposed to users. By this logic the sink volume visible to the user, will always be the "upper" boundary for everything that is played. Saved/restored stream volumes are measured relative to this boundary, the factor here is always < 1.0. - introduce accuracy for sink volumes, similar to the accuracy we already have for source volumes. - other cleanups. --- src/modules/alsa/alsa-sink.c | 2 +- src/modules/module-device-restore.c | 2 +- src/modules/module-lirc.c | 2 +- src/modules/module-match.c | 2 +- src/modules/module-mmkbd-evdev.c | 6 +- src/modules/module-tunnel.c | 4 +- src/modules/oss/module-oss.c | 8 +- src/modules/raop/module-raop-sink.c | 6 +- src/pulsecore/cli-command.c | 4 +- src/pulsecore/cli-text.c | 6 +- src/pulsecore/core.h | 1 - src/pulsecore/protocol-native.c | 4 +- src/pulsecore/sink-input.c | 164 ++++++---------- src/pulsecore/sink-input.h | 15 +- src/pulsecore/sink.c | 381 +++++++++++++++++++++++------------- src/pulsecore/sink.h | 12 +- 16 files changed, 333 insertions(+), 286 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 12538368..e3707ae7 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1009,7 +1009,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { return 0; if (mask & SND_CTL_EVENT_MASK_VALUE) { - pa_sink_get_volume(u->sink, TRUE, FALSE); + pa_sink_get_volume(u->sink, TRUE); pa_sink_get_mute(u->sink, TRUE); } diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c index 120b762c..da6c9666 100644 --- a/src/modules/module-device-restore.c +++ b/src/modules/module-device-restore.c @@ -218,7 +218,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (sink->save_volume) { entry.channel_map = sink->channel_map; - entry.volume = *pa_sink_get_volume(sink, FALSE, TRUE); + entry.volume = *pa_sink_get_volume(sink, FALSE); entry.volume_valid = TRUE; } diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index 2bb8014d..fdfdc797 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -120,7 +120,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event pa_log("Failed to get sink '%s'", u->sink_name); else { int i; - pa_cvolume cv = *pa_sink_get_volume(s, FALSE, FALSE); + pa_cvolume cv = *pa_sink_get_volume(s, FALSE); #define DELTA (PA_VOLUME_NORM/20) diff --git a/src/modules/module-match.c b/src/modules/module-match.c index 14e01127..0bd781d2 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -216,7 +216,7 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v pa_cvolume cv; pa_log_debug("changing volume of sink input '%s' to 0x%03x", n, r->volume); pa_cvolume_set(&cv, si->sample_spec.channels, r->volume); - pa_sink_input_set_volume(si, &cv, TRUE, TRUE); + pa_sink_input_set_volume(si, &cv, TRUE, FALSE); } } } diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index b30fae51..7be48700 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -102,7 +102,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event pa_log("Failed to get sink '%s'", u->sink_name); else { int i; - pa_cvolume cv = *pa_sink_get_volume(s, FALSE, FALSE); + pa_cvolume cv = *pa_sink_get_volume(s, FALSE); #define DELTA (PA_VOLUME_NORM/20) @@ -115,7 +115,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event cv.values[i] = PA_VOLUME_MAX; } - pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE, TRUE); + pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case DOWN: @@ -126,7 +126,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event cv.values[i] = PA_VOLUME_MUTED; } - pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE, TRUE); + pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case MUTE_TOGGLE: diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index eaccea4e..5ccb81d0 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1162,7 +1162,7 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag pa_assert(u->sink); if ((u->version < 11 || !!mute == !!u->sink->muted) && - pa_cvolume_equal(&volume, &u->sink->virtual_volume)) + pa_cvolume_equal(&volume, &u->sink->real_volume)) return; pa_sink_volume_changed(u->sink, &volume); @@ -1763,7 +1763,7 @@ static void sink_set_volume(pa_sink *sink) { pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); pa_tagstruct_putu32(t, tag = u->ctag++); pa_tagstruct_putu32(t, u->device_index); - pa_tagstruct_put_cvolume(t, &sink->virtual_volume); + pa_tagstruct_put_cvolume(t, &sink->real_volume); pa_pstream_send_tagstruct(u->pstream, t); } diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c index 0848d43b..71536260 100644 --- a/src/modules/oss/module-oss.c +++ b/src/modules/oss/module-oss.c @@ -812,11 +812,11 @@ static void sink_get_volume(pa_sink *s) { pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM)); if (u->mixer_devmask & SOUND_MASK_VOLUME) - if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0) + if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->real_volume) >= 0) return; if (u->mixer_devmask & SOUND_MASK_PCM) - if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->virtual_volume) >= 0) + if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->real_volume) >= 0) return; pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); @@ -830,11 +830,11 @@ static void sink_set_volume(pa_sink *s) { pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM)); if (u->mixer_devmask & SOUND_MASK_VOLUME) - if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0) + if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->real_volume) >= 0) return; if (u->mixer_devmask & SOUND_MASK_PCM) - if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->virtual_volume) >= 0) + if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->real_volume) >= 0) return; pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); diff --git a/src/modules/raop/module-raop-sink.c b/src/modules/raop/module-raop-sink.c index 9699132d..ac48ab10 100644 --- a/src/modules/raop/module-raop-sink.c +++ b/src/modules/raop/module-raop-sink.c @@ -283,15 +283,15 @@ static void sink_set_volume_cb(pa_sink *s) { /* Calculate the max volume of all channels. We'll use this as our (single) volume on the APEX device and emulate any variation in channel volumes in software */ - v = pa_cvolume_max(&s->virtual_volume); + v = pa_cvolume_max(&s->real_volume); /* Create a pa_cvolume version of our single value */ pa_cvolume_set(&hw, s->sample_spec.channels, v); /* Perform any software manipulation of the volume needed */ - pa_sw_cvolume_divide(&s->soft_volume, &s->virtual_volume, &hw); + pa_sw_cvolume_divide(&s->soft_volume, &s->real_volume, &hw); - pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->virtual_volume)); + pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->real_volume)); pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &hw)); pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->soft_volume)); diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index e2c3c066..6ec74647 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -530,7 +530,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu } pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); - pa_sink_set_volume(sink, &cvolume, TRUE, TRUE, TRUE, TRUE); + pa_sink_set_volume(sink, &cvolume, TRUE, TRUE); return 0; } @@ -1586,7 +1586,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b nl = 1; } - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE, TRUE))); + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE))); pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, FALSE))); pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED)); } diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index a5530991..c7a178d6 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -262,10 +262,10 @@ char *pa_sink_list_to_string(pa_core *c) { sink->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "", sink->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "", sink->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "", - pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE, FALSE)), + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)), sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "", - sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE, FALSE)) : "", - pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE, FALSE), &sink->channel_map), + sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE)) : "", + pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE), &sink->channel_map), pa_volume_snprint(v, sizeof(v), sink->base_volume), sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "", sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "", diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index e7abd61b..f6ec7122 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -83,7 +83,6 @@ typedef enum pa_core_hook { PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL, PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED, PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED, - PA_CORE_HOOK_SINK_INPUT_SET_VOLUME, PA_CORE_HOOK_SINK_INPUT_SEND_EVENT, PA_CORE_HOOK_SOURCE_OUTPUT_NEW, PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE, diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 280707e2..b1285e15 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2840,7 +2840,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin PA_TAG_SAMPLE_SPEC, &fixed_ss, PA_TAG_CHANNEL_MAP, &sink->channel_map, PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE, FALSE), + PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE), PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE), PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL, @@ -3388,7 +3388,7 @@ static void command_set_volume( if (sink) { pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name); - pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE, TRUE); + pa_sink_set_volume(sink, &volume, TRUE, TRUE); } else if (source) { pa_log_debug("Client %s changes volume of sink %s.", client_name, source->name); pa_source_set_volume(source, &volume, TRUE); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index f6d9ac73..a29334f9 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -47,6 +47,7 @@ static PA_DEFINE_CHECK_TYPE(pa_sink_input, pa_msgobject); static void sink_input_free(pa_object *o); +static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v); pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) { pa_assert(data); @@ -270,18 +271,20 @@ int pa_sink_input_new( i->channel_map = data->channel_map; if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !data->volume_is_absolute) { + pa_cvolume remapped; + /* When the 'absolute' bool is not set then we'll treat the volume * as relative to the sink volume even in flat volume mode */ - - pa_cvolume v = data->sink->reference_volume; - pa_cvolume_remap(&v, &data->sink->channel_map, &data->channel_map); - pa_sw_cvolume_multiply(&i->virtual_volume, &data->volume, &v); + remapped = data->sink->reference_volume; + pa_cvolume_remap(&remapped, &data->sink->channel_map, &data->channel_map); + pa_sw_cvolume_multiply(&i->volume, &data->volume, &remapped); } else - i->virtual_volume = data->volume; + i->volume = data->volume; i->volume_factor = data->volume_factor; - pa_cvolume_init(&i->soft_volume); - memset(i->relative_volume, 0, sizeof(i->relative_volume)); + i->real_ratio = i->reference_ratio = data->volume; + pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels); + pa_cvolume_reset(&i->real_ratio, i->sample_spec.channels); i->save_volume = data->save_volume; i->save_sink = data->save_sink; i->save_muted = data->save_muted; @@ -445,11 +448,8 @@ void pa_sink_input_unlink(pa_sink_input *i) { if (linked && i->sink) { /* We might need to update the sink's volume if we are in flat volume mode. */ - if (i->sink->flags & PA_SINK_FLAT_VOLUME) { - pa_cvolume new_volume; - pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE); - } + if (i->sink->flags & PA_SINK_FLAT_VOLUME) + pa_sink_set_volume(i->sink, NULL, FALSE, FALSE); if (i->sink->asyncmsgq) pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL) == 0); @@ -526,12 +526,10 @@ void pa_sink_input_put(pa_sink_input *i) { i->state = state; /* We might need to update the sink's volume if we are in flat volume mode. */ - if (i->sink->flags & PA_SINK_FLAT_VOLUME) { - pa_cvolume new_volume; - pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE); - } else - pa_sink_input_set_relative_volume(i, &i->virtual_volume); + if (i->sink->flags & PA_SINK_FLAT_VOLUME) + pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume); + else + set_real_ratio(i, &i->volume); i->thread_info.soft_volume = i->soft_volume; i->thread_info.muted = i->muted; @@ -909,6 +907,27 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) { return i->thread_info.requested_sink_latency; } +/* Called from main context */ +static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) { + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); + pa_assert(!v || pa_cvolume_compatible(v, &i->sample_spec)); + + /* This basically calculates: + * + * i->real_ratio := v + * i->soft_volume := i->real_ratio * i->volume_factor */ + + if (v) + i->real_ratio = *v; + else + pa_cvolume_reset(&i->real_ratio, i->sample_spec.channels); + + pa_sw_cvolume_multiply(&i->soft_volume, &i->real_ratio, &i->volume_factor); + /* We don't copy the data to the thread_info data. That's left for someone else to do */ +} + /* Called from main context */ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute) { pa_cvolume v; @@ -926,29 +945,24 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo volume = pa_sw_cvolume_multiply(&v, &v, volume); } - if (pa_cvolume_equal(volume, &i->virtual_volume)) + if (pa_cvolume_equal(volume, &i->volume)) { + i->save_volume = i->save_volume || save; return; + } - i->virtual_volume = *volume; + i->volume = *volume; i->save_volume = save; - if (i->sink->flags & PA_SINK_FLAT_VOLUME) { - pa_cvolume new_volume; - + if (i->sink->flags & PA_SINK_FLAT_VOLUME) /* We are in flat volume mode, so let's update all sink input * volumes and update the flat volume of the sink */ - pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE, FALSE, FALSE); - - } else { + pa_sink_set_volume(i->sink, NULL, TRUE, save); + else { /* OK, we are in normal volume mode. The volume only affects * ourselves */ - pa_sink_input_set_relative_volume(i, volume); - - /* Hooks have the ability to play games with i->soft_volume */ - pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i); + set_real_ratio(i, volume); /* Copy the new soft_volume to the thread_info struct */ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0); @@ -964,67 +978,14 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bo pa_assert_ctl_context(); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) { - pa_cvolume v = i->sink->reference_volume; - pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map); - pa_sw_cvolume_divide(volume, &i->virtual_volume, &v); - } else - *volume = i->virtual_volume; + if (absolute || !(i->sink->flags & PA_SINK_FLAT_VOLUME)) + *volume = i->volume; + else + *volume = i->reference_ratio; return volume; } -/* Called from main context */ -pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) { - unsigned c; - - pa_sink_input_assert_ref(i); - pa_assert_ctl_context(); - pa_assert(v); - pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - - /* This always returns the relative volume. Converts the float - * version into a pa_cvolume */ - - v->channels = i->sample_spec.channels; - - for (c = 0; c < v->channels; c++) - v->values[c] = pa_sw_volume_from_linear(i->relative_volume[c]); - - return v; -} - -/* Called from main context */ -void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v) { - unsigned c; - pa_cvolume _v; - - pa_sink_input_assert_ref(i); - pa_assert_ctl_context(); - pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - pa_assert(!v || pa_cvolume_compatible(v, &i->sample_spec)); - - if (!v) - v = pa_cvolume_reset(&_v, i->sample_spec.channels); - - /* This basically calculates: - * - * i->relative_volume := v - * i->soft_volume := i->relative_volume * i->volume_factor */ - - i->soft_volume.channels = i->sample_spec.channels; - - for (c = 0; c < i->sample_spec.channels; c++) { - i->relative_volume[c] = pa_sw_volume_to_linear(v->values[c]); - - i->soft_volume.values[c] = pa_sw_volume_from_linear( - i->relative_volume[c] * - pa_sw_volume_to_linear(i->volume_factor.values[c])); - } - - /* We don't copy the data to the thread_info data. That's left for someone else to do */ -} - /* Called from main context */ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) { pa_sink_input_assert_ref(i); @@ -1198,20 +1159,10 @@ int pa_sink_input_start_move(pa_sink_input *i) { if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED) pa_assert_se(i->sink->n_corked-- >= 1); - if (i->sink->flags & PA_SINK_FLAT_VOLUME) { - pa_cvolume new_volume; - - /* Make the virtual volume relative */ - pa_sink_input_get_relative_volume(i, &i->virtual_volume); - - /* And reset the the relative volume */ - pa_sink_input_set_relative_volume(i, NULL); - + if (i->sink->flags & PA_SINK_FLAT_VOLUME) /* We might need to update the sink's volume if we are in flat * volume mode. */ - pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE); - } + pa_sink_set_volume(i->sink, NULL, FALSE, FALSE); pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0); @@ -1295,16 +1246,15 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { pa_sink_update_status(dest); if (i->sink->flags & PA_SINK_FLAT_VOLUME) { - pa_cvolume new_volume; + pa_cvolume remapped; - /* Make relative volume absolute again */ - pa_cvolume t = dest->reference_volume; - pa_cvolume_remap(&t, &dest->channel_map, &i->channel_map); - pa_sw_cvolume_multiply(&i->virtual_volume, &i->virtual_volume, &t); + /* Make relative volumes absolute */ + remapped = dest->reference_volume; + pa_cvolume_remap(&remapped, &dest->channel_map, &i->channel_map); + pa_sw_cvolume_multiply(&i->volume, &i->reference_ratio, &remapped); /* We might need to update the sink's volume if we are in flat volume mode. */ - pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE); + pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume); } pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index b5502c45..ea0f8c0e 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -94,10 +94,12 @@ struct pa_sink_input { pa_sink_input *sync_prev, *sync_next; /* Also see http://pulseaudio.org/wiki/InternalVolumes */ - pa_cvolume virtual_volume; /* The volume clients are informed about */ - pa_cvolume volume_factor; /* An internally used volume factor that can be used by modules to apply effects and suchlike without having that visible to the outside */ - double relative_volume[PA_CHANNELS_MAX]; /* The calculated volume relative to the sink volume as linear factors. */ - pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through. Usually calculated as relative_volume * volume_factor */ + pa_cvolume volume; /* The volume clients are informed about */ + pa_cvolume reference_ratio; /* The ratio of the stream's volume to the sink's reference volume */ + pa_cvolume real_ratio; /* The ratio of the stream's volume to the sink's real volume */ + pa_cvolume volume_factor; /* An internally used volume factor that can be used by modules to apply effects and suchlike without having that visible to the outside */ + pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through. Usually calculated as real_ratio * volume_factor */ + pa_bool_t muted:1; /* if TRUE then the source we are connected to and/or the volume @@ -325,8 +327,6 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency); void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute); pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute); -pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v); - void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save); pa_bool_t pa_sink_input_get_mute(pa_sink_input *i); @@ -369,9 +369,6 @@ pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i); pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret); -/* To be used by sink.c only */ -void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v); - #define pa_sink_input_assert_io_context(s) \ pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state)) diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 717584f2..1cce8e6b 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -212,7 +212,7 @@ pa_sink* pa_sink_new( pa_cvolume_reset(&data->volume, data->sample_spec.channels); pa_return_null_if_fail(pa_cvolume_valid(&data->volume)); - pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec)); if (!data->muted_is_set) data->muted = FALSE; @@ -249,7 +249,7 @@ pa_sink* pa_sink_new( s->inputs = pa_idxset_new(NULL, NULL); s->n_corked = 0; - s->reference_volume = s->virtual_volume = data->volume; + s->reference_volume = s->real_volume = data->volume; pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels); s->base_volume = PA_VOLUME_NORM; s->n_volume_steps = PA_VOLUME_NORM+1; @@ -434,6 +434,11 @@ void pa_sink_put(pa_sink* s) { if ((s->flags & PA_SINK_DECIBEL_VOLUME) && s->core->flat_volumes) s->flags |= PA_SINK_FLAT_VOLUME; + /* We assume that if the sink implementor changed the default + * volume he did so in real_volume, because that is the usual + * place where he is supposed to place his changes. */ + s->reference_volume = s->real_volume; + s->thread_info.soft_volume = s->soft_volume; s->thread_info.soft_muted = s->muted; @@ -1212,105 +1217,144 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) { return usec; } -static void compute_new_soft_volume(pa_sink_input *i, const pa_cvolume *new_volume) { - unsigned c; +/* Called from main context */ +static void compute_reference_ratios(pa_sink *s) { + uint32_t idx; + pa_sink_input *i; + + pa_sink_assert_ref(s); + pa_assert_ctl_context(); + pa_assert(PA_SINK_IS_LINKED(s->state)); + pa_assert(s->flags & PA_SINK_FLAT_VOLUME); - pa_sink_input_assert_ref(i); - pa_assert(new_volume->channels == i->sample_spec.channels); + PA_IDXSET_FOREACH(i, s->inputs, idx) { + unsigned c; + pa_cvolume remapped; - /* - * This basically calculates: - * - * i->relative_volume := i->virtual_volume / new_volume - * i->soft_volume := i->relative_volume * i->volume_factor - */ + /* + * Calculates the reference volume from the sink's reference + * volume. This basically calculates: + * + * i->reference_ratio = i->volume / s->reference_volume + */ - /* The new sink volume passed in here must already be remapped to - * the sink input's channel map! */ + remapped = s->reference_volume; + pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map); - i->soft_volume.channels = i->sample_spec.channels; + i->reference_ratio.channels = i->sample_spec.channels; - for (c = 0; c < i->sample_spec.channels; c++) + for (c = 0; c < i->sample_spec.channels; c++) { - if (new_volume->values[c] <= PA_VOLUME_MUTED) - /* We leave i->relative_volume untouched */ - i->soft_volume.values[c] = PA_VOLUME_MUTED; - else { - i->relative_volume[c] = - pa_sw_volume_to_linear(i->virtual_volume.values[c]) / - pa_sw_volume_to_linear(new_volume->values[c]); + /* We don't update when the sink volume is 0 anyway */ + if (remapped.values[c] <= PA_VOLUME_MUTED) + continue; - i->soft_volume.values[c] = pa_sw_volume_from_linear( - i->relative_volume[c] * - pa_sw_volume_to_linear(i->volume_factor.values[c])); + /* Don't update the reference ratio unless necessary */ + if (pa_sw_volume_multiply( + i->reference_ratio.values[c], + remapped.values[c]) == i->volume.values[c]) + continue; + + i->reference_ratio.values[c] = pa_sw_volume_divide( + i->volume.values[c], + remapped.values[c]); } + } +} + +/* Called from main context */ +static void compute_real_ratios(pa_sink *s) { + pa_sink_input *i; + uint32_t idx; - /* Hooks have the ability to play games with i->soft_volume */ - pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i); + pa_sink_assert_ref(s); + pa_assert_ctl_context(); + pa_assert(PA_SINK_IS_LINKED(s->state)); + pa_assert(s->flags & PA_SINK_FLAT_VOLUME); - /* We don't copy the soft_volume to the thread_info data - * here. That must be done by the caller */ + PA_IDXSET_FOREACH(i, s->inputs, idx) { + unsigned c; + pa_cvolume remapped; + + /* + * This basically calculates: + * + * i->real_ratio := i->volume / s->real_volume + * i->soft_volume := i->real_ratio * i->volume_factor + */ + + remapped = s->real_volume; + pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map); + + i->real_ratio.channels = i->sample_spec.channels; + i->soft_volume.channels = i->sample_spec.channels; + + for (c = 0; c < i->sample_spec.channels; c++) { + + if (remapped.values[c] <= PA_VOLUME_MUTED) { + /* We leave i->real_ratio untouched */ + i->soft_volume.values[c] = PA_VOLUME_MUTED; + continue; + } + + /* Don't lose accuracy unless necessary */ + if (pa_sw_volume_multiply( + i->real_ratio.values[c], + remapped.values[c]) != i->volume.values[c]) + + i->real_ratio.values[c] = pa_sw_volume_divide( + i->volume.values[c], + remapped.values[c]); + + i->soft_volume.values[c] = pa_sw_volume_multiply( + i->real_ratio.values[c], + i->volume_factor.values[c]); + } + + /* We don't copy the soft_volume to the thread_info data + * here. That must be done by the caller */ + } } /* Called from main thread */ -void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) { +static void compute_real_volume(pa_sink *s) { pa_sink_input *i; uint32_t idx; pa_sink_assert_ref(s); pa_assert_ctl_context(); - pa_assert(new_volume); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(s->flags & PA_SINK_FLAT_VOLUME); - /* This is called whenever a sink input volume changes or a sink - * input is added/removed and we might need to fix up the sink - * volume accordingly. Please note that we don't actually update - * the sinks volume here, we only return how it needs to be - * updated. The caller should then call pa_sink_set_volume().*/ + /* This determines the maximum volume of all streams and sets + * s->real_volume accordingly. */ if (pa_idxset_isempty(s->inputs)) { /* In the special case that we have no sink input we leave the * volume unmodified. */ - *new_volume = s->reference_volume; + s->real_volume = s->reference_volume; return; } - pa_cvolume_mute(new_volume, s->channel_map.channels); + pa_cvolume_mute(&s->real_volume, s->channel_map.channels); /* First let's determine the new maximum volume of all inputs * connected to this sink */ - for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) { - unsigned c; - pa_cvolume remapped_volume; - - remapped_volume = i->virtual_volume; - pa_cvolume_remap(&remapped_volume, &i->channel_map, &s->channel_map); + PA_IDXSET_FOREACH(i, s->inputs, idx) { + pa_cvolume remapped; - for (c = 0; c < new_volume->channels; c++) - if (remapped_volume.values[c] > new_volume->values[c]) - new_volume->values[c] = remapped_volume.values[c]; + remapped = i->volume; + pa_cvolume_remap(&remapped, &i->channel_map, &s->channel_map); + pa_cvolume_merge(&s->real_volume, &s->real_volume, &remapped); } - /* Then, let's update the soft volumes of all inputs connected - * to this sink */ - for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) { - pa_cvolume remapped_new_volume; - - remapped_new_volume = *new_volume; - pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map); - compute_new_soft_volume(i, &remapped_new_volume); - - /* We don't copy soft_volume to the thread_info data here - * (i.e. issue PA_SINK_INPUT_MESSAGE_SET_VOLUME) because we - * want the update to be atomically with the sink volume - * update, hence we do it within the pa_sink_set_volume() call - * below */ - } + /* Then, let's update the real ratios/soft volumes of all inputs + * connected to this sink */ + compute_real_ratios(s); } /* Called from main thread */ -void pa_sink_propagate_flat_volume(pa_sink *s) { +static void propagate_reference_volume(pa_sink *s) { pa_sink_input *i; uint32_t idx; @@ -1323,64 +1367,77 @@ void pa_sink_propagate_flat_volume(pa_sink *s) { * caused by a sink input volume change. We need to fix up the * sink input volumes accordingly */ - for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) { - pa_cvolume sink_volume, new_virtual_volume; - unsigned c; - - /* This basically calculates i->virtual_volume := i->relative_volume * s->virtual_volume */ - - sink_volume = s->virtual_volume; - pa_cvolume_remap(&sink_volume, &s->channel_map, &i->channel_map); - - for (c = 0; c < i->sample_spec.channels; c++) - new_virtual_volume.values[c] = pa_sw_volume_from_linear( - i->relative_volume[c] * - pa_sw_volume_to_linear(sink_volume.values[c])); + PA_IDXSET_FOREACH(i, s->inputs, idx) { + pa_cvolume old_volume, remapped; - new_virtual_volume.channels = i->sample_spec.channels; + old_volume = i->volume; - if (!pa_cvolume_equal(&new_virtual_volume, &i->virtual_volume)) { - i->virtual_volume = new_virtual_volume; + /* This basically calculates: + * + * i->volume := s->reference_volume * i->reference_ratio */ - /* Hmm, the soft volume might no longer actually match - * what has been chosen as new virtual volume here, - * especially when the old volume was - * PA_VOLUME_MUTED. Hence let's recalculate the soft - * volumes here. */ - compute_new_soft_volume(i, &sink_volume); + remapped = s->reference_volume; + pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map); + pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio); - /* The virtual volume changed, let's tell people so */ + /* The reference volume changed, let's tell people so */ + if (!pa_cvolume_equal(&old_volume, &i->volume)) pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); - } } - - /* If the soft_volume of any of the sink inputs got changed, let's - * make sure the thread copies are synced up. */ - pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SYNC_VOLUMES, NULL, 0, NULL) == 0); } /* Called from main thread */ -void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference, pa_bool_t save) { - pa_bool_t virtual_volume_changed; +void pa_sink_set_volume( + pa_sink *s, + const pa_cvolume *volume, + pa_bool_t sendmsg, + pa_bool_t save) { + + pa_cvolume old_reference_volume; + pa_bool_t reference_changed; pa_sink_assert_ref(s); pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); - pa_assert(volume); - pa_assert(pa_cvolume_valid(volume)); - pa_assert(pa_cvolume_compatible(volume, &s->sample_spec)); + pa_assert(!volume || pa_cvolume_valid(volume)); + pa_assert(!volume || pa_cvolume_compatible(volume, &s->sample_spec)); + pa_assert(volume || (s->flags & PA_SINK_FLAT_VOLUME)); + + /* If volume is NULL we synchronize the sink's real and reference + * volumes with the stream volumes. If it is not NULL we update + * the reference_volume with it. */ + + old_reference_volume = s->reference_volume; + + if (volume) { + + s->reference_volume = *volume; + + if (s->flags & PA_SINK_FLAT_VOLUME) { + /* OK, propagate this volume change back to the inputs */ + propagate_reference_volume(s); + + /* And now recalculate the real volume */ + compute_real_volume(s); + } else + s->real_volume = s->reference_volume; + + } else { + pa_assert(s->flags & PA_SINK_FLAT_VOLUME); + + /* Ok, let's determine the new real volume */ + compute_real_volume(s); - virtual_volume_changed = !pa_cvolume_equal(volume, &s->virtual_volume); - s->virtual_volume = *volume; - s->save_volume = (!virtual_volume_changed && s->save_volume) || save; + /* Let's 'push' the reference volume if necessary */ + pa_cvolume_merge(&s->reference_volume, &s->reference_volume, &s->real_volume); - if (become_reference) - s->reference_volume = s->virtual_volume; + /* We need to fix the reference ratios of all streams now that + * we changed the reference volume */ + compute_reference_ratios(s); + } - /* Propagate this volume change back to the inputs */ - if (virtual_volume_changed) - if (propagate && (s->flags & PA_SINK_FLAT_VOLUME)) - pa_sink_propagate_flat_volume(s); + reference_changed = !pa_cvolume_equal(&old_reference_volume, &s->reference_volume); + s->save_volume = (!reference_changed && s->save_volume) || save; if (s->set_volume) { /* If we have a function set_volume(), then we do not apply a @@ -1393,13 +1450,13 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat } else /* If we have no function set_volume(), then the soft volume * becomes the virtual volume */ - s->soft_volume = s->virtual_volume; + s->soft_volume = s->real_volume; /* This tells the sink that soft and/or virtual volume changed */ if (sendmsg) pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0); - if (virtual_volume_changed) + if (reference_changed) pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } @@ -1407,67 +1464,114 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) { pa_sink_assert_ref(s); pa_assert_ctl_context(); - pa_assert(volume); - s->soft_volume = *volume; + if (!volume) + pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels); + else + s->soft_volume = *volume; if (PA_SINK_IS_LINKED(s->state)) pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0); else - s->thread_info.soft_volume = *volume; + s->thread_info.soft_volume = s->soft_volume; } -/* Called from main thread */ -const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_bool_t reference) { +static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume) { + pa_sink_input *i; + uint32_t idx; + pa_cvolume old_reference_volume; + pa_sink_assert_ref(s); pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); - if (s->refresh_volume || force_refresh) { - struct pa_cvolume old_virtual_volume = s->virtual_volume; + /* This is called when the hardware's real volume changes due to + * some external event. We copy the real volume into our + * reference volume and then rebuild the stream volumes based on + * i->real_ratio which should stay fixed. */ - if (s->get_volume) - s->get_volume(s); + if (pa_cvolume_equal(old_real_volume, &s->real_volume)) + return; - pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0); + old_reference_volume = s->reference_volume; - if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) { + /* 1. Make the real volume the reference volume */ + s->reference_volume = s->real_volume; - s->reference_volume = s->virtual_volume; + if (s->flags & PA_SINK_FLAT_VOLUME) { - /* Something got changed in the hardware. It probably - * makes sense to save changed hw settings given that hw - * volume changes not triggered by PA are almost certainly - * done by the user. */ - s->save_volume = TRUE; + PA_IDXSET_FOREACH(i, s->inputs, idx) { + pa_cvolume old_volume, remapped; - if (s->flags & PA_SINK_FLAT_VOLUME) - pa_sink_propagate_flat_volume(s); + old_volume = i->volume; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + /* 2. Since the sink's reference and real volumes are equal + * now our ratios should be too. */ + i->reference_ratio = i->real_ratio; + + /* 3. Recalculate the new stream reference volume based on the + * reference ratio and the sink's reference volume. + * + * This basically calculates: + * + * i->volume = s->reference_volume * i->reference_ratio + * + * This is identical to propagate_reference_volume() */ + remapped = s->reference_volume; + pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map); + pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio); + + /* Notify if something changed */ + if (!pa_cvolume_equal(&old_volume, &i->volume)) + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } } - return reference ? &s->reference_volume : &s->virtual_volume; + /* Something got changed in the hardware. It probably makes sense + * to save changed hw settings given that hw volume changes not + * triggered by PA are almost certainly done by the user. */ + s->save_volume = TRUE; + + if (!pa_cvolume_equal(&old_reference_volume, &s->reference_volume)) + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } /* Called from main thread */ -void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) { +const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) { pa_sink_assert_ref(s); pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); - /* The sink implementor may call this if the volume changed to make sure everyone is notified */ - if (pa_cvolume_equal(&s->virtual_volume, new_volume)) - return; + if (s->refresh_volume || force_refresh) { + struct pa_cvolume old_real_volume; - s->reference_volume = s->virtual_volume = *new_volume; - s->save_volume = TRUE; + old_real_volume = s->real_volume; - if (s->flags & PA_SINK_FLAT_VOLUME) - pa_sink_propagate_flat_volume(s); + if (s->get_volume) + s->get_volume(s); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0); + + propagate_real_volume(s, &old_real_volume); + } + + return &s->reference_volume; +} + +/* Called from main thread */ +void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_real_volume) { + pa_cvolume old_real_volume; + + pa_sink_assert_ref(s); + pa_assert_ctl_context(); + pa_assert(PA_SINK_IS_LINKED(s->state)); + + /* The sink implementor may call this if the volume changed to make sure everyone is notified */ + + old_real_volume = s->real_volume; + s->real_volume = *new_real_volume; + + propagate_real_volume(s, &old_real_volume); } /* Called from main thread */ @@ -1516,7 +1620,6 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) { } } - return s->muted; } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 3cd7e59d..936d1c2a 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -90,9 +90,10 @@ struct pa_sink { unsigned n_volume_steps; /* shall be constant */ /* Also see http://pulseaudio.org/wiki/InternalVolumes */ - pa_cvolume virtual_volume; /* The volume clients are informed about */ - pa_cvolume reference_volume; /* The volume taken as refernce base for relative sink input volumes */ + pa_cvolume reference_volume; /* The volume exported and taken as reference base for relative sink input volumes */ + pa_cvolume real_volume; /* The volume that the hardware is configured to */ pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through */ + pa_bool_t muted:1; pa_bool_t refresh_volume:1; @@ -303,11 +304,8 @@ int pa_sink_update_status(pa_sink*s); int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause); int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause); -void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume); -void pa_sink_propagate_flat_volume(pa_sink *s); - -void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference, pa_bool_t save); -const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh, pa_bool_t reference); +void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t sendmsg, pa_bool_t save); +const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh); void pa_sink_set_mute(pa_sink *sink, pa_bool_t mute, pa_bool_t save); pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refresh); -- cgit From 2f54798b1afdbe684dd1e5ba6d39a807c6afc8d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 03:37:29 +0200 Subject: mmkbd: replace manual code by pa_cvolume_{inc|dec}() --- src/modules/module-mmkbd-evdev.c | 43 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 7be48700..516bf413 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -65,6 +65,8 @@ struct userdata { pa_module *module; }; +#define DELTA (PA_VOLUME_NORM/20) + static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; @@ -85,14 +87,27 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event } if (ev.type == EV_KEY && (ev.value == 1 || ev.value == 2)) { - enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID; + enum { + INVALID, + UP, + DOWN, + MUTE_TOGGLE + } volchange = INVALID; pa_log_debug("Key code=%u, value=%u", ev.code, ev.value); switch (ev.code) { - case KEY_VOLUMEDOWN: volchange = DOWN; break; - case KEY_VOLUMEUP: volchange = UP; break; - case KEY_MUTE: volchange = MUTE_TOGGLE; break; + case KEY_VOLUMEDOWN: + volchange = DOWN; + break; + + case KEY_VOLUMEUP: + volchange = UP; + break; + + case KEY_MUTE: + volchange = MUTE_TOGGLE; + break; } if (volchange != INVALID) { @@ -101,36 +116,20 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK))) pa_log("Failed to get sink '%s'", u->sink_name); else { - int i; pa_cvolume cv = *pa_sink_get_volume(s, FALSE); -#define DELTA (PA_VOLUME_NORM/20) - switch (volchange) { case UP: - for (i = 0; i < cv.channels; i++) { - if (cv.values[i] < PA_VOLUME_MAX - DELTA) - cv.values[i] += DELTA; - else - cv.values[i] = PA_VOLUME_MAX; - } - + pa_cvolume_inc(&cv, DELTA); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case DOWN: - for (i = 0; i < cv.channels; i++) { - if (cv.values[i] > DELTA) - cv.values[i] -= DELTA; - else - cv.values[i] = PA_VOLUME_MUTED; - } - + pa_cvolume_dec(&cv, DELTA); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case MUTE_TOGGLE: - pa_sink_set_mute(s, !pa_sink_get_mute(s, FALSE), TRUE); break; -- cgit From 7af3833b7110c08d3717edb6018350d390e9d492 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Aug 2009 03:37:42 +0200 Subject: lirc: replace manual code by pa_cvolume_{inc|dec}() --- src/modules/module-lirc.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index fdfdc797..d0e902f6 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -63,6 +63,8 @@ struct userdata { float mute_toggle_save; }; +#define DELTA (PA_VOLUME_NORM/20) + static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; char *name = NULL, *code = NULL; @@ -119,31 +121,16 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK))) pa_log("Failed to get sink '%s'", u->sink_name); else { - int i; pa_cvolume cv = *pa_sink_get_volume(s, FALSE); -#define DELTA (PA_VOLUME_NORM/20) - switch (volchange) { case UP: - for (i = 0; i < cv.channels; i++) { - if (cv.values[i] < PA_VOLUME_MAX - DELTA) - cv.values[i] += DELTA; - else - cv.values[i] = PA_VOLUME_MAX; - } - + pa_cvolume_inc(&cv, DELTA); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case DOWN: - for (i = 0; i < cv.channels; i++) { - if (cv.values[i] > DELTA) - cv.values[i] -= DELTA; - else - cv.values[i] = PA_VOLUME_MUTED; - } - + pa_cvolume_dec(&cv, DELTA); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; @@ -156,7 +143,6 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event break; case MUTE_TOGGLE: - pa_sink_set_mute(s, !pa_sink_get_mute(s, FALSE), TRUE); break; -- cgit From c5bd72509ecae1c12bb523fa56432fd71428fbf1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Aug 2009 00:20:03 +0200 Subject: core: check return value of getgrnam_r() instead of errno According to POSIX getgrnam_r() returns the error code as return value, and not in errno. Honour that. Pointed out and inspired by a patch from Ted Percival. --- src/pulsecore/core-util.c | 74 ++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 6494244e..ef8c8472 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -975,6 +975,7 @@ static int is_group(gid_t gid, const char *name) { int r = -1; #ifdef HAVE_GETGRGID_R + #ifdef _SC_GETGR_R_SIZE_MAX n = sysconf(_SC_GETGR_R_SIZE_MAX); #else @@ -985,38 +986,25 @@ static int is_group(gid_t gid, const char *name) { data = pa_xmalloc((size_t) n); + if ((errno = getgrgid_r(gid, &group, data, (size_t) n, &result)) || !result) +#else errno = 0; - if (getgrgid_r(gid, &group, data, (size_t) n, &result) < 0 || !result) { - pa_log("getgrgid_r(%u): %s", (unsigned) gid, pa_cstrerror(errno)); - + if (!(result = getgrgid(gid))) +#endif + { if (!errno) errno = ENOENT; - goto finish; - } - - r = strcmp(name, result->gr_name) == 0; - -finish: - pa_xfree(data); -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not - * support getgrgid_r. */ - - errno = 0; - if (!(result = getgrgid(gid))) { pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno)); - if (!errno) - errno = ENOENT; - goto finish; } r = strcmp(name, result->gr_name) == 0; finish: -#endif + + pa_xfree(data); return r; } @@ -1065,12 +1053,14 @@ finish: /* Check whether the specifc user id is a member of the specified group */ int pa_uid_in_group(uid_t uid, const char *name) { - char *g_buf, *p_buf; + char *g_buf = NULL, *p_buf = NULL; long g_n, p_n; - struct group grbuf, *gr; + struct group grbuf, *gr = NULL; char **i; int r = -1; +#ifdef HAVE_GETGRNAM_R + #ifdef _SC_GETGR_R_SIZE_MAX g_n = sysconf(_SC_GETGR_R_SIZE_MAX); #else @@ -1081,6 +1071,19 @@ int pa_uid_in_group(uid_t uid, const char *name) { g_buf = pa_xmalloc((size_t) g_n); + if ((errno = getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr)) != 0 || !gr) +#else + errno = 0; + if (!(gr = getgrnam(name))) +#endif + { + if (!errno) + errno = ENOENT; + goto finish; + } + +#ifdef HAVE_GETPWNAM_R + #ifdef _SC_GETPW_R_SIZE_MAX p_n = sysconf(_SC_GETPW_R_SIZE_MAX); #else @@ -1090,26 +1093,16 @@ int pa_uid_in_group(uid_t uid, const char *name) { p_n = 512; p_buf = pa_xmalloc((size_t) p_n); - - errno = 0; -#ifdef HAVE_GETGRNAM_R - if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) -#else - if (!(gr = getgrnam(name))) #endif - { - if (!errno) - errno = ENOENT; - goto finish; - } r = 0; for (i = gr->gr_mem; *i; i++) { - struct passwd pwbuf, *pw; + struct passwd pwbuf, *pw = NULL; #ifdef HAVE_GETPWNAM_R - if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) + if ((errno = getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw)) != 0 || !pw) #else + errno = 0; if (!(pw = getpwnam(*i))) #endif continue; @@ -1130,9 +1123,11 @@ finish: /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */ gid_t pa_get_gid_of_group(const char *name) { gid_t ret = (gid_t) -1; - char *g_buf; + char *g_buf = NULL; long g_n; - struct group grbuf, *gr; + struct group grbuf, *gr = NULL; + +#ifdef HAVE_GETGRNAM_R #ifdef _SC_GETGR_R_SIZE_MAX g_n = sysconf(_SC_GETGR_R_SIZE_MAX); @@ -1144,10 +1139,9 @@ gid_t pa_get_gid_of_group(const char *name) { g_buf = pa_xmalloc((size_t) g_n); - errno = 0; -#ifdef HAVE_GETGRNAM_R - if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) + if ((errno = getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr)) != 0 || !gr) #else + errno = 0; if (!(gr = getgrnam(name))) #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') 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') 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') 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 26839c4b9eb549eebf8db6eae2399ed6fd94efa8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 11 Aug 2009 15:15:57 +0200 Subject: sample-utils: split out functions from case Move the volume functions out of the switch case and use a table indexed by the sample format to find the volume function. --- src/pulsecore/sample-util.c | 586 +++++++++++++++++++++++--------------------- 1 file changed, 303 insertions(+), 283 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 5b8ccf59..ef435673 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -690,361 +690,381 @@ size_t pa_mix( return length; } +typedef struct pa_volume_funcs { + void (*u8) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*alaw) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*ulaw) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*s16ne) (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*s16re) (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*float32ne) (float *samples, float *volumes, unsigned channels, unsigned length); + void (*float32re) (float *samples, float *volumes, unsigned channels, unsigned length); + void (*s32ne) (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*s32re) (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*s24ne) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*s24re) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*s24_32ne) (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length); + void (*s24_32re) (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length); +} pa_volume_funcs; + +static void +pa_volume_u8_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) *samples - 0x80; + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); + *samples++ = (uint8_t) (t + 0x80); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} -void pa_volume_memchunk( - pa_memchunk*c, - const pa_sample_spec *spec, - const pa_cvolume *volume) { - - void *ptr; - - pa_assert(c); - pa_assert(spec); - pa_assert(c->length % pa_frame_size(spec) == 0); - pa_assert(volume); - - if (pa_memblock_is_silence(c->memblock)) - return; - - if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) - return; - - if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { - pa_silence_memchunk(c, spec); - return; - } - - ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; - - switch (spec->format) { - - case PA_SAMPLE_S16NE: { - int16_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; - - calc_linear_integer_volume(linear, volume); - - e = (int16_t*) ptr + c->length/sizeof(int16_t); - - for (channel = 0, d = ptr; d < e; d++) { - int32_t t, hi, lo; - - /* Multiplying the 32bit volume factor with the 16bit - * sample might result in an 48bit value. We want to - * do without 64 bit integers and hence do the - * multiplication independantly for the HI and LO part - * of the volume. */ - - hi = linear[channel] >> 16; - lo = linear[channel] & 0xFFFF; - - t = (int32_t)(*d); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *d = (int16_t) t; - - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - - break; - } - - case PA_SAMPLE_S16RE: { - int16_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; - - calc_linear_integer_volume(linear, volume); - - e = (int16_t*) ptr + c->length/sizeof(int16_t); - - for (channel = 0, d = ptr; d < e; d++) { - int32_t t, hi, lo; +static void +pa_volume_alaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - hi = linear[channel] >> 16; - lo = linear[channel] & 0xFFFF; + for (channel = 0; length; length--) { + int32_t t, hi, lo; - t = (int32_t) PA_INT16_SWAP(*d); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *d = PA_INT16_SWAP((int16_t) t); + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } + t = (int32_t) st_alaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3); - break; - } - - case PA_SAMPLE_S32NE: { - int32_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - calc_linear_integer_volume(linear, volume); +static void +pa_volume_ulaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - e = (int32_t*) ptr + c->length/sizeof(int32_t); + for (channel = 0; length; length--) { + int32_t t, hi, lo; - for (channel = 0, d = ptr; d < e; d++) { - int64_t t; + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; - t = (int64_t)(*d); - t = (t * linear[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *d = (int32_t) t; + t = (int32_t) st_ulaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - break; - } - - case PA_SAMPLE_S32RE: { - int32_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; - - calc_linear_integer_volume(linear, volume); - - e = (int32_t*) ptr + c->length/sizeof(int32_t); + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - for (channel = 0, d = ptr; d < e; d++) { - int64_t t; +static void +pa_volume_s16ne_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - t = (int64_t) PA_INT32_SWAP(*d); - t = (t * linear[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *d = PA_INT32_SWAP((int32_t) t); + length /= sizeof (int16_t); - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - break; - } + for (channel = 0; length; length--) { + int32_t t, hi, lo; - case PA_SAMPLE_S24NE: { - uint8_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; + /* Multiplying the 32bit volume factor with the 16bit + * sample might result in an 48bit value. We want to + * do without 64 bit integers and hence do the + * multiplication independantly for the HI and LO part + * of the volume. */ - calc_linear_integer_volume(linear, volume); + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; - e = (uint8_t*) ptr + c->length; + t = (int32_t)(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (int16_t) t; - for (channel = 0, d = ptr; d < e; d += 3) { - int64_t t; + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - t = (int64_t)((int32_t) (PA_READ24NE(d) << 8)); - t = (t * linear[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24NE(d, ((uint32_t) (int32_t) t) >> 8); +static void +pa_volume_s16re_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - break; - } + length /= sizeof (int16_t); - case PA_SAMPLE_S24RE: { - uint8_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; + for (channel = 0; length; length--) { + int32_t t, hi, lo; - calc_linear_integer_volume(linear, volume); + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; - e = (uint8_t*) ptr + c->length; + t = (int32_t) PA_INT16_SWAP(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = PA_INT16_SWAP((int16_t) t); - for (channel = 0, d = ptr; d < e; d += 3) { - int64_t t; + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - t = (int64_t)((int32_t) (PA_READ24RE(d) << 8)); - t = (t * linear[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24RE(d, ((uint32_t) (int32_t) t) >> 8); +static void +pa_volume_float32ne_c (float *samples, float *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - break; - } + length /= sizeof (float); - case PA_SAMPLE_S24_32NE: { - uint32_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; + for (channel = 0; length; length--) { + *samples++ *= volumes[channel]; - calc_linear_integer_volume(linear, volume); + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - e = (uint32_t*) ptr + c->length/sizeof(uint32_t); +static void +pa_volume_float32re_c (float *samples, float *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - for (channel = 0, d = ptr; d < e; d++) { - int64_t t; + length /= sizeof (float); - t = (int64_t) ((int32_t) (*d << 8)); - t = (t * linear[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *d = ((uint32_t) ((int32_t) t)) >> 8; + for (channel = 0; length; length--) { + float t; - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - break; - } + t = PA_FLOAT32_SWAP(*samples); + t *= volumes[channel]; + *samples++ = PA_FLOAT32_SWAP(t); - case PA_SAMPLE_S24_32RE: { - uint32_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - calc_linear_integer_volume(linear, volume); +static void +pa_volume_s32ne_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - e = (uint32_t*) ptr + c->length/sizeof(uint32_t); + length /= sizeof (int32_t); - for (channel = 0, d = ptr; d < e; d++) { - int64_t t; + for (channel = 0; length; length--) { + int64_t t; - t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*d) << 8)); - t = (t * linear[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *d = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); + t = (int64_t)(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = (int32_t) t; - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - break; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - case PA_SAMPLE_U8: { - uint8_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; +static void +pa_volume_s32re_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - calc_linear_integer_volume(linear, volume); + length /= sizeof (int32_t); - e = (uint8_t*) ptr + c->length; + for (channel = 0; length; length--) { + int64_t t; - for (channel = 0, d = ptr; d < e; d++) { - int32_t t, hi, lo; + t = (int64_t) PA_INT32_SWAP(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_INT32_SWAP((int32_t) t); - hi = linear[channel] >> 16; - lo = linear[channel] & 0xFFFF; + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - t = (int32_t) *d - 0x80; - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); - *d = (uint8_t) (t + 0x80); +static void +pa_volume_s24ne_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + uint8_t *e; - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - break; - } + e = samples + length; - case PA_SAMPLE_ULAW: { - uint8_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; + for (channel = 0; samples < e; samples += 3) { + int64_t t; - calc_linear_integer_volume(linear, volume); + t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8); - e = (uint8_t*) ptr + c->length; + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - for (channel = 0, d = ptr; d < e; d++) { - int32_t t, hi, lo; +static void +pa_volume_s24re_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + uint8_t *e; - hi = linear[channel] >> 16; - lo = linear[channel] & 0xFFFF; + e = samples + length; - t = (int32_t) st_ulaw2linear16(*d); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *d = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); + for (channel = 0; samples < e; samples += 3) { + int64_t t; - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - break; - } + t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8); - case PA_SAMPLE_ALAW: { - uint8_t *d, *e; - unsigned channel; - int32_t linear[PA_CHANNELS_MAX]; + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - calc_linear_integer_volume(linear, volume); +static void +pa_volume_s24_32ne_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - e = (uint8_t*) ptr + c->length; + length /= sizeof (uint32_t); - for (channel = 0, d = ptr; d < e; d++) { - int32_t t, hi, lo; + for (channel = 0; length; length--) { + int64_t t; - hi = linear[channel] >> 16; - lo = linear[channel] & 0xFFFF; + t = (int64_t) ((int32_t) (*samples << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = ((uint32_t) ((int32_t) t)) >> 8; - t = (int32_t) st_alaw2linear16(*d); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *d = (uint8_t) st_13linear2alaw((int16_t) t >> 3); + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } - break; - } +static void +pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; - case PA_SAMPLE_FLOAT32NE: { - float *d; - int skip; - unsigned n; - unsigned channel; + length /= sizeof (uint32_t); - d = ptr; - skip = (int) (spec->channels * sizeof(float)); - n = (unsigned) (c->length/sizeof(float)/spec->channels); + for (channel = 0; length; length--) { + int64_t t; - for (channel = 0; channel < spec->channels; channel ++) { - float v, *t; + t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); - if (PA_UNLIKELY(volume->values[channel] == PA_VOLUME_NORM)) - continue; + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} - v = (float) pa_sw_volume_to_linear(volume->values[channel]); - t = d + channel; - oil_scalarmult_f32(t, skip, t, skip, &v, (int) n); - } - break; - } +typedef void (*pa_do_volume_func) (void *samples, void *volumes, unsigned channels, unsigned length); +typedef void (*pa_calc_volume_func) (void *volumes, const pa_cvolume *volume); + +typedef union { + float f; + uint32_t i; +} volume_val; + +static pa_calc_volume_func calc_volume_funcs[] = +{ + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_float_volume, + (pa_calc_volume_func) calc_linear_float_volume, + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_integer_volume, + (pa_calc_volume_func) calc_linear_integer_volume +}; + +static pa_do_volume_func do_volume_funcs[] = +{ + (pa_do_volume_func) pa_volume_u8_c, + (pa_do_volume_func) pa_volume_alaw_c, + (pa_do_volume_func) pa_volume_ulaw_c, +#ifdef WORDS_BIGENDIAN + (pa_do_volume_func) pa_volume_s16re_c, + (pa_do_volume_func) pa_volume_s16ne_c, + (pa_do_volume_func) pa_volume_float32re_c, + (pa_do_volume_func) pa_volume_float32ne_c, + (pa_do_volume_func) pa_volume_s32re_c, + (pa_do_volume_func) pa_volume_s32ne_c, + (pa_do_volume_func) pa_volume_s24re_c, + (pa_do_volume_func) pa_volume_s24ne_c, + (pa_do_volume_func) pa_volume_s24_32re_c + (pa_do_volume_func) pa_volume_s24_32ne_c, +#else + (pa_do_volume_func) pa_volume_s16ne_c, + (pa_do_volume_func) pa_volume_s16re_c, + (pa_do_volume_func) pa_volume_float32ne_c, + (pa_do_volume_func) pa_volume_float32re_c, + (pa_do_volume_func) pa_volume_s32ne_c, + (pa_do_volume_func) pa_volume_s32re_c, + (pa_do_volume_func) pa_volume_s24ne_c, + (pa_do_volume_func) pa_volume_s24re_c, + (pa_do_volume_func) pa_volume_s24_32ne_c, + (pa_do_volume_func) pa_volume_s24_32re_c +#endif +}; - case PA_SAMPLE_FLOAT32RE: { - float *d, *e; - unsigned channel; - float linear[PA_CHANNELS_MAX]; +void pa_volume_memchunk( + pa_memchunk*c, + const pa_sample_spec *spec, + const pa_cvolume *volume) { - calc_linear_float_volume(linear, volume); + void *ptr; + volume_val linear[PA_CHANNELS_MAX]; - e = (float*) ptr + c->length/sizeof(float); + pa_assert(c); + pa_assert(spec); + pa_assert(c->length % pa_frame_size(spec) == 0); + pa_assert(volume); - for (channel = 0, d = ptr; d < e; d++) { - float t; + if (pa_memblock_is_silence(c->memblock)) + return; - t = PA_FLOAT32_SWAP(*d); - t *= linear[channel]; - *d = PA_FLOAT32_SWAP(t); + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) + return; - if (PA_UNLIKELY(++channel >= spec->channels)) - channel = 0; - } + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { + pa_silence_memchunk(c, spec); + return; + } - break; - } + if (spec->format < 0 || spec->format > PA_SAMPLE_MAX) { + pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format)); + return; + } + ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; - default: - pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format)); - /* If we cannot change the volume, we just don't do it */ - } + calc_volume_funcs[spec->format] ((void *)linear, volume); + do_volume_funcs[spec->format] (ptr, (void *)linear, spec->channels, c->length); pa_memblock_release(c->memblock); } -- cgit From 5b8b6544e205237d41bc502a7fd9f79051af78ec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 11 Aug 2009 16:25:44 +0200 Subject: sample-utils: coding style cleanup Make the coding style match the rest of pulseaudio more. Remove some liboil functions, they seem unoptimized and likely slower than our handrolled versions here. --- src/pulsecore/sample-util.c | 99 +++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index ef435673..0d4e01ef 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -30,9 +30,6 @@ #include #include -#include -#include - #include #include @@ -977,59 +974,50 @@ pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, un } } -typedef void (*pa_do_volume_func) (void *samples, void *volumes, unsigned channels, unsigned length); -typedef void (*pa_calc_volume_func) (void *volumes, const pa_cvolume *volume); +typedef void (*pa_do_volume_func_t) (void *samples, void *volumes, unsigned channels, unsigned length); +typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume); typedef union { float f; uint32_t i; } volume_val; -static pa_calc_volume_func calc_volume_funcs[] = -{ - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_float_volume, - (pa_calc_volume_func) calc_linear_float_volume, - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_integer_volume, - (pa_calc_volume_func) calc_linear_integer_volume +typedef struct pa_sample_func_t { + pa_calc_volume_func_t calc_volume; + pa_do_volume_func_t do_volume; +} pa_sample_func_t; + +static const pa_calc_volume_func_t calc_volume_table[] = { + [PA_SAMPLE_U8] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_ALAW] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_ULAW] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S16LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S16BE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_func_t) calc_linear_float_volume, + [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_func_t) calc_linear_float_volume, + [PA_SAMPLE_S32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S24LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S24BE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S24_32LE] = (pa_calc_volume_func_t) calc_linear_integer_volume, + [PA_SAMPLE_S24_32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume }; -static pa_do_volume_func do_volume_funcs[] = +static pa_do_volume_func_t do_volume_table[] = { - (pa_do_volume_func) pa_volume_u8_c, - (pa_do_volume_func) pa_volume_alaw_c, - (pa_do_volume_func) pa_volume_ulaw_c, -#ifdef WORDS_BIGENDIAN - (pa_do_volume_func) pa_volume_s16re_c, - (pa_do_volume_func) pa_volume_s16ne_c, - (pa_do_volume_func) pa_volume_float32re_c, - (pa_do_volume_func) pa_volume_float32ne_c, - (pa_do_volume_func) pa_volume_s32re_c, - (pa_do_volume_func) pa_volume_s32ne_c, - (pa_do_volume_func) pa_volume_s24re_c, - (pa_do_volume_func) pa_volume_s24ne_c, - (pa_do_volume_func) pa_volume_s24_32re_c - (pa_do_volume_func) pa_volume_s24_32ne_c, -#else - (pa_do_volume_func) pa_volume_s16ne_c, - (pa_do_volume_func) pa_volume_s16re_c, - (pa_do_volume_func) pa_volume_float32ne_c, - (pa_do_volume_func) pa_volume_float32re_c, - (pa_do_volume_func) pa_volume_s32ne_c, - (pa_do_volume_func) pa_volume_s32re_c, - (pa_do_volume_func) pa_volume_s24ne_c, - (pa_do_volume_func) pa_volume_s24re_c, - (pa_do_volume_func) pa_volume_s24_32ne_c, - (pa_do_volume_func) pa_volume_s24_32re_c -#endif + [PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c, + [PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c, + [PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c, + [PA_SAMPLE_S16NE] = (pa_do_volume_func_t) pa_volume_s16ne_c, + [PA_SAMPLE_S16RE] = (pa_do_volume_func_t) pa_volume_s16re_c, + [PA_SAMPLE_FLOAT32NE] = (pa_do_volume_func_t) pa_volume_float32ne_c, + [PA_SAMPLE_FLOAT32RE] = (pa_do_volume_func_t) pa_volume_float32re_c, + [PA_SAMPLE_S32NE] = (pa_do_volume_func_t) pa_volume_s32ne_c, + [PA_SAMPLE_S32RE] = (pa_do_volume_func_t) pa_volume_s32re_c, + [PA_SAMPLE_S24NE] = (pa_do_volume_func_t) pa_volume_s24ne_c, + [PA_SAMPLE_S24RE] = (pa_do_volume_func_t) pa_volume_s24re_c, + [PA_SAMPLE_S24_32NE] = (pa_do_volume_func_t) pa_volume_s24_32ne_c, + [PA_SAMPLE_S24_32RE] = (pa_do_volume_func_t) pa_volume_s24_32re_c }; void pa_volume_memchunk( @@ -1063,8 +1051,8 @@ void pa_volume_memchunk( ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; - calc_volume_funcs[spec->format] ((void *)linear, volume); - do_volume_funcs[spec->format] (ptr, (void *)linear, spec->channels, c->length); + calc_volume_table[spec->format] ((void *)linear, volume); + do_volume_table[spec->format] (ptr, (void *)linear, spec->channels, c->length); pa_memblock_release(c->memblock); } @@ -1110,7 +1098,7 @@ void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, u d = (uint8_t*) dst + c * ss; for (j = 0; j < n; j ++) { - oil_memcpy(d, s, (int) ss); + memcpy(d, s, (int) ss); s = (uint8_t*) s + ss; d = (uint8_t*) d + fs; } @@ -1138,7 +1126,7 @@ void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, d = dst[c]; for (j = 0; j < n; j ++) { - oil_memcpy(d, s, (int) ss); + memcpy(d, s, (int) ss); s = (uint8_t*) s + fs; d = (uint8_t*) d + ss; } @@ -1247,10 +1235,15 @@ void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const vo s = src; d = dst; if (format == PA_SAMPLE_FLOAT32NE) { + for (; n > 0; n--) { + float f; - float minus_one = -1.0, plus_one = 1.0; - oil_clip_f32(d, (int) dstr, s, (int) sstr, (int) n, &minus_one, &plus_one); + f = *s; + *d = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f); + s = (const float*) ((const uint8_t*) s + sstr); + d = (float*) ((uint8_t*) d + dstr); + } } else { pa_assert(format == PA_SAMPLE_FLOAT32RE); -- cgit From e71e644eb668b6336dd48d2730839aa3e9f7278e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 11 Aug 2009 16:43:46 +0200 Subject: sample-util: move some functions around Move some stuff around before splitting it into a separate file. --- src/pulsecore/sample-util.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 0d4e01ef..f8a4c70a 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -975,17 +975,34 @@ pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, un } typedef void (*pa_do_volume_func_t) (void *samples, void *volumes, unsigned channels, unsigned length); -typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume); + +typedef struct pa_sample_func_t { + pa_do_volume_func_t do_volume; +} pa_sample_func_t; + +static pa_do_volume_func_t do_volume_table[] = +{ + [PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c, + [PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c, + [PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c, + [PA_SAMPLE_S16NE] = (pa_do_volume_func_t) pa_volume_s16ne_c, + [PA_SAMPLE_S16RE] = (pa_do_volume_func_t) pa_volume_s16re_c, + [PA_SAMPLE_FLOAT32NE] = (pa_do_volume_func_t) pa_volume_float32ne_c, + [PA_SAMPLE_FLOAT32RE] = (pa_do_volume_func_t) pa_volume_float32re_c, + [PA_SAMPLE_S32NE] = (pa_do_volume_func_t) pa_volume_s32ne_c, + [PA_SAMPLE_S32RE] = (pa_do_volume_func_t) pa_volume_s32re_c, + [PA_SAMPLE_S24NE] = (pa_do_volume_func_t) pa_volume_s24ne_c, + [PA_SAMPLE_S24RE] = (pa_do_volume_func_t) pa_volume_s24re_c, + [PA_SAMPLE_S24_32NE] = (pa_do_volume_func_t) pa_volume_s24_32ne_c, + [PA_SAMPLE_S24_32RE] = (pa_do_volume_func_t) pa_volume_s24_32re_c +}; typedef union { float f; uint32_t i; } volume_val; -typedef struct pa_sample_func_t { - pa_calc_volume_func_t calc_volume; - pa_do_volume_func_t do_volume; -} pa_sample_func_t; +typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume); static const pa_calc_volume_func_t calc_volume_table[] = { [PA_SAMPLE_U8] = (pa_calc_volume_func_t) calc_linear_integer_volume, @@ -1003,23 +1020,6 @@ static const pa_calc_volume_func_t calc_volume_table[] = { [PA_SAMPLE_S24_32BE] = (pa_calc_volume_func_t) calc_linear_integer_volume }; -static pa_do_volume_func_t do_volume_table[] = -{ - [PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c, - [PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c, - [PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c, - [PA_SAMPLE_S16NE] = (pa_do_volume_func_t) pa_volume_s16ne_c, - [PA_SAMPLE_S16RE] = (pa_do_volume_func_t) pa_volume_s16re_c, - [PA_SAMPLE_FLOAT32NE] = (pa_do_volume_func_t) pa_volume_float32ne_c, - [PA_SAMPLE_FLOAT32RE] = (pa_do_volume_func_t) pa_volume_float32re_c, - [PA_SAMPLE_S32NE] = (pa_do_volume_func_t) pa_volume_s32ne_c, - [PA_SAMPLE_S32RE] = (pa_do_volume_func_t) pa_volume_s32re_c, - [PA_SAMPLE_S24NE] = (pa_do_volume_func_t) pa_volume_s24ne_c, - [PA_SAMPLE_S24RE] = (pa_do_volume_func_t) pa_volume_s24re_c, - [PA_SAMPLE_S24_32NE] = (pa_do_volume_func_t) pa_volume_s24_32ne_c, - [PA_SAMPLE_S24_32RE] = (pa_do_volume_func_t) pa_volume_s24_32re_c -}; - void pa_volume_memchunk( pa_memchunk*c, const pa_sample_spec *spec, -- cgit From 3d008961c095cf8d41d2c61d13d446c98c892136 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 11 Aug 2009 17:10:44 +0200 Subject: sample-util: move volume code to separate file Move the volume code into a separate file with the reference C implementations. Add a function to retrieve the volume function and one to install a new one. --- src/Makefile.am | 1 + src/pulsecore/sample-util.c | 316 +---------------------------------------- src/pulsecore/sample-util.h | 6 + src/pulsecore/svolume_c.c | 335 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 347 insertions(+), 311 deletions(-) create mode 100644 src/pulsecore/svolume_c.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 17011cd3..fc5d39fb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -825,6 +825,7 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/resampler.c pulsecore/resampler.h \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ pulsecore/sample-util.c pulsecore/sample-util.h \ + pulsecore/svolume_c.c \ pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \ pulsecore/sconv-s16le.c pulsecore/sconv-s16le.h \ pulsecore/sconv.c pulsecore/sconv.h \ diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index f8a4c70a..0bbd5192 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -687,316 +687,6 @@ size_t pa_mix( return length; } -typedef struct pa_volume_funcs { - void (*u8) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*alaw) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*ulaw) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*s16ne) (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*s16re) (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*float32ne) (float *samples, float *volumes, unsigned channels, unsigned length); - void (*float32re) (float *samples, float *volumes, unsigned channels, unsigned length); - void (*s32ne) (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*s32re) (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*s24ne) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*s24re) (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*s24_32ne) (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length); - void (*s24_32re) (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length); -} pa_volume_funcs; - -static void -pa_volume_u8_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) *samples - 0x80; - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); - *samples++ = (uint8_t) (t + 0x80); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_alaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) st_alaw2linear16(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_ulaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) st_ulaw2linear16(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s16ne_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (int16_t); - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - /* Multiplying the 32bit volume factor with the 16bit - * sample might result in an 48bit value. We want to - * do without 64 bit integers and hence do the - * multiplication independantly for the HI and LO part - * of the volume. */ - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t)(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (int16_t) t; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s16re_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (int16_t); - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) PA_INT16_SWAP(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = PA_INT16_SWAP((int16_t) t); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_float32ne_c (float *samples, float *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (float); - - for (channel = 0; length; length--) { - *samples++ *= volumes[channel]; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_float32re_c (float *samples, float *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (float); - - for (channel = 0; length; length--) { - float t; - - t = PA_FLOAT32_SWAP(*samples); - t *= volumes[channel]; - *samples++ = PA_FLOAT32_SWAP(t); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s32ne_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (int32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t)(*samples); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = (int32_t) t; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s32re_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (int32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t) PA_INT32_SWAP(*samples); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = PA_INT32_SWAP((int32_t) t); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24ne_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - uint8_t *e; - - e = samples + length; - - for (channel = 0; samples < e; samples += 3) { - int64_t t; - - t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24re_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - uint8_t *e; - - e = samples + length; - - for (channel = 0; samples < e; samples += 3) { - int64_t t; - - t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24_32ne_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (uint32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t) ((int32_t) (*samples << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = ((uint32_t) ((int32_t) t)) >> 8; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (uint32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -typedef void (*pa_do_volume_func_t) (void *samples, void *volumes, unsigned channels, unsigned length); - -typedef struct pa_sample_func_t { - pa_do_volume_func_t do_volume; -} pa_sample_func_t; - -static pa_do_volume_func_t do_volume_table[] = -{ - [PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c, - [PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c, - [PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c, - [PA_SAMPLE_S16NE] = (pa_do_volume_func_t) pa_volume_s16ne_c, - [PA_SAMPLE_S16RE] = (pa_do_volume_func_t) pa_volume_s16re_c, - [PA_SAMPLE_FLOAT32NE] = (pa_do_volume_func_t) pa_volume_float32ne_c, - [PA_SAMPLE_FLOAT32RE] = (pa_do_volume_func_t) pa_volume_float32re_c, - [PA_SAMPLE_S32NE] = (pa_do_volume_func_t) pa_volume_s32ne_c, - [PA_SAMPLE_S32RE] = (pa_do_volume_func_t) pa_volume_s32re_c, - [PA_SAMPLE_S24NE] = (pa_do_volume_func_t) pa_volume_s24ne_c, - [PA_SAMPLE_S24RE] = (pa_do_volume_func_t) pa_volume_s24re_c, - [PA_SAMPLE_S24_32NE] = (pa_do_volume_func_t) pa_volume_s24_32ne_c, - [PA_SAMPLE_S24_32RE] = (pa_do_volume_func_t) pa_volume_s24_32re_c -}; - typedef union { float f; uint32_t i; @@ -1027,6 +717,7 @@ void pa_volume_memchunk( void *ptr; volume_val linear[PA_CHANNELS_MAX]; + pa_do_volume_func_t do_volume; pa_assert(c); pa_assert(spec); @@ -1051,8 +742,11 @@ void pa_volume_memchunk( ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; + do_volume = pa_get_volume_func (spec->format); + pa_assert(do_volume); + calc_volume_table[spec->format] ((void *)linear, volume); - do_volume_table[spec->format] (ptr, (void *)linear, spec->channels, c->length); + do_volume (ptr, (void *)linear, spec->channels, c->length); pa_memblock_release(c->memblock); } diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 6a306c11..278b88b0 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -86,6 +86,12 @@ void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn); void pa_memchunk_sine(pa_memchunk *c, pa_mempool *pool, unsigned rate, unsigned freq); +typedef void (*pa_do_volume_func_t) (void *samples, void *volumes, unsigned channels, unsigned length); + +pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f); +void pa_set_volume_func(pa_sample_format_t f, pa_do_volume_func_t func); + + #define PA_CHANNEL_POSITION_MASK_LEFT \ (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \ | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT) \ diff --git a/src/pulsecore/svolume_c.c b/src/pulsecore/svolume_c.c new file mode 100644 index 00000000..2148a573 --- /dev/null +++ b/src/pulsecore/svolume_c.c @@ -0,0 +1,335 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include +#include +#include + +#include "sample-util.h" +#include "endianmacros.h" + +static void +pa_volume_u8_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) *samples - 0x80; + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); + *samples++ = (uint8_t) (t + 0x80); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_alaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) st_alaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_ulaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) st_ulaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s16ne_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int16_t); + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + /* Multiplying the 32bit volume factor with the 16bit + * sample might result in an 48bit value. We want to + * do without 64 bit integers and hence do the + * multiplication independantly for the HI and LO part + * of the volume. */ + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t)(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (int16_t) t; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s16re_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int16_t); + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) PA_INT16_SWAP(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = PA_INT16_SWAP((int16_t) t); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_float32ne_c (float *samples, float *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (float); + + for (channel = 0; length; length--) { + *samples++ *= volumes[channel]; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_float32re_c (float *samples, float *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (float); + + for (channel = 0; length; length--) { + float t; + + t = PA_FLOAT32_SWAP(*samples); + t *= volumes[channel]; + *samples++ = PA_FLOAT32_SWAP(t); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s32ne_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t)(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = (int32_t) t; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s32re_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t) PA_INT32_SWAP(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_INT32_SWAP((int32_t) t); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24ne_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + uint8_t *e; + + e = samples + length; + + for (channel = 0; samples < e; samples += 3) { + int64_t t; + + t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24re_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + uint8_t *e; + + e = samples + length; + + for (channel = 0; samples < e; samples += 3) { + int64_t t; + + t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24_32ne_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (uint32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t) ((int32_t) (*samples << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = ((uint32_t) ((int32_t) t)) >> 8; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (uint32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static pa_do_volume_func_t do_volume_table[] = +{ + [PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c, + [PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c, + [PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c, + [PA_SAMPLE_S16NE] = (pa_do_volume_func_t) pa_volume_s16ne_c, + [PA_SAMPLE_S16RE] = (pa_do_volume_func_t) pa_volume_s16re_c, + [PA_SAMPLE_FLOAT32NE] = (pa_do_volume_func_t) pa_volume_float32ne_c, + [PA_SAMPLE_FLOAT32RE] = (pa_do_volume_func_t) pa_volume_float32re_c, + [PA_SAMPLE_S32NE] = (pa_do_volume_func_t) pa_volume_s32ne_c, + [PA_SAMPLE_S32RE] = (pa_do_volume_func_t) pa_volume_s32re_c, + [PA_SAMPLE_S24NE] = (pa_do_volume_func_t) pa_volume_s24ne_c, + [PA_SAMPLE_S24RE] = (pa_do_volume_func_t) pa_volume_s24re_c, + [PA_SAMPLE_S24_32NE] = (pa_do_volume_func_t) pa_volume_s24_32ne_c, + [PA_SAMPLE_S24_32RE] = (pa_do_volume_func_t) pa_volume_s24_32re_c +}; + +pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f) { + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + return do_volume_table[f]; +} + +void pa_set_volume_func(pa_sample_format_t f, pa_do_volume_func_t func) { + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + do_volume_table[f] = func; +} -- cgit From 2d73f13567ad03efe798d07eda87fa776b0505f2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Aug 2009 17:03:30 +0200 Subject: samples-util: add padding to volume array Pad the volume array with a copy of the start. We'll need this later to be able to write optimized functions. --- src/pulsecore/sample-util.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 0bbd5192..677f914a 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -103,24 +103,36 @@ void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { return p; } +#define VOLUME_PADDING 32 + static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) { - unsigned channel; + unsigned channel, nchannels, padding; pa_assert(linear); pa_assert(volume); - for (channel = 0; channel < volume->channels; channel++) + nchannels = volume->channels; + + for (channel = 0; channel < nchannels; channel++) linear[channel] = (int32_t) lrint(pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + + for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) + linear[channel] = linear[padding]; } static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) { - unsigned channel; + unsigned channel, nchannels, padding; pa_assert(linear); pa_assert(volume); - for (channel = 0; channel < volume->channels; channel++) + nchannels = volume->channels; + + for (channel = 0; channel < nchannels; channel++) linear[channel] = (float) pa_sw_volume_to_linear(volume->values[channel]); + + for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) + linear[channel] = linear[padding]; } static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) { @@ -716,7 +728,7 @@ void pa_volume_memchunk( const pa_cvolume *volume) { void *ptr; - volume_val linear[PA_CHANNELS_MAX]; + volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING]; pa_do_volume_func_t do_volume; pa_assert(c); -- cgit From 3a0b012ee016e2fe40f49c72da119cb89d2ba312 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Aug 2009 17:08:41 +0200 Subject: volume: add first mmx optimized function Add code for an mmx optimized version of s16ne volume scaling. Install the custom function. --- src/Makefile.am | 1 + src/daemon/main.c | 2 + src/pulsecore/sample-util.h | 1 + src/pulsecore/svolume_mmx.c | 424 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 428 insertions(+) create mode 100644 src/pulsecore/svolume_mmx.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index fc5d39fb..e7a99003 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -826,6 +826,7 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ pulsecore/sample-util.c pulsecore/sample-util.h \ pulsecore/svolume_c.c \ + pulsecore/svolume_mmx.c \ pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \ pulsecore/sconv-s16le.c pulsecore/sconv-s16le.h \ pulsecore/sconv.c pulsecore/sconv.h \ diff --git a/src/daemon/main.c b/src/daemon/main.c index 8521e720..e3c395f2 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -821,6 +821,8 @@ int main(int argc, char *argv[]) { pa_memtrap_install(); + pa_volume_func_init_mmx(); + pa_assert_se(mainloop = pa_mainloop_new()); if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm, conf->shm_size))) { diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 278b88b0..00b9ae0b 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -91,6 +91,7 @@ typedef void (*pa_do_volume_func_t) (void *samples, void *volumes, unsigned chan pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f); void pa_set_volume_func(pa_sample_format_t f, pa_do_volume_func_t func); +void pa_volume_func_init_mmx(void); #define PA_CHANNEL_POSITION_MASK_LEFT \ (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \ diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c new file mode 100644 index 00000000..9f49a624 --- /dev/null +++ b/src/pulsecore/svolume_mmx.c @@ -0,0 +1,424 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include "sample-util.h" +#include "endianmacros.h" + +#if 0 +static void +pa_volume_u8_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) *samples - 0x80; + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); + *samples++ = (uint8_t) (t + 0x80); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_alaw_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) st_alaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_ulaw_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) st_ulaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} +#endif + +static void +pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + int64_t channel, temp; + + /* the max number of samples we process at a time */ + channels = MAX (4, channels); + +#define VOLUME_32x16(s,v) /* v1_h | v1_l | v0_h | v0_l */ \ + " pxor %%mm4, %%mm4 \n\t" \ + " punpcklwd %%mm4, "#s" \n\t" /* 0 | p1 | 0 | p0 */ \ + " pcmpgtw "#s", %%mm4 \n\t" /* select sign from sample */ \ + " pand "#v", %%mm4 \n\t" /* extract correction factors */ \ + " movq "#s", %%mm5 \n\t" \ + " pmulhuw "#v", "#s" \n\t" /* 0 | p1*v1lh | 0 | p0*v0lh */ \ + " psubd %%mm4, "#s" \n\t" /* sign correction */ \ + " psrld $16, "#v" \n\t" /* 0 | v1h | 0 | v0h */ \ + " pmaddwd %%mm5, "#v" \n\t" /* p1 * v1h | p0 * v0h */ \ + " paddd "#s", "#v" \n\t" /* p1 * v1 | p0 * v0 */ \ + " packssdw "#v", "#v" \n\t" /* p0*v0 | p1*v1 | p0*v0 | p1*v1 */ + +#define MOD_ADD(a,b) \ + " add "#a", %3 \n\t" \ + " mov %3, %4 \n\t" \ + " sub %5, %4 \n\t" \ + " cmp %3, "#b" \n\t" \ + " cmovae %4, %3 \n\t" + + __asm__ __volatile__ ( + " xor %3, %3 \n\t" + " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ + + " test $1, %2 \n\t" /* check for odd samples */ + " je 2f \n\t" + + " movd (%1, %3, 4), %%mm0 \n\t" /* do odd samples */ + " movw (%0), %%ax \n\t" + " movd %%eax, %%mm1 \n\t" + VOLUME_32x16 (%%mm1, %%mm0) + " movd %%mm0, %%eax \n\t" + " movw %%ax, (%0) \n\t" + " add $2, %0 \n\t" + MOD_ADD ($1, %5) + " dec %2 \n\t" + + "2: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ + " test $1, %2 \n\t" /* check for odd samples */ + " je 4f \n\t" + + "3: \n\t" /* do samples in pairs of 2 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ + " movd (%0), %%mm1 \n\t" /* X | X | p1 | p0 */ + VOLUME_32x16 (%%mm1, %%mm0) + " movd %%mm0, (%0) \n\t" + " add $4, %0 \n\t" + MOD_ADD ($2, %5) + " dec %2 \n\t" + + "4: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ + " cmp $0, %2 \n\t" + " je 6f \n\t" + + "5: \n\t" /* do samples in pairs of 4 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ + " movq 8(%1, %3, 4), %%mm2 \n\t" /* v3_h | v3_l | v2_h | v2_l */ + " movd (%0), %%mm1 \n\t" /* X | X | p1 | p0 */ + " movd 4(%0), %%mm3 \n\t" /* X | X | p3 | p2 */ + VOLUME_32x16 (%%mm1, %%mm0) + VOLUME_32x16 (%%mm3, %%mm2) + " movd %%mm0, (%0) \n\t" + " movd %%mm2, 4(%0) \n\t" + " add $8, %0 \n\t" + MOD_ADD ($4, %5) + " dec %2 \n\t" + " jne 5b \n\t" + + "6: \n\t" + " emms \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((int64_t)channel), "=r" (temp) + : "r" ((int64_t)channels) + : "rax", "cc" + ); +} + +#if 0 +static void +pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int16_t); + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) PA_INT16_SWAP(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = PA_INT16_SWAP((int16_t) t); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_float32ne_mmx (float *samples, float *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (float); + + for (channel = 0; length; length--) { + *samples++ *= volumes[channel]; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_float32re_mmx (float *samples, float *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (float); + + for (channel = 0; length; length--) { + float t; + + t = PA_FLOAT32_SWAP(*samples); + t *= volumes[channel]; + *samples++ = PA_FLOAT32_SWAP(t); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s32ne_mmx (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t)(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = (int32_t) t; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s32re_mmx (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t) PA_INT32_SWAP(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_INT32_SWAP((int32_t) t); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24ne_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + uint8_t *e; + + e = samples + length; + + for (channel = 0; samples < e; samples += 3) { + int64_t t; + + t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24re_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + uint8_t *e; + + e = samples + length; + + for (channel = 0; samples < e; samples += 3) { + int64_t t; + + t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24_32ne_mmx (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (uint32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t) ((int32_t) (*samples << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = ((uint32_t) ((int32_t) t)) >> 8; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24_32re_mmx (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (uint32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} +#endif + +#undef RUN_TEST + +#ifdef RUN_TEST +#define CHANNELS 1 +#define SAMPLES 1021 +#define TIMES 1000 + +static void run_test (void) { + int16_t samples[SAMPLES]; + int16_t samples_ref[SAMPLES]; + int16_t samples_orig[SAMPLES]; + int32_t volumes[CHANNELS]; + int i, j; + pa_do_volume_func_t func; + + func = pa_get_volume_func (PA_SAMPLE_S16NE); + + printf ("checking\n"); + + for (j = 0; j < TIMES; j++) { + pa_random (samples, sizeof (samples)); + memcpy (samples_ref, samples, sizeof (samples)); + memcpy (samples_orig, samples, sizeof (samples)); + + for (i = 0; i < CHANNELS; i++) { + volumes[i] = rand() >> 15; + } + + pa_volume_s16ne_mmx (samples, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); + func (samples_ref, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); + + for (i = 0; i < SAMPLES; i++) { + if (samples[i] != samples_ref[i]) { + printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); + } +#if 0 + else + printf ("%d: %04x == %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); +#endif + } + } +} +#endif + +void pa_volume_func_init_mmx (void) { + pa_log_info("Initialising MMX optimized functions."); + +#ifdef RUN_TEST + run_test (); +#endif + + pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx); +} -- cgit From 08f3e16c84fabca9c6789440f98ff8dca62eb81a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Aug 2009 20:43:37 +0200 Subject: volume_mmx: fix mmx code a bit --- src/pulsecore/svolume_mmx.c | 46 +++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index 9f49a624..6dcc26c2 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -104,14 +104,15 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi { int64_t channel, temp; - /* the max number of samples we process at a time */ + /* the max number of samples we process at a time, this is also the max amount + * we overread the volume array, which should have enough padding. */ channels = MAX (4, channels); #define VOLUME_32x16(s,v) /* v1_h | v1_l | v0_h | v0_l */ \ " pxor %%mm4, %%mm4 \n\t" \ " punpcklwd %%mm4, "#s" \n\t" /* 0 | p1 | 0 | p0 */ \ " pcmpgtw "#s", %%mm4 \n\t" /* select sign from sample */ \ - " pand "#v", %%mm4 \n\t" /* extract correction factors */ \ + " pand "#v", %%mm4 \n\t" /* extract sign correction factors */ \ " movq "#s", %%mm5 \n\t" \ " pmulhuw "#v", "#s" \n\t" /* 0 | p1*v1lh | 0 | p0*v0lh */ \ " psubd %%mm4, "#s" \n\t" /* sign correction */ \ @@ -123,8 +124,8 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi #define MOD_ADD(a,b) \ " add "#a", %3 \n\t" \ " mov %3, %4 \n\t" \ - " sub %5, %4 \n\t" \ - " cmp %3, "#b" \n\t" \ + " sub "#b", %4 \n\t" \ + " cmp "#b", %3 \n\t" \ " cmovae %4, %3 \n\t" __asm__ __volatile__ ( @@ -135,14 +136,13 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi " je 2f \n\t" " movd (%1, %3, 4), %%mm0 \n\t" /* do odd samples */ - " movw (%0), %%ax \n\t" - " movd %%eax, %%mm1 \n\t" + " movw (%0), %4 \n\t" + " movd %4, %%mm1 \n\t" VOLUME_32x16 (%%mm1, %%mm0) - " movd %%mm0, %%eax \n\t" - " movw %%ax, (%0) \n\t" + " movd %%mm0, %4 \n\t" + " movw %4, (%0) \n\t" " add $2, %0 \n\t" MOD_ADD ($1, %5) - " dec %2 \n\t" "2: \n\t" " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ @@ -156,7 +156,6 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi " movd %%mm0, (%0) \n\t" " add $4, %0 \n\t" MOD_ADD ($2, %5) - " dec %2 \n\t" "4: \n\t" " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ @@ -180,9 +179,9 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi "6: \n\t" " emms \n\t" - : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((int64_t)channel), "=r" (temp) + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((int64_t)channel), "=&r" (temp) : "r" ((int64_t)channels) - : "rax", "cc" + : "cc" ); } @@ -370,7 +369,7 @@ pa_volume_s24_32re_mmx (uint32_t *samples, int32_t *volumes, unsigned channels, #undef RUN_TEST #ifdef RUN_TEST -#define CHANNELS 1 +#define CHANNELS 2 #define SAMPLES 1021 #define TIMES 1000 @@ -378,25 +377,32 @@ static void run_test (void) { int16_t samples[SAMPLES]; int16_t samples_ref[SAMPLES]; int16_t samples_orig[SAMPLES]; - int32_t volumes[CHANNELS]; - int i, j; + int32_t volumes[CHANNELS + 16]; + int i, j, padding; pa_do_volume_func_t func; func = pa_get_volume_func (PA_SAMPLE_S16NE); - printf ("checking\n"); + printf ("checking %d\n", sizeof (samples)); for (j = 0; j < TIMES; j++) { + /* + for (i = 0; i < SAMPLES; i++) { + samples[i] samples_ref[i] = samples_orig[i] = rand() >> 16; + } + */ + pa_random (samples, sizeof (samples)); memcpy (samples_ref, samples, sizeof (samples)); memcpy (samples_orig, samples, sizeof (samples)); - for (i = 0; i < CHANNELS; i++) { + for (i = 0; i < CHANNELS; i++) volumes[i] = rand() >> 15; - } + for (padding = 0; padding < 16; padding++, i++) + volumes[i] = volumes[padding]; - pa_volume_s16ne_mmx (samples, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); - func (samples_ref, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); + pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); + func (samples_ref, volumes, CHANNELS, sizeof (samples)); for (i = 0; i < SAMPLES; i++) { if (samples[i] != samples_ref[i]) { -- cgit From 7086784573e9e6c92d4c34404f18891c2d19872a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Aug 2009 20:44:12 +0200 Subject: volume_sse: add sse optimisations --- src/Makefile.am | 2 +- src/daemon/main.c | 1 + src/pulsecore/sample-util.h | 1 + src/pulsecore/svolume_sse.c | 437 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 440 insertions(+), 1 deletion(-) create mode 100644 src/pulsecore/svolume_sse.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index e7a99003..b692e4a9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -826,7 +826,7 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ pulsecore/sample-util.c pulsecore/sample-util.h \ pulsecore/svolume_c.c \ - pulsecore/svolume_mmx.c \ + pulsecore/svolume_mmx.c pulsecore/svolume_sse.c \ pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \ pulsecore/sconv-s16le.c pulsecore/sconv-s16le.h \ pulsecore/sconv.c pulsecore/sconv.h \ diff --git a/src/daemon/main.c b/src/daemon/main.c index e3c395f2..3c5f7f95 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -822,6 +822,7 @@ int main(int argc, char *argv[]) { pa_memtrap_install(); pa_volume_func_init_mmx(); + pa_volume_func_init_sse(); pa_assert_se(mainloop = pa_mainloop_new()); diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 00b9ae0b..563dbb6a 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -92,6 +92,7 @@ pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f); void pa_set_volume_func(pa_sample_format_t f, pa_do_volume_func_t func); void pa_volume_func_init_mmx(void); +void pa_volume_func_init_sse(void); #define PA_CHANNEL_POSITION_MASK_LEFT \ (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \ diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c new file mode 100644 index 00000000..2d4c541b --- /dev/null +++ b/src/pulsecore/svolume_sse.c @@ -0,0 +1,437 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include "sample-util.h" +#include "endianmacros.h" + +#if 0 +static void +pa_volume_u8_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) *samples - 0x80; + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); + *samples++ = (uint8_t) (t + 0x80); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_alaw_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) st_alaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_ulaw_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) st_ulaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} +#endif + +static void +pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + int64_t channel; + int64_t temp; + + /* the max number of samples we process at a time, this is also the max amount + * we overread the volume array, which should have enough padding. */ + channels = MAX (8, channels); + +#define VOLUME_32x16(s,v) /* v1_h | v1_l | v0_h | v0_l */ \ + " pxor %%xmm4, %%xmm4 \n\t" \ + " punpcklwd %%xmm4, "#s" \n\t" /* 0 | p1 | 0 | p0 */ \ + " pcmpgtw "#s", %%xmm4 \n\t" /* select sign from sample */ \ + " pand "#v", %%xmm4 \n\t" /* extract sign correction factors */ \ + " movdqa "#s", %%xmm5 \n\t" \ + " pmulhuw "#v", "#s" \n\t" /* 0 | p1*v1lh | 0 | p0*v0lh */ \ + " psubd %%xmm4, "#s" \n\t" /* sign correction */ \ + " psrld $16, "#v" \n\t" /* 0 | v1h | 0 | v0h */ \ + " pmaddwd %%xmm5, "#v" \n\t" /* p1 * v1h | p0 * v0h */ \ + " paddd "#s", "#v" \n\t" /* p1 * v1 | p0 * v0 */ \ + " packssdw "#v", "#v" \n\t" /* p0*v0 | p1*v1 | p0*v0 | p1*v1 */ + +#define MOD_ADD(a,b) \ + " add "#a", %3 \n\t" \ + " mov %3, %4 \n\t" \ + " sub "#b", %4 \n\t" \ + " cmp "#b", %3 \n\t" \ + " cmovae %4, %3 \n\t" + + __asm__ __volatile__ ( + " xor %3, %3 \n\t" + " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ + + " test $1, %2 \n\t" /* check for odd samples */ + " je 2f \n\t" + + " movd (%1, %3, 4), %%xmm0 \n\t" /* do odd sample */ + " movw (%0), %4 \n\t" + " movd %4, %%xmm1 \n\t" + VOLUME_32x16 (%%xmm1, %%xmm0) + " movd %%xmm0, %4 \n\t" + " movw %4, (%0) \n\t" + " add $2, %0 \n\t" + MOD_ADD ($1, %5) + + "2: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ + " test $1, %2 \n\t" /* check for odd samples */ + " je 4f \n\t" + + "3: \n\t" /* do samples in pairs of 2 */ + " movq (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ + " movd (%0), %%xmm1 \n\t" /* X | X | p1 | p0 */ + VOLUME_32x16 (%%xmm1, %%xmm0) + " movd %%xmm0, (%0) \n\t" + " add $4, %0 \n\t" + MOD_ADD ($2, %5) + + "4: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ + " test $1, %2 \n\t" /* check for odd samples */ + " je 6f \n\t" + + "5: \n\t" /* do samples in pairs of 4 */ + " movdqa (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ + " movq (%0), %%xmm1 \n\t" /* X | X | p1 | p0 */ + VOLUME_32x16 (%%xmm1, %%xmm0) + " movq %%xmm0, (%0) \n\t" + " add $8, %0 \n\t" + MOD_ADD ($4, %5) + + "6: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 8 samples at a time */ + " cmp $0, %2 \n\t" + " je 8f \n\t" + + "7: \n\t" /* do samples in pairs of 8 */ + " movdqa (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ + " movdqa 16(%1, %3, 4), %%xmm2 \n\t" /* v3_h | v3_l | v2_h | v2_l */ + " movq (%0), %%xmm1 \n\t" /* X | X | p1 | p0 */ + " movq 8(%0), %%xmm3 \n\t" /* X | X | p3 | p2 */ + VOLUME_32x16 (%%xmm1, %%xmm0) + VOLUME_32x16 (%%xmm3, %%xmm2) + " movq %%xmm0, (%0) \n\t" + " movq %%xmm2, 8(%0) \n\t" + " add $16, %0 \n\t" + MOD_ADD ($8, %5) + " dec %2 \n\t" + " jne 7b \n\t" + "8: \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp) + : "r" ((int64_t)channels) + : "cc" + ); +} + +#if 0 +static void +pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int16_t); + + for (channel = 0; length; length--) { + int32_t t, hi, lo; + + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; + + t = (int32_t) PA_INT16_SWAP(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = PA_INT16_SWAP((int16_t) t); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_float32ne_sse (float *samples, float *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (float); + + for (channel = 0; length; length--) { + *samples++ *= volumes[channel]; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_float32re_sse (float *samples, float *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (float); + + for (channel = 0; length; length--) { + float t; + + t = PA_FLOAT32_SWAP(*samples); + t *= volumes[channel]; + *samples++ = PA_FLOAT32_SWAP(t); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s32ne_sse (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t)(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = (int32_t) t; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s32re_sse (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (int32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t) PA_INT32_SWAP(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_INT32_SWAP((int32_t) t); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24ne_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + uint8_t *e; + + e = samples + length; + + for (channel = 0; samples < e; samples += 3) { + int64_t t; + + t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24re_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + uint8_t *e; + + e = samples + length; + + for (channel = 0; samples < e; samples += 3) { + int64_t t; + + t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24_32ne_sse (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (uint32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t) ((int32_t) (*samples << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = ((uint32_t) ((int32_t) t)) >> 8; + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} + +static void +pa_volume_s24_32re_sse (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + unsigned channel; + + length /= sizeof (uint32_t); + + for (channel = 0; length; length--) { + int64_t t; + + t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); + + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } +} +#endif + +#undef RUN_TEST + +#ifdef RUN_TEST +#define CHANNELS 2 +#define SAMPLES 1021 +#define TIMES 1000 + +static void run_test (void) { + int16_t samples[SAMPLES]; + int16_t samples_ref[SAMPLES]; + int16_t samples_orig[SAMPLES]; + int32_t volumes[CHANNELS + 16]; + int i, j, padding; + pa_do_volume_func_t func; + + func = pa_get_volume_func (PA_SAMPLE_S16NE); + + printf ("checking %d\n", sizeof (samples)); + + for (j = 0; j < TIMES; j++) { + pa_random (samples, sizeof (samples)); + memcpy (samples_ref, samples, sizeof (samples)); + memcpy (samples_orig, samples, sizeof (samples)); + + for (i = 0; i < CHANNELS; i++) + volumes[i] = rand() >> 15; + + for (padding = 0; padding < 16; padding++, i++) + volumes[i] = volumes[padding]; + + pa_volume_s16ne_sse (samples, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); + func (samples_ref, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); + + for (i = 0; i < SAMPLES; i++) { + if (samples[i] != samples_ref[i]) { + printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); + } +#if 0 + else + printf ("%d: %04x == %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); +#endif + } + } +} +#endif + +void pa_volume_func_init_sse (void) { + pa_log_info("Initialising SSE optimized functions."); + +#ifdef RUN_TEST + run_test (); +#endif + + pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse); +} -- cgit From 5998cf99b08d448dd5158ed6229262aa67ea4a66 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Aug 2009 13:45:01 +0200 Subject: svolume: improve SSE and MMX code --- src/pulsecore/svolume_mmx.c | 200 +++++++++++++++++++++++++++++--------------- src/pulsecore/svolume_sse.c | 191 +++++++++++++++++++++++++++++------------- 2 files changed, 268 insertions(+), 123 deletions(-) (limited to 'src') diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index 6dcc26c2..3c229456 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -99,6 +99,46 @@ pa_volume_ulaw_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsig } #endif +#define VOLUME_32x16(s,v) /* .. | vh | vl | */ \ + " pxor %%mm4, %%mm4 \n\t" /* .. | 0 | 0 | */ \ + " punpcklwd %%mm4, "#s" \n\t" /* .. | 0 | p0 | */ \ + " pcmpgtw "#v", %%mm4 \n\t" /* .. | 0 | s(vl) | */ \ + " pand "#s", %%mm4 \n\t" /* .. | 0 | (p0) | (vl >> 15) & p */ \ + " movq %%mm6, %%mm5 \n\t" /* .. | ffff | 0 | */ \ + " pand "#v", %%mm5 \n\t" /* .. | vh | 0 | */ \ + " por %%mm5, %%mm4 \n\t" /* .. | vh | (p0) | */ \ + " pmulhw "#s", "#v" \n\t" /* .. | 0 | vl*p0 | */ \ + " paddw %%mm4, "#v" \n\t" /* .. | vh | vl*p0 | vh + sign correct */ \ + " pslld $16, "#s" \n\t" /* .. | p0 | 0 | */ \ + " por %%mm7, "#s" \n\t" /* .. | p0 | 1 | */ \ + " pmaddwd "#s", "#v" \n\t" /* .. | p0 * v0 | */ \ + " packssdw "#v", "#v" \n\t" /* .. | p1*v1 | p0*v0 | */ + +#define MOD_ADD(a,b) \ + " add "#a", %3 \n\t" \ + " mov %3, %4 \n\t" \ + " sub "#b", %4 \n\t" \ + " cmp "#b", %3 \n\t" \ + " cmovae %4, %3 \n\t" + +/* swap 16 bits */ +#define SWAP_16(s) \ + " movq "#s", %%mm4 \n\t" /* .. | h l | */ \ + " psrlw $8, %%mm4 \n\t" /* .. | 0 h | */ \ + " psllw $8, "#s" \n\t" /* .. | l 0 | */ \ + " por %%mm4, "#s" \n\t" /* .. | l h | */ + +/* swap 2 registers 16 bits for better pairing */ +#define SWAP_16_2(s1,s2) \ + " movq "#s1", %%mm4 \n\t" /* .. | h l | */ \ + " movq "#s2", %%mm5 \n\t" \ + " psrlw $8, %%mm4 \n\t" /* .. | 0 h | */ \ + " psrlw $8, %%mm5 \n\t" \ + " psllw $8, "#s1" \n\t" /* .. | l 0 | */ \ + " psllw $8, "#s2" \n\t" \ + " por %%mm4, "#s1" \n\t" /* .. | l h | */ \ + " por %%mm5, "#s2" \n\t" + static void pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { @@ -108,38 +148,22 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi * we overread the volume array, which should have enough padding. */ channels = MAX (4, channels); -#define VOLUME_32x16(s,v) /* v1_h | v1_l | v0_h | v0_l */ \ - " pxor %%mm4, %%mm4 \n\t" \ - " punpcklwd %%mm4, "#s" \n\t" /* 0 | p1 | 0 | p0 */ \ - " pcmpgtw "#s", %%mm4 \n\t" /* select sign from sample */ \ - " pand "#v", %%mm4 \n\t" /* extract sign correction factors */ \ - " movq "#s", %%mm5 \n\t" \ - " pmulhuw "#v", "#s" \n\t" /* 0 | p1*v1lh | 0 | p0*v0lh */ \ - " psubd %%mm4, "#s" \n\t" /* sign correction */ \ - " psrld $16, "#v" \n\t" /* 0 | v1h | 0 | v0h */ \ - " pmaddwd %%mm5, "#v" \n\t" /* p1 * v1h | p0 * v0h */ \ - " paddd "#s", "#v" \n\t" /* p1 * v1 | p0 * v0 */ \ - " packssdw "#v", "#v" \n\t" /* p0*v0 | p1*v1 | p0*v0 | p1*v1 */ - -#define MOD_ADD(a,b) \ - " add "#a", %3 \n\t" \ - " mov %3, %4 \n\t" \ - " sub "#b", %4 \n\t" \ - " cmp "#b", %3 \n\t" \ - " cmovae %4, %3 \n\t" - __asm__ __volatile__ ( " xor %3, %3 \n\t" " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ + " pcmpeqw %%mm6, %%mm6 \n\t" /* .. | ffff | ffff | */ + " pcmpeqw %%mm7, %%mm7 \n\t" /* .. | ffff | ffff | */ + " pslld $16, %%mm6 \n\t" /* .. | ffff | 0 | */ + " psrld $31, %%mm7 \n\t" /* .. | 0 | 1 | */ " test $1, %2 \n\t" /* check for odd samples */ " je 2f \n\t" - " movd (%1, %3, 4), %%mm0 \n\t" /* do odd samples */ - " movw (%0), %4 \n\t" + " movd (%1, %3, 4), %%mm0 \n\t" /* | v0h | v0l | */ + " movw (%0), %4 \n\t" /* .. | p0 | */ " movd %4, %%mm1 \n\t" VOLUME_32x16 (%%mm1, %%mm0) - " movd %%mm0, %4 \n\t" + " movd %%mm0, %4 \n\t" /* .. | p0*v0 | */ " movw %4, (%0) \n\t" " add $2, %0 \n\t" MOD_ADD ($1, %5) @@ -149,11 +173,11 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi " test $1, %2 \n\t" /* check for odd samples */ " je 4f \n\t" - "3: \n\t" /* do samples in pairs of 2 */ - " movq (%1, %3, 4), %%mm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ - " movd (%0), %%mm1 \n\t" /* X | X | p1 | p0 */ + "3: \n\t" /* do samples in groups of 2 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ VOLUME_32x16 (%%mm1, %%mm0) - " movd %%mm0, (%0) \n\t" + " movd %%mm0, (%0) \n\t" /* | p1*v1 | p0*v0 | */ " add $4, %0 \n\t" MOD_ADD ($2, %5) @@ -162,15 +186,15 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi " cmp $0, %2 \n\t" " je 6f \n\t" - "5: \n\t" /* do samples in pairs of 4 */ - " movq (%1, %3, 4), %%mm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ - " movq 8(%1, %3, 4), %%mm2 \n\t" /* v3_h | v3_l | v2_h | v2_l */ - " movd (%0), %%mm1 \n\t" /* X | X | p1 | p0 */ - " movd 4(%0), %%mm3 \n\t" /* X | X | p3 | p2 */ + "5: \n\t" /* do samples in groups of 4 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movq 8(%1, %3, 4), %%mm2 \n\t" /* | v3h | v3l | v2h | v2l | */ + " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ + " movd 4(%0), %%mm3 \n\t" /* .. | p3 | p2 | */ VOLUME_32x16 (%%mm1, %%mm0) VOLUME_32x16 (%%mm3, %%mm2) - " movd %%mm0, (%0) \n\t" - " movd %%mm2, 4(%0) \n\t" + " movd %%mm0, (%0) \n\t" /* | p1*v1 | p0*v0 | */ + " movd %%mm2, 4(%0) \n\t" /* | p3*v3 | p2*v2 | */ " add $8, %0 \n\t" MOD_ADD ($4, %5) " dec %2 \n\t" @@ -185,30 +209,83 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi ); } -#if 0 static void pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + int64_t channel, temp; - length /= sizeof (int16_t); + /* the max number of samples we process at a time, this is also the max amount + * we overread the volume array, which should have enough padding. */ + channels = MAX (4, channels); - for (channel = 0; length; length--) { - int32_t t, hi, lo; + __asm__ __volatile__ ( + " xor %3, %3 \n\t" + " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ + " pcmpeqw %%mm6, %%mm6 \n\t" /* .. | ffff | ffff | */ + " pcmpeqw %%mm7, %%mm7 \n\t" /* .. | ffff | ffff | */ + " pslld $16, %%mm6 \n\t" /* .. | ffff | 0 | */ + " psrld $31, %%mm7 \n\t" /* .. | 0 | 1 | */ - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; + " test $1, %2 \n\t" /* check for odd samples */ + " je 2f \n\t" - t = (int32_t) PA_INT16_SWAP(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = PA_INT16_SWAP((int16_t) t); + " movd (%1, %3, 4), %%mm0 \n\t" /* | v0h | v0l | */ + " movw (%0), %4 \n\t" /* .. | p0 | */ + " rorw $8, %4 \n\t" + " movd %4, %%mm1 \n\t" + VOLUME_32x16 (%%mm1, %%mm0) + " movd %%mm0, %4 \n\t" /* .. | p0*v0 | */ + " rorw $8, %4 \n\t" + " movw %4, (%0) \n\t" + " add $2, %0 \n\t" + MOD_ADD ($1, %5) - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + "2: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ + " test $1, %2 \n\t" /* check for odd samples */ + " je 4f \n\t" + + "3: \n\t" /* do samples in groups of 2 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ + SWAP_16 (%%mm1) + VOLUME_32x16 (%%mm1, %%mm0) + SWAP_16 (%%mm0) + " movd %%mm0, (%0) \n\t" /* | p1*v1 | p0*v0 | */ + " add $4, %0 \n\t" + MOD_ADD ($2, %5) + + "4: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ + " cmp $0, %2 \n\t" + " je 6f \n\t" + + "5: \n\t" /* do samples in groups of 4 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movq 8(%1, %3, 4), %%mm2 \n\t" /* | v3h | v3l | v2h | v2l | */ + " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ + " movd 4(%0), %%mm3 \n\t" /* .. | p3 | p2 | */ + SWAP_16_2 (%%mm1, %%mm3) + VOLUME_32x16 (%%mm1, %%mm0) + VOLUME_32x16 (%%mm3, %%mm2) + SWAP_16_2 (%%mm0, %%mm2) + " movd %%mm0, (%0) \n\t" /* | p1*v1 | p0*v0 | */ + " movd %%mm2, 4(%0) \n\t" /* | p3*v3 | p2*v2 | */ + " add $8, %0 \n\t" + MOD_ADD ($4, %5) + " dec %2 \n\t" + " jne 5b \n\t" + + "6: \n\t" + " emms \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((int64_t)channel), "=&r" (temp) + : "r" ((int64_t)channels) + : "cc" + ); } +#if 0 static void pa_volume_float32ne_mmx (float *samples, float *volumes, unsigned channels, unsigned length) { @@ -366,42 +443,37 @@ pa_volume_s24_32re_mmx (uint32_t *samples, int32_t *volumes, unsigned channels, } #endif -#undef RUN_TEST +#define RUN_TEST #ifdef RUN_TEST #define CHANNELS 2 #define SAMPLES 1021 #define TIMES 1000 +#define PADDING 16 static void run_test (void) { int16_t samples[SAMPLES]; int16_t samples_ref[SAMPLES]; int16_t samples_orig[SAMPLES]; - int32_t volumes[CHANNELS + 16]; + int32_t volumes[CHANNELS + PADDING]; int i, j, padding; pa_do_volume_func_t func; - func = pa_get_volume_func (PA_SAMPLE_S16NE); + func = pa_get_volume_func (PA_SAMPLE_S16RE); - printf ("checking %d\n", sizeof (samples)); + printf ("checking MMX %d\n", sizeof (samples)); for (j = 0; j < TIMES; j++) { - /* - for (i = 0; i < SAMPLES; i++) { - samples[i] samples_ref[i] = samples_orig[i] = rand() >> 16; - } - */ - pa_random (samples, sizeof (samples)); memcpy (samples_ref, samples, sizeof (samples)); memcpy (samples_orig, samples, sizeof (samples)); for (i = 0; i < CHANNELS; i++) - volumes[i] = rand() >> 15; - for (padding = 0; padding < 16; padding++, i++) + volumes[i] = rand() >> 1; + for (padding = 0; padding < PADDING; padding++, i++) volumes[i] = volumes[padding]; - pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); + pa_volume_s16re_mmx (samples, volumes, CHANNELS, sizeof (samples)); func (samples_ref, volumes, CHANNELS, sizeof (samples)); for (i = 0; i < SAMPLES; i++) { @@ -409,11 +481,6 @@ static void run_test (void) { printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], samples_orig[i], volumes[i % CHANNELS]); } -#if 0 - else - printf ("%d: %04x == %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], - samples_orig[i], volumes[i % CHANNELS]); -#endif } } } @@ -427,4 +494,5 @@ void pa_volume_func_init_mmx (void) { #endif pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx); + pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx); } diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index 2d4c541b..ff583a06 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -99,6 +99,44 @@ pa_volume_ulaw_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsig } #endif +#define VOLUME_32x16(s,v) /* .. | vh | vl | */ \ + " pxor %%xmm4, %%xmm4 \n\t" /* .. | 0 | 0 | */ \ + " punpcklwd %%xmm4, "#s" \n\t" /* .. | 0 | p0 | */ \ + " pcmpgtw "#s", %%xmm4 \n\t" /* .. | 0 | s(p0) | */ \ + " pand "#v", %%xmm4 \n\t" /* .. | 0 | (vl) | */ \ + " movdqa "#s", %%xmm5 \n\t" \ + " pmulhuw "#v", "#s" \n\t" /* .. | 0 | vl*p0 | */ \ + " psubd %%xmm4, "#s" \n\t" /* .. | 0 | vl*p0 | + sign correct */ \ + " psrld $16, "#v" \n\t" /* .. | p0 | 0 | */ \ + " pmaddwd %%xmm5, "#v" \n\t" /* .. | p0 * vh | */ \ + " paddd "#s", "#v" \n\t" /* .. | p0 * v0 | */ \ + " packssdw "#v", "#v" \n\t" /* .. | p1*v1 | p0*v0 | */ + +#define MOD_ADD(a,b) \ + " add "#a", %3 \n\t" /* channel += inc */ \ + " mov %3, %4 \n\t" \ + " sub "#b", %4 \n\t" /* tmp = channel - channels */ \ + " cmp "#b", %3 \n\t" /* if (channel >= channels) */ \ + " cmovae %4, %3 \n\t" /* channel = tmp */ + +/* swap 16 bits */ +#define SWAP_16(s) \ + " movdqa "#s", %%xmm4 \n\t" /* .. | h l | */ \ + " psrlw $8, %%xmm4 \n\t" /* .. | 0 h | */ \ + " psllw $8, "#s" \n\t" /* .. | l 0 | */ \ + " por %%xmm4, "#s" \n\t" /* .. | l h | */ + +/* swap 2 registers 16 bits for better pairing */ +#define SWAP_16_2(s1,s2) \ + " movdqa "#s1", %%xmm4 \n\t" /* .. | h l | */ \ + " movdqa "#s2", %%xmm5 \n\t" \ + " psrlw $8, %%xmm4 \n\t" /* .. | 0 h | */ \ + " psrlw $8, %%xmm5 \n\t" \ + " psllw $8, "#s1" \n\t" /* .. | l 0 | */ \ + " psllw $8, "#s2" \n\t" \ + " por %%xmm4, "#s1" \n\t" /* .. | l h | */ \ + " por %%xmm5, "#s2" \n\t" + static void pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { @@ -109,25 +147,83 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi * we overread the volume array, which should have enough padding. */ channels = MAX (8, channels); -#define VOLUME_32x16(s,v) /* v1_h | v1_l | v0_h | v0_l */ \ - " pxor %%xmm4, %%xmm4 \n\t" \ - " punpcklwd %%xmm4, "#s" \n\t" /* 0 | p1 | 0 | p0 */ \ - " pcmpgtw "#s", %%xmm4 \n\t" /* select sign from sample */ \ - " pand "#v", %%xmm4 \n\t" /* extract sign correction factors */ \ - " movdqa "#s", %%xmm5 \n\t" \ - " pmulhuw "#v", "#s" \n\t" /* 0 | p1*v1lh | 0 | p0*v0lh */ \ - " psubd %%xmm4, "#s" \n\t" /* sign correction */ \ - " psrld $16, "#v" \n\t" /* 0 | v1h | 0 | v0h */ \ - " pmaddwd %%xmm5, "#v" \n\t" /* p1 * v1h | p0 * v0h */ \ - " paddd "#s", "#v" \n\t" /* p1 * v1 | p0 * v0 */ \ - " packssdw "#v", "#v" \n\t" /* p0*v0 | p1*v1 | p0*v0 | p1*v1 */ + __asm__ __volatile__ ( + " xor %3, %3 \n\t" + " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ -#define MOD_ADD(a,b) \ - " add "#a", %3 \n\t" \ - " mov %3, %4 \n\t" \ - " sub "#b", %4 \n\t" \ - " cmp "#b", %3 \n\t" \ - " cmovae %4, %3 \n\t" + " test $1, %2 \n\t" /* check for odd samples */ + " je 2f \n\t" + + " movd (%1, %3, 4), %%xmm0 \n\t" /* | v0h | v0l | */ + " movw (%0), %4 \n\t" /* .. | p0 | */ + " movd %4, %%xmm1 \n\t" + VOLUME_32x16 (%%xmm1, %%xmm0) + " movd %%xmm0, %4 \n\t" /* .. | p0*v0 | */ + " movw %4, (%0) \n\t" + " add $2, %0 \n\t" + MOD_ADD ($1, %5) + + "2: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ + " test $1, %2 \n\t" + " je 4f \n\t" + + "3: \n\t" /* do samples in groups of 2 */ + " movq (%1, %3, 4), %%xmm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movd (%0), %%xmm1 \n\t" /* .. | p1 | p0 | */ + VOLUME_32x16 (%%xmm1, %%xmm0) + " movd %%xmm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ + " add $4, %0 \n\t" + MOD_ADD ($2, %5) + + "4: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ + " test $1, %2 \n\t" + " je 6f \n\t" + + "5: \n\t" /* do samples in groups of 4 */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ + " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ + VOLUME_32x16 (%%xmm1, %%xmm0) + " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ + " add $8, %0 \n\t" + MOD_ADD ($4, %5) + + "6: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 8 samples at a time */ + " cmp $0, %2 \n\t" + " je 8f \n\t" + + "7: \n\t" /* do samples in groups of 8 */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ + " movdqu 16(%1, %3, 4), %%xmm2 \n\t" /* | v7h | v7l .. v4h | v4l | */ + " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ + " movq 8(%0), %%xmm3 \n\t" /* .. | p7 .. p4 | */ + VOLUME_32x16 (%%xmm1, %%xmm0) + VOLUME_32x16 (%%xmm3, %%xmm2) + " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ + " movq %%xmm2, 8(%0) \n\t" /* .. | p7*v7 .. p4*v4 | */ + " add $16, %0 \n\t" + MOD_ADD ($8, %5) + " dec %2 \n\t" + " jne 7b \n\t" + "8: \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp) + : "r" ((int64_t)channels) + : "cc" + ); +} + +static void +pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + int64_t channel; + int64_t temp; + + /* the max number of samples we process at a time, this is also the max amount + * we overread the volume array, which should have enough padding. */ + channels = MAX (8, channels); __asm__ __volatile__ ( " xor %3, %3 \n\t" @@ -138,9 +234,11 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi " movd (%1, %3, 4), %%xmm0 \n\t" /* do odd sample */ " movw (%0), %4 \n\t" + " rorw $8, %4 \n\t" " movd %4, %%xmm1 \n\t" VOLUME_32x16 (%%xmm1, %%xmm0) " movd %%xmm0, %4 \n\t" + " rorw $8, %4 \n\t" " movw %4, (%0) \n\t" " add $2, %0 \n\t" MOD_ADD ($1, %5) @@ -153,7 +251,9 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi "3: \n\t" /* do samples in pairs of 2 */ " movq (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ " movd (%0), %%xmm1 \n\t" /* X | X | p1 | p0 */ + SWAP_16 (%%xmm1) VOLUME_32x16 (%%xmm1, %%xmm0) + SWAP_16 (%%xmm0) " movd %%xmm0, (%0) \n\t" " add $4, %0 \n\t" MOD_ADD ($2, %5) @@ -164,9 +264,11 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi " je 6f \n\t" "5: \n\t" /* do samples in pairs of 4 */ - " movdqa (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ " movq (%0), %%xmm1 \n\t" /* X | X | p1 | p0 */ + SWAP_16 (%%xmm1) VOLUME_32x16 (%%xmm1, %%xmm0) + SWAP_16 (%%xmm0) " movq %%xmm0, (%0) \n\t" " add $8, %0 \n\t" MOD_ADD ($4, %5) @@ -177,12 +279,14 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi " je 8f \n\t" "7: \n\t" /* do samples in pairs of 8 */ - " movdqa (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ - " movdqa 16(%1, %3, 4), %%xmm2 \n\t" /* v3_h | v3_l | v2_h | v2_l */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ + " movdqu 16(%1, %3, 4), %%xmm2 \n\t" /* v3_h | v3_l | v2_h | v2_l */ " movq (%0), %%xmm1 \n\t" /* X | X | p1 | p0 */ " movq 8(%0), %%xmm3 \n\t" /* X | X | p3 | p2 */ + SWAP_16_2 (%%xmm1, %%xmm3) VOLUME_32x16 (%%xmm1, %%xmm0) VOLUME_32x16 (%%xmm3, %%xmm2) + SWAP_16_2 (%%xmm0, %%xmm2) " movq %%xmm0, (%0) \n\t" " movq %%xmm2, 8(%0) \n\t" " add $16, %0 \n\t" @@ -198,29 +302,6 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi } #if 0 -static void -pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (int16_t); - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) PA_INT16_SWAP(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = PA_INT16_SWAP((int16_t) t); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - static void pa_volume_float32ne_sse (float *samples, float *volumes, unsigned channels, unsigned length) { @@ -378,24 +459,25 @@ pa_volume_s24_32re_sse (uint32_t *samples, int32_t *volumes, unsigned channels, } #endif -#undef RUN_TEST +#define RUN_TEST #ifdef RUN_TEST #define CHANNELS 2 #define SAMPLES 1021 #define TIMES 1000 +#define PADDING 16 static void run_test (void) { int16_t samples[SAMPLES]; int16_t samples_ref[SAMPLES]; int16_t samples_orig[SAMPLES]; - int32_t volumes[CHANNELS + 16]; + int32_t volumes[CHANNELS + PADDING]; int i, j, padding; pa_do_volume_func_t func; - func = pa_get_volume_func (PA_SAMPLE_S16NE); + func = pa_get_volume_func (PA_SAMPLE_S16RE); - printf ("checking %d\n", sizeof (samples)); + printf ("checking SSE %d\n", sizeof (samples)); for (j = 0; j < TIMES; j++) { pa_random (samples, sizeof (samples)); @@ -403,12 +485,11 @@ static void run_test (void) { memcpy (samples_orig, samples, sizeof (samples)); for (i = 0; i < CHANNELS; i++) - volumes[i] = rand() >> 15; - - for (padding = 0; padding < 16; padding++, i++) + volumes[i] = rand() >> 1; + for (padding = 0; padding < PADDING; padding++, i++) volumes[i] = volumes[padding]; - pa_volume_s16ne_sse (samples, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); + pa_volume_s16re_sse (samples, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); func (samples_ref, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); for (i = 0; i < SAMPLES; i++) { @@ -416,11 +497,6 @@ static void run_test (void) { printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], samples_orig[i], volumes[i % CHANNELS]); } -#if 0 - else - printf ("%d: %04x == %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], - samples_orig[i], volumes[i % CHANNELS]); -#endif } } } @@ -434,4 +510,5 @@ void pa_volume_func_init_sse (void) { #endif pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse); + pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse); } -- cgit From a83f5524fbf2f0fa861d2fae6973f0f42e8c9c25 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Aug 2009 17:11:43 +0200 Subject: cpu-x86: add cpu detection code and helpers Add CPU detection code and various macros and typdefs to make it easier to write 64 and 32 bit code. --- src/Makefile.am | 1 + src/pulsecore/cpu-x86.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/cpu-x86.h | 61 ++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 src/pulsecore/cpu-x86.c create mode 100644 src/pulsecore/cpu-x86.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index b692e4a9..4e90d793 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -825,6 +825,7 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/resampler.c pulsecore/resampler.h \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ pulsecore/sample-util.c pulsecore/sample-util.h \ + pulsecore/cpu-x86.c \ pulsecore/svolume_c.c \ pulsecore/svolume_mmx.c pulsecore/svolume_sse.c \ pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \ diff --git a/src/pulsecore/cpu-x86.c b/src/pulsecore/cpu-x86.c new file mode 100644 index 00000000..2da31c92 --- /dev/null +++ b/src/pulsecore/cpu-x86.c @@ -0,0 +1,122 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include "cpu-x86.h" + +#if defined (__i386__) || defined (__amd64__) +static void +get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) +{ + __asm__ __volatile__ ( + " push %%"PA_REG_b" \n\t" + " cpuid \n\t" + " mov %%ebx, %%esi \n\t" + " pop %%"PA_REG_b" \n\t" + + : "=a" (*a), "=S" (*b), "=c" (*c), "=d" (*d) + : "0" (op)); +} +#endif + +static pa_cpu_x86_flag_t pa_cpu_x86_flags; + +void pa_cpu_init_x86 (void) { +#if defined (__i386__) || defined (__amd64__) + uint32_t eax, ebx, ecx, edx; + uint32_t level; + + /* get standard level */ + get_cpuid (0x00000000, &level, &ebx, &ecx, &edx); + if (level >= 1) { + get_cpuid (0x00000001, &eax, &ebx, &ecx, &edx); + + if (edx & (1<<23)) + pa_cpu_x86_flags |= PA_CPU_X86_MMX; + + if (edx & (1<<25)) + pa_cpu_x86_flags |= PA_CPU_X86_SSE; + + if (edx & (1<<26)) + pa_cpu_x86_flags |= PA_CPU_X86_SSE2; + + if (ecx & (1<<0)) + pa_cpu_x86_flags |= PA_CPU_X86_SSE3; + + if (ecx & (1<<9)) + pa_cpu_x86_flags |= PA_CPU_X86_SSSE3; + + if (ecx & (1<<19)) + pa_cpu_x86_flags |= PA_CPU_X86_SSE4_1; + + if (ecx & (1<<20)) + pa_cpu_x86_flags |= PA_CPU_X86_SSE4_2; + } + + /* get extended level */ + get_cpuid (0x80000000, &level, &ebx, &ecx, &edx); + if (level >= 0x80000001) { + get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx); + + if (edx & (1<<22)) + pa_cpu_x86_flags |= PA_CPU_X86_MMXEXT; + + if (edx & (1<<23)) + pa_cpu_x86_flags |= PA_CPU_X86_MMX; + + if (edx & (1<<30)) + pa_cpu_x86_flags |= PA_CPU_X86_3DNOWEXT; + + if (edx & (1<<31)) + pa_cpu_x86_flags |= PA_CPU_X86_3DNOW; + } + + pa_log_info ("CPU flags: %s%s%s%s%s%s%s%s%s%s", + (pa_cpu_x86_flags & PA_CPU_X86_MMX) ? "MMX " : "", + (pa_cpu_x86_flags & PA_CPU_X86_SSE) ? "SSE " : "", + (pa_cpu_x86_flags & PA_CPU_X86_SSE2) ? "SSE2 " : "", + (pa_cpu_x86_flags & PA_CPU_X86_SSE3) ? "SSE3 " : "", + (pa_cpu_x86_flags & PA_CPU_X86_SSSE3) ? "SSSE3 " : "", + (pa_cpu_x86_flags & PA_CPU_X86_SSE4_1) ? "SSE4_1 " : "", + (pa_cpu_x86_flags & PA_CPU_X86_SSE4_2) ? "SSE4_2 " : "", + (pa_cpu_x86_flags & PA_CPU_X86_MMXEXT) ? "MMXEXT " : "", + (pa_cpu_x86_flags & PA_CPU_X86_3DNOW) ? "3DNOW " : "", + (pa_cpu_x86_flags & PA_CPU_X86_3DNOWEXT) ? "3DNOWEXT " : ""); + + /* activate various optimisations */ + if (pa_cpu_x86_flags & PA_CPU_X86_MMX) { + pa_volume_func_init_mmx (pa_cpu_x86_flags); + } + if (pa_cpu_x86_flags & PA_CPU_X86_SSE) { + pa_volume_func_init_sse (pa_cpu_x86_flags); + } +#else + pa_cpu_x86_flags = 0; +#endif +} diff --git a/src/pulsecore/cpu-x86.h b/src/pulsecore/cpu-x86.h new file mode 100644 index 00000000..8158ea7a --- /dev/null +++ b/src/pulsecore/cpu-x86.h @@ -0,0 +1,61 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef enum pa_cpu_x86_flag { + PA_CPU_X86_MMX = (1 << 0), + PA_CPU_X86_MMXEXT = (1 << 1), + PA_CPU_X86_SSE = (1 << 2), + PA_CPU_X86_SSE2 = (1 << 3), + PA_CPU_X86_SSE3 = (1 << 4), + PA_CPU_X86_SSSE3 = (1 << 5), + PA_CPU_X86_SSE4_1 = (1 << 6), + PA_CPU_X86_SSE4_2 = (1 << 7), + PA_CPU_X86_3DNOW = (1 << 8), + PA_CPU_X86_3DNOWEXT = (1 << 9) +} pa_cpu_x86_flag_t; + +void pa_cpu_init_x86 (void); + + +#if defined (__i386__) +typedef int32_t pa_reg_x86; +#define PA_REG_a "eax" +#define PA_REG_b "ebx" +#define PA_REG_c "ecx" +#define PA_REG_d "edx" +#define PA_REG_D "edi" +#define PA_REG_S "esi" +#elif defined (__amd64__) +typedef int64_t pa_reg_x86; +#define PA_REG_a "rax" +#define PA_REG_b "rbx" +#define PA_REG_c "rcx" +#define PA_REG_d "rdx" +#define PA_REG_D "rdi" +#define PA_REG_S "rsi" +#endif + +/* some optimized functions */ +void pa_volume_func_init_mmx(pa_cpu_x86_flag_t flags); +void pa_volume_func_init_sse(pa_cpu_x86_flag_t flags); -- cgit From 563cb2dea9f7f73180e2b8cc8d45b0df9358c936 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Aug 2009 17:12:44 +0200 Subject: main: hook up cpu detection code Add CPU detection code to activate the various optimisations. Move some method definitions around. Use compatibility macros when we can. --- src/daemon/main.c | 4 ++-- src/pulsecore/sample-util.h | 3 --- src/pulsecore/svolume_mmx.c | 18 ++++++++++-------- src/pulsecore/svolume_sse.c | 16 ++++++++-------- 4 files changed, 20 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/daemon/main.c b/src/daemon/main.c index 3c5f7f95..774b4e90 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -95,6 +95,7 @@ #ifdef HAVE_DBUS #include #endif +#include #include "cmdline.h" #include "cpulimit.h" @@ -821,8 +822,7 @@ int main(int argc, char *argv[]) { pa_memtrap_install(); - pa_volume_func_init_mmx(); - pa_volume_func_init_sse(); + pa_cpu_init_x86(); pa_assert_se(mainloop = pa_mainloop_new()); diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 563dbb6a..34df5cf3 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -91,9 +91,6 @@ typedef void (*pa_do_volume_func_t) (void *samples, void *volumes, unsigned chan pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f); void pa_set_volume_func(pa_sample_format_t f, pa_do_volume_func_t func); -void pa_volume_func_init_mmx(void); -void pa_volume_func_init_sse(void); - #define PA_CHANNEL_POSITION_MASK_LEFT \ (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \ | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT) \ diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index 3c229456..e56f7c31 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -31,6 +31,8 @@ #include #include +#include "cpu-x86.h" + #include "sample-util.h" #include "endianmacros.h" @@ -142,7 +144,7 @@ pa_volume_ulaw_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsig static void pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - int64_t channel, temp; + pa_reg_x86 channel, temp; /* the max number of samples we process at a time, this is also the max amount * we overread the volume array, which should have enough padding. */ @@ -203,8 +205,8 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi "6: \n\t" " emms \n\t" - : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((int64_t)channel), "=&r" (temp) - : "r" ((int64_t)channels) + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp) + : "r" ((pa_reg_x86)channels) : "cc" ); } @@ -212,7 +214,7 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi static void pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - int64_t channel, temp; + pa_reg_x86 channel, temp; /* the max number of samples we process at a time, this is also the max amount * we overread the volume array, which should have enough padding. */ @@ -279,8 +281,8 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi "6: \n\t" " emms \n\t" - : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((int64_t)channel), "=&r" (temp) - : "r" ((int64_t)channels) + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp) + : "r" ((pa_reg_x86)channels) : "cc" ); } @@ -443,7 +445,7 @@ pa_volume_s24_32re_mmx (uint32_t *samples, int32_t *volumes, unsigned channels, } #endif -#define RUN_TEST +#undef RUN_TEST #ifdef RUN_TEST #define CHANNELS 2 @@ -486,7 +488,7 @@ static void run_test (void) { } #endif -void pa_volume_func_init_mmx (void) { +void pa_volume_func_init_mmx (pa_cpu_x86_flag_t flags) { pa_log_info("Initialising MMX optimized functions."); #ifdef RUN_TEST diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index ff583a06..b60471a7 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -31,6 +31,8 @@ #include #include +#include "cpu-x86.h" + #include "sample-util.h" #include "endianmacros.h" @@ -140,8 +142,7 @@ pa_volume_ulaw_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsig static void pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - int64_t channel; - int64_t temp; + pa_reg_x86 channel, temp; /* the max number of samples we process at a time, this is also the max amount * we overread the volume array, which should have enough padding. */ @@ -210,7 +211,7 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi "8: \n\t" : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp) - : "r" ((int64_t)channels) + : "r" ((pa_reg_x86)channels) : "cc" ); } @@ -218,8 +219,7 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi static void pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - int64_t channel; - int64_t temp; + pa_reg_x86 channel, temp; /* the max number of samples we process at a time, this is also the max amount * we overread the volume array, which should have enough padding. */ @@ -296,7 +296,7 @@ pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi "8: \n\t" : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp) - : "r" ((int64_t)channels) + : "r" ((pa_reg_x86)channels) : "cc" ); } @@ -459,7 +459,7 @@ pa_volume_s24_32re_sse (uint32_t *samples, int32_t *volumes, unsigned channels, } #endif -#define RUN_TEST +#undef RUN_TEST #ifdef RUN_TEST #define CHANNELS 2 @@ -502,7 +502,7 @@ static void run_test (void) { } #endif -void pa_volume_func_init_sse (void) { +void pa_volume_func_init_sse (pa_cpu_x86_flag_t flags) { pa_log_info("Initialising SSE optimized functions."); #ifdef RUN_TEST -- cgit From e396fe67fb3b0acec40c2334c426bcb284163d20 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 13 Aug 2009 17:22:39 +0200 Subject: cpu-x86: guard header with ifdef --- src/pulsecore/cpu-x86.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/pulsecore/cpu-x86.h b/src/pulsecore/cpu-x86.h index 8158ea7a..07e630ea 100644 --- a/src/pulsecore/cpu-x86.h +++ b/src/pulsecore/cpu-x86.h @@ -1,3 +1,6 @@ +#ifndef foocpux86hfoo +#define foocpux86hfoo + /*** This file is part of PulseAudio. @@ -59,3 +62,5 @@ typedef int64_t pa_reg_x86; /* some optimized functions */ void pa_volume_func_init_mmx(pa_cpu_x86_flag_t flags); void pa_volume_func_init_sse(pa_cpu_x86_flag_t flags); + +#endif /* foocpux86hfoo */ -- cgit From dcae9a3113d1ce30e330c97dd5a81fec4e272bed Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 14 Aug 2009 13:12:30 +0200 Subject: svolume: add some comments --- src/pulsecore/svolume_mmx.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src') diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index e56f7c31..b36fe946 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -101,6 +101,22 @@ pa_volume_ulaw_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsig } #endif +/* in s: 2 int16_t samples + * in v: 2 int32_t volumes, fixed point 16:16 + * out s: contains scaled and clamped int16_t samples. + * + * We calculate the high 32 bits of a 32x16 multiply which we then + * clamp to 16 bits. The calulcation is: + * + * vl = (v & 0xffff) + * vh = (v >> 16) + * s = ((s * vl) >> 16) + (s * vh); + * + * For the first multiply we have to do a sign correction as we need to + * multiply a signed int with an unsigned int. Hacker's delight 8-3 gives a + * simple formula to correct the sign of the high word after the signed + * multiply. + */ #define VOLUME_32x16(s,v) /* .. | vh | vl | */ \ " pxor %%mm4, %%mm4 \n\t" /* .. | 0 | 0 | */ \ " punpcklwd %%mm4, "#s" \n\t" /* .. | 0 | p0 | */ \ @@ -116,6 +132,8 @@ pa_volume_ulaw_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsig " pmaddwd "#s", "#v" \n\t" /* .. | p0 * v0 | */ \ " packssdw "#v", "#v" \n\t" /* .. | p1*v1 | p0*v0 | */ +/* approximately advances %3 = (%3 + a) % b. This function requires that + * a <= b. */ #define MOD_ADD(a,b) \ " add "#a", %3 \n\t" \ " mov %3, %4 \n\t" \ -- cgit From a1235446a733164f00a96688784913172456a34e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 14 Aug 2009 15:19:26 +0200 Subject: volume: make the benchmark more meaningfull MMX is about 6x faster, SSE around 15x on my machine. --- src/pulsecore/svolume_mmx.c | 53 +++++++++++++++++++++++++--------------- src/pulsecore/svolume_sse.c | 59 +++++++++++++++++++++++++++------------------ 2 files changed, 69 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index b36fe946..9ad7dea1 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -24,8 +24,7 @@ #include #endif -#include - +#include #include #include #include @@ -478,31 +477,45 @@ static void run_test (void) { int32_t volumes[CHANNELS + PADDING]; int i, j, padding; pa_do_volume_func_t func; + struct timeval start, stop; - func = pa_get_volume_func (PA_SAMPLE_S16RE); - - printf ("checking MMX %d\n", sizeof (samples)); + func = pa_get_volume_func (PA_SAMPLE_S16NE); - for (j = 0; j < TIMES; j++) { - pa_random (samples, sizeof (samples)); - memcpy (samples_ref, samples, sizeof (samples)); - memcpy (samples_orig, samples, sizeof (samples)); + printf ("checking MMX %zd\n", sizeof (samples)); - for (i = 0; i < CHANNELS; i++) - volumes[i] = rand() >> 1; - for (padding = 0; padding < PADDING; padding++, i++) - volumes[i] = volumes[padding]; + pa_random (samples, sizeof (samples)); + memcpy (samples_ref, samples, sizeof (samples)); + memcpy (samples_orig, samples, sizeof (samples)); - pa_volume_s16re_mmx (samples, volumes, CHANNELS, sizeof (samples)); - func (samples_ref, volumes, CHANNELS, sizeof (samples)); + for (i = 0; i < CHANNELS; i++) + volumes[i] = rand() >> 1; + for (padding = 0; padding < PADDING; padding++, i++) + volumes[i] = volumes[padding]; - for (i = 0; i < SAMPLES; i++) { - if (samples[i] != samples_ref[i]) { - printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], - samples_orig[i], volumes[i % CHANNELS]); - } + func (samples_ref, volumes, CHANNELS, sizeof (samples)); + pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); + for (i = 0; i < SAMPLES; i++) { + if (samples[i] != samples_ref[i]) { + printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); } } + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples, samples_orig, sizeof (samples)); + pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("MMX: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples_ref, samples_orig, sizeof (samples)); + func (samples_ref, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); } #endif diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index b60471a7..8138c6c1 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -24,8 +24,7 @@ #include #endif -#include - +#include #include #include #include @@ -459,7 +458,7 @@ pa_volume_s24_32re_sse (uint32_t *samples, int32_t *volumes, unsigned channels, } #endif -#undef RUN_TEST +#define RUN_TEST #ifdef RUN_TEST #define CHANNELS 2 @@ -474,31 +473,45 @@ static void run_test (void) { int32_t volumes[CHANNELS + PADDING]; int i, j, padding; pa_do_volume_func_t func; + struct timeval start, stop; - func = pa_get_volume_func (PA_SAMPLE_S16RE); + func = pa_get_volume_func (PA_SAMPLE_S16NE); - printf ("checking SSE %d\n", sizeof (samples)); + printf ("checking SSE %zd\n", sizeof (samples)); - for (j = 0; j < TIMES; j++) { - pa_random (samples, sizeof (samples)); - memcpy (samples_ref, samples, sizeof (samples)); - memcpy (samples_orig, samples, sizeof (samples)); - - for (i = 0; i < CHANNELS; i++) - volumes[i] = rand() >> 1; - for (padding = 0; padding < PADDING; padding++, i++) - volumes[i] = volumes[padding]; - - pa_volume_s16re_sse (samples, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); - func (samples_ref, volumes, CHANNELS, SAMPLES * sizeof (int16_t)); - - for (i = 0; i < SAMPLES; i++) { - if (samples[i] != samples_ref[i]) { - printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], - samples_orig[i], volumes[i % CHANNELS]); - } + pa_random (samples, sizeof (samples)); + memcpy (samples_ref, samples, sizeof (samples)); + memcpy (samples_orig, samples, sizeof (samples)); + + for (i = 0; i < CHANNELS; i++) + volumes[i] = rand() >> 1; + for (padding = 0; padding < PADDING; padding++, i++) + volumes[i] = volumes[padding]; + + func (samples_ref, volumes, CHANNELS, sizeof (samples)); + pa_volume_s16ne_sse (samples, volumes, CHANNELS, sizeof (samples)); + for (i = 0; i < SAMPLES; i++) { + if (samples[i] != samples_ref[i]) { + printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); } } + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples, samples_orig, sizeof (samples)); + pa_volume_s16ne_sse (samples, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("SSE: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples_ref, samples_orig, sizeof (samples)); + func (samples_ref, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); } #endif -- cgit From f24c24c14b6614cf19ee916886c8b02384bac435 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 14 Aug 2009 15:41:32 +0200 Subject: volume: improved comments --- src/pulsecore/svolume_mmx.c | 12 ++++++------ src/pulsecore/svolume_sse.c | 45 ++++++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index 9ad7dea1..d4fcedf5 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -196,7 +196,7 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ VOLUME_32x16 (%%mm1, %%mm0) - " movd %%mm0, (%0) \n\t" /* | p1*v1 | p0*v0 | */ + " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ " add $4, %0 \n\t" MOD_ADD ($2, %5) @@ -212,8 +212,8 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi " movd 4(%0), %%mm3 \n\t" /* .. | p3 | p2 | */ VOLUME_32x16 (%%mm1, %%mm0) VOLUME_32x16 (%%mm3, %%mm2) - " movd %%mm0, (%0) \n\t" /* | p1*v1 | p0*v0 | */ - " movd %%mm2, 4(%0) \n\t" /* | p3*v3 | p2*v2 | */ + " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ + " movd %%mm2, 4(%0) \n\t" /* .. | p3*v3 | p2*v2 | */ " add $8, %0 \n\t" MOD_ADD ($4, %5) " dec %2 \n\t" @@ -270,7 +270,7 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi SWAP_16 (%%mm1) VOLUME_32x16 (%%mm1, %%mm0) SWAP_16 (%%mm0) - " movd %%mm0, (%0) \n\t" /* | p1*v1 | p0*v0 | */ + " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ " add $4, %0 \n\t" MOD_ADD ($2, %5) @@ -288,8 +288,8 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi VOLUME_32x16 (%%mm1, %%mm0) VOLUME_32x16 (%%mm3, %%mm2) SWAP_16_2 (%%mm0, %%mm2) - " movd %%mm0, (%0) \n\t" /* | p1*v1 | p0*v0 | */ - " movd %%mm2, 4(%0) \n\t" /* | p3*v3 | p2*v2 | */ + " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ + " movd %%mm2, 4(%0) \n\t" /* .. | p3*v3 | p2*v2 | */ " add $8, %0 \n\t" MOD_ADD ($4, %5) " dec %2 \n\t" diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index 8138c6c1..d95fa9d9 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -231,12 +231,12 @@ pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi " test $1, %2 \n\t" /* check for odd samples */ " je 2f \n\t" - " movd (%1, %3, 4), %%xmm0 \n\t" /* do odd sample */ - " movw (%0), %4 \n\t" + " movd (%1, %3, 4), %%xmm0 \n\t" /* | v0h | v0l | */ + " movw (%0), %4 \n\t" /* .. | p0 | */ " rorw $8, %4 \n\t" " movd %4, %%xmm1 \n\t" VOLUME_32x16 (%%xmm1, %%xmm0) - " movd %%xmm0, %4 \n\t" + " movd %%xmm0, %4 \n\t" /* .. | p0*v0 | */ " rorw $8, %4 \n\t" " movw %4, (%0) \n\t" " add $2, %0 \n\t" @@ -244,31 +244,34 @@ pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi "2: \n\t" " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ - " test $1, %2 \n\t" /* check for odd samples */ + " test $1, %2 \n\t" " je 4f \n\t" - "3: \n\t" /* do samples in pairs of 2 */ - " movq (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ - " movd (%0), %%xmm1 \n\t" /* X | X | p1 | p0 */ + "3: \n\t" /* do samples in groups of 2 */ + " movq (%1, %3, 4), %%xmm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movd (%0), %%xmm1 \n\t" /* .. | p1 | p0 | */ SWAP_16 (%%xmm1) VOLUME_32x16 (%%xmm1, %%xmm0) SWAP_16 (%%xmm0) - " movd %%xmm0, (%0) \n\t" + " movd %%xmm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ " add $4, %0 \n\t" MOD_ADD ($2, %5) "4: \n\t" " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ - " test $1, %2 \n\t" /* check for odd samples */ + " test $1, %2 \n\t" " je 6f \n\t" - "5: \n\t" /* do samples in pairs of 4 */ - " movdqu (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ - " movq (%0), %%xmm1 \n\t" /* X | X | p1 | p0 */ + /* FIXME, we can do aligned access of the volume values if we can guarantee + * that the array is 16 bytes aligned, we probably have to do the odd values + * after this then. */ + "5: \n\t" /* do samples in groups of 4 */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ + " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ SWAP_16 (%%xmm1) VOLUME_32x16 (%%xmm1, %%xmm0) SWAP_16 (%%xmm0) - " movq %%xmm0, (%0) \n\t" + " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ " add $8, %0 \n\t" MOD_ADD ($4, %5) @@ -277,17 +280,17 @@ pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi " cmp $0, %2 \n\t" " je 8f \n\t" - "7: \n\t" /* do samples in pairs of 8 */ - " movdqu (%1, %3, 4), %%xmm0 \n\t" /* v1_h | v1_l | v0_h | v0_l */ - " movdqu 16(%1, %3, 4), %%xmm2 \n\t" /* v3_h | v3_l | v2_h | v2_l */ - " movq (%0), %%xmm1 \n\t" /* X | X | p1 | p0 */ - " movq 8(%0), %%xmm3 \n\t" /* X | X | p3 | p2 */ + "7: \n\t" /* do samples in groups of 8 */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ + " movdqu 16(%1, %3, 4), %%xmm2 \n\t" /* | v7h | v7l .. v4h | v4l | */ + " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ + " movq 8(%0), %%xmm3 \n\t" /* .. | p7 .. p4 | */ SWAP_16_2 (%%xmm1, %%xmm3) VOLUME_32x16 (%%xmm1, %%xmm0) VOLUME_32x16 (%%xmm3, %%xmm2) SWAP_16_2 (%%xmm0, %%xmm2) - " movq %%xmm0, (%0) \n\t" - " movq %%xmm2, 8(%0) \n\t" + " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ + " movq %%xmm2, 8(%0) \n\t" /* .. | p7*v7 .. p4*v4 | */ " add $16, %0 \n\t" MOD_ADD ($8, %5) " dec %2 \n\t" @@ -458,7 +461,7 @@ pa_volume_s24_32re_sse (uint32_t *samples, int32_t *volumes, unsigned channels, } #endif -#define RUN_TEST +#undef RUN_TEST #ifdef RUN_TEST #define CHANNELS 2 -- cgit From 591baacba5913de32e6556a71a8300d25addbec4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 14 Aug 2009 15:48:10 +0200 Subject: volume: remove ref functions --- src/pulsecore/svolume_mmx.c | 223 -------------------------------------------- src/pulsecore/svolume_sse.c | 223 -------------------------------------------- 2 files changed, 446 deletions(-) (limited to 'src') diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index d4fcedf5..ad539278 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -35,71 +35,6 @@ #include "sample-util.h" #include "endianmacros.h" -#if 0 -static void -pa_volume_u8_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) *samples - 0x80; - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); - *samples++ = (uint8_t) (t + 0x80); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_alaw_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) st_alaw2linear16(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_ulaw_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) st_ulaw2linear16(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} -#endif - /* in s: 2 int16_t samples * in v: 2 int32_t volumes, fixed point 16:16 * out s: contains scaled and clamped int16_t samples. @@ -304,164 +239,6 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi ); } -#if 0 -static void -pa_volume_float32ne_mmx (float *samples, float *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (float); - - for (channel = 0; length; length--) { - *samples++ *= volumes[channel]; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_float32re_mmx (float *samples, float *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (float); - - for (channel = 0; length; length--) { - float t; - - t = PA_FLOAT32_SWAP(*samples); - t *= volumes[channel]; - *samples++ = PA_FLOAT32_SWAP(t); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s32ne_mmx (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (int32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t)(*samples); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = (int32_t) t; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s32re_mmx (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (int32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t) PA_INT32_SWAP(*samples); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = PA_INT32_SWAP((int32_t) t); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24ne_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - uint8_t *e; - - e = samples + length; - - for (channel = 0; samples < e; samples += 3) { - int64_t t; - - t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24re_mmx (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - uint8_t *e; - - e = samples + length; - - for (channel = 0; samples < e; samples += 3) { - int64_t t; - - t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24_32ne_mmx (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (uint32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t) ((int32_t) (*samples << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = ((uint32_t) ((int32_t) t)) >> 8; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24_32re_mmx (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (uint32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} -#endif - #undef RUN_TEST #ifdef RUN_TEST diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index d95fa9d9..b0a6e0dd 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -35,71 +35,6 @@ #include "sample-util.h" #include "endianmacros.h" -#if 0 -static void -pa_volume_u8_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) *samples - 0x80; - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); - *samples++ = (uint8_t) (t + 0x80); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_alaw_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) st_alaw2linear16(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_ulaw_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - for (channel = 0; length; length--) { - int32_t t, hi, lo; - - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; - - t = (int32_t) st_ulaw2linear16(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} -#endif - #define VOLUME_32x16(s,v) /* .. | vh | vl | */ \ " pxor %%xmm4, %%xmm4 \n\t" /* .. | 0 | 0 | */ \ " punpcklwd %%xmm4, "#s" \n\t" /* .. | 0 | p0 | */ \ @@ -303,164 +238,6 @@ pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi ); } -#if 0 -static void -pa_volume_float32ne_sse (float *samples, float *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (float); - - for (channel = 0; length; length--) { - *samples++ *= volumes[channel]; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_float32re_sse (float *samples, float *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (float); - - for (channel = 0; length; length--) { - float t; - - t = PA_FLOAT32_SWAP(*samples); - t *= volumes[channel]; - *samples++ = PA_FLOAT32_SWAP(t); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s32ne_sse (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (int32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t)(*samples); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = (int32_t) t; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s32re_sse (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (int32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t) PA_INT32_SWAP(*samples); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = PA_INT32_SWAP((int32_t) t); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24ne_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - uint8_t *e; - - e = samples + length; - - for (channel = 0; samples < e; samples += 3) { - int64_t t; - - t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24re_sse (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - uint8_t *e; - - e = samples + length; - - for (channel = 0; samples < e; samples += 3) { - int64_t t; - - t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24_32ne_sse (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (uint32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t) ((int32_t) (*samples << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = ((uint32_t) ((int32_t) t)) >> 8; - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} - -static void -pa_volume_s24_32re_sse (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) -{ - unsigned channel; - - length /= sizeof (uint32_t); - - for (channel = 0; length; length--) { - int64_t t; - - t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); - - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } -} -#endif - #undef RUN_TEST #ifdef RUN_TEST -- cgit From 25724cdd40283a00e6edd9449d0f3cf16823b41b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 14 Aug 2009 19:45:39 +0200 Subject: Get rid of liboil Get rid of the liboil dependency and reimplement the liboil functions with an equivalent C implementation. Note that most of these functions are deprecated in liboil and that none of them had any optimisations. We can further specialize our handrolled versions for some extra speedups. --- src/daemon/main.c | 4 --- src/pulsecore/resampler.c | 69 ++++++++++++++++++++++++--------------------- src/pulsecore/sconv-s16le.c | 42 +++++++++++---------------- src/pulsecore/sconv.c | 28 ++++++++---------- src/tests/envelope-test.c | 3 -- src/tests/mix-test.c | 3 -- src/tests/remix-test.c | 3 -- src/tests/resampler-test.c | 3 -- 8 files changed, 65 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/src/daemon/main.c b/src/daemon/main.c index 774b4e90..31e434d9 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -39,8 +39,6 @@ #include #include -#include - #ifdef HAVE_SYS_MMAN_H #include #endif @@ -863,8 +861,6 @@ int main(int argc, char *argv[]) { win32_timer = pa_mainloop_get_api(mainloop)->rtclock_time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&win32_tv), message_cb, NULL); #endif - oil_init(); - if (!conf->no_cpu_limit) pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0); diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 59e0a0c1..a3c17f8c 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -31,9 +31,6 @@ #include -#include -#include - #include #include #include @@ -1045,33 +1042,46 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) return &r->buf1; } -static void vectoradd_s16_with_fraction( - int16_t *d, int dstr, - const int16_t *s1, int sstr1, - const int16_t *s2, int sstr2, - int n, - float s3, float s4) { +static void vectoradd_f32( + float *d, int dstr, + const float *s, int sstr, + int n, float s4) { - int32_t i3, i4; + for (; n > 0; n--) { + *d = (float) (*d + (s4 * *s)); - i3 = (int32_t) (s3 * 0x10000); - i4 = (int32_t) (s4 * 0x10000); + s = (const float*) ((const uint8_t*) s + sstr); + d = (float*) ((uint8_t*) d + dstr); + } +} + +static void vectoradd_s16( + int16_t *d, int dstr, + const int16_t *s, int sstr, + int n) { for (; n > 0; n--) { - int32_t a, b; + *d = (int16_t) (*d + *s); - a = *s1; - b = *s2; + s = (const int16_t*) ((const uint8_t*) s + sstr); + d = (int16_t*) ((uint8_t*) d + dstr); + } +} - a = (a * i3) / 0x10000; - b = (b * i4) / 0x10000; +static void vectoradd_s16_with_fraction( + int16_t *d, int dstr, + const int16_t *s, int sstr, + int n, float s4) { - *d = (int16_t) (a + b); + int32_t i4; - s1 = (const int16_t*) ((const uint8_t*) s1 + sstr1); - s2 = (const int16_t*) ((const uint8_t*) s2 + sstr2); - d = (int16_t*) ((uint8_t*) d + dstr); + i4 = (int32_t) (s4 * 0x10000); + + for (; n > 0; n--) { + *d = (int16_t) (*d + (((int32_t)*s * i4) >> 16)); + s = (const int16_t*) ((const uint8_t*) s + sstr); + d = (int16_t*) ((uint8_t*) d + dstr); } } @@ -1125,12 +1135,11 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { if (r->map_table[oc][ic] <= 0.0) continue; - oil_vectoradd_f32( - (float*) dst + oc, o_skip, + vectoradd_f32( (float*) dst + oc, o_skip, (float*) src + ic, i_skip, (int) n_frames, - &one, &r->map_table[oc][ic]); + r->map_table[oc][ic]); } } @@ -1147,23 +1156,19 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { continue; if (r->map_table[oc][ic] >= 1.0) { - static const int16_t one = 1; - oil_vectoradd_s16( - (int16_t*) dst + oc, o_skip, + vectoradd_s16( (int16_t*) dst + oc, o_skip, (int16_t*) src + ic, i_skip, - (int) n_frames, - &one, &one); + (int) n_frames); } else vectoradd_s16_with_fraction( - (int16_t*) dst + oc, o_skip, (int16_t*) dst + oc, o_skip, (int16_t*) src + ic, i_skip, (int) n_frames, - 1.0f, r->map_table[oc][ic]); + r->map_table[oc][ic]); } } @@ -1469,7 +1474,7 @@ static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned pa_assert(o_index * fz < pa_memblock_get_length(output->memblock)); - oil_memcpy((uint8_t*) dst + fz * o_index, + memcpy((uint8_t*) dst + fz * o_index, (uint8_t*) src + fz * j, (int) fz); } diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c index 43b8cb3e..0fefdf1c 100644 --- a/src/pulsecore/sconv-s16le.c +++ b/src/pulsecore/sconv-s16le.c @@ -28,8 +28,6 @@ #include #include -#include - #include #include #include @@ -86,17 +84,13 @@ void pa_sconv_s16le_to_float32ne(unsigned n, const int16_t *a, float *b) { pa_assert(b); #if SWAP_WORDS == 1 - for (; n > 0; n--) { int16_t s = *(a++); *(b++) = ((float) INT16_FROM(s))/(float) 0x7FFF; } - #else -{ - static const double add = 0, factor = 1.0/0x7FFF; - oil_scaleconv_f32_s16(b, a, (int) n, &add, &factor); -} + for (; n > 0; n--) + *(b++) = ((float) (*(a++)))/(float) 0x7FFF; #endif } @@ -105,17 +99,13 @@ void pa_sconv_s32le_to_float32ne(unsigned n, const int32_t *a, float *b) { pa_assert(b); #if SWAP_WORDS == 1 - for (; n > 0; n--) { int32_t s = *(a++); *(b++) = (float) (((double) INT32_FROM(s))/0x7FFFFFFF); } - #else -{ - static const double add = 0, factor = 1.0/0x7FFFFFFF; - oil_scaleconv_f32_s32(b, a, (int) n, &add, &factor); -} + for (; n > 0; n--) + *(b++) = (float) (((double) (*(a++)))/0x7FFFFFFF); #endif } @@ -124,7 +114,6 @@ void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b) { pa_assert(b); #if SWAP_WORDS == 1 - for (; n > 0; n--) { int16_t s; float v = *(a++); @@ -133,12 +122,13 @@ void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b) { s = (int16_t) lrintf(v * 0x7FFF); *(b++) = INT16_TO(s); } - #else -{ - static const double add = 0, factor = 0x7FFF; - oil_scaleconv_s16_f32(b, a, (int) n, &add, &factor); -} + for (; n > 0; n--) { + float v = *(a++); + + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.f); + *(b++) = (int16_t) lrintf(v * 0x7FFF); + } #endif } @@ -147,7 +137,6 @@ void pa_sconv_s32le_from_float32ne(unsigned n, const float *a, int32_t *b) { pa_assert(b); #if SWAP_WORDS == 1 - for (; n > 0; n--) { int32_t s; float v = *(a++); @@ -156,12 +145,13 @@ void pa_sconv_s32le_from_float32ne(unsigned n, const float *a, int32_t *b) { s = (int32_t) lrint((double) v * (double) 0x7FFFFFFF); *(b++) = INT32_TO(s); } - #else -{ - static const double add = 0, factor = 0x7FFFFFFF; - oil_scaleconv_s32_f32(b, a, (int) n, &add, &factor); -} + for (; n > 0; n--) { + float v = *(a++); + + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.0f); + *(b++) = (int32_t) lrint((double) v * (double) 0x7FFFFFFF); + } #endif } diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index d89f4283..937bf5d1 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -27,9 +27,6 @@ #include #include -#include -#include - #include #include @@ -41,32 +38,31 @@ /* u8 */ static void u8_to_float32ne(unsigned n, const uint8_t *a, float *b) { - static const double add = -1, factor = 1.0/128.0; - pa_assert(a); pa_assert(b); - oil_scaleconv_f32_u8(b, a, (int) n, &add, &factor); + for (; n > 0; n--, a++, b++) + *b = (*a * 1.0/128.0) - 1.0; } static void u8_from_float32ne(unsigned n, const float *a, uint8_t *b) { - static const double add = 128, factor = 127.0; - pa_assert(a); pa_assert(b); - oil_scaleconv_u8_f32(b, a, (int) n, &add, &factor); + for (; n > 0; n--, a++, b++) { + float v; + v = (*a * 127.0) + 128.0; + v = PA_CLAMP_UNLIKELY (v, 0.0, 255.0); + *b = rint (v); + } } static void u8_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) { - static const int16_t add = -0x80, factor = 0x100; - pa_assert(a); pa_assert(b); - oil_conv_s16_u8(b, 2, a, 1, (int) n); - oil_scalaradd_s16(b, 2, b, 2, &add, (int) n); - oil_scalarmult_s16(b, 2, b, 2, &factor, (int) n); + for (; n > 0; n--, a++, b++) + *b = (((int16_t)*a) - 128) << 8; } static void u8_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) { @@ -84,7 +80,7 @@ static void float32ne_to_float32ne(unsigned n, const float *a, float *b) { pa_assert(a); pa_assert(b); - oil_memcpy(b, a, (int) (sizeof(float) * n)); + memcpy(b, a, (int) (sizeof(float) * n)); } static void float32re_to_float32ne(unsigned n, const float *a, float *b) { @@ -101,7 +97,7 @@ static void s16ne_to_s16ne(unsigned n, const int16_t *a, int16_t *b) { pa_assert(a); pa_assert(b); - oil_memcpy(b, a, (int) (sizeof(int16_t) * n)); + memcpy(b, a, (int) (sizeof(int16_t) * n)); } static void s16re_to_s16ne(unsigned n, const int16_t *a, int16_t *b) { diff --git a/src/tests/envelope-test.c b/src/tests/envelope-test.c index 3af3044e..9382040b 100644 --- a/src/tests/envelope-test.c +++ b/src/tests/envelope-test.c @@ -34,8 +34,6 @@ #include #include -#include - const pa_envelope_def ramp_down = { .n_points = 2, .points_x = { 100*PA_USEC_PER_MSEC, 300*PA_USEC_PER_MSEC }, @@ -202,7 +200,6 @@ int main(int argc, char *argv[]) { .values = { PA_VOLUME_NORM, PA_VOLUME_NORM/2 } }; - oil_init(); pa_log_set_level(PA_LOG_DEBUG); pa_assert_se(pool = pa_mempool_new(FALSE, 0)); diff --git a/src/tests/mix-test.c b/src/tests/mix-test.c index f9f76da3..457c4acd 100644 --- a/src/tests/mix-test.c +++ b/src/tests/mix-test.c @@ -32,8 +32,6 @@ #include #include -#include - static float swap_float(float a) { uint32_t *b = (uint32_t*) &a; *b = PA_UINT32_SWAP(*b); @@ -211,7 +209,6 @@ int main(int argc, char *argv[]) { pa_sample_spec a; pa_cvolume v; - oil_init(); pa_log_set_level(PA_LOG_DEBUG); pa_assert_se(pool = pa_mempool_new(FALSE, 0)); diff --git a/src/tests/remix-test.c b/src/tests/remix-test.c index 9d110d6b..4990bf93 100644 --- a/src/tests/remix-test.c +++ b/src/tests/remix-test.c @@ -32,8 +32,6 @@ #include #include -#include - int main(int argc, char *argv[]) { static const pa_channel_map maps[] = { @@ -55,7 +53,6 @@ int main(int argc, char *argv[]) { unsigned i, j; pa_mempool *pool; - oil_init(); pa_log_set_level(PA_LOG_DEBUG); pa_assert_se(pool = pa_mempool_new(FALSE, 0)); diff --git a/src/tests/resampler-test.c b/src/tests/resampler-test.c index 7236265a..82198b5e 100644 --- a/src/tests/resampler-test.c +++ b/src/tests/resampler-test.c @@ -32,8 +32,6 @@ #include #include -#include - static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) { void *d; unsigned i; @@ -248,7 +246,6 @@ int main(int argc, char *argv[]) { pa_sample_spec a, b; pa_cvolume v; - oil_init(); pa_log_set_level(PA_LOG_DEBUG); pa_assert_se(pool = pa_mempool_new(FALSE, 0)); -- cgit From 601e5f1867065912e1740e2408a948ca818f6c59 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 17 Aug 2009 11:35:47 +0200 Subject: resampler: cache integer channel_map Calculate and cache an integer version of the channel map so that we don't have to regenerate it when dealing with s16 samples. --- src/pulsecore/resampler.c | 66 +++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index a3c17f8c..e3473ac5 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -61,7 +61,8 @@ struct pa_resampler { pa_convert_func_t to_work_format_func; pa_convert_func_t from_work_format_func; - float map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + float map_table_f[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + int32_t map_table_i[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; pa_bool_t map_required; void (*impl_free)(pa_resampler *r); @@ -587,7 +588,8 @@ static void calc_map_table(pa_resampler *r) { if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || (!(r->flags & PA_RESAMPLER_NO_REMAP) && !pa_channel_map_equal(&r->i_cm, &r->o_cm))))) return; - memset(r->map_table, 0, sizeof(r->map_table)); + memset(r->map_table_f, 0, sizeof(r->map_table_f)); + memset(r->map_table_i, 0, sizeof(r->map_table_i)); memset(ic_connected, 0, sizeof(ic_connected)); remix = (r->flags & (PA_RESAMPLER_NO_REMAP|PA_RESAMPLER_NO_REMIX)) == 0; @@ -602,7 +604,7 @@ static void calc_map_table(pa_resampler *r) { /* We shall not do any remapping. Hence, just check by index */ if (ic == oc) - r->map_table[oc][ic] = 1.0; + r->map_table_f[oc][ic] = 1.0; continue; } @@ -611,7 +613,7 @@ static void calc_map_table(pa_resampler *r) { /* We shall not do any remixing. Hence, just check by name */ if (a == b) - r->map_table[oc][ic] = 1.0; + r->map_table_f[oc][ic] = 1.0; continue; } @@ -686,7 +688,7 @@ static void calc_map_table(pa_resampler *r) { */ if (a == b || a == PA_CHANNEL_POSITION_MONO || b == PA_CHANNEL_POSITION_MONO) { - r->map_table[oc][ic] = 1.0; + r->map_table_f[oc][ic] = 1.0; oc_connected = TRUE; ic_connected[ic] = TRUE; @@ -711,7 +713,7 @@ static void calc_map_table(pa_resampler *r) { if (n > 0) for (ic = 0; ic < r->i_ss.channels; ic++) if (on_left(r->i_cm.map[ic])) { - r->map_table[oc][ic] = 1.0f / (float) n; + r->map_table_f[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } @@ -732,7 +734,7 @@ static void calc_map_table(pa_resampler *r) { if (n > 0) for (ic = 0; ic < r->i_ss.channels; ic++) if (on_right(r->i_cm.map[ic])) { - r->map_table[oc][ic] = 1.0f / (float) n; + r->map_table_f[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } @@ -753,7 +755,7 @@ static void calc_map_table(pa_resampler *r) { if (n > 0) { for (ic = 0; ic < r->i_ss.channels; ic++) if (on_center(r->i_cm.map[ic])) { - r->map_table[oc][ic] = 1.0f / (float) n; + r->map_table_f[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } } else { @@ -770,7 +772,7 @@ static void calc_map_table(pa_resampler *r) { if (n > 0) for (ic = 0; ic < r->i_ss.channels; ic++) if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) { - r->map_table[oc][ic] = 1.0f / (float) n; + r->map_table_f[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } @@ -787,9 +789,9 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { if (!(r->flags & PA_RESAMPLER_NO_LFE)) - r->map_table[oc][ic] = 1.0f / (float) r->i_ss.channels; + r->map_table_f[oc][ic] = 1.0f / (float) r->i_ss.channels; else - r->map_table[oc][ic] = 0; + r->map_table_f[oc][ic] = 0; /* Please note that a channel connected to LFE * doesn't really count as connected. */ @@ -836,12 +838,12 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { if (ic_connected[ic]) { - r->map_table[oc][ic] *= .9f; + r->map_table_f[oc][ic] *= .9f; continue; } if (on_left(r->i_cm.map[ic])) - r->map_table[oc][ic] = .1f / (float) ic_unconnected_left; + r->map_table_f[oc][ic] = .1f / (float) ic_unconnected_left; } } } @@ -861,12 +863,12 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { if (ic_connected[ic]) { - r->map_table[oc][ic] *= .9f; + r->map_table_f[oc][ic] *= .9f; continue; } if (on_right(r->i_cm.map[ic])) - r->map_table[oc][ic] = .1f / (float) ic_unconnected_right; + r->map_table_f[oc][ic] = .1f / (float) ic_unconnected_right; } } } @@ -887,12 +889,12 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { if (ic_connected[ic]) { - r->map_table[oc][ic] *= .9f; + r->map_table_f[oc][ic] *= .9f; continue; } if (on_center(r->i_cm.map[ic])) { - r->map_table[oc][ic] = .1f / (float) ic_unconnected_center; + r->map_table_f[oc][ic] = .1f / (float) ic_unconnected_center; mixed_in = TRUE; } } @@ -950,7 +952,7 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { if (ic_connected[ic]) { - r->map_table[oc][ic] *= .75f; + r->map_table_f[oc][ic] *= .75f; continue; } @@ -958,7 +960,7 @@ static void calc_map_table(pa_resampler *r) { continue; if (!found_frs[ic] || front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc])) - r->map_table[oc][ic] = .375f / (float) ncenter[oc]; + r->map_table_f[oc][ic] = .375f / (float) ncenter[oc]; } } } @@ -975,11 +977,14 @@ static void calc_map_table(pa_resampler *r) { continue; for (oc = 0; oc < r->o_ss.channels; oc++) - r->map_table[oc][ic] = 0.375f / (float) ic_unconnected_lfe; + r->map_table_f[oc][ic] = 0.375f / (float) ic_unconnected_lfe; } } } - + /* make an 16:16 int version of the matrix */ + for (oc = 0; oc < r->o_ss.channels; oc++) + for (ic = 0; ic < r->i_ss.channels; ic++) + r->map_table_i[oc][ic] = (int32_t) (r->map_table_f[oc][ic] * 0x10000); s = pa_strbuf_new(); @@ -996,7 +1001,7 @@ static void calc_map_table(pa_resampler *r) { pa_strbuf_printf(s, "O%02u |", oc); for (ic = 0; ic < r->i_ss.channels; ic++) - pa_strbuf_printf(s, " %1.3f", r->map_table[oc][ic]); + pa_strbuf_printf(s, " %1.3f", r->map_table_f[oc][ic]); pa_strbuf_puts(s, "\n"); } @@ -1071,11 +1076,7 @@ static void vectoradd_s16( static void vectoradd_s16_with_fraction( int16_t *d, int dstr, const int16_t *s, int sstr, - int n, float s4) { - - int32_t i4; - - i4 = (int32_t) (s4 * 0x10000); + int n, int32_t i4) { for (; n > 0; n--) { *d = (int16_t) (*d + (((int32_t)*s * i4) >> 16)); @@ -1128,18 +1129,17 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { for (oc = 0; oc < r->o_ss.channels; oc++) { unsigned ic; - static const float one = 1.0; for (ic = 0; ic < r->i_ss.channels; ic++) { - if (r->map_table[oc][ic] <= 0.0) + if (r->map_table_f[oc][ic] <= 0.0) continue; vectoradd_f32( (float*) dst + oc, o_skip, (float*) src + ic, i_skip, (int) n_frames, - r->map_table[oc][ic]); + r->map_table_f[oc][ic]); } } @@ -1152,10 +1152,10 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { for (ic = 0; ic < r->i_ss.channels; ic++) { - if (r->map_table[oc][ic] <= 0.0) + if (r->map_table_f[oc][ic] <= 0.0) continue; - if (r->map_table[oc][ic] >= 1.0) { + if (r->map_table_f[oc][ic] >= 1.0) { vectoradd_s16( (int16_t*) dst + oc, o_skip, @@ -1168,7 +1168,7 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { (int16_t*) dst + oc, o_skip, (int16_t*) src + ic, i_skip, (int) n_frames, - r->map_table[oc][ic]); + r->map_table_i[oc][ic]); } } -- cgit From a98fa950d2f04e2ba4d4a470296a081e1050f76d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 15:56:44 +0200 Subject: svolume: remove unneeded compare We don't need the compare because the sub operation already set the right flags for us. --- src/pulsecore/svolume_mmx.c | 1 - src/pulsecore/svolume_sse.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index ad539278..5243b447 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -72,7 +72,6 @@ " add "#a", %3 \n\t" \ " mov %3, %4 \n\t" \ " sub "#b", %4 \n\t" \ - " cmp "#b", %3 \n\t" \ " cmovae %4, %3 \n\t" /* swap 16 bits */ diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index b0a6e0dd..98f828c0 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -52,8 +52,7 @@ " add "#a", %3 \n\t" /* channel += inc */ \ " mov %3, %4 \n\t" \ " sub "#b", %4 \n\t" /* tmp = channel - channels */ \ - " cmp "#b", %3 \n\t" /* if (channel >= channels) */ \ - " cmovae %4, %3 \n\t" /* channel = tmp */ + " cmovae %4, %3 \n\t" /* if (tmp >= 0) channel = tmp */ /* swap 16 bits */ #define SWAP_16(s) \ -- cgit From 951bf1b28d25a93b99cbe074a46b8313a9e5f9f0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 16:09:14 +0200 Subject: svolume: add ARM optimized volume scaling --- src/Makefile.am | 4 +- src/daemon/main.c | 2 + src/pulsecore/cpu-arm.c | 43 ++++++++++ src/pulsecore/cpu-arm.h | 39 +++++++++ src/pulsecore/svolume_arm.c | 195 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 281 insertions(+), 2 deletions(-) create mode 100644 src/pulsecore/cpu-arm.c create mode 100644 src/pulsecore/cpu-arm.h create mode 100644 src/pulsecore/svolume_arm.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 4e90d793..eca68b16 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -825,8 +825,8 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/resampler.c pulsecore/resampler.h \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ pulsecore/sample-util.c pulsecore/sample-util.h \ - pulsecore/cpu-x86.c \ - pulsecore/svolume_c.c \ + pulsecore/cpu-arm.c pulsecore/cpu-x86.c \ + pulsecore/svolume_c.c pulsecore/svolume_arm.c\ pulsecore/svolume_mmx.c pulsecore/svolume_sse.c \ pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \ pulsecore/sconv-s16le.c pulsecore/sconv-s16le.h \ diff --git a/src/daemon/main.c b/src/daemon/main.c index 31e434d9..ec8ff400 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -93,6 +93,7 @@ #ifdef HAVE_DBUS #include #endif +#include #include #include "cmdline.h" @@ -821,6 +822,7 @@ int main(int argc, char *argv[]) { pa_memtrap_install(); pa_cpu_init_x86(); + pa_cpu_init_arm(); pa_assert_se(mainloop = pa_mainloop_new()); diff --git a/src/pulsecore/cpu-arm.c b/src/pulsecore/cpu-arm.c new file mode 100644 index 00000000..75646fe4 --- /dev/null +++ b/src/pulsecore/cpu-arm.c @@ -0,0 +1,43 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include "cpu-arm.h" + +static pa_cpu_arm_flag_t pa_cpu_arm_flags; + +void pa_cpu_init_arm (void) { +#if defined (__arm__) + pa_cpu_arm_flags = 0; + + pa_log ("ARM init\n"); + + pa_volume_func_init_arm (pa_cpu_arm_flags); +#endif /* defined (__arm__) */ +} diff --git a/src/pulsecore/cpu-arm.h b/src/pulsecore/cpu-arm.h new file mode 100644 index 00000000..1a0ac273 --- /dev/null +++ b/src/pulsecore/cpu-arm.h @@ -0,0 +1,39 @@ +#ifndef foocpuarmhfoo +#define foocpuarmhfoo + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef enum pa_cpu_arm_flag { + PA_CPU_ARM_V6 = (1 << 0), + PA_CPU_ARM_NEON = (1 << 1), + PA_CPU_ARM_VFP = (1 << 2) +} pa_cpu_arm_flag_t; + +void pa_cpu_init_arm (void); + +/* some optimized functions */ +void pa_volume_func_init_arm(pa_cpu_arm_flag_t flags); + +#endif /* foocpuarmhfoo */ diff --git a/src/pulsecore/svolume_arm.c b/src/pulsecore/svolume_arm.c new file mode 100644 index 00000000..7e25a13c --- /dev/null +++ b/src/pulsecore/svolume_arm.c @@ -0,0 +1,195 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "cpu-arm.h" + +#include "sample-util.h" +#include "endianmacros.h" + +#if defined (__arm__) + +#define MOD_INC() \ + " subs r0, r6, %2 \n\t" \ + " addcs r0, %1 \n\t" \ + " movcs r6, r0 \n\t" + +static void +pa_volume_s16ne_arm (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +{ + int32_t *ve; + + channels = MAX (4, channels); + ve = volumes + channels; + + __asm__ __volatile__ ( + " mov r6, %1 \n\t" + " mov %3, %3, LSR #1 \n\t" /* length /= sizeof (int16_t) */ + " tst %3, #1 \n\t" /* check for odd samples */ + " beq 2f \n\t" + + "1: \n\t" + " ldr r0, [r6], #4 \n\t" /* odd samples volumes */ + " ldrh r2, [%0] \n\t" + + " smulwb r0, r0, r2 \n\t" + " ssat r0, #16, r0 \n\t" + + " strh r0, [%0], #2 \n\t" + + MOD_INC() + + "2: \n\t" + " mov %3, %3, LSR #1 \n\t" + " tst %3, #1 \n\t" /* check for odd samples */ + " beq 4f \n\t" + + "3: \n\t" + " ldrd r2, [r6], #8 \n\t" /* 2 samples at a time */ + " ldr r0, [%0] \n\t" + + " smulwt r2, r2, r0 \n\t" + " smulwb r3, r3, r0 \n\t" + + " ssat r2, #16, r2 \n\t" + " ssat r3, #16, r3 \n\t" + + " pkhbt r0, r3, r2, LSL #16 \n\t" + " str r0, [%0], #4 \n\t" + + MOD_INC() + + "4: \n\t" + " movs %3, %3, LSR #1 \n\t" + " beq 6f \n\t" + + "5: \n\t" + " ldrd r2, [r6], #8 \n\t" /* 4 samples at a time */ + " ldrd r4, [r6], #8 \n\t" + " ldrd r0, [%0] \n\t" + + " smulwt r2, r2, r0 \n\t" + " smulwb r3, r3, r0 \n\t" + " smulwt r4, r4, r1 \n\t" + " smulwb r5, r5, r1 \n\t" + + " ssat r2, #16, r2 \n\t" + " ssat r3, #16, r3 \n\t" + " ssat r4, #16, r4 \n\t" + " ssat r5, #16, r5 \n\t" + + " pkhbt r0, r3, r2, LSL #16 \n\t" + " pkhbt r1, r5, r4, LSL #16 \n\t" + " strd r0, [%0], #8 \n\t" + + MOD_INC() + + " subs %3, %3, #1 \n\t" + " bne 5b \n\t" + "6: \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (ve), "+r" (length) + : + : "r6", "r5", "r4", "r3", "r2", "r1", "r0", "cc" + ); +} + +#undef RUN_TEST + +#ifdef RUN_TEST +#define CHANNELS 2 +#define SAMPLES 1023 +#define TIMES 1000 +#define PADDING 16 + +static void run_test (void) { + int16_t samples[SAMPLES]; + int16_t samples_ref[SAMPLES]; + int16_t samples_orig[SAMPLES]; + int32_t volumes[CHANNELS + PADDING]; + int i, j, padding; + pa_do_volume_func_t func; + struct timeval start, stop; + + func = pa_get_volume_func (PA_SAMPLE_S16NE); + + printf ("checking ARM %zd\n", sizeof (samples)); + + pa_random (samples, sizeof (samples)); + memcpy (samples_ref, samples, sizeof (samples)); + memcpy (samples_orig, samples, sizeof (samples)); + + for (i = 0; i < CHANNELS; i++) + volumes[i] = rand() >> 1; + for (padding = 0; padding < PADDING; padding++, i++) + volumes[i] = volumes[padding]; + + func (samples_ref, volumes, CHANNELS, sizeof (samples)); + pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples)); + for (i = 0; i < SAMPLES; i++) { + if (samples[i] != samples_ref[i]) { + printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); + } + } + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples, samples_orig, sizeof (samples)); + pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("ARM: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples_ref, samples_orig, sizeof (samples)); + func (samples_ref, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); +} +#endif + +#endif /* defined (__arm__) */ + + +void pa_volume_func_init_arm (pa_cpu_arm_flag_t flags) { +#if defined (__arm__) + pa_log_info("Initialising ARM optimized functions."); + +#ifdef RUN_TEST + run_test (); +#endif + + pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_arm); +#endif /* defined (__arm__) */ +} -- cgit From bd49d43bd387758f151c56b7ed1643ecb72c0258 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 16:09:48 +0200 Subject: svolume: add CPU guards around code Mark code that should only be compiled on x86 CPUs with proper defines. --- src/pulsecore/svolume_mmx.c | 6 ++++++ src/pulsecore/svolume_sse.c | 5 +++++ 2 files changed, 11 insertions(+) (limited to 'src') diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index 5243b447..fb4c82c6 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -35,6 +35,7 @@ #include "sample-util.h" #include "endianmacros.h" +#if defined (__i386__) || defined (__amd64__) /* in s: 2 int16_t samples * in v: 2 int32_t volumes, fixed point 16:16 * out s: contains scaled and clamped int16_t samples. @@ -295,7 +296,11 @@ static void run_test (void) { } #endif +#endif /* defined (__i386__) || defined (__amd64__) */ + + void pa_volume_func_init_mmx (pa_cpu_x86_flag_t flags) { +#if defined (__i386__) || defined (__amd64__) pa_log_info("Initialising MMX optimized functions."); #ifdef RUN_TEST @@ -304,4 +309,5 @@ void pa_volume_func_init_mmx (pa_cpu_x86_flag_t flags) { pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx); pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx); +#endif /* defined (__i386__) || defined (__amd64__) */ } diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index 98f828c0..141c466e 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -35,6 +35,8 @@ #include "sample-util.h" #include "endianmacros.h" +#if defined (__i386__) || defined (__amd64__) + #define VOLUME_32x16(s,v) /* .. | vh | vl | */ \ " pxor %%xmm4, %%xmm4 \n\t" /* .. | 0 | 0 | */ \ " punpcklwd %%xmm4, "#s" \n\t" /* .. | 0 | p0 | */ \ @@ -293,8 +295,10 @@ static void run_test (void) { pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); } #endif +#endif /* defined (__i386__) || defined (__amd64__) */ void pa_volume_func_init_sse (pa_cpu_x86_flag_t flags) { +#if defined (__i386__) || defined (__amd64__) pa_log_info("Initialising SSE optimized functions."); #ifdef RUN_TEST @@ -303,4 +307,5 @@ void pa_volume_func_init_sse (pa_cpu_x86_flag_t flags) { pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse); pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse); +#endif /* defined (__i386__) || defined (__amd64__) */ } -- cgit From b4e9942c2f3929b4baf4b53b0561102af7845269 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 16:15:18 +0200 Subject: resample: refactor the channel remapping a little Factor out the channel remap matrix code into a separate function. Keep a pointer to the channel remapping function so we can install custom functions. Catch the common mono->stereo remapping case and install a custom, more optimized function. --- src/pulsecore/resampler.c | 197 +++++++++++++++++++++++++--------------------- 1 file changed, 109 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index e3473ac5..4fb03ce7 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -44,6 +44,11 @@ /* Number of samples of extra space we allow the resamplers to return */ #define EXTRA_FRAMES 128 +typedef void (*pa_do_remap_func_t) (pa_resampler *r, void *d, const void *s, unsigned n); + +static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, unsigned n); +static void remap_mono_to_stereo(pa_resampler *r, void *dst, const void *src, unsigned n); + struct pa_resampler { pa_resample_method_t method; pa_resample_flags_t flags; @@ -64,6 +69,7 @@ struct pa_resampler { float map_table_f[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; int32_t map_table_i[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; pa_bool_t map_required; + pa_do_remap_func_t do_remap; void (*impl_free)(pa_resampler *r); void (*impl_update_rates)(pa_resampler *r); @@ -1008,6 +1014,17 @@ static void calc_map_table(pa_resampler *r) { pa_log_debug("Channel matrix:\n%s", t = pa_strbuf_tostring_free(s)); pa_xfree(t); + + /* find some common channel remappings, fall back to full matrix operation. */ + if (r->i_ss.channels == 1 && r->o_ss.channels == 2 && + r->map_table_i[0][0] == 1.0 && r->map_table_i[1][0] == 1.0) { + r->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo;; + pa_log_debug("Using mono to stereo remapping"); + } else { + r->do_remap = (pa_do_remap_func_t) remap_channels_matrix; + pa_log_debug("Using generic matrix remapping"); + } + } static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) { @@ -1047,49 +1064,111 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) return &r->buf1; } -static void vectoradd_f32( - float *d, int dstr, - const float *s, int sstr, - int n, float s4) { +static void remap_mono_to_stereo(pa_resampler *r, void *dst, const void *src, unsigned n) { + + switch (r->work_format) { + case PA_SAMPLE_FLOAT32NE: + { + float *d, *s; + + d = (float *) dst; + s = (float *) src; + + for (; n > 0; n--) { + *d++ = *s; + *d++ = *s++; + } + break; + } + case PA_SAMPLE_S16NE: + { + int16_t *d, *s; - for (; n > 0; n--) { - *d = (float) (*d + (s4 * *s)); + d = (int16_t *) dst; + s = (int16_t *) src; - s = (const float*) ((const uint8_t*) s + sstr); - d = (float*) ((uint8_t*) d + dstr); + for (; n > 0; n--) { + *d++ = *s; + *d++ = *s++; + } + break; + } + default: + pa_assert_not_reached(); } } -static void vectoradd_s16( - int16_t *d, int dstr, - const int16_t *s, int sstr, - int n) { +static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, unsigned n) { + unsigned oc; + unsigned n_ic, n_oc; - for (; n > 0; n--) { - *d = (int16_t) (*d + *s); + n_ic = r->i_ss.channels; + n_oc = r->o_ss.channels; - s = (const int16_t*) ((const uint8_t*) s + sstr); - d = (int16_t*) ((uint8_t*) d + dstr); - } -} + memset(dst, 0, r->buf2.length); -static void vectoradd_s16_with_fraction( - int16_t *d, int dstr, - const int16_t *s, int sstr, - int n, int32_t i4) { + switch (r->work_format) { + case PA_SAMPLE_FLOAT32NE: + { + float *d, *s; - for (; n > 0; n--) { - *d = (int16_t) (*d + (((int32_t)*s * i4) >> 16)); + for (oc = 0; oc < n_oc; oc++) { + unsigned ic; - s = (const int16_t*) ((const uint8_t*) s + sstr); - d = (int16_t*) ((uint8_t*) d + dstr); + for (ic = 0; ic < n_ic; ic++) { + float vol; + + vol = r->map_table_f[oc][ic]; + + if (vol <= 0.0) + continue; + + d = (float *)dst + oc; + s = (float *)src + ic; + + for (; n > 0; n--, s += n_ic, d += n_oc) + *d += *s * vol; + } + } + + break; + } + case PA_SAMPLE_S16NE: + { + int16_t *d, *s; + + for (oc = 0; oc < n_oc; oc++) { + unsigned ic; + + for (ic = 0; ic < n_ic; ic++) { + int32_t vol; + + vol = r->map_table_i[oc][ic]; + + if (vol <= 0) + continue; + + d = (int16_t *)dst + oc; + s = (int16_t *)src + ic; + + if (vol >= 0x10000) { + for (; n > 0; n--, s += n_ic, d += n_oc) + *d += *s; + } else { + for (; n > 0; n--, s += n_ic, d += n_oc) + *d = (int16_t) (*d + (((int32_t)*s * vol) >> 16)); + } + } + } + break; + } + default: + pa_assert_not_reached(); } } static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { unsigned in_n_samples, out_n_samples, n_frames; - int i_skip, o_skip; - unsigned oc; void *src, *dst; pa_assert(r); @@ -1119,70 +1198,12 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { src = ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); dst = pa_memblock_acquire(r->buf2.memblock); - memset(dst, 0, r->buf2.length); - - o_skip = (int) (r->w_sz * r->o_ss.channels); - i_skip = (int) (r->w_sz * r->i_ss.channels); - - switch (r->work_format) { - case PA_SAMPLE_FLOAT32NE: - - for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned ic; - - for (ic = 0; ic < r->i_ss.channels; ic++) { - - if (r->map_table_f[oc][ic] <= 0.0) - continue; - - vectoradd_f32( - (float*) dst + oc, o_skip, - (float*) src + ic, i_skip, - (int) n_frames, - r->map_table_f[oc][ic]); - } - } - - break; - - case PA_SAMPLE_S16NE: - - for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned ic; - - for (ic = 0; ic < r->i_ss.channels; ic++) { - - if (r->map_table_f[oc][ic] <= 0.0) - continue; - - if (r->map_table_f[oc][ic] >= 1.0) { - - vectoradd_s16( - (int16_t*) dst + oc, o_skip, - (int16_t*) src + ic, i_skip, - (int) n_frames); - - } else - - vectoradd_s16_with_fraction( - (int16_t*) dst + oc, o_skip, - (int16_t*) src + ic, i_skip, - (int) n_frames, - r->map_table_i[oc][ic]); - } - } - - break; - - default: - pa_assert_not_reached(); - } + pa_assert (r->do_remap); + r->do_remap (r, dst, src, n_frames); pa_memblock_release(input->memblock); pa_memblock_release(r->buf2.memblock); - r->buf2.length = out_n_samples * r->w_sz; - return &r->buf2; } -- cgit From d04a6e935f8352a4ffd93cb1aeddac8f605a099a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 16:23:55 +0200 Subject: resample: fix counters --- src/pulsecore/resampler.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 4fb03ce7..cc57b54e 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -1099,7 +1099,7 @@ static void remap_mono_to_stereo(pa_resampler *r, void *dst, const void *src, un } static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, unsigned n) { - unsigned oc; + unsigned oc, i; unsigned n_ic, n_oc; n_ic = r->i_ss.channels; @@ -1126,7 +1126,7 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, d = (float *)dst + oc; s = (float *)src + ic; - for (; n > 0; n--, s += n_ic, d += n_oc) + for (i = n; i > 0; i--, s += n_ic, d += n_oc) *d += *s * vol; } } @@ -1152,10 +1152,10 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, s = (int16_t *)src + ic; if (vol >= 0x10000) { - for (; n > 0; n--, s += n_ic, d += n_oc) + for (i = n; i > 0; i--, s += n_ic, d += n_oc) *d += *s; } else { - for (; n > 0; n--, s += n_ic, d += n_oc) + for (i = n; i > 0; i--, s += n_ic, d += n_oc) *d = (int16_t) (*d + (((int32_t)*s * vol) >> 16)); } } -- cgit From 548b735ccf8474ebe60137375cdda4e58582efc3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 17:24:23 +0200 Subject: resampler: fix identity check Fix the identity matrix check for mono to stereo. Help the compiler generate better code for the C implementation of the channel remapping code. --- src/pulsecore/resampler.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index cc57b54e..2256516e 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -1017,7 +1017,7 @@ static void calc_map_table(pa_resampler *r) { /* find some common channel remappings, fall back to full matrix operation. */ if (r->i_ss.channels == 1 && r->o_ss.channels == 2 && - r->map_table_i[0][0] == 1.0 && r->map_table_i[1][0] == 1.0) { + r->map_table_f[0][0] >= 1.0 && r->map_table_f[1][0] >= 1.0) { r->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo;; pa_log_debug("Using mono to stereo remapping"); } else { @@ -1074,10 +1074,8 @@ static void remap_mono_to_stereo(pa_resampler *r, void *dst, const void *src, un d = (float *) dst; s = (float *) src; - for (; n > 0; n--) { - *d++ = *s; - *d++ = *s++; - } + for (; n > 0; n--, s++, d += 2) + d[0] = d[1] = *s; break; } case PA_SAMPLE_S16NE: @@ -1087,10 +1085,8 @@ static void remap_mono_to_stereo(pa_resampler *r, void *dst, const void *src, un d = (int16_t *) dst; s = (int16_t *) src; - for (; n > 0; n--) { - *d++ = *s; - *d++ = *s++; - } + for (; n > 0; n--, s++, d += 2) + d[0] = d[1] = *s; break; } default: @@ -1156,7 +1152,7 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, *d += *s; } else { for (i = n; i > 0; i--, s += n_ic, d += n_oc) - *d = (int16_t) (*d + (((int32_t)*s * vol) >> 16)); + *d += (int16_t) (((int32_t)*s * vol) >> 16); } } } -- 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') 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 370016c0e73236830513a9ea9c16366c15bd30a2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 18:52:28 +0200 Subject: svolume: fix compilation in 32bits --- src/pulsecore/svolume_mmx.c | 12 ++++++------ src/pulsecore/svolume_sse.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index fb4c82c6..86af76d3 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -114,11 +114,11 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi " je 2f \n\t" " movd (%1, %3, 4), %%mm0 \n\t" /* | v0h | v0l | */ - " movw (%0), %4 \n\t" /* .. | p0 | */ + " movw (%0), %w4 \n\t" /* .. | p0 | */ " movd %4, %%mm1 \n\t" VOLUME_32x16 (%%mm1, %%mm0) " movd %%mm0, %4 \n\t" /* .. | p0*v0 | */ - " movw %4, (%0) \n\t" + " movw %w4, (%0) \n\t" " add $2, %0 \n\t" MOD_ADD ($1, %5) @@ -184,13 +184,13 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi " je 2f \n\t" " movd (%1, %3, 4), %%mm0 \n\t" /* | v0h | v0l | */ - " movw (%0), %4 \n\t" /* .. | p0 | */ - " rorw $8, %4 \n\t" + " movw (%0), %w4 \n\t" /* .. | p0 | */ + " rorw $8, %w4 \n\t" " movd %4, %%mm1 \n\t" VOLUME_32x16 (%%mm1, %%mm0) " movd %%mm0, %4 \n\t" /* .. | p0*v0 | */ - " rorw $8, %4 \n\t" - " movw %4, (%0) \n\t" + " rorw $8, %w4 \n\t" + " movw %w4, (%0) \n\t" " add $2, %0 \n\t" MOD_ADD ($1, %5) diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index 141c466e..0054d301 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -91,11 +91,11 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi " je 2f \n\t" " movd (%1, %3, 4), %%xmm0 \n\t" /* | v0h | v0l | */ - " movw (%0), %4 \n\t" /* .. | p0 | */ + " movw (%0), %w4 \n\t" /* .. | p0 | */ " movd %4, %%xmm1 \n\t" VOLUME_32x16 (%%xmm1, %%xmm0) " movd %%xmm0, %4 \n\t" /* .. | p0*v0 | */ - " movw %4, (%0) \n\t" + " movw %w4, (%0) \n\t" " add $2, %0 \n\t" MOD_ADD ($1, %5) @@ -168,13 +168,13 @@ pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi " je 2f \n\t" " movd (%1, %3, 4), %%xmm0 \n\t" /* | v0h | v0l | */ - " movw (%0), %4 \n\t" /* .. | p0 | */ - " rorw $8, %4 \n\t" + " movw (%0), %w4 \n\t" /* .. | p0 | */ + " rorw $8, %w4 \n\t" " movd %4, %%xmm1 \n\t" VOLUME_32x16 (%%xmm1, %%xmm0) " movd %%xmm0, %4 \n\t" /* .. | p0*v0 | */ - " rorw $8, %4 \n\t" - " movw %4, (%0) \n\t" + " rorw $8, %w4 \n\t" + " movw %w4, (%0) \n\t" " add $2, %0 \n\t" MOD_ADD ($1, %5) -- cgit From 078bde1b49a11f6c76e47fea19f9d920a45ce3f1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 19:50:42 +0200 Subject: x86: keep the cpu flags local --- src/pulsecore/cpu-x86.c | 57 +++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/pulsecore/cpu-x86.c b/src/pulsecore/cpu-x86.c index 2da31c92..453ecf5b 100644 --- a/src/pulsecore/cpu-x86.c +++ b/src/pulsecore/cpu-x86.c @@ -45,12 +45,11 @@ get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) } #endif -static pa_cpu_x86_flag_t pa_cpu_x86_flags; - void pa_cpu_init_x86 (void) { #if defined (__i386__) || defined (__amd64__) uint32_t eax, ebx, ecx, edx; uint32_t level; + pa_cpu_x86_flag_t flags = 0; /* get standard level */ get_cpuid (0x00000000, &level, &ebx, &ecx, &edx); @@ -58,25 +57,25 @@ void pa_cpu_init_x86 (void) { get_cpuid (0x00000001, &eax, &ebx, &ecx, &edx); if (edx & (1<<23)) - pa_cpu_x86_flags |= PA_CPU_X86_MMX; + flags |= PA_CPU_X86_MMX; if (edx & (1<<25)) - pa_cpu_x86_flags |= PA_CPU_X86_SSE; + flags |= PA_CPU_X86_SSE; if (edx & (1<<26)) - pa_cpu_x86_flags |= PA_CPU_X86_SSE2; + flags |= PA_CPU_X86_SSE2; if (ecx & (1<<0)) - pa_cpu_x86_flags |= PA_CPU_X86_SSE3; + flags |= PA_CPU_X86_SSE3; if (ecx & (1<<9)) - pa_cpu_x86_flags |= PA_CPU_X86_SSSE3; + flags |= PA_CPU_X86_SSSE3; if (ecx & (1<<19)) - pa_cpu_x86_flags |= PA_CPU_X86_SSE4_1; + flags |= PA_CPU_X86_SSE4_1; if (ecx & (1<<20)) - pa_cpu_x86_flags |= PA_CPU_X86_SSE4_2; + flags |= PA_CPU_X86_SSE4_2; } /* get extended level */ @@ -85,38 +84,36 @@ void pa_cpu_init_x86 (void) { get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx); if (edx & (1<<22)) - pa_cpu_x86_flags |= PA_CPU_X86_MMXEXT; + flags |= PA_CPU_X86_MMXEXT; if (edx & (1<<23)) - pa_cpu_x86_flags |= PA_CPU_X86_MMX; + flags |= PA_CPU_X86_MMX; if (edx & (1<<30)) - pa_cpu_x86_flags |= PA_CPU_X86_3DNOWEXT; + flags |= PA_CPU_X86_3DNOWEXT; if (edx & (1<<31)) - pa_cpu_x86_flags |= PA_CPU_X86_3DNOW; + flags |= PA_CPU_X86_3DNOW; } pa_log_info ("CPU flags: %s%s%s%s%s%s%s%s%s%s", - (pa_cpu_x86_flags & PA_CPU_X86_MMX) ? "MMX " : "", - (pa_cpu_x86_flags & PA_CPU_X86_SSE) ? "SSE " : "", - (pa_cpu_x86_flags & PA_CPU_X86_SSE2) ? "SSE2 " : "", - (pa_cpu_x86_flags & PA_CPU_X86_SSE3) ? "SSE3 " : "", - (pa_cpu_x86_flags & PA_CPU_X86_SSSE3) ? "SSSE3 " : "", - (pa_cpu_x86_flags & PA_CPU_X86_SSE4_1) ? "SSE4_1 " : "", - (pa_cpu_x86_flags & PA_CPU_X86_SSE4_2) ? "SSE4_2 " : "", - (pa_cpu_x86_flags & PA_CPU_X86_MMXEXT) ? "MMXEXT " : "", - (pa_cpu_x86_flags & PA_CPU_X86_3DNOW) ? "3DNOW " : "", - (pa_cpu_x86_flags & PA_CPU_X86_3DNOWEXT) ? "3DNOWEXT " : ""); + (flags & PA_CPU_X86_MMX) ? "MMX " : "", + (flags & PA_CPU_X86_SSE) ? "SSE " : "", + (flags & PA_CPU_X86_SSE2) ? "SSE2 " : "", + (flags & PA_CPU_X86_SSE3) ? "SSE3 " : "", + (flags & PA_CPU_X86_SSSE3) ? "SSSE3 " : "", + (flags & PA_CPU_X86_SSE4_1) ? "SSE4_1 " : "", + (flags & PA_CPU_X86_SSE4_2) ? "SSE4_2 " : "", + (flags & PA_CPU_X86_MMXEXT) ? "MMXEXT " : "", + (flags & PA_CPU_X86_3DNOW) ? "3DNOW " : "", + (flags & PA_CPU_X86_3DNOWEXT) ? "3DNOWEXT " : ""); /* activate various optimisations */ - if (pa_cpu_x86_flags & PA_CPU_X86_MMX) { - pa_volume_func_init_mmx (pa_cpu_x86_flags); + if (flags & PA_CPU_X86_MMX) { + pa_volume_func_init_mmx (flags); } - if (pa_cpu_x86_flags & PA_CPU_X86_SSE) { - pa_volume_func_init_sse (pa_cpu_x86_flags); + if (flags & PA_CPU_X86_SSE) { + pa_volume_func_init_sse (flags); } -#else - pa_cpu_x86_flags = 0; -#endif +#endif /* defined (__i386__) || defined (__amd64__) */ } -- cgit From 8aa86f5247103432faf660cba33f5ce80fbbc2c7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 19:51:11 +0200 Subject: arm: implement ARM cpu detection --- src/pulsecore/cpu-arm.c | 107 +++++++++++++++++++++++++++++++++++++++++++++--- src/pulsecore/cpu-arm.h | 7 +++- 2 files changed, 107 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/pulsecore/cpu-arm.c b/src/pulsecore/cpu-arm.c index 75646fe4..93ad3891 100644 --- a/src/pulsecore/cpu-arm.c +++ b/src/pulsecore/cpu-arm.c @@ -25,19 +25,116 @@ #endif #include +#include +#include +#include +#include #include #include "cpu-arm.h" -static pa_cpu_arm_flag_t pa_cpu_arm_flags; +#if defined (__arm__) && defined (__linux__) + +#define MAX_BUFFER 4096 +static char * +get_cpuinfo_line (char *cpuinfo, const char *tag) { + char *line, *end, *colon; + + if (!(line = strstr (cpuinfo, tag))) + return NULL; + + if (!(end = strchr (line, '\n'))) + return NULL; + + if (!(colon = strchr (line, ':'))) + return NULL; + + if (++colon >= end) + return NULL; + + return pa_xstrndup (colon, end - colon); +} + +static char *get_cpuinfo(void) { + char *cpuinfo; + int n, fd; + + if (!(cpuinfo = malloc(MAX_BUFFER))) + return NULL; + + if ((fd = open("/proc/cpuinfo", O_RDONLY)) < 0) { + free (cpuinfo); + return NULL; + } + + if ((n = read(fd, cpuinfo, MAX_BUFFER-1)) < 0) { + free (cpuinfo); + close (fd); + return NULL; + } + cpuinfo[n] = 0; + close (fd); + + return cpuinfo; +} +#endif /* defined (__arm__) && defined (__linux__) */ void pa_cpu_init_arm (void) { #if defined (__arm__) - pa_cpu_arm_flags = 0; - - pa_log ("ARM init\n"); +#if defined (__linux__) + char *cpuinfo, *line; + int arch; + pa_cpu_arm_flag_t flags = 0; + + /* We need to read the CPU flags from /proc/cpuinfo because there is no user + * space support to get the CPU features. This only works on linux AFAIK. */ + if (!(cpuinfo = get_cpuinfo ())) { + pa_log ("Can't read cpuinfo"); + return; + } + + /* get the CPU architecture */ + if ((line = get_cpuinfo_line (cpuinfo, "CPU architecture"))) { + arch = strtoul (line, NULL, 0); + if (arch >= 6) + flags |= PA_CPU_ARM_V6; + if (arch >= 7) + flags |= PA_CPU_ARM_V7; + + free (line); + } + /* get the CPU features */ + if ((line = get_cpuinfo_line (cpuinfo, "Features"))) { + char *state = NULL, *current; + + while ((current = pa_split_spaces (line, &state))) { + if (!strcmp (current, "vfp")) + flags |= PA_CPU_ARM_VFP; + else if (!strcmp (current, "edsp")) + flags |= PA_CPU_ARM_EDSP; + else if (!strcmp (current, "neon")) + flags |= PA_CPU_ARM_NEON; + else if (!strcmp (current, "vfpv3")) + flags |= PA_CPU_ARM_VFPV3; + + free (current); + } + } + free (cpuinfo); + + pa_log_info ("CPU flags: %s%s%s%s%s%s", + (flags & PA_CPU_ARM_V6) ? "V6 " : "", + (flags & PA_CPU_ARM_V7) ? "V7 " : "", + (flags & PA_CPU_ARM_VFP) ? "VFP " : "", + (flags & PA_CPU_ARM_EDSP) ? "EDSP " : "", + (flags & PA_CPU_ARM_NEON) ? "NEON " : "", + (flags & PA_CPU_ARM_VFPV3) ? "VFPV3 " : ""); +#else /* defined (__linux__) */ + pa_log ("ARM cpu features not yet supported on this OS"); +#endif /* defined (__linux__) */ - pa_volume_func_init_arm (pa_cpu_arm_flags); + if (flags & PA_CPU_ARM_V6) + pa_volume_func_init_arm (flags); #endif /* defined (__arm__) */ } diff --git a/src/pulsecore/cpu-arm.h b/src/pulsecore/cpu-arm.h index 1a0ac273..3ccd0708 100644 --- a/src/pulsecore/cpu-arm.h +++ b/src/pulsecore/cpu-arm.h @@ -27,8 +27,11 @@ typedef enum pa_cpu_arm_flag { PA_CPU_ARM_V6 = (1 << 0), - PA_CPU_ARM_NEON = (1 << 1), - PA_CPU_ARM_VFP = (1 << 2) + PA_CPU_ARM_V7 = (1 << 1), + PA_CPU_ARM_VFP = (1 << 2), + PA_CPU_ARM_EDSP = (1 << 3), + PA_CPU_ARM_NEON = (1 << 4), + PA_CPU_ARM_VFPV3 = (1 << 5) } pa_cpu_arm_flag_t; void pa_cpu_init_arm (void); -- cgit From aeae567f8861d2f068ebd0f054cd9d0aa6a7fe95 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 20:00:28 +0200 Subject: svolume: add comment --- src/pulsecore/svolume_sse.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index 0054d301..5979f7c2 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -117,6 +117,9 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi " test $1, %2 \n\t" " je 6f \n\t" + /* FIXME, we can do aligned access of the volume values if we can guarantee + * that the array is 16 bytes aligned, we probably have to do the odd values + * after this then. */ "5: \n\t" /* do samples in groups of 4 */ " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ -- cgit From 3cc1278dcf44c9fb93bfd2725a2f75de1958cf23 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Aug 2009 20:47:48 +0200 Subject: resampler: avoid some multiplies when we can --- src/pulsecore/resampler.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 2256516e..43771dc8 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -1122,8 +1122,13 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, d = (float *)dst + oc; s = (float *)src + ic; - for (i = n; i > 0; i--, s += n_ic, d += n_oc) - *d += *s * vol; + if (vol >= 1.0) { + for (i = n; i > 0; i--, s += n_ic, d += n_oc) + *d += *s; + } else { + for (i = n; i > 0; i--, s += n_ic, d += n_oc) + *d += *s * vol; + } } } -- cgit From f09b51198f43d79b22cb92b5223d01a7ab339d9f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 10:56:20 +0200 Subject: whitespace fixes --- src/pulsecore/cpu-arm.c | 32 ++-- src/pulsecore/cpu-x86.c | 49 +++--- src/pulsecore/resampler.c | 65 ++++--- src/pulsecore/sample-util.c | 11 +- src/pulsecore/svolume_arm.c | 242 +++++++++++++------------- src/pulsecore/svolume_c.c | 330 +++++++++++++++++------------------ src/pulsecore/svolume_mmx.c | 366 +++++++++++++++++++-------------------- src/pulsecore/svolume_sse.c | 410 ++++++++++++++++++++++---------------------- 8 files changed, 765 insertions(+), 740 deletions(-) (limited to 'src') diff --git a/src/pulsecore/cpu-arm.c b/src/pulsecore/cpu-arm.c index 93ad3891..5a994b71 100644 --- a/src/pulsecore/cpu-arm.c +++ b/src/pulsecore/cpu-arm.c @@ -36,14 +36,14 @@ #if defined (__arm__) && defined (__linux__) -#define MAX_BUFFER 4096 +#define MAX_BUFFER 4096 static char * get_cpuinfo_line (char *cpuinfo, const char *tag) { char *line, *end, *colon; if (!(line = strstr (cpuinfo, tag))) return NULL; - + if (!(end = strchr (line, '\n'))) return NULL; @@ -106,20 +106,20 @@ void pa_cpu_init_arm (void) { } /* get the CPU features */ if ((line = get_cpuinfo_line (cpuinfo, "Features"))) { - char *state = NULL, *current; - - while ((current = pa_split_spaces (line, &state))) { - if (!strcmp (current, "vfp")) - flags |= PA_CPU_ARM_VFP; - else if (!strcmp (current, "edsp")) - flags |= PA_CPU_ARM_EDSP; - else if (!strcmp (current, "neon")) - flags |= PA_CPU_ARM_NEON; - else if (!strcmp (current, "vfpv3")) - flags |= PA_CPU_ARM_VFPV3; - - free (current); - } + char *state = NULL, *current; + + while ((current = pa_split_spaces (line, &state))) { + if (!strcmp (current, "vfp")) + flags |= PA_CPU_ARM_VFP; + else if (!strcmp (current, "edsp")) + flags |= PA_CPU_ARM_EDSP; + else if (!strcmp (current, "neon")) + flags |= PA_CPU_ARM_NEON; + else if (!strcmp (current, "vfpv3")) + flags |= PA_CPU_ARM_VFPV3; + + free (current); + } } free (cpuinfo); diff --git a/src/pulsecore/cpu-x86.c b/src/pulsecore/cpu-x86.c index 453ecf5b..0457199d 100644 --- a/src/pulsecore/cpu-x86.c +++ b/src/pulsecore/cpu-x86.c @@ -2,7 +2,7 @@ This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering - Copyright 2009 Wim Taymans + Copyright 2009 Wim Taymans PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -34,14 +34,15 @@ static void get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { - __asm__ __volatile__ ( - " push %%"PA_REG_b" \n\t" - " cpuid \n\t" - " mov %%ebx, %%esi \n\t" - " pop %%"PA_REG_b" \n\t" - - : "=a" (*a), "=S" (*b), "=c" (*c), "=d" (*d) - : "0" (op)); + __asm__ __volatile__ ( + " push %%"PA_REG_b" \n\t" + " cpuid \n\t" + " mov %%ebx, %%esi \n\t" + " pop %%"PA_REG_b" \n\t" + + : "=a" (*a), "=S" (*b), "=c" (*c), "=d" (*d) + : "0" (op) + ); } #endif @@ -97,23 +98,23 @@ void pa_cpu_init_x86 (void) { } pa_log_info ("CPU flags: %s%s%s%s%s%s%s%s%s%s", - (flags & PA_CPU_X86_MMX) ? "MMX " : "", - (flags & PA_CPU_X86_SSE) ? "SSE " : "", - (flags & PA_CPU_X86_SSE2) ? "SSE2 " : "", - (flags & PA_CPU_X86_SSE3) ? "SSE3 " : "", - (flags & PA_CPU_X86_SSSE3) ? "SSSE3 " : "", - (flags & PA_CPU_X86_SSE4_1) ? "SSE4_1 " : "", - (flags & PA_CPU_X86_SSE4_2) ? "SSE4_2 " : "", - (flags & PA_CPU_X86_MMXEXT) ? "MMXEXT " : "", - (flags & PA_CPU_X86_3DNOW) ? "3DNOW " : "", - (flags & PA_CPU_X86_3DNOWEXT) ? "3DNOWEXT " : ""); + (flags & PA_CPU_X86_MMX) ? "MMX " : "", + (flags & PA_CPU_X86_SSE) ? "SSE " : "", + (flags & PA_CPU_X86_SSE2) ? "SSE2 " : "", + (flags & PA_CPU_X86_SSE3) ? "SSE3 " : "", + (flags & PA_CPU_X86_SSSE3) ? "SSSE3 " : "", + (flags & PA_CPU_X86_SSE4_1) ? "SSE4_1 " : "", + (flags & PA_CPU_X86_SSE4_2) ? "SSE4_2 " : "", + (flags & PA_CPU_X86_MMXEXT) ? "MMXEXT " : "", + (flags & PA_CPU_X86_3DNOW) ? "3DNOW " : "", + (flags & PA_CPU_X86_3DNOWEXT) ? "3DNOWEXT " : ""); /* activate various optimisations */ - if (flags & PA_CPU_X86_MMX) { + if (flags & PA_CPU_X86_MMX) pa_volume_func_init_mmx (flags); - } - if (flags & PA_CPU_X86_SSE) { - pa_volume_func_init_sse (flags); - } + + if (flags & PA_CPU_X86_SSE) + pa_volume_func_init_sse (flags); + #endif /* defined (__i386__) || defined (__amd64__) */ } diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 43771dc8..5a6c398e 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -1065,30 +1065,53 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) } static void remap_mono_to_stereo(pa_resampler *r, void *dst, const void *src, unsigned n) { - + unsigned i; + switch (r->work_format) { case PA_SAMPLE_FLOAT32NE: { float *d, *s; - d = (float *) dst; - s = (float *) src; + d = (float *) dst; + s = (float *) src; - for (; n > 0; n--, s++, d += 2) - d[0] = d[1] = *s; - break; - } + for (i = n >> 2; i; i--) { + d[0] = d[1] = s[0]; + d[2] = d[3] = s[1]; + d[4] = d[5] = s[2]; + d[6] = d[7] = s[3]; + s += 4; + d += 8; + } + for (i = n & 3; i; i--) { + d[0] = d[1] = s[0]; + s++; + d += 2; + } + break; + } case PA_SAMPLE_S16NE: { int16_t *d, *s; - d = (int16_t *) dst; - s = (int16_t *) src; + d = (int16_t *) dst; + s = (int16_t *) src; - for (; n > 0; n--, s++, d += 2) - d[0] = d[1] = *s; - break; - } + for (i = n >> 2; i; i--) { + d[0] = d[1] = s[0]; + d[2] = d[3] = s[1]; + d[4] = d[5] = s[2]; + d[6] = d[7] = s[3]; + s += 4; + d += 8; + } + for (i = n & 3; i; i--) { + d[0] = d[1] = s[0]; + s++; + d += 2; + } + break; + } default: pa_assert_not_reached(); } @@ -1114,7 +1137,7 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, for (ic = 0; ic < n_ic; ic++) { float vol; - vol = r->map_table_f[oc][ic]; + vol = r->map_table_f[oc][ic]; if (vol <= 0.0) continue; @@ -1122,18 +1145,18 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, d = (float *)dst + oc; s = (float *)src + ic; - if (vol >= 1.0) { + if (vol >= 1.0) { for (i = n; i > 0; i--, s += n_ic, d += n_oc) *d += *s; - } else { + } else { for (i = n; i > 0; i--, s += n_ic, d += n_oc) *d += *s * vol; - } + } } } break; - } + } case PA_SAMPLE_S16NE: { int16_t *d, *s; @@ -1144,7 +1167,7 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, for (ic = 0; ic < n_ic; ic++) { int32_t vol; - vol = r->map_table_i[oc][ic]; + vol = r->map_table_i[oc][ic]; if (vol <= 0) continue; @@ -1158,11 +1181,11 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, } else { for (i = n; i > 0; i--, s += n_ic, d += n_oc) *d += (int16_t) (((int32_t)*s * vol) >> 16); - } + } } } break; - } + } default: pa_assert_not_reached(); } diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 677f914a..6e97e5a9 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -752,12 +752,13 @@ void pa_volume_memchunk( return; } - ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; - do_volume = pa_get_volume_func (spec->format); pa_assert(do_volume); - + calc_volume_table[spec->format] ((void *)linear, volume); + + ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; + do_volume (ptr, (void *)linear, spec->channels, c->length); pa_memblock_release(c->memblock); @@ -944,12 +945,12 @@ void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const vo for (; n > 0; n--) { float f; - f = *s; + f = *s; *d = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f); s = (const float*) ((const uint8_t*) s + sstr); d = (float*) ((uint8_t*) d + dstr); - } + } } else { pa_assert(format == PA_SAMPLE_FLOAT32RE); diff --git a/src/pulsecore/svolume_arm.c b/src/pulsecore/svolume_arm.c index 7e25a13c..0d39d105 100644 --- a/src/pulsecore/svolume_arm.c +++ b/src/pulsecore/svolume_arm.c @@ -40,86 +40,86 @@ #define MOD_INC() \ " subs r0, r6, %2 \n\t" \ " addcs r0, %1 \n\t" \ - " movcs r6, r0 \n\t" + " movcs r6, r0 \n\t" static void pa_volume_s16ne_arm (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - int32_t *ve; - - channels = MAX (4, channels); - ve = volumes + channels; - - __asm__ __volatile__ ( - " mov r6, %1 \n\t" - " mov %3, %3, LSR #1 \n\t" /* length /= sizeof (int16_t) */ - " tst %3, #1 \n\t" /* check for odd samples */ - " beq 2f \n\t" - - "1: \n\t" - " ldr r0, [r6], #4 \n\t" /* odd samples volumes */ - " ldrh r2, [%0] \n\t" - - " smulwb r0, r0, r2 \n\t" - " ssat r0, #16, r0 \n\t" - - " strh r0, [%0], #2 \n\t" - - MOD_INC() - - "2: \n\t" - " mov %3, %3, LSR #1 \n\t" - " tst %3, #1 \n\t" /* check for odd samples */ - " beq 4f \n\t" - - "3: \n\t" - " ldrd r2, [r6], #8 \n\t" /* 2 samples at a time */ - " ldr r0, [%0] \n\t" - - " smulwt r2, r2, r0 \n\t" - " smulwb r3, r3, r0 \n\t" - - " ssat r2, #16, r2 \n\t" - " ssat r3, #16, r3 \n\t" - - " pkhbt r0, r3, r2, LSL #16 \n\t" - " str r0, [%0], #4 \n\t" - - MOD_INC() - - "4: \n\t" - " movs %3, %3, LSR #1 \n\t" - " beq 6f \n\t" - - "5: \n\t" - " ldrd r2, [r6], #8 \n\t" /* 4 samples at a time */ - " ldrd r4, [r6], #8 \n\t" - " ldrd r0, [%0] \n\t" - - " smulwt r2, r2, r0 \n\t" - " smulwb r3, r3, r0 \n\t" - " smulwt r4, r4, r1 \n\t" - " smulwb r5, r5, r1 \n\t" - - " ssat r2, #16, r2 \n\t" - " ssat r3, #16, r3 \n\t" - " ssat r4, #16, r4 \n\t" - " ssat r5, #16, r5 \n\t" - - " pkhbt r0, r3, r2, LSL #16 \n\t" - " pkhbt r1, r5, r4, LSL #16 \n\t" - " strd r0, [%0], #8 \n\t" - - MOD_INC() - - " subs %3, %3, #1 \n\t" - " bne 5b \n\t" - "6: \n\t" - - : "+r" (samples), "+r" (volumes), "+r" (ve), "+r" (length) - : - : "r6", "r5", "r4", "r3", "r2", "r1", "r0", "cc" - ); + int32_t *ve; + + channels = MAX (4, channels); + ve = volumes + channels; + + __asm__ __volatile__ ( + " mov r6, %1 \n\t" + " mov %3, %3, LSR #1 \n\t" /* length /= sizeof (int16_t) */ + " tst %3, #1 \n\t" /* check for odd samples */ + " beq 2f \n\t" + + "1: \n\t" + " ldr r0, [r6], #4 \n\t" /* odd samples volumes */ + " ldrh r2, [%0] \n\t" + + " smulwb r0, r0, r2 \n\t" + " ssat r0, #16, r0 \n\t" + + " strh r0, [%0], #2 \n\t" + + MOD_INC() + + "2: \n\t" + " mov %3, %3, LSR #1 \n\t" + " tst %3, #1 \n\t" /* check for odd samples */ + " beq 4f \n\t" + + "3: \n\t" + " ldrd r2, [r6], #8 \n\t" /* 2 samples at a time */ + " ldr r0, [%0] \n\t" + + " smulwt r2, r2, r0 \n\t" + " smulwb r3, r3, r0 \n\t" + + " ssat r2, #16, r2 \n\t" + " ssat r3, #16, r3 \n\t" + + " pkhbt r0, r3, r2, LSL #16 \n\t" + " str r0, [%0], #4 \n\t" + + MOD_INC() + + "4: \n\t" + " movs %3, %3, LSR #1 \n\t" + " beq 6f \n\t" + + "5: \n\t" + " ldrd r2, [r6], #8 \n\t" /* 4 samples at a time */ + " ldrd r4, [r6], #8 \n\t" + " ldrd r0, [%0] \n\t" + + " smulwt r2, r2, r0 \n\t" + " smulwb r3, r3, r0 \n\t" + " smulwt r4, r4, r1 \n\t" + " smulwb r5, r5, r1 \n\t" + + " ssat r2, #16, r2 \n\t" + " ssat r3, #16, r3 \n\t" + " ssat r4, #16, r4 \n\t" + " ssat r5, #16, r5 \n\t" + + " pkhbt r0, r3, r2, LSL #16 \n\t" + " pkhbt r1, r5, r4, LSL #16 \n\t" + " strd r0, [%0], #8 \n\t" + + MOD_INC() + + " subs %3, %3, #1 \n\t" + " bne 5b \n\t" + "6: \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (ve), "+r" (length) + : + : "r6", "r5", "r4", "r3", "r2", "r1", "r0", "cc" + ); } #undef RUN_TEST @@ -131,51 +131,51 @@ pa_volume_s16ne_arm (int16_t *samples, int32_t *volumes, unsigned channels, unsi #define PADDING 16 static void run_test (void) { - int16_t samples[SAMPLES]; - int16_t samples_ref[SAMPLES]; - int16_t samples_orig[SAMPLES]; - int32_t volumes[CHANNELS + PADDING]; - int i, j, padding; - pa_do_volume_func_t func; - struct timeval start, stop; - - func = pa_get_volume_func (PA_SAMPLE_S16NE); - - printf ("checking ARM %zd\n", sizeof (samples)); - - pa_random (samples, sizeof (samples)); - memcpy (samples_ref, samples, sizeof (samples)); - memcpy (samples_orig, samples, sizeof (samples)); - - for (i = 0; i < CHANNELS; i++) - volumes[i] = rand() >> 1; - for (padding = 0; padding < PADDING; padding++, i++) - volumes[i] = volumes[padding]; - - func (samples_ref, volumes, CHANNELS, sizeof (samples)); - pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples)); - for (i = 0; i < SAMPLES; i++) { - if (samples[i] != samples_ref[i]) { - printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], - samples_orig[i], volumes[i % CHANNELS]); - } - } + int16_t samples[SAMPLES]; + int16_t samples_ref[SAMPLES]; + int16_t samples_orig[SAMPLES]; + int32_t volumes[CHANNELS + PADDING]; + int i, j, padding; + pa_do_volume_func_t func; + struct timeval start, stop; - pa_gettimeofday(&start); - for (j = 0; j < TIMES; j++) { - memcpy (samples, samples_orig, sizeof (samples)); - pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples)); - } - pa_gettimeofday(&stop); - pa_log_info("ARM: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + func = pa_get_volume_func (PA_SAMPLE_S16NE); + + printf ("checking ARM %zd\n", sizeof (samples)); + + pa_random (samples, sizeof (samples)); + memcpy (samples_ref, samples, sizeof (samples)); + memcpy (samples_orig, samples, sizeof (samples)); + + for (i = 0; i < CHANNELS; i++) + volumes[i] = rand() >> 1; + for (padding = 0; padding < PADDING; padding++, i++) + volumes[i] = volumes[padding]; - pa_gettimeofday(&start); - for (j = 0; j < TIMES; j++) { - memcpy (samples_ref, samples_orig, sizeof (samples)); func (samples_ref, volumes, CHANNELS, sizeof (samples)); - } - pa_gettimeofday(&stop); - pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples)); + for (i = 0; i < SAMPLES; i++) { + if (samples[i] != samples_ref[i]) { + printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); + } + } + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples, samples_orig, sizeof (samples)); + pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("ARM: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples_ref, samples_orig, sizeof (samples)); + func (samples_ref, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); } #endif @@ -184,12 +184,12 @@ static void run_test (void) { void pa_volume_func_init_arm (pa_cpu_arm_flag_t flags) { #if defined (__arm__) - pa_log_info("Initialising ARM optimized functions."); + pa_log_info("Initialising ARM optimized functions."); #ifdef RUN_TEST - run_test (); + run_test (); #endif - pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_arm); + pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_arm); #endif /* defined (__arm__) */ } diff --git a/src/pulsecore/svolume_c.c b/src/pulsecore/svolume_c.c index 2148a573..5fc052b8 100644 --- a/src/pulsecore/svolume_c.c +++ b/src/pulsecore/svolume_c.c @@ -35,289 +35,289 @@ static void pa_volume_u8_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - for (channel = 0; length; length--) { - int32_t t, hi, lo; + for (channel = 0; length; length--) { + int32_t t, hi, lo; - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; - t = (int32_t) *samples - 0x80; - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); - *samples++ = (uint8_t) (t + 0x80); + t = (int32_t) *samples - 0x80; + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F); + *samples++ = (uint8_t) (t + 0x80); - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_alaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - for (channel = 0; length; length--) { - int32_t t, hi, lo; + for (channel = 0; length; length--) { + int32_t t, hi, lo; - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; - t = (int32_t) st_alaw2linear16(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3); + t = (int32_t) st_alaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3); - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_ulaw_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - for (channel = 0; length; length--) { - int32_t t, hi, lo; + for (channel = 0; length; length--) { + int32_t t, hi, lo; - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; - t = (int32_t) st_ulaw2linear16(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); + t = (int32_t) st_ulaw2linear16(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_s16ne_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - length /= sizeof (int16_t); + length /= sizeof (int16_t); - for (channel = 0; length; length--) { - int32_t t, hi, lo; + for (channel = 0; length; length--) { + int32_t t, hi, lo; - /* Multiplying the 32bit volume factor with the 16bit - * sample might result in an 48bit value. We want to - * do without 64 bit integers and hence do the - * multiplication independantly for the HI and LO part - * of the volume. */ + /* Multiplying the 32bit volume factor with the 16bit + * sample might result in an 48bit value. We want to + * do without 64 bit integers and hence do the + * multiplication independantly for the HI and LO part + * of the volume. */ - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; - t = (int32_t)(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = (int16_t) t; + t = (int32_t)(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = (int16_t) t; - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_s16re_c (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - length /= sizeof (int16_t); + length /= sizeof (int16_t); - for (channel = 0; length; length--) { - int32_t t, hi, lo; + for (channel = 0; length; length--) { + int32_t t, hi, lo; - hi = volumes[channel] >> 16; - lo = volumes[channel] & 0xFFFF; + hi = volumes[channel] >> 16; + lo = volumes[channel] & 0xFFFF; - t = (int32_t) PA_INT16_SWAP(*samples); - t = ((t * lo) >> 16) + (t * hi); - t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *samples++ = PA_INT16_SWAP((int16_t) t); + t = (int32_t) PA_INT16_SWAP(*samples); + t = ((t * lo) >> 16) + (t * hi); + t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); + *samples++ = PA_INT16_SWAP((int16_t) t); - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_float32ne_c (float *samples, float *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - length /= sizeof (float); + length /= sizeof (float); - for (channel = 0; length; length--) { - *samples++ *= volumes[channel]; + for (channel = 0; length; length--) { + *samples++ *= volumes[channel]; - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_float32re_c (float *samples, float *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - length /= sizeof (float); + length /= sizeof (float); - for (channel = 0; length; length--) { - float t; + for (channel = 0; length; length--) { + float t; - t = PA_FLOAT32_SWAP(*samples); - t *= volumes[channel]; - *samples++ = PA_FLOAT32_SWAP(t); + t = PA_FLOAT32_SWAP(*samples); + t *= volumes[channel]; + *samples++ = PA_FLOAT32_SWAP(t); - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_s32ne_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - length /= sizeof (int32_t); + length /= sizeof (int32_t); - for (channel = 0; length; length--) { - int64_t t; + for (channel = 0; length; length--) { + int64_t t; - t = (int64_t)(*samples); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = (int32_t) t; + t = (int64_t)(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = (int32_t) t; - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_s32re_c (int32_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - length /= sizeof (int32_t); + length /= sizeof (int32_t); - for (channel = 0; length; length--) { - int64_t t; + for (channel = 0; length; length--) { + int64_t t; - t = (int64_t) PA_INT32_SWAP(*samples); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = PA_INT32_SWAP((int32_t) t); + t = (int64_t) PA_INT32_SWAP(*samples); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_INT32_SWAP((int32_t) t); - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_s24ne_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; - uint8_t *e; + unsigned channel; + uint8_t *e; - e = samples + length; + e = samples + length; - for (channel = 0; samples < e; samples += 3) { - int64_t t; + for (channel = 0; samples < e; samples += 3) { + int64_t t; - t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8); + t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8); - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_s24re_c (uint8_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; - uint8_t *e; + unsigned channel; + uint8_t *e; - e = samples + length; + e = samples + length; - for (channel = 0; samples < e; samples += 3) { - int64_t t; + for (channel = 0; samples < e; samples += 3) { + int64_t t; - t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8); + t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8); - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_s24_32ne_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - length /= sizeof (uint32_t); + length /= sizeof (uint32_t); - for (channel = 0; length; length--) { - int64_t t; + for (channel = 0; length; length--) { + int64_t t; - t = (int64_t) ((int32_t) (*samples << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = ((uint32_t) ((int32_t) t)) >> 8; + t = (int64_t) ((int32_t) (*samples << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = ((uint32_t) ((int32_t) t)) >> 8; - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static void pa_volume_s24_32re_c (uint32_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - unsigned channel; + unsigned channel; - length /= sizeof (uint32_t); + length /= sizeof (uint32_t); - for (channel = 0; length; length--) { - int64_t t; + for (channel = 0; length; length--) { + int64_t t; - t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8)); - t = (t * volumes[channel]) >> 16; - t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); - *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); + t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8)); + t = (t * volumes[channel]) >> 16; + t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); + *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8); - if (PA_UNLIKELY(++channel >= channels)) - channel = 0; - } + if (PA_UNLIKELY(++channel >= channels)) + channel = 0; + } } static pa_do_volume_func_t do_volume_table[] = { - [PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c, - [PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c, - [PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c, - [PA_SAMPLE_S16NE] = (pa_do_volume_func_t) pa_volume_s16ne_c, - [PA_SAMPLE_S16RE] = (pa_do_volume_func_t) pa_volume_s16re_c, - [PA_SAMPLE_FLOAT32NE] = (pa_do_volume_func_t) pa_volume_float32ne_c, - [PA_SAMPLE_FLOAT32RE] = (pa_do_volume_func_t) pa_volume_float32re_c, - [PA_SAMPLE_S32NE] = (pa_do_volume_func_t) pa_volume_s32ne_c, - [PA_SAMPLE_S32RE] = (pa_do_volume_func_t) pa_volume_s32re_c, - [PA_SAMPLE_S24NE] = (pa_do_volume_func_t) pa_volume_s24ne_c, - [PA_SAMPLE_S24RE] = (pa_do_volume_func_t) pa_volume_s24re_c, - [PA_SAMPLE_S24_32NE] = (pa_do_volume_func_t) pa_volume_s24_32ne_c, - [PA_SAMPLE_S24_32RE] = (pa_do_volume_func_t) pa_volume_s24_32re_c + [PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c, + [PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c, + [PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c, + [PA_SAMPLE_S16NE] = (pa_do_volume_func_t) pa_volume_s16ne_c, + [PA_SAMPLE_S16RE] = (pa_do_volume_func_t) pa_volume_s16re_c, + [PA_SAMPLE_FLOAT32NE] = (pa_do_volume_func_t) pa_volume_float32ne_c, + [PA_SAMPLE_FLOAT32RE] = (pa_do_volume_func_t) pa_volume_float32re_c, + [PA_SAMPLE_S32NE] = (pa_do_volume_func_t) pa_volume_s32ne_c, + [PA_SAMPLE_S32RE] = (pa_do_volume_func_t) pa_volume_s32re_c, + [PA_SAMPLE_S24NE] = (pa_do_volume_func_t) pa_volume_s24ne_c, + [PA_SAMPLE_S24RE] = (pa_do_volume_func_t) pa_volume_s24re_c, + [PA_SAMPLE_S24_32NE] = (pa_do_volume_func_t) pa_volume_s24_32ne_c, + [PA_SAMPLE_S24_32RE] = (pa_do_volume_func_t) pa_volume_s24_32re_c }; pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f) { diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index 86af76d3..7e242684 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -73,7 +73,7 @@ " add "#a", %3 \n\t" \ " mov %3, %4 \n\t" \ " sub "#b", %4 \n\t" \ - " cmovae %4, %3 \n\t" + " cmovae %4, %3 \n\t" /* swap 16 bits */ #define SWAP_16(s) \ @@ -96,147 +96,147 @@ static void pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - pa_reg_x86 channel, temp; - - /* the max number of samples we process at a time, this is also the max amount - * we overread the volume array, which should have enough padding. */ - channels = MAX (4, channels); - - __asm__ __volatile__ ( - " xor %3, %3 \n\t" - " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ - " pcmpeqw %%mm6, %%mm6 \n\t" /* .. | ffff | ffff | */ - " pcmpeqw %%mm7, %%mm7 \n\t" /* .. | ffff | ffff | */ - " pslld $16, %%mm6 \n\t" /* .. | ffff | 0 | */ - " psrld $31, %%mm7 \n\t" /* .. | 0 | 1 | */ - - " test $1, %2 \n\t" /* check for odd samples */ - " je 2f \n\t" - - " movd (%1, %3, 4), %%mm0 \n\t" /* | v0h | v0l | */ - " movw (%0), %w4 \n\t" /* .. | p0 | */ - " movd %4, %%mm1 \n\t" - VOLUME_32x16 (%%mm1, %%mm0) - " movd %%mm0, %4 \n\t" /* .. | p0*v0 | */ - " movw %w4, (%0) \n\t" - " add $2, %0 \n\t" - MOD_ADD ($1, %5) - - "2: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ - " test $1, %2 \n\t" /* check for odd samples */ - " je 4f \n\t" - - "3: \n\t" /* do samples in groups of 2 */ - " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ - " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ - VOLUME_32x16 (%%mm1, %%mm0) - " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ - " add $4, %0 \n\t" - MOD_ADD ($2, %5) - - "4: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ - " cmp $0, %2 \n\t" - " je 6f \n\t" - - "5: \n\t" /* do samples in groups of 4 */ - " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ - " movq 8(%1, %3, 4), %%mm2 \n\t" /* | v3h | v3l | v2h | v2l | */ - " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ - " movd 4(%0), %%mm3 \n\t" /* .. | p3 | p2 | */ - VOLUME_32x16 (%%mm1, %%mm0) - VOLUME_32x16 (%%mm3, %%mm2) - " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ - " movd %%mm2, 4(%0) \n\t" /* .. | p3*v3 | p2*v2 | */ - " add $8, %0 \n\t" - MOD_ADD ($4, %5) - " dec %2 \n\t" - " jne 5b \n\t" - - "6: \n\t" - " emms \n\t" - - : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp) - : "r" ((pa_reg_x86)channels) - : "cc" - ); + pa_reg_x86 channel, temp; + + /* the max number of samples we process at a time, this is also the max amount + * we overread the volume array, which should have enough padding. */ + channels = MAX (4, channels); + + __asm__ __volatile__ ( + " xor %3, %3 \n\t" + " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ + " pcmpeqw %%mm6, %%mm6 \n\t" /* .. | ffff | ffff | */ + " pcmpeqw %%mm7, %%mm7 \n\t" /* .. | ffff | ffff | */ + " pslld $16, %%mm6 \n\t" /* .. | ffff | 0 | */ + " psrld $31, %%mm7 \n\t" /* .. | 0 | 1 | */ + + " test $1, %2 \n\t" /* check for odd samples */ + " je 2f \n\t" + + " movd (%1, %3, 4), %%mm0 \n\t" /* | v0h | v0l | */ + " movw (%0), %w4 \n\t" /* .. | p0 | */ + " movd %4, %%mm1 \n\t" + VOLUME_32x16 (%%mm1, %%mm0) + " movd %%mm0, %4 \n\t" /* .. | p0*v0 | */ + " movw %w4, (%0) \n\t" + " add $2, %0 \n\t" + MOD_ADD ($1, %5) + + "2: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ + " test $1, %2 \n\t" /* check for odd samples */ + " je 4f \n\t" + + "3: \n\t" /* do samples in groups of 2 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ + VOLUME_32x16 (%%mm1, %%mm0) + " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ + " add $4, %0 \n\t" + MOD_ADD ($2, %5) + + "4: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ + " cmp $0, %2 \n\t" + " je 6f \n\t" + + "5: \n\t" /* do samples in groups of 4 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movq 8(%1, %3, 4), %%mm2 \n\t" /* | v3h | v3l | v2h | v2l | */ + " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ + " movd 4(%0), %%mm3 \n\t" /* .. | p3 | p2 | */ + VOLUME_32x16 (%%mm1, %%mm0) + VOLUME_32x16 (%%mm3, %%mm2) + " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ + " movd %%mm2, 4(%0) \n\t" /* .. | p3*v3 | p2*v2 | */ + " add $8, %0 \n\t" + MOD_ADD ($4, %5) + " dec %2 \n\t" + " jne 5b \n\t" + + "6: \n\t" + " emms \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp) + : "r" ((pa_reg_x86)channels) + : "cc" + ); } static void pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - pa_reg_x86 channel, temp; - - /* the max number of samples we process at a time, this is also the max amount - * we overread the volume array, which should have enough padding. */ - channels = MAX (4, channels); - - __asm__ __volatile__ ( - " xor %3, %3 \n\t" - " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ - " pcmpeqw %%mm6, %%mm6 \n\t" /* .. | ffff | ffff | */ - " pcmpeqw %%mm7, %%mm7 \n\t" /* .. | ffff | ffff | */ - " pslld $16, %%mm6 \n\t" /* .. | ffff | 0 | */ - " psrld $31, %%mm7 \n\t" /* .. | 0 | 1 | */ - - " test $1, %2 \n\t" /* check for odd samples */ - " je 2f \n\t" - - " movd (%1, %3, 4), %%mm0 \n\t" /* | v0h | v0l | */ - " movw (%0), %w4 \n\t" /* .. | p0 | */ - " rorw $8, %w4 \n\t" - " movd %4, %%mm1 \n\t" - VOLUME_32x16 (%%mm1, %%mm0) - " movd %%mm0, %4 \n\t" /* .. | p0*v0 | */ - " rorw $8, %w4 \n\t" - " movw %w4, (%0) \n\t" - " add $2, %0 \n\t" - MOD_ADD ($1, %5) - - "2: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ - " test $1, %2 \n\t" /* check for odd samples */ - " je 4f \n\t" - - "3: \n\t" /* do samples in groups of 2 */ - " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ - " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ - SWAP_16 (%%mm1) - VOLUME_32x16 (%%mm1, %%mm0) - SWAP_16 (%%mm0) - " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ - " add $4, %0 \n\t" - MOD_ADD ($2, %5) - - "4: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ - " cmp $0, %2 \n\t" - " je 6f \n\t" - - "5: \n\t" /* do samples in groups of 4 */ - " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ - " movq 8(%1, %3, 4), %%mm2 \n\t" /* | v3h | v3l | v2h | v2l | */ - " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ - " movd 4(%0), %%mm3 \n\t" /* .. | p3 | p2 | */ - SWAP_16_2 (%%mm1, %%mm3) - VOLUME_32x16 (%%mm1, %%mm0) - VOLUME_32x16 (%%mm3, %%mm2) - SWAP_16_2 (%%mm0, %%mm2) - " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ - " movd %%mm2, 4(%0) \n\t" /* .. | p3*v3 | p2*v2 | */ - " add $8, %0 \n\t" - MOD_ADD ($4, %5) - " dec %2 \n\t" - " jne 5b \n\t" - - "6: \n\t" - " emms \n\t" - - : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp) - : "r" ((pa_reg_x86)channels) - : "cc" - ); + pa_reg_x86 channel, temp; + + /* the max number of samples we process at a time, this is also the max amount + * we overread the volume array, which should have enough padding. */ + channels = MAX (4, channels); + + __asm__ __volatile__ ( + " xor %3, %3 \n\t" + " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ + " pcmpeqw %%mm6, %%mm6 \n\t" /* .. | ffff | ffff | */ + " pcmpeqw %%mm7, %%mm7 \n\t" /* .. | ffff | ffff | */ + " pslld $16, %%mm6 \n\t" /* .. | ffff | 0 | */ + " psrld $31, %%mm7 \n\t" /* .. | 0 | 1 | */ + + " test $1, %2 \n\t" /* check for odd samples */ + " je 2f \n\t" + + " movd (%1, %3, 4), %%mm0 \n\t" /* | v0h | v0l | */ + " movw (%0), %w4 \n\t" /* .. | p0 | */ + " rorw $8, %w4 \n\t" + " movd %4, %%mm1 \n\t" + VOLUME_32x16 (%%mm1, %%mm0) + " movd %%mm0, %4 \n\t" /* .. | p0*v0 | */ + " rorw $8, %w4 \n\t" + " movw %w4, (%0) \n\t" + " add $2, %0 \n\t" + MOD_ADD ($1, %5) + + "2: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ + " test $1, %2 \n\t" /* check for odd samples */ + " je 4f \n\t" + + "3: \n\t" /* do samples in groups of 2 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ + SWAP_16 (%%mm1) + VOLUME_32x16 (%%mm1, %%mm0) + SWAP_16 (%%mm0) + " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ + " add $4, %0 \n\t" + MOD_ADD ($2, %5) + + "4: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ + " cmp $0, %2 \n\t" + " je 6f \n\t" + + "5: \n\t" /* do samples in groups of 4 */ + " movq (%1, %3, 4), %%mm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movq 8(%1, %3, 4), %%mm2 \n\t" /* | v3h | v3l | v2h | v2l | */ + " movd (%0), %%mm1 \n\t" /* .. | p1 | p0 | */ + " movd 4(%0), %%mm3 \n\t" /* .. | p3 | p2 | */ + SWAP_16_2 (%%mm1, %%mm3) + VOLUME_32x16 (%%mm1, %%mm0) + VOLUME_32x16 (%%mm3, %%mm2) + SWAP_16_2 (%%mm0, %%mm2) + " movd %%mm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ + " movd %%mm2, 4(%0) \n\t" /* .. | p3*v3 | p2*v2 | */ + " add $8, %0 \n\t" + MOD_ADD ($4, %5) + " dec %2 \n\t" + " jne 5b \n\t" + + "6: \n\t" + " emms \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" ((pa_reg_x86)channel), "=&r" (temp) + : "r" ((pa_reg_x86)channels) + : "cc" + ); } #undef RUN_TEST @@ -248,51 +248,51 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi #define PADDING 16 static void run_test (void) { - int16_t samples[SAMPLES]; - int16_t samples_ref[SAMPLES]; - int16_t samples_orig[SAMPLES]; - int32_t volumes[CHANNELS + PADDING]; - int i, j, padding; - pa_do_volume_func_t func; - struct timeval start, stop; - - func = pa_get_volume_func (PA_SAMPLE_S16NE); - - printf ("checking MMX %zd\n", sizeof (samples)); - - pa_random (samples, sizeof (samples)); - memcpy (samples_ref, samples, sizeof (samples)); - memcpy (samples_orig, samples, sizeof (samples)); - - for (i = 0; i < CHANNELS; i++) - volumes[i] = rand() >> 1; - for (padding = 0; padding < PADDING; padding++, i++) - volumes[i] = volumes[padding]; - - func (samples_ref, volumes, CHANNELS, sizeof (samples)); - pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); - for (i = 0; i < SAMPLES; i++) { - if (samples[i] != samples_ref[i]) { - printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], - samples_orig[i], volumes[i % CHANNELS]); - } - } + int16_t samples[SAMPLES]; + int16_t samples_ref[SAMPLES]; + int16_t samples_orig[SAMPLES]; + int32_t volumes[CHANNELS + PADDING]; + int i, j, padding; + pa_do_volume_func_t func; + struct timeval start, stop; - pa_gettimeofday(&start); - for (j = 0; j < TIMES; j++) { - memcpy (samples, samples_orig, sizeof (samples)); - pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); - } - pa_gettimeofday(&stop); - pa_log_info("MMX: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + func = pa_get_volume_func (PA_SAMPLE_S16NE); + + printf ("checking MMX %zd\n", sizeof (samples)); + + pa_random (samples, sizeof (samples)); + memcpy (samples_ref, samples, sizeof (samples)); + memcpy (samples_orig, samples, sizeof (samples)); + + for (i = 0; i < CHANNELS; i++) + volumes[i] = rand() >> 1; + for (padding = 0; padding < PADDING; padding++, i++) + volumes[i] = volumes[padding]; - pa_gettimeofday(&start); - for (j = 0; j < TIMES; j++) { - memcpy (samples_ref, samples_orig, sizeof (samples)); func (samples_ref, volumes, CHANNELS, sizeof (samples)); - } - pa_gettimeofday(&stop); - pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); + for (i = 0; i < SAMPLES; i++) { + if (samples[i] != samples_ref[i]) { + printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); + } + } + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples, samples_orig, sizeof (samples)); + pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("MMX: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples_ref, samples_orig, sizeof (samples)); + func (samples_ref, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); } #endif @@ -301,13 +301,13 @@ static void run_test (void) { void pa_volume_func_init_mmx (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) - pa_log_info("Initialising MMX optimized functions."); + pa_log_info("Initialising MMX optimized functions."); #ifdef RUN_TEST - run_test (); + run_test (); #endif - pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx); - pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx); + pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx); + pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx); #endif /* defined (__i386__) || defined (__amd64__) */ } diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index 5979f7c2..b5e3687f 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -48,7 +48,7 @@ " psrld $16, "#v" \n\t" /* .. | p0 | 0 | */ \ " pmaddwd %%xmm5, "#v" \n\t" /* .. | p0 * vh | */ \ " paddd "#s", "#v" \n\t" /* .. | p0 * v0 | */ \ - " packssdw "#v", "#v" \n\t" /* .. | p1*v1 | p0*v0 | */ + " packssdw "#v", "#v" \n\t" /* .. | p1*v1 | p0*v0 | */ #define MOD_ADD(a,b) \ " add "#a", %3 \n\t" /* channel += inc */ \ @@ -77,169 +77,169 @@ static void pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - pa_reg_x86 channel, temp; - - /* the max number of samples we process at a time, this is also the max amount - * we overread the volume array, which should have enough padding. */ - channels = MAX (8, channels); - - __asm__ __volatile__ ( - " xor %3, %3 \n\t" - " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ - - " test $1, %2 \n\t" /* check for odd samples */ - " je 2f \n\t" - - " movd (%1, %3, 4), %%xmm0 \n\t" /* | v0h | v0l | */ - " movw (%0), %w4 \n\t" /* .. | p0 | */ - " movd %4, %%xmm1 \n\t" - VOLUME_32x16 (%%xmm1, %%xmm0) - " movd %%xmm0, %4 \n\t" /* .. | p0*v0 | */ - " movw %w4, (%0) \n\t" - " add $2, %0 \n\t" - MOD_ADD ($1, %5) - - "2: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ - " test $1, %2 \n\t" - " je 4f \n\t" - - "3: \n\t" /* do samples in groups of 2 */ - " movq (%1, %3, 4), %%xmm0 \n\t" /* | v1h | v1l | v0h | v0l | */ - " movd (%0), %%xmm1 \n\t" /* .. | p1 | p0 | */ - VOLUME_32x16 (%%xmm1, %%xmm0) - " movd %%xmm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ - " add $4, %0 \n\t" - MOD_ADD ($2, %5) - - "4: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ - " test $1, %2 \n\t" - " je 6f \n\t" - - /* FIXME, we can do aligned access of the volume values if we can guarantee - * that the array is 16 bytes aligned, we probably have to do the odd values - * after this then. */ - "5: \n\t" /* do samples in groups of 4 */ - " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ - " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ - VOLUME_32x16 (%%xmm1, %%xmm0) - " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ - " add $8, %0 \n\t" - MOD_ADD ($4, %5) - - "6: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 8 samples at a time */ - " cmp $0, %2 \n\t" - " je 8f \n\t" - - "7: \n\t" /* do samples in groups of 8 */ - " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ - " movdqu 16(%1, %3, 4), %%xmm2 \n\t" /* | v7h | v7l .. v4h | v4l | */ - " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ - " movq 8(%0), %%xmm3 \n\t" /* .. | p7 .. p4 | */ - VOLUME_32x16 (%%xmm1, %%xmm0) - VOLUME_32x16 (%%xmm3, %%xmm2) - " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ - " movq %%xmm2, 8(%0) \n\t" /* .. | p7*v7 .. p4*v4 | */ - " add $16, %0 \n\t" - MOD_ADD ($8, %5) - " dec %2 \n\t" - " jne 7b \n\t" - "8: \n\t" - - : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp) - : "r" ((pa_reg_x86)channels) - : "cc" - ); + pa_reg_x86 channel, temp; + + /* the max number of samples we process at a time, this is also the max amount + * we overread the volume array, which should have enough padding. */ + channels = MAX (8, channels); + + __asm__ __volatile__ ( + " xor %3, %3 \n\t" + " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ + + " test $1, %2 \n\t" /* check for odd samples */ + " je 2f \n\t" + + " movd (%1, %3, 4), %%xmm0 \n\t" /* | v0h | v0l | */ + " movw (%0), %w4 \n\t" /* .. | p0 | */ + " movd %4, %%xmm1 \n\t" + VOLUME_32x16 (%%xmm1, %%xmm0) + " movd %%xmm0, %4 \n\t" /* .. | p0*v0 | */ + " movw %w4, (%0) \n\t" + " add $2, %0 \n\t" + MOD_ADD ($1, %5) + + "2: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ + " test $1, %2 \n\t" + " je 4f \n\t" + + "3: \n\t" /* do samples in groups of 2 */ + " movq (%1, %3, 4), %%xmm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movd (%0), %%xmm1 \n\t" /* .. | p1 | p0 | */ + VOLUME_32x16 (%%xmm1, %%xmm0) + " movd %%xmm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ + " add $4, %0 \n\t" + MOD_ADD ($2, %5) + + "4: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ + " test $1, %2 \n\t" + " je 6f \n\t" + + /* FIXME, we can do aligned access of the volume values if we can guarantee + * that the array is 16 bytes aligned, we probably have to do the odd values + * after this then. */ + "5: \n\t" /* do samples in groups of 4 */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ + " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ + VOLUME_32x16 (%%xmm1, %%xmm0) + " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ + " add $8, %0 \n\t" + MOD_ADD ($4, %5) + + "6: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 8 samples at a time */ + " cmp $0, %2 \n\t" + " je 8f \n\t" + + "7: \n\t" /* do samples in groups of 8 */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ + " movdqu 16(%1, %3, 4), %%xmm2 \n\t" /* | v7h | v7l .. v4h | v4l | */ + " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ + " movq 8(%0), %%xmm3 \n\t" /* .. | p7 .. p4 | */ + VOLUME_32x16 (%%xmm1, %%xmm0) + VOLUME_32x16 (%%xmm3, %%xmm2) + " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ + " movq %%xmm2, 8(%0) \n\t" /* .. | p7*v7 .. p4*v4 | */ + " add $16, %0 \n\t" + MOD_ADD ($8, %5) + " dec %2 \n\t" + " jne 7b \n\t" + "8: \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp) + : "r" ((pa_reg_x86)channels) + : "cc" + ); } static void pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { - pa_reg_x86 channel, temp; - - /* the max number of samples we process at a time, this is also the max amount - * we overread the volume array, which should have enough padding. */ - channels = MAX (8, channels); - - __asm__ __volatile__ ( - " xor %3, %3 \n\t" - " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ - - " test $1, %2 \n\t" /* check for odd samples */ - " je 2f \n\t" - - " movd (%1, %3, 4), %%xmm0 \n\t" /* | v0h | v0l | */ - " movw (%0), %w4 \n\t" /* .. | p0 | */ - " rorw $8, %w4 \n\t" - " movd %4, %%xmm1 \n\t" - VOLUME_32x16 (%%xmm1, %%xmm0) - " movd %%xmm0, %4 \n\t" /* .. | p0*v0 | */ - " rorw $8, %w4 \n\t" - " movw %w4, (%0) \n\t" - " add $2, %0 \n\t" - MOD_ADD ($1, %5) - - "2: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ - " test $1, %2 \n\t" - " je 4f \n\t" - - "3: \n\t" /* do samples in groups of 2 */ - " movq (%1, %3, 4), %%xmm0 \n\t" /* | v1h | v1l | v0h | v0l | */ - " movd (%0), %%xmm1 \n\t" /* .. | p1 | p0 | */ - SWAP_16 (%%xmm1) - VOLUME_32x16 (%%xmm1, %%xmm0) - SWAP_16 (%%xmm0) - " movd %%xmm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ - " add $4, %0 \n\t" - MOD_ADD ($2, %5) - - "4: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ - " test $1, %2 \n\t" - " je 6f \n\t" - - /* FIXME, we can do aligned access of the volume values if we can guarantee - * that the array is 16 bytes aligned, we probably have to do the odd values - * after this then. */ - "5: \n\t" /* do samples in groups of 4 */ - " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ - " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ - SWAP_16 (%%xmm1) - VOLUME_32x16 (%%xmm1, %%xmm0) - SWAP_16 (%%xmm0) - " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ - " add $8, %0 \n\t" - MOD_ADD ($4, %5) - - "6: \n\t" - " sar $1, %2 \n\t" /* prepare for processing 8 samples at a time */ - " cmp $0, %2 \n\t" - " je 8f \n\t" - - "7: \n\t" /* do samples in groups of 8 */ - " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ - " movdqu 16(%1, %3, 4), %%xmm2 \n\t" /* | v7h | v7l .. v4h | v4l | */ - " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ - " movq 8(%0), %%xmm3 \n\t" /* .. | p7 .. p4 | */ - SWAP_16_2 (%%xmm1, %%xmm3) - VOLUME_32x16 (%%xmm1, %%xmm0) - VOLUME_32x16 (%%xmm3, %%xmm2) - SWAP_16_2 (%%xmm0, %%xmm2) - " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ - " movq %%xmm2, 8(%0) \n\t" /* .. | p7*v7 .. p4*v4 | */ - " add $16, %0 \n\t" - MOD_ADD ($8, %5) - " dec %2 \n\t" - " jne 7b \n\t" - "8: \n\t" - - : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp) - : "r" ((pa_reg_x86)channels) - : "cc" - ); + pa_reg_x86 channel, temp; + + /* the max number of samples we process at a time, this is also the max amount + * we overread the volume array, which should have enough padding. */ + channels = MAX (8, channels); + + __asm__ __volatile__ ( + " xor %3, %3 \n\t" + " sar $1, %2 \n\t" /* length /= sizeof (int16_t) */ + + " test $1, %2 \n\t" /* check for odd samples */ + " je 2f \n\t" + + " movd (%1, %3, 4), %%xmm0 \n\t" /* | v0h | v0l | */ + " movw (%0), %w4 \n\t" /* .. | p0 | */ + " rorw $8, %w4 \n\t" + " movd %4, %%xmm1 \n\t" + VOLUME_32x16 (%%xmm1, %%xmm0) + " movd %%xmm0, %4 \n\t" /* .. | p0*v0 | */ + " rorw $8, %w4 \n\t" + " movw %w4, (%0) \n\t" + " add $2, %0 \n\t" + MOD_ADD ($1, %5) + + "2: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 2 samples at a time */ + " test $1, %2 \n\t" + " je 4f \n\t" + + "3: \n\t" /* do samples in groups of 2 */ + " movq (%1, %3, 4), %%xmm0 \n\t" /* | v1h | v1l | v0h | v0l | */ + " movd (%0), %%xmm1 \n\t" /* .. | p1 | p0 | */ + SWAP_16 (%%xmm1) + VOLUME_32x16 (%%xmm1, %%xmm0) + SWAP_16 (%%xmm0) + " movd %%xmm0, (%0) \n\t" /* .. | p1*v1 | p0*v0 | */ + " add $4, %0 \n\t" + MOD_ADD ($2, %5) + + "4: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 4 samples at a time */ + " test $1, %2 \n\t" + " je 6f \n\t" + + /* FIXME, we can do aligned access of the volume values if we can guarantee + * that the array is 16 bytes aligned, we probably have to do the odd values + * after this then. */ + "5: \n\t" /* do samples in groups of 4 */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ + " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ + SWAP_16 (%%xmm1) + VOLUME_32x16 (%%xmm1, %%xmm0) + SWAP_16 (%%xmm0) + " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ + " add $8, %0 \n\t" + MOD_ADD ($4, %5) + + "6: \n\t" + " sar $1, %2 \n\t" /* prepare for processing 8 samples at a time */ + " cmp $0, %2 \n\t" + " je 8f \n\t" + + "7: \n\t" /* do samples in groups of 8 */ + " movdqu (%1, %3, 4), %%xmm0 \n\t" /* | v3h | v3l .. v0h | v0l | */ + " movdqu 16(%1, %3, 4), %%xmm2 \n\t" /* | v7h | v7l .. v4h | v4l | */ + " movq (%0), %%xmm1 \n\t" /* .. | p3 .. p0 | */ + " movq 8(%0), %%xmm3 \n\t" /* .. | p7 .. p4 | */ + SWAP_16_2 (%%xmm1, %%xmm3) + VOLUME_32x16 (%%xmm1, %%xmm0) + VOLUME_32x16 (%%xmm3, %%xmm2) + SWAP_16_2 (%%xmm0, %%xmm2) + " movq %%xmm0, (%0) \n\t" /* .. | p3*v3 .. p0*v0 | */ + " movq %%xmm2, 8(%0) \n\t" /* .. | p7*v7 .. p4*v4 | */ + " add $16, %0 \n\t" + MOD_ADD ($8, %5) + " dec %2 \n\t" + " jne 7b \n\t" + "8: \n\t" + + : "+r" (samples), "+r" (volumes), "+r" (length), "=D" (channel), "=&r" (temp) + : "r" ((pa_reg_x86)channels) + : "cc" + ); } #undef RUN_TEST @@ -251,64 +251,64 @@ pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi #define PADDING 16 static void run_test (void) { - int16_t samples[SAMPLES]; - int16_t samples_ref[SAMPLES]; - int16_t samples_orig[SAMPLES]; - int32_t volumes[CHANNELS + PADDING]; - int i, j, padding; - pa_do_volume_func_t func; - struct timeval start, stop; - - func = pa_get_volume_func (PA_SAMPLE_S16NE); - - printf ("checking SSE %zd\n", sizeof (samples)); - - pa_random (samples, sizeof (samples)); - memcpy (samples_ref, samples, sizeof (samples)); - memcpy (samples_orig, samples, sizeof (samples)); - - for (i = 0; i < CHANNELS; i++) - volumes[i] = rand() >> 1; - for (padding = 0; padding < PADDING; padding++, i++) - volumes[i] = volumes[padding]; - - func (samples_ref, volumes, CHANNELS, sizeof (samples)); - pa_volume_s16ne_sse (samples, volumes, CHANNELS, sizeof (samples)); - for (i = 0; i < SAMPLES; i++) { - if (samples[i] != samples_ref[i]) { - printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], - samples_orig[i], volumes[i % CHANNELS]); - } - } + int16_t samples[SAMPLES]; + int16_t samples_ref[SAMPLES]; + int16_t samples_orig[SAMPLES]; + int32_t volumes[CHANNELS + PADDING]; + int i, j, padding; + pa_do_volume_func_t func; + struct timeval start, stop; - pa_gettimeofday(&start); - for (j = 0; j < TIMES; j++) { - memcpy (samples, samples_orig, sizeof (samples)); - pa_volume_s16ne_sse (samples, volumes, CHANNELS, sizeof (samples)); - } - pa_gettimeofday(&stop); - pa_log_info("SSE: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + func = pa_get_volume_func (PA_SAMPLE_S16NE); + + printf ("checking SSE %zd\n", sizeof (samples)); + + pa_random (samples, sizeof (samples)); + memcpy (samples_ref, samples, sizeof (samples)); + memcpy (samples_orig, samples, sizeof (samples)); + + for (i = 0; i < CHANNELS; i++) + volumes[i] = rand() >> 1; + for (padding = 0; padding < PADDING; padding++, i++) + volumes[i] = volumes[padding]; - pa_gettimeofday(&start); - for (j = 0; j < TIMES; j++) { - memcpy (samples_ref, samples_orig, sizeof (samples)); func (samples_ref, volumes, CHANNELS, sizeof (samples)); - } - pa_gettimeofday(&stop); - pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + pa_volume_s16ne_sse (samples, volumes, CHANNELS, sizeof (samples)); + for (i = 0; i < SAMPLES; i++) { + if (samples[i] != samples_ref[i]) { + printf ("%d: %04x != %04x (%04x * %04x)\n", i, samples[i], samples_ref[i], + samples_orig[i], volumes[i % CHANNELS]); + } + } + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples, samples_orig, sizeof (samples)); + pa_volume_s16ne_sse (samples, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("SSE: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + + pa_gettimeofday(&start); + for (j = 0; j < TIMES; j++) { + memcpy (samples_ref, samples_orig, sizeof (samples)); + func (samples_ref, volumes, CHANNELS, sizeof (samples)); + } + pa_gettimeofday(&stop); + pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); } #endif #endif /* defined (__i386__) || defined (__amd64__) */ void pa_volume_func_init_sse (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) - pa_log_info("Initialising SSE optimized functions."); + pa_log_info("Initialising SSE optimized functions."); #ifdef RUN_TEST - run_test (); + run_test (); #endif - pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse); - pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse); + pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse); + pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse); #endif /* defined (__i386__) || defined (__amd64__) */ } -- cgit From f8ffe0dabcedf56437c00feb895d7d7229971ba0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 12:30:48 +0200 Subject: svolume: cleanups Use PA_MAX Use pa_rtclock_now() for benchmarks --- src/pulsecore/svolume_arm.c | 16 ++++++++-------- src/pulsecore/svolume_mmx.c | 18 +++++++++--------- src/pulsecore/svolume_sse.c | 18 +++++++++--------- 3 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/pulsecore/svolume_arm.c b/src/pulsecore/svolume_arm.c index 0d39d105..5bd1448f 100644 --- a/src/pulsecore/svolume_arm.c +++ b/src/pulsecore/svolume_arm.c @@ -47,7 +47,7 @@ pa_volume_s16ne_arm (int16_t *samples, int32_t *volumes, unsigned channels, unsi { int32_t *ve; - channels = MAX (4, channels); + channels = PA_MAX (4U, channels); ve = volumes + channels; __asm__ __volatile__ ( @@ -137,7 +137,7 @@ static void run_test (void) { int32_t volumes[CHANNELS + PADDING]; int i, j, padding; pa_do_volume_func_t func; - struct timeval start, stop; + pa_usec_t start, stop; func = pa_get_volume_func (PA_SAMPLE_S16NE); @@ -161,21 +161,21 @@ static void run_test (void) { } } - pa_gettimeofday(&start); + start = pa_rtclock_now(); for (j = 0; j < TIMES; j++) { memcpy (samples, samples_orig, sizeof (samples)); pa_volume_s16ne_arm (samples, volumes, CHANNELS, sizeof (samples)); } - pa_gettimeofday(&stop); - pa_log_info("ARM: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + stop = pa_rtclock_now(); + pa_log_info("ARM: %llu usec.", (long long unsigned int) (stop - start)); - pa_gettimeofday(&start); + start = pa_rtclock_now(); for (j = 0; j < TIMES; j++) { memcpy (samples_ref, samples_orig, sizeof (samples)); func (samples_ref, volumes, CHANNELS, sizeof (samples)); } - pa_gettimeofday(&stop); - pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + stop = pa_rtclock_now(); + pa_log_info("ref: %llu usec.", (long long unsigned int) (stop - start)); } #endif diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index 7e242684..8510b0c4 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -100,7 +100,7 @@ pa_volume_s16ne_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi /* the max number of samples we process at a time, this is also the max amount * we overread the volume array, which should have enough padding. */ - channels = MAX (4, channels); + channels = PA_MAX (4U, channels); __asm__ __volatile__ ( " xor %3, %3 \n\t" @@ -170,7 +170,7 @@ pa_volume_s16re_mmx (int16_t *samples, int32_t *volumes, unsigned channels, unsi /* the max number of samples we process at a time, this is also the max amount * we overread the volume array, which should have enough padding. */ - channels = MAX (4, channels); + channels = PA_MAX (4U, channels); __asm__ __volatile__ ( " xor %3, %3 \n\t" @@ -254,7 +254,7 @@ static void run_test (void) { int32_t volumes[CHANNELS + PADDING]; int i, j, padding; pa_do_volume_func_t func; - struct timeval start, stop; + pa_usec_t start, stop; func = pa_get_volume_func (PA_SAMPLE_S16NE); @@ -278,21 +278,21 @@ static void run_test (void) { } } - pa_gettimeofday(&start); + start = pa_rtclock_now(); for (j = 0; j < TIMES; j++) { memcpy (samples, samples_orig, sizeof (samples)); pa_volume_s16ne_mmx (samples, volumes, CHANNELS, sizeof (samples)); } - pa_gettimeofday(&stop); - pa_log_info("MMX: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + stop = pa_rtclock_now(); + pa_log_info("MMX: %llu usec.", (long long unsigned int)(stop - start)); - pa_gettimeofday(&start); + start = pa_rtclock_now(); for (j = 0; j < TIMES; j++) { memcpy (samples_ref, samples_orig, sizeof (samples)); func (samples_ref, volumes, CHANNELS, sizeof (samples)); } - pa_gettimeofday(&stop); - pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + stop = pa_rtclock_now(); + pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start)); } #endif diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index b5e3687f..54af4a57 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -81,7 +81,7 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi /* the max number of samples we process at a time, this is also the max amount * we overread the volume array, which should have enough padding. */ - channels = MAX (8, channels); + channels = PA_MAX (8U, channels); __asm__ __volatile__ ( " xor %3, %3 \n\t" @@ -161,7 +161,7 @@ pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi /* the max number of samples we process at a time, this is also the max amount * we overread the volume array, which should have enough padding. */ - channels = MAX (8, channels); + channels = PA_MAX (8U, channels); __asm__ __volatile__ ( " xor %3, %3 \n\t" @@ -257,7 +257,7 @@ static void run_test (void) { int32_t volumes[CHANNELS + PADDING]; int i, j, padding; pa_do_volume_func_t func; - struct timeval start, stop; + pa_usec_t start, stop; func = pa_get_volume_func (PA_SAMPLE_S16NE); @@ -281,21 +281,21 @@ static void run_test (void) { } } - pa_gettimeofday(&start); + start = pa_rtclock_now(); for (j = 0; j < TIMES; j++) { memcpy (samples, samples_orig, sizeof (samples)); pa_volume_s16ne_sse (samples, volumes, CHANNELS, sizeof (samples)); } - pa_gettimeofday(&stop); - pa_log_info("SSE: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + stop = pa_rtclock_now(); + pa_log_info("SSE: %llu usec.", (long long unsigned int)(stop - start)); - pa_gettimeofday(&start); + start = pa_rtclock_now(); for (j = 0; j < TIMES; j++) { memcpy (samples_ref, samples_orig, sizeof (samples)); func (samples_ref, volumes, CHANNELS, sizeof (samples)); } - pa_gettimeofday(&stop); - pa_log_info("ref: %llu usec.", (long long unsigned int)pa_timeval_diff (&stop, &start)); + stop = pa_rtclock_now(); + pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start)); } #endif #endif /* defined (__i386__) || defined (__amd64__) */ -- cgit From c1b6a87b27b569cda135da05b53cc98aa9ca37cb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 13:40:27 +0200 Subject: alsa-sink: reduce the amount of smoother updates Exponentially increase the amount of time between smoother updates. We start with a 2ms interval and increase up to 200ms intervals. Smoother updates and the resulting linear regression take a fair amount of CPU so we want to reduce the amount of updates. --- src/modules/alsa/alsa-sink.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index e3707ae7..c3694729 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -68,6 +68,9 @@ #define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- Sleep at least 10ms on each iteration */ #define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms -- Wakeup at least this long before the buffer runs empty*/ +#define SMOOTHER_MIN_INTERVAL (2*PA_USEC_PER_MSEC) /* 2ms -- min smoother update interval */ +#define SMOOTHER_MAX_INTERVAL (200*PA_USEC_PER_MSEC) /* 200ms -- max smoother update inteval */ + #define VOLUME_ACCURACY (PA_VOLUME_NORM/100) /* don't require volume adjustments to be perfectly correct. don't necessarily extend granularity in software unless the differences get greater than this level */ struct userdata { @@ -115,6 +118,8 @@ struct userdata { pa_smoother *smoother; uint64_t write_count; uint64_t since_start; + pa_usec_t smoother_interval; + pa_usec_t last_smoother_update; pa_reserve_wrapper *reserve; pa_hook_slot *reserve_slot; @@ -723,17 +728,27 @@ static void update_smoother(struct userdata *u) { now1 = pa_timespec_load(&htstamp); } + /* Hmm, if the timestamp is 0, then it wasn't set and we take the current time */ + if (now1 <= 0) + now1 = pa_rtclock_now(); + + /* check if the time since the last update is bigger than the interval */ + if (u->last_smoother_update > 0) { + if (u->last_smoother_update + u->smoother_interval > now1) + return; + } + position = (int64_t) u->write_count - ((int64_t) delay * (int64_t) u->frame_size); if (PA_UNLIKELY(position < 0)) position = 0; - /* Hmm, if the timestamp is 0, then it wasn't set and we take the current time */ - if (now1 <= 0) - now1 = pa_rtclock_now(); - now2 = pa_bytes_to_usec((uint64_t) position, &u->sink->sample_spec); + u->last_smoother_update = now1; + /* exponentially increase the update interval up to the MAX limit */ + u->smoother_interval = PA_MIN (u->smoother_interval * 2, SMOOTHER_MAX_INTERVAL); + pa_smoother_put(u->smoother, now1, now2); } @@ -906,6 +921,8 @@ static int unsuspend(struct userdata *u) { u->write_count = 0; pa_smoother_reset(u->smoother, pa_rtclock_now(), TRUE); + u->smoother_interval = SMOOTHER_MIN_INTERVAL; + u->last_smoother_update = 0; u->first = TRUE; u->since_start = 0; @@ -1622,6 +1639,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca 5, pa_rtclock_now(), TRUE); + u->smoother_interval = SMOOTHER_MIN_INTERVAL; dev_id = pa_modargs_get_value( ma, "device_id", -- cgit From 05fef5f551ac7f295d2f2cb74642cb359be1b12d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 15:50:02 +0200 Subject: sconv: allow for setting custom functions Add methods to override the default conversion functions. --- src/pulsecore/sconv.c | 160 ++++++++++++++++++++++++++++++-------------------- src/pulsecore/sconv.h | 6 ++ 2 files changed, 102 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index 937bf5d1..d06d6985 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -184,98 +184,130 @@ static void alaw_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) { *b = st_13linear2alaw(*a >> 3); } +static pa_convert_func_t to_float32ne_table[] = { + [PA_SAMPLE_U8] = (pa_convert_func_t) u8_to_float32ne, + [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_to_float32ne, + [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_to_float32ne, + [PA_SAMPLE_S16LE] = (pa_convert_func_t) pa_sconv_s16le_to_float32ne, + [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_to_float32ne, + [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_to_float32ne, + [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_to_float32ne, + [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_to_float32ne, + [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_to_float32ne, + [PA_SAMPLE_S24_32LE] = (pa_convert_func_t) pa_sconv_s24_32le_to_float32ne, + [PA_SAMPLE_S24_32BE] = (pa_convert_func_t) pa_sconv_s24_32be_to_float32ne, + [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, + [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, +}; + pa_convert_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { - static const pa_convert_func_t table[] = { - [PA_SAMPLE_U8] = (pa_convert_func_t) u8_to_float32ne, - [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_to_float32ne, - [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_to_float32ne, - [PA_SAMPLE_S16LE] = (pa_convert_func_t) pa_sconv_s16le_to_float32ne, - [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_to_float32ne, - [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_to_float32ne, - [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_to_float32ne, - [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_to_float32ne, - [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_to_float32ne, - [PA_SAMPLE_S24_32LE] = (pa_convert_func_t) pa_sconv_s24_32le_to_float32ne, - [PA_SAMPLE_S24_32BE] = (pa_convert_func_t) pa_sconv_s24_32be_to_float32ne, - [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, - [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, - }; + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + return to_float32ne_table[f]; +} + +void pa_set_convert_to_float32ne_function(pa_sample_format_t f, pa_convert_func_t func) { pa_assert(f >= 0); pa_assert(f < PA_SAMPLE_MAX); - return table[f]; + to_float32ne_table[f] = func; } +static pa_convert_func_t from_float32ne_table[] = { + [PA_SAMPLE_U8] = (pa_convert_func_t) u8_from_float32ne, + [PA_SAMPLE_S16LE] = (pa_convert_func_t) pa_sconv_s16le_from_float32ne, + [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_from_float32ne, + [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_from_float32ne, + [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_from_float32ne, + [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_from_float32ne, + [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_from_float32ne, + [PA_SAMPLE_S24_32LE] = (pa_convert_func_t) pa_sconv_s24_32le_from_float32ne, + [PA_SAMPLE_S24_32BE] = (pa_convert_func_t) pa_sconv_s24_32be_from_float32ne, + [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, + [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, + [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_float32ne, + [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_from_float32ne +}; + pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { - static const pa_convert_func_t table[] = { - [PA_SAMPLE_U8] = (pa_convert_func_t) u8_from_float32ne, - [PA_SAMPLE_S16LE] = (pa_convert_func_t) pa_sconv_s16le_from_float32ne, - [PA_SAMPLE_S16BE] = (pa_convert_func_t) pa_sconv_s16be_from_float32ne, - [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_from_float32ne, - [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_from_float32ne, - [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_from_float32ne, - [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_from_float32ne, - [PA_SAMPLE_S24_32LE] = (pa_convert_func_t) pa_sconv_s24_32le_from_float32ne, - [PA_SAMPLE_S24_32BE] = (pa_convert_func_t) pa_sconv_s24_32be_from_float32ne, - [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne, - [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne, - [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_float32ne, - [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_from_float32ne - }; + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + return from_float32ne_table[f]; +} + +void pa_set_convert_from_float32ne_function(pa_sample_format_t f, pa_convert_func_t func) { pa_assert(f >= 0); pa_assert(f < PA_SAMPLE_MAX); - return table[f]; + from_float32ne_table[f] = func; } +static pa_convert_func_t to_s16ne_table[] = { + [PA_SAMPLE_U8] = (pa_convert_func_t) u8_to_s16ne, + [PA_SAMPLE_S16NE] = (pa_convert_func_t) s16ne_to_s16ne, + [PA_SAMPLE_S16RE] = (pa_convert_func_t) s16re_to_s16ne, + [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_to_s16ne, + [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_to_s16ne, + [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_to_s16ne, + [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_to_s16ne, + [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_to_s16ne, + [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_to_s16ne, + [PA_SAMPLE_S24_32BE] = (pa_convert_func_t) pa_sconv_s24_32be_to_s16ne, + [PA_SAMPLE_S24_32LE] = (pa_convert_func_t) pa_sconv_s24_32le_to_s16ne, + [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_to_s16ne, + [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_to_s16ne +}; + pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f) { - static const pa_convert_func_t table[] = { - [PA_SAMPLE_U8] = (pa_convert_func_t) u8_to_s16ne, - [PA_SAMPLE_S16NE] = (pa_convert_func_t) s16ne_to_s16ne, - [PA_SAMPLE_S16RE] = (pa_convert_func_t) s16re_to_s16ne, - [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_to_s16ne, - [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_to_s16ne, - [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_to_s16ne, - [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_to_s16ne, - [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_to_s16ne, - [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_to_s16ne, - [PA_SAMPLE_S24_32BE] = (pa_convert_func_t) pa_sconv_s24_32be_to_s16ne, - [PA_SAMPLE_S24_32LE] = (pa_convert_func_t) pa_sconv_s24_32le_to_s16ne, - [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_to_s16ne, - [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_to_s16ne - }; + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + return to_s16ne_table[f]; +} + +void pa_set_convert_to_s16ne_function(pa_sample_format_t f, pa_convert_func_t func) { pa_assert(f >= 0); pa_assert(f < PA_SAMPLE_MAX); - return table[f]; + to_s16ne_table[f] = func; } +static pa_convert_func_t from_s16ne_table[] = { + [PA_SAMPLE_U8] = (pa_convert_func_t) u8_from_s16ne, + [PA_SAMPLE_S16NE] = (pa_convert_func_t) s16ne_to_s16ne, + [PA_SAMPLE_S16RE] = (pa_convert_func_t) s16re_to_s16ne, + [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_from_s16ne, + [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_from_s16ne, + [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_from_s16ne, + [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_from_s16ne, + [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_from_s16ne, + [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_from_s16ne, + [PA_SAMPLE_S24_32BE] = (pa_convert_func_t) pa_sconv_s24_32be_from_s16ne, + [PA_SAMPLE_S24_32LE] = (pa_convert_func_t) pa_sconv_s24_32le_from_s16ne, + [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_s16ne, + [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_from_s16ne, +}; + pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f) { - static const pa_convert_func_t table[] = { - [PA_SAMPLE_U8] = (pa_convert_func_t) u8_from_s16ne, - [PA_SAMPLE_S16NE] = (pa_convert_func_t) s16ne_to_s16ne, - [PA_SAMPLE_S16RE] = (pa_convert_func_t) s16re_to_s16ne, - [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_from_s16ne, - [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_from_s16ne, - [PA_SAMPLE_S32BE] = (pa_convert_func_t) pa_sconv_s32be_from_s16ne, - [PA_SAMPLE_S32LE] = (pa_convert_func_t) pa_sconv_s32le_from_s16ne, - [PA_SAMPLE_S24BE] = (pa_convert_func_t) pa_sconv_s24be_from_s16ne, - [PA_SAMPLE_S24LE] = (pa_convert_func_t) pa_sconv_s24le_from_s16ne, - [PA_SAMPLE_S24_32BE] = (pa_convert_func_t) pa_sconv_s24_32be_from_s16ne, - [PA_SAMPLE_S24_32LE] = (pa_convert_func_t) pa_sconv_s24_32le_from_s16ne, - [PA_SAMPLE_ALAW] = (pa_convert_func_t) alaw_from_s16ne, - [PA_SAMPLE_ULAW] = (pa_convert_func_t) ulaw_from_s16ne, - }; + pa_assert(f >= 0); + pa_assert(f < PA_SAMPLE_MAX); + + return from_s16ne_table[f]; +} + +void pa_set_convert_from_s16ne_function(pa_sample_format_t f, pa_convert_func_t func) { pa_assert(f >= 0); pa_assert(f < PA_SAMPLE_MAX); - return table[f]; + from_s16ne_table[f] = func; } diff --git a/src/pulsecore/sconv.h b/src/pulsecore/sconv.h index b00a16a4..cd937559 100644 --- a/src/pulsecore/sconv.h +++ b/src/pulsecore/sconv.h @@ -33,4 +33,10 @@ pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) P pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f) PA_GCC_PURE; pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f) PA_GCC_PURE; +void pa_set_convert_to_float32ne_function(pa_sample_format_t f, pa_convert_func_t func); +void pa_set_convert_from_float32ne_function(pa_sample_format_t f, pa_convert_func_t func); + +void pa_set_convert_to_s16ne_function(pa_sample_format_t f, pa_convert_func_t func); +void pa_set_convert_from_s16ne_function(pa_sample_format_t f, pa_convert_func_t func); + #endif -- cgit From a3f4a4f6ba741a996442d7a80cc3e267fab705fb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 17:54:45 +0200 Subject: resamples; refactor the channel remapping bits Move the channel remapping bits into a separate structure. We'll make this structure global so that optimized versions can use it to perform the channel remapping. --- src/pulsecore/resampler.c | 186 ++++++++++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 5a6c398e..0d8ca010 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -44,10 +44,20 @@ /* Number of samples of extra space we allow the resamplers to return */ #define EXTRA_FRAMES 128 -typedef void (*pa_do_remap_func_t) (pa_resampler *r, void *d, const void *s, unsigned n); +typedef struct pa_remap pa_remap_t; -static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, unsigned n); -static void remap_mono_to_stereo(pa_resampler *r, void *dst, const void *src, unsigned n); +typedef void (*pa_do_remap_func_t) (pa_remap_t *m, void *d, const void *s, unsigned n); + +struct pa_remap { + pa_sample_format_t *format; + pa_sample_spec *i_ss, *o_ss; + float map_table_f[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + int32_t map_table_i[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + pa_do_remap_func_t do_remap; +}; + +static void remap_channels_matrix (pa_remap_t *m, void *dst, const void *src, unsigned n); +static void remap_mono_to_stereo(pa_remap_t *m, void *dst, const void *src, unsigned n); struct pa_resampler { pa_resample_method_t method; @@ -66,10 +76,8 @@ struct pa_resampler { pa_convert_func_t to_work_format_func; pa_convert_func_t from_work_format_func; - float map_table_f[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; - int32_t map_table_i[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + pa_remap_t remap; pa_bool_t map_required; - pa_do_remap_func_t do_remap; void (*impl_free)(pa_resampler *r); void (*impl_update_rates)(pa_resampler *r); @@ -218,6 +226,11 @@ pa_resampler* pa_resampler_new( r->i_ss = *a; r->o_ss = *b; + /* set up the remap structure */ + r->remap.i_ss = &r->i_ss; + r->remap.o_ss = &r->o_ss; + r->remap.format = &r->work_format; + if (am) r->i_cm = *am; else if (!pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels, PA_CHANNEL_MAP_DEFAULT)) @@ -584,33 +597,41 @@ static int front_rear_side(pa_channel_position_t p) { static void calc_map_table(pa_resampler *r) { unsigned oc, ic; + unsigned n_oc, n_ic; pa_bool_t ic_connected[PA_CHANNELS_MAX]; pa_bool_t remix; pa_strbuf *s; char *t; + pa_remap_t *m; pa_assert(r); if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || (!(r->flags & PA_RESAMPLER_NO_REMAP) && !pa_channel_map_equal(&r->i_cm, &r->o_cm))))) return; - memset(r->map_table_f, 0, sizeof(r->map_table_f)); - memset(r->map_table_i, 0, sizeof(r->map_table_i)); + m = &r->remap; + + n_oc = r->o_ss.channels; + n_ic = r->i_ss.channels; + + memset(m->map_table_f, 0, sizeof(m->map_table_f)); + memset(m->map_table_i, 0, sizeof(m->map_table_i)); + memset(ic_connected, 0, sizeof(ic_connected)); remix = (r->flags & (PA_RESAMPLER_NO_REMAP|PA_RESAMPLER_NO_REMIX)) == 0; - for (oc = 0; oc < r->o_ss.channels; oc++) { + for (oc = 0; oc < n_oc; oc++) { pa_bool_t oc_connected = FALSE; pa_channel_position_t b = r->o_cm.map[oc]; - for (ic = 0; ic < r->i_ss.channels; ic++) { + for (ic = 0; ic < n_ic; ic++) { pa_channel_position_t a = r->i_cm.map[ic]; if (r->flags & PA_RESAMPLER_NO_REMAP) { /* We shall not do any remapping. Hence, just check by index */ if (ic == oc) - r->map_table_f[oc][ic] = 1.0; + m->map_table_f[oc][ic] = 1.0; continue; } @@ -619,7 +640,7 @@ static void calc_map_table(pa_resampler *r) { /* We shall not do any remixing. Hence, just check by name */ if (a == b) - r->map_table_f[oc][ic] = 1.0; + m->map_table_f[oc][ic] = 1.0; continue; } @@ -694,7 +715,7 @@ static void calc_map_table(pa_resampler *r) { */ if (a == b || a == PA_CHANNEL_POSITION_MONO || b == PA_CHANNEL_POSITION_MONO) { - r->map_table_f[oc][ic] = 1.0; + m->map_table_f[oc][ic] = 1.0; oc_connected = TRUE; ic_connected[ic] = TRUE; @@ -712,14 +733,14 @@ static void calc_map_table(pa_resampler *r) { /* We are not connected and on the left side, let's * average all left side input channels. */ - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) if (on_left(r->i_cm.map[ic])) n++; if (n > 0) - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) if (on_left(r->i_cm.map[ic])) { - r->map_table_f[oc][ic] = 1.0f / (float) n; + m->map_table_f[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } @@ -733,14 +754,14 @@ static void calc_map_table(pa_resampler *r) { /* We are not connected and on the right side, let's * average all right side input channels. */ - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) if (on_right(r->i_cm.map[ic])) n++; if (n > 0) - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) if (on_right(r->i_cm.map[ic])) { - r->map_table_f[oc][ic] = 1.0f / (float) n; + m->map_table_f[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } @@ -754,14 +775,14 @@ static void calc_map_table(pa_resampler *r) { /* We are not connected and at the center. Let's * average all center input channels. */ - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) if (on_center(r->i_cm.map[ic])) n++; if (n > 0) { - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) if (on_center(r->i_cm.map[ic])) { - r->map_table_f[oc][ic] = 1.0f / (float) n; + m->map_table_f[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } } else { @@ -771,14 +792,14 @@ static void calc_map_table(pa_resampler *r) { n = 0; - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) n++; if (n > 0) - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) { - r->map_table_f[oc][ic] = 1.0f / (float) n; + m->map_table_f[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } @@ -792,12 +813,12 @@ static void calc_map_table(pa_resampler *r) { /* We are not connected and an LFE. Let's average all * channels for LFE. */ - for (ic = 0; ic < r->i_ss.channels; ic++) { + for (ic = 0; ic < n_ic; ic++) { if (!(r->flags & PA_RESAMPLER_NO_LFE)) - r->map_table_f[oc][ic] = 1.0f / (float) r->i_ss.channels; + m->map_table_f[oc][ic] = 1.0f / (float) n_ic; else - r->map_table_f[oc][ic] = 0; + m->map_table_f[oc][ic] = 0; /* Please note that a channel connected to LFE * doesn't really count as connected. */ @@ -813,7 +834,7 @@ static void calc_map_table(pa_resampler *r) { ic_unconnected_center = 0, ic_unconnected_lfe = 0; - for (ic = 0; ic < r->i_ss.channels; ic++) { + for (ic = 0; ic < n_ic; ic++) { pa_channel_position_t a = r->i_cm.map[ic]; if (ic_connected[ic]) @@ -836,20 +857,20 @@ static void calc_map_table(pa_resampler *r) { * the left side by .9 and add in our averaged unconnected * channels multplied by .1 */ - for (oc = 0; oc < r->o_ss.channels; oc++) { + for (oc = 0; oc < n_oc; oc++) { if (!on_left(r->o_cm.map[oc])) continue; - for (ic = 0; ic < r->i_ss.channels; ic++) { + for (ic = 0; ic < n_ic; ic++) { if (ic_connected[ic]) { - r->map_table_f[oc][ic] *= .9f; + m->map_table_f[oc][ic] *= .9f; continue; } if (on_left(r->i_cm.map[ic])) - r->map_table_f[oc][ic] = .1f / (float) ic_unconnected_left; + m->map_table_f[oc][ic] = .1f / (float) ic_unconnected_left; } } } @@ -861,20 +882,20 @@ static void calc_map_table(pa_resampler *r) { * the right side by .9 and add in our averaged unconnected * channels multplied by .1 */ - for (oc = 0; oc < r->o_ss.channels; oc++) { + for (oc = 0; oc < n_oc; oc++) { if (!on_right(r->o_cm.map[oc])) continue; - for (ic = 0; ic < r->i_ss.channels; ic++) { + for (ic = 0; ic < n_ic; ic++) { if (ic_connected[ic]) { - r->map_table_f[oc][ic] *= .9f; + m->map_table_f[oc][ic] *= .9f; continue; } if (on_right(r->i_cm.map[ic])) - r->map_table_f[oc][ic] = .1f / (float) ic_unconnected_right; + m->map_table_f[oc][ic] = .1f / (float) ic_unconnected_right; } } } @@ -887,20 +908,20 @@ static void calc_map_table(pa_resampler *r) { * the center side by .9 and add in our averaged unconnected * channels multplied by .1 */ - for (oc = 0; oc < r->o_ss.channels; oc++) { + for (oc = 0; oc < n_oc; oc++) { if (!on_center(r->o_cm.map[oc])) continue; - for (ic = 0; ic < r->i_ss.channels; ic++) { + for (ic = 0; ic < n_ic; ic++) { if (ic_connected[ic]) { - r->map_table_f[oc][ic] *= .9f; + m->map_table_f[oc][ic] *= .9f; continue; } if (on_center(r->i_cm.map[ic])) { - r->map_table_f[oc][ic] = .1f / (float) ic_unconnected_center; + m->map_table_f[oc][ic] = .1f / (float) ic_unconnected_center; mixed_in = TRUE; } } @@ -918,7 +939,7 @@ static void calc_map_table(pa_resampler *r) { it into left and right. Using .375 and 0.75 as factors. */ - for (ic = 0; ic < r->i_ss.channels; ic++) { + for (ic = 0; ic < n_ic; ic++) { if (ic_connected[ic]) continue; @@ -926,7 +947,7 @@ static void calc_map_table(pa_resampler *r) { if (!on_center(r->i_cm.map[ic])) continue; - for (oc = 0; oc < r->o_ss.channels; oc++) { + for (oc = 0; oc < n_oc; oc++) { if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc])) continue; @@ -937,7 +958,7 @@ static void calc_map_table(pa_resampler *r) { } } - for (oc = 0; oc < r->o_ss.channels; oc++) { + for (oc = 0; oc < n_oc; oc++) { if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc])) continue; @@ -947,7 +968,7 @@ static void calc_map_table(pa_resampler *r) { } } - for (oc = 0; oc < r->o_ss.channels; oc++) { + for (oc = 0; oc < n_oc; oc++) { if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc])) continue; @@ -955,10 +976,10 @@ static void calc_map_table(pa_resampler *r) { if (ncenter[oc] <= 0) continue; - for (ic = 0; ic < r->i_ss.channels; ic++) { + for (ic = 0; ic < n_ic; ic++) { if (ic_connected[ic]) { - r->map_table_f[oc][ic] *= .75f; + m->map_table_f[oc][ic] *= .75f; continue; } @@ -966,7 +987,7 @@ static void calc_map_table(pa_resampler *r) { continue; if (!found_frs[ic] || front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc])) - r->map_table_f[oc][ic] = .375f / (float) ncenter[oc]; + m->map_table_f[oc][ic] = .375f / (float) ncenter[oc]; } } } @@ -977,37 +998,37 @@ static void calc_map_table(pa_resampler *r) { /* OK, so there is an unconnected LFE channel. Let's mix * it into all channels, with factor 0.375 */ - for (ic = 0; ic < r->i_ss.channels; ic++) { + for (ic = 0; ic < n_ic; ic++) { if (!on_lfe(r->i_cm.map[ic])) continue; - for (oc = 0; oc < r->o_ss.channels; oc++) - r->map_table_f[oc][ic] = 0.375f / (float) ic_unconnected_lfe; + for (oc = 0; oc < n_oc; oc++) + m->map_table_f[oc][ic] = 0.375f / (float) ic_unconnected_lfe; } } } /* make an 16:16 int version of the matrix */ - for (oc = 0; oc < r->o_ss.channels; oc++) - for (ic = 0; ic < r->i_ss.channels; ic++) - r->map_table_i[oc][ic] = (int32_t) (r->map_table_f[oc][ic] * 0x10000); + for (oc = 0; oc < n_oc; oc++) + for (ic = 0; ic < n_ic; ic++) + m->map_table_i[oc][ic] = (int32_t) (m->map_table_f[oc][ic] * 0x10000); s = pa_strbuf_new(); pa_strbuf_printf(s, " "); - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) pa_strbuf_printf(s, " I%02u ", ic); pa_strbuf_puts(s, "\n +"); - for (ic = 0; ic < r->i_ss.channels; ic++) + for (ic = 0; ic < n_ic; ic++) pa_strbuf_printf(s, "------"); pa_strbuf_puts(s, "\n"); - for (oc = 0; oc < r->o_ss.channels; oc++) { + for (oc = 0; oc < n_oc; oc++) { pa_strbuf_printf(s, "O%02u |", oc); - for (ic = 0; ic < r->i_ss.channels; ic++) - pa_strbuf_printf(s, " %1.3f", r->map_table_f[oc][ic]); + for (ic = 0; ic < n_ic; ic++) + pa_strbuf_printf(s, " %1.3f", m->map_table_f[oc][ic]); pa_strbuf_puts(s, "\n"); } @@ -1016,13 +1037,13 @@ static void calc_map_table(pa_resampler *r) { pa_xfree(t); /* find some common channel remappings, fall back to full matrix operation. */ - if (r->i_ss.channels == 1 && r->o_ss.channels == 2 && - r->map_table_f[0][0] >= 1.0 && r->map_table_f[1][0] >= 1.0) { - r->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo;; - pa_log_debug("Using mono to stereo remapping"); + if (n_ic == 1 && n_oc == 2 && + m->map_table_f[0][0] >= 1.0 && m->map_table_f[1][0] >= 1.0) { + m->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo;; + pa_log_info("Using mono to stereo remapping"); } else { - r->do_remap = (pa_do_remap_func_t) remap_channels_matrix; - pa_log_debug("Using generic matrix remapping"); + m->do_remap = (pa_do_remap_func_t) remap_channels_matrix; + pa_log_info("Using generic matrix remapping"); } } @@ -1064,10 +1085,10 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) return &r->buf1; } -static void remap_mono_to_stereo(pa_resampler *r, void *dst, const void *src, unsigned n) { +static void remap_mono_to_stereo(pa_remap_t *m, void *dst, const void *src, unsigned n) { unsigned i; - switch (r->work_format) { + switch (*m->format) { case PA_SAMPLE_FLOAT32NE: { float *d, *s; @@ -1117,27 +1138,26 @@ static void remap_mono_to_stereo(pa_resampler *r, void *dst, const void *src, un } } -static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, unsigned n) { - unsigned oc, i; +static void remap_channels_matrix (pa_remap_t *m, void *dst, const void *src, unsigned n) { + unsigned oc, ic, i; unsigned n_ic, n_oc; - n_ic = r->i_ss.channels; - n_oc = r->o_ss.channels; + n_ic = m->i_ss->channels; + n_oc = m->o_ss->channels; - memset(dst, 0, r->buf2.length); - - switch (r->work_format) { + switch (*m->format) { case PA_SAMPLE_FLOAT32NE: { float *d, *s; + memset(dst, 0, n * sizeof (float) * n_oc); + for (oc = 0; oc < n_oc; oc++) { - unsigned ic; for (ic = 0; ic < n_ic; ic++) { float vol; - vol = r->map_table_f[oc][ic]; + vol = m->map_table_f[oc][ic]; if (vol <= 0.0) continue; @@ -1161,13 +1181,14 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, { int16_t *d, *s; + memset(dst, 0, n * sizeof (int16_t) * n_oc); + for (oc = 0; oc < n_oc; oc++) { - unsigned ic; for (ic = 0; ic < n_ic; ic++) { int32_t vol; - vol = r->map_table_i[oc][ic]; + vol = m->map_table_i[oc][ic]; if (vol <= 0) continue; @@ -1181,7 +1202,7 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, } else { for (i = n; i > 0; i--, s += n_ic, d += n_oc) *d += (int16_t) (((int32_t)*s * vol) >> 16); - } + } } } break; @@ -1194,6 +1215,7 @@ static void remap_channels_matrix (pa_resampler *r, void *dst, const void *src, static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { unsigned in_n_samples, out_n_samples, n_frames; void *src, *dst; + pa_remap_t *remap; pa_assert(r); pa_assert(input); @@ -1222,8 +1244,10 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { src = ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); dst = pa_memblock_acquire(r->buf2.memblock); - pa_assert (r->do_remap); - r->do_remap (r, dst, src, n_frames); + remap = &r->remap; + + pa_assert (remap->do_remap); + remap->do_remap (remap, dst, src, n_frames); pa_memblock_release(input->memblock); pa_memblock_release(r->buf2.memblock); -- cgit From ac1f2e0a2e0707636aabd48baa57c124a877f834 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 18:23:42 +0200 Subject: remap: move remapping code in separate file Move the remapping code into a separate file. Have functions to install custom init functions that can install optimized versions, when they want. --- src/Makefile.am | 1 + src/pulsecore/remap.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/remap.h | 48 +++++++++++ src/pulsecore/resampler.c | 155 +----------------------------------- 4 files changed, 249 insertions(+), 152 deletions(-) create mode 100644 src/pulsecore/remap.c create mode 100644 src/pulsecore/remap.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index eca68b16..b818c3e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -822,6 +822,7 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/object.c pulsecore/object.h \ pulsecore/play-memblockq.c pulsecore/play-memblockq.h \ pulsecore/play-memchunk.c pulsecore/play-memchunk.h \ + pulsecore/remap.c pulsecore/remap.h \ pulsecore/resampler.c pulsecore/resampler.h \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ pulsecore/sample-util.c pulsecore/sample-util.h \ diff --git a/src/pulsecore/remap.c b/src/pulsecore/remap.c new file mode 100644 index 00000000..2e93afce --- /dev/null +++ b/src/pulsecore/remap.c @@ -0,0 +1,197 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include "remap.h" + +static void remap_mono_to_stereo_c (pa_remap_t *m, void *dst, const void *src, unsigned n) { + unsigned i; + + switch (*m->format) { + case PA_SAMPLE_FLOAT32NE: + { + float *d, *s; + + d = (float *) dst; + s = (float *) src; + + for (i = n >> 2; i; i--) { + d[0] = d[1] = s[0]; + d[2] = d[3] = s[1]; + d[4] = d[5] = s[2]; + d[6] = d[7] = s[3]; + s += 4; + d += 8; + } + for (i = n & 3; i; i--) { + d[0] = d[1] = s[0]; + s++; + d += 2; + } + break; + } + case PA_SAMPLE_S16NE: + { + int16_t *d, *s; + + d = (int16_t *) dst; + s = (int16_t *) src; + + for (i = n >> 2; i; i--) { + d[0] = d[1] = s[0]; + d[2] = d[3] = s[1]; + d[4] = d[5] = s[2]; + d[6] = d[7] = s[3]; + s += 4; + d += 8; + } + for (i = n & 3; i; i--) { + d[0] = d[1] = s[0]; + s++; + d += 2; + } + break; + } + default: + pa_assert_not_reached(); + } +} + +static void remap_channels_matrix_c (pa_remap_t *m, void *dst, const void *src, unsigned n) { + unsigned oc, ic, i; + unsigned n_ic, n_oc; + + n_ic = m->i_ss->channels; + n_oc = m->o_ss->channels; + + switch (*m->format) { + case PA_SAMPLE_FLOAT32NE: + { + float *d, *s; + + memset(dst, 0, n * sizeof (float) * n_oc); + + for (oc = 0; oc < n_oc; oc++) { + + for (ic = 0; ic < n_ic; ic++) { + float vol; + + vol = m->map_table_f[oc][ic]; + + if (vol <= 0.0) + continue; + + d = (float *)dst + oc; + s = (float *)src + ic; + + if (vol >= 1.0) { + for (i = n; i > 0; i--, s += n_ic, d += n_oc) + *d += *s; + } else { + for (i = n; i > 0; i--, s += n_ic, d += n_oc) + *d += *s * vol; + } + } + } + + break; + } + case PA_SAMPLE_S16NE: + { + int16_t *d, *s; + + memset(dst, 0, n * sizeof (int16_t) * n_oc); + + for (oc = 0; oc < n_oc; oc++) { + + for (ic = 0; ic < n_ic; ic++) { + int32_t vol; + + vol = m->map_table_i[oc][ic]; + + if (vol <= 0) + continue; + + d = (int16_t *)dst + oc; + s = (int16_t *)src + ic; + + if (vol >= 0x10000) { + for (i = n; i > 0; i--, s += n_ic, d += n_oc) + *d += *s; + } else { + for (i = n; i > 0; i--, s += n_ic, d += n_oc) + *d += (int16_t) (((int32_t)*s * vol) >> 16); + } + } + } + break; + } + default: + pa_assert_not_reached(); + } +} + +/* set the function that will execute the remapping based on the matrices */ +static void init_remap_c (pa_remap_t *m) { + unsigned n_oc, n_ic; + + n_oc = m->o_ss->channels; + n_ic = m->i_ss->channels; + + /* find some common channel remappings, fall back to full matrix operation. */ + if (n_ic == 1 && n_oc == 2 && + m->map_table_f[0][0] >= 1.0 && m->map_table_f[1][0] >= 1.0) { + m->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo_c; + pa_log_info("Using mono to stereo remapping"); + } else { + m->do_remap = (pa_do_remap_func_t) remap_channels_matrix_c; + pa_log_info("Using generic matrix remapping"); + } +} + + +/* default C implementation */ +static pa_init_remap_func_t remap_func = init_remap_c; + +void pa_init_remap (pa_remap_t *m) { + pa_assert (remap_func); + + /* just call the installed remap init functions */ + remap_func (m); +} + +pa_init_remap_func_t pa_get_init_remap_func(void) { + return remap_func; +} + +void pa_set_init_remap_func(pa_init_remap_func_t func) { + remap_func = func; +} diff --git a/src/pulsecore/remap.h b/src/pulsecore/remap.h new file mode 100644 index 00000000..32a67cdd --- /dev/null +++ b/src/pulsecore/remap.h @@ -0,0 +1,48 @@ +#ifndef fooremapfoo +#define fooremapfoo + +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +typedef struct pa_remap pa_remap_t; + +typedef void (*pa_do_remap_func_t) (pa_remap_t *m, void *d, const void *s, unsigned n); + +struct pa_remap { + pa_sample_format_t *format; + pa_sample_spec *i_ss, *o_ss; + float map_table_f[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + int32_t map_table_i[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + pa_do_remap_func_t do_remap; +}; + +void pa_init_remap (pa_remap_t *m); + +/* custom installation of init functions */ +typedef void (*pa_init_remap_func_t) (pa_remap_t *m); + +pa_init_remap_func_t pa_get_init_remap_func(void); +void pa_set_init_remap_func(pa_init_remap_func_t func); + +#endif /* fooremapfoo */ diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 0d8ca010..f1bfa156 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -40,25 +40,11 @@ #include "ffmpeg/avcodec.h" #include "resampler.h" +#include "remap.h" /* Number of samples of extra space we allow the resamplers to return */ #define EXTRA_FRAMES 128 -typedef struct pa_remap pa_remap_t; - -typedef void (*pa_do_remap_func_t) (pa_remap_t *m, void *d, const void *s, unsigned n); - -struct pa_remap { - pa_sample_format_t *format; - pa_sample_spec *i_ss, *o_ss; - float map_table_f[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; - int32_t map_table_i[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; - pa_do_remap_func_t do_remap; -}; - -static void remap_channels_matrix (pa_remap_t *m, void *dst, const void *src, unsigned n); -static void remap_mono_to_stereo(pa_remap_t *m, void *dst, const void *src, unsigned n); - struct pa_resampler { pa_resample_method_t method; pa_resample_flags_t flags; @@ -1036,16 +1022,8 @@ static void calc_map_table(pa_resampler *r) { pa_log_debug("Channel matrix:\n%s", t = pa_strbuf_tostring_free(s)); pa_xfree(t); - /* find some common channel remappings, fall back to full matrix operation. */ - if (n_ic == 1 && n_oc == 2 && - m->map_table_f[0][0] >= 1.0 && m->map_table_f[1][0] >= 1.0) { - m->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo;; - pa_log_info("Using mono to stereo remapping"); - } else { - m->do_remap = (pa_do_remap_func_t) remap_channels_matrix; - pa_log_info("Using generic matrix remapping"); - } - + /* initialize the remapping function */ + pa_init_remap (m); } static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) { @@ -1085,133 +1063,6 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) return &r->buf1; } -static void remap_mono_to_stereo(pa_remap_t *m, void *dst, const void *src, unsigned n) { - unsigned i; - - switch (*m->format) { - case PA_SAMPLE_FLOAT32NE: - { - float *d, *s; - - d = (float *) dst; - s = (float *) src; - - for (i = n >> 2; i; i--) { - d[0] = d[1] = s[0]; - d[2] = d[3] = s[1]; - d[4] = d[5] = s[2]; - d[6] = d[7] = s[3]; - s += 4; - d += 8; - } - for (i = n & 3; i; i--) { - d[0] = d[1] = s[0]; - s++; - d += 2; - } - break; - } - case PA_SAMPLE_S16NE: - { - int16_t *d, *s; - - d = (int16_t *) dst; - s = (int16_t *) src; - - for (i = n >> 2; i; i--) { - d[0] = d[1] = s[0]; - d[2] = d[3] = s[1]; - d[4] = d[5] = s[2]; - d[6] = d[7] = s[3]; - s += 4; - d += 8; - } - for (i = n & 3; i; i--) { - d[0] = d[1] = s[0]; - s++; - d += 2; - } - break; - } - default: - pa_assert_not_reached(); - } -} - -static void remap_channels_matrix (pa_remap_t *m, void *dst, const void *src, unsigned n) { - unsigned oc, ic, i; - unsigned n_ic, n_oc; - - n_ic = m->i_ss->channels; - n_oc = m->o_ss->channels; - - switch (*m->format) { - case PA_SAMPLE_FLOAT32NE: - { - float *d, *s; - - memset(dst, 0, n * sizeof (float) * n_oc); - - for (oc = 0; oc < n_oc; oc++) { - - for (ic = 0; ic < n_ic; ic++) { - float vol; - - vol = m->map_table_f[oc][ic]; - - if (vol <= 0.0) - continue; - - d = (float *)dst + oc; - s = (float *)src + ic; - - if (vol >= 1.0) { - for (i = n; i > 0; i--, s += n_ic, d += n_oc) - *d += *s; - } else { - for (i = n; i > 0; i--, s += n_ic, d += n_oc) - *d += *s * vol; - } - } - } - - break; - } - case PA_SAMPLE_S16NE: - { - int16_t *d, *s; - - memset(dst, 0, n * sizeof (int16_t) * n_oc); - - for (oc = 0; oc < n_oc; oc++) { - - for (ic = 0; ic < n_ic; ic++) { - int32_t vol; - - vol = m->map_table_i[oc][ic]; - - if (vol <= 0) - continue; - - d = (int16_t *)dst + oc; - s = (int16_t *)src + ic; - - if (vol >= 0x10000) { - for (i = n; i > 0; i--, s += n_ic, d += n_oc) - *d += *s; - } else { - for (i = n; i > 0; i--, s += n_ic, d += n_oc) - *d += (int16_t) (((int32_t)*s * vol) >> 16); - } - } - } - break; - } - default: - pa_assert_not_reached(); - } -} - static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { unsigned in_n_samples, out_n_samples, n_frames; void *src, *dst; -- cgit From 28baa53d55fa51d5fbbb1be54db3581fc3d151dd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 18:29:02 +0200 Subject: remap: allow specialisations to install NULL Fallback to the default C implementation when the remap init function did not set a function. --- src/pulsecore/remap.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/pulsecore/remap.c b/src/pulsecore/remap.c index 2e93afce..108df900 100644 --- a/src/pulsecore/remap.c +++ b/src/pulsecore/remap.c @@ -186,6 +186,11 @@ void pa_init_remap (pa_remap_t *m) { /* just call the installed remap init functions */ remap_func (m); + + if (m->do_remap == NULL) { + /* nothing was installed, fallback to C versions */ + init_remap_c (m); + } } pa_init_remap_func_t pa_get_init_remap_func(void) { -- cgit From e961efc130481ff4c5a053eb03dd3ec4d513c615 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 18:32:51 +0200 Subject: remap: init the do_remap function to NULL --- src/pulsecore/remap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/remap.c b/src/pulsecore/remap.c index 108df900..a0fc85b9 100644 --- a/src/pulsecore/remap.c +++ b/src/pulsecore/remap.c @@ -184,11 +184,13 @@ static pa_init_remap_func_t remap_func = init_remap_c; void pa_init_remap (pa_remap_t *m) { pa_assert (remap_func); - /* just call the installed remap init functions */ + m->do_remap = NULL; + + /* call the installed remap init function */ remap_func (m); if (m->do_remap == NULL) { - /* nothing was installed, fallback to C versions */ + /* nothing was installed, fallback to C version */ init_remap_c (m); } } -- cgit From 6e5dbed51ee508759ed8b5adabc998ba8faf4774 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 19:46:06 +0200 Subject: remap: add MMX mono to stereo --- src/Makefile.am | 1 + src/pulsecore/cpu-x86.c | 4 +- src/pulsecore/cpu-x86.h | 2 + src/pulsecore/remap_mmx.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 src/pulsecore/remap_mmx.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index b818c3e7..ab91be83 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -823,6 +823,7 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/play-memblockq.c pulsecore/play-memblockq.h \ pulsecore/play-memchunk.c pulsecore/play-memchunk.h \ pulsecore/remap.c pulsecore/remap.h \ + pulsecore/remap_mmx.c \ pulsecore/resampler.c pulsecore/resampler.h \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ pulsecore/sample-util.c pulsecore/sample-util.h \ diff --git a/src/pulsecore/cpu-x86.c b/src/pulsecore/cpu-x86.c index 0457199d..bc093ec0 100644 --- a/src/pulsecore/cpu-x86.c +++ b/src/pulsecore/cpu-x86.c @@ -110,8 +110,10 @@ void pa_cpu_init_x86 (void) { (flags & PA_CPU_X86_3DNOWEXT) ? "3DNOWEXT " : ""); /* activate various optimisations */ - if (flags & PA_CPU_X86_MMX) + if (flags & PA_CPU_X86_MMX) { pa_volume_func_init_mmx (flags); + pa_remap_func_init_mmx (flags); + } if (flags & PA_CPU_X86_SSE) pa_volume_func_init_sse (flags); diff --git a/src/pulsecore/cpu-x86.h b/src/pulsecore/cpu-x86.h index 07e630ea..b11ef6ea 100644 --- a/src/pulsecore/cpu-x86.h +++ b/src/pulsecore/cpu-x86.h @@ -63,4 +63,6 @@ typedef int64_t pa_reg_x86; void pa_volume_func_init_mmx(pa_cpu_x86_flag_t flags); void pa_volume_func_init_sse(pa_cpu_x86_flag_t flags); +void pa_remap_func_init_mmx(pa_cpu_x86_flag_t flags); + #endif /* foocpux86hfoo */ diff --git a/src/pulsecore/remap_mmx.c b/src/pulsecore/remap_mmx.c new file mode 100644 index 00000000..6690cfa4 --- /dev/null +++ b/src/pulsecore/remap_mmx.c @@ -0,0 +1,174 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include "cpu-x86.h" +#include "remap.h" + +#define LOAD_SAMPLES \ + " movq (%1), %%mm0 \n\t" \ + " movq 8(%1), %%mm2 \n\t" \ + " movq 16(%1), %%mm4 \n\t" \ + " movq 24(%1), %%mm6 \n\t" \ + " movq %%mm0, %%mm1 \n\t" \ + " movq %%mm2, %%mm3 \n\t" \ + " movq %%mm4, %%mm5 \n\t" \ + " movq %%mm6, %%mm7 \n\t" + +#define UNPACK_SAMPLES(s) \ + " punpckl"#s" %%mm0, %%mm0 \n\t" \ + " punpckh"#s" %%mm1, %%mm1 \n\t" \ + " punpckl"#s" %%mm2, %%mm2 \n\t" \ + " punpckh"#s" %%mm3, %%mm3 \n\t" \ + " punpckl"#s" %%mm4, %%mm4 \n\t" \ + " punpckh"#s" %%mm5, %%mm5 \n\t" \ + " punpckl"#s" %%mm6, %%mm6 \n\t" \ + " punpckh"#s" %%mm7, %%mm7 \n\t" \ + +#define STORE_SAMPLES \ + " movq %%mm0, (%0) \n\t" \ + " movq %%mm1, 8(%0) \n\t" \ + " movq %%mm2, 16(%0) \n\t" \ + " movq %%mm3, 24(%0) \n\t" \ + " movq %%mm4, 32(%0) \n\t" \ + " movq %%mm5, 40(%0) \n\t" \ + " movq %%mm6, 48(%0) \n\t" \ + " movq %%mm7, 56(%0) \n\t" \ + " add $32, %1 \n\t" \ + " add $64, %0 \n\t" + +#define HANDLE_SINGLE(s) \ + " movd (%1), %%mm0 \n\t" \ + " movq %%mm0, %%mm1 \n\t" \ + " punpckl"#s" %%mm0, %%mm0 \n\t" \ + " movq %%mm0, (%0) \n\t" \ + " add $4, %1 \n\t" \ + " add $8, %0 \n\t" + +static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src, unsigned n) { + pa_reg_x86 temp; + + switch (*m->format) { + case PA_SAMPLE_FLOAT32NE: + { + __asm__ __volatile__ ( + " mov %3, %2 \n\t" + " sar $3, %2 \n\t" /* prepare for processing 8 samples at a time */ + " cmp $0, %2 \n\t" + " je 2f \n\t" + + "1: \n\t" /* do samples in groups of 8 */ + LOAD_SAMPLES + UNPACK_SAMPLES(dq) + STORE_SAMPLES + " dec %2 \n\t" + " jne 1b \n\t" + + "2: \n\t" + " mov %3, %2 \n\t" + " and $7, %2 \n\t" /* prepare for processing the remaining samples */ + " je 4f \n\t" + + "3: \n\t" + HANDLE_SINGLE(dq) + " dec %2 \n\t" + " jne 3b \n\t" + + "4: \n\t" + " emms \n\t" + + : "+r" (dst), "+r" (src), "=&r" (temp) + : "r" ((pa_reg_x86)n) + : "cc" + ); + break; + } + case PA_SAMPLE_S16NE: + { + __asm__ __volatile__ ( + " mov %3, %2 \n\t" + " sar $3, %2 \n\t" /* prepare for processing 8 samples at a time */ + " cmp $0, %2 \n\t" + " je 2f \n\t" + + "1: \n\t" /* do samples in groups of 16 */ + LOAD_SAMPLES + UNPACK_SAMPLES(wd) + STORE_SAMPLES + " dec %2 \n\t" + " jne 1b \n\t" + + "2: \n\t" + " mov %3, %2 \n\t" + " and $7, %2 \n\t" /* prepare for processing the remaining samples */ + " je 4f \n\t" + + "3: \n\t" + HANDLE_SINGLE(wd) + " dec %2 \n\t" + " jne 3b \n\t" + + "4: \n\t" + " emms \n\t" + + : "+r" (dst), "+r" (src), "=&r" (temp) + : "r" ((pa_reg_x86)n) + : "cc" + ); + break; + } + default: + pa_assert_not_reached(); + } +} + +/* set the function that will execute the remapping based on the matrices */ +static void init_remap_mmx (pa_remap_t *m) { + unsigned n_oc, n_ic; + + n_oc = m->o_ss->channels; + n_ic = m->i_ss->channels; + + /* find some common channel remappings, fall back to full matrix operation. */ + if (n_ic == 1 && n_oc == 2 && + m->map_table_f[0][0] >= 1.0 && m->map_table_f[1][0] >= 1.0) { + m->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo_mmx; + pa_log_info("Using MMX mono to stereo remapping"); + } +} + +void pa_remap_func_init_mmx (pa_cpu_x86_flag_t flags) { +#if defined (__i386__) || defined (__amd64__) + pa_log_info("Initialising MMX optimized remappers."); + + pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_mmx); +#endif /* defined (__i386__) || defined (__amd64__) */ +} -- cgit From 6076cef2092391d8b46aa84f86857cffebce4583 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Aug 2009 20:00:50 +0200 Subject: remap: make the MMX code pretier --- src/pulsecore/remap_mmx.c | 74 +++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/pulsecore/remap_mmx.c b/src/pulsecore/remap_mmx.c index 6690cfa4..bfcae6c5 100644 --- a/src/pulsecore/remap_mmx.c +++ b/src/pulsecore/remap_mmx.c @@ -73,6 +73,28 @@ " add $4, %1 \n\t" \ " add $8, %0 \n\t" +#define MONO_TO_STEREO(s) \ + " mov %3, %2 \n\t" \ + " sar $3, %2 \n\t" \ + " cmp $0, %2 \n\t" \ + " je 2f \n\t" \ + "1: \n\t" \ + LOAD_SAMPLES \ + UNPACK_SAMPLES(s) \ + STORE_SAMPLES \ + " dec %2 \n\t" \ + " jne 1b \n\t" \ + "2: \n\t" \ + " mov %3, %2 \n\t" \ + " and $7, %2 \n\t" \ + " je 4f \n\t" \ + "3: \n\t" \ + HANDLE_SINGLE(s) \ + " dec %2 \n\t" \ + " jne 3b \n\t" \ + "4: \n\t" \ + " emms \n\t" + static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src, unsigned n) { pa_reg_x86 temp; @@ -80,31 +102,7 @@ static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src, case PA_SAMPLE_FLOAT32NE: { __asm__ __volatile__ ( - " mov %3, %2 \n\t" - " sar $3, %2 \n\t" /* prepare for processing 8 samples at a time */ - " cmp $0, %2 \n\t" - " je 2f \n\t" - - "1: \n\t" /* do samples in groups of 8 */ - LOAD_SAMPLES - UNPACK_SAMPLES(dq) - STORE_SAMPLES - " dec %2 \n\t" - " jne 1b \n\t" - - "2: \n\t" - " mov %3, %2 \n\t" - " and $7, %2 \n\t" /* prepare for processing the remaining samples */ - " je 4f \n\t" - - "3: \n\t" - HANDLE_SINGLE(dq) - " dec %2 \n\t" - " jne 3b \n\t" - - "4: \n\t" - " emms \n\t" - + MONO_TO_STEREO(dq) /* do doubles to quads */ : "+r" (dst), "+r" (src), "=&r" (temp) : "r" ((pa_reg_x86)n) : "cc" @@ -114,31 +112,7 @@ static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src, case PA_SAMPLE_S16NE: { __asm__ __volatile__ ( - " mov %3, %2 \n\t" - " sar $3, %2 \n\t" /* prepare for processing 8 samples at a time */ - " cmp $0, %2 \n\t" - " je 2f \n\t" - - "1: \n\t" /* do samples in groups of 16 */ - LOAD_SAMPLES - UNPACK_SAMPLES(wd) - STORE_SAMPLES - " dec %2 \n\t" - " jne 1b \n\t" - - "2: \n\t" - " mov %3, %2 \n\t" - " and $7, %2 \n\t" /* prepare for processing the remaining samples */ - " je 4f \n\t" - - "3: \n\t" - HANDLE_SINGLE(wd) - " dec %2 \n\t" - " jne 3b \n\t" - - "4: \n\t" - " emms \n\t" - + MONO_TO_STEREO(wd) /* do words to doubles */ : "+r" (dst), "+r" (src), "=&r" (temp) : "r" ((pa_reg_x86)n) : "cc" -- cgit From 9f97b7cbe13b3a4f0fefd8588a3dec95f0d14e58 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 02:56:17 +0200 Subject: sink-input: add callbacks that are called whenever the mute/volume changes --- src/pulsecore/sink-input.c | 16 +++++++++++++++- src/pulsecore/sink-input.h | 12 ++++++++++-- src/pulsecore/sink.c | 16 +++++++++++++--- 3 files changed, 38 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index a29334f9..975fda01 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -126,6 +126,8 @@ static void reset_callbacks(pa_sink_input *i) { i->state_change = NULL; i->may_move_to = NULL; i->send_event = NULL; + i->volume_changed = NULL; + i->mute_changed = NULL; } /* Called from main context */ @@ -968,7 +970,10 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0); } - /* The virtual volume changed, let's tell people so */ + /* The volume changed, let's tell people so */ + if (i->volume_changed) + i->volume_changed(i); + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } @@ -999,6 +1004,11 @@ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) { i->save_muted = save; pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0); + + /* The mute status changed, let's tell people so */ + if (i->mute_changed) + i->mute_changed(i); + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } @@ -1263,6 +1273,10 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { /* Notify everyone */ pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], i); + + if (i->volume_changed) + i->volume_changed(i); + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); return 0; diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index ea0f8c0e..5285e618 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -192,8 +192,16 @@ struct pa_sink_input { pa_bool_t (*may_move_to) (pa_sink_input *i, pa_sink *s); /* may be NULL */ /* If non-NULL this function is used to dispatch asynchronous - * control events. */ - void (*send_event)(pa_sink_input *i, const char *event, pa_proplist* data); + * control events. Called from main context. */ + void (*send_event)(pa_sink_input *i, const char *event, pa_proplist* data); /* may be NULL */ + + /* If non-NULL this function is called whenever the sink input + * volume changes. Called from main context */ + void (*volume_changed)(pa_sink_input *i); /* may be NULL */ + + /* If non-NULL this function is called whenever the sink input + * mute status changes. Called from main context */ + void (*mute_changed)(pa_sink_input *i); /* may be NULL */ struct { pa_sink_input_state_t state; diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 1cce8e6b..fab88755 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1380,9 +1380,14 @@ static void propagate_reference_volume(pa_sink *s) { pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map); pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio); - /* The reference volume changed, let's tell people so */ - if (!pa_cvolume_equal(&old_volume, &i->volume)) + /* The volume changed, let's tell people so */ + if (!pa_cvolume_equal(&old_volume, &i->volume)) { + + if (i->volume_changed) + i->volume_changed(i); + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + } } } @@ -1522,8 +1527,13 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume) pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio); /* Notify if something changed */ - if (!pa_cvolume_equal(&old_volume, &i->volume)) + if (!pa_cvolume_equal(&old_volume, &i->volume)) { + + if (i->volume_changed) + i->volume_changed(i); + pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + } } } -- cgit From a562978509674f37f3cc7d5d5d1002f52a59654d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 02:59:26 +0200 Subject: ladspa: forward volume changes from ladspa sink to stream and hence via flat volume logic to master sink --- src/modules/module-ladspa-sink.c | 72 +++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index f2d53d00..233f90c4 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -99,7 +99,7 @@ static const char* const valid_modargs[] = { }; /* Called from I/O thread context */ -static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { +static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { @@ -130,7 +130,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse } /* Called from main context */ -static int sink_set_state(pa_sink *s, pa_sink_state_t state) { +static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) { struct userdata *u; pa_sink_assert_ref(s); @@ -145,7 +145,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) { } /* Called from I/O thread context */ -static void sink_request_rewind(pa_sink *s) { +static void sink_request_rewind_cb(pa_sink *s) { struct userdata *u; pa_sink_assert_ref(s); @@ -160,7 +160,7 @@ static void sink_request_rewind(pa_sink *s) { } /* Called from I/O thread context */ -static void sink_update_requested_latency(pa_sink *s) { +static void sink_update_requested_latency_cb(pa_sink *s) { struct userdata *u; pa_sink_assert_ref(s); @@ -176,6 +176,34 @@ static void sink_update_requested_latency(pa_sink *s) { pa_sink_get_requested_latency_within_thread(s)); } +/* Called from main context */ +static void sink_set_volume_cb(pa_sink *s) { + struct userdata *u; + + pa_sink_assert_ref(s); + pa_assert_se(u = s->userdata); + + if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) || + !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input))) + return; + + pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, TRUE); +} + +/* Called from main context */ +static void sink_set_mute_cb(pa_sink *s) { + struct userdata *u; + + pa_sink_assert_ref(s); + pa_assert_se(u = s->userdata); + + if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) || + !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input))) + return; + + pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted); +} + /* Called from I/O thread context */ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) { struct userdata *u; @@ -394,6 +422,26 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); } +/* Called from main context */ +static void sink_input_volume_changed_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_volume_changed(u->sink, &i->volume); +} + +/* Called from main context */ +static void sink_input_mute_changed_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + pa_sink_mute_changed(u->sink, i->muted); +} + int pa__init(pa_module*m) { struct userdata *u; pa_sample_spec ss; @@ -731,7 +779,9 @@ int pa__init(pa_module*m) { goto fail; } - u->sink = pa_sink_new(m->core, &sink_data, master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY)); + u->sink = pa_sink_new(m->core, &sink_data, + PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME| + (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))); pa_sink_new_data_done(&sink_data); if (!u->sink) { @@ -739,10 +789,12 @@ int pa__init(pa_module*m) { goto fail; } - u->sink->parent.process_msg = sink_process_msg; - u->sink->set_state = sink_set_state; - u->sink->update_requested_latency = sink_update_requested_latency; - u->sink->request_rewind = sink_request_rewind; + u->sink->parent.process_msg = sink_process_msg_cb; + u->sink->set_state = sink_set_state_cb; + u->sink->update_requested_latency = sink_update_requested_latency_cb; + u->sink->request_rewind = sink_request_rewind_cb; + u->sink->set_volume = sink_set_volume_cb; + u->sink->set_mute = sink_set_mute_cb; u->sink->userdata = u; pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq); @@ -775,6 +827,8 @@ int pa__init(pa_module*m) { u->sink_input->state_change = sink_input_state_change_cb; u->sink_input->may_move_to = sink_input_may_move_to_cb; u->sink_input->moving = sink_input_moving_cb; + u->sink_input->volume_changed = sink_input_volume_changed_cb; + u->sink_input->mute_changed = sink_input_mute_changed_cb; u->sink_input->userdata = u; pa_sink_put(u->sink); -- cgit From 8a2a6b2004cd299467de1955f7f99e25033faa63 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 03:43:53 +0200 Subject: adjust various data/library paths automatically if we are run from a build tree --- src/Makefile.am | 5 +++-- src/daemon/daemon-conf.c | 20 ++++++++++++++++++-- src/daemon/main.c | 2 ++ src/modules/alsa/alsa-mixer.c | 16 +++++++++++++--- src/pulsecore/core-util.c | 19 +++++++++++++++++++ src/pulsecore/core-util.h | 4 ++++ 6 files changed, 59 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 17011cd3..fd440991 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -74,6 +74,7 @@ AM_CFLAGS = \ $(LIBSAMPLERATE_CFLAGS) \ $(LIBSNDFILE_CFLAGS) \ $(LIBSPEEX_CFLAGS) \ + -DPA_BUILDDIR=\"$(abs_builddir)\" \ -DPA_DLSEARCHPATH=\"$(modlibexecdir)\" \ -DPA_DEFAULT_CONFIG_DIR=\"$(PA_DEFAULT_CONFIG_DIR)\" \ -DPA_BINARY=\"$(PA_BINARY)\" \ @@ -83,8 +84,8 @@ AM_CFLAGS = \ -DAO_REQUIRE_CAS \ -DPULSE_LOCALEDIR=\"$(pulselocaledir)\" \ -DPA_MACHINE_ID=\"$(localstatedir)/lib/dbus/machine-id\" \ - -DPA_ALSA_PATHS_DIR=\"$(alsapathsdir)\" \ - -DPA_ALSA_PROFILE_SETS_DIR=\"$(alsaprofilesetsdir)\" + -DPA_ALSA_PATHS_DIR=\"$(alsapathsdir)\" \ + -DPA_ALSA_PROFILE_SETS_DIR=\"$(alsaprofilesetsdir)\" AM_LIBADD = $(PTHREAD_LIBS) $(INTLLIBS) AM_LDADD = $(PTHREAD_LIBS) $(INTLLIBS) diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index 9a87b555..ec1ec5ce 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -133,9 +133,25 @@ static const pa_daemon_conf default_conf = { }; pa_daemon_conf* pa_daemon_conf_new(void) { - pa_daemon_conf *c = pa_xnewdup(pa_daemon_conf, &default_conf, 1); + pa_daemon_conf *c; + + c = pa_xnewdup(pa_daemon_conf, &default_conf, 1); + +#if defined(__linux__) && !defined(__OPTIMIZE__) + + /* We abuse __OPTIMIZE__ as a check whether we are a debug build + * or not. If we are and are run from the build tree then we + * override the search path to point to our build tree */ + + if (pa_run_from_build_tree()) { + pa_log_notice("Detected that we are run from the build tree, fixing search path."); + c->dl_search_path = pa_xstrdup(PA_BUILDDIR "/.libs/"); + + } else + +#endif + c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH); - c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH); return c; } diff --git a/src/daemon/main.c b/src/daemon/main.c index 8521e720..72984590 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -774,6 +774,8 @@ int main(int argc, char *argv[]) { pa_log_info(_("Using state directory %s."), s); pa_xfree(s); + pa_log_info(_("Using modules directory %s."), conf->dl_search_path); + pa_log_info(_("Running in system mode: %s"), pa_yes_no(pa_in_system_mode())); if (pa_in_system_mode()) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index a4c2ee0f..61c92cd0 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -929,7 +929,7 @@ static int element_zero_volume(pa_alsa_element *e, snd_mixer_t *m) { int pa_alsa_path_select(pa_alsa_path *p, snd_mixer_t *m) { pa_alsa_element *e; - int r; + int r = 0; pa_assert(m); pa_assert(p); @@ -1849,7 +1849,12 @@ pa_alsa_path* pa_alsa_path_new(const char *fname, pa_alsa_direction_t direction) items[1].data = &p->description; items[2].data = &p->name; - fn = pa_maybe_prefix_path(fname, PA_ALSA_PATHS_DIR); + fn = pa_maybe_prefix_path(fname, +#if defined(__linux__) && !defined(__OPTIMIZE__) + pa_run_from_build_tree() ? PA_BUILDDIR "/modules/alsa/mixer/paths/" : +#endif + PA_ALSA_PATHS_DIR); + r = pa_config_parse(fn, NULL, items, p); pa_xfree(fn); @@ -3110,7 +3115,12 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel if (!fname) fname = "default.conf"; - fn = pa_maybe_prefix_path(fname, PA_ALSA_PROFILE_SETS_DIR); + fn = pa_maybe_prefix_path(fname, +#if defined(__linux__) && !defined(__OPTIMIZE__) + pa_run_from_build_tree() ? PA_BUILDDIR "/modules/alsa/mixer/profile-sets/" : +#endif + PA_ALSA_PROFILE_SETS_DIR); + r = pa_config_parse(fn, NULL, items, ps); pa_xfree(fn); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index ef8c8472..843c8377 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2862,3 +2862,22 @@ void pa_reset_personality(void) { #endif } + +#if defined(__linux__) && !defined(__OPTIMIZE__) + +pa_bool_t pa_run_from_build_tree(void) { + char *rp; + pa_bool_t b = FALSE; + + /* We abuse __OPTIMIZE__ as a check whether we are a debug build + * or not. */ + + if ((rp = pa_readlink("/proc/self/exe"))) { + b = pa_startswith(rp, PA_BUILDDIR); + pa_xfree(rp); + } + + return b; +} + +#endif diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 3d3aec71..2551f794 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -243,4 +243,8 @@ size_t pa_pipe_buf(int fd); void pa_reset_personality(void); +#if defined(__linux__) && !defined(__OPTIMIZE__) +pa_bool_t pa_run_from_build_tree(void); +#endif + #endif -- cgit From ac056191410b67466b429720778fe87279d9912a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 03:45:17 +0200 Subject: combine: quieten gcc a bit --- src/modules/module-combine.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 582cbce1..e90ef11c 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -1161,6 +1161,8 @@ int pa__init(pa_module*m) { pa_channel_map slaves_map; pa_bool_t is_first_slave = TRUE; + pa_sample_spec_init(&slaves_spec); + while ((n = pa_split(slaves, ",", &split_state))) { pa_sink *slave_sink; -- cgit From fe9a577cf2799c0864a05a08c785161ba3738d88 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 03:45:58 +0200 Subject: alsa: leave headphone jack enabled in normal mixer paths --- src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf | 7 +++++-- src/modules/alsa/mixer/paths/analog-output-mono.conf | 7 +++++-- src/modules/alsa/mixer/paths/analog-output.conf | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf b/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf index 2db976a5..3457d4a2 100644 --- a/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf +++ b/src/modules/alsa/mixer/paths/analog-output-lfe-on-mono.conf @@ -41,9 +41,12 @@ volume = merge override-map.1 = lfe override-map.2 = lfe,lfe +; This profile path is intended to control the speaker, not the +; headphones. But it should not hurt if we leave the headphone jack +; enabled nonetheless. [Element Headphone] -switch = off -volume = off +switch = mute +volume = zero [Element Speaker] switch = mute diff --git a/src/modules/alsa/mixer/paths/analog-output-mono.conf b/src/modules/alsa/mixer/paths/analog-output-mono.conf index a58cc970..dc270cfe 100644 --- a/src/modules/alsa/mixer/paths/analog-output-mono.conf +++ b/src/modules/alsa/mixer/paths/analog-output-mono.conf @@ -38,9 +38,12 @@ volume = merge override-map.1 = all override-map.2 = all-left,all-right +; This profile path is intended to control the speaker, not the +; headphones. But it should not hurt if we leave the headphone jack +; enabled nonetheless. [Element Headphone] -switch = off -volume = off +switch = mute +volume = zero [Element Speaker] switch = mute diff --git a/src/modules/alsa/mixer/paths/analog-output.conf b/src/modules/alsa/mixer/paths/analog-output.conf index b412a437..f71a05a1 100644 --- a/src/modules/alsa/mixer/paths/analog-output.conf +++ b/src/modules/alsa/mixer/paths/analog-output.conf @@ -37,9 +37,12 @@ override-map.2 = all-left,all-right switch = off volume = off +; This profile path is intended to control the speaker, not the +; headphones. But it should not hurt if we leave the headphone jack +; enabled nonetheless. [Element Headphone] -switch = off -volume = off +switch = mute +volume = zero [Element Speaker] switch = mute -- cgit From 5317e35543ab208a416cc662e2a6a88899a96704 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 14:55:05 +0200 Subject: udev: when a device appears that we cannot access right-away try again later on inotify --- src/modules/module-udev-detect.c | 91 +++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index 0b30fd54..22ce8c3c 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -47,6 +47,7 @@ struct device { char *path; pa_bool_t accessible; char *card_name; + char *args; uint32_t module; }; @@ -78,6 +79,7 @@ static void device_free(struct device *d) { pa_xfree(d->path); pa_xfree(d->card_name); + pa_xfree(d->args); pa_xfree(d); } @@ -103,22 +105,43 @@ static void verify_access(struct userdata *u, struct device *d) { pa_assert(u); pa_assert(d); - if (!(card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD))) - return; - cd = pa_sprintf_malloc("%s/snd/controlC%s", udev_get_dev_path(u->udev), path_get_card_id(d->path)); - d->accessible = access(cd, W_OK) >= 0; - pa_log_info("%s is accessible: %s", cd, pa_yes_no(d->accessible)); + d->accessible = access(cd, R_OK|W_OK) >= 0; pa_xfree(cd); - pa_card_suspend(card, !d->accessible, PA_SUSPEND_SESSION); + pa_log_info("%s is accessible: %s", cd, pa_yes_no(d->accessible)); + + if (d->module == PA_INVALID_INDEX) { + + /* If we not loaded, try to load */ + + if (d->accessible) { + pa_module *m; + + pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args); + m = pa_module_load(u->core, "module-alsa-card", d->args); + + if (m) { + d->module = m->index; + pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name); + } else + pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name); + } + + } else { + + /* If we are already loaded update suspend status with + * accessible boolean */ + + if ((card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD))) + pa_card_suspend(card, !d->accessible, PA_SUSPEND_SESSION); + } } static void card_changed(struct userdata *u, struct udev_device *dev) { struct device *d; const char *path; const char *t; - char *card_name, *args; pa_module *m; char *n; @@ -135,44 +158,41 @@ static void card_changed(struct userdata *u, struct udev_device *dev) { return; } + d = pa_xnew0(struct device, 1); + d->path = pa_xstrdup(path); + d->accessible = TRUE; + d->module = PA_INVALID_INDEX; + if (!(t = udev_device_get_property_value(dev, "PULSE_NAME"))) if (!(t = udev_device_get_property_value(dev, "ID_ID"))) if (!(t = udev_device_get_property_value(dev, "ID_PATH"))) t = path_get_card_id(path); n = pa_namereg_make_valid_name(t); + d->card_name = pa_sprintf_malloc("alsa_card.%s", n); + d->args = pa_sprintf_malloc("device_id=\"%s\" " + "name=\"%s\" " + "card_name=\"%s\" " + "tsched=%s " + "ignore_dB=%s " + "card_properties=\"module-udev-detect.discovered=1\"", + path_get_card_id(path), + n, + d->card_name, + pa_yes_no(u->use_tsched), + pa_yes_no(u->ignore_dB)); + pa_xfree(n); - card_name = pa_sprintf_malloc("alsa_card.%s", n); - args = pa_sprintf_malloc("device_id=\"%s\" " - "name=\"%s\" " - "card_name=\"%s\" " - "tsched=%s " - "ignore_dB=%s " - "card_properties=\"module-udev-detect.discovered=1\"", - path_get_card_id(path), - n, - card_name, - pa_yes_no(u->use_tsched), - pa_yes_no(u->ignore_dB)); - - pa_log_debug("Loading module-alsa-card with arguments '%s'", args); - m = pa_module_load(u->core, "module-alsa-card", args); - pa_xfree(args); + pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args); + m = pa_module_load(u->core, "module-alsa-card", d->args); if (m) { - pa_log_info("Card %s (%s) added.", path, n); - - d = pa_xnew(struct device, 1); - d->path = pa_xstrdup(path); - d->card_name = card_name; d->module = m->index; - d->accessible = TRUE; - - pa_hashmap_put(u->devices, d->path, d); + pa_log_info("Card %s (%s) added and module loaded.", path, d->card_name); } else - pa_xfree(card_name); + pa_log_info("Card %s (%s) added but failed to load module.", path, d->card_name); - pa_xfree(n); + pa_hashmap_put(u->devices, d->path, d); } static void remove_card(struct userdata *u, struct udev_device *dev) { @@ -185,7 +205,10 @@ static void remove_card(struct userdata *u, struct udev_device *dev) { return; pa_log_info("Card %s removed.", d->path); - pa_module_unload_request_by_index(u->core, d->module, TRUE); + + if (d->module != PA_INVALID_INDEX) + pa_module_unload_request_by_index(u->core, d->module, TRUE); + device_free(d); } -- cgit From 9abc010c930999eed67253f5b83f7c226b1a17f6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 21:27:44 +0200 Subject: object: speed up type verification by not relying on strcmp() Instead of using string contents for type identification use the address of a constant string array. This should speed up type verifications a little sind we only need to compare one machine word instead of a full string. Also, this saves a few strings. To make clear that types must be compared via address and not string contents 'type_name' is now called 'type_id'. This also simplifies the macros for declaring and defining public and private subclasses. --- src/pulsecore/core.c | 2 +- src/pulsecore/core.h | 2 +- src/pulsecore/msgobject.c | 14 +++++------ src/pulsecore/msgobject.h | 8 +++--- src/pulsecore/object.c | 18 ++++++++------ src/pulsecore/object.h | 51 ++++++++++++++++++++++++++------------- src/pulsecore/play-memblockq.c | 3 +-- src/pulsecore/protocol-esound.c | 3 +-- src/pulsecore/protocol-native.c | 15 ++++-------- src/pulsecore/protocol-simple.c | 3 +-- src/pulsecore/sink-input.c | 2 +- src/pulsecore/sink-input.h | 2 +- src/pulsecore/sink.c | 2 +- src/pulsecore/sink.h | 2 +- src/pulsecore/sound-file-stream.c | 3 +-- src/pulsecore/source-output.c | 2 +- src/pulsecore/source-output.h | 2 +- src/pulsecore/source.c | 2 +- src/pulsecore/source.h | 2 +- 19 files changed, 73 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index f5eb8352..f0726453 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -47,7 +47,7 @@ #include "core.h" -static PA_DEFINE_CHECK_TYPE(pa_core, pa_msgobject); +PA_DEFINE_PUBLIC_CLASS(pa_core, pa_msgobject); static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { pa_core *c = PA_CORE(o); diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index f6ec7122..c1002f93 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -165,7 +165,7 @@ struct pa_core { pa_hook hooks[PA_CORE_HOOK_MAX]; }; -PA_DECLARE_CLASS(pa_core); +PA_DECLARE_PUBLIC_CLASS(pa_core); #define PA_CORE(o) pa_core_cast(o) enum { diff --git a/src/pulsecore/msgobject.c b/src/pulsecore/msgobject.c index 6a2a612d..075a28c5 100644 --- a/src/pulsecore/msgobject.c +++ b/src/pulsecore/msgobject.c @@ -26,22 +26,22 @@ #include "msgobject.h" -PA_DEFINE_CHECK_TYPE(pa_msgobject, pa_object); +PA_DEFINE_PUBLIC_CLASS(pa_msgobject, pa_object); -pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)) { +pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_id, pa_bool_t (*check_type)(const char *type_name)) { pa_msgobject *o; pa_assert(size > sizeof(pa_msgobject)); - pa_assert(type_name); + pa_assert(type_id); if (!check_type) check_type = pa_msgobject_check_type; - pa_assert(check_type(type_name)); - pa_assert(check_type("pa_object")); - pa_assert(check_type("pa_msgobject")); + pa_assert(check_type(type_id)); + pa_assert(check_type(pa_object_type_id)); + pa_assert(check_type(pa_msgobject_type_id)); - o = PA_MSGOBJECT(pa_object_new_internal(size, type_name, check_type)); + o = PA_MSGOBJECT(pa_object_new_internal(size, type_id, check_type)); o->process_msg = NULL; return o; } diff --git a/src/pulsecore/msgobject.h b/src/pulsecore/msgobject.h index a35a23b5..ee0ec1ed 100644 --- a/src/pulsecore/msgobject.h +++ b/src/pulsecore/msgobject.h @@ -38,15 +38,13 @@ struct pa_msgobject { int (*process_msg)(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); }; -pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)); +pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_id, pa_bool_t (*check_type)(const char *type_name)); -int pa_msgobject_check_type(const char *type); - -#define pa_msgobject_new(type) ((type*) pa_msgobject_new_internal(sizeof(type), #type, type##_check_type)) +#define pa_msgobject_new(type) ((type*) pa_msgobject_new_internal(sizeof(type), type##_type_id, type##_check_type)) #define pa_msgobject_free ((void (*) (pa_msgobject* o)) pa_object_free) #define PA_MSGOBJECT(o) pa_msgobject_cast(o) -PA_DECLARE_CLASS(pa_msgobject); +PA_DECLARE_PUBLIC_CLASS(pa_msgobject); #endif diff --git a/src/pulsecore/object.c b/src/pulsecore/object.c index f3ead9c5..099d50d9 100644 --- a/src/pulsecore/object.c +++ b/src/pulsecore/object.c @@ -28,21 +28,23 @@ #include "object.h" -pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)) { +const char pa_object_type_id[] = "pa_object"; + +pa_object *pa_object_new_internal(size_t size, const char *type_id, pa_bool_t (*check_type)(const char *type_id)) { pa_object *o; pa_assert(size > sizeof(pa_object)); - pa_assert(type_name); + pa_assert(type_id); if (!check_type) check_type = pa_object_check_type; - pa_assert(check_type(type_name)); - pa_assert(check_type("pa_object")); + pa_assert(check_type(type_id)); + pa_assert(check_type(pa_object_type_id)); o = pa_xmalloc(size); PA_REFCNT_INIT(o); - o->type_name = type_name; + o->type_id = type_id; o->free = pa_object_free; o->check_type = check_type; @@ -65,8 +67,8 @@ void pa_object_unref(pa_object *o) { } } -int pa_object_check_type(const char *type_name) { - pa_assert(type_name); +pa_bool_t pa_object_check_type(const char *type_id) { + pa_assert(type_id); - return pa_streq(type_name, "pa_object"); + return type_id == pa_object_type_id; } diff --git a/src/pulsecore/object.h b/src/pulsecore/object.h index 43e79327..4c120cd5 100644 --- a/src/pulsecore/object.h +++ b/src/pulsecore/object.h @@ -34,21 +34,23 @@ typedef struct pa_object pa_object; struct pa_object { PA_REFCNT_DECLARE; - const char *type_name; + const char *type_id; void (*free)(pa_object *o); - int (*check_type)(const char *type_name); + pa_bool_t (*check_type)(const char *type_name); }; -pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)); -#define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), #type, type##_check_type) +pa_object *pa_object_new_internal(size_t size, const char *type_id, pa_bool_t (*check_type)(const char *type_id)); +#define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), type##_type_id, type##_check_type) #define pa_object_free ((void (*) (pa_object* _obj)) pa_xfree) -int pa_object_check_type(const char *type); +pa_bool_t pa_object_check_type(const char *type_id); -static inline int pa_object_isinstance(void *o) { +extern const char pa_object_type_id[]; + +static inline pa_bool_t pa_object_isinstance(void *o) { pa_object *obj = (pa_object*) o; - return obj ? obj->check_type("pa_object") : 0; + return obj ? obj->check_type(pa_object_type_id) : TRUE; } pa_object *pa_object_ref(pa_object *o); @@ -60,7 +62,7 @@ static inline int pa_object_refcnt(pa_object *o) { static inline pa_object* pa_object_cast(void *o) { pa_object *obj = (pa_object*) o; - pa_assert(!obj || obj->check_type("pa_object")); + pa_assert(!obj || obj->check_type(pa_object_type_id)); return obj; } @@ -68,10 +70,10 @@ static inline pa_object* pa_object_cast(void *o) { #define PA_OBJECT(o) pa_object_cast(o) -#define PA_DECLARE_CLASS(c) \ - static inline int c##_isinstance(void *o) { \ +#define PA_DECLARE_CLASS_COMMON(c) \ + static inline pa_bool_t c##_isinstance(void *o) { \ pa_object *obj = (pa_object*) o; \ - return obj ? obj->check_type(#c) : 1; \ + return obj ? obj->check_type(c##_type_id) : TRUE; \ } \ static inline c* c##_cast(void *o) { \ pa_assert(c##_isinstance(o)); \ @@ -91,12 +93,27 @@ static inline pa_object* pa_object_cast(void *o) { } \ struct __stupid_useless_struct_to_allow_trailing_semicolon -#define PA_DEFINE_CHECK_TYPE(c, parent) \ - int c##_check_type(const char *type) { \ - pa_assert(type); \ - if (strcmp(type, #c) == 0) \ - return 1; \ - return parent##_check_type(type); \ +#define PA_DECLARE_PUBLIC_CLASS(c) \ + extern const char c##_type_id[]; \ + PA_DECLARE_CLASS_COMMON(c); \ + pa_bool_t c##_check_type(const char *type_id) + +#define PA_DEFINE_PUBLIC_CLASS(c, parent) \ + const char c##_type_id[] = #c; \ + pa_bool_t c##_check_type(const char *type_id) { \ + if (type_id == c##_type_id) \ + return TRUE; \ + return parent##_check_type(type_id); \ + } \ + struct __stupid_useless_struct_to_allow_trailing_semicolon + +#define PA_DEFINE_PRIVATE_CLASS(c, parent) \ + static const char c##_type_id[] = #c; \ + PA_DECLARE_CLASS_COMMON(c); \ + static pa_bool_t c##_check_type(const char *type_id) { \ + if (type_id == c##_type_id) \ + return TRUE; \ + return parent##_check_type(type_id); \ } \ struct __stupid_useless_struct_to_allow_trailing_semicolon diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index fceb2ca1..b0d76993 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -47,9 +47,8 @@ enum { MEMBLOCKQ_STREAM_MESSAGE_UNLINK, }; -PA_DECLARE_CLASS(memblockq_stream); +PA_DEFINE_PRIVATE_CLASS(memblockq_stream, pa_msgobject); #define MEMBLOCKQ_STREAM(o) (memblockq_stream_cast(o)) -static PA_DEFINE_CHECK_TYPE(memblockq_stream, pa_msgobject); static void memblockq_stream_unlink(memblockq_stream *u) { pa_assert(u); diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index f64552aa..cfbaee6f 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -120,9 +120,8 @@ typedef struct connection { pa_time_event *auth_timeout_event; } connection; -PA_DECLARE_CLASS(connection); +PA_DEFINE_PRIVATE_CLASS(connection, pa_msgobject); #define CONNECTION(o) (connection_cast(o)) -static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject); struct pa_esound_protocol { PA_REFCNT_DECLARE; diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index b1285e15..6678d847 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -98,17 +98,15 @@ typedef struct record_stream { pa_usec_t current_source_latency; } record_stream; -PA_DECLARE_CLASS(record_stream); #define RECORD_STREAM(o) (record_stream_cast(o)) -static PA_DEFINE_CHECK_TYPE(record_stream, pa_msgobject); +PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject); typedef struct output_stream { pa_msgobject parent; } output_stream; -PA_DECLARE_CLASS(output_stream); #define OUTPUT_STREAM(o) (output_stream_cast(o)) -static PA_DEFINE_CHECK_TYPE(output_stream, pa_msgobject); +PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject); typedef struct playback_stream { output_stream parent; @@ -138,9 +136,8 @@ typedef struct playback_stream { uint64_t playing_for, underrun_for; } playback_stream; -PA_DECLARE_CLASS(playback_stream); #define PLAYBACK_STREAM(o) (playback_stream_cast(o)) -static PA_DEFINE_CHECK_TYPE(playback_stream, output_stream); +PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream); typedef struct upload_stream { output_stream parent; @@ -156,9 +153,8 @@ typedef struct upload_stream { pa_proplist *proplist; } upload_stream; -PA_DECLARE_CLASS(upload_stream); #define UPLOAD_STREAM(o) (upload_stream_cast(o)) -static PA_DEFINE_CHECK_TYPE(upload_stream, output_stream); +PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream); struct pa_native_connection { pa_msgobject parent; @@ -176,9 +172,8 @@ struct pa_native_connection { pa_time_event *auth_timeout_event; }; -PA_DECLARE_CLASS(pa_native_connection); #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o)) -static PA_DEFINE_CHECK_TYPE(pa_native_connection, pa_msgobject); +PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject); struct pa_native_protocol { PA_REFCNT_DECLARE; diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 776d74b6..95ec6ac8 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -69,9 +69,8 @@ typedef struct connection { } playback; } connection; -PA_DECLARE_CLASS(connection); +PA_DEFINE_PRIVATE_CLASS(connection, pa_msgobject); #define CONNECTION(o) (connection_cast(o)) -static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject); struct pa_simple_protocol { PA_REFCNT_DECLARE; diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 975fda01..4137a425 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -44,7 +44,7 @@ #define MEMBLOCKQ_MAXLENGTH (32*1024*1024) #define CONVERT_BUFFER_LENGTH (PA_PAGE_SIZE) -static PA_DEFINE_CHECK_TYPE(pa_sink_input, pa_msgobject); +PA_DEFINE_PUBLIC_CLASS(pa_sink_input, pa_msgobject); static void sink_input_free(pa_object *o); static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 5285e618..fe6cf75c 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -235,7 +235,7 @@ struct pa_sink_input { void *userdata; }; -PA_DECLARE_CLASS(pa_sink_input); +PA_DECLARE_PUBLIC_CLASS(pa_sink_input); #define PA_SINK_INPUT(o) pa_sink_input_cast(o) enum { diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index fab88755..5cec7747 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -52,7 +52,7 @@ #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC) #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC) -static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject); +PA_DEFINE_PUBLIC_CLASS(pa_sink, pa_msgobject); static void sink_free(pa_object *s); diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 936d1c2a..b5284b71 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -191,7 +191,7 @@ struct pa_sink { void *userdata; }; -PA_DECLARE_CLASS(pa_sink); +PA_DECLARE_PUBLIC_CLASS(pa_sink); #define PA_SINK(s) (pa_sink_cast(s)) typedef enum pa_sink_message { diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 502e5c69..f41c53f3 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -64,9 +64,8 @@ enum { FILE_STREAM_MESSAGE_UNLINK }; -PA_DECLARE_CLASS(file_stream); +PA_DEFINE_PRIVATE_CLASS(file_stream, pa_msgobject); #define FILE_STREAM(o) (file_stream_cast(o)) -static PA_DEFINE_CHECK_TYPE(file_stream, pa_msgobject); /* Called from main context */ static void file_stream_unlink(file_stream *u) { diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 3803a6cc..b0298616 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -41,7 +41,7 @@ #define MEMBLOCKQ_MAXLENGTH (32*1024*1024) -static PA_DEFINE_CHECK_TYPE(pa_source_output, pa_msgobject); +PA_DEFINE_PUBLIC_CLASS(pa_source_output, pa_msgobject); static void source_output_free(pa_object* mo); diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index a70a3fdb..aca9ddf2 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -182,7 +182,7 @@ struct pa_source_output { void *userdata; }; -PA_DECLARE_CLASS(pa_source_output); +PA_DECLARE_PUBLIC_CLASS(pa_source_output); #define PA_SOURCE_OUTPUT(o) pa_source_output_cast(o) enum { diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 8aa07f5e..3026654e 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -46,7 +46,7 @@ #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC) #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC) -static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject); +PA_DEFINE_PUBLIC_CLASS(pa_source, pa_msgobject); static void source_free(pa_object *o); diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 7b3e4953..df3f99df 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -158,7 +158,7 @@ struct pa_source { void *userdata; }; -PA_DECLARE_CLASS(pa_source); +PA_DECLARE_PUBLIC_CLASS(pa_source); #define PA_SOURCE(s) pa_source_cast(s) typedef enum pa_source_message { -- cgit From 14c27c7ade403683e06705e45b9a3df28102a909 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 22:05:27 +0200 Subject: gconf: use correct path for gconf-helper tool when running from build tree --- src/modules/gconf/module-gconf.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/modules/gconf/module-gconf.c b/src/modules/gconf/module-gconf.c index c01ebbf6..85523b39 100644 --- a/src/modules/gconf/module-gconf.c +++ b/src/modules/gconf/module-gconf.c @@ -52,9 +52,6 @@ PA_MODULE_LOAD_ONCE(TRUE); #define MAX_MODULES 10 #define BUF_MAX 2048 -/* #undef PA_GCONF_HELPER */ -/* #define PA_GCONF_HELPER "/home/lennart/projects/pulseaudio/src/gconf-helper" */ - struct module_item { char *name; char *args; @@ -343,7 +340,11 @@ int pa__init(pa_module*m) { u->io_event = NULL; u->buf_fill = 0; - if ((u->fd = pa_start_child_for_read(PA_GCONF_HELPER, NULL, &u->pid)) < 0) + if ((u->fd = pa_start_child_for_read( +#if defined(__linux__) && !defined(__OPTIMIZE__) + pa_run_from_build_tree() ? PA_BUILDDIR "/.libs/gconf-helper" : +#endif + PA_GCONF_HELPER, NULL, &u->pid)) < 0) goto fail; u->io_event = m->core->mainloop->io_new( -- cgit From d06680afe88d14a46ce8a4541d43d514a225732f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 22:06:23 +0200 Subject: udev: always verify access before loading modules --- src/modules/module-udev-detect.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index 22ce8c3c..2c7e7dc3 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -142,7 +142,6 @@ static void card_changed(struct userdata *u, struct udev_device *dev) { struct device *d; const char *path; const char *t; - pa_module *m; char *n; pa_assert(u); @@ -183,16 +182,9 @@ static void card_changed(struct userdata *u, struct udev_device *dev) { pa_yes_no(u->ignore_dB)); pa_xfree(n); - pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args); - m = pa_module_load(u->core, "module-alsa-card", d->args); - - if (m) { - d->module = m->index; - pa_log_info("Card %s (%s) added and module loaded.", path, d->card_name); - } else - pa_log_info("Card %s (%s) added but failed to load module.", path, d->card_name); - pa_hashmap_put(u->devices, d->path, d); + + verify_access(u, d); } static void remove_card(struct userdata *u, struct udev_device *dev) { @@ -472,7 +464,7 @@ int pa__init(pa_module *m) { udev_enumerate_unref(enumerate); - pa_log_info("Loaded %u modules.", pa_hashmap_size(u->devices)); + pa_log_info("Found %u cards.", pa_hashmap_size(u->devices)); pa_modargs_free(ma); -- cgit From 4ec701aa21c51a0a0c1dd60bd94ee4af1c1d1343 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 22:11:38 +0200 Subject: udev: don't access string after free() --- src/modules/module-udev-detect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index 2c7e7dc3..f2e7b0df 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -107,9 +107,9 @@ static void verify_access(struct userdata *u, struct device *d) { cd = pa_sprintf_malloc("%s/snd/controlC%s", udev_get_dev_path(u->udev), path_get_card_id(d->path)); d->accessible = access(cd, R_OK|W_OK) >= 0; - pa_xfree(cd); pa_log_info("%s is accessible: %s", cd, pa_yes_no(d->accessible)); + pa_xfree(cd); if (d->module == PA_INVALID_INDEX) { -- cgit From 2d0120485c60e0eacc81d1e28e2993559350211b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 22:49:23 +0200 Subject: udev: watch for both ACL changes and processes closing devices --- src/modules/module-udev-detect.c | 63 ++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index f2e7b0df..2fcbe216 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -45,7 +45,8 @@ PA_MODULE_USAGE( struct device { char *path; - pa_bool_t accessible; + pa_bool_t accessible:1; + pa_bool_t need_verify:1; char *card_name; char *args; uint32_t module; @@ -277,6 +278,34 @@ fail: u->udev_io = NULL; } +static pa_bool_t pcm_node_belongs_to_device( + struct device *d, + const char *node) { + + char *cd; + pa_bool_t b; + + cd = pa_sprintf_malloc("pcmC%sD", path_get_card_id(d->path)); + b = pa_startswith(node, cd); + pa_xfree(cd); + + return b; +} + +static pa_bool_t control_node_belongs_to_device( + struct device *d, + const char *node) { + + char *cd; + pa_bool_t b; + + cd = pa_sprintf_malloc("controlC%s", path_get_card_id(d->path)); + b = pa_streq(node, cd); + pa_xfree(cd); + + return b; +} + static void inotify_cb( pa_mainloop_api*a, pa_io_event* e, @@ -290,7 +319,9 @@ static void inotify_cb( } buf; struct userdata *u = userdata; static int type = 0; - pa_bool_t verify = FALSE, deleted = FALSE; + pa_bool_t deleted = FALSE; + struct device *d; + void *state; for (;;) { ssize_t r; @@ -305,22 +336,30 @@ static void inotify_cb( goto fail; } - if ((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC")) - verify = TRUE; + /* From udev we get the guarantee that the control + * device's ACL is changes last. To avoid races when ACLs + * are changed we hence watch only the control device */ + if (((buf.e.mask & IN_ATTRIB) && pa_startswith(buf.e.name, "controlC"))) + PA_HASHMAP_FOREACH(d, u->devices, state) + if (control_node_belongs_to_device(d, buf.e.name)) + d->need_verify = TRUE; + + /* ALSA doesn't really give us any guarantee on the closing + * order, so let's simply hope */ + if (((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC"))) + PA_HASHMAP_FOREACH(d, u->devices, state) + if (pcm_node_belongs_to_device(d, buf.e.name)) + d->need_verify = TRUE; if ((buf.e.mask & (IN_DELETE_SELF|IN_MOVE_SELF))) deleted = TRUE; } - if (verify) { - struct device *d; - void *state; - - pa_log_debug("Verifying access."); - - PA_HASHMAP_FOREACH(d, u->devices, state) + PA_HASHMAP_FOREACH(d, u->devices, state) + if (d->need_verify) { + d->need_verify = FALSE; verify_access(u, d); - } + } if (!deleted) return; -- cgit From 066e160bbd095afe79fc7ea79fbc88b8746960cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 21 Aug 2009 23:24:40 +0200 Subject: udev: tell inotify to actually inform us about ACL changes --- src/modules/module-udev-detect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index 2fcbe216..1d67c0cc 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -389,7 +389,7 @@ static int setup_inotify(struct userdata *u) { } dev_snd = pa_sprintf_malloc("%s/snd", udev_get_dev_path(u->udev)); - r = inotify_add_watch(u->inotify_fd, dev_snd, IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF); + r = inotify_add_watch(u->inotify_fd, dev_snd, IN_ATTRIB|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF); pa_xfree(dev_snd); if (r < 0) { -- cgit From de19bdd34e54c6a4fe8791d28ce0733343381488 Mon Sep 17 00:00:00 2001 From: Scott Reeves Date: Fri, 21 Aug 2009 23:59:39 +0200 Subject: daemon: fix leak of script_commands --- src/daemon/cmdline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index ecb38486..3ebc9270 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -385,7 +385,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d pa_xfree(conf->script_commands); conf->script_commands = pa_strbuf_tostring_free(buf); - if (!conf->script_commands) { + if (conf->script_commands) { pa_xfree(conf->script_commands); conf->script_commands = NULL; } -- 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/Makefile.am | 12 +- src/pulse/util.c | 52 +++---- src/pulsecore/core-util.c | 106 +++---------- src/pulsecore/usergroup.c | 376 +++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/usergroup.h | 51 ++++++ src/tests/usergroup-test.c | 161 +++++++++++++++++++ 6 files changed, 643 insertions(+), 115 deletions(-) create mode 100644 src/pulsecore/usergroup.c create mode 100644 src/pulsecore/usergroup.h create mode 100644 src/tests/usergroup-test.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index fd440991..73c0db5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -280,7 +280,8 @@ TESTS = \ proplist-test \ lock-autospawn-test \ prioq-test \ - sigbus-test + sigbus-test \ + usergroup-test TESTS_BINARIES = \ mainloop-test \ @@ -318,7 +319,8 @@ TESTS_BINARIES = \ stripnul \ lock-autospawn-test \ prioq-test \ - sigbus-test + sigbus-test \ + usergroup-test if HAVE_SIGXCPU #TESTS += \ @@ -557,6 +559,11 @@ alsa_time_test_LDADD = $(AM_LDADD) alsa_time_test_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) alsa_time_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(ASOUNDLIB_LIBS) +usergroup_test_SOURCES = tests/usergroup-test.c +usergroup_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la +usergroup_test_CFLAGS = $(AM_CFLAGS) +usergroup_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) + ################################### # Common library # ################################### @@ -621,6 +628,7 @@ libpulsecommon_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/tagstruct.c pulsecore/tagstruct.h \ pulsecore/time-smoother.c pulsecore/time-smoother.h \ pulsecore/tokenizer.c pulsecore/tokenizer.h \ + pulsecore/usergroup.c pulsecore/usergroup.h \ pulsecore/sndfile-util.c pulsecore/sndfile-util.h \ pulsecore/winsock.h 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; diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 843c8377..0eb32cc4 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -115,6 +115,7 @@ #include #include #include +#include #include "core-util.h" @@ -969,42 +970,24 @@ fail: /* Check whether the specified GID and the group name match */ static int is_group(gid_t gid, const char *name) { - struct group group, *result = NULL; - long n; - void *data; + struct group *group = NULL; int r = -1; -#ifdef HAVE_GETGRGID_R - -#ifdef _SC_GETGR_R_SIZE_MAX - n = sysconf(_SC_GETGR_R_SIZE_MAX); -#else - n = -1; -#endif - if (n <= 0) - n = 512; - - data = pa_xmalloc((size_t) n); - - if ((errno = getgrgid_r(gid, &group, data, (size_t) n, &result)) || !result) -#else errno = 0; - if (!(result = getgrgid(gid))) -#endif + if (!(group = pa_getgrgid_malloc(gid))) { if (!errno) errno = ENOENT; - pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno)); + pa_log("pa_getgrgid_malloc(%u): %s", gid, pa_cstrerror(errno)); goto finish; } - r = strcmp(name, result->gr_name) == 0; + r = strcmp(name, group->gr_name) == 0; finish: - - pa_xfree(data); + pa_getgrgid_free(group); return r; } @@ -1053,69 +1036,37 @@ finish: /* Check whether the specifc user id is a member of the specified group */ int pa_uid_in_group(uid_t uid, const char *name) { - char *g_buf = NULL, *p_buf = NULL; - long g_n, p_n; - struct group grbuf, *gr = NULL; + struct group *group = NULL; char **i; int r = -1; -#ifdef HAVE_GETGRNAM_R - -#ifdef _SC_GETGR_R_SIZE_MAX - g_n = sysconf(_SC_GETGR_R_SIZE_MAX); -#else - g_n = -1; -#endif - if (g_n <= 0) - g_n = 512; - - g_buf = pa_xmalloc((size_t) g_n); - - if ((errno = getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr)) != 0 || !gr) -#else errno = 0; - if (!(gr = getgrnam(name))) -#endif + if (!(group = pa_getgrnam_malloc(name))) { if (!errno) errno = ENOENT; goto finish; } -#ifdef HAVE_GETPWNAM_R - -#ifdef _SC_GETPW_R_SIZE_MAX - p_n = sysconf(_SC_GETPW_R_SIZE_MAX); -#else - p_n = -1; -#endif - if (p_n <= 0) - p_n = 512; - - p_buf = pa_xmalloc((size_t) p_n); -#endif - r = 0; - for (i = gr->gr_mem; *i; i++) { - struct passwd pwbuf, *pw = NULL; + for (i = group->gr_mem; *i; i++) { + struct passwd *pw = NULL; -#ifdef HAVE_GETPWNAM_R - if ((errno = getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw)) != 0 || !pw) -#else errno = 0; - if (!(pw = getpwnam(*i))) -#endif + if (!(pw = pa_getpwnam_malloc(*i))) continue; - if (pw->pw_uid == uid) { + if (pw->pw_uid == uid) r = 1; + + pa_getpwnam_free(pw); + + if (r == 1) break; - } } finish: - pa_xfree(g_buf); - pa_xfree(p_buf); + pa_getgrnam_free(group); return r; } @@ -1123,27 +1074,10 @@ finish: /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */ gid_t pa_get_gid_of_group(const char *name) { gid_t ret = (gid_t) -1; - char *g_buf = NULL; - long g_n; - struct group grbuf, *gr = NULL; - -#ifdef HAVE_GETGRNAM_R - -#ifdef _SC_GETGR_R_SIZE_MAX - g_n = sysconf(_SC_GETGR_R_SIZE_MAX); -#else - g_n = -1; -#endif - if (g_n <= 0) - g_n = 512; - - g_buf = pa_xmalloc((size_t) g_n); + struct group *gr = NULL; - if ((errno = getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr)) != 0 || !gr) -#else errno = 0; - if (!(gr = getgrnam(name))) -#endif + if (!(gr = pa_getgrnam_malloc(name))) { if (!errno) errno = ENOENT; @@ -1153,7 +1087,7 @@ gid_t pa_get_gid_of_group(const char *name) { ret = gr->gr_gid; finish: - pa_xfree(g_buf); + pa_getgrnam_free(gr); return ret; } diff --git a/src/pulsecore/usergroup.c b/src/pulsecore/usergroup.c new file mode 100644 index 00000000..bf686b77 --- /dev/null +++ b/src/pulsecore/usergroup.c @@ -0,0 +1,376 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Ted Percival + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_PWD_H +#include +#endif + +#ifdef HAVE_GRP_H +#include +#endif + +#include +#include + +#include "usergroup.h" + +#ifdef HAVE_GRP_H + +/* Returns a suitable starting size for a getgrnam_r() or getgrgid_r() buffer, + plus the size of a struct group. + */ +static size_t starting_getgr_buflen(void) { + size_t full_size; + long n; +#ifdef _SC_GETGR_R_SIZE_MAX + n = sysconf(_SC_GETGR_R_SIZE_MAX); +#else + n = -1; +#endif + if (n <= 0) + n = 512; + + full_size = (size_t) n + sizeof(struct group); + + if (full_size < (size_t) n) /* check for integer overflow */ + return (size_t) n; + + return full_size; +} + +/* Returns a suitable starting size for a getpwnam_r() or getpwuid_r() buffer, + plus the size of a struct passwd. + */ +static size_t starting_getpw_buflen(void) { + long n; + size_t full_size; + +#ifdef _SC_GETPW_R_SIZE_MAX + n = sysconf(_SC_GETPW_R_SIZE_MAX); +#else + n = -1; +#endif + if (n <= 0) + n = 512; + + full_size = (size_t) n + sizeof(struct passwd); + + if (full_size < (size_t) n) /* check for integer overflow */ + return (size_t) n; + + return full_size; +} + +/* Given a memory allocation (*bufptr) and its length (*buflenptr), + double the size of the allocation, updating the given buffer and length + arguments. This function should be used in conjunction with the pa_*alloc + and pa_xfree functions. + + Unlike realloc(), this function does *not* retain the original buffer's + contents. + + Returns 0 on success, nonzero on error. The error cause is indicated by + errno. + */ +static int expand_buffer_trashcontents(void **bufptr, size_t *buflenptr) { + size_t newlen; + + if (!bufptr || !*bufptr || !buflenptr) { + errno = EINVAL; + return -1; + } + + newlen = *buflenptr * 2; + + if (newlen < *buflenptr) { + errno = EOVERFLOW; + return -1; + } + + /* Don't bother retaining memory contents; free & alloc anew */ + pa_xfree(*bufptr); + + *bufptr = pa_xmalloc(newlen); + *buflenptr = newlen; + + return 0; +} + +#ifdef HAVE_GETGRGID_R +/* Thread-safe getgrgid() replacement. + Returned value should be freed using pa_getgrgid_free() when the caller is + finished with the returned group data. + + API is the same as getgrgid(), errors are indicated by a NULL return; + consult errno for the error cause (zero it before calling). + The returned value must be freed using pa_xfree(). + */ +struct group *pa_getgrgid_malloc(gid_t gid) { + size_t buflen, getgr_buflen; + int err; + void *buf; + void *getgr_buf; + struct group *result = NULL; + + buflen = starting_getgr_buflen(); + buf = pa_xmalloc(buflen); + + getgr_buflen = buflen - sizeof(struct group); + getgr_buf = (char *)buf + sizeof(struct group); + + while ((err = getgrgid_r(gid, (struct group *)buf, getgr_buf, + getgr_buflen, &result)) == ERANGE) + { + if (expand_buffer_trashcontents(&buf, &buflen)) + break; + + getgr_buflen = buflen - sizeof(struct group); + getgr_buf = (char *)buf + sizeof(struct group); + } + + if (err || !result) { + result = NULL; + if (buf) { + pa_xfree(buf); + buf = NULL; + } + } + + pa_assert(result == buf || result == NULL); + + return result; +} + +void pa_getgrgid_free(struct group *grp) { + pa_xfree(grp); +} + +#else /* !HAVE_GETGRGID_R */ + +struct group *pa_getgrgid_malloc(gid_t gid) { + return getgrgid(gid); +} + +void pa_getgrgid_free(struct group *grp) { + /* nothing */ + return; +} + +#endif /* !HAVE_GETGRGID_R */ + +#ifdef HAVE_GETGRNAM_R +/* Thread-safe getgrnam() function. + Returned value should be freed using pa_getgrnam_free() when the caller is + finished with the returned group data. + + API is the same as getgrnam(), errors are indicated by a NULL return; + consult errno for the error cause (zero it before calling). + The returned value must be freed using pa_xfree(). + */ +struct group *pa_getgrnam_malloc(const char *name) { + size_t buflen, getgr_buflen; + int err; + void *buf; + void *getgr_buf; + struct group *result = NULL; + + buflen = starting_getgr_buflen(); + buf = pa_xmalloc(buflen); + + getgr_buflen = buflen - sizeof(struct group); + getgr_buf = (char *)buf + sizeof(struct group); + + while ((err = getgrnam_r(name, (struct group *)buf, getgr_buf, + getgr_buflen, &result)) == ERANGE) + { + if (expand_buffer_trashcontents(&buf, &buflen)) + break; + + getgr_buflen = buflen - sizeof(struct group); + getgr_buf = (char *)buf + sizeof(struct group); + } + + if (err || !result) { + result = NULL; + if (buf) { + pa_xfree(buf); + buf = NULL; + } + } + + pa_assert(result == buf || result == NULL); + + return result; +} + +void pa_getgrnam_free(struct group *group) { + pa_xfree(group); +} + +#else /* !HAVE_GETGRNAM_R */ + +struct group *pa_getgrnam_malloc(const char *name) { + return getgrnam(name); +} + +void pa_getgrnam_free(struct group *group) { + /* nothing */ + return; +} + +#endif /* HAVE_GETGRNAM_R */ + +#endif /* HAVE_GRP_H */ + +#ifdef HAVE_PWD_H + +#ifdef HAVE_GETPWNAM_R +/* Thread-safe getpwnam() function. + Returned value should be freed using pa_getpwnam_free() when the caller is + finished with the returned passwd data. + + API is the same as getpwnam(), errors are indicated by a NULL return; + consult errno for the error cause (zero it before calling). + The returned value must be freed using pa_xfree(). + */ +struct passwd *pa_getpwnam_malloc(const char *name) { + size_t buflen, getpw_buflen; + int err; + void *buf; + void *getpw_buf; + struct passwd *result = NULL; + + buflen = starting_getpw_buflen(); + buf = pa_xmalloc(buflen); + + getpw_buflen = buflen - sizeof(struct passwd); + getpw_buf = (char *)buf + sizeof(struct passwd); + + while ((err = getpwnam_r(name, (struct passwd *)buf, getpw_buf, + getpw_buflen, &result)) == ERANGE) + { + if (expand_buffer_trashcontents(&buf, &buflen)) + break; + + getpw_buflen = buflen - sizeof(struct passwd); + getpw_buf = (char *)buf + sizeof(struct passwd); + } + + if (err || !result) { + result = NULL; + if (buf) { + pa_xfree(buf); + buf = NULL; + } + } + + pa_assert(result == buf || result == NULL); + + return result; +} + +void pa_getpwnam_free(struct passwd *passwd) { + pa_xfree(passwd); +} + +#else /* !HAVE_GETPWNAM_R */ + +struct passwd *pa_getpwnam_malloc(const char *name) { + return getpwnam(name); +} + +void pa_getpwnam_free(struct passwd *passwd) { + /* nothing */ + return; +} + +#endif /* !HAVE_GETPWNAM_R */ + +#ifdef HAVE_GETPWUID_R +/* Thread-safe getpwuid() function. + Returned value should be freed using pa_getpwuid_free() when the caller is + finished with the returned group data. + + API is the same as getpwuid(), errors are indicated by a NULL return; + consult errno for the error cause (zero it before calling). + The returned value must be freed using pa_xfree(). + */ +struct passwd *pa_getpwuid_malloc(uid_t uid) { + size_t buflen, getpw_buflen; + int err; + void *buf; + void *getpw_buf; + struct passwd *result = NULL; + + buflen = starting_getpw_buflen(); + buf = pa_xmalloc(buflen); + + getpw_buflen = buflen - sizeof(struct passwd); + getpw_buf = (char *)buf + sizeof(struct passwd); + + while ((err = getpwuid_r(uid, (struct passwd *)buf, getpw_buf, + getpw_buflen, &result)) == ERANGE) + { + if (expand_buffer_trashcontents(&buf, &buflen)) + break; + + getpw_buflen = buflen - sizeof(struct passwd); + getpw_buf = (char *)buf + sizeof(struct passwd); + } + + if (err || !result) { + result = NULL; + if (buf) { + pa_xfree(buf); + buf = NULL; + } + } + + pa_assert(result == buf || result == NULL); + + return result; +} + +void pa_getpwuid_free(struct passwd *passwd) { + pa_xfree(passwd); +} + +#else /* !HAVE_GETPWUID_R */ + +struct passwd *pa_getpwuid_malloc(uid_t uid) { + return getpwuid(uid); +} + +void pa_getpwuid_free(struct passwd *passwd) { + /* nothing */ + return; +} + +#endif /* !HAVE_GETPWUID_R */ + +#endif /* HAVE_PWD_H */ diff --git a/src/pulsecore/usergroup.h b/src/pulsecore/usergroup.h new file mode 100644 index 00000000..1c091638 --- /dev/null +++ b/src/pulsecore/usergroup.h @@ -0,0 +1,51 @@ +#ifndef foousergrouphfoo +#define foousergrouphfoo + +/*** + This file is part of PulseAudio. + + Copyright 2009 Ted Percival + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#ifndef PACKAGE +#error "Please include config.h before including this file!" +#endif + +#ifdef HAVE_GRP_H + +struct group *pa_getgrgid_malloc(gid_t gid); +void pa_getgrgid_free(struct group *grp); + +struct group *pa_getgrnam_malloc(const char *name); +void pa_getgrnam_free(struct group *group); + +#endif /* HAVE_GRP_H */ + +#ifdef HAVE_PWD_H + +struct passwd *pa_getpwuid_malloc(uid_t uid); +void pa_getpwuid_free(struct passwd *passwd); + +struct passwd *pa_getpwnam_malloc(const char *name); +void pa_getpwnam_free(struct passwd *passwd); + +#endif /* HAVE_PWD_H */ + +#endif /* foousergrouphfoo */ diff --git a/src/tests/usergroup-test.c b/src/tests/usergroup-test.c new file mode 100644 index 00000000..a48b016d --- /dev/null +++ b/src/tests/usergroup-test.c @@ -0,0 +1,161 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Ted Percival + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +static int load_reference_structs(struct group **gr, struct passwd **pw) { + setpwent(); + *pw = getpwent(); + endpwent(); + + setgrent(); + *gr = getgrent(); + endgrent(); + + return (*gr && *pw) ? 0 : 1; +} + +static int compare_group(const struct group *a, const struct group *b) { + char **amem, **bmem; + + if (strcmp(a->gr_name, b->gr_name)) { + fprintf(stderr, "Group name mismatch: [%s] [%s]\n", + a->gr_name, b->gr_name); + return 1; + } + + if (strcmp(a->gr_passwd, b->gr_passwd)) { + fprintf(stderr, "Group password mismatch: [%s] [%s]\n", + a->gr_passwd, b->gr_passwd); + return 1; + } + + if (a->gr_gid != b->gr_gid) { + fprintf(stderr, "Gid mismatch: [%lu] [%lu]\n", + (unsigned long) a->gr_gid, (unsigned long) b->gr_gid); + return 1; + } + + /* XXX: Assuming the group ordering is identical. */ + for (amem = a->gr_mem, bmem = b->gr_mem; *amem && *bmem; ++amem, ++bmem) { + if (strcmp(*amem, *bmem)) { + fprintf(stderr, "Group member mismatch: [%s] [%s]\n", + *amem, *bmem); + return 1; + } + } + + if (*amem || *bmem) { + fprintf(stderr, "Mismatched group count\n"); + return 1; + } + + return 0; +} + +static int compare_passwd(const struct passwd *a, const struct passwd *b) { + if (strcmp(a->pw_name, b->pw_name)) { + fprintf(stderr, "pw_name mismatch: [%s] [%s]\n", a->pw_name, b->pw_name); + return 1; + } + + if (strcmp(a->pw_passwd, b->pw_passwd)) { + fprintf(stderr, "pw_passwd mismatch: [%s] [%s]\n", a->pw_passwd, b->pw_passwd); + return 1; + } + + if (a->pw_uid != b->pw_uid) { + fprintf(stderr, "pw_uid mismatch: [%lu] [%lu]\n", + (unsigned long) a->pw_uid, (unsigned long) b->pw_uid); + return 1; + } + + if (a->pw_gid != b->pw_gid) { + fprintf(stderr, "pw_gid mismatch: [%lu] [%lu]\n", + (unsigned long) a->pw_gid, (unsigned long) b->pw_gid); + return 1; + } + + if (strcmp(a->pw_gecos, b->pw_gecos)) { + fprintf(stderr, "pw_gecos mismatch: [%s] [%s]\n", a->pw_gecos, b->pw_gecos); + return 1; + } + + if (strcmp(a->pw_dir, b->pw_dir)) { + fprintf(stderr, "pw_dir mismatch: [%s] [%s]\n", a->pw_dir, b->pw_dir); + return 1; + } + + if (strcmp(a->pw_shell, b->pw_shell)) { + fprintf(stderr, "pw_shell mismatch: [%s] [%s]\n", a->pw_shell, b->pw_shell); + return 1; + } + + return 0; +} + +int main(int argc, char *argv[]) { + struct group *gr; + struct passwd *pw; + int err; + struct group *reference_group = NULL; + struct passwd *reference_passwd = NULL; + + err = load_reference_structs(&reference_group, &reference_passwd); + if (err) + return 77; + + errno = 0; + gr = pa_getgrgid_malloc(reference_group->gr_gid); + if (compare_group(reference_group, gr)) + return 1; + pa_getgrgid_free(gr); + + errno = 0; + gr = pa_getgrnam_malloc(reference_group->gr_name); + if (compare_group(reference_group, gr)) + return 1; + pa_getgrnam_free(gr); + + errno = 0; + pw = pa_getpwuid_malloc(reference_passwd->pw_uid); + if (compare_passwd(reference_passwd, pw)) + return 1; + pa_getpwuid_free(pw); + + errno = 0; + pw = pa_getpwnam_malloc(reference_passwd->pw_name); + if (compare_passwd(reference_passwd, pw)) + return 1; + pa_getpwnam_free(pw); + + return 0; +} -- cgit From 44c7aa55e25334901769b82355c12dee91cb3629 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Fri, 21 Aug 2009 13:15:38 +1000 Subject: Solaris: build fixes (resent) Fix bit rot due to recent flat volume changes. --- src/modules/module-solaris.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 0920d25e..2c878c20 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -479,7 +479,7 @@ static void sink_set_volume(pa_sink *s) { if (u->fd >= 0) { AUDIO_INITINFO(&info); - info.play.gain = pa_cvolume_max(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; + info.play.gain = pa_cvolume_max(&s->real_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; assert(info.play.gain <= AUDIO_MAX_GAIN); if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { @@ -501,8 +501,7 @@ static void sink_get_volume(pa_sink *s) { if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0) pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); else - pa_cvolume_set(&s->virtual_volume, s->sample_spec.channels, - info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); + pa_cvolume_set(&s->real_volume, s->sample_spec.channels, info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); } } @@ -515,7 +514,7 @@ static void source_set_volume(pa_source *s) { if (u->fd >= 0) { AUDIO_INITINFO(&info); - info.play.gain = pa_cvolume_max(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; + info.play.gain = pa_cvolume_max(&s->volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; assert(info.play.gain <= AUDIO_MAX_GAIN); if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { @@ -537,8 +536,7 @@ static void source_get_volume(pa_source *s) { if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0) pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); else - pa_cvolume_set(&s->virtual_volume, s->sample_spec.channels, - info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); + pa_cvolume_set(&s->volume, s->sample_spec.channels, info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); } } @@ -797,7 +795,7 @@ static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void pa_log_debug("caught signal"); if (u->sink) { - pa_sink_get_volume(u->sink, TRUE, FALSE); + pa_sink_get_volume(u->sink, TRUE); pa_sink_get_mute(u->sink, TRUE); } -- cgit From 87d2dded9b90331943a6c7b9d8d9b1ac100b6689 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Fri, 21 Aug 2009 13:17:03 +1000 Subject: Solaris: use smoother (resent) Make use of the smoother, just in case. --- src/modules/module-solaris.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 2c878c20..3bf7c4b0 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -60,6 +60,7 @@ #include #include #include +#include #include "module-solaris-symdef.h" @@ -110,6 +111,8 @@ struct userdata { uint32_t prev_playback_samples, prev_record_samples; int32_t minimum_request; + + pa_smoother *smoother; }; static const char* const valid_modargs[] = { @@ -145,7 +148,12 @@ static uint64_t get_playback_buffered_bytes(struct userdata *u) { /* Handle wrap-around of the device's sample counter, which is a uint_32. */ if (u->prev_playback_samples > info.play.samples) { - /* Unfortunately info.play.samples can sometimes go backwards, even before it wraps! */ + /* + * Unfortunately info.play.samples can sometimes go backwards, even before it wraps! + * The bug seems to be absent on Solaris x86 nv117 with audio810 driver, at least on this (UP) machine. + * The bug is present on a different (SMP) machine running Solaris x86 nv103 with audioens driver. + * An earlier revision of this file mentions the same bug independently (unknown configuration). + */ if (u->prev_playback_samples + info.play.samples < 240000) { ++u->play_samples_msw; } else { @@ -155,6 +163,8 @@ static uint64_t get_playback_buffered_bytes(struct userdata *u) { u->prev_playback_samples = info.play.samples; played_bytes = (((uint64_t)u->play_samples_msw << 32) + info.play.samples) * u->frame_size; + pa_smoother_put(u->smoother, pa_rtclock_now(), pa_bytes_to_usec(played_bytes, &u->sink->sample_spec)); + return u->written_bytes - played_bytes; } @@ -387,6 +397,8 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state)); + pa_smoother_pause(u->smoother, pa_rtclock_now()); + if (!u->source || u->source_suspended) { if (suspend(u) < 0) return -1; @@ -398,6 +410,8 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse case PA_SINK_RUNNING: if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { + pa_smoother_resume(u->smoother, pa_rtclock_now(), TRUE); + if (!u->source || u->source_suspended) { if (unsuspend(u) < 0) return -1; @@ -604,11 +618,13 @@ static void thread_func(void *userdata) { pa_thread_mq_install(&u->thread_mq); + pa_smoother_set_time_offset(u->smoother, pa_rtclock_now()); + for (;;) { /* Render some data and write it to the dsp */ if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) { - pa_usec_t xtime0; + pa_usec_t xtime0, ysleep_interval, xsleep_interval; uint64_t buffered_bytes; if (u->sink->thread_info.rewind_requested) @@ -627,6 +643,8 @@ static void thread_func(void *userdata) { info.play.error = 0; if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); + + pa_smoother_reset(u->smoother, pa_rtclock_now(), TRUE); } for (;;) { @@ -689,7 +707,9 @@ static void thread_func(void *userdata) { } } - pa_rtpoll_set_timer_absolute(u->rtpoll, xtime0 + pa_bytes_to_usec(buffered_bytes / 2, &u->sink->sample_spec)); + ysleep_interval = pa_bytes_to_usec(buffered_bytes / 2, &u->sink->sample_spec); + xsleep_interval = pa_smoother_translate(u->smoother, xtime0, ysleep_interval); + pa_rtpoll_set_timer_absolute(u->rtpoll, xtime0 + PA_MIN(xsleep_interval, ysleep_interval)); } else pa_rtpoll_set_timer_disabled(u->rtpoll); @@ -836,6 +856,9 @@ int pa__init(pa_module *m) { u = pa_xnew0(struct userdata, 1); + if (!(u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC * 2, TRUE, TRUE, 10, pa_rtclock_now(), TRUE))) + goto fail; + /* * For a process (or several processes) to use the same audio device for both * record and playback at the same time, the device's mixer must be enabled. @@ -1073,6 +1096,9 @@ void pa__done(pa_module *m) { if (u->fd >= 0) close(u->fd); + if (u->smoother) + pa_smoother_free(u->smoother); + pa_xfree(u->device_name); pa_xfree(u); -- cgit From 601fb63b0160d3d76083d07dcc1201a123031915 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Fri, 21 Aug 2009 13:18:40 +1000 Subject: Solaris: fixed latency (resent) Set a fixed latency based on the given buffer size, which is constrained to the 128 KB limit on buffered writes. Also fix an error path. --- src/modules/module-solaris.c | 56 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 3bf7c4b0..71f14071 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -136,6 +136,9 @@ static const char* const valid_modargs[] = { #define MAX_RENDER_HZ (300) /* This render rate limit imposes a minimum latency, but without it we waste too much CPU time. */ +#define MAX_BUFFER_SIZE (128 * 1024) +/* An attempt to buffer more than 128 KB causes write() to fail with errno == EAGAIN. */ + static uint64_t get_playback_buffered_bytes(struct userdata *u) { audio_info_t info; uint64_t played_bytes; @@ -651,6 +654,7 @@ static void thread_func(void *userdata) { void *p; ssize_t w; size_t len; + int write_type = 1; /* * Since we cannot modify the size of the output buffer we fake it @@ -668,38 +672,31 @@ static void thread_func(void *userdata) { break; if (u->memchunk.length < len) - pa_sink_render(u->sink, u->sink->thread_info.max_request, &u->memchunk); + pa_sink_render(u->sink, len - u->memchunk.length, &u->memchunk); + + len = PA_MIN(u->memchunk.length, len); p = pa_memblock_acquire(u->memchunk.memblock); - w = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, NULL); + w = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, len, &write_type); pa_memblock_release(u->memchunk.memblock); if (w <= 0) { - switch (errno) { - case EINTR: - continue; - case EAGAIN: - /* If the buffer_size is too big, we get EAGAIN. Avoiding that limit by trial and error - * is not ideal, but I don't know how to get the system to tell me what the limit is. - */ - u->buffer_size = u->buffer_size * 18 / 25; - u->buffer_size -= u->buffer_size % u->frame_size; - u->buffer_size = PA_MAX(u->buffer_size, 2 * u->minimum_request); - pa_sink_set_max_request_within_thread(u->sink, u->buffer_size); - pa_sink_set_max_rewind_within_thread(u->sink, u->buffer_size); - pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u->buffer_size, buffered_bytes); - break; - default: - pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno)); - goto fail; + if (errno == EINTR) { + continue; + } else if (errno == EAGAIN) { + /* We may have realtime priority so yield the CPU to ensure that fd can become writable again. */ + pa_log_debug("EAGAIN with %llu bytes buffered.", buffered_bytes); + break; + } else { + pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno)); + goto fail; } } else { pa_assert(w % u->frame_size == 0); u->written_bytes += w; - u->memchunk.length -= w; - u->memchunk.index += w; + u->memchunk.length -= w; if (u->memchunk.length <= 0) { pa_memblock_unref(u->memchunk.memblock); pa_memchunk_reset(&u->memchunk); @@ -830,7 +827,7 @@ int pa__init(pa_module *m) { pa_channel_map map; pa_modargs *ma = NULL; uint32_t buffer_length_msec; - int fd; + int fd = -1; pa_sink_new_data sink_new_data; pa_source_new_data source_new_data; char const *name; @@ -882,7 +879,13 @@ int pa__init(pa_module *m) { } u->buffer_size = pa_usec_to_bytes(1000 * buffer_length_msec, &ss); if (u->buffer_size < 2 * u->minimum_request) { - pa_log("supplied buffer size argument is too small"); + pa_log("buffer_length argument cannot be smaller than %u", + (unsigned)(pa_bytes_to_usec(2 * u->minimum_request, &ss) / 1000)); + goto fail; + } + if (u->buffer_size > MAX_BUFFER_SIZE) { + pa_log("buffer_length argument cannot be greater than %u", + (unsigned)(pa_bytes_to_usec(MAX_BUFFER_SIZE, &ss) / 1000)); goto fail; } @@ -945,6 +948,7 @@ int pa__init(pa_module *m) { pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); pa_source_set_rtpoll(u->source, u->rtpoll); + pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, &u->source->sample_spec)); u->source->get_volume = source_get_volume; u->source->set_volume = source_set_volume; @@ -987,15 +991,15 @@ int pa__init(pa_module *m) { pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); + pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->buffer_size, &u->sink->sample_spec)); + pa_sink_set_max_request(u->sink, u->buffer_size); + pa_sink_set_max_rewind(u->sink, u->buffer_size); u->sink->get_volume = sink_get_volume; u->sink->set_volume = sink_set_volume; u->sink->get_mute = sink_get_mute; u->sink->set_mute = sink_set_mute; u->sink->refresh_volume = u->sink->refresh_muted = TRUE; - - pa_sink_set_max_request(u->sink, u->buffer_size); - pa_sink_set_max_rewind(u->sink, u->buffer_size); } else u->sink = NULL; -- cgit From 17dc410e8874d38ce7a9882245360314a8251e06 Mon Sep 17 00:00:00 2001 From: Ted Percival Date: Fri, 21 Aug 2009 17:05:41 -0600 Subject: core: Remove wrong doc on how to free returned data --- src/pulsecore/usergroup.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/pulsecore/usergroup.c b/src/pulsecore/usergroup.c index bf686b77..71b13bca 100644 --- a/src/pulsecore/usergroup.c +++ b/src/pulsecore/usergroup.c @@ -128,7 +128,6 @@ static int expand_buffer_trashcontents(void **bufptr, size_t *buflenptr) { API is the same as getgrgid(), errors are indicated by a NULL return; consult errno for the error cause (zero it before calling). - The returned value must be freed using pa_xfree(). */ struct group *pa_getgrgid_malloc(gid_t gid) { size_t buflen, getgr_buflen; @@ -190,7 +189,6 @@ void pa_getgrgid_free(struct group *grp) { API is the same as getgrnam(), errors are indicated by a NULL return; consult errno for the error cause (zero it before calling). - The returned value must be freed using pa_xfree(). */ struct group *pa_getgrnam_malloc(const char *name) { size_t buflen, getgr_buflen; @@ -256,7 +254,6 @@ void pa_getgrnam_free(struct group *group) { API is the same as getpwnam(), errors are indicated by a NULL return; consult errno for the error cause (zero it before calling). - The returned value must be freed using pa_xfree(). */ struct passwd *pa_getpwnam_malloc(const char *name) { size_t buflen, getpw_buflen; @@ -318,7 +315,6 @@ void pa_getpwnam_free(struct passwd *passwd) { API is the same as getpwuid(), errors are indicated by a NULL return; consult errno for the error cause (zero it before calling). - The returned value must be freed using pa_xfree(). */ struct passwd *pa_getpwuid_malloc(uid_t uid) { size_t buflen, getpw_buflen; -- cgit From aa5429805f88bcade639e5e8667b79a07ec104b6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Aug 2009 03:16:47 +0200 Subject: daemon: don't free script_commands twice --- src/daemon/cmdline.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src') diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index 3ebc9270..f6cdcdc8 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -385,11 +385,6 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d pa_xfree(conf->script_commands); conf->script_commands = pa_strbuf_tostring_free(buf); - if (conf->script_commands) { - pa_xfree(conf->script_commands); - conf->script_commands = NULL; - } - *d = optind; return 0; -- cgit From 2595b9d98569e62f4d375ced1d3f7c7af34efa74 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Aug 2009 03:17:24 +0200 Subject: add usergroup-test to .gitignore --- src/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/.gitignore b/src/.gitignore index 82331524..6cd173c0 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,4 @@ +usergroup-test sigbus-test TAGS alsa-time-test -- cgit From 5b0683d6cd103a7a91bc2e88bcc9f77750d10c25 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Aug 2009 04:03:31 +0200 Subject: ladspa/remap: handle failing stream moves properly --- src/modules/module-ladspa-sink.c | 7 +++++-- src/modules/module-remap-sink.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 233f90c4..aa28f7fd 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -418,8 +418,11 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); - pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); + if (dest) { + pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); + pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); + } else + pa_sink_set_asyncmsgq(u->sink, NULL); } /* Called from main context */ diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 0b4fdc9b..becff55c 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -302,8 +302,11 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { pa_sink_input_assert_ref(i); pa_assert_se(u = i->userdata); - pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); - pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); + if (dest) { + pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); + pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); + } else + pa_sink_set_asyncmsgq(u->sink, NULL); } int pa__init(pa_module*m) { -- cgit From 1a05d67f07fb4bfa6e419791cf5609d608f536cd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Aug 2009 04:04:23 +0200 Subject: core: relex validity checks when destructing half-set up source outputs/sink inputs --- src/pulsecore/sink-input.c | 5 ++++- src/pulsecore/source-output.c | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 4137a425..0ad95e6f 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -487,7 +487,10 @@ static void sink_input_free(pa_object *o) { pa_log_info("Freeing input %u \"%s\"", i->index, pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME))); - pa_assert(!i->thread_info.attached); + /* Side note: this function must be able to destruct properly any + * kind of sink input in any state, even those which are + * "half-moved" or are connected to sinks that have no asyncmsgq + * and are hence half-destructed themselves! */ if (i->thread_info.render_memblockq) pa_memblockq_free(i->thread_info.render_memblockq); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index b0298616..43733400 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -359,8 +359,6 @@ static void source_output_free(pa_object* mo) { pa_log_info("Freeing output %u \"%s\"", o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME))); - pa_assert(!o->thread_info.attached); - if (o->thread_info.delay_memblockq) pa_memblockq_free(o->thread_info.delay_memblockq); -- cgit From 560da5b0a1386c2a158d69b6ba0ef99c0f03bbf4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Aug 2009 21:59:17 +0200 Subject: udev: process all inotify events queued up, not just the first one in the queue --- src/modules/module-udev-detect.c | 56 ++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index 1d67c0cc..55136348 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -325,6 +325,7 @@ static void inotify_cb( for (;;) { ssize_t r; + struct inotify_event *event; pa_zero(buf); if ((r = pa_read(fd, &buf, sizeof(buf), &type)) <= 0) { @@ -336,23 +337,44 @@ static void inotify_cb( goto fail; } - /* From udev we get the guarantee that the control - * device's ACL is changes last. To avoid races when ACLs - * are changed we hence watch only the control device */ - if (((buf.e.mask & IN_ATTRIB) && pa_startswith(buf.e.name, "controlC"))) - PA_HASHMAP_FOREACH(d, u->devices, state) - if (control_node_belongs_to_device(d, buf.e.name)) - d->need_verify = TRUE; - - /* ALSA doesn't really give us any guarantee on the closing - * order, so let's simply hope */ - if (((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC"))) - PA_HASHMAP_FOREACH(d, u->devices, state) - if (pcm_node_belongs_to_device(d, buf.e.name)) - d->need_verify = TRUE; - - if ((buf.e.mask & (IN_DELETE_SELF|IN_MOVE_SELF))) - deleted = TRUE; + event = &buf.e; + while (r > 0) { + size_t len; + + if ((size_t) r < sizeof(struct inotify_event)) { + pa_log("read() too short."); + goto fail; + } + + len = sizeof(struct inotify_event) + event->len; + + if ((size_t) r < len) { + pa_log("Payload missing."); + goto fail; + } + + /* From udev we get the guarantee that the control + * device's ACL is changed last. To avoid races when ACLs + * are changed we hence watch only the control device */ + if (((event->mask & IN_ATTRIB) && pa_startswith(event->name, "controlC"))) + PA_HASHMAP_FOREACH(d, u->devices, state) + if (control_node_belongs_to_device(d, event->name)) + d->need_verify = TRUE; + + /* ALSA doesn't really give us any guarantee on the closing + * order, so let's simply hope */ + if (((event->mask & IN_CLOSE_WRITE) && pa_startswith(event->name, "pcmC"))) + PA_HASHMAP_FOREACH(d, u->devices, state) + if (pcm_node_belongs_to_device(d, event->name)) + d->need_verify = TRUE; + + /* /dev/snd/ might have been removed */ + if ((event->mask & (IN_DELETE_SELF|IN_MOVE_SELF))) + deleted = TRUE; + + event = (struct inotify_event*) ((uint8_t*) event + len); + r -= len; + } } PA_HASHMAP_FOREACH(d, u->devices, state) -- cgit From d6fb8d10819bebc1cee203de7330cceeafde9fed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 22 Aug 2009 23:10:45 +0200 Subject: udev: check busy status of alsa cards before loading alsa modules and hence initiating profile probing --- src/modules/module-udev-detect.c | 149 ++++++++++++++++++++++++++++++++++----- 1 file changed, 132 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index 55136348..b41b9c0f 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -45,8 +46,7 @@ PA_MODULE_USAGE( struct device { char *path; - pa_bool_t accessible:1; - pa_bool_t need_verify:1; + pa_bool_t need_verify; char *card_name; char *args; uint32_t module; @@ -99,34 +99,150 @@ static const char *path_get_card_id(const char *path) { return e + 5; } +static pa_bool_t is_card_busy(const char *id) { + char *card_path = NULL, *pcm_path = NULL, *sub_status = NULL; + DIR *card_dir = NULL, *pcm_dir = NULL; + FILE *status_file = NULL; + size_t len; + struct dirent *space = NULL, *de; + pa_bool_t busy = FALSE; + int r; + + pa_assert(id); + + card_path = pa_sprintf_malloc("/proc/asound/card%s", id); + + if (!(card_dir = opendir(card_path))) { + pa_log_warn("Failed to open %s: %s", card_path, pa_cstrerror(errno)); + goto fail; + } + + len = offsetof(struct dirent, d_name) + fpathconf(dirfd(card_dir), _PC_NAME_MAX) + 1; + space = pa_xmalloc(len); + + for (;;) { + de = NULL; + + if ((r = readdir_r(card_dir, space, &de)) != 0) { + pa_log_warn("readdir_r() failed: %s", pa_cstrerror(r)); + goto fail; + } + + if (!de) + break; + + if (!pa_startswith(de->d_name, "pcm")) + continue; + + pa_xfree(pcm_path); + pcm_path = pa_sprintf_malloc("%s/%s", card_path, de->d_name); + + if (pcm_dir) + closedir(pcm_dir); + + if (!(pcm_dir = opendir(pcm_path))) { + pa_log_warn("Failed to open %s: %s", pcm_path, pa_cstrerror(errno)); + continue; + } + + for (;;) { + char line[32]; + + if ((r = readdir_r(pcm_dir, space, &de)) != 0) { + pa_log_warn("readdir_r() failed: %s", pa_cstrerror(r)); + goto fail; + } + + if (!de) + break; + + if (!pa_startswith(de->d_name, "sub")) + continue; + + pa_xfree(sub_status); + sub_status = pa_sprintf_malloc("%s/%s/status", pcm_path, de->d_name); + + if (status_file) + fclose(status_file); + + if (!(status_file = fopen(sub_status, "r"))) { + pa_log_warn("Failed to open %s: %s", sub_status, pa_cstrerror(errno)); + continue; + } + + if (!(fgets(line, sizeof(line)-1, status_file))) { + pa_log_warn("Failed to read from %s: %s", sub_status, pa_cstrerror(errno)); + continue; + } + + if (!pa_streq(line, "closed\n")) { + busy = TRUE; + break; + } + } + } + +fail: + + pa_xfree(card_path); + pa_xfree(pcm_path); + pa_xfree(sub_status); + pa_xfree(space); + + if (card_dir) + closedir(card_dir); + + if (pcm_dir) + closedir(pcm_dir); + + if (status_file) + fclose(status_file); + + return busy; +} + static void verify_access(struct userdata *u, struct device *d) { char *cd; pa_card *card; + pa_bool_t accessible; pa_assert(u); pa_assert(d); cd = pa_sprintf_malloc("%s/snd/controlC%s", udev_get_dev_path(u->udev), path_get_card_id(d->path)); - d->accessible = access(cd, R_OK|W_OK) >= 0; + accessible = access(cd, R_OK|W_OK) >= 0; + pa_log_debug("%s is accessible: %s", cd, pa_yes_no(accessible)); - pa_log_info("%s is accessible: %s", cd, pa_yes_no(d->accessible)); pa_xfree(cd); if (d->module == PA_INVALID_INDEX) { - /* If we not loaded, try to load */ + /* If we are not loaded, try to load */ - if (d->accessible) { + if (accessible) { pa_module *m; - - pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args); - m = pa_module_load(u->core, "module-alsa-card", d->args); - - if (m) { - d->module = m->index; - pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name); - } else - pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name); + pa_bool_t busy; + + /* Check if any of the PCM devices that belong to this + * card are currently busy. If they are, don't try to load + * right now, to make sure the probing phase can + * successfully complete. When the current user of the + * device closes it we will get another notification via + * inotify and can then recheck. */ + + busy = is_card_busy(path_get_card_id(d->path)); + pa_log_debug("%s is busy: %s", d->path, pa_yes_no(busy)); + + if (!busy) { + pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args); + m = pa_module_load(u->core, "module-alsa-card", d->args); + + if (m) { + d->module = m->index; + pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name); + } else + pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name); + } } } else { @@ -135,7 +251,7 @@ static void verify_access(struct userdata *u, struct device *d) { * accessible boolean */ if ((card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD))) - pa_card_suspend(card, !d->accessible, PA_SUSPEND_SESSION); + pa_card_suspend(card, !accessible, PA_SUSPEND_SESSION); } } @@ -160,7 +276,6 @@ static void card_changed(struct userdata *u, struct udev_device *dev) { d = pa_xnew0(struct device, 1); d->path = pa_xstrdup(path); - d->accessible = TRUE; d->module = PA_INVALID_INDEX; if (!(t = udev_device_get_property_value(dev, "PULSE_NAME"))) -- cgit From a0f01ddc951694e1d13f44dc3a5d0d3fb2daa142 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Aug 2009 21:49:37 +0200 Subject: port a few things over to use xmalloc and friends instead of low-level libc malloc/free directly --- src/pulsecore/core-util.c | 2 +- src/pulsecore/cpu-arm.c | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 0eb32cc4..1c8c6780 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2223,7 +2223,7 @@ int pa_close_all(int except_fd, ...) { va_end(ap); r = pa_close_allv(p); - free(p); + pa_xfree(p); return r; } diff --git a/src/pulsecore/cpu-arm.c b/src/pulsecore/cpu-arm.c index 5a994b71..453b7848 100644 --- a/src/pulsecore/cpu-arm.c +++ b/src/pulsecore/cpu-arm.c @@ -2,7 +2,7 @@ This file is part of PulseAudio. Copyright 2004-2006 Lennart Poettering - Copyright 2009 Wim Taymans + Copyright 2009 Wim Taymans PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -60,21 +60,20 @@ static char *get_cpuinfo(void) { char *cpuinfo; int n, fd; - if (!(cpuinfo = malloc(MAX_BUFFER))) - return NULL; + cpuinfo = pa_xmalloc(MAX_BUFFER); if ((fd = open("/proc/cpuinfo", O_RDONLY)) < 0) { - free (cpuinfo); + pa_xfree(cpuinfo); return NULL; } - if ((n = read(fd, cpuinfo, MAX_BUFFER-1)) < 0) { - free (cpuinfo); - close (fd); + if ((n = pa_read(fd, cpuinfo, MAX_BUFFER-1)) < 0) { + pa_xfree(cpuinfo); + pa_close(fd); return NULL; } cpuinfo[n] = 0; - close (fd); + pa_close(fd); return cpuinfo; } @@ -102,7 +101,7 @@ void pa_cpu_init_arm (void) { if (arch >= 7) flags |= PA_CPU_ARM_V7; - free (line); + pa_xfree(line); } /* get the CPU features */ if ((line = get_cpuinfo_line (cpuinfo, "Features"))) { @@ -118,10 +117,10 @@ void pa_cpu_init_arm (void) { else if (!strcmp (current, "vfpv3")) flags |= PA_CPU_ARM_VFPV3; - free (current); + pa_xfree(current); } } - free (cpuinfo); + pa_xfree(cpuinfo); pa_log_info ("CPU flags: %s%s%s%s%s%s", (flags & PA_CPU_ARM_V6) ? "V6 " : "", -- cgit From 80c693730365c1a375a5c0e781f38e7f165b37bf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 23 Aug 2009 22:34:42 +0200 Subject: alsa: increase interval between smoother updates exponentially for alsa sources, following the scheme for sinks --- src/modules/alsa/alsa-sink.c | 8 +++----- src/modules/alsa/alsa-source.c | 20 ++++++++++++++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index c3694729..b99ed782 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -733,10 +733,9 @@ static void update_smoother(struct userdata *u) { now1 = pa_rtclock_now(); /* check if the time since the last update is bigger than the interval */ - if (u->last_smoother_update > 0) { + if (u->last_smoother_update > 0) if (u->last_smoother_update + u->smoother_interval > now1) return; - } position = (int64_t) u->write_count - ((int64_t) delay * (int64_t) u->frame_size); @@ -745,11 +744,11 @@ static void update_smoother(struct userdata *u) { now2 = pa_bytes_to_usec((uint64_t) position, &u->sink->sample_spec); + pa_smoother_put(u->smoother, now1, now2); + u->last_smoother_update = now1; /* exponentially increase the update interval up to the MAX limit */ u->smoother_interval = PA_MIN (u->smoother_interval * 2, SMOOTHER_MAX_INTERVAL); - - pa_smoother_put(u->smoother, now1, now2); } static pa_usec_t sink_get_latency(struct userdata *u) { @@ -927,7 +926,6 @@ static int unsuspend(struct userdata *u) { u->first = TRUE; u->since_start = 0; - pa_log_info("Resumed successfully..."); return 0; diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 7da37553..336027a2 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -65,6 +65,9 @@ #define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */ #define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms */ +#define SMOOTHER_MIN_INTERVAL (2*PA_USEC_PER_MSEC) /* 2ms */ +#define SMOOTHER_MAX_INTERVAL (200*PA_USEC_PER_MSEC) /* 200ms */ + #define VOLUME_ACCURACY (PA_VOLUME_NORM/100) struct userdata { @@ -108,6 +111,8 @@ struct userdata { pa_smoother *smoother; uint64_t read_count; + pa_usec_t smoother_interval; + pa_usec_t last_smoother_update; pa_reserve_wrapper *reserve; pa_hook_slot *reserve_slot; @@ -691,15 +696,23 @@ static void update_smoother(struct userdata *u) { now1 = pa_timespec_load(&htstamp); } - position = u->read_count + ((uint64_t) delay * (uint64_t) u->frame_size); - /* Hmm, if the timestamp is 0, then it wasn't set and we take the current time */ if (now1 <= 0) now1 = pa_rtclock_now(); + /* check if the time since the last update is bigger than the interval */ + if (u->last_smoother_update > 0) + if (u->last_smoother_update + u->smoother_interval > now1) + return; + + position = u->read_count + ((uint64_t) delay * (uint64_t) u->frame_size); now2 = pa_bytes_to_usec(position, &u->source->sample_spec); pa_smoother_put(u->smoother, now1, now2); + + u->last_smoother_update = now1; + /* exponentially increase the update interval up to the MAX limit */ + u->smoother_interval = PA_MIN (u->smoother_interval * 2, SMOOTHER_MAX_INTERVAL); } static pa_usec_t source_get_latency(struct userdata *u) { @@ -862,6 +875,8 @@ static int unsuspend(struct userdata *u) { u->read_count = 0; pa_smoother_reset(u->smoother, pa_rtclock_now(), TRUE); + u->smoother_interval = SMOOTHER_MIN_INTERVAL; + u->last_smoother_update = 0; pa_log_info("Resumed successfully..."); @@ -1469,6 +1484,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p 5, pa_rtclock_now(), FALSE); + u->smoother_interval = SMOOTHER_MIN_INTERVAL; dev_id = pa_modargs_get_value( ma, "device_id", -- cgit From 050a3a99e1d151b4f55c89f82073ef33f3399646 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Aug 2009 03:26:56 +0200 Subject: alsa: automatically decrease watermark after a time of stability --- src/modules/alsa/alsa-sink.c | 146 +++++++++++++++++++++++++++++++---------- src/modules/alsa/alsa-source.c | 145 ++++++++++++++++++++++++++++++---------- src/pulsecore/rtpoll.c | 28 ++++---- src/pulsecore/rtpoll.h | 4 ++ 4 files changed, 240 insertions(+), 83 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index b99ed782..07d53880 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -62,14 +62,21 @@ /* #define DEBUG_TIMING */ #define DEFAULT_DEVICE "default" -#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC) /* 2s -- Overall buffer size */ -#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC) /* 20ms -- Fill up when only this much is left in the buffer */ -#define TSCHED_WATERMARK_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- On underrun, increase watermark by this */ -#define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- Sleep at least 10ms on each iteration */ -#define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms -- Wakeup at least this long before the buffer runs empty*/ -#define SMOOTHER_MIN_INTERVAL (2*PA_USEC_PER_MSEC) /* 2ms -- min smoother update interval */ -#define SMOOTHER_MAX_INTERVAL (200*PA_USEC_PER_MSEC) /* 200ms -- max smoother update inteval */ +#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC) /* 2s -- Overall buffer size */ +#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC) /* 20ms -- Fill up when only this much is left in the buffer */ + +#define TSCHED_WATERMARK_INC_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- On underrun, increase watermark by this */ +#define TSCHED_WATERMARK_DEC_STEP_USEC (5*PA_USEC_PER_MSEC) /* 5ms -- When everything's great, decrease watermark by this */ +#define TSCHED_WATERMARK_VERIFY_AFTER_USEC (20*PA_USEC_PER_SEC) /* 20s -- How long after a drop out recheck if things are good now */ +#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (1*PA_USEC_PER_MSEC) /* 3ms -- If the buffer level ever below this theshold, increase the watermark */ +#define TSCHED_WATERMARK_DEC_THRESHOLD_USEC (100*PA_USEC_PER_MSEC) /* 100ms -- If the buffer level didn't drop below this theshold in the verification time, decrease the watermark */ + +#define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- Sleep at least 10ms on each iteration */ +#define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms -- Wakeup at least this long before the buffer runs empty*/ + +#define SMOOTHER_MIN_INTERVAL (2*PA_USEC_PER_MSEC) /* 2ms -- min smoother update interval */ +#define SMOOTHER_MAX_INTERVAL (200*PA_USEC_PER_MSEC) /* 200ms -- max smoother update inteval */ #define VOLUME_ACCURACY (PA_VOLUME_NORM/100) /* don't require volume adjustments to be perfectly correct. don't necessarily extend granularity in software unless the differences get greater than this level */ @@ -99,7 +106,12 @@ struct userdata { hwbuf_unused, min_sleep, min_wakeup, - watermark_step; + watermark_inc_step, + watermark_dec_step, + watermark_inc_threshold, + watermark_dec_threshold; + + pa_usec_t watermark_dec_not_before; unsigned nfragments; pa_memchunk memchunk; @@ -248,6 +260,7 @@ static void fix_min_sleep_wakeup(struct userdata *u) { size_t max_use, max_use_2; pa_assert(u); + pa_assert(u->use_tsched); max_use = u->hwbuf_size - u->hwbuf_unused; max_use_2 = pa_frame_align(max_use/2, &u->sink->sample_spec); @@ -262,6 +275,7 @@ static void fix_min_sleep_wakeup(struct userdata *u) { static void fix_tsched_watermark(struct userdata *u) { size_t max_use; pa_assert(u); + pa_assert(u->use_tsched); max_use = u->hwbuf_size - u->hwbuf_unused; @@ -272,7 +286,7 @@ static void fix_tsched_watermark(struct userdata *u) { u->tsched_watermark = u->min_wakeup; } -static void adjust_after_underrun(struct userdata *u) { +static void increase_watermark(struct userdata *u) { size_t old_watermark; pa_usec_t old_min_latency, new_min_latency; @@ -281,31 +295,64 @@ static void adjust_after_underrun(struct userdata *u) { /* First, just try to increase the watermark */ old_watermark = u->tsched_watermark; - u->tsched_watermark = PA_MIN(u->tsched_watermark * 2, u->tsched_watermark + u->watermark_step); + u->tsched_watermark = PA_MIN(u->tsched_watermark * 2, u->tsched_watermark + u->watermark_inc_step); fix_tsched_watermark(u); if (old_watermark != u->tsched_watermark) { - pa_log_notice("Increasing wakeup watermark to %0.2f ms", - (double) pa_bytes_to_usec(u->tsched_watermark, &u->sink->sample_spec) / PA_USEC_PER_MSEC); + pa_log_info("Increasing wakeup watermark to %0.2f ms", + (double) pa_bytes_to_usec(u->tsched_watermark, &u->sink->sample_spec) / PA_USEC_PER_MSEC); return; } /* Hmm, we cannot increase the watermark any further, hence let's raise the latency */ old_min_latency = u->sink->thread_info.min_latency; - new_min_latency = PA_MIN(old_min_latency * 2, old_min_latency + TSCHED_WATERMARK_STEP_USEC); + new_min_latency = PA_MIN(old_min_latency * 2, old_min_latency + TSCHED_WATERMARK_INC_STEP_USEC); new_min_latency = PA_MIN(new_min_latency, u->sink->thread_info.max_latency); if (old_min_latency != new_min_latency) { - pa_log_notice("Increasing minimal latency to %0.2f ms", - (double) new_min_latency / PA_USEC_PER_MSEC); + pa_log_info("Increasing minimal latency to %0.2f ms", + (double) new_min_latency / PA_USEC_PER_MSEC); pa_sink_set_latency_range_within_thread(u->sink, new_min_latency, u->sink->thread_info.max_latency); - return; } /* When we reach this we're officialy fucked! */ } +static void decrease_watermark(struct userdata *u) { + size_t old_watermark; + pa_usec_t now; + + pa_assert(u); + pa_assert(u->use_tsched); + + now = pa_rtclock_now(); + + if (u->watermark_dec_not_before <= 0) + goto restart; + + if (u->watermark_dec_not_before > now) + return; + + old_watermark = u->tsched_watermark; + + if (u->tsched_watermark < u->watermark_dec_step) + u->tsched_watermark = u->tsched_watermark / 2; + else + u->tsched_watermark = PA_MAX(u->tsched_watermark / 2, u->tsched_watermark - u->watermark_dec_step); + + fix_tsched_watermark(u); + + if (old_watermark != u->tsched_watermark) + pa_log_info("Decreasing wakeup watermark to %0.2f ms", + (double) pa_bytes_to_usec(u->tsched_watermark, &u->sink->sample_spec) / PA_USEC_PER_MSEC); + + /* We don't change the latency range*/ + +restart: + u->watermark_dec_not_before = now + TSCHED_WATERMARK_VERIFY_AFTER_USEC; +} + static void hw_sleep_time(struct userdata *u, pa_usec_t *sleep_usec, pa_usec_t*process_usec) { pa_usec_t usec, wm; @@ -313,6 +360,7 @@ static void hw_sleep_time(struct userdata *u, pa_usec_t *sleep_usec, pa_usec_t*p pa_assert(process_usec); pa_assert(u); + pa_assert(u->use_tsched); usec = pa_sink_get_requested_latency_within_thread(u->sink); @@ -360,7 +408,7 @@ static int try_recover(struct userdata *u, const char *call, int err) { return 0; } -static size_t check_left_to_play(struct userdata *u, size_t n_bytes) { +static size_t check_left_to_play(struct userdata *u, size_t n_bytes, pa_bool_t on_timeout) { size_t left_to_play; /* We use <= instead of < for this check here because an underrun @@ -368,34 +416,55 @@ static size_t check_left_to_play(struct userdata *u, size_t n_bytes) { * it is removed from the buffer. This is particularly important * when block transfer is used. */ - if (n_bytes <= u->hwbuf_size) { + if (n_bytes <= u->hwbuf_size) left_to_play = u->hwbuf_size - n_bytes; + else { + + /* We got a dropout. What a mess! */ + left_to_play = 0; #ifdef DEBUG_TIMING - pa_log_debug("%0.2f ms left to play", (double) pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) / PA_USEC_PER_MSEC); + PA_DEBUG_TRAP; #endif - } else { - left_to_play = 0; + if (!u->first && !u->after_rewind) + if (pa_log_ratelimit()) + pa_log_info("Underrun!"); + } #ifdef DEBUG_TIMING - PA_DEBUG_TRAP; + pa_log_debug("%0.2f ms left to play; inc threshold = %0.2f ms; dec threshold = %0.2f ms", + (double) pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) / PA_USEC_PER_MSEC, + (double) pa_bytes_to_usec(u->watermark_inc_threshold, &u->sink->sample_spec) / PA_USEC_PER_MSEC, + (double) pa_bytes_to_usec(u->watermark_dec_threshold, &u->sink->sample_spec) / PA_USEC_PER_MSEC); #endif + if (u->use_tsched) { + pa_bool_t reset_not_before = TRUE; + if (!u->first && !u->after_rewind) { + if (left_to_play < u->watermark_inc_threshold) + increase_watermark(u); + else if (left_to_play > u->watermark_dec_threshold) { + reset_not_before = FALSE; - if (pa_log_ratelimit()) - pa_log_info("Underrun!"); + /* We decrease the watermark only if have actually + * been woken up by a timeout. If something else woke + * us up it's too easy to fulfill the deadlines... */ - if (u->use_tsched) - adjust_after_underrun(u); + if (on_timeout) + decrease_watermark(u); + } } + + if (reset_not_before) + u->watermark_dec_not_before = 0; } return left_to_play; } -static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled) { +static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled, pa_bool_t on_timeout) { pa_bool_t work_done = TRUE; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_play; @@ -430,7 +499,8 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle pa_log_debug("avail: %lu", (unsigned long) n_bytes); #endif - left_to_play = check_left_to_play(u, n_bytes); + left_to_play = check_left_to_play(u, n_bytes, on_timeout); + on_timeout = FALSE; if (u->use_tsched) @@ -565,7 +635,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle return work_done ? 1 : 0; } -static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled) { +static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled, pa_bool_t on_timeout) { pa_bool_t work_done = FALSE; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_play; @@ -591,7 +661,8 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle } n_bytes = (size_t) n * u->frame_size; - left_to_play = check_left_to_play(u, n_bytes); + left_to_play = check_left_to_play(u, n_bytes, on_timeout); + on_timeout = FALSE; if (u->use_tsched) @@ -1278,15 +1349,16 @@ static void thread_func(void *userdata) { if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) { int work_done; pa_usec_t sleep_usec = 0; + pa_bool_t on_timeout = pa_rtpoll_timer_elapsed(u->rtpoll); if (PA_UNLIKELY(u->sink->thread_info.rewind_requested)) if (process_rewind(u) < 0) goto fail; if (u->use_mmap) - work_done = mmap_write(u, &sleep_usec, revents & POLLOUT); + work_done = mmap_write(u, &sleep_usec, revents & POLLOUT, on_timeout); else - work_done = unix_write(u, &sleep_usec, revents & POLLOUT); + work_done = unix_write(u, &sleep_usec, revents & POLLOUT, on_timeout); if (work_done < 0) goto fail; @@ -1787,7 +1859,6 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size); u->nfragments = nfrags; u->hwbuf_size = u->fragment_size * nfrags; - u->tsched_watermark = pa_usec_to_bytes_round_up(pa_bytes_to_usec_round_up(tsched_watermark, &requested_ss), &u->sink->sample_spec); pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels); pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms", @@ -1798,7 +1869,13 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca pa_sink_set_max_rewind(u->sink, u->hwbuf_size); if (u->use_tsched) { - u->watermark_step = pa_usec_to_bytes(TSCHED_WATERMARK_STEP_USEC, &u->sink->sample_spec); + u->tsched_watermark = pa_usec_to_bytes_round_up(pa_bytes_to_usec_round_up(tsched_watermark, &requested_ss), &u->sink->sample_spec); + + u->watermark_inc_step = pa_usec_to_bytes(TSCHED_WATERMARK_INC_STEP_USEC, &u->sink->sample_spec); + u->watermark_dec_step = pa_usec_to_bytes(TSCHED_WATERMARK_DEC_STEP_USEC, &u->sink->sample_spec); + + u->watermark_inc_threshold = pa_usec_to_bytes_round_up(TSCHED_WATERMARK_INC_THRESHOLD_USEC, &u->sink->sample_spec); + u->watermark_dec_threshold = pa_usec_to_bytes_round_up(TSCHED_WATERMARK_DEC_THRESHOLD_USEC, &u->sink->sample_spec); fix_min_sleep_wakeup(u); fix_tsched_watermark(u); @@ -1812,6 +1889,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca } else pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->hwbuf_size, &ss)); + reserve_update(u); if (update_sw_params(u) < 0) diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 336027a2..165b2e3b 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -59,14 +59,22 @@ /* #define DEBUG_TIMING */ #define DEFAULT_DEVICE "default" -#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC) /* 2s */ -#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC) /* 20ms */ -#define TSCHED_WATERMARK_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */ -#define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */ -#define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms */ -#define SMOOTHER_MIN_INTERVAL (2*PA_USEC_PER_MSEC) /* 2ms */ -#define SMOOTHER_MAX_INTERVAL (200*PA_USEC_PER_MSEC) /* 200ms */ +#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC) /* 2s */ +#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC) /* 20ms */ + +#define TSCHED_WATERMARK_INC_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */ +#define TSCHED_WATERMARK_DEC_STEP_USEC (5*PA_USEC_PER_MSEC) /* 5ms */ +#define TSCHED_WATERMARK_VERIFY_AFTER_USEC (20*PA_USEC_PER_SEC) /* 20s */ +#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (1*PA_USEC_PER_MSEC) /* 3ms */ +#define TSCHED_WATERMARK_DEC_THRESHOLD_USEC (100*PA_USEC_PER_MSEC) /* 100ms */ +#define TSCHED_WATERMARK_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */ + +#define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */ +#define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms */ + +#define SMOOTHER_MIN_INTERVAL (2*PA_USEC_PER_MSEC) /* 2ms */ +#define SMOOTHER_MAX_INTERVAL (200*PA_USEC_PER_MSEC) /* 200ms */ #define VOLUME_ACCURACY (PA_VOLUME_NORM/100) @@ -96,7 +104,12 @@ struct userdata { hwbuf_unused, min_sleep, min_wakeup, - watermark_step; + watermark_inc_step, + watermark_dec_step, + watermark_inc_threshold, + watermark_dec_threshold; + + pa_usec_t watermark_dec_not_before; unsigned nfragments; @@ -241,6 +254,7 @@ static int reserve_monitor_init(struct userdata *u, const char *dname) { static void fix_min_sleep_wakeup(struct userdata *u) { size_t max_use, max_use_2; pa_assert(u); + pa_assert(u->use_tsched); max_use = u->hwbuf_size - u->hwbuf_unused; max_use_2 = pa_frame_align(max_use/2, &u->source->sample_spec); @@ -255,6 +269,7 @@ static void fix_min_sleep_wakeup(struct userdata *u) { static void fix_tsched_watermark(struct userdata *u) { size_t max_use; pa_assert(u); + pa_assert(u->use_tsched); max_use = u->hwbuf_size - u->hwbuf_unused; @@ -265,7 +280,7 @@ static void fix_tsched_watermark(struct userdata *u) { u->tsched_watermark = u->min_wakeup; } -static void adjust_after_overrun(struct userdata *u) { +static void increase_watermark(struct userdata *u) { size_t old_watermark; pa_usec_t old_min_latency, new_min_latency; @@ -274,36 +289,72 @@ static void adjust_after_overrun(struct userdata *u) { /* First, just try to increase the watermark */ old_watermark = u->tsched_watermark; - u->tsched_watermark = PA_MIN(u->tsched_watermark * 2, u->tsched_watermark + u->watermark_step); - + u->tsched_watermark = PA_MIN(u->tsched_watermark * 2, u->tsched_watermark + u->watermark_inc_step); fix_tsched_watermark(u); if (old_watermark != u->tsched_watermark) { - pa_log_notice("Increasing wakeup watermark to %0.2f ms", - (double) pa_bytes_to_usec(u->tsched_watermark, &u->source->sample_spec) / PA_USEC_PER_MSEC); + pa_log_info("Increasing wakeup watermark to %0.2f ms", + (double) pa_bytes_to_usec(u->tsched_watermark, &u->source->sample_spec) / PA_USEC_PER_MSEC); return; } /* Hmm, we cannot increase the watermark any further, hence let's raise the latency */ old_min_latency = u->source->thread_info.min_latency; - new_min_latency = PA_MIN(old_min_latency * 2, old_min_latency + TSCHED_WATERMARK_STEP_USEC); + new_min_latency = PA_MIN(old_min_latency * 2, old_min_latency + TSCHED_WATERMARK_INC_STEP_USEC); new_min_latency = PA_MIN(new_min_latency, u->source->thread_info.max_latency); if (old_min_latency != new_min_latency) { - pa_log_notice("Increasing minimal latency to %0.2f ms", - (double) new_min_latency / PA_USEC_PER_MSEC); + pa_log_info("Increasing minimal latency to %0.2f ms", + (double) new_min_latency / PA_USEC_PER_MSEC); pa_source_set_latency_range_within_thread(u->source, new_min_latency, u->source->thread_info.max_latency); - return; } /* When we reach this we're officialy fucked! */ } +static void decrease_watermark(struct userdata *u) { + size_t old_watermark; + pa_usec_t now; + + pa_assert(u); + pa_assert(u->use_tsched); + + now = pa_rtclock_now(); + + if (u->watermark_dec_not_before <= 0) + goto restart; + + if (u->watermark_dec_not_before > now) + return; + + old_watermark = u->tsched_watermark; + + if (u->tsched_watermark < u->watermark_dec_step) + u->tsched_watermark = u->tsched_watermark / 2; + else + u->tsched_watermark = PA_MAX(u->tsched_watermark / 2, u->tsched_watermark - u->watermark_dec_step); + + fix_tsched_watermark(u); + + if (old_watermark != u->tsched_watermark) + pa_log_info("Decreasing wakeup watermark to %0.2f ms", + (double) pa_bytes_to_usec(u->tsched_watermark, &u->source->sample_spec) / PA_USEC_PER_MSEC); + + /* We don't change the latency range*/ + +restart: + u->watermark_dec_not_before = now + TSCHED_WATERMARK_VERIFY_AFTER_USEC; +} + static pa_usec_t hw_sleep_time(struct userdata *u, pa_usec_t *sleep_usec, pa_usec_t*process_usec) { pa_usec_t wm, usec; + pa_assert(sleep_usec); + pa_assert(process_usec); + pa_assert(u); + pa_assert(u->use_tsched); usec = pa_source_get_requested_latency_within_thread(u->source); @@ -352,7 +403,7 @@ static int try_recover(struct userdata *u, const char *call, int err) { return 0; } -static size_t check_left_to_record(struct userdata *u, size_t n_bytes) { +static size_t check_left_to_record(struct userdata *u, size_t n_bytes, pa_bool_t on_timeout) { size_t left_to_record; size_t rec_space = u->hwbuf_size - u->hwbuf_unused; @@ -361,14 +412,11 @@ static size_t check_left_to_record(struct userdata *u, size_t n_bytes) { * it is removed from the buffer. This is particularly important * when block transfer is used. */ - if (n_bytes <= rec_space) { + if (n_bytes <= rec_space) left_to_record = rec_space - n_bytes; + else { -#ifdef DEBUG_TIMING - pa_log_debug("%0.2f ms left to record", (double) pa_bytes_to_usec(left_to_record, &u->source->sample_spec) / PA_USEC_PER_MSEC); -#endif - - } else { + /* We got a dropout. What a mess! */ left_to_record = 0; #ifdef DEBUG_TIMING @@ -377,15 +425,36 @@ static size_t check_left_to_record(struct userdata *u, size_t n_bytes) { if (pa_log_ratelimit()) pa_log_info("Overrun!"); + } - if (u->use_tsched) - adjust_after_overrun(u); +#ifdef DEBUG_TIMING + pa_log_debug("%0.2f ms left to record", (double) pa_bytes_to_usec(left_to_record, &u->source->sample_spec) / PA_USEC_PER_MSEC); +#endif + + if (u->use_tsched) { + pa_bool_t reset_not_before = TRUE; + + if (left_to_record < u->watermark_inc_threshold) + increase_watermark(u); + else if (left_to_record > u->watermark_dec_threshold) { + reset_not_before = FALSE; + + /* We decrease the watermark only if have actually been + * woken up by a timeout. If something else woke us up + * it's too easy to fulfill the deadlines... */ + + if (on_timeout) + decrease_watermark(u); + } + + if (reset_not_before) + u->watermark_dec_not_before = 0; } return left_to_record; } -static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled) { +static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled, pa_bool_t on_timeout) { pa_bool_t work_done = FALSE; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_record; @@ -417,7 +486,8 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled pa_log_debug("avail: %lu", (unsigned long) n_bytes); #endif - left_to_record = check_left_to_record(u, n_bytes); + left_to_record = check_left_to_record(u, n_bytes, on_timeout); + on_timeout = FALSE; if (u->use_tsched) if (!polled && @@ -543,7 +613,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled return work_done ? 1 : 0; } -static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled) { +static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled, pa_bool_t on_timeout) { int work_done = FALSE; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_record; @@ -570,7 +640,8 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled } n_bytes = (size_t) n * u->frame_size; - left_to_record = check_left_to_record(u, n_bytes); + left_to_record = check_left_to_record(u, n_bytes, on_timeout); + on_timeout = FALSE; if (u->use_tsched) if (!polled && @@ -1158,11 +1229,12 @@ static void thread_func(void *userdata) { if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) { int work_done; pa_usec_t sleep_usec = 0; + pa_bool_t on_timeout = pa_rtpoll_timer_elapsed(u->rtpoll); if (u->use_mmap) - work_done = mmap_read(u, &sleep_usec, revents & POLLIN); + work_done = mmap_read(u, &sleep_usec, revents & POLLIN, on_timeout); else - work_done = unix_read(u, &sleep_usec, revents & POLLIN); + work_done = unix_read(u, &sleep_usec, revents & POLLIN, on_timeout); if (work_done < 0) goto fail; @@ -1632,7 +1704,6 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size); u->nfragments = nfrags; u->hwbuf_size = u->fragment_size * nfrags; - u->tsched_watermark = pa_usec_to_bytes_round_up(pa_bytes_to_usec_round_up(tsched_watermark, &requested_ss), &u->source->sample_spec); pa_cvolume_mute(&u->hardware_volume, u->source->sample_spec.channels); pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms", @@ -1640,7 +1711,13 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC); if (u->use_tsched) { - u->watermark_step = pa_usec_to_bytes(TSCHED_WATERMARK_STEP_USEC, &u->source->sample_spec); + u->tsched_watermark = pa_usec_to_bytes_round_up(pa_bytes_to_usec_round_up(tsched_watermark, &requested_ss), &u->source->sample_spec); + + u->watermark_inc_step = pa_usec_to_bytes(TSCHED_WATERMARK_INC_STEP_USEC, &u->source->sample_spec); + u->watermark_dec_step = pa_usec_to_bytes(TSCHED_WATERMARK_DEC_STEP_USEC, &u->source->sample_spec); + + u->watermark_inc_threshold = pa_usec_to_bytes_round_up(TSCHED_WATERMARK_INC_THRESHOLD_USEC, &u->source->sample_spec); + u->watermark_dec_threshold = pa_usec_to_bytes_round_up(TSCHED_WATERMARK_DEC_THRESHOLD_USEC, &u->source->sample_spec); fix_min_sleep_wakeup(u); fix_tsched_watermark(u); diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c index 42708a8a..666cbc98 100644 --- a/src/pulsecore/rtpoll.c +++ b/src/pulsecore/rtpoll.c @@ -63,6 +63,7 @@ struct pa_rtpoll { pa_bool_t running:1; pa_bool_t rebuild_needed:1; pa_bool_t quit:1; + pa_bool_t timer_elapsed:1; #ifdef DEBUG_TIMING pa_usec_t timestamp; @@ -94,26 +95,14 @@ PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree); pa_rtpoll *pa_rtpoll_new(void) { pa_rtpoll *p; - p = pa_xnew(pa_rtpoll, 1); + p = pa_xnew0(pa_rtpoll, 1); p->n_pollfd_alloc = 32; p->pollfd = pa_xnew(struct pollfd, p->n_pollfd_alloc); p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc); - p->n_pollfd_used = 0; - - pa_zero(p->next_elapse); - p->timer_enabled = FALSE; - - p->running = FALSE; - p->scan_for_dead = FALSE; - p->rebuild_needed = FALSE; - p->quit = FALSE; - - PA_LLIST_HEAD_INIT(pa_rtpoll_item, p->items); #ifdef DEBUG_TIMING p->timestamp = pa_rtclock_now(); - p->slept = p->awake = 0; #endif return p; @@ -229,6 +218,7 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait_op) { pa_assert(!p->running); p->running = TRUE; + p->timer_elapsed = FALSE; /* First, let's do some work */ for (i = p->items; i && i->priority < PA_RTPOLL_NEVER; i = i->next) { @@ -286,7 +276,7 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait_op) { if (p->rebuild_needed) rtpoll_rebuild(p); - memset(&timeout, 0, sizeof(timeout)); + pa_zero(timeout); /* Calculate timeout */ if (wait_op && !p->quit && p->timer_enabled) { @@ -314,9 +304,11 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait_op) { r = ppoll(p->pollfd, p->n_pollfd_used, (!wait_op || p->quit || p->timer_enabled) ? &ts : NULL, NULL); } #else - r = poll(p->pollfd, p->n_pollfd_used, (!wait_op || p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1); + r = poll(p->pollfd, p->n_pollfd_used, (!wait_op || p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1); #endif + p->timer_elapsed = r == 0; + #ifdef DEBUG_TIMING { pa_usec_t now = pa_rtclock_now(); @@ -628,3 +620,9 @@ void pa_rtpoll_quit(pa_rtpoll *p) { p->quit = TRUE; } + +pa_bool_t pa_rtpoll_timer_elapsed(pa_rtpoll *p) { + pa_assert(p); + + return p->timer_elapsed; +} diff --git a/src/pulsecore/rtpoll.h b/src/pulsecore/rtpoll.h index d2d69cad..b2a87fca 100644 --- a/src/pulsecore/rtpoll.h +++ b/src/pulsecore/rtpoll.h @@ -73,6 +73,10 @@ void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, pa_usec_t usec); void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec); void pa_rtpoll_set_timer_disabled(pa_rtpoll *p); +/* Return TRUE when the elapsed timer was the reason for + * the last pa_rtpoll_run() invocation to finish */ +pa_bool_t pa_rtpoll_timer_elapsed(pa_rtpoll *p); + /* A new fd wakeup item for pa_rtpoll */ pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds); void pa_rtpoll_item_free(pa_rtpoll_item *i); -- cgit From 65c3e6576c635c06103fe44a4987b36de81db7a9 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Thu, 30 Jul 2009 03:18:15 -0300 Subject: bluetooth: handle bluetooth source --- src/modules/bluetooth/module-bluetooth-device.c | 181 ++++++++++++++++++++++-- 1 file changed, 168 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 4e23862c..b8a88042 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -1,7 +1,7 @@ /*** This file is part of PulseAudio. - Copyright 2008 Joao Paulo Rechi Vita + Copyright 2008-2009 Joao Paulo Rechi Vita PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -129,6 +129,7 @@ struct hsp_info { enum profile { PROFILE_A2DP, + PROFILE_A2DP_SOURCE, PROFILE_HSP, PROFILE_OFF }; @@ -178,6 +179,7 @@ struct userdata { }; #define FIXED_LATENCY_PLAYBACK_A2DP (25*PA_USEC_PER_MSEC) +#define FIXED_LATENCY_RECORD_A2DP (25*PA_USEC_PER_MSEC) #define FIXED_LATENCY_PLAYBACK_HSP (125*PA_USEC_PER_MSEC) #define FIXED_LATENCY_RECORD_HSP (25*PA_USEC_PER_MSEC) @@ -307,7 +309,7 @@ static int parse_caps(struct userdata *u, uint8_t seid, const struct bt_get_capa pa_log_debug("Payload size is %lu %lu", (unsigned long) bytes_left, (unsigned long) sizeof(*codec)); - if ((u->profile == PROFILE_A2DP && codec->transport != BT_CAPABILITIES_TRANSPORT_A2DP) || + if (((u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) && codec->transport != BT_CAPABILITIES_TRANSPORT_A2DP) || (u->profile == PROFILE_HSP && codec->transport != BT_CAPABILITIES_TRANSPORT_SCO)) { pa_log_error("Got capabilities for wrong codec."); return -1; @@ -340,6 +342,26 @@ static int parse_caps(struct userdata *u, uint8_t seid, const struct bt_get_capa pa_assert(codec->type == BT_A2DP_SBC_SINK); + if (codec->configured && seid == 0) + return codec->seid; + + memcpy(&u->a2dp.sbc_capabilities, codec, sizeof(u->a2dp.sbc_capabilities)); + + } else if (u->profile == PROFILE_A2DP_SOURCE) { + + while (bytes_left > 0) { + if ((codec->type == BT_A2DP_SBC_SOURCE) && !codec->lock) + break; + + bytes_left -= codec->length; + codec = (const codec_capabilities_t*) ((const uint8_t*) codec + codec->length); + } + + if (bytes_left <= 0 || codec->length != sizeof(u->a2dp.sbc_capabilities)) + return -1; + + pa_assert(codec->type == BT_A2DP_SBC_SOURCE); + if (codec->configured && seid == 0) return codec->seid; @@ -368,7 +390,7 @@ static int get_caps(struct userdata *u, uint8_t seid) { msg.getcaps_req.seid = seid; pa_strlcpy(msg.getcaps_req.object, u->path, sizeof(msg.getcaps_req.object)); - if (u->profile == PROFILE_A2DP) + if (u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP; else { pa_assert(u->profile == PROFILE_HSP); @@ -451,7 +473,7 @@ static int setup_a2dp(struct userdata *u) { }; pa_assert(u); - pa_assert(u->profile == PROFILE_A2DP); + pa_assert(u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE); cap = &u->a2dp.sbc_capabilities; @@ -652,8 +674,8 @@ static int set_conf(struct userdata *u) { msg.open_req.h.length = sizeof(msg.open_req); pa_strlcpy(msg.open_req.object, u->path, sizeof(msg.open_req.object)); - msg.open_req.seid = u->profile == PROFILE_A2DP ? u->a2dp.sbc_capabilities.capability.seid : BT_A2DP_SEID_RANGE + 1; - msg.open_req.lock = u->profile == PROFILE_A2DP ? BT_WRITE_LOCK : BT_READ_LOCK | BT_WRITE_LOCK; + msg.open_req.seid = (u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) ? u->a2dp.sbc_capabilities.capability.seid : BT_A2DP_SEID_RANGE + 1; + msg.open_req.lock = (u->profile == PROFILE_A2DP) ? BT_WRITE_LOCK : BT_READ_LOCK | BT_WRITE_LOCK; if (service_send(u, &msg.open_req.h) < 0) return -1; @@ -661,7 +683,7 @@ static int set_conf(struct userdata *u) { if (service_expect(u, &msg.open_rsp.h, sizeof(msg), BT_OPEN, sizeof(msg.open_rsp)) < 0) return -1; - if (u->profile == PROFILE_A2DP ) { + if (u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) { u->sample_spec.format = PA_SAMPLE_S16LE; if (setup_a2dp(u) < 0) @@ -679,7 +701,7 @@ static int set_conf(struct userdata *u) { msg.setconf_req.h.name = BT_SET_CONFIGURATION; msg.setconf_req.h.length = sizeof(msg.setconf_req); - if (u->profile == PROFILE_A2DP) { + if (u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) { memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities, sizeof(u->a2dp.sbc_capabilities)); } else { msg.setconf_req.codec.transport = BT_CAPABILITIES_TRANSPORT_SCO; @@ -697,7 +719,7 @@ static int set_conf(struct userdata *u) { u->link_mtu = msg.setconf_rsp.link_mtu; /* setup SBC encoder now we agree on parameters */ - if (u->profile == PROFILE_A2DP) { + if (u->profile == PROFILE_A2DP || u->profile == PROFILE_A2DP_SOURCE) { setup_sbc(&u->a2dp); u->block_size = @@ -1250,6 +1272,119 @@ static int a2dp_process_render(struct userdata *u) { return ret; } +static int a2dp_process_push(struct userdata *u) { + int ret = 0; + pa_memchunk memchunk; + + pa_assert(u); + pa_assert(u->profile == PROFILE_A2DP_SOURCE); + pa_assert(u->source); + pa_assert(u->read_smoother); + + memchunk.memblock = pa_memblock_new(u->core->mempool, u->block_size); + memchunk.index = memchunk.length = 0; + + for (;;) { + pa_bool_t found_tstamp = FALSE; + pa_usec_t tstamp; + struct a2dp_info *a2dp; + struct rtp_header *header; + struct rtp_payload *payload; + const void *p; + void *d; + ssize_t l; + size_t to_write, to_decode; + unsigned frame_count; + + a2dp_prepare_buffer(u); + + a2dp = &u->a2dp; + header = a2dp->buffer; + payload = (struct rtp_payload*) ((uint8_t*) a2dp->buffer + sizeof(*header)); + + l = pa_read(u->stream_fd, a2dp->buffer, a2dp->buffer_size, &u->stream_write_type); + + if (l <= 0) { + + if (l < 0 && errno == EINTR) + /* Retry right away if we got interrupted */ + continue; + + else if (l < 0 && errno == EAGAIN) + /* Hmm, apparently the socket was not readable, give up for now. */ + break; + + pa_log_error("Failed to read data from socket: %s", l < 0 ? pa_cstrerror(errno) : "EOF"); + ret = -1; + break; + } + + pa_assert((size_t) l <= a2dp->buffer_size); + + u->read_index += (uint64_t) l; + + /* TODO: get timestamp from rtp */ + if (!found_tstamp) { + /* pa_log_warn("Couldn't find SO_TIMESTAMP data in auxiliary recvmsg() data!"); */ + tstamp = pa_rtclock_now(); + } + + pa_smoother_put(u->read_smoother, tstamp, pa_bytes_to_usec(u->read_index, &u->sample_spec)); + pa_smoother_resume(u->read_smoother, tstamp, TRUE); + + p = (uint8_t*) a2dp->buffer + sizeof(*header) + sizeof(*payload); + to_decode = l - sizeof(*header) - sizeof(*payload); + + d = pa_memblock_acquire(memchunk.memblock); + to_write = memchunk.length = pa_memblock_get_length(memchunk.memblock); + + while (PA_LIKELY(to_decode > 0 && to_write > 0)) { + size_t written; + ssize_t decoded; + + decoded = sbc_decode(&a2dp->sbc, + p, to_decode, + d, to_write, + &written); + + if (PA_UNLIKELY(decoded <= 0)) { + pa_log_error("SBC decoding error (%li)", (long) decoded); + pa_memblock_release(memchunk.memblock); + pa_memblock_unref(memchunk.memblock); + return -1; + } + +/* pa_log_debug("SBC: decoded: %lu; written: %lu", (unsigned long) decoded, (unsigned long) written); */ +/* pa_log_debug("SBC: frame_length: %lu; codesize: %lu", (unsigned long) a2dp->frame_length, (unsigned long) a2dp->codesize); */ + + pa_assert_fp((size_t) decoded <= to_decode); + pa_assert_fp((size_t) decoded == a2dp->frame_length); + + pa_assert_fp((size_t) written <= to_write); + pa_assert_fp((size_t) written == a2dp->codesize); + + p = (const uint8_t*) p + decoded; + to_decode -= decoded; + + d = (uint8_t*) d + written; + to_write -= written; + + frame_count++; + } + + pa_memblock_release(memchunk.memblock); + + pa_source_post(u->source, &memchunk); + + ret = 1; + break; + } + + pa_memblock_unref(memchunk.memblock); + + return ret; +} + static void thread_func(void *userdata) { struct userdata *u = userdata; unsigned do_write = 0; @@ -1285,7 +1420,12 @@ static void thread_func(void *userdata) { if (pollfd && (pollfd->revents & POLLIN)) { int n_read; - if ((n_read = hsp_process_push(u)) < 0) + if (u->profile == PROFILE_HSP) + n_read = hsp_process_push(u); + else + n_read = a2dp_process_push(u); + + if (n_read < 0) goto fail; /* We just read something, so we are supposed to write something, too */ @@ -1687,7 +1827,7 @@ static int add_source(struct userdata *u) { data.driver = __FILE__; data.module = u->module; pa_source_new_data_set_sample_spec(&data, &u->sample_spec); - pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP ? "a2dp" : "hsp"); + pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP_SOURCE ? "a2dp_source" : "hsp"); if (u->profile == PROFILE_HSP) pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone"); data.card = u->card; @@ -1712,7 +1852,7 @@ static int add_source(struct userdata *u) { u->source->parent.process_msg = source_process_msg; pa_source_set_fixed_latency(u->source, - (/* u->profile == PROFILE_A2DP ? FIXED_LATENCY_RECORD_A2DP : */ FIXED_LATENCY_RECORD_HSP) + + (u->profile == PROFILE_A2DP_SOURCE ? FIXED_LATENCY_RECORD_A2DP : FIXED_LATENCY_RECORD_HSP) + pa_bytes_to_usec(u->block_size, &u->sample_spec)); } @@ -1809,7 +1949,8 @@ static int init_profile(struct userdata *u) { if (add_sink(u) < 0) r = -1; - if (u->profile == PROFILE_HSP) + if (u->profile == PROFILE_HSP || + u->profile == PROFILE_A2DP_SOURCE) if (add_source(u) < 0) r = -1; @@ -2050,6 +2191,20 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) { pa_hashmap_put(data.profiles, p->name, p); } + if (pa_bluetooth_uuid_has(device->uuids, A2DP_SOURCE_UUID)) { + p = pa_card_profile_new("a2dp_source", _("High Fidelity Capture (A2DP)"), sizeof(enum profile)); + p->priority = 10; + p->n_sinks = 0; + p->n_sources = 1; + p->max_sink_channels = 0; + p->max_source_channels = 2; + + d = PA_CARD_PROFILE_DATA(p); + *d = PROFILE_A2DP_SOURCE; + + pa_hashmap_put(data.profiles, p->name, p); + } + if (pa_bluetooth_uuid_has(device->uuids, HSP_HS_UUID) || pa_bluetooth_uuid_has(device->uuids, HFP_HS_UUID)) { p = pa_card_profile_new("hsp", _("Telephony Duplex (HSP/HFP)"), sizeof(enum profile)); -- cgit From 2772521698caa4ffe7c0c2de174e9d901d7752fd Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Fri, 24 Jul 2009 21:44:36 -0300 Subject: bluetooth: add discover of bluetooth sources --- src/modules/bluetooth/bluetooth-util.c | 26 +++++++++++++++++------ src/modules/bluetooth/bluetooth-util.h | 7 ++++-- src/modules/bluetooth/module-bluetooth-discover.c | 8 +++++-- 3 files changed, 31 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index f576823d..d0c89aab 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -1,7 +1,7 @@ /*** This file is part of PulseAudio. - Copyright 2008 Joao Paulo Rechi Vita + Copyright 2008-2009 Joao Paulo Rechi Vita PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -95,6 +95,7 @@ static pa_bluetooth_device* device_new(const char *path) { d->audio_state = PA_BT_AUDIO_STATE_INVALID; d->audio_sink_state = PA_BT_AUDIO_STATE_INVALID; + d->audio_source_state = PA_BT_AUDIO_STATE_INVALID; d->headset_state = PA_BT_AUDIO_STATE_INVALID; return d; @@ -124,6 +125,7 @@ static pa_bool_t device_is_audio(pa_bluetooth_device *d) { d->device_info_valid && (d->audio_state != PA_BT_AUDIO_STATE_INVALID && (d->audio_sink_state != PA_BT_AUDIO_STATE_INVALID || + d->audio_source_state != PA_BT_AUDIO_STATE_INVALID || d->headset_state != PA_BT_AUDIO_STATE_INVALID)); } @@ -233,6 +235,9 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device } else if (strcasecmp(A2DP_SINK_UUID, value) == 0) { pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.AudioSink", "GetProperties")); send_and_add_to_pending(y, d, m, get_properties_reply); + } else if (strcasecmp(A2DP_SOURCE_UUID, value) == 0) { + pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.AudioSource", "GetProperties")); + send_and_add_to_pending(y, d, m, get_properties_reply); } /* this might eventually be racy if .Audio is not there yet, but the State change will come anyway later, so this call is for cold-detection mostly */ @@ -278,7 +283,7 @@ static int parse_audio_property(pa_bluetooth_discovery *u, int *state, DBusMessa dbus_message_iter_recurse(i, &variant_i); -/* pa_log_debug("Parsing property org.bluez.{Audio|AudioSink|Headset}.%s", key); */ +/* pa_log_debug("Parsing property org.bluez.{Audio|AudioSink|AudioSource|Headset}.%s", key); */ switch (dbus_message_iter_get_arg_type(&variant_i)) { @@ -390,6 +395,9 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) { } else if (dbus_message_has_interface(p->message, "org.bluez.AudioSink")) { if (parse_audio_property(y, &d->audio_sink_state, &dict_i) < 0) goto finish; + } else if (dbus_message_has_interface(p->message, "org.bluez.AudioSource")) { + if (parse_audio_property(y, &d->audio_source_state, &dict_i) < 0) + goto finish; } } @@ -440,8 +448,8 @@ static void found_device(pa_bluetooth_discovery *y, const char* path) { pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Device", "GetProperties")); send_and_add_to_pending(y, d, m, get_properties_reply); - /* Before we read the other properties (Audio, AudioSink, Headset) we wait - * that the UUID is read */ + /* Before we read the other properties (Audio, AudioSink, AudioSource, + * Headset) we wait that the UUID is read */ } static void list_devices_reply(DBusPendingCall *pending, void *userdata) { @@ -616,6 +624,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us } else if (dbus_message_is_signal(m, "org.bluez.Audio", "PropertyChanged") || dbus_message_is_signal(m, "org.bluez.Headset", "PropertyChanged") || dbus_message_is_signal(m, "org.bluez.AudioSink", "PropertyChanged") || + dbus_message_is_signal(m, "org.bluez.AudioSource", "PropertyChanged") || dbus_message_is_signal(m, "org.bluez.Device", "PropertyChanged")) { pa_bluetooth_device *d; @@ -643,6 +652,9 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us } else if (dbus_message_has_interface(m, "org.bluez.AudioSink")) { if (parse_audio_property(y, &d->audio_sink_state, &arg_i) < 0) goto fail; + } else if (dbus_message_has_interface(m, "org.bluez.AudioSource")) { + if (parse_audio_property(y, &d->audio_source_state, &arg_i) < 0) + goto fail; } run_callback(y, d, FALSE); @@ -765,7 +777,8 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) { "type='signal',sender='org.bluez',interface='org.bluez.Device',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'", - "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", NULL) < 0) { + "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", + "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'", NULL) < 0) { pa_log("Failed to add D-Bus matches: %s", err.message); goto fail; } @@ -817,7 +830,8 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) { "type='signal',sender='org.bluez',interface='org.bluez.Device',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'", - "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", NULL); + "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", + "type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'", NULL); dbus_connection_remove_filter(pa_dbus_connection_get(y->connection), filter_cb, y); diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h index f15f2170..e2a0c3d5 100644 --- a/src/modules/bluetooth/bluetooth-util.h +++ b/src/modules/bluetooth/bluetooth-util.h @@ -4,7 +4,7 @@ /*** This file is part of PulseAudio. - Copyright 2008 Joao Paulo Rechi Vita + Copyright 2008-2009 Joao Paulo Rechi Vita PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -53,7 +53,7 @@ struct pa_bluetooth_uuid { PA_LLIST_FIELDS(pa_bluetooth_uuid); }; -/* This enum is shared among Audio, Headset, and AudioSink, although not all values are acceptable in all profiles */ +/* This enum is shared among Audio, Headset, AudioSink, and AudioSource, although not all values are acceptable in all profiles */ typedef enum pa_bt_audio_state { PA_BT_AUDIO_STATE_INVALID = -1, PA_BT_AUDIO_STATE_DISCONNECTED, @@ -84,6 +84,9 @@ struct pa_bluetooth_device { /* AudioSink state */ pa_bt_audio_state_t audio_sink_state; + /* AudioSource state */ + pa_bt_audio_state_t audio_source_state; + /* Headset state */ pa_bt_audio_state_t headset_state; }; diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c index 788fee00..7571e48a 100644 --- a/src/modules/bluetooth/module-bluetooth-discover.c +++ b/src/modules/bluetooth/module-bluetooth-discover.c @@ -1,7 +1,7 @@ /*** This file is part of PulseAudio. - Copyright 2008 Joao Paulo Rechi Vita + Copyright 2008-2009 Joao Paulo Rechi Vita PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -83,8 +83,9 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const mi = pa_hashmap_get(u->hashmap, d->path); + pa_log("dead: %d, device_connected: %d, audio_state: %d, audio_source_state: %d", d->dead, d->device_connected, d->audio_state, d->audio_source_state); if (!d->dead && - d->device_connected > 0 && d->audio_state >= PA_BT_AUDIO_STATE_CONNECTED) { + d->device_connected > 0 && (d->audio_state >= PA_BT_AUDIO_STATE_CONNECTED || d->audio_source_state >= PA_BT_AUDIO_STATE_CONNECTED)) { if (!mi) { pa_module *m = NULL; @@ -116,6 +117,9 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const } #endif + if (d->audio_source_state >= PA_BT_AUDIO_STATE_CONNECTED) + args = pa_sprintf_malloc("%s profile=\"a2dp_source\"", args); + pa_log_debug("Loading module-bluetooth-device %s", args); m = pa_module_load(u->module->core, "module-bluetooth-device", args); pa_xfree(args); -- cgit From ba17ff4101e276f0fdba58861d51af7a0bbcfa3b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Aug 2009 04:02:08 +0200 Subject: build-sys: add missing header files to tarball --- src/Makefile.am | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 2fd9a734..561891ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -836,8 +836,9 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/resampler.c pulsecore/resampler.h \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ pulsecore/sample-util.c pulsecore/sample-util.h \ - pulsecore/cpu-arm.c pulsecore/cpu-x86.c \ - pulsecore/svolume_c.c pulsecore/svolume_arm.c\ + pulsecore/cpu-arm.c pulsecore/cpu-arm.h \ + pulsecore/cpu-x86.c pulsecore/cpu-x86.h \ + pulsecore/svolume_c.c pulsecore/svolume_arm.c \ pulsecore/svolume_mmx.c pulsecore/svolume_sse.c \ pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \ pulsecore/sconv-s16le.c pulsecore/sconv-s16le.h \ -- cgit From 419b071a1eaf96870021b894f837fbf3da74ca80 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Aug 2009 16:35:19 +0200 Subject: detect: recommend module-udev-detect instead of module-hal-detect --- src/modules/module-detect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c index 956fe4c5..b1f24e15 100644 --- a/src/modules/module-detect.c +++ b/src/modules/module-detect.c @@ -50,7 +50,7 @@ PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(TRUE); PA_MODULE_USAGE("just-one="); -PA_MODULE_DEPRECATED("Please use module-hal-detect instead of module-detect!"); +PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-detect!"); static const char* const valid_modargs[] = { "just-one", -- cgit From 57fb77134b319c6f7eaf262c561082fcae49c1a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Aug 2009 17:01:44 +0200 Subject: remap: fix build for non-x86 builds --- src/pulsecore/remap_mmx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/pulsecore/remap_mmx.c b/src/pulsecore/remap_mmx.c index bfcae6c5..00252dac 100644 --- a/src/pulsecore/remap_mmx.c +++ b/src/pulsecore/remap_mmx.c @@ -95,6 +95,7 @@ "4: \n\t" \ " emms \n\t" +#if defined (__i386__) || defined (__amd64__) static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src, unsigned n) { pa_reg_x86 temp; @@ -138,6 +139,7 @@ static void init_remap_mmx (pa_remap_t *m) { pa_log_info("Using MMX mono to stereo remapping"); } } +#endif /* defined (__i386__) || defined (__amd64__) */ void pa_remap_func_init_mmx (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) -- cgit From 457b973ba69d1a417d438b8716389464eb62e049 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 25 Aug 2009 03:47:59 +1000 Subject: Solaris: debug my latest enbugging, take 2 Prevent partially played memchunks from getting lost. If the sink has a memblock, don't leak it when rewinding. --- src/modules/module-solaris.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 71f14071..b0d4db43 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -600,6 +600,10 @@ static void process_rewind(struct userdata *u) { pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes); rewind_nbytes = PA_MIN(u->memchunk.length, rewind_nbytes); u->memchunk.length -= rewind_nbytes; + if (u->memchunk.length <= 0 && u->memchunk.memblock) { + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); + } pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes); } @@ -671,8 +675,8 @@ static void thread_func(void *userdata) { if (len < (size_t) u->minimum_request) break; - if (u->memchunk.length < len) - pa_sink_render(u->sink, len - u->memchunk.length, &u->memchunk); + if (!u->memchunk.length) + pa_sink_render(u->sink, u->sink->thread_info.max_request, &u->memchunk); len = PA_MIN(u->memchunk.length, len); -- cgit From 827ae07c1ec73c8fe48dc4182726c38c3e9c992f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Aug 2009 01:41:34 +0200 Subject: macro: add PA_CLIP_SUB() for saturated subtraction --- src/pulsecore/macro.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index ce88c1b9..87684ad3 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -157,6 +157,17 @@ static inline size_t PA_PAGE_ALIGN(size_t l) { #define PA_ROUND_DOWN(a, b) (((a) / (b)) * (b)) #endif +#ifdef __GNUC__ +#define PA_CLIP_SUB(a, b) \ + __extension__ ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a > _b ? _a - _b : 0; \ + }) +#else +#define PA_CLIP_SUB(a, b) ((a) > (b) ? (a) - (b) : 0) +#endif + /* This type is not intended to be used in exported APIs! Use classic "int" there! */ #ifdef HAVE_STD_BOOL typedef _Bool pa_bool_t; -- cgit From ea4b65b8e0202755dddf20cd5a46dafea86bb29c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Aug 2009 01:42:17 +0200 Subject: loopback: add loopback module for direct connections of sinks and sources --- src/Makefile.am | 11 +- src/modules/module-loopback.c | 706 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 714 insertions(+), 3 deletions(-) create mode 100644 src/modules/module-loopback.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 561891ed..e65662c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1010,8 +1010,8 @@ modlibexec_LTLIBRARIES += \ module-tunnel-source.la \ module-position-event-sounds.la \ module-augment-properties.la \ - module-cork-music-on-phone.la - + module-cork-music-on-phone.la \ + module-loopback.la # See comment at librtp.la above if !OS_IS_WIN32 @@ -1249,7 +1249,8 @@ SYMDEF_FILES = \ modules/module-position-event-sounds-symdef.h \ modules/module-augment-properties-symdef.h \ modules/module-cork-music-on-phone-symdef.h \ - modules/module-console-kit-symdef.h + modules/module-console-kit-symdef.h \ + modules/module-loopback-symdef.h EXTRA_DIST += $(SYMDEF_FILES) BUILT_SOURCES += $(SYMDEF_FILES) @@ -1391,6 +1392,10 @@ module_tunnel_source_la_SOURCES = modules/module-tunnel.c module_tunnel_source_la_LDFLAGS = $(MODULE_LDFLAGS) module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la +module_loopback_la_SOURCES = modules/module-loopback.c +module_loopback_la_LDFLAGS = $(MODULE_LDFLAGS) +module_loopback_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la + # X11 module_x11_bell_la_SOURCES = modules/x11/module-x11-bell.c diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c new file mode 100644 index 00000000..8b22fa1a --- /dev/null +++ b/src/modules/module-loopback.c @@ -0,0 +1,706 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Intel Corporation + Contributor: Pierre-Louis Bossart + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "module-loopback-symdef.h" + +PA_MODULE_AUTHOR("Pierre-Louis Bossart"); +PA_MODULE_DESCRIPTION("Loopback from source to sink"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_USAGE( + "source= " + "sink= " + "adjust_time= " + "latency_msec= " + "format= " + "rate= " + "channels= " + "channel_map="); + +#define DEFAULT_LATENCY_MSEC 200 + +#define MEMBLOCKQ_MAXLENGTH (1024*1024*16) + +#define DEFAULT_ADJUST_TIME_USEC (10*PA_USEC_PER_SEC) + +struct userdata { + pa_core *core; + pa_module *module; + + pa_sink_input *sink_input; + pa_source_output *source_output; + + pa_asyncmsgq *asyncmsgq; + pa_memblockq *memblockq; + + pa_rtpoll_item *rtpoll_item_read, *rtpoll_item_write; + + pa_time_event *time_event; + pa_usec_t adjust_time; + + int64_t recv_counter; + int64_t send_counter; + + size_t skip; + pa_usec_t latency; + + pa_bool_t in_pop; + size_t min_memblockq_length; + + struct { + int64_t send_counter; + size_t source_output_buffer; + pa_usec_t source_latency; + + int64_t recv_counter; + size_t sink_input_buffer; + pa_usec_t sink_latency; + + size_t min_memblockq_length; + size_t max_request; + } latency_snapshot; +}; + +static const char* const valid_modargs[] = { + "source", + "sink", + "latency", + "format", + "rate", + "channels", + "channel_map", + NULL, +}; + +enum { + SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX, + SINK_INPUT_MESSAGE_REWIND, + SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, + SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED +}; + +enum { + SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT +}; + +/* Called from main context */ +static void teardown(struct userdata *u) { + pa_assert(u); + pa_assert_ctl_context(); + + if (u->sink_input) + pa_sink_input_unlink(u->sink_input); + + if (u->source_output) + pa_source_output_unlink(u->source_output); + + if (u->sink_input) { + pa_sink_input_unref(u->sink_input); + u->sink_input = NULL; + } + + if (u->source_output) { + pa_source_output_unref(u->source_output); + u->source_output = NULL; + } +} + +/* Called from main context */ +static void adjust_rates(struct userdata *u) { + size_t buffer, fs; + uint32_t old_rate, base_rate, new_rate; + pa_usec_t buffer_latency; + + pa_assert(u); + pa_assert_ctl_context(); + + pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); + pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); + + buffer = + u->latency_snapshot.sink_input_buffer + + u->latency_snapshot.source_output_buffer; + + if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter) + buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter); + else + buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter)); + + buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec); + + pa_log_info("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms", + (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC, + (double) buffer_latency / PA_USEC_PER_MSEC, + (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC, + ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC); + + pa_log_info("Should buffer %lu bytes, buffered at minimum %lu bytes", + u->latency_snapshot.max_request*2, + u->latency_snapshot.min_memblockq_length); + + fs = pa_frame_size(&u->sink_input->sample_spec); + old_rate = u->sink_input->sample_spec.rate; + base_rate = u->source_output->sample_spec.rate; + + if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2) + new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time; + else + new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time; + + pa_log_info("Old rate %lu Hz, new rate %lu Hz", (unsigned long) old_rate, (unsigned long) new_rate); + + pa_sink_input_set_rate(u->sink_input, new_rate); + + pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time); +} + +/* Called from main context */ +static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) { + struct userdata *u = userdata; + + pa_assert(u); + pa_assert(a); + pa_assert(u->time_event == e); + + adjust_rates(u); +} + +/* Called from input thread context */ +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { + struct userdata *u; + pa_memchunk copy; + + pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); + pa_assert_se(u = o->userdata); + + if (u->skip > chunk->length) { + u->skip -= chunk->length; + return; + } + + if (u->skip > 0) { + copy = *chunk; + copy.index += u->skip; + copy.length -= u->skip; + u->skip = 0; + + chunk = © + } + + pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, chunk, NULL); + u->send_counter += (int64_t) chunk->length; +} + +/* Called from input thread context */ +static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) { + struct userdata *u; + + pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); + pa_assert_se(u = o->userdata); + + pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL); + u->send_counter -= (int64_t) nbytes; +} + +/* Called from output thread context */ +static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE_OUTPUT(obj)->userdata; + + switch (code) { + + case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: { + size_t length; + + length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq); + + u->latency_snapshot.send_counter = u->send_counter; + u->latency_snapshot.source_output_buffer = u->source_output->thread_info.resampler ? pa_resampler_result(u->source_output->thread_info.resampler, length) : length; + u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source); + + return 0; + } + } + + return pa_source_output_process_msg(obj, code, data, offset, chunk); +} + +/* Called from output thread context */ +static void source_output_attach_cb(pa_source_output *o) { + struct userdata *u; + + pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); + pa_assert_se(u = o->userdata); + + u->rtpoll_item_write = pa_rtpoll_item_new_asyncmsgq_write( + o->source->thread_info.rtpoll, + PA_RTPOLL_LATE, + u->asyncmsgq); +} + +/* Called from output thread context */ +static void source_output_detach_cb(pa_source_output *o) { + struct userdata *u; + + pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); + pa_assert_se(u = o->userdata); + + if (u->rtpoll_item_write) { + pa_rtpoll_item_free(u->rtpoll_item_write); + u->rtpoll_item_write = NULL; + } +} + +/* Called from output thread context */ +static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) { + struct userdata *u; + + pa_source_output_assert_ref(o); + pa_source_output_assert_io_context(o); + pa_assert_se(u = o->userdata); + + if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) { + + u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source), + u->latency), + &o->sample_spec); + + pa_log_info("Skipping %lu bytes", (unsigned long) u->skip); + } +} + +/* Called from main thread */ +static void source_output_kill_cb(pa_source_output *o) { + struct userdata *u; + + pa_source_output_assert_ref(o); + pa_assert_ctl_context(); + pa_assert_se(u = o->userdata); + + teardown(u); + pa_module_unload_request(u->module, TRUE); +} + +/* Called from output thread context */ +static void update_min_memblockq_length(struct userdata *u) { + size_t length; + + pa_assert(u); + pa_sink_input_assert_io_context(u->sink_input); + + length = pa_memblockq_get_length(u->memblockq); + + if (u->min_memblockq_length == (size_t) -1 || + length < u->min_memblockq_length) + u->min_memblockq_length = length; +} + +/* Called from output thread context */ +static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); + pa_assert_se(u = i->userdata); + pa_assert(chunk); + + u->in_pop = TRUE; + while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0) + ; + u->in_pop = FALSE; + + if (pa_memblockq_peek(u->memblockq, chunk) < 0) { + pa_log_info("Coud not peek into queue"); + return -1; + } + + chunk->length = PA_MIN(chunk->length, nbytes); + pa_memblockq_drop(u->memblockq, chunk->length); + + update_min_memblockq_length(u); + + return 0; +} + +/* Called from output thread context */ +static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); + pa_assert_se(u = i->userdata); + + pa_memblockq_rewind(u->memblockq, nbytes); +} + +/* Called from output thread context */ +static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK_INPUT(obj)->userdata; + + switch (code) { + + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: { + pa_usec_t *r = data; + + pa_sink_input_assert_io_context(u->sink_input); + + *r = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->sink_input->sample_spec); + + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + break; + } + + case SINK_INPUT_MESSAGE_POST: + + pa_sink_input_assert_io_context(u->sink_input); + + if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state)) + pa_memblockq_push_align(u->memblockq, chunk); + else + pa_memblockq_flush_write(u->memblockq); + + update_min_memblockq_length(u); + + /* Is this the end of an underrun? Then let's start things + * right-away */ + if (!u->in_pop && + u->sink_input->thread_info.underrun_for > 0 && + pa_memblockq_is_readable(u->memblockq)) { + + pa_log_debug("Requesting rewind due to end of underrun."); + pa_sink_input_request_rewind(u->sink_input, + (size_t) (u->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : u->sink_input->thread_info.underrun_for), + FALSE, TRUE, FALSE); + } + + u->recv_counter += (int64_t) chunk->length; + + return 0; + + case SINK_INPUT_MESSAGE_REWIND: + + pa_sink_input_assert_io_context(u->sink_input); + + if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state)) + pa_memblockq_seek(u->memblockq, -offset, PA_SEEK_RELATIVE, TRUE); + else + pa_memblockq_flush_write(u->memblockq); + + u->recv_counter -= offset; + + update_min_memblockq_length(u); + + return 0; + + case SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT: { + size_t length; + + update_min_memblockq_length(u); + + length = pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq); + + u->latency_snapshot.recv_counter = u->recv_counter; + u->latency_snapshot.sink_input_buffer = + pa_memblockq_get_length(u->memblockq) + + (u->sink_input->thread_info.resampler ? pa_resampler_request(u->sink_input->thread_info.resampler, length) : length); + u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink); + + u->latency_snapshot.max_request = pa_sink_input_get_max_request(u->sink_input); + + u->latency_snapshot.min_memblockq_length = u->min_memblockq_length; + u->min_memblockq_length = (size_t) -1; + + return 0; + } + + case SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED: { + /* This message is sent from the IO thread to the main + * thread! So don't be confused. All the user cases above + * are executed in thread context, but this one is not! */ + + pa_assert_ctl_context(); + + adjust_rates(u); + return 0; + } + } + + return pa_sink_input_process_msg(obj, code, data, offset, chunk); +} + +/* Called from output thread context */ +static void sink_input_attach_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); + pa_assert_se(u = i->userdata); + + u->rtpoll_item_read = pa_rtpoll_item_new_asyncmsgq_read( + i->sink->thread_info.rtpoll, + PA_RTPOLL_LATE, + u->asyncmsgq); + + pa_memblockq_set_prebuf(u->memblockq, pa_sink_input_get_max_request(i)*2); + pa_memblockq_set_maxrewind(u->memblockq, pa_sink_input_get_max_rewind(i)); + + u->min_memblockq_length = (size_t) -1; +} + +/* Called from output thread context */ +static void sink_input_detach_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); + pa_assert_se(u = i->userdata); + + if (u->rtpoll_item_read) { + pa_rtpoll_item_free(u->rtpoll_item_read); + u->rtpoll_item_read = NULL; + } +} + +/* Called from output thread context */ +static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); + pa_assert_se(u = i->userdata); + + pa_memblockq_set_maxrewind(u->memblockq, nbytes); +} + +/* Called from output thread context */ +static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_sink_input_assert_io_context(i); + pa_assert_se(u = i->userdata); + + pa_memblockq_set_prebuf(u->memblockq, nbytes*2); + pa_log_info("Max request changed"); + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_MAX_REQUEST_CHANGED, NULL, 0, NULL, NULL); +} + +/* Called from main thread */ +static void sink_input_kill_cb(pa_sink_input *i) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + pa_assert_se(u = i->userdata); + + teardown(u); + pa_module_unload_request(u->module, TRUE); +} + +int pa__init(pa_module *m) { + pa_modargs *ma = NULL; + struct userdata *u; + pa_sink *sink; + pa_sink_input_new_data sink_input_data; + pa_source *source; + pa_source_output_new_data source_output_data; + uint32_t latency_msec; + pa_sample_spec ss; + pa_channel_map map; + pa_memchunk silence; + uint32_t adjust_time_sec; + + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments"); + goto fail; + } + + if (!(source = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) { + pa_log("No such source."); + goto fail; + } + + if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK))) { + pa_log("No such sink."); + goto fail; + } + + ss = sink->sample_spec; + map = sink->channel_map; + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { + pa_log("Invalid sample format specification or channel map"); + goto fail; + } + + latency_msec = DEFAULT_LATENCY_MSEC; + if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 1 || latency_msec > 2000) { + pa_log("Invalid latency specification"); + goto fail; + } + + m->userdata = u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC; + + adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC; + if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) { + pa_log("Failed to parse adjust_time value"); + goto fail; + } + + if (adjust_time_sec != DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC) + u->adjust_time = adjust_time_sec * PA_USEC_PER_SEC; + else + u->adjust_time = DEFAULT_ADJUST_TIME_USEC; + + pa_sink_input_new_data_init(&sink_input_data); + sink_input_data.driver = __FILE__; + sink_input_data.module = m; + sink_input_data.sink = sink; + pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Loopback of %s", pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)); + pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract"); + pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); + pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); + + pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, PA_SINK_INPUT_VARIABLE_RATE); + pa_sink_input_new_data_done(&sink_input_data); + + if (!u->sink_input) + goto fail; + + u->sink_input->parent.process_msg = sink_input_process_msg_cb; + u->sink_input->pop = sink_input_pop_cb; + u->sink_input->process_rewind = sink_input_process_rewind_cb; + u->sink_input->kill = sink_input_kill_cb; + u->sink_input->attach = sink_input_attach_cb; + u->sink_input->detach = sink_input_detach_cb; + u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; + u->sink_input->update_max_request = sink_input_update_max_request_cb; + u->sink_input->userdata = u; + + pa_sink_input_set_requested_latency(u->sink_input, u->latency/3); + + pa_source_output_new_data_init(&source_output_data); + source_output_data.driver = __FILE__; + source_output_data.module = m; + source_output_data.source = source; + pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Loopback to %s", pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)); + pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract"); + pa_source_output_new_data_set_sample_spec(&source_output_data, &ss); + pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); + + pa_source_output_new(&u->source_output, m->core, &source_output_data, 0); + pa_source_output_new_data_done(&source_output_data); + + if (!u->source_output) + goto fail; + + u->source_output->parent.process_msg = source_output_process_msg_cb; + u->source_output->push = source_output_push_cb; + u->source_output->process_rewind = source_output_process_rewind_cb; + u->source_output->kill = source_output_kill_cb; + u->source_output->attach = source_output_attach_cb; + u->source_output->detach = source_output_detach_cb; + u->source_output->state_change = source_output_state_change_cb; + u->source_output->userdata = u; + + pa_source_output_set_requested_latency(u->source_output, u->latency/3); + + pa_sink_input_get_silence(u->sink_input, &silence); + u->memblockq = pa_memblockq_new( + 0, /* idx */ + MEMBLOCKQ_MAXLENGTH, /* maxlength */ + MEMBLOCKQ_MAXLENGTH, /* tlength */ + pa_frame_size(&ss), /* base */ + 0, /* prebuf */ + 0, /* minreq */ + 0, /* maxrewind */ + &silence); /* silence frame */ + pa_memblock_unref(silence.memblock); + + u->asyncmsgq = pa_asyncmsgq_new(0); + + pa_sink_input_put(u->sink_input); + pa_source_output_put(u->source_output); + + if (u->adjust_time > 0) + u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u); + + pa_modargs_free(ma); + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(m); + + return -1; +} + +void pa__done(pa_module*m) { + struct userdata *u; + + pa_assert(m); + + if (!(u = m->userdata)) + return; + + teardown(u); + + if (u->memblockq) + pa_memblockq_free(u->memblockq); + + if (u->asyncmsgq) + pa_asyncmsgq_unref(u->asyncmsgq); + + if (u->time_event) + u->core->mainloop->time_free(u->time_event); + + pa_xfree(u); +} -- cgit From 99d3e6b744c2a45af1e8e2cf7219e8c6908fca94 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Aug 2009 01:51:29 +0200 Subject: combine: store adjust time in usec --- src/modules/module-combine.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index e90ef11c..4a57ce2d 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -58,7 +58,7 @@ PA_MODULE_USAGE( "sink_name= " "sink_properties= " "slaves= " - "adjust_time= " + "adjust_time= " "resample_method= " "format= " "rate= " @@ -69,7 +69,7 @@ PA_MODULE_USAGE( #define MEMBLOCKQ_MAXLENGTH (1024*1024*16) -#define DEFAULT_ADJUST_TIME 10 +#define DEFAULT_ADJUST_TIME_USEC (10*PA_USEC_PER_SEC) #define BLOCK_USEC (PA_USEC_PER_MSEC * 200) @@ -91,7 +91,6 @@ struct output { pa_sink *sink; pa_sink_input *sink_input; - pa_bool_t ignore_state_change; pa_asyncmsgq *inq, /* Message queue from the sink thread to this sink input */ @@ -121,7 +120,7 @@ struct userdata { pa_rtpoll *rtpoll; pa_time_event *time_event; - uint32_t adjust_time; + pa_usec_t adjust_time; pa_bool_t automatic; pa_bool_t auto_desc; @@ -221,9 +220,9 @@ static void adjust_rates(struct userdata *u) { continue; if (o->total_latency < target_latency) - r -= (uint32_t) ((((double) (target_latency - o->total_latency))/(double)u->adjust_time)*(double)r/PA_USEC_PER_SEC); + r -= (uint32_t) ((((double) (target_latency - o->total_latency))/(double)u->adjust_time)*(double)r); else if (o->total_latency > target_latency) - r += (uint32_t) ((((double) (o->total_latency - target_latency))/(double)u->adjust_time)*(double)r/PA_USEC_PER_SEC); + r += (uint32_t) ((((double) (o->total_latency - target_latency))/(double)u->adjust_time)*(double)r); if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) { pa_log_warn("[%s] sample rates too different, not adjusting (%u vs. %u).", o->sink_input->sink->name, base_rate, r); @@ -246,7 +245,7 @@ static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct tim adjust_rates(u); - pa_core_rttime_restart(u->core, e, pa_rtclock_now() + u->adjust_time * PA_USEC_PER_SEC); + pa_core_rttime_restart(u->core, e, pa_rtclock_now() + u->adjust_time); } static void process_render_null(struct userdata *u, pa_usec_t now) { @@ -1105,6 +1104,7 @@ int pa__init(pa_module*m) { struct output *o; uint32_t idx; pa_sink_new_data data; + uint32_t adjust_time_sec; pa_assert(m); @@ -1123,16 +1123,10 @@ int pa__init(pa_module*m) { m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; - u->adjust_time = DEFAULT_ADJUST_TIME; u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); u->resample_method = resample_method; u->outputs = pa_idxset_new(NULL, NULL); - u->sink_put_slot = u->sink_unlink_slot = u->sink_state_changed_slot = NULL; - PA_LLIST_HEAD_INIT(struct output, u->thread_info.active_outputs); - pa_atomic_store(&u->thread_info.running, FALSE); - u->thread_info.in_null_mode = FALSE; - u->thread_info.counter = 0; u->thread_info.smoother = pa_smoother_new( PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, @@ -1142,11 +1136,17 @@ int pa__init(pa_module*m) { 0, FALSE); - if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) { + adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC; + if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) { pa_log("Failed to parse adjust_time value"); goto fail; } + if (adjust_time_sec != DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC) + u->adjust_time = adjust_time_sec * PA_USEC_PER_SEC; + else + u->adjust_time = DEFAULT_ADJUST_TIME_USEC; + slaves = pa_modargs_get_value(ma, "slaves", NULL); u->automatic = !slaves; @@ -1315,7 +1315,7 @@ int pa__init(pa_module*m) { output_verify(o); if (u->adjust_time > 0) - u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time * PA_USEC_PER_SEC, time_callback, u); + u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u); pa_modargs_free(ma); -- cgit From d909f593894cef45040ce2135368edd4a1861ee7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Aug 2009 01:52:02 +0200 Subject: loopback: make sure a monitor can't be looped back to its sink --- src/modules/module-loopback.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src') diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index 8b22fa1a..ac7029ae 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -322,6 +322,17 @@ static void source_output_kill_cb(pa_source_output *o) { pa_module_unload_request(u->module, TRUE); } +/* Called from main thread */ +static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) { + struct userdata *u; + + pa_source_output_assert_ref(o); + pa_assert_ctl_context(); + pa_assert_se(u = o->userdata); + + return dest != u->sink_input->sink->monitor_source; +} + /* Called from output thread context */ static void update_min_memblockq_length(struct userdata *u) { size_t length; @@ -539,6 +550,20 @@ static void sink_input_kill_cb(pa_sink_input *i) { pa_module_unload_request(u->module, TRUE); } +/* Called from main thread */ +static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + pa_assert_se(u = i->userdata); + + if (!u->source_output->source->monitor_of) + return TRUE; + + return dest != u->source_output->source->monitor_of; +} + int pa__init(pa_module *m) { pa_modargs *ma = NULL; struct userdata *u; @@ -621,6 +646,7 @@ int pa__init(pa_module *m) { u->sink_input->detach = sink_input_detach_cb; u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; u->sink_input->update_max_request = sink_input_update_max_request_cb; + u->sink_input->may_move_to = sink_input_may_move_to_cb; u->sink_input->userdata = u; pa_sink_input_set_requested_latency(u->sink_input, u->latency/3); @@ -647,6 +673,7 @@ int pa__init(pa_module *m) { u->source_output->attach = source_output_attach_cb; u->source_output->detach = source_output_detach_cb; u->source_output->state_change = source_output_state_change_cb; + u->source_output->may_move_to = source_output_may_move_to_cb; u->source_output->userdata = u; pa_source_output_set_requested_latency(u->source_output, u->latency/3); -- cgit From 4614412f94eef8ed65076c6fc76b463547f8f072 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Aug 2009 02:17:37 +0200 Subject: loopback: update description and icons when moving loopback streams --- src/modules/module-loopback.c | 54 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index ac7029ae..d9edbac0 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -333,6 +333,26 @@ static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *de return dest != u->sink_input->sink->monitor_source; } +/* Called from main thread */ +static void source_output_moving_cb(pa_source_output *o, pa_source *dest) { + pa_proplist *p; + const char *n; + struct userdata *u; + + pa_source_output_assert_ref(o); + pa_assert_ctl_context(); + pa_assert_se(u = o->userdata); + + p = pa_proplist_new(); + pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback of %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION))); + + if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME))) + pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n); + + pa_sink_input_update_proplist(u->sink_input, PA_UPDATE_REPLACE, p); + pa_proplist_free(p); +} + /* Called from output thread context */ static void update_min_memblockq_length(struct userdata *u) { size_t length; @@ -550,6 +570,26 @@ static void sink_input_kill_cb(pa_sink_input *i) { pa_module_unload_request(u->module, TRUE); } +/* Called from main thread */ +static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { + struct userdata *u; + pa_proplist *p; + const char *n; + + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + pa_assert_se(u = i->userdata); + + p = pa_proplist_new(); + pa_proplist_setf(p, PA_PROP_MEDIA_NAME, "Loopback to %s", pa_strnull(pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION))); + + if ((n = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_ICON_NAME))) + pa_proplist_sets(p, PA_PROP_MEDIA_ICON_NAME, n); + + pa_source_output_update_proplist(u->source_output, PA_UPDATE_REPLACE, p); + pa_proplist_free(p); +} + /* Called from main thread */ static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) { struct userdata *u; @@ -576,6 +616,7 @@ int pa__init(pa_module *m) { pa_channel_map map; pa_memchunk silence; uint32_t adjust_time_sec; + const char *n; pa_assert(m); @@ -627,7 +668,11 @@ int pa__init(pa_module *m) { sink_input_data.driver = __FILE__; sink_input_data.module = m; sink_input_data.sink = sink; - pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Loopback of %s", pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)); + + pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Loopback of %s", + pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION))); + if ((n = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME))) + pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ICON_NAME, n); pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); @@ -647,6 +692,7 @@ int pa__init(pa_module *m) { u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; u->sink_input->update_max_request = sink_input_update_max_request_cb; u->sink_input->may_move_to = sink_input_may_move_to_cb; + u->sink_input->moving = sink_input_moving_cb; u->sink_input->userdata = u; pa_sink_input_set_requested_latency(u->sink_input, u->latency/3); @@ -655,7 +701,10 @@ int pa__init(pa_module *m) { source_output_data.driver = __FILE__; source_output_data.module = m; source_output_data.source = source; - pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Loopback to %s", pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)); + pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Loopback to %s", + pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION))); + if ((n = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME))) + pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ICON_NAME, n); pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "abstract"); pa_source_output_new_data_set_sample_spec(&source_output_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); @@ -674,6 +723,7 @@ int pa__init(pa_module *m) { u->source_output->detach = source_output_detach_cb; u->source_output->state_change = source_output_state_change_cb; u->source_output->may_move_to = source_output_may_move_to_cb; + u->source_output->moving = source_output_moving_cb; u->source_output->userdata = u; pa_source_output_set_requested_latency(u->source_output, u->latency/3); -- cgit From 368c3e3f904c7dba5ba8ba4b17d76ba49b40c6ae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Aug 2009 20:05:19 +0200 Subject: loopback: quieten gcc on 32bit --- src/modules/module-loopback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index d9edbac0..6e4f66d5 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -172,7 +172,7 @@ static void adjust_rates(struct userdata *u) { (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC, ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC); - pa_log_info("Should buffer %lu bytes, buffered at minimum %lu bytes", + pa_log_info("Should buffer %zu bytes, buffered at minimum %zu bytes", u->latency_snapshot.max_request*2, u->latency_snapshot.min_memblockq_length); -- cgit From 4e1298d7c7a5dc01c2ef6e76d1520f2b04cb167a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Aug 2009 20:05:48 +0200 Subject: llist: add PA_LLIST_FOREACH_SAFE macro for iteration that allows deleting --- src/pulsecore/llist.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h index 58b51c68..27f174a9 100644 --- a/src/pulsecore/llist.h +++ b/src/pulsecore/llist.h @@ -107,4 +107,7 @@ #define PA_LLIST_FOREACH(i,head) \ for (i = (head); i; i = i->next) +#define PA_LLIST_FOREACH_SAFE(i,n,head) \ + for (i = (head); i && ((n = i->next), 1); i = n) + #endif -- cgit From 34829eb07f4b76f72d8dc504f7e0dabc2e0b0744 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Aug 2009 20:06:24 +0200 Subject: pdispatch: add missing commands to command table --- src/pulsecore/pdispatch.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index fc8ce76f..7d4e8c46 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -169,7 +169,7 @@ static const char *command_names[PA_COMMAND_MAX] = { /* Supported since protocol v14 (0.9.12) */ [PA_COMMAND_EXTENSION] = "EXTENSION", - + /* Supported since protocol v15 (0.9.15) */ [PA_COMMAND_GET_CARD_INFO] = "GET_CARD_INFO", [PA_COMMAND_GET_CARD_INFO_LIST] = "GET_CARD_INFO_LIST", [PA_COMMAND_SET_CARD_PROFILE] = "SET_CARD_PROFILE", @@ -180,7 +180,11 @@ static const char *command_names[PA_COMMAND_MAX] = { /* SERVER->CLIENT */ [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = "PLAYBACK_BUFFER_ATTR_CHANGED", - [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = "RECORD_BUFFER_ATTR_CHANGED" + [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = "RECORD_BUFFER_ATTR_CHANGED", + + /* Supported since protocol v16 (0.9.16) */ + [PA_COMMAND_SET_SINK_PORT] = "SET_SINK_PORT", + [PA_COMMAND_SET_SOURCE_PORT] = "SET_SOURCE_PORT" }; #endif -- cgit From 44b798237a62707ec5f8b1fd70bb7e6f7efc509c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Aug 2009 20:07:04 +0200 Subject: pdispatch: various modernizations --- src/pulsecore/pdispatch.c | 28 ++++++++++++---------------- src/pulsecore/pdispatch.h | 6 +++--- 2 files changed, 15 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index 7d4e8c46..f15466ce 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -207,10 +207,10 @@ struct pa_pdispatch { const pa_pdispatch_cb_t *callback_table; unsigned n_commands; PA_LLIST_HEAD(struct reply_info, replies); - pa_pdispatch_drain_callback drain_callback; + pa_pdispatch_drain_cb_t drain_callback; void *drain_userdata; const pa_creds *creds; - pa_bool_t use_rtclock:1; + pa_bool_t use_rtclock; }; static void reply_info_free(struct reply_info *r) { @@ -229,19 +229,16 @@ static void reply_info_free(struct reply_info *r) { pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, pa_bool_t use_rtclock, const pa_pdispatch_cb_t *table, unsigned entries) { pa_pdispatch *pd; - pa_assert(mainloop); + pa_assert(mainloop); pa_assert((entries && table) || (!entries && !table)); - pd = pa_xnew(pa_pdispatch, 1); + pd = pa_xnew0(pa_pdispatch, 1); PA_REFCNT_INIT(pd); pd->mainloop = mainloop; pd->callback_table = table; pd->n_commands = entries; PA_LLIST_HEAD_INIT(struct reply_info, pd->replies); - pd->drain_callback = NULL; - pd->drain_userdata = NULL; - pd->creds = NULL; pd->use_rtclock = use_rtclock; return pd; @@ -321,7 +318,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { struct reply_info *r; - for (r = pd->replies; r; r = r->next) + PA_LLIST_FOREACH(r, pd->replies) if (r->tag == tag) break; @@ -329,9 +326,9 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds, run_action(pd, r, command, ts); } else if (pd->callback_table && (command < pd->n_commands) && pd->callback_table[command]) { - const pa_pdispatch_cb_t *c = pd->callback_table+command; + const pa_pdispatch_cb_t *cb = pd->callback_table+command; - (*c)(pd, command, tag, ts, userdata); + (*cb)(pd, command, tag, ts, userdata); } else { pa_log("Received unsupported command %u", command); goto finish; @@ -379,7 +376,9 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa r->free_cb = free_cb; r->tag = tag; - pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop, pa_timeval_rtstore(&tv, pa_rtclock_now() + timeout * PA_USEC_PER_SEC, pd->use_rtclock), timeout_callback, r)); + pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop, + pa_timeval_rtstore(&tv, pa_rtclock_now() + timeout * PA_USEC_PER_SEC, pd->use_rtclock), + timeout_callback, r)); PA_LLIST_PREPEND(struct reply_info, pd->replies, r); } @@ -391,7 +390,7 @@ int pa_pdispatch_is_pending(pa_pdispatch *pd) { return !!pd->replies; } -void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *pd, void *userdata), void *userdata) { +void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_cb_t cb, void *userdata) { pa_assert(pd); pa_assert(PA_REFCNT_VALUE(pd) >= 1); pa_assert(!cb || pa_pdispatch_is_pending(pd)); @@ -406,12 +405,9 @@ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) { pa_assert(pd); pa_assert(PA_REFCNT_VALUE(pd) >= 1); - for (r = pd->replies; r; r = n) { - n = r->next; - + PA_LLIST_FOREACH_SAFE(r, n, pd->replies) if (r->userdata == userdata) reply_info_free(r); - } } void pa_pdispatch_unref(pa_pdispatch *pd) { diff --git a/src/pulsecore/pdispatch.h b/src/pulsecore/pdispatch.h index dae475af..c5431c2e 100644 --- a/src/pulsecore/pdispatch.h +++ b/src/pulsecore/pdispatch.h @@ -35,9 +35,9 @@ typedef struct pa_pdispatch pa_pdispatch; typedef void (*pa_pdispatch_cb_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata); +typedef void (*pa_pdispatch_drain_cb_t)(pa_pdispatch *pd, void *userdata); -pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, pa_bool_t use_rtclock, const pa_pdispatch_cb_t*table, unsigned entries); +pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, pa_bool_t use_rtclock, const pa_pdispatch_cb_t *table, unsigned entries); void pa_pdispatch_unref(pa_pdispatch *pd); pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd); @@ -47,7 +47,7 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa int pa_pdispatch_is_pending(pa_pdispatch *pd); -void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_callback callback, void *userdata); +void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, pa_pdispatch_drain_cb_t callback, void *userdata); /* Remove all reply slots with the give userdata parameter */ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata); -- cgit From cab48d48d12b26ef5651a5dc829fc7296395ef0a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Aug 2009 00:04:33 +0200 Subject: protocol-native: compare uint64_t variable with (uint64_t) -1 instead of (size_t) -1 for compat with 32bit archs --- src/pulsecore/protocol-native.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 6678d847..98ff407c 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1289,7 +1289,8 @@ static void handle_seek(playback_stream *s, int64_t indexw) { pa_log_debug("Requesting rewind due to end of underrun."); pa_sink_input_request_rewind(s->sink_input, - (size_t) (s->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : s->sink_input->thread_info.underrun_for), + (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 : + s->sink_input->thread_info.underrun_for), FALSE, TRUE, FALSE); } -- cgit From c372b52a77b20b454c49d5368a7d1afbc1a23188 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Aug 2009 00:05:54 +0200 Subject: protocol-native: print more volume change debug messages to easy tracking down of feedback loops --- src/modules/module-stream-restore.c | 4 ++++ src/pulsecore/protocol-native.c | 26 ++++++++++++++++++++------ src/pulsecore/protocol-native.h | 2 +- 3 files changed, 25 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index e560bd28..d6e3c153 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -934,6 +934,10 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio data.data = &entry; data.size = sizeof(entry); + pa_log_debug("Client %s changes entry %s.", + pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c)->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)), + name); + if (pa_database_set(u->database, &key, &data, mode == PA_UPDATE_REPLACE) == 0) if (apply_immediately) apply_entry(u, name, &entry); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 98ff407c..956767ad 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -3386,10 +3386,10 @@ static void command_set_volume( pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name); pa_sink_set_volume(sink, &volume, TRUE, TRUE); } else if (source) { - pa_log_debug("Client %s changes volume of sink %s.", client_name, source->name); + pa_log_debug("Client %s changes volume of source %s.", client_name, source->name); pa_source_set_volume(source, &volume, TRUE); } else if (si) { - pa_log_debug("Client %s changes volume of sink %s.", + pa_log_debug("Client %s changes volume of sink input %s.", client_name, pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME))); pa_sink_input_set_volume(si, &volume, TRUE, TRUE); @@ -3411,7 +3411,7 @@ static void command_set_mute( pa_sink *sink = NULL; pa_source *source = NULL; pa_sink_input *si = NULL; - const char *name = NULL; + const char *name = NULL, *client_name; pa_native_connection_assert_ref(c); pa_assert(t); @@ -3460,12 +3460,20 @@ static void command_set_mute( CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY); - if (sink) + client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); + + if (sink) { + pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name); pa_sink_set_mute(sink, mute, TRUE); - else if (source) + } else if (source) { + pa_log_debug("Client %s changes mute of source %s.", client_name, source->name); pa_source_set_mute(source, mute, TRUE); - else if (si) + } else if (si) { + pa_log_debug("Client %s changes mute of sink input %s.", + client_name, + pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME))); pa_sink_input_set_mute(si, mute, TRUE); + } pa_pstream_send_simple_ack(c->pstream, tag); } @@ -4843,3 +4851,9 @@ pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) { return c->pstream; } + +pa_client* pa_native_connection_get_client(pa_native_connection *c) { + pa_native_connection_assert_ref(c); + + return c->client; +} diff --git a/src/pulsecore/protocol-native.h b/src/pulsecore/protocol-native.h index 8a8d601c..97126274 100644 --- a/src/pulsecore/protocol-native.h +++ b/src/pulsecore/protocol-native.h @@ -47,7 +47,6 @@ typedef struct pa_native_options { char *auth_group; pa_ip_acl *auth_ip_acl; pa_auth_cookie *auth_cookie; - } pa_native_options; typedef enum pa_native_hook { @@ -80,6 +79,7 @@ int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_nativ void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m); pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c); +pa_client* pa_native_connection_get_client(pa_native_connection *c); pa_native_options* pa_native_options_new(void); pa_native_options* pa_native_options_ref(pa_native_options *o); -- cgit From 5df842db648d876192569e3aa6e0beace1a7ac5c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Aug 2009 00:07:15 +0200 Subject: sink-input: extend comments on rewinding logic a bit --- src/pulsecore/sink-input.c | 22 +++++++++++++++------- src/pulsecore/sink-input.h | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 0ad95e6f..484421bb 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -1472,7 +1472,13 @@ pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i) { } /* Called from IO context */ -void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sample spec */, pa_bool_t rewrite, pa_bool_t flush, pa_bool_t dont_rewind_render) { +void pa_sink_input_request_rewind( + pa_sink_input *i, + size_t nbytes /* in our sample spec */, + pa_bool_t rewrite, + pa_bool_t flush, + pa_bool_t dont_rewind_render) { + size_t lbq; /* If 'rewrite' is TRUE the sink is rewound as far as requested @@ -1487,19 +1493,20 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam * dont_rewind_render is TRUE then the render memblockq is not * rewound. */ + /* nbytes = 0 means maximum rewind request */ + pa_sink_input_assert_ref(i); pa_sink_input_assert_io_context(i); - - nbytes = PA_MAX(i->thread_info.rewrite_nbytes, nbytes); - -/* pa_log_debug("request rewrite %lu", (unsigned long) nbytes); */ + pa_assert(rewrite || flush); + pa_assert(!dont_rewind_render || !rewrite); /* We don't take rewind requests while we are corked */ if (i->thread_info.state == PA_SINK_INPUT_CORKED) return; - pa_assert(rewrite || flush); - pa_assert(!dont_rewind_render || !rewrite); + nbytes = PA_MAX(i->thread_info.rewrite_nbytes, nbytes); + + /* pa_log_debug("request rewrite %zu", nbytes); */ /* Calculate how much we can rewind locally without having to * touch the sink */ @@ -1519,6 +1526,7 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam nbytes = pa_resampler_request(i->thread_info.resampler, nbytes); } + /* Remember how much we actually want to rewrite */ if (i->thread_info.rewrite_nbytes != (size_t) -1) { if (rewrite) { /* Make sure to not overwrite over underruns */ diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index fe6cf75c..06e9e4f2 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -212,7 +212,7 @@ struct pa_sink_input { pa_bool_t attached:1; /* True only between ->attach() and ->detach() calls */ - /* 0: rewrite nothing, (size_t) -1: rewrite everything, otherwise how many bytes to rewrite */ + /* rewrite_nbytes: 0: rewrite nothing, (size_t) -1: rewrite everything, otherwise how many bytes to rewrite */ pa_bool_t rewrite_flush:1, dont_rewind_render:1; size_t rewrite_nbytes; uint64_t underrun_for, playing_for; -- 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') 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 26bd0901ac02cff3a40c36f711c65c28e00806dc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 24 Aug 2009 17:00:23 +0200 Subject: sconv: fix indentation --- src/pulsecore/sconv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index d06d6985..301f08b4 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -52,8 +52,8 @@ static void u8_from_float32ne(unsigned n, const float *a, uint8_t *b) { for (; n > 0; n--, a++, b++) { float v; v = (*a * 127.0) + 128.0; - v = PA_CLAMP_UNLIKELY (v, 0.0, 255.0); - *b = rint (v); + v = PA_CLAMP_UNLIKELY (v, 0.0, 255.0); + *b = rint (v); } } -- cgit From 509d9f04e56258e8bcb59b0bb42e84053ba6021c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 25 Aug 2009 12:27:32 +0200 Subject: remap: add sse optimized mono to stereo --- src/Makefile.am | 2 +- src/pulsecore/cpu-x86.c | 4 +- src/pulsecore/cpu-x86.h | 1 + src/pulsecore/remap_sse.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 src/pulsecore/remap_sse.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index e65662c7..138256db 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -832,7 +832,7 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/play-memblockq.c pulsecore/play-memblockq.h \ pulsecore/play-memchunk.c pulsecore/play-memchunk.h \ pulsecore/remap.c pulsecore/remap.h \ - pulsecore/remap_mmx.c \ + pulsecore/remap_mmx.c pulsecore/remap_sse.c \ pulsecore/resampler.c pulsecore/resampler.h \ pulsecore/rtpoll.c pulsecore/rtpoll.h \ pulsecore/sample-util.c pulsecore/sample-util.h \ diff --git a/src/pulsecore/cpu-x86.c b/src/pulsecore/cpu-x86.c index bc093ec0..6f0cecc8 100644 --- a/src/pulsecore/cpu-x86.c +++ b/src/pulsecore/cpu-x86.c @@ -115,8 +115,10 @@ void pa_cpu_init_x86 (void) { pa_remap_func_init_mmx (flags); } - if (flags & PA_CPU_X86_SSE) + if (flags & PA_CPU_X86_SSE) { pa_volume_func_init_sse (flags); + pa_remap_func_init_sse (flags); + } #endif /* defined (__i386__) || defined (__amd64__) */ } diff --git a/src/pulsecore/cpu-x86.h b/src/pulsecore/cpu-x86.h index b11ef6ea..b67555b9 100644 --- a/src/pulsecore/cpu-x86.h +++ b/src/pulsecore/cpu-x86.h @@ -64,5 +64,6 @@ void pa_volume_func_init_mmx(pa_cpu_x86_flag_t flags); void pa_volume_func_init_sse(pa_cpu_x86_flag_t flags); void pa_remap_func_init_mmx(pa_cpu_x86_flag_t flags); +void pa_remap_func_init_sse(pa_cpu_x86_flag_t flags); #endif /* foocpux86hfoo */ diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c new file mode 100644 index 00000000..e086862d --- /dev/null +++ b/src/pulsecore/remap_sse.c @@ -0,0 +1,148 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2009 Wim Taymans + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include "cpu-x86.h" +#include "remap.h" + +#define LOAD_SAMPLES \ + " movdqu (%1), %%xmm0 \n\t" \ + " movdqu 16(%1), %%xmm2 \n\t" \ + " movdqu 32(%1), %%xmm4 \n\t" \ + " movdqu 48(%1), %%xmm6 \n\t" \ + " movdqa %%xmm0, %%xmm1 \n\t" \ + " movdqa %%xmm2, %%xmm3 \n\t" \ + " movdqa %%xmm4, %%xmm5 \n\t" \ + " movdqa %%xmm6, %%xmm7 \n\t" + +#define UNPACK_SAMPLES(s) \ + " punpckl"#s" %%xmm0, %%xmm0 \n\t" \ + " punpckh"#s" %%xmm1, %%xmm1 \n\t" \ + " punpckl"#s" %%xmm2, %%xmm2 \n\t" \ + " punpckh"#s" %%xmm3, %%xmm3 \n\t" \ + " punpckl"#s" %%xmm4, %%xmm4 \n\t" \ + " punpckh"#s" %%xmm5, %%xmm5 \n\t" \ + " punpckl"#s" %%xmm6, %%xmm6 \n\t" \ + " punpckh"#s" %%xmm7, %%xmm7 \n\t" \ + +#define STORE_SAMPLES \ + " movdqu %%xmm0, (%0) \n\t" \ + " movdqu %%xmm1, 16(%0) \n\t" \ + " movdqu %%xmm2, 32(%0) \n\t" \ + " movdqu %%xmm3, 48(%0) \n\t" \ + " movdqu %%xmm4, 64(%0) \n\t" \ + " movdqu %%xmm5, 80(%0) \n\t" \ + " movdqu %%xmm6, 96(%0) \n\t" \ + " movdqu %%xmm7, 112(%0) \n\t" \ + " add $64, %1 \n\t" \ + " add $128, %0 \n\t" + +#define HANDLE_SINGLE(s) \ + " movd (%1), %%mm0 \n\t" \ + " movq %%mm0, %%mm1 \n\t" \ + " punpckl"#s" %%mm0, %%mm0 \n\t" \ + " movq %%mm0, (%0) \n\t" \ + " add $4, %1 \n\t" \ + " add $8, %0 \n\t" + +#define MONO_TO_STEREO(s) \ + " mov %3, %2 \n\t" \ + " sar $4, %2 \n\t" \ + " cmp $0, %2 \n\t" \ + " je 2f \n\t" \ + "1: \n\t" \ + LOAD_SAMPLES \ + UNPACK_SAMPLES(s) \ + STORE_SAMPLES \ + " dec %2 \n\t" \ + " jne 1b \n\t" \ + "2: \n\t" \ + " mov %3, %2 \n\t" \ + " and $15, %2 \n\t" \ + " je 4f \n\t" \ + "3: \n\t" \ + HANDLE_SINGLE(s) \ + " dec %2 \n\t" \ + " jne 3b \n\t" \ + "4: \n\t" \ + " emms \n\t" + +static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, unsigned n) { + pa_reg_x86 temp; + + switch (*m->format) { + case PA_SAMPLE_FLOAT32NE: + { + __asm__ __volatile__ ( + MONO_TO_STEREO(dq) /* do doubles to quads */ + : "+r" (dst), "+r" (src), "=&r" (temp) + : "r" ((pa_reg_x86)n) + : "cc" + ); + break; + } + case PA_SAMPLE_S16NE: + { + __asm__ __volatile__ ( + MONO_TO_STEREO(wd) /* do words to doubles */ + : "+r" (dst), "+r" (src), "=&r" (temp) + : "r" ((pa_reg_x86)n) + : "cc" + ); + break; + } + default: + pa_assert_not_reached(); + } +} + +/* set the function that will execute the remapping based on the matrices */ +static void init_remap_sse (pa_remap_t *m) { + unsigned n_oc, n_ic; + + n_oc = m->o_ss->channels; + n_ic = m->i_ss->channels; + + /* find some common channel remappings, fall back to full matrix operation. */ + if (n_ic == 1 && n_oc == 2 && + m->map_table_f[0][0] >= 1.0 && m->map_table_f[1][0] >= 1.0) { + m->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo_sse; + pa_log_info("Using SSE mono to stereo remapping"); + } +} + +void pa_remap_func_init_sse (pa_cpu_x86_flag_t flags) { +#if defined (__i386__) || defined (__amd64__) + pa_log_info("Initialising SSE optimized remappers."); + + pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_sse); +#endif /* defined (__i386__) || defined (__amd64__) */ +} -- cgit From 9d254679649fe3810ec9885251999a084bb7bacb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 25 Aug 2009 17:40:44 +0200 Subject: sample-util: avoid stack overrun The linear volume array needs enough padding when preparing the volumes for mixing. --- src/pulsecore/sample-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 6e97e5a9..5fae1928 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -137,7 +137,7 @@ static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) { static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) { unsigned k, channel; - float linear[PA_CHANNELS_MAX]; + float linear[PA_CHANNELS_MAX + VOLUME_PADDING]; pa_assert(streams); pa_assert(spec); @@ -156,7 +156,7 @@ static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned n static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) { unsigned k, channel; - float linear[PA_CHANNELS_MAX]; + float linear[PA_CHANNELS_MAX + VOLUME_PADDING]; pa_assert(streams); pa_assert(spec); -- cgit From 59070892ed070d0c42d8d9b91d267a39c5763a9c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 26 Aug 2009 19:29:21 +0200 Subject: remap: cleanup assembler a little --- src/pulsecore/remap_mmx.c | 43 +++++++++++++++++++++---------------------- src/pulsecore/remap_sse.c | 12 +++++------- 2 files changed, 26 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/pulsecore/remap_mmx.c b/src/pulsecore/remap_mmx.c index 00252dac..b5fe82ee 100644 --- a/src/pulsecore/remap_mmx.c +++ b/src/pulsecore/remap_mmx.c @@ -51,7 +51,7 @@ " punpckl"#s" %%mm4, %%mm4 \n\t" \ " punpckh"#s" %%mm5, %%mm5 \n\t" \ " punpckl"#s" %%mm6, %%mm6 \n\t" \ - " punpckh"#s" %%mm7, %%mm7 \n\t" \ + " punpckh"#s" %%mm7, %%mm7 \n\t" #define STORE_SAMPLES \ " movq %%mm0, (%0) \n\t" \ @@ -67,32 +67,31 @@ #define HANDLE_SINGLE(s) \ " movd (%1), %%mm0 \n\t" \ - " movq %%mm0, %%mm1 \n\t" \ " punpckl"#s" %%mm0, %%mm0 \n\t" \ " movq %%mm0, (%0) \n\t" \ " add $4, %1 \n\t" \ " add $8, %0 \n\t" -#define MONO_TO_STEREO(s) \ - " mov %3, %2 \n\t" \ - " sar $3, %2 \n\t" \ - " cmp $0, %2 \n\t" \ - " je 2f \n\t" \ - "1: \n\t" \ - LOAD_SAMPLES \ - UNPACK_SAMPLES(s) \ - STORE_SAMPLES \ - " dec %2 \n\t" \ - " jne 1b \n\t" \ - "2: \n\t" \ - " mov %3, %2 \n\t" \ - " and $7, %2 \n\t" \ - " je 4f \n\t" \ - "3: \n\t" \ - HANDLE_SINGLE(s) \ - " dec %2 \n\t" \ - " jne 3b \n\t" \ - "4: \n\t" \ +#define MONO_TO_STEREO(s) \ + " mov %3, %2 \n\t" \ + " sar $3, %2 \n\t" \ + " cmp $0, %2 \n\t" \ + " je 2f \n\t" \ + "1: \n\t" \ + LOAD_SAMPLES \ + UNPACK_SAMPLES(s) \ + STORE_SAMPLES \ + " dec %2 \n\t" \ + " jne 1b \n\t" \ + "2: \n\t" \ + " mov %3, %2 \n\t" \ + " and $7, %2 \n\t" \ + " je 4f \n\t" \ + "3: \n\t" \ + HANDLE_SINGLE(s) \ + " dec %2 \n\t" \ + " jne 3b \n\t" \ + "4: \n\t" \ " emms \n\t" #if defined (__i386__) || defined (__amd64__) diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c index e086862d..97f2476e 100644 --- a/src/pulsecore/remap_sse.c +++ b/src/pulsecore/remap_sse.c @@ -51,7 +51,7 @@ " punpckl"#s" %%xmm4, %%xmm4 \n\t" \ " punpckh"#s" %%xmm5, %%xmm5 \n\t" \ " punpckl"#s" %%xmm6, %%xmm6 \n\t" \ - " punpckh"#s" %%xmm7, %%xmm7 \n\t" \ + " punpckh"#s" %%xmm7, %%xmm7 \n\t" #define STORE_SAMPLES \ " movdqu %%xmm0, (%0) \n\t" \ @@ -66,10 +66,9 @@ " add $128, %0 \n\t" #define HANDLE_SINGLE(s) \ - " movd (%1), %%mm0 \n\t" \ - " movq %%mm0, %%mm1 \n\t" \ - " punpckl"#s" %%mm0, %%mm0 \n\t" \ - " movq %%mm0, (%0) \n\t" \ + " movd (%1), %%xmm0 \n\t" \ + " punpckl"#s" %%xmm0, %%xmm0 \n\t" \ + " movq %%xmm0, (%0) \n\t" \ " add $4, %1 \n\t" \ " add $8, %0 \n\t" @@ -92,8 +91,7 @@ HANDLE_SINGLE(s) \ " dec %2 \n\t" \ " jne 3b \n\t" \ - "4: \n\t" \ - " emms \n\t" + "4: \n\t" static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, unsigned n) { pa_reg_x86 temp; -- cgit From 27bfb7628c709eb6802c9ec73a6feb995fda8375 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 26 Aug 2009 19:29:56 +0200 Subject: macro: add macro to align variables --- src/pulsecore/macro.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index 87684ad3..bffcc264 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -80,6 +80,12 @@ static inline size_t PA_PAGE_ALIGN(size_t l) { #define PA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) +#if defined(__GNUC__) + #define PA_DECLARE_ALIGNED(n,t,v) t v __attribute__ ((aligned (n))) +#else + #define PA_DECLARE_ALIGNED(n,t,v) t v +#endif + /* The users of PA_MIN and PA_MAX, PA_CLAMP, PA_ROUND_UP should be * aware that these macros on non-GCC executed code with side effects * twice. It is thus considered misuse to use code with side effects -- cgit From beb180b7bc5885313cf14d6faf854bc6b805ae11 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 26 Aug 2009 19:30:37 +0200 Subject: convert: add sse/sse2 s16 to float32ne conversions --- src/Makefile.am | 1 + src/pulsecore/cpu-x86.c | 1 + src/pulsecore/cpu-x86.h | 2 + src/pulsecore/sconv_sse.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 239 insertions(+) create mode 100644 src/pulsecore/sconv_sse.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 138256db..654dc41a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -842,6 +842,7 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/svolume_mmx.c pulsecore/svolume_sse.c \ pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \ pulsecore/sconv-s16le.c pulsecore/sconv-s16le.h \ + pulsecore/sconv_sse.c \ pulsecore/sconv.c pulsecore/sconv.h \ pulsecore/shared.c pulsecore/shared.h \ pulsecore/shm.c pulsecore/shm.h \ diff --git a/src/pulsecore/cpu-x86.c b/src/pulsecore/cpu-x86.c index 6f0cecc8..1ba9f1a4 100644 --- a/src/pulsecore/cpu-x86.c +++ b/src/pulsecore/cpu-x86.c @@ -118,6 +118,7 @@ void pa_cpu_init_x86 (void) { if (flags & PA_CPU_X86_SSE) { pa_volume_func_init_sse (flags); pa_remap_func_init_sse (flags); + pa_convert_func_init_sse (flags); } #endif /* defined (__i386__) || defined (__amd64__) */ diff --git a/src/pulsecore/cpu-x86.h b/src/pulsecore/cpu-x86.h index b67555b9..b40eb5ce 100644 --- a/src/pulsecore/cpu-x86.h +++ b/src/pulsecore/cpu-x86.h @@ -66,4 +66,6 @@ void pa_volume_func_init_sse(pa_cpu_x86_flag_t flags); void pa_remap_func_init_mmx(pa_cpu_x86_flag_t flags); void pa_remap_func_init_sse(pa_cpu_x86_flag_t flags); +void pa_convert_func_init_sse (pa_cpu_x86_flag_t flags); + #endif /* foocpux86hfoo */ diff --git a/src/pulsecore/sconv_sse.c b/src/pulsecore/sconv_sse.c new file mode 100644 index 00000000..b213d991 --- /dev/null +++ b/src/pulsecore/sconv_sse.c @@ -0,0 +1,235 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include "endianmacros.h" + +#include "cpu-x86.h" +#include "sconv.h" + +static pa_convert_func_t func; + +#if defined (__i386__) || defined (__amd64__) + +static const PA_DECLARE_ALIGNED (16, float, one[4]) = { 1.0, 1.0, 1.0, 1.0 }; +static const PA_DECLARE_ALIGNED (16, float, mone[4]) = { -1.0, -1.0, -1.0, -1.0 }; +static const PA_DECLARE_ALIGNED (16, float, scale[4]) = { 0x7fff, 0x7fff, 0x7fff, 0x7fff }; + +static void pa_sconv_s16le_from_f32ne_sse(unsigned n, const float *a, int16_t *b) { + pa_reg_x86 temp, i; + + __asm__ __volatile__ ( + " movaps %5, %%xmm5 \n\t" + " movaps %6, %%xmm6 \n\t" + " movaps %7, %%xmm7 \n\t" + " xor %0, %0 \n\t" + + " mov %4, %1 \n\t" + " sar $3, %1 \n\t" /* 8 floats at a time */ + " cmp $0, %1 \n\t" + " je 2f \n\t" + + "1: \n\t" + " movups (%2, %0, 2), %%xmm0 \n\t" /* read 8 floats */ + " movups 16(%2, %0, 2), %%xmm2 \n\t" + " minps %%xmm5, %%xmm0 \n\t" /* clamp to 1.0 */ + " minps %%xmm5, %%xmm2 \n\t" + " maxps %%xmm6, %%xmm0 \n\t" /* clamp to -1.0 */ + " maxps %%xmm6, %%xmm2 \n\t" + " mulps %%xmm7, %%xmm0 \n\t" /* *= 0x7fff */ + " mulps %%xmm7, %%xmm2 \n\t" + + " cvtps2pi %%xmm0, %%mm0 \n\t" /* low part to int */ + " cvtps2pi %%xmm2, %%mm2 \n\t" + " movhlps %%xmm0, %%xmm0 \n\t" /* bring high part in position */ + " movhlps %%xmm2, %%xmm2 \n\t" + " cvtps2pi %%xmm0, %%mm1 \n\t" /* high part to int */ + " cvtps2pi %%xmm2, %%mm3 \n\t" + + " packssdw %%mm1, %%mm0 \n\t" /* pack parts */ + " packssdw %%mm3, %%mm2 \n\t" + " movq %%mm0, (%3, %0) \n\t" + " movq %%mm2, 8(%3, %0) \n\t" + + " add $16, %0 \n\t" + " dec %1 \n\t" + " jne 1b \n\t" + + "2: \n\t" + " mov %4, %1 \n\t" /* prepare for leftovers */ + " and $15, %1 \n\t" + " je 4f \n\t" + + "3: \n\t" + " movss (%2, %0, 2), %%xmm0 \n\t" + " minss %%xmm5, %%xmm0 \n\t" + " maxss %%xmm6, %%xmm0 \n\t" + " mulss %%xmm7, %%xmm0 \n\t" + " cvtss2si %%xmm0, %4 \n\t" + " movw %w4, (%3, %0) \n\t" + " add $2, %0 \n\t" + " dec %1 \n\t" + " jne 3b \n\t" + + "4: \n\t" + " emms \n\t" + + : "=&r" (i), "=&r" (temp) + : "r" (a), "r" (b), "r" ((pa_reg_x86)n), "m" (*one), "m" (*mone), "m" (*scale) + : "cc", "memory" + ); +} + +static void pa_sconv_s16le_from_f32ne_sse2(unsigned n, const float *a, int16_t *b) { + pa_reg_x86 temp, i; + + __asm__ __volatile__ ( + " movaps %5, %%xmm5 \n\t" + " movaps %6, %%xmm6 \n\t" + " movaps %7, %%xmm7 \n\t" + " xor %0, %0 \n\t" + + " mov %4, %1 \n\t" + " sar $3, %1 \n\t" /* 8 floats at a time */ + " cmp $0, %1 \n\t" + " je 2f \n\t" + + "1: \n\t" + " movups (%2, %0, 2), %%xmm0 \n\t" /* read 8 floats */ + " movups 16(%2, %0, 2), %%xmm2 \n\t" + " minps %%xmm5, %%xmm0 \n\t" /* clamp to 1.0 */ + " minps %%xmm5, %%xmm2 \n\t" + " maxps %%xmm6, %%xmm0 \n\t" /* clamp to -1.0 */ + " maxps %%xmm6, %%xmm2 \n\t" + " mulps %%xmm7, %%xmm0 \n\t" /* *= 0x7fff */ + " mulps %%xmm7, %%xmm2 \n\t" + + " cvtps2dq %%xmm0, %%xmm0 \n\t" + " cvtps2dq %%xmm2, %%xmm2 \n\t" + + " packssdw %%xmm2, %%xmm0 \n\t" + " movdqu %%xmm0, (%3, %0) \n\t" + + " add $16, %0 \n\t" + " dec %1 \n\t" + " jne 1b \n\t" + + "2: \n\t" + " mov %4, %1 \n\t" /* prepare for leftovers */ + " and $15, %1 \n\t" + " je 4f \n\t" + + "3: \n\t" + " movss (%2, %0, 2), %%xmm0 \n\t" + " minss %%xmm5, %%xmm0 \n\t" + " maxss %%xmm6, %%xmm0 \n\t" + " mulss %%xmm7, %%xmm0 \n\t" + " cvtss2si %%xmm0, %4 \n\t" + " movw %w4, (%3, %0) \n\t" + " add $2, %0 \n\t" + " dec %1 \n\t" + " jne 3b \n\t" + + "4: \n\t" + + : "=&r" (i), "=&r" (temp) + : "r" (a), "r" (b), "r" ((pa_reg_x86)n), "m" (*one), "m" (*mone), "m" (*scale) + : "cc", "memory" + ); +} + +#undef RUN_TEST + +#ifdef RUN_TEST +#define SAMPLES 1019 +#define TIMES 1000 + +static void run_test (void) { + int16_t samples[SAMPLES]; + int16_t samples_ref[SAMPLES]; + float floats[SAMPLES]; + int i; + pa_usec_t start, stop; + + printf ("checking SSE %zd\n", sizeof (samples)); + + memset (samples_ref, 0, sizeof (samples_ref)); + memset (samples, 0, sizeof (samples)); + + for (i = 0; i < SAMPLES; i++) { + floats[i] = (rand()/(RAND_MAX+2.2)) - 1.1; + } + + func = pa_get_convert_from_float32ne_function (PA_SAMPLE_S16LE); + func (SAMPLES, floats, samples_ref); + pa_sconv_s16le_from_f32ne_sse2 (SAMPLES, floats, samples); + + for (i = 0; i < SAMPLES; i++) { + if (samples[i] != samples_ref[i]) { + printf ("%d: %04x != %04x (%f)\n", i, samples[i], samples_ref[i], + floats[i]); + } + } + + start = pa_rtclock_now(); + for (i = 0; i < TIMES; i++) { + pa_sconv_s16le_from_f32ne_sse2 (SAMPLES, floats, samples); + } + stop = pa_rtclock_now(); + pa_log_info("SSE: %llu usec.", (long long unsigned int)(stop - start)); + + start = pa_rtclock_now(); + for (i = 0; i < TIMES; i++) { + func (SAMPLES, floats, samples_ref); + } + stop = pa_rtclock_now(); + pa_log_info("ref: %llu usec.", (long long unsigned int)(stop - start)); +} +#endif +#endif /* defined (__i386__) || defined (__amd64__) */ + + +void pa_convert_func_init_sse (pa_cpu_x86_flag_t flags) { +#if defined (__i386__) || defined (__amd64__) + pa_log_info("Initialising SSE optimized conversions."); + +#ifdef RUN_TEST + run_test (); +#endif + + if (flags & PA_CPU_X86_SSE2) + pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse2); + else + pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse); + +#endif /* defined (__i386__) || defined (__amd64__) */ +} + -- cgit From 8169a6a6c921215c1353e8a34fccbdc4e2e20440 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 27 Aug 2009 11:29:49 -0300 Subject: Handle DisconnectRequested in bluetooth module. --- src/modules/bluetooth/bluetooth-util.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src') diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index d0c89aab..f8c5b778 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -662,6 +662,21 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal(m, "org.bluez.Device", "DisconnectRequested")) { + pa_bluetooth_device *d; + + if ((d = pa_hashmap_get(y->devices, dbus_message_get_path(m)))) { + /* Device will disconnect in 2 sec */ + d->audio_state = PA_BT_AUDIO_STATE_DISCONNECTED; + d->audio_sink_state = PA_BT_AUDIO_STATE_DISCONNECTED; + d->audio_source_state = PA_BT_AUDIO_STATE_DISCONNECTED; + d->headset_state = PA_BT_AUDIO_STATE_DISCONNECTED; + + run_callback(y, d, FALSE); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } else if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) { const char *name, *old_owner, *new_owner; @@ -775,6 +790,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) { "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'", "type='signal',sender='org.bluez',interface='org.bluez.Device',member='PropertyChanged'", + "type='signal',sender='org.bluez',interface='org.bluez.Device',member='DisconnectRequested'", "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", @@ -828,6 +844,7 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) { "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'", "type='signal',sender='org.bluez',interface='org.bluez.Device',member='PropertyChanged'", + "type='signal',sender='org.bluez',interface='org.bluez.Device',member='DisconnectRequested'", "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", -- cgit From 63f3dc0bdc789fa26a7a6e05f0127411c74ff143 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Aug 2009 17:07:08 +0200 Subject: bluetooth: remove left-over debug line --- src/modules/bluetooth/module-bluetooth-discover.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c index 7571e48a..02fd4240 100644 --- a/src/modules/bluetooth/module-bluetooth-discover.c +++ b/src/modules/bluetooth/module-bluetooth-discover.c @@ -83,7 +83,6 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const mi = pa_hashmap_get(u->hashmap, d->path); - pa_log("dead: %d, device_connected: %d, audio_state: %d, audio_source_state: %d", d->dead, d->device_connected, d->audio_state, d->audio_source_state); if (!d->dead && d->device_connected > 0 && (d->audio_state >= PA_BT_AUDIO_STATE_CONNECTED || d->audio_source_state >= PA_BT_AUDIO_STATE_CONNECTED)) { -- cgit From 9011c4e4f771575fc5bf68d3afcb6d0f5c856384 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Aug 2009 17:10:17 +0200 Subject: build-sys: make proximity helper properly suid --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 654dc41a..88f0ff56 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1738,7 +1738,7 @@ daemon.conf: daemon/daemon.conf.in Makefile -e 's,@PA_DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@ install-exec-hook: - chown root $(DESTDIR)$(bindir)/pulseaudio ; true + -chown root $(DESTDIR)$(pulselibexecdir)/proximity-helper -chmod u+s $(DESTDIR)$(pulselibexecdir)/proximity-helper ln -sf pacat $(DESTDIR)$(bindir)/parec ln -sf pacat $(DESTDIR)$(bindir)/pamon -- cgit From 4e8562c1f1cf5ee134043747feea093ded469be4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 28 Aug 2009 15:16:52 +0300 Subject: raop: Fix memory leak The return memory of the pa_strbuf_tostring_free() should be freed. pa_headerlist_puts() saves its own copy. --- src/modules/rtp/rtsp_client.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/modules/rtp/rtsp_client.c b/src/modules/rtp/rtsp_client.c index 72d304e8..ba657f74 100644 --- a/src/modules/rtp/rtsp_client.c +++ b/src/modules/rtp/rtsp_client.c @@ -214,11 +214,13 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { /* End of headers */ /* We will have a header left from our looping iteration, so add it in :) */ if (c->last_header) { + char *tmp = pa_strbuf_tostring_free(c->header_buffer); /* This is not a continuation header so let's dump it into our proplist */ - pa_headerlist_puts(c->response_headers, c->last_header, pa_strbuf_tostring_free(c->header_buffer)); + pa_headerlist_puts(c->response_headers, c->last_header, tmp); + pa_xfree(tmp); pa_xfree(c->last_header); c->last_header = NULL; - c->header_buffer= NULL; + c->header_buffer = NULL; } pa_log_debug("Full response received. Dispatching"); @@ -240,9 +242,11 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { } if (c->last_header) { + char *tmp = pa_strbuf_tostring_free(c->header_buffer); /* This is not a continuation header so let's dump the full header/value into our proplist */ - pa_headerlist_puts(c->response_headers, c->last_header, pa_strbuf_tostring_free(c->header_buffer)); + pa_headerlist_puts(c->response_headers, c->last_header, tmp); + pa_xfree(tmp); pa_xfree(c->last_header); c->last_header = NULL; c->header_buffer = NULL; -- cgit From ae383539d7001d59044e6d7e06e9270b65ae762b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 28 Aug 2009 15:16:53 +0300 Subject: core-util: Fix logic of pa_make_path_absolute() Make it works as described in commentary (when fn is NULL, pa_assert(fn) could break logic). --- src/pulsecore/core-util.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 1c8c6780..67823019 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -1877,17 +1877,17 @@ char *pa_make_path_absolute(const char *p) { static char *get_path(const char *fn, pa_bool_t prependmid, pa_bool_t rt) { char *rtp; - if (pa_is_path_absolute(fn)) - return pa_xstrdup(fn); - rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir(); - if (!rtp) - return NULL; - if (fn) { char *r; + if (pa_is_path_absolute(fn)) + return pa_xstrdup(fn); + + if (!rtp) + return NULL; + if (prependmid) { char *mid; -- 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 ++++++------------ src/pulsecore/protocol-simple.c | 3 +-- src/pulsecore/resampler.c | 3 +-- src/pulsecore/sound-file-stream.c | 3 +-- 4 files changed, 9 insertions(+), 18 deletions(-) (limited to 'src') 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; diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 95ec6ac8..488d7572 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -627,8 +627,7 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp return; fail: - if (c) - connection_unlink(c); + connection_unlink(c); } void pa_simple_protocol_disconnect(pa_simple_protocol *p, pa_module *m) { diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index f1bfa156..bed5a20d 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -299,8 +299,7 @@ pa_resampler* pa_resampler_new( return r; fail: - if (r) - pa_xfree(r); + pa_xfree(r); return NULL; } diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index f41c53f3..c4b4d1a5 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -334,8 +334,7 @@ int pa_play_file( return 0; fail: - if (u) - file_stream_unref(u); + file_stream_unref(u); if (fd >= 0) pa_close(fd); -- cgit From 84eb6614eb3a4c72d9c529948aff8ffd4c534e19 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Aug 2009 23:24:09 +0200 Subject: core: move 'flags' field into 'pa_sink_input_new_data' structure so that hooks can access it --- src/modules/module-combine.c | 3 ++- src/modules/module-ladspa-sink.c | 2 +- src/modules/module-loopback.c | 5 +++-- src/modules/module-remap-sink.c | 3 ++- src/modules/module-sine.c | 2 +- src/modules/rtp/module-rtp-recv.c | 3 ++- src/modules/rtp/module-rtp-send.c | 3 ++- src/pulsecore/play-memblockq.c | 2 +- src/pulsecore/protocol-esound.c | 4 ++-- src/pulsecore/protocol-http.c | 2 +- src/pulsecore/protocol-native.c | 6 ++++-- src/pulsecore/protocol-simple.c | 4 ++-- src/pulsecore/sink-input.c | 21 ++++++++++----------- src/pulsecore/sink-input.h | 5 +++-- src/pulsecore/sound-file-stream.c | 2 +- src/pulsecore/source-output.c | 21 ++++++++++----------- src/pulsecore/source-output.h | 5 +++-- 17 files changed, 50 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index 4a57ce2d..a186c899 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -844,8 +844,9 @@ static int output_create_sink_input(struct output *o) { pa_sink_input_new_data_set_channel_map(&data, &o->userdata->sink->channel_map); data.module = o->userdata->module; data.resample_method = o->userdata->resample_method; + data.flags = PA_SINK_INPUT_VARIABLE_RATE|PA_SINK_INPUT_DONT_MOVE|PA_SINK_INPUT_NO_CREATE_ON_SUSPEND; - pa_sink_input_new(&o->sink_input, o->userdata->core, &data, PA_SINK_INPUT_VARIABLE_RATE|PA_SINK_INPUT_DONT_MOVE|PA_SINK_INPUT_NO_CREATE_ON_SUSPEND); + pa_sink_input_new(&o->sink_input, o->userdata->core, &data); pa_sink_input_new_data_done(&data); diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index aa28f7fd..933fb182 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -812,7 +812,7 @@ int pa__init(pa_module*m) { pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); - pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, 0); + pa_sink_input_new(&u->sink_input, m->core, &sink_input_data); pa_sink_input_new_data_done(&sink_input_data); if (!u->sink_input) diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index 6e4f66d5..29c3ddab 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -676,8 +676,9 @@ int pa__init(pa_module *m) { pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "abstract"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); + sink_input_data.flags = PA_SINK_INPUT_VARIABLE_RATE; - pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, PA_SINK_INPUT_VARIABLE_RATE); + pa_sink_input_new(&u->sink_input, m->core, &sink_input_data); pa_sink_input_new_data_done(&sink_input_data); if (!u->sink_input) @@ -709,7 +710,7 @@ int pa__init(pa_module *m) { pa_source_output_new_data_set_sample_spec(&source_output_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); - pa_source_output_new(&u->source_output, m->core, &source_output_data, 0); + pa_source_output_new(&u->source_output, m->core, &source_output_data); pa_source_output_new_data_done(&source_output_data); if (!u->source_output) diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index becff55c..6cfd0d15 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -406,8 +406,9 @@ int pa__init(pa_module*m) { pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &stream_map); + sink_input_data.flags = (remix ? 0 : PA_SINK_INPUT_NO_REMIX); - pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, (remix ? 0 : PA_SINK_INPUT_NO_REMIX)); + pa_sink_input_new(&u->sink_input, m->core, &sink_input_data); pa_sink_input_new_data_done(&sink_input_data); if (!u->sink_input) diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c index 0be1d722..69b20028 100644 --- a/src/modules/module-sine.c +++ b/src/modules/module-sine.c @@ -163,7 +163,7 @@ int pa__init(pa_module*m) { pa_proplist_setf(data.proplist, "sine.hz", "%u", frequency); pa_sink_input_new_data_set_sample_spec(&data, &ss); - pa_sink_input_new(&u->sink_input, m->core, &data, 0); + pa_sink_input_new(&u->sink_input, m->core, &data); pa_sink_input_new_data_done(&data); if (!u->sink_input) diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index c195c045..1a05f57d 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -501,8 +501,9 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in pa_proplist_setf(data.proplist, "rtp.payload", "%u", (unsigned) sdp_info->payload); data.module = u->module; pa_sink_input_new_data_set_sample_spec(&data, &sdp_info->sample_spec); + data.flags = PA_SINK_INPUT_VARIABLE_RATE; - pa_sink_input_new(&s->sink_input, u->module->core, &data, PA_SINK_INPUT_VARIABLE_RATE); + pa_sink_input_new(&s->sink_input, u->module->core, &data); pa_sink_input_new_data_done(&data); if (!s->sink_input) { diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index f147364d..8e1cfe36 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -330,8 +330,9 @@ int pa__init(pa_module*m) { data.source = s; pa_source_output_new_data_set_sample_spec(&data, &ss); pa_source_output_new_data_set_channel_map(&data, &cm); + data.flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND; - pa_source_output_new(&o, m->core, &data, PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND); + pa_source_output_new(&o, m->core, &data); pa_source_output_new_data_done(&data); if (!o) { diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c index b0d76993..f528c496 100644 --- a/src/pulsecore/play-memblockq.c +++ b/src/pulsecore/play-memblockq.c @@ -199,7 +199,7 @@ pa_sink_input* pa_memblockq_sink_input_new( pa_sink_input_new_data_set_volume(&data, volume); pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p); - pa_sink_input_new(&u->sink_input, sink->core, &data, 0); + pa_sink_input_new(&u->sink_input, sink->core, &data); pa_sink_input_new_data_done(&data); if (!u->sink_input) diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index cfbaee6f..480af6d5 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -429,7 +429,7 @@ static int esd_proto_stream_play(connection *c, esd_proto_t request, const void sdata.sink = sink; pa_sink_input_new_data_set_sample_spec(&sdata, &ss); - pa_sink_input_new(&c->sink_input, c->protocol->core, &sdata, 0); + pa_sink_input_new(&c->sink_input, c->protocol->core, &sdata); pa_sink_input_new_data_done(&sdata); CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); @@ -525,7 +525,7 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi sdata.source = source; pa_source_output_new_data_set_sample_spec(&sdata, &ss); - pa_source_output_new(&c->source_output, c->protocol->core, &sdata, 0); + pa_source_output_new(&c->source_output, c->protocol->core, &sdata); pa_source_output_new_data_done(&sdata); CHECK_VALIDITY(c->source_output, "Failed to create source output."); diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c index 5220cc91..c09e5348 100644 --- a/src/pulsecore/protocol-http.c +++ b/src/pulsecore/protocol-http.c @@ -533,7 +533,7 @@ static void handle_listen_prefix(struct connection *c, const char *source_name) pa_source_output_new_data_set_sample_spec(&data, &ss); pa_source_output_new_data_set_channel_map(&data, &cm); - pa_source_output_new(&c->source_output, c->protocol->core, &data, 0); + pa_source_output_new(&c->source_output, c->protocol->core, &data); pa_source_output_new_data_done(&data); if (!c->source_output) { diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 956767ad..4bf5b3f9 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -648,8 +648,9 @@ static record_stream* record_stream_new( pa_source_output_new_data_set_channel_map(&data, map); if (peak_detect) data.resample_method = PA_RESAMPLER_PEAKS; + data.flags = flags; - *ret = -pa_source_output_new(&source_output, c->protocol->core, &data, flags); + *ret = -pa_source_output_new(&source_output, c->protocol->core, &data); pa_source_output_new_data_done(&data); @@ -1050,8 +1051,9 @@ static playback_stream* playback_stream_new( if (muted_set) pa_sink_input_new_data_set_muted(&data, muted); data.sync_base = ssync ? ssync->sink_input : NULL; + data.flags = flags; - *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data, flags); + *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data); pa_sink_input_new_data_done(&data); diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 488d7572..d66db4b7 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -541,7 +541,7 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); pa_sink_input_new_data_set_sample_spec(&data, &o->sample_spec); - pa_sink_input_new(&c->sink_input, p->core, &data, 0); + pa_sink_input_new(&c->sink_input, p->core, &data); pa_sink_input_new_data_done(&data); if (!c->sink_input) { @@ -593,7 +593,7 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); pa_source_output_new_data_set_sample_spec(&data, &o->sample_spec); - pa_source_output_new(&c->source_output, p->core, &data, 0); + pa_source_output_new(&c->source_output, p->core, &data); pa_source_output_new_data_done(&data); if (!c->source_output) { diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 484421bb..d3e7a45c 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -134,8 +134,7 @@ static void reset_callbacks(pa_sink_input *i) { int pa_sink_input_new( pa_sink_input **_i, pa_core *core, - pa_sink_input_new_data *data, - pa_sink_input_flags_t flags) { + pa_sink_input_new_data *data) { pa_sink_input *i; pa_resampler *resampler = NULL; @@ -198,15 +197,15 @@ int pa_sink_input_new( if (!data->muted_is_set) data->muted = FALSE; - if (flags & PA_SINK_INPUT_FIX_FORMAT) + if (data->flags & PA_SINK_INPUT_FIX_FORMAT) data->sample_spec.format = data->sink->sample_spec.format; - if (flags & PA_SINK_INPUT_FIX_RATE) + if (data->flags & PA_SINK_INPUT_FIX_RATE) data->sample_spec.rate = data->sink->sample_spec.rate; original_cm = data->channel_map; - if (flags & PA_SINK_INPUT_FIX_CHANNELS) { + if (data->flags & PA_SINK_INPUT_FIX_CHANNELS) { data->sample_spec.channels = data->sink->sample_spec.channels; data->channel_map = data->sink->channel_map; } @@ -225,7 +224,7 @@ int pa_sink_input_new( if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0) return r; - if ((flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND) && + if ((data->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND) && pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) { pa_log_warn("Failed to create sink input: sink is suspended."); return -PA_ERR_BADSTATE; @@ -236,7 +235,7 @@ int pa_sink_input_new( return -PA_ERR_TOOLARGE; } - if ((flags & PA_SINK_INPUT_VARIABLE_RATE) || + if ((data->flags & PA_SINK_INPUT_VARIABLE_RATE) || !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec) || !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) { @@ -245,9 +244,9 @@ int pa_sink_input_new( &data->sample_spec, &data->channel_map, &data->sink->sample_spec, &data->sink->channel_map, data->resample_method, - ((flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | - ((flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | - (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | + ((data->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | + ((data->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | + (core->disable_remixing || (data->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) { pa_log_warn("Unsupported resampling operation."); return -PA_ERR_NOTSUPPORTED; @@ -260,7 +259,7 @@ int pa_sink_input_new( i->core = core; i->state = PA_SINK_INPUT_INIT; - i->flags = flags; + i->flags = data->flags; i->proplist = pa_proplist_copy(data->proplist); i->driver = pa_xstrdup(pa_path_get_filename(data->driver)); i->module = data->module; diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 06e9e4f2..59eabe36 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -256,6 +256,8 @@ typedef struct pa_sink_input_send_event_hook_data { } pa_sink_input_send_event_hook_data; typedef struct pa_sink_input_new_data { + pa_sink_input_flags_t flags; + pa_proplist *proplist; const char *driver; @@ -298,8 +300,7 @@ void pa_sink_input_new_data_done(pa_sink_input_new_data *data); int pa_sink_input_new( pa_sink_input **i, pa_core *core, - pa_sink_input_new_data *data, - pa_sink_input_flags_t flags); + pa_sink_input_new_data *data); void pa_sink_input_put(pa_sink_input *i); void pa_sink_input_unlink(pa_sink_input* i); diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index c4b4d1a5..16de4923 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -311,7 +311,7 @@ int pa_play_file( pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname); pa_sndfile_init_proplist(u->sndfile, data.proplist); - pa_sink_input_new(&u->sink_input, sink->core, &data, 0); + pa_sink_input_new(&u->sink_input, sink->core, &data); pa_sink_input_new_data_done(&data); if (!u->sink_input) diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 43733400..1509807b 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -101,8 +101,7 @@ static void reset_callbacks(pa_source_output *o) { int pa_source_output_new( pa_source_output**_o, pa_core *core, - pa_source_output_new_data *data, - pa_source_output_flags_t flags) { + pa_source_output_new_data *data) { pa_source_output *o; pa_resampler *resampler = NULL; @@ -146,13 +145,13 @@ int pa_source_output_new( pa_return_val_if_fail(pa_channel_map_valid(&data->channel_map), -PA_ERR_INVALID); pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID); - if (flags & PA_SOURCE_OUTPUT_FIX_FORMAT) + if (data->flags & PA_SOURCE_OUTPUT_FIX_FORMAT) data->sample_spec.format = data->source->sample_spec.format; - if (flags & PA_SOURCE_OUTPUT_FIX_RATE) + if (data->flags & PA_SOURCE_OUTPUT_FIX_RATE) data->sample_spec.rate = data->source->sample_spec.rate; - if (flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) { + if (data->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) { data->sample_spec.channels = data->source->sample_spec.channels; data->channel_map = data->source->channel_map; } @@ -168,7 +167,7 @@ int pa_source_output_new( if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0) return r; - if ((flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) && + if ((data->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) && pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) { pa_log("Failed to create source output: source is suspended."); return -PA_ERR_BADSTATE; @@ -179,7 +178,7 @@ int pa_source_output_new( return -PA_ERR_TOOLARGE; } - if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) || + if ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) || !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) { @@ -188,9 +187,9 @@ int pa_source_output_new( &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, data->resample_method, - ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | - ((flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | - (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | + ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | + ((data->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | + (core->disable_remixing || (data->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) { pa_log_warn("Unsupported resampling operation."); return -PA_ERR_NOTSUPPORTED; @@ -203,7 +202,7 @@ int pa_source_output_new( o->core = core; o->state = PA_SOURCE_OUTPUT_INIT; - o->flags = flags; + o->flags = data->flags; o->proplist = pa_proplist_copy(data->proplist); o->driver = pa_xstrdup(pa_path_get_filename(data->driver)); o->module = data->module; diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index aca9ddf2..273b78fc 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -201,6 +201,8 @@ typedef struct pa_source_output_send_event_hook_data { } pa_source_output_send_event_hook_data; typedef struct pa_source_output_new_data { + pa_source_output_flags_t flags; + pa_proplist *proplist; pa_sink_input *direct_on_input; @@ -231,8 +233,7 @@ void pa_source_output_new_data_done(pa_source_output_new_data *data); int pa_source_output_new( pa_source_output**o, pa_core *core, - pa_source_output_new_data *data, - pa_source_output_flags_t flags); + pa_source_output_new_data *data); void pa_source_output_put(pa_source_output *o); void pa_source_output_unlink(pa_source_output*o); -- cgit From f0290413726f98a5a59bb7f1e70cf516f123b8bd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Aug 2009 23:24:37 +0200 Subject: suspend-on-idle: don't resume devices for corked streams --- src/modules/module-suspend-on-idle.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c index 70a7b049..7adaa0b1 100644 --- a/src/modules/module-suspend-on-idle.c +++ b/src/modules/module-suspend-on-idle.c @@ -145,6 +145,9 @@ static pa_hook_result_t sink_input_fixate_hook_cb(pa_core *c, pa_sink_input_new_ pa_assert(data); pa_assert(u); + if (data->flags & PA_SINK_INPUT_START_CORKED) + return PA_HOOK_OK; + if ((d = pa_hashmap_get(u->device_infos, data->sink))) resume(d); @@ -158,6 +161,9 @@ static pa_hook_result_t source_output_fixate_hook_cb(pa_core *c, pa_source_outpu pa_assert(data); pa_assert(u); + if (data->flags & PA_SOURCE_OUTPUT_START_CORKED) + return PA_HOOK_OK; + if (data->source->monitor_of) d = pa_hashmap_get(u->device_infos, data->source->monitor_of); else @@ -226,11 +232,16 @@ static pa_hook_result_t sink_input_move_start_hook_cb(pa_core *c, pa_sink_input static pa_hook_result_t sink_input_move_finish_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { struct device_info *d; + pa_sink_input_state_t state; pa_assert(c); pa_sink_input_assert_ref(s); pa_assert(u); + state = pa_sink_input_get_state(s); + if (state != PA_SINK_INPUT_RUNNING && state != PA_SINK_INPUT_DRAINED) + return PA_HOOK_OK; + if ((d = pa_hashmap_get(u->device_infos, s->sink))) resume(d); @@ -265,6 +276,9 @@ static pa_hook_result_t source_output_move_finish_hook_cb(pa_core *c, pa_source_ pa_source_output_assert_ref(s); pa_assert(u); + if (pa_source_output_get_state(s) != PA_SOURCE_OUTPUT_RUNNING) + return PA_HOOK_OK; + if (s->source->monitor_of) d = pa_hashmap_get(u->device_infos, s->source->monitor_of); else @@ -279,6 +293,7 @@ static pa_hook_result_t source_output_move_finish_hook_cb(pa_core *c, pa_source_ static pa_hook_result_t sink_input_state_changed_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { struct device_info *d; pa_sink_input_state_t state; + pa_assert(c); pa_sink_input_assert_ref(s); pa_assert(u); @@ -292,15 +307,11 @@ static pa_hook_result_t sink_input_state_changed_hook_cb(pa_core *c, pa_sink_inp } static pa_hook_result_t source_output_state_changed_hook_cb(pa_core *c, pa_source_output *s, struct userdata *u) { - pa_source_output_state_t state; - pa_assert(c); pa_source_output_assert_ref(s); pa_assert(u); - state = pa_source_output_get_state(s); - - if (state == PA_SOURCE_OUTPUT_RUNNING) { + if (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_RUNNING) { struct device_info *d; if (s->source->monitor_of) @@ -387,22 +398,17 @@ static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, s pa_sink *s = PA_SINK(o); pa_sink_state_t state = pa_sink_get_state(s); - if (pa_sink_check_suspend(s) <= 0) { - + if (pa_sink_check_suspend(s) <= 0) if (PA_SINK_IS_OPENED(state)) restart(d); - } - } else if (pa_source_isinstance(o)) { pa_source *s = PA_SOURCE(o); pa_source_state_t state = pa_source_get_state(s); - if (pa_source_check_suspend(s) <= 0) { - + if (pa_source_check_suspend(s) <= 0) if (PA_SOURCE_IS_OPENED(state)) restart(d); - } } return PA_HOOK_OK; -- cgit From ca2c0f22d8c2cf68f2119ca6f45fe08865451526 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Aug 2009 23:30:15 +0200 Subject: sconv: quieten gcc a bit --- src/pulsecore/sconv_sse.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sconv_sse.c b/src/pulsecore/sconv_sse.c index b213d991..ef78fc26 100644 --- a/src/pulsecore/sconv_sse.c +++ b/src/pulsecore/sconv_sse.c @@ -35,8 +35,6 @@ #include "cpu-x86.h" #include "sconv.h" -static pa_convert_func_t func; - #if defined (__i386__) || defined (__amd64__) static const PA_DECLARE_ALIGNED (16, float, one[4]) = { 1.0, 1.0, 1.0, 1.0 }; @@ -178,6 +176,7 @@ static void run_test (void) { float floats[SAMPLES]; int i; pa_usec_t start, stop; + pa_convert_func_t func; printf ("checking SSE %zd\n", sizeof (samples)); @@ -232,4 +231,3 @@ void pa_convert_func_init_sse (pa_cpu_x86_flag_t flags) { #endif /* defined (__i386__) || defined (__amd64__) */ } - -- cgit From 3b54849a089a492fdc67dce41795afaf3c0c3b50 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Aug 2009 23:30:41 +0200 Subject: core: add priority field to pa_sink/pa_source --- src/pulsecore/cli-text.c | 4 ++++ src/pulsecore/sink.c | 1 + src/pulsecore/sink.h | 2 ++ src/pulsecore/source.c | 1 + src/pulsecore/source.h | 2 ++ 5 files changed, 10 insertions(+) (limited to 'src') diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index c7a178d6..23a57d37 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -232,6 +232,7 @@ char *pa_sink_list_to_string(pa_core *c) { "\tflags: %s%s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsuspend cause: %s%s%s%s\n" + "\tpriority: %u\n" "\tvolume: %s%s%s\n" "\t balance %0.2f\n" "\tbase volume: %s%s%s\n" @@ -262,6 +263,7 @@ char *pa_sink_list_to_string(pa_core *c) { sink->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "", sink->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "", sink->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "", + sink->priority, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)), sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "", sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE)) : "", @@ -356,6 +358,7 @@ char *pa_source_list_to_string(pa_core *c) { "\tflags: %s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsuspend cause: %s%s%s%s\n" + "\tpriority: %u\n" "\tvolume: %s%s%s\n" "\t balance %0.2f\n" "\tbase volume: %s%s%s\n" @@ -383,6 +386,7 @@ char *pa_source_list_to_string(pa_core *c) { source->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "", source->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "", source->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "", + source->priority, pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source, FALSE)), source->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "", source->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_source_get_volume(source, FALSE)) : "", diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 5cec7747..49a5167e 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -236,6 +236,7 @@ pa_sink* pa_sink_new( s->core = core; s->state = PA_SINK_INIT; s->flags = flags; + s->priority = 0; s->suspend_cause = 0; s->name = pa_xstrdup(name); s->proplist = pa_proplist_copy(data->proplist); diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index b5284b71..1e4d0e31 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -109,6 +109,8 @@ struct pa_sink { pa_hashmap *ports; pa_device_port *active_port; + unsigned priority; + /* Called when the main loop requests a state change. Called from * main loop context. If returns -1 the state change will be * inhibited */ diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 3026654e..6600b74d 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -205,6 +205,7 @@ pa_source* pa_source_new( s->core = core; s->state = PA_SOURCE_INIT; s->flags = flags; + s->priority = 0; s->suspend_cause = 0; s->name = pa_xstrdup(name); s->proplist = pa_proplist_copy(data->proplist); diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index df3f99df..e3e56bc4 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -96,6 +96,8 @@ struct pa_source { pa_hashmap *ports; pa_device_port *active_port; + unsigned priority; + /* Called when the main loop requests a state change. Called from * main loop context. If returns -1 the state change will be * inhibited */ -- cgit From 85a683f39228f506f6a4af3165e84993d283e74d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Aug 2009 03:56:03 +0200 Subject: namereg: add new pa_namereg_is_valid_name_or_wildcard() call --- src/pulsecore/namereg.c | 22 +++++++++++++++++++++- src/pulsecore/namereg.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index e26923d4..7d221aaf 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -57,6 +57,8 @@ static pa_bool_t is_valid_char(char c) { pa_bool_t pa_namereg_is_valid_name(const char *name) { const char *c; + pa_assert(name); + if (*name == 0) return FALSE; @@ -70,6 +72,25 @@ pa_bool_t pa_namereg_is_valid_name(const char *name) { return TRUE; } +pa_bool_t pa_namereg_is_valid_name_or_wildcard(const char *name, pa_namereg_type_t type) { + + pa_assert(name); + + if (pa_namereg_is_valid_name(name)) + return TRUE; + + if (type == PA_NAMEREG_SINK && + pa_streq(name, "@DEFAULT_SINK@")) + return TRUE; + + if (type == PA_NAMEREG_SOURCE && + (pa_streq(name, "@DEFAULT_SOURCE@") || + pa_streq(name, "@DEFAULT_MONITOR@"))) + return TRUE; + + return FALSE; +} + char* pa_namereg_make_valid_name(const char *name) { const char *a; char *b, *n; @@ -191,7 +212,6 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type) { if ((s = pa_namereg_get(c, NULL, PA_NAMEREG_SINK))) return s->monitor_source; - } if (!name) diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index 38fae6f5..b5a976d7 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -45,6 +45,7 @@ pa_sink *pa_namereg_get_default_sink(pa_core *c); pa_source *pa_namereg_get_default_source(pa_core *c); pa_bool_t pa_namereg_is_valid_name(const char *name); +pa_bool_t pa_namereg_is_valid_name_or_wildcard(const char *name, pa_namereg_type_t type); char* pa_namereg_make_valid_name(const char *name); #endif -- cgit From a7b312520600de2315a8ceb9935faabdf929f6db Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Aug 2009 03:57:53 +0200 Subject: protocol-native: replace use of pa_namereg_is_valid_name() by pa_namereg_is_valid_name_or_wildcard() where applicable to allow use of @@ wildcards --- src/pulsecore/protocol-native.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 4bf5b3f9..a5e952a3 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1868,7 +1868,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); @@ -2117,7 +2117,7 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name(source_name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); @@ -2463,7 +2463,7 @@ static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_LOOKUP_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); if (command == PA_COMMAND_LOOKUP_SINK) { pa_sink *sink; @@ -2734,7 +2734,7 @@ static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag return; } - CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); @@ -3108,7 +3108,12 @@ static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, p } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || + (command == PA_COMMAND_GET_SINK_INFO && + pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) || + (command == PA_COMMAND_GET_SOURCE_INFO && + pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) || + pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); @@ -3350,7 +3355,7 @@ static void command_set_volume( } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_VOLUME ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); @@ -3428,7 +3433,7 @@ static void command_set_mute( } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_MUTE ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); @@ -4094,7 +4099,7 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name(name_device), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name_or_wildcard(name_device, command == PA_COMMAND_MOVE_SINK_INPUT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID); @@ -4158,7 +4163,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name) || *name == 0, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SUSPEND_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) || *name == 0, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); @@ -4318,7 +4323,7 @@ static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_PORT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); -- cgit From 18b13a89a516dbc33acbddbd9600c05cb9cb0246 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Aug 2009 03:58:57 +0200 Subject: namereg: select default sink by priority --- src/pulsecore/namereg.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index 7d221aaf..37755777 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -269,7 +269,7 @@ pa_source* pa_namereg_set_default_source(pa_core*c, pa_source *s) { } pa_sink *pa_namereg_get_default_sink(pa_core *c) { - pa_sink *s; + pa_sink *s, *best = NULL; uint32_t idx; pa_assert(c); @@ -277,18 +277,19 @@ pa_sink *pa_namereg_get_default_sink(pa_core *c) { if (c->default_sink && PA_SINK_IS_LINKED(pa_sink_get_state(c->default_sink))) return c->default_sink; - /* FIXME: the selection here should be based priority values on - * the sinks */ - PA_IDXSET_FOREACH(s, c->sinks, idx) if (PA_SINK_IS_LINKED(pa_sink_get_state(s))) - return pa_namereg_set_default_sink(c, s); + if (!best || s->priority > best->priority) + best = s; + + if (best) + return pa_namereg_set_default_sink(c, best); return NULL; } pa_source *pa_namereg_get_default_source(pa_core *c) { - pa_source *s; + pa_source *s, *best = NULL; uint32_t idx; pa_assert(c); @@ -299,12 +300,26 @@ pa_source *pa_namereg_get_default_source(pa_core *c) { /* First, try to find one that isn't a monitor */ PA_IDXSET_FOREACH(s, c->sources, idx) if (!s->monitor_of && PA_SOURCE_IS_LINKED(pa_source_get_state(s))) - return pa_namereg_set_default_source(c, s); + if (!best || + s->priority > best->priority) + best = s; + + if (best) + return pa_namereg_set_default_source(c, best); /* Then, fallback to a monitor */ PA_IDXSET_FOREACH(s, c->sources, idx) if (PA_SOURCE_IS_LINKED(pa_source_get_state(s))) - return pa_namereg_set_default_source(c, s); + if (!best || + s->priority > best->priority || + (s->priority == best->priority && + s->monitor_of && + best->monitor_of && + s->monitor_of->priority > best->monitor_of->priority)) + best = s; + + if (best) + return pa_namereg_set_default_source(c, best); return NULL; } -- cgit From 8bf2e3fe94e0dcd0a39a67c461b787d79adcd0dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Aug 2009 04:31:33 +0200 Subject: core: initialize sink/source priorities automatically based on their proplists --- src/pulsecore/sink.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/pulsecore/sink.h | 1 + src/pulsecore/source.c | 2 ++ 3 files changed, 50 insertions(+) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 49a5167e..48c50b0b 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -244,6 +244,8 @@ pa_sink* pa_sink_new( s->module = data->module; s->card = data->card; + s->priority = pa_device_init_priority(s->proplist); + s->sample_spec = data->sample_spec; s->channel_map = data->channel_map; @@ -2696,3 +2698,48 @@ pa_bool_t pa_device_init_intended_roles(pa_proplist *p) { return FALSE; } + +unsigned pa_device_init_priority(pa_proplist *p) { + const char *s; + unsigned priority = 0; + + pa_assert(p); + + if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS))) { + + if (pa_streq(s, "sound")) + priority += 9000; + else if (!pa_streq(s, "modem")) + priority += 1000; + } + + if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) { + + if (pa_streq(s, "internal")) + priority += 900; + else if (pa_streq(s, "speaker")) + priority += 500; + else if (pa_streq(s, "headphone")) + priority += 400; + } + + if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_BUS))) { + + if (pa_streq(s, "pci")) + priority += 50; + else if (pa_streq(s, "usb")) + priority += 40; + else if (pa_streq(s, "bluetooth")) + priority += 30; + } + + if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) { + + if (pa_startswith(s, "analog-")) + priority += 9; + else if (pa_startswith(s, "iec958-")) + priority += 8; + } + + return priority; +} diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 1e4d0e31..ba547fc3 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -290,6 +290,7 @@ void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t valu pa_bool_t pa_device_init_description(pa_proplist *p); pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink); pa_bool_t pa_device_init_intended_roles(pa_proplist *p); +unsigned pa_device_init_priority(pa_proplist *p); /**** May be called by everyone, from main context */ diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 6600b74d..1c77e0b9 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -213,6 +213,8 @@ pa_source* pa_source_new( s->module = data->module; s->card = data->card; + s->priority = pa_device_init_priority(s->proplist); + s->sample_spec = data->sample_spec; s->channel_map = data->channel_map; -- cgit From e1ce365cd9cdcdfd1535aa58882de249c6274ed4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Aug 2009 06:11:02 +0200 Subject: native: make sure clients cannot trigger an assert by sending us invalid volume info --- src/pulsecore/protocol-native.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index a5e952a3..179e62e2 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -3390,12 +3390,18 @@ static void command_set_volume( client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); if (sink) { + CHECK_VALIDITY(c->pstream, pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID); + pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name); pa_sink_set_volume(sink, &volume, TRUE, TRUE); } else if (source) { + CHECK_VALIDITY(c->pstream, pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID); + pa_log_debug("Client %s changes volume of source %s.", client_name, source->name); pa_source_set_volume(source, &volume, TRUE); } else if (si) { + CHECK_VALIDITY(c->pstream, pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID); + pa_log_debug("Client %s changes volume of sink input %s.", client_name, pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME))); @@ -3441,7 +3447,6 @@ static void command_set_mute( switch (command) { case PA_COMMAND_SET_SINK_MUTE: - if (idx != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else -- cgit From 2970c11902b46414d9ff28db1e850d94b137157c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Aug 2009 21:40:59 +0200 Subject: core: always allow volume setting with single-channel pa_cvolume --- src/pulsecore/protocol-native.c | 6 +++--- src/pulsecore/sink-input.c | 14 ++++++++++++-- src/pulsecore/sink.c | 10 ++++++++-- src/pulsecore/source.c | 13 ++++++++++--- 4 files changed, 33 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 179e62e2..d961dba2 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -3390,17 +3390,17 @@ static void command_set_volume( client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); if (sink) { - CHECK_VALIDITY(c->pstream, pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID); pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name); pa_sink_set_volume(sink, &volume, TRUE, TRUE); } else if (source) { - CHECK_VALIDITY(c->pstream, pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID); pa_log_debug("Client %s changes volume of source %s.", client_name, source->name); pa_source_set_volume(source, &volume, TRUE); } else if (si) { - CHECK_VALIDITY(c->pstream, pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID); pa_log_debug("Client %s changes volume of sink input %s.", client_name, diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index d3e7a45c..adda2aff 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -941,12 +941,22 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(volume); pa_assert(pa_cvolume_valid(volume)); - pa_assert(pa_cvolume_compatible(volume, &i->sample_spec)); + pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &i->sample_spec)); if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) { v = i->sink->reference_volume; pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map); - volume = pa_sw_cvolume_multiply(&v, &v, volume); + + if (pa_cvolume_compatible(volume, &i->sample_spec)) + volume = pa_sw_cvolume_multiply(&v, &v, volume); + else + volume = pa_sw_cvolume_multiply_scalar(&v, &v, pa_cvolume_max(volume)); + } else { + + if (!pa_cvolume_compatible(volume, &i->sample_spec)) { + v = i->volume; + volume = pa_cvolume_scale(&v, pa_cvolume_max(volume)); + } } if (pa_cvolume_equal(volume, &i->volume)) { diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 48c50b0b..f5a6fc50 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1408,8 +1408,11 @@ void pa_sink_set_volume( pa_assert_ctl_context(); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(!volume || pa_cvolume_valid(volume)); - pa_assert(!volume || pa_cvolume_compatible(volume, &s->sample_spec)); pa_assert(volume || (s->flags & PA_SINK_FLAT_VOLUME)); + pa_assert(!volume || volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec)); + + /* As a special exception we accept mono volumes on all sinks -- + * even on those with more complex channel maps */ /* If volume is NULL we synchronize the sink's real and reference * volumes with the stream volumes. If it is not NULL we update @@ -1419,7 +1422,10 @@ void pa_sink_set_volume( if (volume) { - s->reference_volume = *volume; + if (pa_cvolume_compatible(volume, &s->sample_spec)) + s->reference_volume = *volume; + else + pa_cvolume_scale(&s->reference_volume, pa_cvolume_max(volume)); if (s->flags & PA_SINK_FLAT_VOLUME) { /* OK, propagate this volume change back to the inputs */ diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 1c77e0b9..415c54bc 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -760,15 +760,22 @@ void pa_source_set_volume( pa_bool_t save) { pa_bool_t real_changed; + pa_cvolume old_volume; pa_source_assert_ref(s); pa_assert_ctl_context(); pa_assert(PA_SOURCE_IS_LINKED(s->state)); pa_assert(pa_cvolume_valid(volume)); - pa_assert(pa_cvolume_compatible(volume, &s->sample_spec)); + pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec)); - real_changed = !pa_cvolume_equal(volume, &s->volume); - s->volume = *volume; + old_volume = s->volume; + + if (pa_cvolume_compatible(volume, &s->sample_spec)) + s->volume = *volume; + else + pa_cvolume_scale(&s->volume, pa_cvolume_max(volume)); + + real_changed = !pa_cvolume_equal(&old_volume, &s->volume); s->save_volume = (!real_changed && s->save_volume) || save; if (s->set_volume) { -- cgit From 7c6a0ec66cd168b423bb66ef1ed266c4fbbcf3f3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Aug 2009 21:41:36 +0200 Subject: cli: apply single-channel volume changes equally to all channels --- src/pulsecore/cli-command.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 6ec74647..06a83b53 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -529,7 +529,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return -1; } - pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); + pa_cvolume_set(&cvolume, 1, volume); pa_sink_set_volume(sink, &cvolume, TRUE, TRUE); return 0; } @@ -571,7 +571,7 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb return -1; } - pa_cvolume_set(&cvolume, si->sample_spec.channels, volume); + pa_cvolume_set(&cvolume, 1, volume); pa_sink_input_set_volume(si, &cvolume, TRUE, TRUE); return 0; } @@ -607,7 +607,7 @@ static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf * return -1; } - pa_cvolume_set(&cvolume, source->sample_spec.channels, volume); + pa_cvolume_set(&cvolume, 1, volume); pa_source_set_volume(source, &cvolume, TRUE); return 0; } -- cgit From e20d9068a31c7456e292aedec735dc776c44d0b6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Aug 2009 21:42:09 +0200 Subject: cli: make sure 'dump' uses pa_cvolume_max() to deduce a single-channel volume from a multi-channel volume --- src/pulsecore/cli-command.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 06a83b53..3c94960c 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -1586,7 +1586,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b nl = 1; } - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE))); + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_max(pa_sink_get_volume(sink, FALSE))); pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, FALSE))); pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED)); } @@ -1598,7 +1598,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b nl = 1; } - pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, FALSE))); + pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_max(pa_source_get_volume(source, FALSE))); pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source, FALSE))); pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(pa_source_get_state(source) == PA_SOURCE_SUSPENDED)); } -- cgit From 5b61a1991c4e2aaa6c31c5f468cca279b8142e16 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Aug 2009 21:42:54 +0200 Subject: pactl: implement pactl commands for changing volumes/mute stati --- src/utils/pactl.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 177 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/utils/pactl.c b/src/utils/pactl.c index c8c3a437..20095944 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -50,7 +50,6 @@ static pa_context *context = NULL; static pa_mainloop_api *mainloop_api = NULL; static char - *device = NULL, *sample_name = NULL, *sink_name = NULL, *source_name = NULL, @@ -66,6 +65,8 @@ static uint32_t static uint32_t module_index; static pa_bool_t suspend; +static pa_bool_t mute; +static pa_volume_t volume; static pa_proplist *proplist = NULL; @@ -74,7 +75,6 @@ static pa_stream *sample_stream = NULL; static pa_sample_spec sample_spec; static pa_channel_map channel_map; static size_t sample_length = 0; - static int actions = 1; static pa_bool_t nl = FALSE; @@ -95,7 +95,13 @@ static enum { SUSPEND_SOURCE, SET_CARD_PROFILE, SET_SINK_PORT, - SET_SOURCE_PORT + SET_SOURCE_PORT, + SET_SINK_VOLUME, + SET_SOURCE_VOLUME, + SET_SINK_INPUT_VOLUME, + SET_SINK_MUTE, + SET_SOURCE_MUTE, + SET_SINK_INPUT_MUTE } action = NONE; static void quit(int ret) { @@ -109,6 +115,7 @@ static void context_drain_complete(pa_context *c, void *userdata) { static void drain(void) { pa_operation *o; + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) pa_context_disconnect(context); else @@ -726,7 +733,7 @@ static void context_state_callback(pa_context *c, void *userdata) { break; case PLAY_SAMPLE: - pa_operation_unref(pa_context_play_sample(c, sample_name, device, PA_VOLUME_NORM, simple_callback, NULL)); + pa_operation_unref(pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL)); break; case REMOVE_SAMPLE: @@ -800,6 +807,42 @@ static void context_state_callback(pa_context *c, void *userdata) { pa_operation_unref(pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL)); break; + case SET_SINK_MUTE: + pa_operation_unref(pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL)); + break; + + case SET_SOURCE_MUTE: + pa_operation_unref(pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL)); + break; + + case SET_SINK_INPUT_MUTE: + pa_operation_unref(pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL)); + break; + + case SET_SINK_VOLUME: { + pa_cvolume v; + + pa_cvolume_set(&v, 1, volume); + pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL)); + break; + } + + case SET_SOURCE_VOLUME: { + pa_cvolume v; + + pa_cvolume_set(&v, 1, volume); + pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL)); + break; + } + + case SET_SINK_INPUT_VOLUME: { + pa_cvolume v; + + pa_cvolume_set(&v, 1, volume); + pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL)); + break; + } + default: pa_assert_not_reached(); } @@ -829,20 +872,30 @@ static void help(const char *argv0) { "%s [options] upload-sample FILENAME [NAME]\n" "%s [options] play-sample NAME [SINK]\n" "%s [options] remove-sample NAME\n" - "%s [options] move-sink-input ID SINK\n" - "%s [options] move-source-output ID SOURCE\n" + "%s [options] move-sink-input SINKINPUT SINK\n" + "%s [options] move-source-output SOURCEOUTPUT SOURCE\n" "%s [options] load-module NAME [ARGS ...]\n" - "%s [options] unload-module ID\n" - "%s [options] suspend-sink [SINK] 1|0\n" - "%s [options] suspend-source [SOURCE] 1|0\n" - "%s [options] set-card-profile [CARD] [PROFILE] \n" - "%s [options] set-sink-port [SINK] [PORT] \n" - "%s [options] set-source-port [SOURCE] [PORT] \n\n" + "%s [options] unload-module MODULE\n" + "%s [options] suspend-sink SINK 1|0\n" + "%s [options] suspend-source SOURCE 1|0\n" + "%s [options] set-card-profile CARD PROFILE\n" + "%s [options] set-sink-port SINK PORT\n" + "%s [options] set-source-port SOURCE PORT\n" + "%s [options] set-sink-volume SINK VOLUME\n" + "%s [options] set-source-volume SOURCE VOLUME\n" + "%s [options] set-sink-input-volume SINKINPUT VOLUME\n" + "%s [options] set-sink-mute SINK 1|0\n" + "%s [options] set-source-mute SOURCE 1|0\n" + "%s [options] set-sink-input-mute SINKINPUT 1|0\n\n" " -h, --help Show this help\n" " --version Show version\n\n" " -s, --server=SERVER The name of the server to connect to\n" " -n, --client-name=NAME How to call this client on the server\n"), - argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0); + argv0, argv0, argv0, argv0, argv0, + argv0, argv0, argv0, argv0, argv0, + argv0, argv0, argv0, argv0, argv0, + argv0, argv0, argv0, argv0, argv0, + argv0); } enum { @@ -965,7 +1018,7 @@ int main(int argc, char *argv[]) { sample_name = pa_xstrdup(argv[optind+1]); if (optind+2 < argc) - device = pa_xstrdup(argv[optind+2]); + sink_name = pa_xstrdup(argv[optind+2]); } else if (pa_streq(argv[optind], "remove-sample")) { action = REMOVE_SAMPLE; @@ -1088,6 +1141,116 @@ int main(int argc, char *argv[]) { source_name = pa_xstrdup(argv[optind+1]); port_name = pa_xstrdup(argv[optind+2]); + } else if (pa_streq(argv[optind], "set-sink-volume")) { + uint32_t v; + action = SET_SINK_VOLUME; + + if (argc != optind+3) { + pa_log(_("You have to specify a sink name/index and a volume\n")); + goto quit; + } + + if (pa_atou(argv[optind+2], &v) < 0) { + pa_log(_("Invalid volume specification\n")); + goto quit; + } + + sink_name = pa_xstrdup(argv[optind+1]); + volume = (pa_volume_t) v; + + } else if (pa_streq(argv[optind], "set-source-volume")) { + uint32_t v; + action = SET_SOURCE_VOLUME; + + if (argc != optind+3) { + pa_log(_("You have to specify a source name/index and a volume\n")); + goto quit; + } + + if (pa_atou(argv[optind+2], &v) < 0) { + pa_log(_("Invalid volume specification\n")); + goto quit; + } + + source_name = pa_xstrdup(argv[optind+1]); + volume = (pa_volume_t) v; + + } else if (pa_streq(argv[optind], "set-sink-input-volume")) { + uint32_t v; + action = SET_SINK_INPUT_VOLUME; + + if (argc != optind+3) { + pa_log(_("You have to specify a sink input index and a volume\n")); + goto quit; + } + + if (pa_atou(argv[optind+1], &sink_input_idx) < 0) { + pa_log(_("Invalid sink input index\n")); + goto quit; + } + + if (pa_atou(argv[optind+2], &v) < 0) { + pa_log(_("Invalid volume specification\n")); + goto quit; + } + + volume = (pa_volume_t) v; + + } else if (pa_streq(argv[optind], "set-sink-mute")) { + int b; + action = SET_SINK_MUTE; + + if (argc != optind+3) { + pa_log(_("You have to specify a sink name/index and a mute boolean\n")); + goto quit; + } + + if ((b = pa_parse_boolean(argv[optind+2])) < 0) { + pa_log(_("Invalid volume specification\n")); + goto quit; + } + + sink_name = pa_xstrdup(argv[optind+1]); + mute = b; + + } else if (pa_streq(argv[optind], "set-source-mute")) { + int b; + action = SET_SOURCE_MUTE; + + if (argc != optind+3) { + pa_log(_("You have to specify a source name/index and a mute boolean\n")); + goto quit; + } + + if ((b = pa_parse_boolean(argv[optind+2])) < 0) { + pa_log(_("Invalid volume specification\n")); + goto quit; + } + + source_name = pa_xstrdup(argv[optind+1]); + mute = b; + + } else if (pa_streq(argv[optind], "set-sink-input-mute")) { + int b; + action = SET_SINK_INPUT_MUTE; + + if (argc != optind+3) { + pa_log(_("You have to specify a sink input index and a mute boolean\n")); + goto quit; + } + + if (pa_atou(argv[optind+1], &sink_input_idx) < 0) { + pa_log(_("Invalid sink input index specification\n")); + goto quit; + } + + if ((b = pa_parse_boolean(argv[optind+2])) < 0) { + pa_log(_("Invalid volume specification\n")); + goto quit; + } + + mute = b; + } else if (pa_streq(argv[optind], "help")) { help(bn); ret = 0; @@ -1141,7 +1304,6 @@ quit: } pa_xfree(server); - pa_xfree(device); pa_xfree(sample_name); pa_xfree(sink_name); pa_xfree(source_name); -- cgit From dee2aa3f0564caed698e600963b592d50cda068c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 31 Aug 2009 21:45:19 +0200 Subject: pactl: drop unnecessary newlines from pa_log() invocations --- src/utils/pactl.c | 100 +++++++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 20095944..b8f4ea75 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -132,7 +132,7 @@ static void complete_action(void) { static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) { char s[128]; if (!i) { - pa_log(_("Failed to get statistics: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -153,7 +153,7 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (!i) { - pa_log(_("Failed to get server information: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -202,7 +202,7 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_ char *pl; if (is_last < 0) { - pa_log(_("Failed to get sink information: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -294,7 +294,7 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int char *pl; if (is_last < 0) { - pa_log(_("Failed to get source information: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -372,7 +372,7 @@ static void get_module_info_callback(pa_context *c, const pa_module_info *i, int char *pl; if (is_last < 0) { - pa_log(_("Failed to get module information: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -409,7 +409,7 @@ static void get_client_info_callback(pa_context *c, const pa_client_info *i, int char *pl; if (is_last < 0) { - pa_log(_("Failed to get client information: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -444,7 +444,7 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_ char *pl; if (is_last < 0) { - pa_log(_("Failed to get card information: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get card information: %s"), pa_strerror(pa_context_errno(c))); complete_action(); return; } @@ -493,7 +493,7 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info char *pl; if (is_last < 0) { - pa_log(_("Failed to get sink input information: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -551,7 +551,7 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu char *pl; if (is_last < 0) { - pa_log(_("Failed to get source output information: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -602,7 +602,7 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int char *pl; if (is_last < 0) { - pa_log(_("Failed to get sample information: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -650,7 +650,7 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int static void simple_callback(pa_context *c, int success, void *userdata) { if (!success) { - pa_log(_("Failure: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -660,7 +660,7 @@ static void simple_callback(pa_context *c, int success, void *userdata) { static void index_callback(pa_context *c, uint32_t idx, void *userdata) { if (idx == PA_INVALID_INDEX) { - pa_log(_("Failure: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c))); quit(1); return; } @@ -684,7 +684,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) { case PA_STREAM_FAILED: default: - pa_log(_("Failed to upload sample: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s)))); quit(1); } } @@ -701,7 +701,7 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { if ((sf_readf_float(sndfile, d, l)) != l) { pa_xfree(d); - pa_log(_("Premature end of file\n")); + pa_log(_("Premature end of file")); quit(1); return; } @@ -854,13 +854,13 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_FAILED: default: - pa_log(_("Connection failure: %s\n"), pa_strerror(pa_context_errno(c))); + pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c))); quit(1); } } static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { - pa_log(_("Got SIGINT, exiting.\n")); + pa_log(_("Got SIGINT, exiting.")); quit(0); } @@ -950,7 +950,7 @@ int main(int argc, char *argv[]) { if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) { - pa_log(_("Invalid client name '%s'\n"), t ? t : optarg); + pa_log(_("Invalid client name '%s'"), t ? t : optarg); pa_xfree(t); goto quit; } @@ -976,7 +976,7 @@ int main(int argc, char *argv[]) { action = UPLOAD_SAMPLE; if (optind+1 >= argc) { - pa_log(_("Please specify a sample file to load\n")); + pa_log(_("Please specify a sample file to load")); goto quit; } @@ -989,19 +989,19 @@ int main(int argc, char *argv[]) { pa_zero(sfi); if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) { - pa_log(_("Failed to open sound file.\n")); + pa_log(_("Failed to open sound file.")); goto quit; } if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) { - pa_log(_("Failed to determine sample specification from file.\n")); + pa_log(_("Failed to determine sample specification from file.")); goto quit; } sample_spec.format = PA_SAMPLE_FLOAT32; if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) { if (sample_spec.channels > 2) - pa_log(_("Warning: Failed to determine sample specification from file.\n")); + pa_log(_("Warning: Failed to determine sample specification from file.")); pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); } @@ -1011,7 +1011,7 @@ int main(int argc, char *argv[]) { } else if (pa_streq(argv[optind], "play-sample")) { action = PLAY_SAMPLE; if (argc != optind+2 && argc != optind+3) { - pa_log(_("You have to specify a sample name to play\n")); + pa_log(_("You have to specify a sample name to play")); goto quit; } @@ -1023,7 +1023,7 @@ int main(int argc, char *argv[]) { } else if (pa_streq(argv[optind], "remove-sample")) { action = REMOVE_SAMPLE; if (argc != optind+2) { - pa_log(_("You have to specify a sample name to remove\n")); + pa_log(_("You have to specify a sample name to remove")); goto quit; } @@ -1032,7 +1032,7 @@ int main(int argc, char *argv[]) { } else if (pa_streq(argv[optind], "move-sink-input")) { action = MOVE_SINK_INPUT; if (argc != optind+3) { - pa_log(_("You have to specify a sink input index and a sink\n")); + pa_log(_("You have to specify a sink input index and a sink")); goto quit; } @@ -1042,7 +1042,7 @@ int main(int argc, char *argv[]) { } else if (pa_streq(argv[optind], "move-source-output")) { action = MOVE_SOURCE_OUTPUT; if (argc != optind+3) { - pa_log(_("You have to specify a source output index and a source\n")); + pa_log(_("You have to specify a source output index and a source")); goto quit; } @@ -1057,7 +1057,7 @@ int main(int argc, char *argv[]) { action = LOAD_MODULE; if (argc <= optind+1) { - pa_log(_("You have to specify a module name and arguments.\n")); + pa_log(_("You have to specify a module name and arguments.")); goto quit; } @@ -1077,7 +1077,7 @@ int main(int argc, char *argv[]) { action = UNLOAD_MODULE; if (argc != optind+2) { - pa_log(_("You have to specify a module index\n")); + pa_log(_("You have to specify a module index")); goto quit; } @@ -1087,7 +1087,7 @@ int main(int argc, char *argv[]) { action = SUSPEND_SINK; if (argc > optind+3 || optind+1 >= argc) { - pa_log(_("You may not specify more than one sink. You have to specify a boolean value.\n")); + pa_log(_("You may not specify more than one sink. You have to specify a boolean value.")); goto quit; } @@ -1100,7 +1100,7 @@ int main(int argc, char *argv[]) { action = SUSPEND_SOURCE; if (argc > optind+3 || optind+1 >= argc) { - pa_log(_("You may not specify more than one source. You have to specify a boolean value.\n")); + pa_log(_("You may not specify more than one source. You have to specify a boolean value.")); goto quit; } @@ -1112,7 +1112,7 @@ int main(int argc, char *argv[]) { action = SET_CARD_PROFILE; if (argc != optind+3) { - pa_log(_("You have to specify a card name/index and a profile name\n")); + pa_log(_("You have to specify a card name/index and a profile name")); goto quit; } @@ -1123,7 +1123,7 @@ int main(int argc, char *argv[]) { action = SET_SINK_PORT; if (argc != optind+3) { - pa_log(_("You have to specify a sink name/index and a port name\n")); + pa_log(_("You have to specify a sink name/index and a port name")); goto quit; } @@ -1134,7 +1134,7 @@ int main(int argc, char *argv[]) { action = SET_SOURCE_PORT; if (argc != optind+3) { - pa_log(_("You have to specify a source name/index and a port name\n")); + pa_log(_("You have to specify a source name/index and a port name")); goto quit; } @@ -1146,12 +1146,12 @@ int main(int argc, char *argv[]) { action = SET_SINK_VOLUME; if (argc != optind+3) { - pa_log(_("You have to specify a sink name/index and a volume\n")); + pa_log(_("You have to specify a sink name/index and a volume")); goto quit; } if (pa_atou(argv[optind+2], &v) < 0) { - pa_log(_("Invalid volume specification\n")); + pa_log(_("Invalid volume specification")); goto quit; } @@ -1163,12 +1163,12 @@ int main(int argc, char *argv[]) { action = SET_SOURCE_VOLUME; if (argc != optind+3) { - pa_log(_("You have to specify a source name/index and a volume\n")); + pa_log(_("You have to specify a source name/index and a volume")); goto quit; } if (pa_atou(argv[optind+2], &v) < 0) { - pa_log(_("Invalid volume specification\n")); + pa_log(_("Invalid volume specification")); goto quit; } @@ -1180,17 +1180,17 @@ int main(int argc, char *argv[]) { action = SET_SINK_INPUT_VOLUME; if (argc != optind+3) { - pa_log(_("You have to specify a sink input index and a volume\n")); + pa_log(_("You have to specify a sink input index and a volume")); goto quit; } if (pa_atou(argv[optind+1], &sink_input_idx) < 0) { - pa_log(_("Invalid sink input index\n")); + pa_log(_("Invalid sink input index")); goto quit; } if (pa_atou(argv[optind+2], &v) < 0) { - pa_log(_("Invalid volume specification\n")); + pa_log(_("Invalid volume specification")); goto quit; } @@ -1201,12 +1201,12 @@ int main(int argc, char *argv[]) { action = SET_SINK_MUTE; if (argc != optind+3) { - pa_log(_("You have to specify a sink name/index and a mute boolean\n")); + pa_log(_("You have to specify a sink name/index and a mute boolean")); goto quit; } if ((b = pa_parse_boolean(argv[optind+2])) < 0) { - pa_log(_("Invalid volume specification\n")); + pa_log(_("Invalid volume specification")); goto quit; } @@ -1218,12 +1218,12 @@ int main(int argc, char *argv[]) { action = SET_SOURCE_MUTE; if (argc != optind+3) { - pa_log(_("You have to specify a source name/index and a mute boolean\n")); + pa_log(_("You have to specify a source name/index and a mute boolean")); goto quit; } if ((b = pa_parse_boolean(argv[optind+2])) < 0) { - pa_log(_("Invalid volume specification\n")); + pa_log(_("Invalid volume specification")); goto quit; } @@ -1235,17 +1235,17 @@ int main(int argc, char *argv[]) { action = SET_SINK_INPUT_MUTE; if (argc != optind+3) { - pa_log(_("You have to specify a sink input index and a mute boolean\n")); + pa_log(_("You have to specify a sink input index and a mute boolean")); goto quit; } if (pa_atou(argv[optind+1], &sink_input_idx) < 0) { - pa_log(_("Invalid sink input index specification\n")); + pa_log(_("Invalid sink input index specification")); goto quit; } if ((b = pa_parse_boolean(argv[optind+2])) < 0) { - pa_log(_("Invalid volume specification\n")); + pa_log(_("Invalid volume specification")); goto quit; } @@ -1259,12 +1259,12 @@ int main(int argc, char *argv[]) { } if (action == NONE) { - pa_log(_("No valid command specified.\n")); + pa_log(_("No valid command specified.")); goto quit; } if (!(m = pa_mainloop_new())) { - pa_log(_("pa_mainloop_new() failed.\n")); + pa_log(_("pa_mainloop_new() failed.")); goto quit; } @@ -1276,7 +1276,7 @@ int main(int argc, char *argv[]) { pa_disable_sigpipe(); if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) { - pa_log(_("pa_context_new() failed.\n")); + pa_log(_("pa_context_new() failed.")); goto quit; } @@ -1287,7 +1287,7 @@ int main(int argc, char *argv[]) { } if (pa_mainloop_run(m, &ret) < 0) { - pa_log(_("pa_mainloop_run() failed.\n")); + pa_log(_("pa_mainloop_run() failed.")); goto quit; } -- cgit From dc221f204b89fca85c0125e55f3afea4a807ffa7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 29 Aug 2009 12:22:42 +0200 Subject: remap: fix counters for mmx and sse remap Take the size of the sample into account when calculating the amount of samples we process in parallel. --- src/pulsecore/remap_mmx.c | 34 +++++++++++++++++++++------------- src/pulsecore/remap_sse.c | 34 +++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/pulsecore/remap_mmx.c b/src/pulsecore/remap_mmx.c index b5fe82ee..79e4f1fc 100644 --- a/src/pulsecore/remap_mmx.c +++ b/src/pulsecore/remap_mmx.c @@ -65,16 +65,24 @@ " add $32, %1 \n\t" \ " add $64, %0 \n\t" -#define HANDLE_SINGLE(s) \ +#define HANDLE_SINGLE_dq() \ " movd (%1), %%mm0 \n\t" \ - " punpckl"#s" %%mm0, %%mm0 \n\t" \ + " punpckldq %%mm0, %%mm0 \n\t" \ " movq %%mm0, (%0) \n\t" \ " add $4, %1 \n\t" \ " add $8, %0 \n\t" -#define MONO_TO_STEREO(s) \ - " mov %3, %2 \n\t" \ - " sar $3, %2 \n\t" \ +#define HANDLE_SINGLE_wd() \ + " movw (%1), %w3 \n\t" \ + " movd %3, %%mm0 \n\t" \ + " punpcklwd %%mm0, %%mm0 \n\t" \ + " movd %%mm0, (%0) \n\t" \ + " add $2, %1 \n\t" \ + " add $4, %0 \n\t" + +#define MONO_TO_STEREO(s,shift,mask) \ + " mov %4, %2 \n\t" \ + " sar $"#shift", %2 \n\t" \ " cmp $0, %2 \n\t" \ " je 2f \n\t" \ "1: \n\t" \ @@ -84,11 +92,11 @@ " dec %2 \n\t" \ " jne 1b \n\t" \ "2: \n\t" \ - " mov %3, %2 \n\t" \ - " and $7, %2 \n\t" \ + " mov %4, %2 \n\t" \ + " and $"#mask", %2 \n\t" \ " je 4f \n\t" \ "3: \n\t" \ - HANDLE_SINGLE(s) \ + HANDLE_SINGLE_##s() \ " dec %2 \n\t" \ " jne 3b \n\t" \ "4: \n\t" \ @@ -96,14 +104,14 @@ #if defined (__i386__) || defined (__amd64__) static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src, unsigned n) { - pa_reg_x86 temp; + pa_reg_x86 temp, temp2; switch (*m->format) { case PA_SAMPLE_FLOAT32NE: { __asm__ __volatile__ ( - MONO_TO_STEREO(dq) /* do doubles to quads */ - : "+r" (dst), "+r" (src), "=&r" (temp) + MONO_TO_STEREO(dq,3,7) /* do doubles to quads */ + : "+r" (dst), "+r" (src), "=&r" (temp), "=&r" (temp2) : "r" ((pa_reg_x86)n) : "cc" ); @@ -112,8 +120,8 @@ static void remap_mono_to_stereo_mmx (pa_remap_t *m, void *dst, const void *src, case PA_SAMPLE_S16NE: { __asm__ __volatile__ ( - MONO_TO_STEREO(wd) /* do words to doubles */ - : "+r" (dst), "+r" (src), "=&r" (temp) + MONO_TO_STEREO(wd,4,15) /* do words to doubles */ + : "+r" (dst), "+r" (src), "=&r" (temp), "=&r" (temp2) : "r" ((pa_reg_x86)n) : "cc" ); diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c index 97f2476e..d6003571 100644 --- a/src/pulsecore/remap_sse.c +++ b/src/pulsecore/remap_sse.c @@ -65,16 +65,24 @@ " add $64, %1 \n\t" \ " add $128, %0 \n\t" -#define HANDLE_SINGLE(s) \ +#define HANDLE_SINGLE_dq() \ " movd (%1), %%xmm0 \n\t" \ - " punpckl"#s" %%xmm0, %%xmm0 \n\t" \ + " punpckldq %%xmm0, %%xmm0 \n\t" \ " movq %%xmm0, (%0) \n\t" \ " add $4, %1 \n\t" \ " add $8, %0 \n\t" -#define MONO_TO_STEREO(s) \ - " mov %3, %2 \n\t" \ - " sar $4, %2 \n\t" \ +#define HANDLE_SINGLE_wd() \ + " movw (%1), %w3 \n\t" \ + " movd %3, %%xmm0 \n\t" \ + " punpcklwd %%xmm0, %%xmm0 \n\t" \ + " movd %%xmm0, (%0) \n\t" \ + " add $2, %1 \n\t" \ + " add $4, %0 \n\t" + +#define MONO_TO_STEREO(s,shift,mask) \ + " mov %4, %2 \n\t" \ + " sar $"#shift", %2 \n\t" \ " cmp $0, %2 \n\t" \ " je 2f \n\t" \ "1: \n\t" \ @@ -84,24 +92,24 @@ " dec %2 \n\t" \ " jne 1b \n\t" \ "2: \n\t" \ - " mov %3, %2 \n\t" \ - " and $15, %2 \n\t" \ + " mov %4, %2 \n\t" \ + " and $"#mask", %2 \n\t" \ " je 4f \n\t" \ "3: \n\t" \ - HANDLE_SINGLE(s) \ + HANDLE_SINGLE_##s() \ " dec %2 \n\t" \ " jne 3b \n\t" \ "4: \n\t" static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, unsigned n) { - pa_reg_x86 temp; + pa_reg_x86 temp, temp2; switch (*m->format) { case PA_SAMPLE_FLOAT32NE: { __asm__ __volatile__ ( - MONO_TO_STEREO(dq) /* do doubles to quads */ - : "+r" (dst), "+r" (src), "=&r" (temp) + MONO_TO_STEREO(dq,3,7) /* do doubles to quads */ + : "+r" (dst), "+r" (src), "=&r" (temp), "=&r" (temp2) : "r" ((pa_reg_x86)n) : "cc" ); @@ -110,8 +118,8 @@ static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, case PA_SAMPLE_S16NE: { __asm__ __volatile__ ( - MONO_TO_STEREO(wd) /* do words to doubles */ - : "+r" (dst), "+r" (src), "=&r" (temp) + MONO_TO_STEREO(wd,4,15) /* do words to doubles */ + : "+r" (dst), "+r" (src), "=&r" (temp), "=&r" (temp2) : "r" ((pa_reg_x86)n) : "cc" ); -- cgit From dfe3f90b377a9cb2b158088c529a691086490afa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Sep 2009 00:53:49 +0200 Subject: daemon: don't override path env vars if they are already set --- src/daemon/main.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/daemon/main.c b/src/daemon/main.c index b1d1109a..e44892da 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -259,9 +259,14 @@ static int change_user(void) { pa_set_env("HOME", PA_SYSTEM_RUNTIME_PATH); /* Relevant for pa_runtime_path() */ - pa_set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH); - pa_set_env("PULSE_CONFIG_PATH", PA_SYSTEM_CONFIG_PATH); - pa_set_env("PULSE_STATE_PATH", PA_SYSTEM_STATE_PATH); + if (!getenv("PULSE_RUNTIME_PATH")) + pa_set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH); + + if (!getenv("PULSE_CONFIG_PATH")) + pa_set_env("PULSE_CONFIG_PATH", PA_SYSTEM_CONFIG_PATH); + + if (!getenv("PULSE_STATE_PATH")) + pa_set_env("PULSE_STATE_PATH", PA_SYSTEM_STATE_PATH); pa_log_info(_("Successfully dropped root privileges.")); -- cgit From 6b6d14626d5ae8b49edd1abe8ecc2432262358c9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Sep 2009 04:54:18 +0200 Subject: alsa: distuingish real underruns from left_to_play=0 --- src/modules/alsa/alsa-sink.c | 4 +++- src/modules/alsa/alsa-source.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 07d53880..afea8e08 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -410,6 +410,7 @@ static int try_recover(struct userdata *u, const char *call, int err) { static size_t check_left_to_play(struct userdata *u, size_t n_bytes, pa_bool_t on_timeout) { size_t left_to_play; + pa_bool_t underrun = FALSE; /* We use <= instead of < for this check here because an underrun * only happens after the last sample was processed, not already when @@ -422,6 +423,7 @@ static size_t check_left_to_play(struct userdata *u, size_t n_bytes, pa_bool_t o /* We got a dropout. What a mess! */ left_to_play = 0; + underrun = TRUE; #ifdef DEBUG_TIMING PA_DEBUG_TRAP; @@ -443,7 +445,7 @@ static size_t check_left_to_play(struct userdata *u, size_t n_bytes, pa_bool_t o pa_bool_t reset_not_before = TRUE; if (!u->first && !u->after_rewind) { - if (left_to_play < u->watermark_inc_threshold) + if (underrun || left_to_play < u->watermark_inc_threshold) increase_watermark(u); else if (left_to_play > u->watermark_dec_threshold) { reset_not_before = FALSE; diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 165b2e3b..643566b5 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -406,6 +406,7 @@ static int try_recover(struct userdata *u, const char *call, int err) { static size_t check_left_to_record(struct userdata *u, size_t n_bytes, pa_bool_t on_timeout) { size_t left_to_record; size_t rec_space = u->hwbuf_size - u->hwbuf_unused; + pa_bool_t overrun = FALSE; /* We use <= instead of < for this check here because an overrun * only happens after the last sample was processed, not already when @@ -418,6 +419,7 @@ static size_t check_left_to_record(struct userdata *u, size_t n_bytes, pa_bool_t /* We got a dropout. What a mess! */ left_to_record = 0; + overrun = TRUE; #ifdef DEBUG_TIMING PA_DEBUG_TRAP; @@ -434,7 +436,7 @@ static size_t check_left_to_record(struct userdata *u, size_t n_bytes, pa_bool_t if (u->use_tsched) { pa_bool_t reset_not_before = TRUE; - if (left_to_record < u->watermark_inc_threshold) + if (overrun || left_to_record < u->watermark_inc_threshold) increase_watermark(u); else if (left_to_record > u->watermark_dec_threshold) { reset_not_before = FALSE; -- cgit From 46b9ca7fd5747d1ddbb7f2d18d2b572ddb785dc6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Sep 2009 04:55:05 +0200 Subject: alsa: by default increase watermarks only on real underruns, don't try to be smart --- src/modules/alsa/alsa-sink.c | 5 ++++- src/modules/alsa/alsa-source.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index afea8e08..195bdf6e 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -69,9 +69,12 @@ #define TSCHED_WATERMARK_INC_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- On underrun, increase watermark by this */ #define TSCHED_WATERMARK_DEC_STEP_USEC (5*PA_USEC_PER_MSEC) /* 5ms -- When everything's great, decrease watermark by this */ #define TSCHED_WATERMARK_VERIFY_AFTER_USEC (20*PA_USEC_PER_SEC) /* 20s -- How long after a drop out recheck if things are good now */ -#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (1*PA_USEC_PER_MSEC) /* 3ms -- If the buffer level ever below this theshold, increase the watermark */ +#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (0*PA_USEC_PER_MSEC) /* 0ms -- If the buffer level ever below this theshold, increase the watermark */ #define TSCHED_WATERMARK_DEC_THRESHOLD_USEC (100*PA_USEC_PER_MSEC) /* 100ms -- If the buffer level didn't drop below this theshold in the verification time, decrease the watermark */ +/* Note that TSCHED_WATERMARK_INC_THRESHOLD_USEC == 0 means tht we + * will increase the watermark only if we hit a real underrun. */ + #define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- Sleep at least 10ms on each iteration */ #define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms -- Wakeup at least this long before the buffer runs empty*/ diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 643566b5..f42d3542 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -66,7 +66,7 @@ #define TSCHED_WATERMARK_INC_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */ #define TSCHED_WATERMARK_DEC_STEP_USEC (5*PA_USEC_PER_MSEC) /* 5ms */ #define TSCHED_WATERMARK_VERIFY_AFTER_USEC (20*PA_USEC_PER_SEC) /* 20s */ -#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (1*PA_USEC_PER_MSEC) /* 3ms */ +#define TSCHED_WATERMARK_INC_THRESHOLD_USEC (0*PA_USEC_PER_MSEC) /* 0ms */ #define TSCHED_WATERMARK_DEC_THRESHOLD_USEC (100*PA_USEC_PER_MSEC) /* 100ms */ #define TSCHED_WATERMARK_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */ -- cgit From b245b547025945aeca3717f987db3dd152559138 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Sep 2009 06:06:04 +0200 Subject: ladspa,remap: make description of sink follow moves --- src/modules/module-ladspa-sink.c | 25 ++++++++++++++++++++++--- src/modules/module-remap-sink.c | 24 +++++++++++++++++++++--- 2 files changed, 43 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 933fb182..994c778f 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -82,6 +82,8 @@ struct userdata { LADSPA_Data control_out; pa_memblockq *memblockq; + + pa_bool_t auto_desc; }; static const char* const valid_modargs[] = { @@ -423,6 +425,19 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); } else pa_sink_set_asyncmsgq(u->sink, NULL); + + if (u->auto_desc && dest) { + const char *z; + pa_proplist *pl; + + pl = pa_proplist_new(); + z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION); + pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "LADSPA Plugin %s on %s", + pa_proplist_gets(u->sink->proplist, "device.ladspa.name"), z ? z : dest->name); + + pa_sink_update_proplist(u->sink, PA_UPDATE_REPLACE, pl); + pa_proplist_free(pl); + } } /* Called from main context */ @@ -451,7 +466,6 @@ int pa__init(pa_module*m) { pa_channel_map map; pa_modargs *ma; char *t; - const char *z; pa_sink *master; pa_sink_input_new_data sink_input_data; pa_sink_new_data sink_data; @@ -765,8 +779,6 @@ int pa__init(pa_module*m) { sink_data.name = pa_sprintf_malloc("%s.ladspa", master->name); pa_sink_new_data_set_sample_spec(&sink_data, &ss); pa_sink_new_data_set_channel_map(&sink_data, &map); - z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); - pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "LADSPA Plugin %s on %s", d->Name, z ? z : master->name); pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name); pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter"); pa_proplist_sets(sink_data.proplist, "device.ladspa.module", plugin); @@ -782,6 +794,13 @@ int pa__init(pa_module*m) { goto fail; } + if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) { + const char *z; + + z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); + pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "LADSPA Plugin %s on %s", d->Name, z ? z : master->name); + } + u->sink = pa_sink_new(m->core, &sink_data, PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME| (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))); diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 6cfd0d15..43748bd0 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -58,6 +58,8 @@ struct userdata { pa_sink *sink; pa_sink_input *sink_input; + + pa_bool_t auto_desc; }; static const char* const valid_modargs[] = { @@ -307,6 +309,18 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); } else pa_sink_set_asyncmsgq(u->sink, NULL); + + if (u->auto_desc && dest) { + const char *k; + pa_proplist *pl; + + pl = pa_proplist_new(); + k = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION); + pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Remapped %s", k ? k : dest->name); + + pa_sink_update_proplist(u->sink, PA_UPDATE_REPLACE, pl); + pa_proplist_free(pl); + } } int pa__init(pa_module*m) { @@ -314,7 +328,6 @@ int pa__init(pa_module*m) { pa_sample_spec ss; pa_channel_map sink_map, stream_map; pa_modargs *ma; - const char *k; pa_sink *master; pa_sink_input_new_data sink_input_data; pa_sink_new_data sink_data; @@ -370,8 +383,6 @@ int pa__init(pa_module*m) { sink_data.name = pa_sprintf_malloc("%s.remapped", master->name); pa_sink_new_data_set_sample_spec(&sink_data, &ss); pa_sink_new_data_set_channel_map(&sink_data, &sink_map); - k = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); - pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Remapped %s", k ? k : master->name); pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name); pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter"); @@ -381,6 +392,13 @@ int pa__init(pa_module*m) { goto fail; } + if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) { + const char *k; + + k = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); + pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Remapped %s", k ? k : master->name); + } + u->sink = pa_sink_new(m->core, &sink_data, master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY)); pa_sink_new_data_done(&sink_data); -- cgit From ce6dff4ee0a3fe6e0339eb1f5d605caf8af3f989 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Sep 2009 22:18:01 +0200 Subject: core: add missing sink_unref() --- src/pulsecore/sink.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index f5a6fc50..2362db8d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -893,6 +893,8 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { result->memblock = pa_memblock_ref(s->silence.memblock); result->index = s->silence.index; result->length = PA_MIN(s->silence.length, length); + + pa_sink_unref(s); return; } @@ -980,6 +982,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { if (s->thread_info.state == PA_SINK_SUSPENDED) { pa_silence_memchunk(target, &s->sample_spec); + pa_sink_unref(s); return; } -- cgit From 17f609ac830a4a6be9658c7220292a038b2c59ac Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Sep 2009 22:18:55 +0200 Subject: core: handle suspended state in pa_sink_render_full() similar to the other render functions --- src/pulsecore/sink.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 2362db8d..e1ab96db 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1099,7 +1099,16 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { pa_assert(!s->thread_info.rewind_requested); pa_assert(s->thread_info.rewind_nbytes == 0); - pa_assert(length > 0); + if (s->thread_info.state == PA_SINK_SUSPENDED) { + pa_silence_memchunk_get(&s->core->silence_cache, + s->core->mempool, + result, + &s->sample_spec, + length1st); + + pa_sink_unref(s); + return; + } n = fill_mix_info(s, &length1st, info, MAX_MIX_CHANNELS); -- cgit From 45513a2077719850353a9eb34f32ac4548c0dbea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Sep 2009 22:19:30 +0200 Subject: core: fill up memblock with pa_sink_render_into_full() in pa_sink_render_full() instead of doing our own loop --- src/pulsecore/sink.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index e1ab96db..9388d309 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1163,21 +1163,15 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { if (result->length < length) { pa_memchunk chunk; - size_t l, d; + pa_memchunk_make_writable(result, length); - l = length - result->length; - d = result->index + result->length; - while (l > 0) { - chunk = *result; - chunk.index = d; - chunk.length = l; + chunk.memblock = result->memblock; + chunk.index = result->index + result->length; + chunk.length = length - result->length; - pa_sink_render_into(s, &chunk); + pa_sink_render_into_full(s, &chunk); - d += chunk.length; - l -= chunk.length; - } result->length = length; } -- cgit From 5f929963d12c70193a923d620177125d8608f18a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 2 Sep 2009 00:34:27 +0200 Subject: core-util: add api for setting env vars and record them so that we can undo them n fork --- src/pulsecore/core-util.c | 30 ++++++++++++++++++++++++++++++ src/pulsecore/core-util.h | 2 ++ 2 files changed, 32 insertions(+) (limited to 'src') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 67823019..9034dc32 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -116,6 +116,7 @@ #include #include #include +#include #include "core-util.h" @@ -124,6 +125,8 @@ #define MSG_NOSIGNAL 0 #endif +static pa_strlist *recorded_env = NULL; + #ifdef OS_IS_WIN32 #define PULSE_ROOTENV "PULSE_ROOT" @@ -2451,9 +2454,36 @@ void pa_set_env(const char *key, const char *value) { pa_assert(key); pa_assert(value); + /* This is not thread-safe */ + putenv(pa_sprintf_malloc("%s=%s", key, value)); } +void pa_set_env_and_record(const char *key, const char *value) { + pa_assert(key); + pa_assert(value); + + /* This is not thread-safe */ + + pa_set_env(key, value); + recorded_env = pa_strlist_prepend(recorded_env, key); +} + +void pa_unset_env_recorded(void) { + + /* This is not thread-safe */ + + for (;;) { + char *s = NULL; + + if (!(recorded_env = pa_strlist_pop(recorded_env, &s))) + break; + + unsetenv(s); + pa_xfree(s); + } +} + pa_bool_t pa_in_system_mode(void) { const char *e; diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 2551f794..ccc9a38e 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -195,6 +195,8 @@ int pa_reset_sigs(int except, ...); int pa_reset_sigsv(const int except[]); void pa_set_env(const char *key, const char *value); +void pa_set_env_and_record(const char *key, const char *value); +void pa_unset_env_recorded(void); pa_bool_t pa_in_system_mode(void); -- cgit From a8c0f65faecd7058de3bd704ed90985ae2c842f0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 2 Sep 2009 00:42:54 +0200 Subject: daemon: clean up environment when forking off children --- src/daemon/main.c | 7 +++++-- src/pulsecore/start-child.c | 5 +++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/daemon/main.c b/src/daemon/main.c index e44892da..e22e465a 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -706,7 +706,7 @@ int main(int argc, char *argv[]) { #endif } - pa_set_env("PULSE_INTERNAL", "1"); + pa_set_env_and_record("PULSE_INTERNAL", "1"); pa_assert_se(chdir("/") == 0); umask(0022); @@ -721,7 +721,7 @@ int main(int argc, char *argv[]) { if (change_user() < 0) goto finish; - pa_set_env("PULSE_SYSTEM", conf->system_instance ? "1" : "0"); + pa_set_env_and_record("PULSE_SYSTEM", conf->system_instance ? "1" : "0"); pa_log_info(_("This is PulseAudio %s"), PACKAGE_VERSION); pa_log_debug(_("Compilation host: %s"), CANONICAL_HOST); @@ -968,6 +968,9 @@ finish: if (valid_pid_file) pa_pid_file_remove(); + /* This has no real purpose except making things valgrind-clean */ + pa_unset_env_recorded(); + #ifdef OS_IS_WIN32 WSACleanup(); #endif diff --git a/src/pulsecore/start-child.c b/src/pulsecore/start-child.c index b3bce131..4a70aea1 100644 --- a/src/pulsecore/start-child.c +++ b/src/pulsecore/start-child.c @@ -86,6 +86,11 @@ int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) { pa_reset_sigs(-1); pa_unblock_sigs(-1); pa_reset_priority(); + pa_unset_env_recorded(); + + /* Make sure our children are not influenced by the + * LD_BIND_NOW we set for ourselves. */ + unsetenv("LD_BIND_NOW"); #ifdef PR_SET_PDEATHSIG /* On Linux we can use PR_SET_PDEATHSIG to have the helper -- cgit From 1200a0b143c370c1a9351add5f72ecabfd8630cf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 2 Sep 2009 00:54:22 +0200 Subject: sink: simplify pa_sink_render_full() by replacing it by a pa_sink_render() plus a couple of pa_sink_render_full() --- src/pulsecore/sink.c | 90 ++++++++-------------------------------------------- 1 file changed, 14 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 9388d309..b4ecdfcc 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -790,7 +790,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk * /* We optimize for the case where the order of the inputs has not changed */ - while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) { + PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) { unsigned j; pa_mix_info* m = NULL; @@ -884,8 +884,6 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_assert(pa_frame_aligned(length, &s->sample_spec)); pa_assert(result); - pa_sink_ref(s); - pa_assert(!s->thread_info.rewind_requested); pa_assert(s->thread_info.rewind_nbytes == 0); @@ -893,11 +891,11 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { result->memblock = pa_memblock_ref(s->silence.memblock); result->index = s->silence.index; result->length = PA_MIN(s->silence.length, length); - - pa_sink_unref(s); return; } + pa_sink_ref(s); + if (length <= 0) length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec); @@ -975,17 +973,16 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_assert(target->length > 0); pa_assert(pa_frame_aligned(target->length, &s->sample_spec)); - pa_sink_ref(s); - pa_assert(!s->thread_info.rewind_requested); pa_assert(s->thread_info.rewind_nbytes == 0); if (s->thread_info.state == PA_SINK_SUSPENDED) { pa_silence_memchunk(target, &s->sample_spec); - pa_sink_unref(s); return; } + pa_sink_ref(s); + length = target->length; block_size_max = pa_mempool_block_size_max(s->core->mempool); if (length > block_size_max) @@ -1060,11 +1057,16 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { pa_assert(target->length > 0); pa_assert(pa_frame_aligned(target->length, &s->sample_spec)); - pa_sink_ref(s); - pa_assert(!s->thread_info.rewind_requested); pa_assert(s->thread_info.rewind_nbytes == 0); + if (s->thread_info.state == PA_SINK_SUSPENDED) { + pa_silence_memchunk(target, &s->sample_spec); + return; + } + + pa_sink_ref(s); + l = target->length; d = 0; while (l > 0) { @@ -1083,10 +1085,6 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { /* Called from IO thread context */ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { - pa_mix_info info[MAX_MIX_CHANNELS]; - size_t length1st = length; - unsigned n; - pa_sink_assert_ref(s); pa_sink_assert_io_context(s); pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); @@ -1094,72 +1092,12 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { pa_assert(pa_frame_aligned(length, &s->sample_spec)); pa_assert(result); - pa_sink_ref(s); - pa_assert(!s->thread_info.rewind_requested); pa_assert(s->thread_info.rewind_nbytes == 0); - if (s->thread_info.state == PA_SINK_SUSPENDED) { - pa_silence_memchunk_get(&s->core->silence_cache, - s->core->mempool, - result, - &s->sample_spec, - length1st); - - pa_sink_unref(s); - return; - } - - n = fill_mix_info(s, &length1st, info, MAX_MIX_CHANNELS); - - if (n == 0) { - pa_silence_memchunk_get(&s->core->silence_cache, - s->core->mempool, - result, - &s->sample_spec, - length1st); - } else if (n == 1) { - pa_cvolume volume; - - *result = info[0].chunk; - pa_memblock_ref(result->memblock); - - if (result->length > length) - result->length = length; - - pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume); - - if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) { - if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) { - pa_memblock_unref(result->memblock); - pa_silence_memchunk_get(&s->core->silence_cache, - s->core->mempool, - result, - &s->sample_spec, - result->length); - } else { - pa_memchunk_make_writable(result, length); - pa_volume_memchunk(result, &s->sample_spec, &volume); - } - } - } else { - void *ptr; - - result->index = 0; - result->memblock = pa_memblock_new(s->core->mempool, length); - - ptr = pa_memblock_acquire(result->memblock); - - result->length = pa_mix(info, n, - (uint8_t*) ptr + result->index, length1st, - &s->sample_spec, - &s->thread_info.soft_volume, - s->thread_info.soft_muted); - - pa_memblock_release(result->memblock); - } + pa_sink_ref(s); - inputs_drop(s, info, n, result); + pa_sink_render(s, length, result); if (result->length < length) { pa_memchunk chunk; -- cgit From 470e9a878740b826acaa89d856ba1c7a9d5635b3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 2 Sep 2009 03:17:34 +0200 Subject: build-sys: drop LIBOIL_{FLAGS|LIBS} from Makefile.am since we don't use the library anymore --- src/Makefile.am | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 88f0ff56..6544e2aa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -177,8 +177,8 @@ pulseaudio_SOURCES = \ daemon/ltdl-bind-now.c daemon/ltdl-bind-now.h \ daemon/main.c -pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSPEEX_CFLAGS) $(LIBSNDFILE_CFLAGS) $(CAP_CFLAGS) $(LIBOIL_CFLAGS) $(DBUS_CFLAGS) -pulseaudio_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSPEEX_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) $(DBUS_LIBS) +pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSPEEX_CFLAGS) $(LIBSNDFILE_CFLAGS) $(CAP_CFLAGS) $(DBUS_CFLAGS) +pulseaudio_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSPEEX_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(DBUS_LIBS) # This is needed because automake doesn't properly expand the foreach below pulseaudio_DEPENDENCIES = libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la $(PREOPEN_LIBS) @@ -496,18 +496,18 @@ sig2str_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) resampler_test_SOURCES = tests/resampler-test.c resampler_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -resampler_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -resampler_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +resampler_test_CFLAGS = $(AM_CFLAGS) +resampler_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) mix_test_SOURCES = tests/mix-test.c mix_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -mix_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -mix_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +mix_test_CFLAGS = $(AM_CFLAGS) +mix_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) remix_test_SOURCES = tests/remix-test.c remix_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -remix_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -remix_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +remix_test_CFLAGS = $(AM_CFLAGS) +remix_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) smoother_test_SOURCES = tests/smoother-test.c smoother_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la @@ -516,38 +516,38 @@ smoother_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) envelope_test_SOURCES = tests/envelope-test.c envelope_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -envelope_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -envelope_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +envelope_test_CFLAGS = $(AM_CFLAGS) +envelope_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) proplist_test_SOURCES = tests/proplist-test.c proplist_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -proplist_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -proplist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +proplist_test_CFLAGS = $(AM_CFLAGS) +proplist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) rtstutter_SOURCES = tests/rtstutter.c rtstutter_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -rtstutter_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -rtstutter_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +rtstutter_CFLAGS = $(AM_CFLAGS) +rtstutter_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) stripnul_SOURCES = tests/stripnul.c stripnul_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -stripnul_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -stripnul_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +stripnul_CFLAGS = $(AM_CFLAGS) +stripnul_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) lock_autospawn_test_SOURCES = tests/lock-autospawn-test.c lock_autospawn_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -lock_autospawn_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -lock_autospawn_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +lock_autospawn_test_CFLAGS = $(AM_CFLAGS) +lock_autospawn_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) prioq_test_SOURCES = tests/prioq-test.c prioq_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -prioq_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -prioq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +prioq_test_CFLAGS = $(AM_CFLAGS) +prioq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) sigbus_test_SOURCES = tests/sigbus-test.c sigbus_test_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la -sigbus_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) -sigbus_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS) +sigbus_test_CFLAGS = $(AM_CFLAGS) +sigbus_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) gtk_test_SOURCES = tests/gtk-test.c gtk_test_LDADD = $(AM_LDADD) libpulse.la libpulse-mainloop-glib.la @@ -858,9 +858,9 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/time-smoother.c pulsecore/time-smoother.h \ pulsecore/database.h -libpulsecore_@PA_MAJORMINORMICRO@_la_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSPEEX_CFLAGS) $(WINSOCK_CFLAGS) $(LIBOIL_CFLAGS) +libpulsecore_@PA_MAJORMINORMICRO@_la_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSPEEX_CFLAGS) $(WINSOCK_CFLAGS) libpulsecore_@PA_MAJORMINORMICRO@_la_LDFLAGS = -avoid-version -libpulsecore_@PA_MAJORMINORMICRO@_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSPEEX_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LTLIBICONV) libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la libpulsecore-foreign.la +libpulsecore_@PA_MAJORMINORMICRO@_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSPEEX_LIBS) $(WINSOCK_LIBS) $(LTLIBICONV) libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la libpulsecore-foreign.la if HAVE_X11 libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES += pulsecore/x11wrap.c pulsecore/x11wrap.h -- cgit From 767c7c7cf42463c591edaa5e5cdc7930fa0f6026 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 2 Sep 2009 04:03:18 +0200 Subject: core-util: call dbus_connection_set_exit_on_disconnect() on shared busses to make sure dbus_shutdown() isn't fatal --- src/pulsecore/core-util.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 9034dc32..eeb81a60 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -612,6 +612,11 @@ static int set_scheduler(int rtprio) { return -1; } + /* We need to disable exit on disconnect because otherwise + * dbus_shutdown will kill us. See + * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */ + dbus_connection_set_exit_on_disconnect(bus, FALSE); + r = rtkit_make_realtime(bus, 0, rtprio); dbus_connection_unref(bus); @@ -680,6 +685,11 @@ static int set_nice(int nice_level) { return -1; } + /* We need to disable exit on disconnect because otherwise + * dbus_shutdown will kill us. See + * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */ + dbus_connection_set_exit_on_disconnect(bus, FALSE); + r = rtkit_make_high_priority(bus, 0, nice_level); dbus_connection_unref(bus); -- cgit From 297afadbef238f7a37f65bd3740a2ce24861c414 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 2 Sep 2009 04:05:34 +0200 Subject: core-util: don't leak memory in pa_unset_env_recorded() --- src/pulsecore/core-util.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 9034dc32..a3c60130 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2474,9 +2474,11 @@ void pa_unset_env_recorded(void) { /* This is not thread-safe */ for (;;) { - char *s = NULL; + char *s; - if (!(recorded_env = pa_strlist_pop(recorded_env, &s))) + recorded_env = pa_strlist_pop(recorded_env, &s); + + if (!s) break; unsetenv(s); -- cgit From 39e4652a78850c3ece3ada2e3cdb2266668dba45 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 2 Sep 2009 04:05:41 +0200 Subject: daemon: drop polkit code from git repo we weren't using anymore --- src/daemon/polkit.c | 172 ---------------------------------------------------- src/daemon/polkit.h | 27 --------- 2 files changed, 199 deletions(-) delete mode 100644 src/daemon/polkit.c delete mode 100644 src/daemon/polkit.h (limited to 'src') diff --git a/src/daemon/polkit.c b/src/daemon/polkit.c deleted file mode 100644 index 9799e094..00000000 --- a/src/daemon/polkit.c +++ /dev/null @@ -1,172 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 2004-2006 Lennart Poettering - Copyright 2006 Pierre Ossman for Cendio AB - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2.1 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#include "polkit.h" - -int pa_polkit_check(const char *action_id) { - int ret = -1; - DBusError dbus_error; - DBusConnection *bus = NULL; - PolKitCaller *caller = NULL; - PolKitAction *action = NULL; - PolKitContext *context = NULL; - PolKitError *polkit_error = NULL; - PolKitSession *session = NULL; - PolKitResult polkit_result; - - dbus_error_init(&dbus_error); - - if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error))) { - pa_log_error(_("Cannot connect to system bus: %s"), dbus_error.message); - goto finish; - } - - /* There seems to be a bug in some versions of D-Bus that causes - * dbus_shutdown() to call exit() when a connection without this - * flag disabled was created during runtime.*/ - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (!(caller = polkit_caller_new_from_pid(bus, getpid(), &dbus_error))) { - pa_log_error(_("Cannot get caller from PID: %s"), dbus_error.message); - goto finish; - } - - /* This function is called when PulseAudio is called SUID root. We - * want to authenticate the real user that called us and not the - * effective user we gained through being SUID root. Hence we - * overwrite the UID caller data here explicitly, just for - * paranoia. In fact PolicyKit should fill in the UID here anyway - * -- an not the EUID or any other user id. */ - - if (!(polkit_caller_set_uid(caller, getuid()))) { - pa_log_error(_("Cannot set UID on caller object.")); - goto finish; - } - - if (!(polkit_caller_get_ck_session(caller, &session))) { - pa_log_error(_("Failed to get CK session.")); - goto finish; - } - - /* We need to overwrite the UID in both the caller and the session - * object */ - - if (!(polkit_session_set_uid(session, getuid()))) { - pa_log_error(_("Cannot set UID on session object.")); - goto finish; - } - - if (!(action = polkit_action_new())) { - pa_log_error(_("Cannot allocate PolKitAction.")); - goto finish; - } - - if (!polkit_action_set_action_id(action, action_id)) { - pa_log_error(_("Cannot set action_id")); - goto finish; - } - - if (!(context = polkit_context_new())) { - pa_log_error(_("Cannot allocate PolKitContext.")); - goto finish; - } - - if (!polkit_context_init(context, &polkit_error)) { - pa_log_error(_("Cannot initialize PolKitContext: %s"), polkit_error_get_error_message(polkit_error)); - goto finish; - } - - for (;;) { - - polkit_result = polkit_context_is_caller_authorized(context, action, caller, TRUE, &polkit_error); - - if (polkit_error_is_set(polkit_error)) { - pa_log_error(_("Could not determine whether caller is authorized: %s"), polkit_error_get_error_message(polkit_error)); - goto finish; - } - - if (polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH || - polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_SESSION || - polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_ALWAYS || - polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_ONE_SHOT || - polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH || - polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_SESSION || - polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_ALWAYS || - polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH_ONE_SHOT - ) { - - if (polkit_auth_obtain(action_id, 0, getpid(), &dbus_error)) { - polkit_result = POLKIT_RESULT_YES; - break; - } - - if (dbus_error_is_set(&dbus_error)) { - pa_log_error(_("Cannot obtain auth: %s"), dbus_error.message); - goto finish; - } - } - - break; - } - - if (polkit_result != POLKIT_RESULT_YES && polkit_result != POLKIT_RESULT_NO) - pa_log_warn(_("PolicyKit responded with '%s'"), polkit_result_to_string_representation(polkit_result)); - - ret = polkit_result == POLKIT_RESULT_YES; - -finish: - - if (caller) - polkit_caller_unref(caller); - - if (action) - polkit_action_unref(action); - - if (context) - polkit_context_unref(context); - - if (bus) - dbus_connection_unref(bus); - - dbus_error_free(&dbus_error); - - if (polkit_error) - polkit_error_free(polkit_error); - - return ret; -} diff --git a/src/daemon/polkit.h b/src/daemon/polkit.h deleted file mode 100644 index 018f6ef1..00000000 --- a/src/daemon/polkit.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef foopolkithfoo -#define foopolkithfoo - -/*** - This file is part of PulseAudio. - - Copyright 2007 Lennart Poettering - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2.1 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -int pa_polkit_check(const char *action); - -#endif -- cgit From 26164ff05178db3aec351452b038f9d49fd0c5af Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 2 Sep 2009 19:42:17 +0200 Subject: sconv_sse: fix leftover counter --- src/pulsecore/sconv_sse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sconv_sse.c b/src/pulsecore/sconv_sse.c index ef78fc26..7c3aa199 100644 --- a/src/pulsecore/sconv_sse.c +++ b/src/pulsecore/sconv_sse.c @@ -83,7 +83,7 @@ static void pa_sconv_s16le_from_f32ne_sse(unsigned n, const float *a, int16_t *b "2: \n\t" " mov %4, %1 \n\t" /* prepare for leftovers */ - " and $15, %1 \n\t" + " and $7, %1 \n\t" " je 4f \n\t" "3: \n\t" @@ -142,7 +142,7 @@ static void pa_sconv_s16le_from_f32ne_sse2(unsigned n, const float *a, int16_t * "2: \n\t" " mov %4, %1 \n\t" /* prepare for leftovers */ - " and $15, %1 \n\t" + " and $7, %1 \n\t" " je 4f \n\t" "3: \n\t" -- cgit From 51423cae52333f604de198691d487c7de65cd096 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Sep 2009 00:13:21 +0200 Subject: remap_sse: reindent macro so that diff to MMX is nicer Completely useless, but diff -u remap_mmx.c remap_sse.c is much nicer this way. --- src/pulsecore/remap_sse.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c index d6003571..fa21c6c8 100644 --- a/src/pulsecore/remap_sse.c +++ b/src/pulsecore/remap_sse.c @@ -80,25 +80,25 @@ " add $2, %1 \n\t" \ " add $4, %0 \n\t" -#define MONO_TO_STEREO(s,shift,mask) \ - " mov %4, %2 \n\t" \ - " sar $"#shift", %2 \n\t" \ - " cmp $0, %2 \n\t" \ - " je 2f \n\t" \ - "1: \n\t" \ - LOAD_SAMPLES \ - UNPACK_SAMPLES(s) \ - STORE_SAMPLES \ - " dec %2 \n\t" \ - " jne 1b \n\t" \ - "2: \n\t" \ - " mov %4, %2 \n\t" \ - " and $"#mask", %2 \n\t" \ - " je 4f \n\t" \ - "3: \n\t" \ - HANDLE_SINGLE_##s() \ - " dec %2 \n\t" \ - " jne 3b \n\t" \ +#define MONO_TO_STEREO(s,shift,mask) \ + " mov %4, %2 \n\t" \ + " sar $"#shift", %2 \n\t" \ + " cmp $0, %2 \n\t" \ + " je 2f \n\t" \ + "1: \n\t" \ + LOAD_SAMPLES \ + UNPACK_SAMPLES(s) \ + STORE_SAMPLES \ + " dec %2 \n\t" \ + " jne 1b \n\t" \ + "2: \n\t" \ + " mov %4, %2 \n\t" \ + " and $"#mask", %2 \n\t" \ + " je 4f \n\t" \ + "3: \n\t" \ + HANDLE_SINGLE_##s() \ + " dec %2 \n\t" \ + " jne 3b \n\t" \ "4: \n\t" static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, unsigned n) { -- cgit From 9f4f374a19e808ba4f7d4bb04266526bf5ed428b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Sep 2009 00:17:28 +0200 Subject: remap_sse: fix inner loop increment on SSE In each iteration we can process 2^4 S16NE samples and 2^5 F32NE samples, that's twice as much as in MMX, hence correct the increments. --- src/pulsecore/remap_sse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c index fa21c6c8..368a3196 100644 --- a/src/pulsecore/remap_sse.c +++ b/src/pulsecore/remap_sse.c @@ -108,7 +108,7 @@ static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, case PA_SAMPLE_FLOAT32NE: { __asm__ __volatile__ ( - MONO_TO_STEREO(dq,3,7) /* do doubles to quads */ + MONO_TO_STEREO(dq, 4, 15) /* do doubles to quads */ : "+r" (dst), "+r" (src), "=&r" (temp), "=&r" (temp2) : "r" ((pa_reg_x86)n) : "cc" @@ -118,7 +118,7 @@ static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, case PA_SAMPLE_S16NE: { __asm__ __volatile__ ( - MONO_TO_STEREO(wd,4,15) /* do words to doubles */ + MONO_TO_STEREO(wd, 5, 31) /* do words to doubles */ : "+r" (dst), "+r" (src), "=&r" (temp), "=&r" (temp2) : "r" ((pa_reg_x86)n) : "cc" -- cgit From d088c8f05abfae70379d720871f59962a2b3b16b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Sep 2009 00:19:03 +0200 Subject: daemon: make use of SIMD optional via config variable to ease debugging --- src/daemon/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/daemon/main.c b/src/daemon/main.c index e22e465a..af59adef 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -828,8 +828,10 @@ int main(int argc, char *argv[]) { pa_memtrap_install(); - pa_cpu_init_x86(); - pa_cpu_init_arm(); + if (!getenv("PULSE_NO_SIMD")) { + pa_cpu_init_x86(); + pa_cpu_init_arm(); + } pa_assert_se(mainloop = pa_mainloop_new()); -- cgit From 14a97716891706d2f4984b0d1da10b354b3042db Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Sep 2009 00:21:19 +0200 Subject: core: drop unnecessary variable initialization --- src/pulsecore/sink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index b4ecdfcc..bda92fcc 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -778,7 +778,7 @@ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, uns /* Called from IO thread context */ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) { pa_sink_input *i; - void *state = NULL; + void *state; unsigned p = 0; unsigned n_unreffed = 0; -- cgit From 6f396c89ab48c4897ebbcb846c5914b06a8225fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Sep 2009 01:48:30 +0200 Subject: remap: build sse code only on x86 --- src/pulsecore/remap_sse.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c index 368a3196..bf22df7c 100644 --- a/src/pulsecore/remap_sse.c +++ b/src/pulsecore/remap_sse.c @@ -101,6 +101,7 @@ " jne 3b \n\t" \ "4: \n\t" +#if defined (__i386__) || defined (__amd64__) static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, unsigned n) { pa_reg_x86 temp, temp2; @@ -144,6 +145,7 @@ static void init_remap_sse (pa_remap_t *m) { pa_log_info("Using SSE mono to stereo remapping"); } } +#endif /* defined (__i386__) || defined (__amd64__) */ void pa_remap_func_init_sse (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) -- cgit From 8cd635bc614834c13d0f1c586d472b4a52b98664 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Sep 2009 04:45:55 +0200 Subject: alsa: add more input sources to path set --- src/modules/alsa/mixer/paths/analog-input.conf.common | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/modules/alsa/mixer/paths/analog-input.conf.common b/src/modules/alsa/mixer/paths/analog-input.conf.common index 6728a6ae..87af38b3 100644 --- a/src/modules/alsa/mixer/paths/analog-input.conf.common +++ b/src/modules/alsa/mixer/paths/analog-input.conf.common @@ -78,6 +78,10 @@ priority = 19 name = input-microphone priority = 19 +[Option Input Source:Internal Mic] +name = input-microphone +priority = 19 + [Option Input Source:Line] name = input-linein priority = 18 @@ -90,6 +94,10 @@ priority = 18 name = input-linein priority = 18 +[Option Input Source:Docking-Station] +name = input-docking +priority = 17 + ;;; ' Capture Source' [Element Capture Source] -- cgit From 0ad6a574a1eb206f40a1eed3abab8b05a1b6f6ec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 4 Sep 2009 02:44:43 +0200 Subject: null: make name of null sink translatable --- src/modules/module-null-sink.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 36c50b05..74a2ebb1 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -51,7 +52,7 @@ #include "module-null-sink-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering"); -PA_MODULE_DESCRIPTION("Clocked NULL sink"); +PA_MODULE_DESCRIPTION(_("Clocked NULL sink")); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( @@ -287,7 +288,7 @@ int pa__init(pa_module*m) { pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); pa_sink_new_data_set_sample_spec(&data, &ss); pa_sink_new_data_set_channel_map(&data, &map); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "Null Output")); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", _("Null Output"))); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { -- cgit From 5daecea4dd4e0962e90e24a4ff594e2fa6a624a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 4 Sep 2009 02:46:43 +0200 Subject: always-sink: rename null sink created to 'dummy sink' and make it translatable --- src/modules/module-always-sink.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/module-always-sink.c b/src/modules/module-always-sink.c index aee1c650..3d7de9c6 100644 --- a/src/modules/module-always-sink.c +++ b/src/modules/module-always-sink.c @@ -24,6 +24,7 @@ #endif #include +#include #include #include @@ -35,7 +36,7 @@ #include "module-always-sink-symdef.h" PA_MODULE_AUTHOR("Colin Guthrie"); -PA_MODULE_DESCRIPTION("Always keeps at least one sink loaded even if it's a null one"); +PA_MODULE_DESCRIPTION(_("Always keeps at least one sink loaded even if it's a null one")); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(TRUE); PA_MODULE_USAGE( @@ -78,7 +79,8 @@ static void load_null_sink_if_needed(pa_core *c, pa_sink *sink, struct userdata* u->ignore = TRUE; - t = pa_sprintf_malloc("sink_name=%s", u->sink_name); + t = pa_sprintf_malloc("sink_name=%s sink_properties='device.description=\"%s\"'", u->sink_name, + _("Dummy Output")); m = pa_module_load(c, "module-null-sink", t); u->null_module = m ? m->index : PA_INVALID_INDEX; pa_xfree(t); -- cgit From 812be327836c93492ad389333bcc037566141eb8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 4 Sep 2009 02:47:48 +0200 Subject: daemon: disable CPU load limiter by default RLIMIT_RTTIME and rtki can do this job much better, so let's disable this by default. --- src/daemon/daemon-conf.c | 2 +- src/daemon/daemon.conf.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index ec1ec5ce..6e7926f8 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -83,7 +83,7 @@ static const pa_daemon_conf default_conf = { .config_file = NULL, .use_pid_file = TRUE, .system_instance = FALSE, - .no_cpu_limit = FALSE, + .no_cpu_limit = TRUE, .disable_shm = FALSE, .lock_memory = FALSE, .default_n_fragments = 4, diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index d8b58d8a..db2059e1 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -28,7 +28,7 @@ ; enable-shm = yes ; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB ; lock-memory = no -; cpu-limit = yes +; cpu-limit = no ; high-priority = yes ; nice-level = -11 -- 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 +- src/pulsecore/cli-command.c | 12 ++++++------ src/pulsecore/memblock.c | 2 +- src/utils/pactl.c | 4 ++-- 6 files changed, 17 insertions(+), 11 deletions(-) (limited to 'src') 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); diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 3c94960c..143db3b2 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -328,7 +328,7 @@ static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - char s[256]; + char bytes[PA_BYTES_SNPRINT_MAX]; const pa_mempool_stat *stat; unsigned k; pa_sink *def_sink; @@ -352,22 +352,22 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", (unsigned) pa_atomic_load(&stat->n_allocated), - pa_bytes_snprint(s, sizeof(s), (unsigned) pa_atomic_load(&stat->allocated_size))); + pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&stat->allocated_size))); pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", (unsigned) pa_atomic_load(&stat->n_accumulated), - pa_bytes_snprint(s, sizeof(s), (unsigned) pa_atomic_load(&stat->accumulated_size))); + pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&stat->accumulated_size))); pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n", (unsigned) pa_atomic_load(&stat->n_imported), - pa_bytes_snprint(s, sizeof(s), (unsigned) pa_atomic_load(&stat->imported_size))); + pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&stat->imported_size))); pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n", (unsigned) pa_atomic_load(&stat->n_exported), - pa_bytes_snprint(s, sizeof(s), (unsigned) pa_atomic_load(&stat->exported_size))); + pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&stat->exported_size))); pa_strbuf_printf(buf, "Total sample cache size: %s.\n", - pa_bytes_snprint(s, sizeof(s), (unsigned) pa_scache_total_size(c))); + pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_scache_total_size(c))); pa_strbuf_printf(buf, "Default sample spec: %s\n", pa_sample_spec_snprint(ss, sizeof(ss), &c->default_sample_spec)); diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 441b397b..0e40d12b 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -694,7 +694,7 @@ static void memblock_replace_import(pa_memblock *b) { pa_mempool* pa_mempool_new(pa_bool_t shared, size_t size) { pa_mempool *p; - char t1[64], t2[64]; + char t1[PA_BYTES_SNPRINT_MAX], t2[PA_BYTES_SNPRINT_MAX]; p = pa_xnew(pa_mempool, 1); diff --git a/src/utils/pactl.c b/src/utils/pactl.c index b8f4ea75..141ab5b1 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -130,7 +130,7 @@ static void complete_action(void) { } static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) { - char s[128]; + char s[PA_BYTES_SNPRINT_MAX]; if (!i) { pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c))); quit(1); @@ -598,7 +598,7 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu } static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) { - char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + char t[PA_BYTES_SNPRINT_MAX], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; char *pl; if (is_last < 0) { -- 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') 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 b5ac3839e18524524fa3e0da7ec68dbce16e8203 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 7 Sep 2009 17:21:21 +0200 Subject: x86: only install some functions when SSE2 Remap and volume functions use SSE2 instructions so only install them when SSE2 is present. --- src/pulsecore/remap_sse.c | 9 +++++---- src/pulsecore/svolume_sse.c | 10 ++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c index bf22df7c..dac072ec 100644 --- a/src/pulsecore/remap_sse.c +++ b/src/pulsecore/remap_sse.c @@ -102,7 +102,7 @@ "4: \n\t" #if defined (__i386__) || defined (__amd64__) -static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, unsigned n) { +static void remap_mono_to_stereo_sse2 (pa_remap_t *m, void *dst, const void *src, unsigned n) { pa_reg_x86 temp, temp2; switch (*m->format) { @@ -132,7 +132,7 @@ static void remap_mono_to_stereo_sse (pa_remap_t *m, void *dst, const void *src, } /* set the function that will execute the remapping based on the matrices */ -static void init_remap_sse (pa_remap_t *m) { +static void init_remap_sse2 (pa_remap_t *m) { unsigned n_oc, n_ic; n_oc = m->o_ss->channels; @@ -141,7 +141,7 @@ static void init_remap_sse (pa_remap_t *m) { /* find some common channel remappings, fall back to full matrix operation. */ if (n_ic == 1 && n_oc == 2 && m->map_table_f[0][0] >= 1.0 && m->map_table_f[1][0] >= 1.0) { - m->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo_sse; + m->do_remap = (pa_do_remap_func_t) remap_mono_to_stereo_sse2; pa_log_info("Using SSE mono to stereo remapping"); } } @@ -151,6 +151,7 @@ void pa_remap_func_init_sse (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) pa_log_info("Initialising SSE optimized remappers."); - pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_sse); + if (flags & PA_CPU_X86_SSE2) + pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_sse2); #endif /* defined (__i386__) || defined (__amd64__) */ } diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index 54af4a57..d9dcf476 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -75,7 +75,7 @@ " por %%xmm5, "#s2" \n\t" static void -pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +pa_volume_s16ne_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { pa_reg_x86 channel, temp; @@ -155,7 +155,7 @@ pa_volume_s16ne_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsi } static void -pa_volume_s16re_sse (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) +pa_volume_s16re_sse2 (int16_t *samples, int32_t *volumes, unsigned channels, unsigned length) { pa_reg_x86 channel, temp; @@ -308,7 +308,9 @@ void pa_volume_func_init_sse (pa_cpu_x86_flag_t flags) { run_test (); #endif - pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse); - pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse); + if (flags & PA_CPU_X86_SSE2) { + pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse2); + pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse2); + } #endif /* defined (__i386__) || defined (__amd64__) */ } -- cgit From 723499439f575f744f07c85a42b47d95cdc98de6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 7 Sep 2009 17:28:19 +0200 Subject: x86: also call see init for SSE2 --- src/pulsecore/cpu-x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/cpu-x86.c b/src/pulsecore/cpu-x86.c index 1ba9f1a4..f194a608 100644 --- a/src/pulsecore/cpu-x86.c +++ b/src/pulsecore/cpu-x86.c @@ -115,7 +115,7 @@ void pa_cpu_init_x86 (void) { pa_remap_func_init_mmx (flags); } - if (flags & PA_CPU_X86_SSE) { + if (flags & (PA_CPU_X86_SSE | PA_CPU_X86_SSE2)) { pa_volume_func_init_sse (flags); pa_remap_func_init_sse (flags); pa_convert_func_init_sse (flags); -- 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 ++++++--- src/pulsecore/core-scache.c | 4 ++-- 5 files changed, 17 insertions(+), 14 deletions(-) (limited to 'src') 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 { diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index fde12ecf..1fb81d0d 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -335,12 +335,12 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t pass_volume = TRUE; - if (e->volume_is_set && volume != (pa_volume_t) -1) { + if (e->volume_is_set && volume != PA_VOLUME_INVALID) { pa_cvolume_set(&r, e->sample_spec.channels, volume); pa_sw_cvolume_multiply(&r, &r, &e->volume); } else if (e->volume_is_set) r = e->volume; - else if (volume != (pa_volume_t) -1) + else if (volume != PA_VOLUME_INVALID) pa_cvolume_set(&r, e->sample_spec.channels, volume); else pass_volume = FALSE; -- 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') 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') 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') 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') 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 b705a9bb8dfd7f859b0aca98833010f831ba2e6a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2009 22:32:11 +0200 Subject: vector: don't try to build vector stuff on altivec --- src/pulsecore/vector.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/vector.h b/src/pulsecore/vector.h index 924e3cb8..9de3b8cd 100644 --- a/src/pulsecore/vector.h +++ b/src/pulsecore/vector.h @@ -23,7 +23,8 @@ #include /* First, define HAVE_VECTOR if we have the gcc vector extensions at all */ -#if defined(__SSE2__) || defined(__ALTIVEC__) +#if defined(__SSE2__) + /* || defined(__ALTIVEC__)*/ #define HAVE_VECTOR -- 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') 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 b2606cf641f01f688dcb05abcfef3ba003e74efb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Sep 2009 23:34:31 +0200 Subject: i18n: move \r out of translatable string https://bugzilla.redhat.com/show_bug.cgi?id=521552 --- src/utils/pacat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 9264a062..0a369bc2 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -574,9 +574,10 @@ static void stream_update_timing_callback(pa_stream *s, int success, void *userd return; } - pa_log(_("Time: %0.3f sec; Latency: %0.0f usec. \r"), + fprintf(stderr, _("Time: %0.3f sec; Latency: %0.0f usec."), (float) usec / 1000000, (float) l * (negative?-1.0f:1.0f)); + fprintf(stderr, " \r"); } /* Someone requested that the latency is shown */ -- 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/modules/alsa/alsa-mixer.c | 2 +- src/modules/alsa/alsa-sink.c | 3 +-- src/modules/alsa/alsa-source.c | 3 +-- src/modules/alsa/alsa-util.c | 2 +- src/modules/module-hal-detect.c | 4 +--- src/modules/module-tunnel.c | 15 ++++++--------- src/modules/raop/base64.c | 1 - src/modules/x11/module-x11-publish.c | 2 +- src/pulse/utf8.c | 4 +--- src/pulse/volume.c | 8 ++++---- src/pulsecore/core-util.c | 13 +++++-------- src/pulsecore/flist.c | 22 ++++++++++++++++++---- src/pulsecore/memtrap.c | 4 ++-- src/pulsecore/pid.c | 4 +--- src/pulsecore/protocol-esound.c | 4 +--- src/pulsecore/protocol-native.c | 3 +-- src/pulsecore/protocol-simple.c | 2 +- src/pulsecore/sink-input.c | 3 --- src/pulsecore/socket-client.c | 4 +--- src/utils/pacat.c | 5 ++--- 20 files changed, 49 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 61c92cd0..9eb7b462 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -2889,7 +2889,7 @@ static void profile_set_add_auto_pair( else name = pa_sprintf_malloc("input:%s", n->name); - if ((p = pa_hashmap_get(ps->profiles, name))) { + if (pa_hashmap_get(ps->profiles, name)) { pa_xfree(name); return; } diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 195bdf6e..63a3e906 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1638,7 +1638,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca const char *dev_id = NULL; pa_sample_spec ss, requested_ss; pa_channel_map map; - uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark; + uint32_t nfrags, frag_size, tsched_size, tsched_watermark; snd_pcm_uframes_t period_frames, tsched_frames; size_t frame_size; pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE; @@ -1673,7 +1673,6 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca goto fail; } - hwbuf_size = frag_size * nfrags; period_frames = frag_size/frame_size; tsched_frames = tsched_size/frame_size; diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index f42d3542..64f89806 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -1483,7 +1483,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p const char *dev_id = NULL; pa_sample_spec ss, requested_ss; pa_channel_map map; - uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark; + uint32_t nfrags, frag_size, tsched_size, tsched_watermark; snd_pcm_uframes_t period_frames, tsched_frames; size_t frame_size; pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE; @@ -1518,7 +1518,6 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p goto fail; } - hwbuf_size = frag_size * nfrags; period_frames = frag_size/frame_size; tsched_frames = tsched_size/frame_size; diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index a47a8958..4d75c63c 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -900,7 +900,7 @@ void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) { snd_ctl_card_info_alloca(&info); if ((err = snd_ctl_open(&ctl, name, 0)) < 0) { - pa_log_warn("Error opening low-level control device '%s'", name); + pa_log_warn("Error opening low-level control device '%s': %s", name, snd_strerror(err)); return; } diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 6034d0ee..18519131 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -435,9 +435,7 @@ static int hal_device_add_all(struct userdata *u) { int i; for (i = 0; i < n; i++) { - struct device *d; - - if ((d = hal_device_add(u, udis[i]))) { + if (hal_device_add(u, udis[i])) { count++; pa_log_debug("Loaded device %s", udis[i]); } else diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 5ccb81d0..af4b8b2a 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -332,7 +332,7 @@ static void command_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa static void command_stream_buffer_attr_changed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - uint32_t channel, maxlength, tlength, fragsize, prebuf, minreq; + uint32_t channel, maxlength, tlength = 0, fragsize, prebuf, minreq; pa_usec_t usec; pa_assert(pd); @@ -1097,7 +1097,7 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag uint32_t idx, owner_module, client, sink; pa_usec_t buffer_usec, sink_usec; const char *name, *driver, *resample_method; - pa_bool_t mute; + pa_bool_t mute = FALSE; pa_sample_spec sample_spec; pa_channel_map channel_map; pa_cvolume volume; @@ -1345,12 +1345,11 @@ static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32 /* Called from main context */ static void start_subscribe(struct userdata *u) { pa_tagstruct *t; - uint32_t tag; pa_assert(u); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, u->ctag++); pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SERVER| #ifdef TUNNEL_SINK PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SINK @@ -1526,7 +1525,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t reply = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); - pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_putu32(reply, u->ctag++); if (u->version >= 13) { pa_proplist *pl; @@ -1753,7 +1752,6 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata static void sink_set_volume(pa_sink *sink) { struct userdata *u; pa_tagstruct *t; - uint32_t tag; pa_assert(sink); u = sink->userdata; @@ -1761,7 +1759,7 @@ static void sink_set_volume(pa_sink *sink) { t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); - pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, u->ctag++); pa_tagstruct_putu32(t, u->device_index); pa_tagstruct_put_cvolume(t, &sink->real_volume); pa_pstream_send_tagstruct(u->pstream, t); @@ -1771,7 +1769,6 @@ static void sink_set_volume(pa_sink *sink) { static void sink_set_mute(pa_sink *sink) { struct userdata *u; pa_tagstruct *t; - uint32_t tag; pa_assert(sink); u = sink->userdata; @@ -1782,7 +1779,7 @@ static void sink_set_mute(pa_sink *sink) { t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_MUTE); - pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, u->ctag++); pa_tagstruct_putu32(t, u->device_index); pa_tagstruct_put_boolean(t, !!sink->muted); pa_pstream_send_tagstruct(u->pstream, t); diff --git a/src/modules/raop/base64.c b/src/modules/raop/base64.c index e1cbed02..5b061034 100644 --- a/src/modules/raop/base64.c +++ b/src/modules/raop/base64.c @@ -57,7 +57,6 @@ int pa_base64_encode(const void *data, int size, char **str) p = s = pa_xnew(char, size * 4 / 3 + 4); q = (const unsigned char *) data; - i = 0; for (i = 0; i < size;) { c = q[i++]; c *= 256; diff --git a/src/modules/x11/module-x11-publish.c b/src/modules/x11/module-x11-publish.c index 2c7fdc12..7ee1b6da 100644 --- a/src/modules/x11/module-x11-publish.c +++ b/src/modules/x11/module-x11-publish.c @@ -90,7 +90,7 @@ static void publish_servers(struct userdata *u, pa_strlist *l) { l = pa_strlist_reverse(l); s = pa_strlist_tostring(l); - l = pa_strlist_reverse(l); + pa_strlist_reverse(l); pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER", s); pa_xfree(s); 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; diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 1daa46eb..d64c7388 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -591,13 +591,13 @@ static int set_scheduler(int rtprio) { sp.sched_priority = rtprio; #ifdef SCHED_RESET_ON_FORK - if ((r = pthread_setschedparam(pthread_self(), SCHED_RR|SCHED_RESET_ON_FORK, &sp)) == 0) { + if (pthread_setschedparam(pthread_self(), SCHED_RR|SCHED_RESET_ON_FORK, &sp) == 0) { pa_log_debug("SCHED_RR|SCHED_RESET_ON_FORK worked."); return 0; } #endif - if ((r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp)) == 0) { + if (pthread_setschedparam(pthread_self(), SCHED_RR, &sp) == 0) { pa_log_debug("SCHED_RR worked."); return 0; } @@ -786,7 +786,6 @@ int pa_match(const char *expr, const char *v) { /* Try to parse a boolean string value.*/ int pa_parse_boolean(const char *v) { const char *expr; - int r; pa_assert(v); /* First we check language independant */ @@ -798,12 +797,12 @@ int pa_parse_boolean(const char *v) { /* And then we check language dependant */ if ((expr = nl_langinfo(YESEXPR))) if (expr[0]) - if ((r = pa_match(expr, v)) > 0) + if (pa_match(expr, v) > 0) return 1; if ((expr = nl_langinfo(NOEXPR))) if (expr[0]) - if ((r = pa_match(expr, v)) > 0) + if (pa_match(expr, v) > 0) return 0; errno = EINVAL; @@ -1195,7 +1194,7 @@ char* pa_strip_nl(char *s) { /* Create a temporary lock file and lock it. */ int pa_lock_lockfile(const char *fn) { - int fd = -1; + int fd; pa_assert(fn); for (;;) { @@ -1238,8 +1237,6 @@ int pa_lock_lockfile(const char *fn) { fd = -1; goto fail; } - - fd = -1; } return fd; diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c index 6fb944f9..7e5ee244 100644 --- a/src/pulsecore/flist.c +++ b/src/pulsecore/flist.c @@ -130,15 +130,22 @@ void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) { } int pa_flist_push(pa_flist*l, void *p) { - unsigned idx, n, len; + unsigned idx, n; pa_atomic_ptr_t*cells; +#ifdef PROFILE + unsigned len; +#endif pa_assert(l); pa_assert(p); cells = PA_FLIST_CELLS(l); - n = len = l->size + N_EXTRA_SCAN - (unsigned) pa_atomic_load(&l->length); + n = l->size + N_EXTRA_SCAN - (unsigned) pa_atomic_load(&l->length); + +#ifdef PROFILE + len = n; +#endif _Y; idx = reduce(l, (unsigned) pa_atomic_load(&l->write_idx)); @@ -171,14 +178,21 @@ int pa_flist_push(pa_flist*l, void *p) { } void* pa_flist_pop(pa_flist*l) { - unsigned idx, len, n; + unsigned idx, n; pa_atomic_ptr_t *cells; +#ifdef PROFILE + unsigned len; +#endif pa_assert(l); cells = PA_FLIST_CELLS(l); - n = len = (unsigned) pa_atomic_load(&l->length) + N_EXTRA_SCAN; + n = (unsigned) pa_atomic_load(&l->length) + N_EXTRA_SCAN; + +#ifdef PROFILE + len = n; +#endif _Y; idx = reduce(l, (unsigned) pa_atomic_load(&l->read_idx)); diff --git a/src/pulsecore/memtrap.c b/src/pulsecore/memtrap.c index c647e507..373872c1 100644 --- a/src/pulsecore/memtrap.c +++ b/src/pulsecore/memtrap.c @@ -200,13 +200,13 @@ pa_memtrap *pa_memtrap_update(pa_memtrap *m, const void *start, size_t size) { goto unlock; memtrap_unlink(m, j); - j = pa_aupdate_write_swap(aupdate); + pa_aupdate_write_swap(aupdate); m->start = (void*) start; m->size = size; pa_atomic_store(&m->bad, 0); - j = pa_aupdate_write_swap(aupdate); + pa_assert_se(pa_aupdate_write_swap(aupdate) == j); memtrap_link(m, j); unlock: diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index 00878462..996946c2 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -81,7 +81,7 @@ static pid_t read_pid(const char *fn, int fd) { } static int open_pid_file(const char *fn, int mode) { - int fd = -1; + int fd; pa_assert(fn); @@ -123,8 +123,6 @@ static int open_pid_file(const char *fn, int mode) { fd = -1; goto fail; } - - fd = -1; } return fd; diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 480af6d5..2326eb3a 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -771,7 +771,6 @@ static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void * memcpy(&rvolume, data, sizeof(uint32_t)); rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); - data = (const char*)data + sizeof(uint32_t); if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx)) && conn->sink_input) { pa_cvolume volume; @@ -809,7 +808,6 @@ static int esd_proto_sample_pan(connection *c, esd_proto_t request, const void * memcpy(&rvolume, data, sizeof(uint32_t)); rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); - data = (const char*)data + sizeof(uint32_t); volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; @@ -1123,7 +1121,7 @@ static int do_read(connection *c) { ssize_t r; size_t l; void *p; - size_t space; + size_t space = 0; pa_assert(c->input_memblockq); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index d961dba2..0215c233 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -628,7 +628,6 @@ static record_stream* record_stream_new( record_stream *s; pa_source_output *source_output = NULL; - size_t base; pa_source_output_new_data data; pa_assert(c); @@ -682,7 +681,7 @@ static record_stream* record_stream_new( 0, s->buffer_attr.maxlength, 0, - base = pa_frame_size(&source_output->sample_spec), + pa_frame_size(&source_output->sample_spec), 1, 0, 0, diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index d66db4b7..a9f73896 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -154,7 +154,7 @@ static int do_read(connection *c) { ssize_t r; size_t l; void *p; - size_t space; + size_t space = 0; connection_assert_ref(c); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index adda2aff..5f79ab1e 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -1152,7 +1152,6 @@ pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) { /* Called from main context */ int pa_sink_input_start_move(pa_sink_input *i) { pa_source_output *o, *p = NULL; - pa_sink *origin; int r; pa_sink_input_assert_ref(i); @@ -1166,8 +1165,6 @@ int pa_sink_input_start_move(pa_sink_input *i) { if ((r = pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], i)) < 0) return r; - origin = i->sink; - /* Kill directly connected outputs */ while ((o = pa_idxset_first(i->direct_outputs, NULL))) { pa_assert(o != p); diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c index 24535157..c9cfdbe3 100644 --- a/src/pulsecore/socket-client.c +++ b/src/pulsecore/socket-client.c @@ -202,8 +202,6 @@ static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event } static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { - int r; - pa_assert(c); pa_assert(PA_REFCNT_VALUE(c) >= 1); pa_assert(sa); @@ -211,7 +209,7 @@ static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t pa_make_fd_nonblock(c->fd); - if ((r = connect(c->fd, sa, len)) < 0) { + if (connect(c->fd, sa, len) < 0) { #ifdef OS_IS_WIN32 if (WSAGetLastError() != EWOULDBLOCK) { pa_log_debug("connect(): %d", WSAGetLastError()); diff --git a/src/utils/pacat.c b/src/utils/pacat.c index 0a369bc2..d6c04db7 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -406,7 +406,6 @@ static void context_state_callback(pa_context *c, void *userdata) { break; case PA_CONTEXT_READY: { - int r; pa_buffer_attr buffer_attr; pa_assert(c); @@ -443,13 +442,13 @@ static void context_state_callback(pa_context *c, void *userdata) { if (mode == PLAYBACK) { pa_cvolume cv; - if ((r = pa_stream_connect_playback(stream, device, latency > 0 ? &buffer_attr : NULL, flags, volume_is_set ? pa_cvolume_set(&cv, sample_spec.channels, volume) : NULL, NULL)) < 0) { + if (pa_stream_connect_playback(stream, device, latency > 0 ? &buffer_attr : NULL, flags, volume_is_set ? pa_cvolume_set(&cv, sample_spec.channels, volume) : NULL, NULL) < 0) { pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c))); goto fail; } } else { - if ((r = pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags)) < 0) { + if (pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags) < 0) { pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c))); goto fail; } -- cgit From 382eced35de93cba8098610f3990c16ae35b6ea0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:47:23 +0200 Subject: alsa-sink: init after_avail earlier (llvm-clang-analyzer) --- src/modules/alsa/alsa-sink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 63a3e906..883b32a7 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -656,6 +656,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle snd_pcm_sframes_t n; size_t n_bytes; int r; + pa_bool_t after_avail = TRUE; if (PA_UNLIKELY((n = pa_alsa_safe_avail(u->pcm_handle, u->hwbuf_size, &u->sink->sample_spec)) < 0)) { @@ -710,7 +711,6 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle for (;;) { snd_pcm_sframes_t frames; void *p; - pa_bool_t after_avail = TRUE; /* pa_log_debug("%lu frames to write", (unsigned long) frames); */ -- cgit From 1380f18e52db48f61fd8582c59e52281728f22b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:48:12 +0200 Subject: blueooth: actually honour 'room' variable (llvm-clang-analyzer) --- src/modules/bluetooth/module-bluetooth-device.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index b8a88042..4592fca1 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -221,9 +221,7 @@ static int service_recv(struct userdata *u, bt_audio_msg_header_t *msg, size_t r pa_assert(u); pa_assert(u->service_fd >= 0); pa_assert(msg); - - if (room <= 0) - room = BT_SUGGESTED_BUFFER_SIZE; + pa_assert(room >= sizeof(*msg)); pa_log_debug("Trying to receive message from audio service..."); @@ -236,6 +234,11 @@ static int service_recv(struct userdata *u, bt_audio_msg_header_t *msg, size_t r return -1; } + if (msg->length > room) { + pa_log_error("Not enough room."); + return -1; + } + /* Secondly, read the payload */ if (msg->length > sizeof(*msg)) { -- cgit From 157ec797dd53e1fb3d14f44c991064b0a2dee8e2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:48:47 +0200 Subject: hal: check properly for failure of libhal_find_device_by_capability() (llvm-clang-analyzer) --- src/modules/hal-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/modules/hal-util.c b/src/modules/hal-util.c index e2a2d8d7..2d59f51d 100644 --- a/src/modules/hal-util.c +++ b/src/modules/hal-util.c @@ -65,7 +65,7 @@ int pa_hal_get_info(pa_core *core, pa_proplist *p, int card) { goto finish; } - if (!(udis = libhal_find_device_by_capability(hal, "sound", &n, &error)) < 0) { + if (!(udis = libhal_find_device_by_capability(hal, "sound", &n, &error))) { pa_log_error("Couldn't find devices: %s: %s", error.name, error.message); goto finish; } -- cgit From f3be47f1e03b5970281527d95c7ee26de2fc6dde Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:49:10 +0200 Subject: rtsp: document that rtsp_exec() needs fixing (llvm-clang-analyzer) --- src/modules/rtp/rtsp_client.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/modules/rtp/rtsp_client.c b/src/modules/rtp/rtsp_client.c index ba657f74..915c1072 100644 --- a/src/modules/rtp/rtsp_client.c +++ b/src/modules/rtp/rtsp_client.c @@ -456,6 +456,8 @@ static int rtsp_exec(pa_rtsp_client* c, const char* cmd, l = pa_iochannel_write(c->io, hdrs, strlen(hdrs)); pa_xfree(hdrs); + /* FIXME: this is broken, not necessarily all bytes are written */ + return 0; } -- 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') 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 5fd751fc2ee44db50c26adc6d1881508c1ab04f5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:50:14 +0200 Subject: cli-command: modernizations --- src/pulsecore/cli-command.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 143db3b2..3941cc85 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -1549,7 +1549,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b pa_sink *sink; pa_source *source; pa_card *card; - int nl; + pa_bool_t nl; uint32_t idx; char txt[256]; time_t now; @@ -1567,7 +1567,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now)); #endif - for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) { + PA_IDXSET_FOREACH(m, c->modules, idx) { pa_strbuf_printf(buf, "load-module %s", m->name); @@ -1577,13 +1577,12 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b pa_strbuf_puts(buf, "\n"); } - nl = 0; - - for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { + nl = FALSE; + PA_IDXSET_FOREACH(sink, c->sinks, idx) { if (!nl) { pa_strbuf_puts(buf, "\n"); - nl = 1; + nl = TRUE; } pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_max(pa_sink_get_volume(sink, FALSE))); @@ -1591,11 +1590,12 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED)); } - for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { + nl = FALSE; + PA_IDXSET_FOREACH(source, c->sources, idx) { if (!nl) { pa_strbuf_puts(buf, "\n"); - nl = 1; + nl = TRUE; } pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_max(pa_source_get_volume(source, FALSE))); @@ -1603,32 +1603,32 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(pa_source_get_state(source) == PA_SOURCE_SUSPENDED)); } - for (card = pa_idxset_first(c->cards, &idx); card; card = pa_idxset_next(c->cards, &idx)) { + nl = FALSE; + PA_IDXSET_FOREACH(card, c->cards, idx) { if (!nl) { pa_strbuf_puts(buf, "\n"); - nl = 1; + nl = TRUE; } if (card->active_profile) pa_strbuf_printf(buf, "set-card-profile %s %s\n", card->name, card->active_profile->name); } - nl = 0; - + nl = FALSE; if ((sink = pa_namereg_get_default_sink(c))) { if (!nl) { pa_strbuf_puts(buf, "\n"); - nl = 1; + nl = TRUE; } + pa_strbuf_printf(buf, "set-default-sink %s\n", sink->name); } if ((source = pa_namereg_get_default_source(c))) { - if (!nl) { + if (!nl) pa_strbuf_puts(buf, "\n"); - nl = 1; - } + pa_strbuf_printf(buf, "set-default-source %s\n", source->name); } -- cgit From 3c9a09bc45608eb333e67bd44c3b69049f4d4ed7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:51:00 +0200 Subject: cli-command: don't necessarily ovveride failure code of files (llvm-clang-analyzer) --- src/pulsecore/cli-command.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 3941cc85..b57919a4 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -1813,8 +1813,6 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, pa_b ret = pa_cli_command_execute_file_stream(c, f, buf, fail); - ret = 0; - fail: if (f) fclose(f); -- cgit From 1516b7c047464e406ec983f10dcd3b854c4f3331 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:51:39 +0200 Subject: conf-parser: properly initialize variable we free() later (llvm-clang-analyzer) --- src/pulsecore/conf-parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index b4ab23cc..dd4a99ee 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -113,7 +113,7 @@ static int parse_line(const char *filename, unsigned line, char **section, const return 0; if (pa_startswith(b, ".include ")) { - char *path, *fn; + char *path = NULL, *fn; int r; fn = strip(b+9); -- cgit From 31ae7deefa72288b0c250b3ddc68c39e8eb840eb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:52:58 +0200 Subject: core-util: properly fill in exception array for pa_reset_sigs() (llvm-clang-analyzer) --- src/pulsecore/core-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index d64c7388..7a9f458c 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2404,7 +2404,7 @@ int pa_reset_sigs(int except, ...) { p[i++] = except; while ((sig = va_arg(ap, int)) >= 0) - sig = p[i++]; + p[i++] = sig; } p[i] = -1; -- cgit From 31d1d9088e18b9d59a259230e0e49e6a5908586a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:53:28 +0200 Subject: protocol-native: log explicitly when someone asks us to quit --- src/pulsecore/protocol-native.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 0215c233..17aee4b1 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2273,6 +2273,8 @@ static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta ret = pa_core_exit(c->protocol->core, FALSE, 0); CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS); + pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY))); + pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ } -- cgit From 49bc6bcf084d143d490c83e0021c447dbf0a6be9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:53:56 +0200 Subject: stripnul: initialize 'found' bool properly (llvm-clang-analyzer) --- src/tests/stripnul.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/tests/stripnul.c b/src/tests/stripnul.c index 1d8c4938..d677ad20 100644 --- a/src/tests/stripnul.c +++ b/src/tests/stripnul.c @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) { FILE *i, *o; size_t granularity; - pa_bool_t found; + pa_bool_t found = FALSE; uint8_t *zero; pa_assert_se(argc >= 2); -- cgit From b51f5e58cc4ebbb5b4343c031ed9e37c352f81a6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:54:31 +0200 Subject: pacat: don't convert stream name twice (llvm-clang-analyzer) --- src/utils/pacat.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/utils/pacat.c b/src/utils/pacat.c index d6c04db7..781bfa33 100644 --- a/src/utils/pacat.c +++ b/src/utils/pacat.c @@ -768,7 +768,6 @@ int main(int argc, char *argv[]) { case ARG_STREAM_NAME: { char *t; - t = pa_locale_to_utf8(optarg); if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) { -- cgit From 7cc100d9e1d7093da44c8c83cbf61bb8c6000d9a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Sep 2009 23:54:53 +0200 Subject: padsp: properly return return values (llvm-clang-analyzer) --- src/utils/padsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/utils/padsp.c b/src/utils/padsp.c index 882522c4..41bfd741 100644 --- a/src/utils/padsp.c +++ b/src/utils/padsp.c @@ -1821,7 +1821,7 @@ fail: pa_threaded_mainloop_unlock(i->mainloop); - return 0; + return r; } static int dsp_trigger(fd_info *i) { @@ -1864,7 +1864,7 @@ fail: pa_threaded_mainloop_unlock(i->mainloop); - return 0; + return r; } static int dsp_cork(fd_info *i, pa_stream *s, int b) { @@ -1902,7 +1902,7 @@ fail: pa_threaded_mainloop_unlock(i->mainloop); - return 0; + return r; } static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) { -- cgit From 12df6860ad1103bf1e90fee4501568e45c882ee2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Sep 2009 02:41:34 +0200 Subject: ratelimit: allow non-static ratelimit structs --- src/pulsecore/ratelimit.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pulsecore/ratelimit.h b/src/pulsecore/ratelimit.h index ec3b5a38..9857a291 100644 --- a/src/pulsecore/ratelimit.h +++ b/src/pulsecore/ratelimit.h @@ -26,21 +26,31 @@ #include typedef struct pa_ratelimit { - const pa_usec_t interval; - const unsigned burst; + pa_usec_t interval; + unsigned burst; unsigned n_printed, n_missed; pa_usec_t begin; } pa_ratelimit; #define PA_DEFINE_RATELIMIT(_name, _interval, _burst) \ pa_ratelimit _name = { \ - .interval = _interval, \ - .burst = _burst, \ + .interval = (_interval), \ + .burst = (_burst), \ .n_printed = 0, \ .n_missed = 0, \ .begin = 0 \ } +#define PA_INIT_RATELIMIT(v, _interval, _burst) \ + do { \ + pa_ratelimit *r = &(v); \ + r->interval = (_interval); \ + r->burst = (_burst); \ + r->n_printed = 0; \ + r->n_missed = 0; \ + r->begin = 0; \ + } while (FALSE); + pa_bool_t pa_ratelimit_test(pa_ratelimit *r); #endif -- cgit From c2f1994968e71f0f0a6c1f44bd8ec40edf1b6434 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Sep 2009 02:41:58 +0200 Subject: udev: ratelimit device initializations --- src/modules/module-udev-detect.c | 47 +++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c index b41b9c0f..1b1e9c1a 100644 --- a/src/modules/module-udev-detect.c +++ b/src/modules/module-udev-detect.c @@ -29,10 +29,13 @@ #include #include +#include + #include #include #include #include +#include #include "module-udev-detect-symdef.h" @@ -50,6 +53,7 @@ struct device { char *card_name; char *args; uint32_t module; + pa_ratelimit ratelimit; }; struct userdata { @@ -110,6 +114,9 @@ static pa_bool_t is_card_busy(const char *id) { pa_assert(id); + /* This simply uses /proc/asound/card.../pcm.../sub.../status to + * check whether there is still a process using this audio device. */ + card_path = pa_sprintf_malloc("/proc/asound/card%s", id); if (!(card_dir = opendir(card_path))) { @@ -234,14 +241,41 @@ static void verify_access(struct userdata *u, struct device *d) { pa_log_debug("%s is busy: %s", d->path, pa_yes_no(busy)); if (!busy) { - pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args); - m = pa_module_load(u->core, "module-alsa-card", d->args); - if (m) { - d->module = m->index; - pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name); + /* So, why do we rate limit here? It's certainly ugly, + * but there seems to be no other way. Problem is + * this: if we are unable to configure/probe an audio + * device after opening it we will close it again and + * the module initialization will fail. This will then + * cause an inotify event on the device node which + * will be forwarded to us. We then try to reopen the + * audio device again, practically entering a busy + * loop. + * + * A clean fix would be if we would be able to ignore + * our own inotify close events. However, inotify + * lacks such functionality. Also, during probing of + * the device we cannot really distuingish between + * other processes causing EBUSY or ourselves, which + * means we have no way to figure out if the probing + * during opening was canceled by a "try again" + * failure or a "fatal" failure. */ + + if (pa_ratelimit_test(&d->ratelimit)) { + pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args); + m = pa_module_load(u->core, "module-alsa-card", d->args); + + if (m) { + d->module = m->index; + pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name); + } else + pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name); } else - pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name); + pa_log_warn("Tried to configure %s (%s) more often than %u times in %llus", + d->path, + d->card_name, + d->ratelimit.burst, + (long long unsigned) (d->ratelimit.interval / PA_USEC_PER_SEC)); } } @@ -277,6 +311,7 @@ static void card_changed(struct userdata *u, struct udev_device *dev) { d = pa_xnew0(struct device, 1); d->path = pa_xstrdup(path); d->module = PA_INVALID_INDEX; + PA_INIT_RATELIMIT(d->ratelimit, 10*PA_USEC_PER_SEC, 5); if (!(t = udev_device_get_property_value(dev, "PULSE_NAME"))) if (!(t = udev_device_get_property_value(dev, "ID_ID"))) -- cgit From 1f0904b800d9d69698e79ce0435a2777d5f7ec27 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Sep 2009 04:27:16 +0200 Subject: sample-util: add pa_convert_size() call for converting sizes between two sample specs --- src/pulsecore/sample-util.c | 10 ++++++++++ src/pulsecore/sample-util.h | 2 ++ 2 files changed, 12 insertions(+) (limited to 'src') diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index 5fae1928..a26dc876 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -1056,3 +1056,13 @@ void pa_memchunk_sine(pa_memchunk *c, pa_mempool *pool, unsigned rate, unsigned calc_sine(p, c->length, freq * l / rate); pa_memblock_release(c->memblock); } + +size_t pa_convert_size(size_t size, const pa_sample_spec *from, const pa_sample_spec *to) { + pa_usec_t usec; + + pa_assert(from); + pa_assert(to); + + usec = pa_bytes_to_usec_round_up(size, from); + return pa_usec_to_bytes_round_up(usec, to); +} diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index 34df5cf3..d0235d60 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -91,6 +91,8 @@ typedef void (*pa_do_volume_func_t) (void *samples, void *volumes, unsigned chan pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f); void pa_set_volume_func(pa_sample_format_t f, pa_do_volume_func_t func); +size_t pa_convert_size(size_t size, const pa_sample_spec *from, const pa_sample_spec *to); + #define PA_CHANNEL_POSITION_MASK_LEFT \ (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \ | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT) \ -- cgit From 71e066c873e5bd31bd446ac0f8d0e97cc0b12ace Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Sep 2009 04:28:22 +0200 Subject: simd: be more precise which SIMD optimizations we activate --- src/pulsecore/remap_mmx.c | 8 ++++++-- src/pulsecore/remap_sse.c | 8 +++++--- src/pulsecore/sconv_sse.c | 12 +++++++----- src/pulsecore/svolume_mmx.c | 9 ++++++--- src/pulsecore/svolume_sse.c | 7 ++++--- 5 files changed, 28 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/pulsecore/remap_mmx.c b/src/pulsecore/remap_mmx.c index 79e4f1fc..d358a58b 100644 --- a/src/pulsecore/remap_mmx.c +++ b/src/pulsecore/remap_mmx.c @@ -150,8 +150,12 @@ static void init_remap_mmx (pa_remap_t *m) { void pa_remap_func_init_mmx (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) - pa_log_info("Initialising MMX optimized remappers."); - pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_mmx); + if (flags & PA_CPU_X86_MMX) { + pa_log_info("Initialising MMX optimized remappers."); + + pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_mmx); + } + #endif /* defined (__i386__) || defined (__amd64__) */ } diff --git a/src/pulsecore/remap_sse.c b/src/pulsecore/remap_sse.c index dac072ec..0ccf3161 100644 --- a/src/pulsecore/remap_sse.c +++ b/src/pulsecore/remap_sse.c @@ -149,9 +149,11 @@ static void init_remap_sse2 (pa_remap_t *m) { void pa_remap_func_init_sse (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) - pa_log_info("Initialising SSE optimized remappers."); - if (flags & PA_CPU_X86_SSE2) - pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_sse2); + if (flags & PA_CPU_X86_SSE2) { + pa_log_info("Initialising SSE2 optimized remappers."); + pa_set_init_remap_func ((pa_init_remap_func_t) init_remap_sse2); + } + #endif /* defined (__i386__) || defined (__amd64__) */ } diff --git a/src/pulsecore/sconv_sse.c b/src/pulsecore/sconv_sse.c index 7c3aa199..3737af2a 100644 --- a/src/pulsecore/sconv_sse.c +++ b/src/pulsecore/sconv_sse.c @@ -218,16 +218,18 @@ static void run_test (void) { void pa_convert_func_init_sse (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) - pa_log_info("Initialising SSE optimized conversions."); #ifdef RUN_TEST run_test (); #endif - if (flags & PA_CPU_X86_SSE2) - pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse2); - else - pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse); + if (flags & PA_CPU_X86_SSE2) { + pa_log_info("Initialising SSE2 optimized conversions."); + pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse2); + } else { + pa_log_info("Initialising SSE optimized conversions."); + pa_set_convert_from_float32ne_function (PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse); + } #endif /* defined (__i386__) || defined (__amd64__) */ } diff --git a/src/pulsecore/svolume_mmx.c b/src/pulsecore/svolume_mmx.c index 8510b0c4..74918e78 100644 --- a/src/pulsecore/svolume_mmx.c +++ b/src/pulsecore/svolume_mmx.c @@ -301,13 +301,16 @@ static void run_test (void) { void pa_volume_func_init_mmx (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) - pa_log_info("Initialising MMX optimized functions."); #ifdef RUN_TEST run_test (); #endif - pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx); - pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx); + if (flags & PA_CPU_X86_MMX) { + pa_log_info("Initialising MMX optimized functions."); + + pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_mmx); + pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_mmx); + } #endif /* defined (__i386__) || defined (__amd64__) */ } diff --git a/src/pulsecore/svolume_sse.c b/src/pulsecore/svolume_sse.c index d9dcf476..bbd73a9b 100644 --- a/src/pulsecore/svolume_sse.c +++ b/src/pulsecore/svolume_sse.c @@ -302,15 +302,16 @@ static void run_test (void) { void pa_volume_func_init_sse (pa_cpu_x86_flag_t flags) { #if defined (__i386__) || defined (__amd64__) - pa_log_info("Initialising SSE optimized functions."); #ifdef RUN_TEST run_test (); #endif if (flags & PA_CPU_X86_SSE2) { - pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse2); - pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse2); + pa_log_info("Initialising SSE2 optimized functions."); + + pa_set_volume_func (PA_SAMPLE_S16NE, (pa_do_volume_func_t) pa_volume_s16ne_sse2); + pa_set_volume_func (PA_SAMPLE_S16RE, (pa_do_volume_func_t) pa_volume_s16re_sse2); } #endif /* defined (__i386__) || defined (__amd64__) */ } -- cgit From 557c4295107dc7374c850b0bd5331dd35e8fdd0f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Sep 2009 04:28:52 +0200 Subject: alsa: rework buffer/period configuration - As discussed on alsa-devel it's probably better to initialize the buffer size first, followed by the period size. If that fails try the other way round. If that fails try to configure only buffer size. If that fails try to configure only period size. Finally, try to configure neither. - Don't require integral periods anymore. Both of these changes should help improving compatibility with various weirder sound devices, such as TV cards. --- src/modules/alsa/alsa-sink.c | 44 ++++---- src/modules/alsa/alsa-source.c | 45 ++++---- src/modules/alsa/alsa-util.c | 248 +++++++++++++++++++++++++++-------------- src/modules/alsa/alsa-util.h | 10 +- 4 files changed, 217 insertions(+), 130 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 883b32a7..c4ff10de 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -116,7 +116,6 @@ struct userdata { pa_usec_t watermark_dec_not_before; - unsigned nfragments; pa_memchunk memchunk; char *device_name; /* name of the PCM device */ @@ -943,8 +942,7 @@ static int unsuspend(struct userdata *u) { pa_sample_spec ss; int err; pa_bool_t b, d; - unsigned nfrags; - snd_pcm_uframes_t period_size; + snd_pcm_uframes_t period_size, buffer_size; pa_assert(u); pa_assert(!u->pcm_handle); @@ -961,12 +959,12 @@ static int unsuspend(struct userdata *u) { } ss = u->sink->sample_spec; - nfrags = u->nfragments; period_size = u->fragment_size / u->frame_size; + buffer_size = u->hwbuf_size / u->frame_size; b = u->use_mmap; d = u->use_tsched; - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, u->hwbuf_size / u->frame_size, &b, &d, TRUE)) < 0) { + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_size, &buffer_size, 0, &b, &d, TRUE)) < 0) { pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err)); goto fail; } @@ -981,10 +979,11 @@ static int unsuspend(struct userdata *u) { goto fail; } - if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) { - pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu*%lu, New %lu*%lu)", - (unsigned long) u->nfragments, (unsigned long) u->fragment_size, - (unsigned long) nfrags, period_size * u->frame_size); + if (period_size*u->frame_size != u->fragment_size || + buffer_size*u->frame_size != u->hwbuf_size) { + pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)", + (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size, + (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size)); goto fail; } @@ -1638,8 +1637,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca const char *dev_id = NULL; pa_sample_spec ss, requested_ss; pa_channel_map map; - uint32_t nfrags, frag_size, tsched_size, tsched_watermark; - snd_pcm_uframes_t period_frames, tsched_frames; + uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark; + snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames; size_t frame_size; pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE; pa_sink_new_data data; @@ -1673,7 +1672,10 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca goto fail; } + buffer_size = nfrags * frag_size; + period_frames = frag_size/frame_size; + buffer_frames = buffer_size/frame_size; tsched_frames = tsched_size/frame_size; if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { @@ -1740,7 +1742,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca &u->device_name, &ss, &map, SND_PCM_STREAM_PLAYBACK, - &nfrags, &period_frames, tsched_frames, + &period_frames, &buffer_frames, tsched_frames, &b, &d, mapping))) goto fail; @@ -1755,7 +1757,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca &u->device_name, &ss, &map, SND_PCM_STREAM_PLAYBACK, - &nfrags, &period_frames, tsched_frames, + &period_frames, &buffer_frames, tsched_frames, &b, &d, profile_set, &mapping))) goto fail; @@ -1767,7 +1769,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca &u->device_name, &ss, &map, SND_PCM_STREAM_PLAYBACK, - &nfrags, &period_frames, tsched_frames, + &period_frames, &buffer_frames, tsched_frames, &b, &d, FALSE))) goto fail; } @@ -1819,7 +1821,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name); - pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags)); + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (buffer_frames * frame_size)); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size)); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial")); @@ -1860,13 +1862,15 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca pa_sink_set_rtpoll(u->sink, u->rtpoll); u->frame_size = frame_size; - u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size); - u->nfragments = nfrags; - u->hwbuf_size = u->fragment_size * nfrags; + u->fragment_size = frag_size = (size_t) (period_frames * frame_size); + u->hwbuf_size = buffer_size = (size_t) (buffer_frames * frame_size); pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels); - pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms", - nfrags, (long unsigned) u->fragment_size, + pa_log_info("Using %0.1f fragments of size %lu bytes (%0.2fms), buffer size is %lu bytes (%0.2fms)", + (double) u->hwbuf_size / (double) u->fragment_size, + (long unsigned) u->fragment_size, + (double) pa_bytes_to_usec(u->fragment_size, &ss) / PA_USEC_PER_MSEC, + (long unsigned) u->hwbuf_size, (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC); pa_sink_set_max_request(u->sink, u->hwbuf_size); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 64f89806..5f89d88c 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -111,8 +111,6 @@ struct userdata { pa_usec_t watermark_dec_not_before; - unsigned nfragments; - char *device_name; char *control_device; @@ -891,8 +889,7 @@ static int unsuspend(struct userdata *u) { pa_sample_spec ss; int err; pa_bool_t b, d; - unsigned nfrags; - snd_pcm_uframes_t period_size; + snd_pcm_uframes_t period_size, buffer_size; pa_assert(u); pa_assert(!u->pcm_handle); @@ -909,12 +906,12 @@ static int unsuspend(struct userdata *u) { } ss = u->source->sample_spec; - nfrags = u->nfragments; period_size = u->fragment_size / u->frame_size; + buffer_size = u->hwbuf_size / u->frame_size; b = u->use_mmap; d = u->use_tsched; - if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, u->hwbuf_size / u->frame_size, &b, &d, TRUE)) < 0) { + if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_size, &buffer_size, 0, &b, &d, TRUE)) < 0) { pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err)); goto fail; } @@ -929,10 +926,11 @@ static int unsuspend(struct userdata *u) { goto fail; } - if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) { - pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu*%lu, New %lu*%lu)", - (unsigned long) u->nfragments, (unsigned long) u->fragment_size, - (unsigned long) nfrags, period_size * u->frame_size); + if (period_size*u->frame_size != u->fragment_size || + buffer_size*u->frame_size != u->hwbuf_size) { + pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)", + (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size, + (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size)); goto fail; } @@ -1483,8 +1481,8 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p const char *dev_id = NULL; pa_sample_spec ss, requested_ss; pa_channel_map map; - uint32_t nfrags, frag_size, tsched_size, tsched_watermark; - snd_pcm_uframes_t period_frames, tsched_frames; + uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark; + snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames; size_t frame_size; pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE; pa_source_new_data data; @@ -1518,7 +1516,10 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p goto fail; } + buffer_size = nfrags * frag_size; + period_frames = frag_size/frame_size; + buffer_frames = buffer_size/frame_size; tsched_frames = tsched_size/frame_size; if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { @@ -1584,7 +1585,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p &u->device_name, &ss, &map, SND_PCM_STREAM_CAPTURE, - &nfrags, &period_frames, tsched_frames, + &period_frames, &buffer_frames, tsched_frames, &b, &d, mapping))) goto fail; @@ -1598,7 +1599,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p &u->device_name, &ss, &map, SND_PCM_STREAM_CAPTURE, - &nfrags, &period_frames, tsched_frames, + &period_frames, &buffer_frames, tsched_frames, &b, &d, profile_set, &mapping))) goto fail; @@ -1609,7 +1610,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p &u->device_name, &ss, &map, SND_PCM_STREAM_CAPTURE, - &nfrags, &period_frames, tsched_frames, + &period_frames, &buffer_frames, tsched_frames, &b, &d, FALSE))) goto fail; } @@ -1661,7 +1662,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name); - pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags)); + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (buffer_frames * frame_size)); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size)); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial")); @@ -1702,13 +1703,15 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p pa_source_set_rtpoll(u->source, u->rtpoll); u->frame_size = frame_size; - u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size); - u->nfragments = nfrags; - u->hwbuf_size = u->fragment_size * nfrags; + u->fragment_size = frag_size = (size_t) (period_frames * frame_size); + u->hwbuf_size = buffer_size = (size_t) (buffer_frames * frame_size); pa_cvolume_mute(&u->hardware_volume, u->source->sample_spec.channels); - pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms", - nfrags, (long unsigned) u->fragment_size, + pa_log_info("Using %0.1f fragments of size %lu bytes (%0.2fms), buffer size is %lu bytes (%0.2fms)", + (double) u->hwbuf_size / (double) u->fragment_size, + (long unsigned) u->fragment_size, + (double) pa_bytes_to_usec(u->fragment_size, &ss) / PA_USEC_PER_MSEC, + (long unsigned) u->hwbuf_size, (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC); if (u->use_tsched) { diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 4d75c63c..91474527 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -93,6 +93,7 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s int ret; pa_assert(pcm_handle); + pa_assert(hwparams); pa_assert(f); if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0) @@ -148,33 +149,71 @@ try_auto: return -1; } +static int set_period_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) { + snd_pcm_uframes_t s; + int d, ret; + + pa_assert(pcm_handle); + pa_assert(hwparams); + + s = size; + d = 0; + if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) { + s = size; + d = -1; + if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) { + s = size; + d = 1; + if ((ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d)) < 0) { + pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret)); + return ret; + } + } + } + + return 0; +} + +static int set_buffer_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) { + int ret; + + pa_assert(pcm_handle); + pa_assert(hwparams); + + if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &size)) < 0) { + pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret)); + return ret; + } + + return 0; +} + /* Set the hardware parameters of the given ALSA device. Returns the * selected fragment settings in *period and *period_size */ int pa_alsa_set_hw_params( snd_pcm_t *pcm_handle, pa_sample_spec *ss, - uint32_t *periods, snd_pcm_uframes_t *period_size, + snd_pcm_uframes_t *buffer_size, snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, pa_bool_t *use_tsched, pa_bool_t require_exact_channel_number) { int ret = -1; + snd_pcm_hw_params_t *hwparams, *hwparams_copy; + int dir; snd_pcm_uframes_t _period_size = period_size ? *period_size : 0; - unsigned int _periods = periods ? *periods : 0; - unsigned int r = ss->rate; - unsigned int c = ss->channels; - pa_sample_format_t f = ss->format; - snd_pcm_hw_params_t *hwparams; + snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0; pa_bool_t _use_mmap = use_mmap && *use_mmap; pa_bool_t _use_tsched = use_tsched && *use_tsched; - int dir; + pa_sample_spec _ss = *ss; pa_assert(pcm_handle); pa_assert(ss); snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_hw_params_alloca(&hwparams_copy); if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) { pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret)); @@ -208,114 +247,140 @@ int pa_alsa_set_hw_params( if (!_use_mmap) _use_tsched = FALSE; - if ((ret = set_format(pcm_handle, hwparams, &f)) < 0) + if ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0) goto finish; - if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0) { + if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &_ss.rate, NULL)) < 0) { pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret)); goto finish; } if (require_exact_channel_number) { - if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0) { - pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", c, pa_alsa_strerror(ret)); + if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) { + pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret)); goto finish; } } else { + unsigned int c = _ss.channels; + if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) { - pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", c, pa_alsa_strerror(ret)); + pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret)); goto finish; } - } - if ((ret = snd_pcm_hw_params_set_periods_integer(pcm_handle, hwparams)) < 0) { - pa_log_debug("snd_pcm_hw_params_set_periods_integer() failed: %s", pa_alsa_strerror(ret)); - goto finish; + _ss.channels = c; } - if (_period_size > 0 && tsched_size > 0 && _periods > 0) { - snd_pcm_uframes_t buffer_size; - unsigned int p; + if (_use_tsched && tsched_size > 0) { + _buffer_size = pa_convert_size(tsched_size, ss, &_ss); + _period_size = _buffer_size; + } else { + _period_size = pa_convert_size(_period_size, ss, &_ss); + _buffer_size = pa_convert_size(_buffer_size, ss, &_ss); + } - /* Adjust the buffer sizes, if we didn't get the rate we were asking for */ - _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate); - tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate); + if (_buffer_size > 0 || _period_size > 0) { + snd_pcm_uframes_t max_frames = 0; - if (_use_tsched) { - buffer_size = 0; + if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0) + pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret)); + else + pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) max_frames * PA_MSEC_PER_SEC / _ss.rate); - if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size)) < 0) - pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret)); - else - pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size * 1000 / r); + /* Some ALSA drivers really don't like if we set the buffer + * size first and the number of periods second. (which would + * make a lot more sense to me) So, try a few combinations + * before we give up. */ + + if (_buffer_size > 0 && _period_size > 0) { + snd_pcm_hw_params_copy(hwparams_copy, hwparams); + + /* First try: set buffer size first, followed by period size */ + if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && + set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && + snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { + pa_log_debug("Set buffer size first, period size second."); + goto success; + } - _period_size = tsched_size; - _periods = 1; + /* Second try: set period size first, followed by buffer size */ + if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && + set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && + snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { + pa_log_debug("Set period size first, buffer size second."); + goto success; + } } - /* Some ALSA drivers really don't like if we set the buffer - * size first and the number of periods second. (which would - * make a lot more sense to me) So, follow this rule and - * adjust the periods first and the buffer size second */ - - /* First we pass 0 as direction to get exactly what we - * asked for. That this is necessary is presumably a bug - * in ALSA. All in all this is mostly a hint to ALSA, so - * we don't care if this fails. */ - - p = _periods; - dir = 0; - if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) { - p = _periods; - dir = 1; - if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) { - p = _periods; - dir = -1; - if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir)) < 0) - pa_log_info("snd_pcm_hw_params_set_periods_near() failed: %s", pa_alsa_strerror(ret)); + if (_buffer_size > 0) { + snd_pcm_hw_params_copy(hwparams_copy, hwparams); + + /* Third try: set only buffer size */ + if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && + snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { + pa_log_debug("Set only buffer size second."); + goto success; } } - /* Now set the buffer size */ - buffer_size = _periods * _period_size; - if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0) - pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret)); + if (_period_size > 0) { + snd_pcm_hw_params_copy(hwparams_copy, hwparams); + + /* Fourth try: set only period size */ + if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && + snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { + pa_log_debug("Set only period size second."); + goto success; + } + } } - if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) + pa_log_debug("Set neither period nor buffer size."); + + /* Last chance, set nothing */ + if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { + pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret)); goto finish; + } + +success: - if (ss->rate != r) - pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r); + if (ss->rate != _ss.rate) + pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, _ss.rate); - if (ss->channels != c) - pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c); + if (ss->channels != _ss.channels) + pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, _ss.channels); - if (ss->format != f) - pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f)); + if (ss->format != _ss.format) + pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(_ss.format)); if ((ret = snd_pcm_prepare(pcm_handle)) < 0) { pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret)); goto finish; } + if ((ret = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) { + pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret)); + goto finish; + } + if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 || - (ret = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0) { - pa_log_info("snd_pcm_hw_params_get_period{s|_size}() failed: %s", pa_alsa_strerror(ret)); + (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) { + pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret)); goto finish; } /* If the sample rate deviates too much, we need to resample */ - if (r < ss->rate*.95 || r > ss->rate*1.05) - ss->rate = r; - ss->channels = (uint8_t) c; - ss->format = f; + if (_ss.rate < ss->rate*.95 || _ss.rate > ss->rate*1.05) + ss->rate = _ss.rate; + ss->channels = _ss.channels; + ss->format = _ss.format; - pa_assert(_periods > 0); pa_assert(_period_size > 0); + pa_assert(_buffer_size > 0); - if (periods) - *periods = _periods; + if (buffer_size) + *buffer_size = _buffer_size; if (period_size) *period_size = _period_size; @@ -393,8 +458,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( pa_sample_spec *ss, pa_channel_map* map, int mode, - uint32_t *nfrags, snd_pcm_uframes_t *period_size, + snd_pcm_uframes_t *buffer_size, snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, pa_bool_t *use_tsched, @@ -410,8 +475,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( pa_assert(dev); pa_assert(ss); pa_assert(map); - pa_assert(nfrags); - pa_assert(period_size); pa_assert(ps); /* First we try to find a device string with a superset of the @@ -433,8 +496,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( ss, map, mode, - nfrags, period_size, + buffer_size, tsched_size, use_mmap, use_tsched, @@ -460,8 +523,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( ss, map, mode, - nfrags, period_size, + buffer_size, tsched_size, use_mmap, use_tsched, @@ -478,7 +541,18 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( /* OK, we didn't find any good device, so let's try the raw hw: stuff */ d = pa_sprintf_malloc("hw:%s", dev_id); pa_log_debug("Trying %s as last resort...", d); - pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, tsched_size, use_mmap, use_tsched, FALSE); + pcm_handle = pa_alsa_open_by_device_string( + d, + dev, + ss, + map, + mode, + period_size, + buffer_size, + tsched_size, + use_mmap, + use_tsched, + FALSE); pa_xfree(d); if (pcm_handle && mapping) @@ -493,8 +567,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( pa_sample_spec *ss, pa_channel_map* map, int mode, - uint32_t *nfrags, snd_pcm_uframes_t *period_size, + snd_pcm_uframes_t *buffer_size, snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, pa_bool_t *use_tsched, @@ -508,8 +582,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( pa_assert(dev); pa_assert(ss); pa_assert(map); - pa_assert(nfrags); - pa_assert(period_size); pa_assert(m); try_ss.channels = m->channel_map.channels; @@ -524,8 +596,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( &try_ss, &try_map, mode, - nfrags, period_size, + buffer_size, tsched_size, use_mmap, use_tsched, @@ -547,8 +619,8 @@ snd_pcm_t *pa_alsa_open_by_device_string( pa_sample_spec *ss, pa_channel_map* map, int mode, - uint32_t *nfrags, snd_pcm_uframes_t *period_size, + snd_pcm_uframes_t *buffer_size, snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, pa_bool_t *use_tsched, @@ -579,7 +651,15 @@ snd_pcm_t *pa_alsa_open_by_device_string( pa_log_debug("Managed to open %s", d); - if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) { + if ((err = pa_alsa_set_hw_params( + pcm_handle, + ss, + period_size, + buffer_size, + tsched_size, + use_mmap, + use_tsched, + require_exact_channel_number)) < 0) { if (!reformat) { reformat = TRUE; @@ -632,8 +712,8 @@ snd_pcm_t *pa_alsa_open_by_template( pa_sample_spec *ss, pa_channel_map* map, int mode, - uint32_t *nfrags, snd_pcm_uframes_t *period_size, + snd_pcm_uframes_t *buffer_size, snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, pa_bool_t *use_tsched, @@ -653,8 +733,8 @@ snd_pcm_t *pa_alsa_open_by_template( ss, map, mode, - nfrags, period_size, + buffer_size, tsched_size, use_mmap, use_tsched, diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 830a922e..265cd28c 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -42,8 +42,8 @@ int pa_alsa_set_hw_params( snd_pcm_t *pcm_handle, pa_sample_spec *ss, /* modified at return */ - uint32_t *periods, /* modified at return */ snd_pcm_uframes_t *period_size, /* modified at return */ + snd_pcm_uframes_t *buffer_size, /* modified at return */ snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, /* modified at return */ pa_bool_t *use_tsched, /* modified at return */ @@ -60,8 +60,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( pa_sample_spec *ss, /* modified at return */ pa_channel_map* map, /* modified at return */ int mode, - uint32_t *nfrags, /* modified at return */ snd_pcm_uframes_t *period_size, /* modified at return */ + snd_pcm_uframes_t *buffer_size, /* modified at return */ snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, /* modified at return */ pa_bool_t *use_tsched, /* modified at return */ @@ -75,8 +75,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( pa_sample_spec *ss, /* modified at return */ pa_channel_map* map, /* modified at return */ int mode, - uint32_t *nfrags, /* modified at return */ snd_pcm_uframes_t *period_size, /* modified at return */ + snd_pcm_uframes_t *buffer_size, /* modified at return */ snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, /* modified at return */ pa_bool_t *use_tsched, /* modified at return */ @@ -89,8 +89,8 @@ snd_pcm_t *pa_alsa_open_by_device_string( pa_sample_spec *ss, /* modified at return */ pa_channel_map* map, /* modified at return */ int mode, - uint32_t *nfrags, /* modified at return */ snd_pcm_uframes_t *period_size, /* modified at return */ + snd_pcm_uframes_t *buffer_size, /* modified at return */ snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, /* modified at return */ pa_bool_t *use_tsched, /* modified at return */ @@ -104,8 +104,8 @@ snd_pcm_t *pa_alsa_open_by_template( pa_sample_spec *ss, /* modified at return */ pa_channel_map* map, /* modified at return */ int mode, - uint32_t *nfrags, /* modified at return */ snd_pcm_uframes_t *period_size, /* modified at return */ + snd_pcm_uframes_t *buffer_size, /* modified at return */ snd_pcm_uframes_t tsched_size, pa_bool_t *use_mmap, /* modified at return */ pa_bool_t *use_tsched, /* modified at return */ -- cgit From 84ade2140ed44bf241eda494d0970390e48b21d3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Sep 2009 04:44:51 +0200 Subject: alsa: pass SND_PCM_NONBLOCK when opening device during unsuspend, the same way we do it for initial opening --- src/modules/alsa/alsa-sink.c | 2 +- src/modules/alsa/alsa-source.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index c4ff10de..7fe77831 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -950,7 +950,7 @@ static int unsuspend(struct userdata *u) { pa_log_info("Trying resume..."); if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_PLAYBACK, - /*SND_PCM_NONBLOCK|*/ + SND_PCM_NONBLOCK| SND_PCM_NO_AUTO_RESAMPLE| SND_PCM_NO_AUTO_CHANNELS| SND_PCM_NO_AUTO_FORMAT)) < 0) { diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 5f89d88c..a7f2a018 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -897,7 +897,7 @@ static int unsuspend(struct userdata *u) { pa_log_info("Trying resume..."); if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE, - /*SND_PCM_NONBLOCK|*/ + SND_PCM_NONBLOCK| SND_PCM_NO_AUTO_RESAMPLE| SND_PCM_NO_AUTO_CHANNELS| SND_PCM_NO_AUTO_FORMAT)) < 0) { -- cgit From 8364b959b452a2b9e3f230705feb176a1fa6de06 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Sep 2009 23:56:51 +0200 Subject: alsa: when probing for profiles configure buffer/period sizes since some broken drivers apparently need that --- src/modules/alsa/alsa-mixer.c | 23 ++++++++++++++++++++--- src/modules/alsa/alsa-mixer.h | 2 +- src/modules/alsa/module-alsa-card.c | 2 +- 3 files changed, 22 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 9eb7b462..685169b9 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -3145,7 +3145,13 @@ fail: return NULL; } -void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss) { +void pa_alsa_profile_set_probe( + pa_alsa_profile_set *ps, + const char *dev_id, + const pa_sample_spec *ss, + unsigned default_n_fragments, + unsigned default_fragment_size_msec) { + void *state; pa_alsa_profile *p, *last = NULL; pa_alsa_mapping *m; @@ -3160,6 +3166,7 @@ void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, cons PA_HASHMAP_FOREACH(p, ps->profiles, state) { pa_sample_spec try_ss; pa_channel_map try_map; + snd_pcm_uframes_t try_period_size, try_buffer_size; uint32_t idx; /* Is this already marked that it is supported? (i.e. from the config file) */ @@ -3213,13 +3220,18 @@ void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, cons try_ss = *ss; try_ss.channels = try_map.channels; + try_period_size = + pa_usec_to_bytes(default_fragment_size_msec * PA_USEC_PER_MSEC, &try_ss) / + pa_frame_size(&try_ss); + try_buffer_size = default_n_fragments * try_period_size; + if (!(m ->output_pcm = pa_alsa_open_by_template( m->device_strings, dev_id, NULL, &try_ss, &try_map, SND_PCM_STREAM_PLAYBACK, - NULL, NULL, 0, NULL, NULL, + &try_period_size, &try_buffer_size, 0, NULL, NULL, TRUE))) { p->supported = FALSE; break; @@ -3237,13 +3249,18 @@ void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, cons try_ss = *ss; try_ss.channels = try_map.channels; + try_period_size = + pa_usec_to_bytes(default_fragment_size_msec*PA_USEC_PER_MSEC, &try_ss) / + pa_frame_size(&try_ss); + try_buffer_size = default_n_fragments * try_period_size; + if (!(m ->input_pcm = pa_alsa_open_by_template( m->device_strings, dev_id, NULL, &try_ss, &try_map, SND_PCM_STREAM_CAPTURE, - NULL, NULL, 0, NULL, NULL, + &try_period_size, &try_buffer_size, 0, NULL, NULL, TRUE))) { p->supported = FALSE; break; diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h index 76788183..a0d4fcbe 100644 --- a/src/modules/alsa/alsa-mixer.h +++ b/src/modules/alsa/alsa-mixer.h @@ -269,7 +269,7 @@ void pa_alsa_mapping_dump(pa_alsa_mapping *m); void pa_alsa_profile_dump(pa_alsa_profile *p); pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel_map *bonus); -void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss); +void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss, unsigned default_n_fragments, unsigned default_fragment_size_msec); void pa_alsa_profile_set_free(pa_alsa_profile_set *s); void pa_alsa_profile_set_dump(pa_alsa_profile_set *s); diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index 55f6a6e2..6bea33d7 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -329,7 +329,7 @@ int pa__init(pa_module *m) { if (!u->profile_set) goto fail; - pa_alsa_profile_set_probe(u->profile_set, u->device_id, &m->core->default_sample_spec); + pa_alsa_profile_set_probe(u->profile_set, u->device_id, &m->core->default_sample_spec, m->core->default_n_fragments, m->core->default_fragment_size_msec); pa_card_new_data_init(&data); data.driver = __FILE__; -- cgit From d5f43bd4c6a7eecff7bc0c4ff1be9152b33cb1e0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Sep 2009 23:57:49 +0200 Subject: alsa: disable tsched for software devices before we configure the buffer metrics so that we don't accidently set a buffer size that is suitable for tsched where we don't use tsched --- src/modules/alsa/alsa-sink.c | 5 ----- src/modules/alsa/alsa-source.c | 5 ----- src/modules/alsa/alsa-util.c | 5 ++++- 3 files changed, 4 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 7fe77831..76cbe46f 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1795,11 +1795,6 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca u->use_tsched = use_tsched = FALSE; } - if (use_tsched && !pa_alsa_pcm_is_hw(u->pcm_handle)) { - pa_log_info("Device is not a hardware device, disabling timer-based scheduling."); - u->use_tsched = use_tsched = FALSE; - } - if (u->use_mmap) pa_log_info("Successfully enabled mmap() mode."); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index a7f2a018..88f2d8ae 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -1636,11 +1636,6 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p u->use_tsched = use_tsched = FALSE; } - if (use_tsched && !pa_alsa_pcm_is_hw(u->pcm_handle)) { - pa_log_info("Device is not a hardware device, disabling timer-based scheduling."); - u->use_tsched = use_tsched = FALSE; - } - if (u->use_mmap) pa_log_info("Successfully enabled mmap() mode."); diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 91474527..f934285a 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -189,7 +189,7 @@ static int set_buffer_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, } /* Set the hardware parameters of the given ALSA device. Returns the - * selected fragment settings in *period and *period_size */ + * selected fragment settings in *buffer_size and *period_size. If tsched mode can be enabled */ int pa_alsa_set_hw_params( snd_pcm_t *pcm_handle, pa_sample_spec *ss, @@ -247,6 +247,9 @@ int pa_alsa_set_hw_params( if (!_use_mmap) _use_tsched = FALSE; + if (!pa_alsa_pcm_is_hw(pcm_handle)) + _use_tsched = FALSE; + if ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0) goto finish; -- cgit From 807f2a9923572a8d88e10672d0cb5886688bb9ff Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 10 Sep 2009 02:15:12 +0200 Subject: native: send PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED messages only to clients that understand it --- src/pulsecore/protocol-native.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 17aee4b1..d06dd4eb 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -826,24 +826,26 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata)); break; - case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH: { - pa_tagstruct *t; + case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH: s->buffer_attr.tlength = (uint32_t) offset; - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED); - pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(t, s->index); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - pa_tagstruct_put_usec(t, s->configured_sink_latency); - pa_pstream_send_tagstruct(s->connection->pstream, t); + if (s->connection->version >= 15) { + pa_tagstruct *t; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_putu32(t, s->buffer_attr.maxlength); + pa_tagstruct_putu32(t, s->buffer_attr.tlength); + pa_tagstruct_putu32(t, s->buffer_attr.prebuf); + pa_tagstruct_putu32(t, s->buffer_attr.minreq); + pa_tagstruct_put_usec(t, s->configured_sink_latency); + pa_pstream_send_tagstruct(s->connection->pstream, t); + } break; - } } return 0; -- 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') 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') 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 bb36bb4bbe1ee01fb95debdca79d9769851a06da Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 01:21:46 +0200 Subject: alsa: properly convert sample buffer sizes --- src/modules/alsa/alsa-util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index f934285a..56d60dfb 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -275,11 +275,11 @@ int pa_alsa_set_hw_params( } if (_use_tsched && tsched_size > 0) { - _buffer_size = pa_convert_size(tsched_size, ss, &_ss); + _buffer_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * _ss.rate) / ss->rate); _period_size = _buffer_size; } else { - _period_size = pa_convert_size(_period_size, ss, &_ss); - _buffer_size = pa_convert_size(_buffer_size, ss, &_ss); + _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * _ss.rate) / ss->rate); + _buffer_size = (snd_pcm_uframes_t) (((uint64_t) _buffer_size * _ss.rate) / ss->rate); } if (_buffer_size > 0 || _period_size > 0) { -- cgit From 80b44574765738532bc688e5d6fa5b40dc61402b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 01:22:10 +0200 Subject: alsa: properly report suspension error codes --- src/modules/alsa/alsa-sink.c | 23 ++++++++++++++--------- src/modules/alsa/alsa-source.c | 22 +++++++++++++--------- 2 files changed, 27 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 76cbe46f..22e88b4a 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1011,7 +1011,7 @@ fail: u->pcm_handle = NULL; } - return -1; + return -PA_ERR_IO; } /* Called from IO context */ @@ -1035,28 +1035,33 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { - case PA_SINK_SUSPENDED: + case PA_SINK_SUSPENDED: { + int r; + pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state)); - if (suspend(u) < 0) - return -1; + if ((r = suspend(u)) < 0) + return r; break; + } case PA_SINK_IDLE: - case PA_SINK_RUNNING: + case PA_SINK_RUNNING: { + int r; if (u->sink->thread_info.state == PA_SINK_INIT) { if (build_pollfd(u) < 0) - return -1; + return -PA_ERR_IO; } if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { - if (unsuspend(u) < 0) - return -1; + if ((r = unsuspend(u)) < 0) + return r; } break; + } case PA_SINK_UNLINKED: case PA_SINK_INIT: @@ -1084,7 +1089,7 @@ static int sink_set_state_cb(pa_sink *s, pa_sink_state_t new_state) { reserve_done(u); else if (old_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(new_state)) if (reserve_init(u, u->device_name) < 0) - return -1; + return -PA_ERR_BUSY; return 0; } diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 88f2d8ae..fa3ac0aa 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -959,7 +959,7 @@ fail: u->pcm_handle = NULL; } - return -1; + return -PA_ERR_IO; } static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { @@ -982,30 +982,34 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) { - case PA_SOURCE_SUSPENDED: + case PA_SOURCE_SUSPENDED: { + int r; pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state)); - if (suspend(u) < 0) - return -1; + if ((r = suspend(u)) < 0) + return r; break; + } case PA_SOURCE_IDLE: - case PA_SOURCE_RUNNING: + case PA_SOURCE_RUNNING: { + int r; if (u->source->thread_info.state == PA_SOURCE_INIT) { if (build_pollfd(u) < 0) - return -1; + return -PA_ERR_IO; snd_pcm_start(u->pcm_handle); } if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) { - if (unsuspend(u) < 0) - return -1; + if ((r = unsuspend(u)) < 0) + return r; } break; + } case PA_SOURCE_UNLINKED: case PA_SOURCE_INIT: @@ -1033,7 +1037,7 @@ static int source_set_state_cb(pa_source *s, pa_source_state_t new_state) { reserve_done(u); else if (old_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(new_state)) if (reserve_init(u, u->device_name) < 0) - return -1; + return -PA_ERR_BUSY; return 0; } -- 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') 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') 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') 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') 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 From 6fa2445e1131c9c42b685451fd47d79ae2884871 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 02:32:21 +0200 Subject: position-event-sounds: honour window position if set, position both vertically and horizontally --- src/modules/module-position-event-sounds.c | 55 ++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/modules/module-position-event-sounds.c b/src/modules/module-position-event-sounds.c index e191ec33..c3329f88 100644 --- a/src/modules/module-position-event-sounds.c +++ b/src/modules/module-position-event-sounds.c @@ -57,34 +57,67 @@ struct userdata { pa_hook_slot *sink_input_fixate_hook_slot; }; +static int parse_pos(const char *pos, double *f) { + + if (pa_atod(pos, f) < 0) { + pa_log_warn("Failed to parse hpos/vpos property '%s'.", pos); + return -1; + } + + if (*f < 0.0 || *f > 1.0) { + pa_log_warn("Property hpos/vpos out of range %0.2f", *f); + return -1; + } + + return 0; +} + static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_input_new_data *data, struct userdata *u) { - const char *hpos; + const char *hpos, *vpos, *role; double f; char t[PA_CVOLUME_SNPRINT_MAX]; pa_cvolume v; pa_assert(data); - if (!(hpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_HPOS))) + if (!(role = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_ROLE))) return PA_HOOK_OK; - if (pa_atod(hpos, &f) < 0) { - pa_log_warn("Failed to parse "PA_PROP_EVENT_MOUSE_HPOS" property '%s'.", hpos); + if (!pa_streq(role, "event")) return PA_HOOK_OK; - } - if (f < 0.0 || f > 1.0) { - pa_log_warn("Property "PA_PROP_EVENT_MOUSE_HPOS" out of range %0.2f", f); + if (!(hpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_HPOS))) + hpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_HPOS); + + if (!(vpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_VPOS))) + vpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_VPOS); + + if (!hpos && !vpos) return PA_HOOK_OK; + + pa_cvolume_reset(&v, data->sample_spec.channels); + + if (hpos) { + if (parse_pos(hpos, &f) < 0) + return PA_HOOK_OK; + + if (pa_channel_map_can_balance(&data->channel_map)) { + pa_log_debug("Positioning event sound '%s' horizontally at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); + pa_cvolume_set_balance(&v, &data->channel_map, f*2.0-1.0); + } } - pa_log_debug("Positioning event sound '%s' at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); + if (vpos) { + if (parse_pos(vpos, &f) < 0) + return PA_HOOK_OK; - pa_cvolume_reset(&v, data->sample_spec.channels); - pa_cvolume_set_balance(&v, &data->channel_map, f*2.0-1.0); + if (pa_channel_map_can_fade(&data->channel_map)) { + pa_log_debug("Positioning event sound '%s' vertically at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); + pa_cvolume_set_fade(&v, &data->channel_map, f*2.0-1.0); + } + } pa_log_debug("Final volume factor %s.", pa_cvolume_snprint(t, sizeof(t), &v)); - pa_sink_input_new_data_apply_volume_factor(data, &v); return PA_HOOK_OK; -- cgit From a015d56fac4a9af5296afe69825168cd1ce486b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 03:26:25 +0200 Subject: core: add an additional volume factor that is applied after resampling took place --- src/pulsecore/sink-input.c | 59 +++++++++++++++++++++++++++++++++++++++------- src/pulsecore/sink-input.h | 7 ++++-- 2 files changed, 56 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 5f79ab1e..744c47ff 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -92,6 +92,18 @@ void pa_sink_input_new_data_apply_volume_factor(pa_sink_input_new_data *data, co } } +void pa_sink_input_new_data_apply_volume_factor_sink(pa_sink_input_new_data *data, const pa_cvolume *volume_factor) { + pa_assert(data); + pa_assert(volume_factor); + + if (data->volume_factor_sink_is_set) + pa_sw_cvolume_multiply(&data->volume_factor_sink, &data->volume_factor_sink, volume_factor); + else { + data->volume_factor_sink_is_set = TRUE; + data->volume_factor_sink = *volume_factor; + } +} + void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute) { pa_assert(data); @@ -176,7 +188,6 @@ int pa_sink_input_new( pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); } - pa_return_val_if_fail(pa_channel_map_valid(&data->channel_map), -PA_ERR_INVALID); pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID); if (!data->volume_is_set) { @@ -185,15 +196,18 @@ int pa_sink_input_new( data->save_volume = FALSE; } - pa_return_val_if_fail(pa_cvolume_valid(&data->volume), -PA_ERR_INVALID); pa_return_val_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec), -PA_ERR_INVALID); if (!data->volume_factor_is_set) pa_cvolume_reset(&data->volume_factor, data->sample_spec.channels); - pa_return_val_if_fail(pa_cvolume_valid(&data->volume_factor), -PA_ERR_INVALID); pa_return_val_if_fail(pa_cvolume_compatible(&data->volume_factor, &data->sample_spec), -PA_ERR_INVALID); + if (!data->volume_factor_sink_is_set) + pa_cvolume_reset(&data->volume_factor_sink, data->sink->sample_spec.channels); + + pa_return_val_if_fail(pa_cvolume_compatible(&data->volume_factor_sink, &data->sink->sample_spec), -PA_ERR_INVALID); + if (!data->muted_is_set) data->muted = FALSE; @@ -283,6 +297,7 @@ int pa_sink_input_new( i->volume = data->volume; i->volume_factor = data->volume_factor; + i->volume_factor_sink = data->volume_factor_sink; i->real_ratio = i->reference_ratio = data->volume; pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels); pa_cvolume_reset(&i->real_ratio, i->sample_spec.channels); @@ -576,7 +591,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) { /* Called from thread context */ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa_memchunk *chunk, pa_cvolume *volume) { - pa_bool_t do_volume_adj_here; + pa_bool_t do_volume_adj_here, need_volume_factor_sink; pa_bool_t volume_is_norm; size_t block_size_max_sink, block_size_max_sink_input; size_t ilength; @@ -624,6 +639,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); volume_is_norm = pa_cvolume_is_norm(&i->thread_info.soft_volume) && !i->thread_info.muted; + need_volume_factor_sink = !pa_cvolume_is_norm(&i->volume_factor_sink); while (!pa_memblockq_is_readable(i->thread_info.render_memblockq)) { pa_memchunk tchunk; @@ -655,6 +671,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p while (tchunk.length > 0) { pa_memchunk wchunk; + pa_bool_t nvfs = need_volume_factor_sink; wchunk = tchunk; pa_memblock_ref(wchunk.memblock); @@ -666,18 +683,41 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p if (do_volume_adj_here && !volume_is_norm) { pa_memchunk_make_writable(&wchunk, 0); - if (i->thread_info.muted) + if (i->thread_info.muted) { pa_silence_memchunk(&wchunk, &i->thread_info.sample_spec); - else + nvfs = FALSE; + + } else if (!i->thread_info.resampler && nvfs) { + pa_cvolume v; + + /* If we don't need a resampler we can merge the + * post and the pre volume adjustment into one */ + + pa_sw_cvolume_multiply(&v, &i->thread_info.soft_volume, &i->volume_factor_sink); + pa_volume_memchunk(&wchunk, &i->thread_info.sample_spec, &v); + nvfs = FALSE; + + } else pa_volume_memchunk(&wchunk, &i->thread_info.sample_spec, &i->thread_info.soft_volume); } - if (!i->thread_info.resampler) + if (!i->thread_info.resampler) { + + if (nvfs) { + pa_memchunk_make_writable(&wchunk, 0); + pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &i->volume_factor_sink); + } + pa_memblockq_push_align(i->thread_info.render_memblockq, &wchunk); - else { + } else { pa_memchunk rchunk; pa_resampler_run(i->thread_info.resampler, &wchunk, &rchunk); + if (nvfs) { + pa_memchunk_make_writable(&rchunk, 0); + pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &i->volume_factor_sink); + } + /* pa_log_debug("pushing %lu", (unsigned long) rchunk.length); */ if (rchunk.memblock) { @@ -1186,6 +1226,7 @@ int pa_sink_input_start_move(pa_sink_input *i) { pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0); pa_sink_update_status(i->sink); + pa_cvolume_remap(&i->volume_factor_sink, &i->sink->channel_map, &i->channel_map); i->sink = NULL; pa_sink_input_unref(i); @@ -1240,6 +1281,8 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { i->save_sink = save; pa_idxset_put(dest->inputs, pa_sink_input_ref(i), NULL); + pa_cvolume_remap(&i->volume_factor_sink, &i->channel_map, &i->sink->channel_map); + if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED) i->sink->n_corked++; diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 59eabe36..415a801f 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -100,6 +100,8 @@ struct pa_sink_input { pa_cvolume volume_factor; /* An internally used volume factor that can be used by modules to apply effects and suchlike without having that visible to the outside */ pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through. Usually calculated as real_ratio * volume_factor */ + pa_cvolume volume_factor_sink; /* A second volume factor in format of the sink this stream is connected to */ + pa_bool_t muted:1; /* if TRUE then the source we are connected to and/or the volume @@ -273,13 +275,13 @@ typedef struct pa_sink_input_new_data { pa_sample_spec sample_spec; pa_channel_map channel_map; - pa_cvolume volume, volume_factor; + pa_cvolume volume, volume_factor, volume_factor_sink; pa_bool_t muted:1; pa_bool_t sample_spec_is_set:1; pa_bool_t channel_map_is_set:1; - pa_bool_t volume_is_set:1, volume_factor_is_set:1; + pa_bool_t volume_is_set:1, volume_factor_is_set:1, volume_factor_sink_is_set:1; pa_bool_t muted_is_set:1; pa_bool_t volume_is_absolute:1; @@ -292,6 +294,7 @@ void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map); void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume); void pa_sink_input_new_data_apply_volume_factor(pa_sink_input_new_data *data, const pa_cvolume *volume_factor); +void pa_sink_input_new_data_apply_volume_factor_sink(pa_sink_input_new_data *data, const pa_cvolume *volume_factor); void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute); void pa_sink_input_new_data_done(pa_sink_input_new_data *data); -- cgit From 180ef1eebdfbdf0220af1fb5e4bf43e348207cde Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Sep 2009 03:27:38 +0200 Subject: position-event-sounds: apply volume factor after, not before resampling --- src/modules/module-position-event-sounds.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/modules/module-position-event-sounds.c b/src/modules/module-position-event-sounds.c index c3329f88..fa8f73d8 100644 --- a/src/modules/module-position-event-sounds.c +++ b/src/modules/module-position-event-sounds.c @@ -95,15 +95,15 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_i if (!hpos && !vpos) return PA_HOOK_OK; - pa_cvolume_reset(&v, data->sample_spec.channels); + pa_cvolume_reset(&v, data->sink->sample_spec.channels); if (hpos) { if (parse_pos(hpos, &f) < 0) return PA_HOOK_OK; - if (pa_channel_map_can_balance(&data->channel_map)) { + if (pa_channel_map_can_balance(&data->sink->channel_map)) { pa_log_debug("Positioning event sound '%s' horizontally at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); - pa_cvolume_set_balance(&v, &data->channel_map, f*2.0-1.0); + pa_cvolume_set_balance(&v, &data->sink->channel_map, f*2.0-1.0); } } @@ -111,14 +111,14 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_i if (parse_pos(vpos, &f) < 0) return PA_HOOK_OK; - if (pa_channel_map_can_fade(&data->channel_map)) { + if (pa_channel_map_can_fade(&data->sink->channel_map)) { pa_log_debug("Positioning event sound '%s' vertically at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); - pa_cvolume_set_fade(&v, &data->channel_map, f*2.0-1.0); + pa_cvolume_set_fade(&v, &data->sink->channel_map, f*2.0-1.0); } } pa_log_debug("Final volume factor %s.", pa_cvolume_snprint(t, sizeof(t), &v)); - pa_sink_input_new_data_apply_volume_factor(data, &v); + pa_sink_input_new_data_apply_volume_factor_sink(data, &v); return PA_HOOK_OK; } -- cgit