diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/daemon/main.c | 37 | ||||
-rw-r--r-- | src/modules/alsa/alsa-sink.c | 2 | ||||
-rw-r--r-- | src/modules/alsa/alsa-source.c | 2 | ||||
-rw-r--r-- | src/modules/alsa/alsa-util.c | 16 | ||||
-rw-r--r-- | src/modules/module-pipe-sink.c | 7 | ||||
-rw-r--r-- | src/modules/module-pipe-source.c | 7 | ||||
-rw-r--r-- | src/modules/module-solaris.c | 2 | ||||
-rw-r--r-- | src/pulse/stream.c | 59 | ||||
-rw-r--r-- | src/pulsecore/atomic.h | 104 |
9 files changed, 220 insertions, 16 deletions
diff --git a/src/daemon/main.c b/src/daemon/main.c index 48911827..e6568364 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -537,6 +537,12 @@ int main(int argc, char *argv[]) { goto finish; case PA_CMD_DUMP_CONF: { + + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + s = pa_daemon_conf_dump(conf); fputs(s, stdout); pa_xfree(s); @@ -547,6 +553,11 @@ int main(int argc, char *argv[]) { case PA_CMD_DUMP_RESAMPLE_METHODS: { int i; + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + for (i = 0; i < PA_RESAMPLER_MAX; i++) if (pa_resample_method_supported(i)) printf("%s\n", pa_resample_method_to_string(i)); @@ -561,6 +572,12 @@ int main(int argc, char *argv[]) { goto finish; case PA_CMD_VERSION : + + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); retval = 0; goto finish; @@ -568,6 +585,11 @@ int main(int argc, char *argv[]) { case PA_CMD_CHECK: { pid_t pid; + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) pa_log_info(_("Daemon not running")); else { @@ -580,6 +602,11 @@ int main(int argc, char *argv[]) { } case PA_CMD_KILL: + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + if (pa_pid_file_kill(SIGINT, NULL, "pulseaudio") < 0) pa_log(_("Failed to kill daemon: %s"), pa_cstrerror(errno)); else @@ -589,6 +616,11 @@ int main(int argc, char *argv[]) { case PA_CMD_CLEANUP_SHM: + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + if (pa_shm_cleanup() >= 0) retval = 0; @@ -598,6 +630,11 @@ int main(int argc, char *argv[]) { pa_assert(conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START); } + if (d < argc) { + pa_log("Too many arguments.\n"); + goto finish; + } + if (getuid() == 0 && !conf->system_instance) pa_log_warn(_("This program is not intended to be run as root (unless --system is specified).")); #ifndef HAVE_DBUS /* A similar, only a notice worthy check was done earlier, if D-Bus is enabled. */ diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 856adb14..ed16c834 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -983,7 +983,7 @@ static int unsuspend(struct userdata *u) { buffer_size*u->frame_size != u->hwbuf_size) { pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)", (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size, - (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size)); + (unsigned long) (buffer_size*u->frame_size), (unsigned long) (period_size*u->frame_size)); goto fail; } diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index e775b20c..157698e3 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -930,7 +930,7 @@ static int unsuspend(struct userdata *u) { buffer_size*u->frame_size != u->hwbuf_size) { pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)", (unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size, - (unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size)); + (unsigned long) (buffer_size*u->frame_size), (unsigned long) (period_size*u->frame_size)); goto fail; } diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index b8d13575..52f12599 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -259,6 +259,10 @@ int pa_alsa_set_hw_params( goto finish; } + /* We ignore very small sampling rate deviations */ + if (_ss.rate >= ss->rate*.95 && _ss.rate <= ss->rate*1.05) + _ss.rate = ss->rate; + if (require_exact_channel_number) { if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) { pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret)); @@ -303,7 +307,7 @@ int pa_alsa_set_hw_params( if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { - pa_log_debug("Set buffer size first, period size second."); + pa_log_debug("Set buffer size first (to %lu samples), period size second (to %lu samples).", (unsigned long) _buffer_size, (unsigned long) _period_size); goto success; } @@ -311,7 +315,7 @@ int pa_alsa_set_hw_params( if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { - pa_log_debug("Set period size first, buffer size second."); + pa_log_debug("Set period size first (to %lu samples), buffer size second (to %lu samples).", (unsigned long) _period_size, (unsigned long) _buffer_size); goto success; } } @@ -322,7 +326,7 @@ int pa_alsa_set_hw_params( /* Third try: set only buffer size */ if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 && snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { - pa_log_debug("Set only buffer size second."); + pa_log_debug("Set only buffer size (to %lu samples).", (unsigned long) _buffer_size); goto success; } } @@ -333,7 +337,7 @@ int pa_alsa_set_hw_params( /* Fourth try: set only period size */ if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 && snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) { - pa_log_debug("Set only period size second."); + pa_log_debug("Set only period size (to %lu samples).", (unsigned long) _period_size); goto success; } } @@ -374,9 +378,7 @@ success: goto finish; } - /* If the sample rate deviates too much, we need to resample */ - if (_ss.rate < ss->rate*.95 || _ss.rate > ss->rate*1.05) - ss->rate = _ss.rate; + ss->rate = _ss.rate; ss->channels = _ss.channels; ss->format = _ss.format; diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index 10cc3415..7a4e730f 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -34,6 +34,10 @@ #include <sys/ioctl.h> #include <poll.h> +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> +#endif + #include <pulse/xmalloc.h> #include <pulsecore/core-error.h> @@ -101,9 +105,10 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse case PA_SINK_MESSAGE_GET_LATENCY: { size_t n = 0; - int l; #ifdef FIONREAD + int l; + if (ioctl(u->fd, FIONREAD, &l) >= 0 && l > 0) n = (size_t) l; #endif diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c index de680933..933f0294 100644 --- a/src/modules/module-pipe-source.c +++ b/src/modules/module-pipe-source.c @@ -34,6 +34,10 @@ #include <sys/ioctl.h> #include <sys/poll.h> +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> +#endif + #include <pulse/xmalloc.h> #include <pulsecore/core-error.h> @@ -105,9 +109,10 @@ static int source_process_msg( case PA_SOURCE_MESSAGE_GET_LATENCY: { size_t n = 0; - int l; #ifdef FIONREAD + int l; + if (ioctl(u->fd, FIONREAD, &l) >= 0 && l > 0) n = (size_t) l; #endif diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 955997ba..396094ce 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -327,7 +327,7 @@ static int open_audio_device(struct userdata *u, pa_sample_spec *ss) { pa_assert(u); pa_assert(ss); - if ((u->fd = pa_open_cloexec(u->device_name, u->mode | O_NONBLOCK)) < 0) { + if ((u->fd = pa_open_cloexec(u->device_name, u->mode | O_NONBLOCK, 0)) < 0) { pa_log_warn("open %s failed (%s)", u->device_name, pa_cstrerror(errno)); return -1; } diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 29979625..4dea5670 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -387,9 +387,26 @@ static void check_smoother_status(pa_stream *s, pa_bool_t aposteriori, pa_bool_t if (s->suspended || s->corked || force_stop) pa_smoother_pause(s->smoother, x); - else if (force_start || s->buffer_attr.prebuf == 0) - pa_smoother_resume(s->smoother, x, TRUE); + else if (force_start || s->buffer_attr.prebuf == 0) { + + if (!s->timing_info_valid && + !aposteriori && + !force_start && + !force_stop && + s->context->version >= 13) { + + /* If the server supports STARTED events we take them as + * indications when audio really starts/stops playing, if + * we don't have any timing info yet -- instead of trying + * to be smart and guessing the server time. Otherwise the + * unknown transport delay add too much noise to our time + * calculations. */ + + return; + } + pa_smoother_resume(s->smoother, x, TRUE); + } /* Please note that we have no idea if playback actually started * if prebuf is non-zero! */ @@ -1465,6 +1482,11 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command(s->context, PA_COMMAND_DRAIN_PLAYBACK_STREAM, &tag); @@ -1472,6 +1494,10 @@ pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *us pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + /* This might cause the read index to conitnue again, hence + * let's request a timing update */ + request_auto_timing_update(s, TRUE); + return o; } @@ -2020,6 +2046,11 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + s->corked = b; o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); @@ -2035,8 +2066,8 @@ pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, voi check_smoother_status(s, FALSE, FALSE, FALSE); - /* This might cause the indexes to hang/start again, hence - * let's request a timing update */ + /* This might cause the indexes to hang/start again, hence let's + * request a timing update, after the cork/uncork, too */ request_auto_timing_update(s, TRUE); return o; @@ -2073,6 +2104,11 @@ pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *use PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); + /* Ask for a timing update *before* the flush, so that the + * transport usec is as up to date as possible when we get the + * underflow message and update the smoother status*/ + request_auto_timing_update(s, TRUE); + if (!(o = stream_send_simple_command(s, (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM), cb, userdata))) return NULL; @@ -2107,6 +2143,11 @@ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *us PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + if (!(o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) return NULL; @@ -2128,6 +2169,11 @@ pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *u PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + if (!(o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) return NULL; @@ -2379,6 +2425,11 @@ pa_operation* pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); + /* Ask for a timing update before we cork/uncork to get the best + * accuracy for the transport latency suitable for the + * check_smoother_status() call in the started callback */ + request_auto_timing_update(s, TRUE); + o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); t = pa_tagstruct_command( diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h index 119c445b..51d08210 100644 --- a/src/pulsecore/atomic.h +++ b/src/pulsecore/atomic.h @@ -180,6 +180,110 @@ static inline pa_bool_t pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, v return r == old_p; } +#elif defined(__FreeBSD__) + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/param.h> +#include <machine/atomic.h> + +#if __FreeBSD_version < 600000 +#if defined(__i386__) || defined(__amd64__) +#if defined(__amd64__) +#define atomic_load_acq_64 atomic_load_acq_long +#endif +static inline u_int atomic_fetchadd_int(volatile u_int *p, u_int v) { + __asm __volatile( + " " __XSTRING(MPLOCKED) " " + " xaddl %0, %1 ; " + "# atomic_fetchadd_int" + : "+r" (v), + "=m" (*p) + : "m" (*p)); + + return (v); +} +#elif defined(__sparc64__) +#define atomic_load_acq_64 atomic_load_acq_long +#define atomic_fetchadd_int atomic_add_int +#elif defined(__ia64__) +#define atomic_load_acq_64 atomic_load_acq_long +static inline uint32_t +atomic_fetchadd_int(volatile uint32_t *p, uint32_t v) { + uint32_t value; + + do { + value = *p; + } while (!atomic_cmpset_32(p, value, value + v)); + return (value); +} +#endif +#endif + +typedef struct pa_atomic { + volatile unsigned long value; +} pa_atomic_t; + +#define PA_ATOMIC_INIT(v) { .value = (v) } + +static inline int pa_atomic_load(const pa_atomic_t *a) { + return (int) atomic_load_acq_int((unsigned int *) &a->value); +} + +static inline void pa_atomic_store(pa_atomic_t *a, int i) { + atomic_store_rel_int((unsigned int *) &a->value, i); +} + +static inline int pa_atomic_add(pa_atomic_t *a, int i) { + return atomic_fetchadd_int((unsigned int *) &a->value, i); +} + +static inline int pa_atomic_sub(pa_atomic_t *a, int i) { + return atomic_fetchadd_int((unsigned int *) &a->value, -(i)); +} + +static inline int pa_atomic_inc(pa_atomic_t *a) { + return atomic_fetchadd_int((unsigned int *) &a->value, 1); +} + +static inline int pa_atomic_dec(pa_atomic_t *a) { + return atomic_fetchadd_int((unsigned int *) &a->value, -1); +} + +static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { + return atomic_cmpset_int((unsigned int *) &a->value, old_i, new_i); +} + +typedef struct pa_atomic_ptr { + volatile unsigned long value; +} pa_atomic_ptr_t; + +#define PA_ATOMIC_PTR_INIT(v) { .value = (unsigned long) (v) } + +static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) { +#ifdef atomic_load_acq_64 + return (void*) atomic_load_acq_ptr((unsigned long *) &a->value); +#else + return (void*) atomic_load_acq_ptr((unsigned int *) &a->value); +#endif +} + +static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { +#ifdef atomic_load_acq_64 + atomic_store_rel_ptr(&a->value, (unsigned long) p); +#else + atomic_store_rel_ptr((unsigned int *) &a->value, (unsigned int) p); +#endif +} + +static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { +#ifdef atomic_load_acq_64 + return atomic_cmpset_ptr(&a->value, (unsigned long) old_p, (unsigned long) new_p); +#else + return atomic_cmpset_ptr((unsigned int *) &a->value, (unsigned int) old_p, (unsigned int) new_p); +#endif +} + #elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__)) #warn "The native atomic operations implementation for AMD64 has not been tested thoroughly. libatomic_ops is known to not work properly on AMD64 and your gcc version is too old for the gcc-builtin atomic ops support. You have three options now: test the native atomic operations implementation for AMD64, fix libatomic_ops, or upgrade your GCC." |