diff options
Diffstat (limited to 'src')
37 files changed, 641 insertions, 293 deletions
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; 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; diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index e7925902..1c38430f 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 == -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; @@ -401,6 +404,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 +488,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 +501,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 +627,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 +645,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; @@ -885,9 +902,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; @@ -1181,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; @@ -1190,7 +1214,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 41bb768b..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; @@ -391,6 +394,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 +467,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 +480,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 +552,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 +613,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; @@ -840,7 +857,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/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) 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/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 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 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=<alsa or oss> " - "tsched=<enable system timer based scheduling mode?>"); + "tsched=<enable system timer based scheduling mode?>" + "subdevs=<init all subdevices>"); #elif defined(HAVE_ALSA) PA_MODULE_USAGE("api=<alsa> " "tsched=<enable system timer based scheduling mode?>"); #elif defined(HAVE_OSS) -PA_MODULE_USAGE("api=<oss>"); +PA_MODULE_USAGE("api=<oss>" + "subdevs=<init all subdevices>"); #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" @@ -92,6 +97,9 @@ static const char* const valid_modargs[] = { #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; 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/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 <pulsecore/core-error.h> #include <pulsecore/proplist-util.h> #include <pulsecore/auth-cookie.h> +#include <pulsecore/mcalign.h> #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 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; diff --git a/src/pulse/context.c b/src/pulse/context.c index 4ded5565..7c3717fa 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(); @@ -688,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(); @@ -699,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))) @@ -714,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 */ @@ -730,9 +740,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; 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 */ diff --git a/src/pulse/simple.c b/src/pulse/simple.c index f4481fc3..9ed7a653 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) \ @@ -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; @@ -182,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))) { @@ -216,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); @@ -248,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); @@ -261,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); @@ -300,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); @@ -375,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); } @@ -411,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); } diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 5baf5c2c..72d49e11 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); } @@ -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); @@ -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 fecc5870..8a08421f 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 */ @@ -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 */, @@ -511,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 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..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. @@ -274,7 +278,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 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 <sys/stat.h> #include <pulse/util.h> +#include <pulse/xmalloc.h> #include <pulsecore/core-error.h> #include <pulsecore/core-util.h> #include <pulsecore/log.h> @@ -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 04e7eb24..d4baf697 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; } @@ -1328,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) { @@ -1372,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" @@ -1481,7 +1539,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); @@ -1626,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 @@ -1713,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 @@ -1904,7 +1964,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); @@ -2779,3 +2839,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..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); @@ -236,4 +238,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 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(); 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; } 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/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index 9d5a0705..d6c37878 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); 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 <limits.h> #include <stdio.h> +#include <string.h> #include <pulse/util.h> +#include <pulse/xmalloc.h> 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/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; 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; } 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 <pulse/pulseaudio.h> #include <pulse/gccmacro.h> #include <pulsecore/llist.h> +#include <pulsecore/core-util.h> /* 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; |