From 59376b039e10b1ceec5f4955361df2ba001abff3 Mon Sep 17 00:00:00 2001 From: Colin Guthrie Date: Sun, 28 Jun 2009 11:56:36 +0100 Subject: introspect: Fix a bug in sink/source info protocol handling related to ports. Previously the active_profile was extracted from the tagstruct regardless of the protocol version which caused errors while speaking to older version servers. --- src/pulse/introspect.c | 124 +++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 60 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index ab67f596..3414f7de 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -201,42 +201,44 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u goto finish; } - if (i.n_ports > 0) { - i.ports = pa_xnew(pa_sink_port_info*, i.n_ports+1); - i.ports[0] = pa_xnew(pa_sink_port_info, i.n_ports); - - for (j = 0; j < i.n_ports; j++) { - if (pa_tagstruct_gets(t, &i.ports[0][j].name) < 0 || - pa_tagstruct_gets(t, &i.ports[0][j].description) < 0 || - pa_tagstruct_getu32(t, &i.ports[0][j].priority) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - pa_xfree(i.ports); - pa_xfree(i.ports[0]); - pa_proplist_free(i.proplist); - goto finish; + if (o->context->version >= 16) { + if (i.n_ports > 0) { + i.ports = pa_xnew(pa_sink_port_info*, i.n_ports+1); + i.ports[0] = pa_xnew(pa_sink_port_info, i.n_ports); + + for (j = 0; j < i.n_ports; j++) { + if (pa_tagstruct_gets(t, &i.ports[0][j].name) < 0 || + pa_tagstruct_gets(t, &i.ports[0][j].description) < 0 || + pa_tagstruct_getu32(t, &i.ports[0][j].priority) < 0) { + + pa_context_fail(o->context, PA_ERR_PROTOCOL); + pa_xfree(i.ports); + pa_xfree(i.ports[0]); + pa_proplist_free(i.proplist); + goto finish; + } + + i.ports[j] = &i.ports[0][j]; } - i.ports[j] = &i.ports[0][j]; + i.ports[j] = NULL; } - i.ports[j] = NULL; - } - - if (pa_tagstruct_gets(t, &ap) < 0) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - pa_xfree(i.ports[0]); - pa_xfree(i.ports); - pa_proplist_free(i.proplist); - goto finish; - } + if (pa_tagstruct_gets(t, &ap) < 0) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + pa_xfree(i.ports[0]); + pa_xfree(i.ports); + pa_proplist_free(i.proplist); + goto finish; + } - if (ap) { - for (j = 0; j < i.n_ports; j++) - if (pa_streq(i.ports[j]->name, ap)) { - i.active_port = i.ports[j]; - break; - } + if (ap) { + for (j = 0; j < i.n_ports; j++) + if (pa_streq(i.ports[j]->name, ap)) { + i.active_port = i.ports[j]; + break; + } + } } i.mute = (int) mute; @@ -428,42 +430,44 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, goto finish; } - if (i.n_ports > 0) { - i.ports = pa_xnew(pa_source_port_info*, i.n_ports+1); - i.ports[0] = pa_xnew(pa_source_port_info, i.n_ports); + if (o->context->version >= 16) { + if (i.n_ports > 0) { + i.ports = pa_xnew(pa_source_port_info*, i.n_ports+1); + i.ports[0] = pa_xnew(pa_source_port_info, i.n_ports); - for (j = 0; j < i.n_ports; j++) { - if (pa_tagstruct_gets(t, &i.ports[0][j].name) < 0 || - pa_tagstruct_gets(t, &i.ports[0][j].description) < 0 || - pa_tagstruct_getu32(t, &i.ports[0][j].priority) < 0) { + for (j = 0; j < i.n_ports; j++) { + if (pa_tagstruct_gets(t, &i.ports[0][j].name) < 0 || + pa_tagstruct_gets(t, &i.ports[0][j].description) < 0 || + pa_tagstruct_getu32(t, &i.ports[0][j].priority) < 0) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - pa_xfree(i.ports[0]); - pa_xfree(i.ports); - pa_proplist_free(i.proplist); - goto finish; + pa_context_fail(o->context, PA_ERR_PROTOCOL); + pa_xfree(i.ports[0]); + pa_xfree(i.ports); + pa_proplist_free(i.proplist); + goto finish; + } + + i.ports[j] = &i.ports[0][j]; } - i.ports[j] = &i.ports[0][j]; + i.ports[j] = NULL; } - i.ports[j] = NULL; - } - - if (pa_tagstruct_gets(t, &ap) < 0) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - pa_xfree(i.ports[0]); - pa_xfree(i.ports); - pa_proplist_free(i.proplist); - goto finish; - } + if (pa_tagstruct_gets(t, &ap) < 0) { + pa_context_fail(o->context, PA_ERR_PROTOCOL); + pa_xfree(i.ports[0]); + pa_xfree(i.ports); + pa_proplist_free(i.proplist); + goto finish; + } - if (ap) { - for (j = 0; j < i.n_ports; j++) - if (pa_streq(i.ports[j]->name, ap)) { - i.active_port = i.ports[j]; - break; - } + if (ap) { + for (j = 0; j < i.n_ports; j++) + if (pa_streq(i.ports[j]->name, ap)) { + i.active_port = i.ports[j]; + break; + } + } } i.mute = (int) mute; -- cgit From b174a511207d67896800ae82a5797dcda1ec2780 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Jul 2009 14:26:07 +0200 Subject: libpulse: minor cleanups --- src/pulse/context.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/context.c b/src/pulse/context.c index 505e758a..4ded5565 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -761,22 +761,33 @@ static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wr pa_assert(conn); dbus_error_init(&error); + if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, c->use_rtclock, type, &error)) || dbus_error_is_set(&error)) { pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message); - goto finish; + goto fail; } if (!dbus_connection_add_filter(pa_dbus_wrap_connection_get(*conn), filter_cb, c, NULL)) { pa_log_warn("Failed to add filter function"); - goto finish; + goto fail; } if (pa_dbus_add_matches( pa_dbus_wrap_connection_get(*conn), &error, - "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged',arg0='org.pulseaudio.Server',arg1=''", NULL) < 0) + "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged',arg0='org.pulseaudio.Server',arg1=''", NULL) < 0) { + pa_log_warn("Unable to track org.pulseaudio.Server: %s: %s", error.name, error.message); + goto fail; + } + + return; + +fail: + if (*conn) { + pa_dbus_wrap_connection_free(*conn); + *conn = NULL; + } - finish: dbus_error_free(&error); } #endif @@ -861,7 +872,7 @@ static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userd c->client = NULL; if (!io) { - /* Try the item in the list */ + /* Try the next item in the list */ if (saved_errno == ECONNREFUSED || saved_errno == ETIMEDOUT || saved_errno == EHOSTUNREACH) { @@ -897,7 +908,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo /* FIXME: We probably should check if this is actually the NameOwnerChanged we were looking for */ is_session = c->session_bus && bus == pa_dbus_wrap_connection_get(c->session_bus); - pa_log_debug("Rock!! PulseAudio is back on %s bus", is_session ? "session" : "system"); + pa_log_debug("Rock!! PulseAudio might be back on %s bus", is_session ? "session" : "system"); if (is_session) /* The user instance via PF_LOCAL */ @@ -937,7 +948,7 @@ int pa_context_connect( pa_context_ref(c); - c->no_fail = flags & PA_CONTEXT_NOFAIL; + c->no_fail = !!(flags & PA_CONTEXT_NOFAIL); c->server_specified = !!server; pa_assert(!c->server_list); @@ -954,10 +965,7 @@ int pa_context_connect( /* Follow the X display */ if ((d = getenv("DISPLAY"))) { - char *e; - d = pa_xstrdup(d); - if ((e = strchr(d, ':'))) - *e = 0; + d = pa_xstrndup(d, strcspn(d, ":")); if (*d) c->server_list = pa_strlist_prepend(c->server_list, d); -- cgit From 61fefd67dab01011d97a06b7e3dd51101d5f5749 Mon Sep 17 00:00:00 2001 From: Colin Guthrie Date: Sun, 12 Jul 2009 20:43:21 +0100 Subject: introspect: Fix two memory issues in port handling code. First one is a simple typo on an error condition that would have likely caused issues if it ever cropped up. Second issue is that port information is never actually freed if everything works fine. --- src/pulse/introspect.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index 3414f7de..27a587cb 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -212,8 +212,8 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u pa_tagstruct_getu32(t, &i.ports[0][j].priority) < 0) { pa_context_fail(o->context, PA_ERR_PROTOCOL); - pa_xfree(i.ports); pa_xfree(i.ports[0]); + pa_xfree(i.ports); pa_proplist_free(i.proplist); goto finish; } @@ -250,6 +250,10 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, u cb(o->context, &i, 0, o->userdata); } + if (i.ports) { + pa_xfree(i.ports[0]); + pa_xfree(i.ports); + } pa_proplist_free(i.proplist); } } @@ -479,6 +483,10 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, cb(o->context, &i, 0, o->userdata); } + if (i.ports) { + pa_xfree(i.ports[0]); + pa_xfree(i.ports); + } pa_proplist_free(i.proplist); } } -- 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/pulse') diff --git a/src/pulse/internal.h b/src/pulse/internal.h index ec2da85b..e069c9e9 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -151,6 +151,11 @@ struct pa_stream { uint32_t device_index; char *device_name; + /* playback */ + pa_memblock *write_memblock; + void *write_data; + + /* recording */ pa_memchunk peek_memchunk; void *peek_data; pa_memblockq *record_memblockq; diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 40556329..5baf5c2c 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -144,12 +144,13 @@ pa_stream *pa_stream_new_with_proplist( s->suspended = FALSE; s->corked = FALSE; + s->write_memblock = NULL; + s->write_data = NULL; + pa_memchunk_reset(&s->peek_memchunk); s->peek_data = NULL; - s->record_memblockq = NULL; - memset(&s->timing_info, 0, sizeof(s->timing_info)); s->timing_info_valid = FALSE; @@ -221,6 +222,11 @@ static void stream_free(pa_stream *s) { stream_unlink(s); + if (s->write_memblock) { + pa_memblock_release(s->write_memblock); + pa_memblock_unref(s->write_data); + } + if (s->peek_memchunk.memblock) { if (s->peek_data) pa_memblock_release(s->peek_memchunk.memblock); @@ -1187,20 +1193,60 @@ int pa_stream_connect_record( return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL); } +int pa_stream_begin_write( + pa_stream *s, + void **data, + size_t *nbytes) { + + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, data, PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, nbytes && *nbytes != 0, PA_ERR_INVALID); + + if (!s->write_memblock) { + s->write_memblock = pa_memblock_new(s->context->mempool, *nbytes); + s->write_data = pa_memblock_acquire(s->write_memblock); + } + + *data = s->write_data; + *nbytes = pa_memblock_get_length(s->write_memblock); + + return 0; +} + +int pa_stream_cancel_write( + pa_stream *s) { + + pa_assert(s); + pa_assert(PA_REFCNT_VALUE(s) >= 1); + + PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); + PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY(s->context, s->write_memblock, PA_ERR_BADSTATE); + + pa_assert(s->write_data); + + pa_memblock_release(s->write_memblock); + pa_memblock_unref(s->write_memblock); + s->write_memblock = NULL; + s->write_data = NULL; + + return 0; +} + int pa_stream_write( pa_stream *s, const void *data, size_t length, - void (*free_cb)(void *p), + pa_free_cb_t free_cb, int64_t offset, pa_seek_mode_t seek) { - pa_memchunk chunk; - pa_seek_mode_t t_seek; - int64_t t_offset; - size_t t_length; - const void *t_data; - pa_assert(s); pa_assert(PA_REFCNT_VALUE(s) >= 1); pa_assert(data); @@ -1210,46 +1256,71 @@ int pa_stream_write( PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); PA_CHECK_VALIDITY(s->context, seek <= PA_SEEK_RELATIVE_END, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || (seek == PA_SEEK_RELATIVE && offset == 0), PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, + !s->write_memblock || + ((data >= s->write_data) && + ((const char*) data + length <= (const char*) s->write_data + pa_memblock_get_length(s->write_memblock))), + PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, !free_cb || !s->write_memblock, PA_ERR_INVALID); - if (length <= 0) - return 0; + if (s->write_memblock) { + pa_memchunk chunk; - t_seek = seek; - t_offset = offset; - t_length = length; - t_data = data; + /* pa_stream_write_begin() was called before */ - while (t_length > 0) { + pa_memblock_release(s->write_memblock); - chunk.index = 0; + chunk.memblock = s->write_memblock; + chunk.index = (const char *) data - (const char *) s->write_data; + chunk.length = length; - if (free_cb && !pa_pstream_get_shm(s->context->pstream)) { - chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) t_data, t_length, free_cb, 1); - chunk.length = t_length; - } else { - void *d; + s->write_memblock = NULL; + s->write_data = NULL; - chunk.length = PA_MIN(t_length, pa_mempool_block_size_max(s->context->mempool)); - chunk.memblock = pa_memblock_new(s->context->mempool, chunk.length); + pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk); + pa_memblock_unref(chunk.memblock); - d = pa_memblock_acquire(chunk.memblock); - memcpy(d, t_data, chunk.length); - pa_memblock_release(chunk.memblock); - } + } else { + pa_seek_mode_t t_seek = seek; + int64_t t_offset = offset; + size_t t_length = length; + const void *t_data = data; - pa_pstream_send_memblock(s->context->pstream, s->channel, t_offset, t_seek, &chunk); + /* pa_stream_write_begin() was not called before */ - t_offset = 0; - t_seek = PA_SEEK_RELATIVE; + while (t_length > 0) { + pa_memchunk chunk; - t_data = (const uint8_t*) t_data + chunk.length; - t_length -= chunk.length; + chunk.index = 0; - pa_memblock_unref(chunk.memblock); - } + if (free_cb && !pa_pstream_get_shm(s->context->pstream)) { + chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) t_data, t_length, free_cb, 1); + chunk.length = t_length; + } else { + void *d; + + chunk.length = PA_MIN(t_length, pa_mempool_block_size_max(s->context->mempool)); + chunk.memblock = pa_memblock_new(s->context->mempool, chunk.length); + + d = pa_memblock_acquire(chunk.memblock); + memcpy(d, t_data, chunk.length); + pa_memblock_release(chunk.memblock); + } - if (free_cb && pa_pstream_get_shm(s->context->pstream)) - free_cb((void*) data); + pa_pstream_send_memblock(s->context->pstream, s->channel, t_offset, t_seek, &chunk); + + t_offset = 0; + t_seek = PA_SEEK_RELATIVE; + + t_data = (const uint8_t*) t_data + chunk.length; + t_length -= chunk.length; + + pa_memblock_unref(chunk.memblock); + } + + if (free_cb && pa_pstream_get_shm(s->context->pstream)) + free_cb((void*) data); + } /* This is obviously wrong since we ignore the seeking index . But * that's OK, the server side applies the same error */ diff --git a/src/pulse/stream.h b/src/pulse/stream.h index 49c132a2..fecc5870 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -418,15 +418,71 @@ int pa_stream_connect_record( /** Disconnect a stream from a source/sink */ int pa_stream_disconnect(pa_stream *s); -/** Write some data to the server (for playback sinks), if free_cb is - * non-NULL this routine is called when all data has been written out - * and an internal reference to the specified data is kept, the data - * is not copied. If NULL, the data is copied into an internal - * buffer. The client my freely seek around in the output buffer. For +/** Prepare writing data to the server (for playback streams). This + * function may be used to optimize the number of memory copies when + * doing playback ("zero-copy"). It is recommended to call this + * function before each call to pa_stream_write(). Pass in the address + * to a pointer and an address of the number of bytes you want to + * write. On return the two values will contain a pointer where you + * can place the data to write and the maximum number of bytes you can + * write. On return *nbytes can be larger or have the same value as + * you passed in. You need to be able to handle both cases. Accessing + * memory beyond the returned *nbytes value is invalid. Acessing the + * memory returned after the following pa_stream_write() or + * pa_stream_cancel_write() is invalid. On invocation only *nbytes + * needs to be initialized, on return both *data and *nbytes will be + * valid. If you place (size_t) -1 in *nbytes on invocation the memory + * size will be chosen automatically (which is recommended to + * do). After placing your data in the memory area returned call + * pa_stream_write() with data set to an address within this memory + * area and an nbytes value that is smaller or equal to what was + * returned by this function to actually execute the write. An + * invocation of pa_stream_write() should follow "quickly" on + * pa_stream_begin_write(). It is not recommended letting an unbounded + * amount of time pass after calling pa_stream_begin_write() and + * before calling pa_stream_write(). If you want to cancel a + * previously called pa_stream_begin_write() without calling + * pa_stream_write() use pa_stream_cancel_write() instead. Calling + * pa_stream_begin_write() twice without calling pa_stream_write() or + * pa_stream_cancel_write() in between will return exactly the same + * pointer/nbytes values.\since 0.9.16 */ +int pa_stream_begin_write( + pa_stream *p, + void **data, + size_t *nbytes); + +/** Reverses the effect of pa_stream_begin_write() dropping all data + * that has already been placed in the memory area returned by + * pa_stream_begin_write(). Only valid to call if + * pa_stream_begin_write() was called before and neither + * pa_stream_cancel_write() nor pa_stream_write() have been called + * yet. Accessing the memory previously returned by + * pa_stream_begin_write() after this call is invalid. Any further + * explicit freeing of the memory area is not necessary. \since + * 0.9.16 */ +int pa_stream_cancel_write( + pa_stream *p); + +/** Write some data to the server (for playback streams), if free_cb + * is non-NULL this routine is called when all data has been written + * out and an internal reference to the specified data is kept, the + * data is not copied. If NULL, the data is copied into an internal + * buffer. The client may freely seek around in the output buffer. For * most applications passing 0 and PA_SEEK_RELATIVE as arguments for * offset and seek should be useful. Afte ther write call succeeded * the write index will be a the position after where this chunk of - * data has been written to. */ + * data has been written to. + * + * As an optimization for avoiding needless memory copies you may call + * pa_stream_begin_write() before this call and then place your audio + * data directly in the memory area returned by that call. Then, pass + * a pointer to that memory area to pa_stream_write(). After the + * invocation of pa_stream_write() the memory area may no longer be + * accessed. Any further explicit freeing of the memory area is not + * necessary. It is OK to write the memory area returned by + * pa_stream_begin_write() only partially with this call, skipping + * bytes both at the end and at the beginning of the reserved memory + * area.*/ int pa_stream_write( pa_stream *p /**< The stream to use */, const void *data /**< The data to write */, @@ -435,7 +491,7 @@ int pa_stream_write( int64_t offset, /**< Offset for seeking, must be 0 for upload streams */ pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); -/** Read the next fragment from the buffer (for recording). +/** Read the next fragment from the buffer (for recording streams). * data will point to the actual data and length will contain the size * of the data in bytes (which can be less than a complete framgnet). * Use pa_stream_drop() to actually remove the data from the -- cgit From f6763917ee757845e2c52e36975d948bc93d8b6e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 18:22:13 +0200 Subject: autospawn: refuse autospawning if process disabled waitpid() --- src/pulse/context.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/context.c b/src/pulse/context.c index 4ded5565..ab1c1638 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -668,11 +668,24 @@ static pa_strlist *prepend_per_user(pa_strlist *l) { static int context_autospawn(pa_context *c) { pid_t pid; int status, r; - - pa_log_debug("Trying to autospawn..."); + struct sigaction sa; pa_context_ref(c); + if (sigaction(SIGCHLD, NULL, &sa) < 0) { + pa_log_debug("sigaction() failed: %s", pa_cstrerror(errno)); + pa_context_fail(c, PA_ERR_INTERNAL); + goto fail; + } + + if ((sa.sa_flags & SA_NOCLDWAIT) || sa.sa_handler == SIG_IGN) { + pa_log_debug("Process disabled waitpid(), cannot autospawn."); + pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); + goto fail; + } + + pa_log_debug("Trying to autospawn..."); + if (c->spawn_api.prefork) c->spawn_api.prefork(); -- cgit From 5efb07281d5be1cddaed5b0610325fedd7f599ec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 20:13:52 +0200 Subject: alsa: throw timing data away after device resume --- src/pulse/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 5baf5c2c..a22816ae 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -827,7 +827,7 @@ static void create_stream_complete(pa_stream *s) { if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC; pa_assert(!s->auto_timing_update_event); - s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s); + s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s); request_auto_timing_update(s, TRUE); } -- cgit From e7ca058427e795b9c2b436c4a819e8d8354ee9de Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 20:20:34 +0200 Subject: client: make volume struct const --- src/pulse/stream.c | 2 +- src/pulse/stream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.c b/src/pulse/stream.c index a22816ae..bbd01499 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -1172,7 +1172,7 @@ int pa_stream_connect_playback( const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, - pa_cvolume *volume, + const pa_cvolume *volume, pa_stream *sync_stream) { pa_assert(s); diff --git a/src/pulse/stream.h b/src/pulse/stream.h index fecc5870..eeffc0c9 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -405,7 +405,7 @@ int pa_stream_connect_playback( const char *dev /**< Name of the sink to connect to, or NULL for default */ , const pa_buffer_attr *attr /**< Buffering attributes, or NULL for default */, pa_stream_flags_t flags /**< Additional flags, or 0 for default */, - pa_cvolume *volume /**< Initial volume, or NULL for default */, + const pa_cvolume *volume /**< Initial volume, or NULL for default */, pa_stream *sync_stream /**< Synchronize this stream with the specified one, or NULL for a standalone stream*/); /** Connect the stream to a source */ -- cgit From 211d0f3dcb23c6d63dd6a212826a872ce972e4ee Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 20:21:30 +0200 Subject: client: limit block size for zero-copy operations to mempool block size --- src/pulse/stream.c | 11 +++++++++++ src/pulse/stream.h | 13 +++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.c b/src/pulse/stream.c index bbd01499..72d49e11 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -1207,6 +1207,17 @@ int pa_stream_begin_write( PA_CHECK_VALIDITY(s->context, data, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, nbytes && *nbytes != 0, PA_ERR_INVALID); + if (*nbytes != (size_t) -1) { + size_t m, fs; + + m = pa_mempool_block_size_max(s->context->mempool); + fs = pa_frame_size(&s->sample_spec); + + m = (m / fs) * fs; + if (*nbytes > m) + *nbytes = m; + } + if (!s->write_memblock) { s->write_memblock = pa_memblock_new(s->context->mempool, *nbytes); s->write_data = pa_memblock_acquire(s->write_memblock); diff --git a/src/pulse/stream.h b/src/pulse/stream.h index eeffc0c9..cb8b74dc 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -425,7 +425,7 @@ int pa_stream_disconnect(pa_stream *s); * to a pointer and an address of the number of bytes you want to * write. On return the two values will contain a pointer where you * can place the data to write and the maximum number of bytes you can - * write. On return *nbytes can be larger or have the same value as + * write. On return *nbytes can be smaller or have the same value as * you passed in. You need to be able to handle both cases. Accessing * memory beyond the returned *nbytes value is invalid. Acessing the * memory returned after the following pa_stream_write() or @@ -442,7 +442,7 @@ int pa_stream_disconnect(pa_stream *s); * amount of time pass after calling pa_stream_begin_write() and * before calling pa_stream_write(). If you want to cancel a * previously called pa_stream_begin_write() without calling - * pa_stream_write() use pa_stream_cancel_write() instead. Calling + * pa_stream_write() use pa_stream_cancel_write(). Calling * pa_stream_begin_write() twice without calling pa_stream_write() or * pa_stream_cancel_write() in between will return exactly the same * pointer/nbytes values.\since 0.9.16 */ @@ -492,10 +492,11 @@ int pa_stream_write( pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); /** Read the next fragment from the buffer (for recording streams). - * data will point to the actual data and length will contain the size - * of the data in bytes (which can be less than a complete framgnet). - * Use pa_stream_drop() to actually remove the data from the - * buffer. If no data is available will return a NULL pointer */ + * data will point to the actual data and nbytes will contain the size + * of the data in bytes (which can be less or more than a complete + * fragment). Use pa_stream_drop() to actually remove the data from + * the buffer. If no data is available this will return a NULL + * pointer */ int pa_stream_peek( pa_stream *p /**< The stream to use */, const void **data /**< Pointer to pointer that will point to data */, -- cgit From 6ce7d208f066f02ee837686e81faa1463a5e2945 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 25 Jul 2009 01:29:36 +0200 Subject: client: if a child we created was already reaped, assume that it was successful --- src/pulse/context.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/context.c b/src/pulse/context.c index ab1c1638..7ba33249 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -743,9 +743,16 @@ static int context_autospawn(pa_context *c) { } while (r < 0 && errno == EINTR); if (r < 0) { - pa_log(_("waitpid(): %s"), pa_cstrerror(errno)); - pa_context_fail(c, PA_ERR_INTERNAL); - goto fail; + + if (errno != ESRCH) { + pa_log(_("waitpid(): %s"), pa_cstrerror(errno)); + pa_context_fail(c, PA_ERR_INTERNAL); + goto fail; + } + + /* hmm, something already reaped our child, so we assume + * startup worked, even if we cannot know */ + } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); goto fail; -- cgit From 8343360da1d8d93e8e3818ab91e7f764a1c8c99e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 25 Jul 2009 03:11:09 +0200 Subject: client: minor modernizations --- src/pulse/context.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/context.c b/src/pulse/context.c index 7ba33249..7c3717fa 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -701,9 +701,8 @@ static int context_autospawn(pa_context *c) { /* Child */ const char *state = NULL; -#define MAX_ARGS 64 - const char * argv[MAX_ARGS+1]; - int n; + const char * argv[32]; + unsigned n = 0; if (c->spawn_api.atfork) c->spawn_api.atfork(); @@ -712,12 +711,10 @@ static int context_autospawn(pa_context *c) { /* Setup argv */ - n = 0; - argv[n++] = c->conf->daemon_binary; argv[n++] = "--start"; - while (n < MAX_ARGS) { + while (n < PA_ELEMENTSOF(argv)-1) { char *a; if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) @@ -727,10 +724,10 @@ static int context_autospawn(pa_context *c) { } argv[n++] = NULL; + pa_assert(n <= PA_ELEMENTSOF(argv)); execv(argv[0], (char * const *) argv); _exit(1); -#undef MAX_ARGS } /* Parent */ -- cgit From 4f5e2b745ea357e2b5c815ff33a556505a7d1f18 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Jul 2009 23:46:25 +0200 Subject: threaded-mainloop: loop around pa_cond_wait() invocation in pa_threaded_mainloop_signal() --- src/pulse/thread-mainloop.c | 13 ++++++++++--- src/pulse/thread-mainloop.h | 4 +++- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c index 6916d867..a2b98ce1 100644 --- a/src/pulse/thread-mainloop.c +++ b/src/pulse/thread-mainloop.c @@ -51,7 +51,7 @@ struct pa_threaded_mainloop { pa_mainloop *real_mainloop; - int n_waiting; + int n_waiting, n_waiting_for_accept; pa_thread* thread; pa_mutex* mutex; @@ -190,8 +190,12 @@ void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { pa_cond_signal(m->cond, 1); - if (wait_for_accept && m->n_waiting > 0) - pa_cond_wait(m->accept_cond, m->mutex); + if (wait_for_accept) { + m->n_waiting_for_accept ++; + + while (m->n_waiting_for_accept > 0) + pa_cond_wait(m->accept_cond, m->mutex); + } } void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { @@ -214,6 +218,9 @@ void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { /* Make sure that this function is not called from the helper thread */ pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m)); + pa_assert(m->n_waiting_for_accept > 0); + m->n_waiting_for_accept --; + pa_cond_signal(m->accept_cond, 0); } diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h index 8eddce4c..41159d98 100644 --- a/src/pulse/thread-mainloop.h +++ b/src/pulse/thread-mainloop.h @@ -274,7 +274,9 @@ void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m); * inside the event loop thread. Prior to this call the event loop * object needs to be locked using pa_threaded_mainloop_lock(). While * waiting the lock will be released, immediately before returning it - * will be acquired again. */ + * will be acquired again. This function may spuriously wake up even + * without _signal() being called. You need to make sure to handle + * that! */ void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); /** Signal all threads waiting for a signalling event in -- cgit From 2952f28c06b254f358ec9b3354dfc05c17a7b871 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 31 Jul 2009 23:07:07 +0200 Subject: client: fix documentation for threaded mainloop Closes #553 --- src/pulse/thread-mainloop.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/thread-mainloop.h b/src/pulse/thread-mainloop.h index 41159d98..e847070d 100644 --- a/src/pulse/thread-mainloop.h +++ b/src/pulse/thread-mainloop.h @@ -137,15 +137,19 @@ PA_C_DECL_BEGIN * The main function, my_drain_stream_func(), will wait for the callback to * be called using pa_threaded_mainloop_wait(). * - * If your application is multi-threaded, then this waiting must be done - * inside a while loop. The reason for this is that multiple threads might be - * using pa_threaded_mainloop_wait() at the same time. Each thread must - * therefore verify that it was its callback that was invoked. + * If your application is multi-threaded, then this waiting must be + * done inside a while loop. The reason for this is that multiple + * threads might be using pa_threaded_mainloop_wait() at the same + * time. Each thread must therefore verify that it was its callback + * that was invoked. Also the underlying OS synchronization primitives + * are usually not free of spurious wake-ups, so a + * pa_threaded_mainloop_wait() must be called within a loop even if + * you have only one thread waiting. * * The callback, my_drain_callback(), indicates to the main function that it * has been called using pa_threaded_mainloop_signal(). * - * As you can see, both pa_threaded_mainloop_wait() may only be called with + * As you can see, pa_threaded_mainloop_wait() may only be called with * the lock held. The same thing is true for pa_threaded_mainloop_signal(), * but as the lock is held before the callback is invoked, you do not have to * deal with that. -- cgit From 478f3254b36f9f4281d58bb048a002096b8d0bb9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 31 Jul 2009 23:09:16 +0200 Subject: client: documented that pa_stream_drain() may only have a single operation active at a time Closes #552. --- src/pulse/stream.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.h b/src/pulse/stream.h index cb8b74dc..8a08421f 100644 --- a/src/pulse/stream.h +++ b/src/pulse/stream.h @@ -512,7 +512,9 @@ size_t pa_stream_writable_size(pa_stream *p); /** Return the number of bytes that may be read using pa_stream_peek()*/ size_t pa_stream_readable_size(pa_stream *p); -/** Drain a playback stream. Use this for notification when the buffer is empty */ +/** Drain a playback stream. Use this for notification when the buffer + * is empty. Please note that only one drain operation per stream may + * be issued at a time. */ pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); /** Request a timing info structure update for a stream. Use -- cgit From 3e2ab9b22ed95bab3c69b1ea32cf2b8449fe3427 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 3 Aug 2009 23:07:59 +0200 Subject: client: extend documentation on pa_operation_cancel() a bit --- src/pulse/operation.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/operation.h b/src/pulse/operation.h index 7b0dabdd..b6b5691d 100644 --- a/src/pulse/operation.h +++ b/src/pulse/operation.h @@ -40,7 +40,11 @@ pa_operation *pa_operation_ref(pa_operation *o); /** Decrease the reference count by one */ void pa_operation_unref(pa_operation *o); -/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ +/** Cancel the operation. Beware! This will not necessarily cancel the + * execution of the operation on the server side. However it will make + * sure that the callback associated with this operation will not be + * called anymore, effectively disabling the operation from the client + * side's view. */ void pa_operation_cancel(pa_operation *o); /** Return the current status of the operation */ -- cgit From a4bc41a7a505c3acfe329d1a64cd82e7538a1e8f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:03:49 +0200 Subject: simple: use PA_xxx_IS_GOOD for state checks --- src/pulse/simple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index f4481fc3..bd11cb37 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -70,8 +70,8 @@ struct pa_simple { #define CHECK_DEAD_GOTO(p, rerror, label) \ do { \ - if (!(p)->context || pa_context_get_state((p)->context) != PA_CONTEXT_READY || \ - !(p)->stream || pa_stream_get_state((p)->stream) != PA_STREAM_READY) { \ + if (!(p)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((p)->context)) || \ + !(p)->stream || !PA_STREAM_IS_GOOD(pa_stream_get_state((p)->stream))) { \ if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \ ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \ if (rerror) \ -- cgit From b553e7283d3ec38080d6544672b920b9811c1a89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:04:08 +0200 Subject: simple: use pa_xnew0 instead of manual reset to 0 --- src/pulse/simple.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index bd11cb37..7fd7cce7 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -157,12 +157,8 @@ pa_simple* pa_simple_new( CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) - p = pa_xnew(pa_simple, 1); - p->context = NULL; - p->stream = NULL; + p = pa_xnew0(pa_simple, 1); p->direction = dir; - p->read_data = NULL; - p->read_index = p->read_length = 0; if (!(p->mainloop = pa_threaded_mainloop_new())) goto fail; -- cgit From a73c615b7480f59991dc37bc838fd16dcbc0175b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:04:36 +0200 Subject: simple: always loop around pa_threaded_mainloop_wait() to handle spurious wakeups properly --- src/pulse/simple.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index 7fd7cce7..c2014c5c 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -178,12 +178,21 @@ pa_simple* pa_simple_new( if (pa_threaded_mainloop_start(p->mainloop) < 0) goto unlock_and_fail; - /* Wait until the context is ready */ - pa_threaded_mainloop_wait(p->mainloop); + for (;;) { + pa_context_state_t state; - if (pa_context_get_state(p->context) != PA_CONTEXT_READY) { - error = pa_context_errno(p->context); - goto unlock_and_fail; + state = pa_context_get_state(p->context); + + if (state == PA_CONTEXT_READY) + break; + + if (!PA_CONTEXT_IS_GOOD(state)) { + error = pa_context_errno(p->context); + goto unlock_and_fail; + } + + /* Wait until the context is ready */ + pa_threaded_mainloop_wait(p->mainloop); } if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) { @@ -212,13 +221,21 @@ pa_simple* pa_simple_new( goto unlock_and_fail; } - /* Wait until the stream is ready */ - pa_threaded_mainloop_wait(p->mainloop); + for (;;) { + pa_stream_state_t state; - /* Wait until the stream is ready */ - if (pa_stream_get_state(p->stream) != PA_STREAM_READY) { - error = pa_context_errno(p->context); - goto unlock_and_fail; + state = pa_stream_get_state(p->stream); + + if (state == PA_STREAM_READY) + break; + + if (!PA_STREAM_IS_GOOD(state)) { + error = pa_context_errno(p->context); + goto unlock_and_fail; + } + + /* Wait until the stream is ready */ + pa_threaded_mainloop_wait(p->mainloop); } pa_threaded_mainloop_unlock(p->mainloop); -- cgit From 53fcf3add0521b83e8b5226e6660d2ec9548f48c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:04:50 +0200 Subject: simple: call pa_context_disconnect() just to be sure --- src/pulse/simple.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index c2014c5c..b5e108fb 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -261,8 +261,10 @@ void pa_simple_free(pa_simple *s) { if (s->stream) pa_stream_unref(s->stream); - if (s->context) + if (s->context) { + pa_context_disconnect(s->context); pa_context_unref(s->context); + } if (s->mainloop) pa_threaded_mainloop_free(s->mainloop); -- cgit From 5bbeb516aa3539e30fccf228d5ac31381209a578 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:05:08 +0200 Subject: simple: split data/length validity checks into two --- src/pulse/simple.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index b5e108fb..1e0f3e18 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -276,7 +276,8 @@ int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); pa_threaded_mainloop_lock(p->mainloop); @@ -315,7 +316,8 @@ int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); + CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); pa_threaded_mainloop_lock(p->mainloop); -- cgit From 2cab6a256ca99c20c7f39e330640df6854d35cc8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 01:05:35 +0200 Subject: simple: check for == RUNNING instead of != DONE when waiting for operations --- src/pulse/simple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/simple.c b/src/pulse/simple.c index 1e0f3e18..9ed7a653 100644 --- a/src/pulse/simple.c +++ b/src/pulse/simple.c @@ -392,7 +392,7 @@ int pa_simple_drain(pa_simple *p, int *rerror) { CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); p->operation_success = 0; - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } @@ -428,7 +428,7 @@ int pa_simple_flush(pa_simple *p, int *rerror) { CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); p->operation_success = 0; - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } -- cgit From 23a294c97e62e0bee9b17b1f8ad20a39e1ba15da Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sun, 9 Aug 2009 03:01:08 +0300 Subject: Correctly deal with events in the past in calc_next_timeout pa_usec_t is unsigned, thus it will always be >= 0 This makes gstreamer pulse mixer work again This fixes a gstreamer mixer regression, when it can't control the volume, after few changes. --- src/pulse/mainloop.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c index c418d108..93a4742d 100644 --- a/src/pulse/mainloop.c +++ b/src/pulse/mainloop.c @@ -765,23 +765,22 @@ static pa_time_event* find_next_time_event(pa_mainloop *m) { static int calc_next_timeout(pa_mainloop *m) { pa_time_event *t; - pa_usec_t usec; + pa_usec_t clock_now; if (!m->n_enabled_time_events) return -1; - t = find_next_time_event(m); - pa_assert(t); + pa_assert_se(t = find_next_time_event(m)); - if (t->time == 0) + if (t->time <= 0) return 0; - usec = t->time - pa_rtclock_now(); + clock_now = pa_rtclock_now(); - if (usec <= 0) + if (t->time <= clock_now) return 0; - return (int) (usec / 1000); /* in milliseconds */ + return (int) ((t->time - clock_now) / 1000); /* in milliseconds */ } static int dispatch_timeout(pa_mainloop *m) { -- cgit From facae1f27504983d7eff7c7c3ffa864f7e002272 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 20:15:28 +0200 Subject: conf: invert all negative boolean configuration option --- src/pulse/client-conf.c | 21 +++++++++++---------- src/pulse/client.conf.in | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'src/pulse') diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 940d0b67..4aa4ba1f 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -92,16 +92,17 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { /* Prepare the configuration parse table */ pa_config_item table[] = { - { "daemon-binary", pa_config_parse_string, &c->daemon_binary, NULL }, - { "extra-arguments", pa_config_parse_string, &c->extra_arguments, NULL }, - { "default-sink", pa_config_parse_string, &c->default_sink, NULL }, - { "default-source", pa_config_parse_string, &c->default_source, NULL }, - { "default-server", pa_config_parse_string, &c->default_server, NULL }, - { "autospawn", pa_config_parse_bool, &c->autospawn, NULL }, - { "cookie-file", pa_config_parse_string, &c->cookie_file, NULL }, - { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, - { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, - { NULL, NULL, NULL, NULL }, + { "daemon-binary", pa_config_parse_string, &c->daemon_binary, NULL }, + { "extra-arguments", pa_config_parse_string, &c->extra_arguments, NULL }, + { "default-sink", pa_config_parse_string, &c->default_sink, NULL }, + { "default-source", pa_config_parse_string, &c->default_source, NULL }, + { "default-server", pa_config_parse_string, &c->default_server, NULL }, + { "autospawn", pa_config_parse_bool, &c->autospawn, NULL }, + { "cookie-file", pa_config_parse_string, &c->cookie_file, NULL }, + { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, + { "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL }, + { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, + { NULL, NULL, NULL, NULL }, }; if (filename) { diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in index 579bcc20..6c8d371c 100644 --- a/src/pulse/client.conf.in +++ b/src/pulse/client.conf.in @@ -29,5 +29,5 @@ ; cookie-file = -; disable-shm = no +; enable-shm = yes ; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB -- cgit From 5921324fd3c16e2b3d38d07b200febd90835f169 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:40:12 +0200 Subject: context: document why we only do minimal cleanups before the autospawn exec() --- src/pulse/context.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/context.c b/src/pulse/context.c index 7c3717fa..894ab2e0 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -707,10 +707,13 @@ static int context_autospawn(pa_context *c) { if (c->spawn_api.atfork) c->spawn_api.atfork(); + /* We leave most of the cleaning up of the process environment + * to the executable. We only clean up the file descriptors to + * make sure the executable can actually be loaded + * correctly. */ pa_close_all(-1); /* Setup argv */ - argv[n++] = c->conf->daemon_binary; argv[n++] = "--start"; -- cgit From 0f2a4ed422530b56b3744efe8055540644c0e774 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 20:03:30 +0200 Subject: volume: guarantee dB/linear conversion is reversible --- src/pulse/volume.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 42cde5b9..c23f360b 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -205,9 +205,12 @@ pa_volume_t pa_sw_volume_from_linear(double v) { * * http://www.robotplanet.dk/audio/audio_gui_design/ * http://lists.linuxaudio.org/pipermail/linux-audio-dev/2009-May/thread.html#23151 + * + * We make sure that the conversion to linear and back yields the + * same volume value! That's why we need the lround() below! */ - return (pa_volume_t) (cbrt(v) * PA_VOLUME_NORM); + return (pa_volume_t) lround(cbrt(v) * PA_VOLUME_NORM); } double pa_sw_volume_to_linear(pa_volume_t v) { -- cgit From d8a90a390041b5603a7caacaaea8296fa76363bc Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Mon, 20 Jul 2009 13:53:17 +0300 Subject: pulse: even in case of record stream, let's initialize req_bytes to 0 --- src/pulse/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulse') diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 72d49e11..2bc2b1e4 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -867,7 +867,7 @@ static void automatic_buffer_attr(pa_stream *s, pa_buffer_attr *attr, const pa_s void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; - uint32_t requested_bytes; + uint32_t requested_bytes = 0; pa_assert(pd); pa_assert(s); -- cgit