[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.16-test2-21-g88d5749
Lennart Poettering
gitmailer-noreply at 0pointer.de
Thu Jul 23 06:19:32 PDT 2009
This is an automated email from the git hooks/post-receive script. It was
generated because of a push to the "PulseAudio Sound Server" repository.
The master branch has been updated
from 3d6278bc31aa7053f1228b3d874ba36f50a8c2d5 (commit)
- Log -----------------------------------------------------------------
88d5749 Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio
0225ef6 memtrap: clarify that we are not interested in the return value of write()
23039af client: allow zero-copy writing to the stream
a2b207e daemon: before exec'ing ourselves, make sure nobody plays games with /proc/self/exe
-----------------------------------------------------------------------
Summary of changes:
src/daemon/main.c | 30 ++++++++++
src/pulse/internal.h | 5 ++
src/pulse/stream.c | 145 +++++++++++++++++++++++++++++++++++------------
src/pulse/stream.h | 70 ++++++++++++++++++++--
src/pulsecore/memtrap.c | 2 +-
src/tests/mix-test.c | 6 +-
6 files changed, 211 insertions(+), 47 deletions(-)
-----------------------------------------------------------------------
commit a2b207e38ac35ffc048351f76d83f7f9db37bb6c
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Jul 20 15:47:57 2009 +0100
daemon: before exec'ing ourselves, make sure nobody plays games with /proc/self/exe
diff --git a/src/daemon/main.c b/src/daemon/main.c
index eb378d2..0743967 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 c7a30d6..3f65cba 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;
}
commit 23039af8427140bafa92dce3021c1f2a14bcfbad
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Jul 20 15:49:33 2009 +0100
client: allow zero-copy writing to the stream
diff --git a/src/pulse/internal.h b/src/pulse/internal.h
index ec2da85..e069c9e 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 4055632..5baf5c2 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 49c132a..fecc587 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
commit 0225ef68f2876bebd14977882db313fd7f3f6d64
Author: Lennart Poettering <lennart at poettering.net>
Date: Mon Jul 20 15:50:02 2009 +0100
memtrap: clarify that we are not interested in the return value of write()
diff --git a/src/pulsecore/memtrap.c b/src/pulsecore/memtrap.c
index 7d91745..c647e50 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) {
commit 88d5749f6ae8d391963a12a6221f006de2947e50
Merge: 0225ef6 3d6278b
Author: Lennart Poettering <lennart at poettering.net>
Date: Thu Jul 23 15:18:06 2009 +0200
Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio
Conflicts:
src/daemon/main.c
--
hooks/post-receive
PulseAudio Sound Server
More information about the pulseaudio-commits
mailing list