diff options
Diffstat (limited to 'src')
51 files changed, 483 insertions, 212 deletions
diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index 57ccd9f4..fa0683e1 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -58,9 +58,9 @@ load-module module-detect .endif ### Automatically load driver modules for Bluetooth hardware -#.ifexists module-bluetooth-discover@PA_SOEXT@ +.ifexists module-bluetooth-discover@PA_SOEXT@ load-module module-bluetooth-discover -#.endif +.endif ### Load several protocols .ifexists module-esound-protocol-unix@PA_SOEXT@ diff --git a/src/daemon/main.c b/src/daemon/main.c index 2faf6508..d25647cb 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -427,7 +427,7 @@ int main(int argc, char *argv[]) { pa_limit_caps(); /* When capabilities are not supported we will not be able to - * aquire RT sched anymore. But yes, that's the way it is. It + * acquire RT sched anymore. But yes, that's the way it is. It * is just too risky tun let PA run as root all the time. */ } @@ -538,7 +538,7 @@ int main(int argc, char *argv[]) { if ((conf->high_priority && !allow_high_priority) || (conf->realtime_scheduling && !allow_realtime)) - pa_log_notice(_("Called SUID root and real-time and/or high-priority scheduling was requested in the configuration. However, we lack the necessary privileges:\n" + pa_log_info(_("Called SUID root and real-time and/or high-priority scheduling was requested in the configuration. However, we lack the necessary privileges:\n" "We are not in group '%s', PolicyKit refuse to grant us the requested privileges and we have no increase RLIMIT_NICE/RLIMIT_RTPRIO resource limits.\n" "For enabling real-time/high-priority scheduling please acquire the appropriate PolicyKit privileges, or become a member of '%s', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource limits for this user."), PA_REALTIME_GROUP, PA_REALTIME_GROUP); @@ -563,7 +563,7 @@ int main(int argc, char *argv[]) { #endif if (conf->high_priority && !pa_can_high_priority()) { - pa_log_warn(_("High-priority scheduling enabled in configuration but not allowed by policy.")); + pa_log_info(_("High-priority scheduling enabled in configuration but not allowed by policy.")); conf->high_priority = FALSE; } @@ -609,7 +609,7 @@ int main(int argc, char *argv[]) { } if (conf->realtime_scheduling && !pa_can_realtime()) { - pa_log_warn(_("Real-time scheduling enabled in configuration but not allowed by policy.")); + pa_log_info(_("Real-time scheduling enabled in configuration but not allowed by policy.")); conf->realtime_scheduling = FALSE; } diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 0dc0e2b3..f9fb0335 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1173,7 +1173,7 @@ static void sink_update_requested_latency_cb(pa_sink *s) { /* Let's check whether we now use only a smaller part of the buffer then before. If so, we need to make sure that subsequent - rewinds are relative to the new maxium fill level and not to the + rewinds are relative to the new maximum fill level and not to the current fill level. Thus, let's do a full rewind once, to clear things up. */ @@ -1286,7 +1286,7 @@ static void thread_func(void *userdata) { pa_log_info("Starting playback."); snd_pcm_start(u->pcm_handle); - pa_smoother_resume(u->smoother, pa_rtclock_usec()); + pa_smoother_resume(u->smoother, pa_rtclock_usec(), TRUE); } update_smoother(u); @@ -1300,7 +1300,7 @@ static void thread_func(void *userdata) { /* USB devices on ALSA seem to hit a buffer * underrun during the first iterations much * quicker then we calculate here, probably due to - * the transport latency. To accomodate for that + * the transport latency. To accommodate for that * we artificially decrease the sleep time until * we have filled the buffer at least once * completely.*/ @@ -1495,7 +1495,6 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca snd_pcm_uframes_t period_frames, tsched_frames; size_t frame_size; pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE; - pa_usec_t usec; pa_sink_new_data data; pa_assert(m); @@ -1559,10 +1558,14 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); - u->smoother = pa_smoother_new(DEFAULT_TSCHED_BUFFER_USEC*2, DEFAULT_TSCHED_BUFFER_USEC*2, TRUE, 5); - usec = pa_rtclock_usec(); - pa_smoother_set_time_offset(u->smoother, usec); - pa_smoother_pause(u->smoother, usec); + u->smoother = pa_smoother_new( + DEFAULT_TSCHED_BUFFER_USEC*2, + DEFAULT_TSCHED_BUFFER_USEC*2, + TRUE, + TRUE, + 5, + pa_rtclock_usec(), + TRUE); if (reserve_init(u, pa_modargs_get_value( ma, "device_id", @@ -1617,6 +1620,11 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca pa_assert(u->device_name); pa_log_info("Successfully opened device %s.", u->device_name); + if (pa_alsa_pcm_is_modem(u->pcm_handle)) { + pa_log_notice("Device %s is modem, refusing further initialization.", u->device_name); + goto fail; + } + if (profile) pa_log_info("Selected configuration '%s' (%s).", profile->description, profile->name); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 348cd082..9c36211b 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -776,7 +776,7 @@ 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_usec()); + pa_smoother_resume(u->smoother, pa_rtclock_usec(), TRUE); pa_log_info("Resumed successfully..."); @@ -1416,8 +1416,14 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); u->alsa_rtpoll_item = NULL; - u->smoother = pa_smoother_new(DEFAULT_TSCHED_WATERMARK_USEC*2, DEFAULT_TSCHED_WATERMARK_USEC*2, TRUE, 5); - pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec()); + u->smoother = pa_smoother_new( + DEFAULT_TSCHED_WATERMARK_USEC*2, + DEFAULT_TSCHED_WATERMARK_USEC*2, + TRUE, + TRUE, + 5, + pa_rtclock_usec(), + FALSE); if (reserve_init(u, pa_modargs_get_value( ma, "device_id", @@ -1469,6 +1475,11 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p pa_assert(u->device_name); pa_log_info("Successfully opened device %s.", u->device_name); + if (pa_alsa_pcm_is_modem(u->pcm_handle)) { + pa_log_notice("Device %s is modem, refusing further initialization.", u->device_name); + goto fail; + } + if (profile) pa_log_info("Selected configuration '%s' (%s).", profile->description, profile->name); diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 5b5270b8..870cf0f1 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -705,7 +705,7 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( } else { /* Hmm, so the next entry does not have the same * number of channels, so let's go backwards until we - * find the next entry with a differnt number of + * find the next entry with a different number of * channels */ for (i--; i >= 0; i--) @@ -1063,7 +1063,7 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const fallback_elem = NULL; } - pa_log_warn("Cannot find fallback mixer control \"%s\" or mixer control is no combination of switch/volume.", snd_mixer_selem_id_get_name(sid)); + pa_log_info("Cannot find fallback mixer control \"%s\" or mixer control is no combination of switch/volume.", snd_mixer_selem_id_get_name(sid)); } if (elem && fallback_elem) { @@ -1769,3 +1769,15 @@ pa_bool_t pa_alsa_pcm_is_hw(snd_pcm_t *pcm) { return snd_pcm_info_get_card(info) >= 0; } + +pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm) { + snd_pcm_info_t* info; + snd_pcm_info_alloca(&info); + + pa_assert(pcm); + + if (snd_pcm_info(pcm, info) < 0) + return FALSE; + + return snd_pcm_info_get_class(info) == SND_PCM_CLASS_MODEM; +} diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 5cad2958..94f27d14 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -141,4 +141,6 @@ char *pa_alsa_get_reserve_name(const char *device); pa_bool_t pa_alsa_pcm_is_hw(snd_pcm_t *pcm); +pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm); + #endif diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 96b95b4f..4613172e 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -869,7 +869,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off if (start_stream_fd(u) < 0) failed = TRUE; - pa_smoother_resume(u->read_smoother, pa_rtclock_usec()); + pa_smoother_resume(u->read_smoother, pa_rtclock_usec(), TRUE); break; case PA_SOURCE_UNLINKED: @@ -1965,7 +1965,14 @@ int pa__init(pa_module* m) { u->core = m->core; u->service_fd = -1; u->stream_fd = -1; - u->read_smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10); + u->read_smoother = pa_smoother_new( + PA_USEC_PER_SEC, + PA_USEC_PER_SEC*2, + TRUE, + TRUE, + 10, + 0, + FALSE); u->sample_spec = m->core->default_sample_spec; u->modargs = ma; diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index b7e18bc3..a1ef8da4 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -664,7 +664,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse if (PA_PTR_TO_UINT(data) == PA_SINK_SUSPENDED) pa_smoother_pause(u->thread_info.smoother, pa_rtclock_usec()); else - pa_smoother_resume(u->thread_info.smoother, pa_rtclock_usec()); + pa_smoother_resume(u->thread_info.smoother, pa_rtclock_usec(), TRUE); break; @@ -1043,7 +1043,14 @@ int pa__init(pa_module*m) { pa_atomic_store(&u->thread_info.running, FALSE); u->thread_info.in_null_mode = FALSE; u->thread_info.counter = 0; - u->thread_info.smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10); + u->thread_info.smoother = pa_smoother_new( + PA_USEC_PER_SEC, + PA_USEC_PER_SEC*2, + TRUE, + TRUE, + 10, + 0, + FALSE); if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) { pa_log("Failed to parse adjust_time value"); diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 5c47f444..a1a783aa 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -150,7 +150,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse case PA_SINK_RUNNING: if (u->sink->thread_info.state == PA_SINK_SUSPENDED) - pa_smoother_resume(u->smoother, pa_rtclock_usec()); + pa_smoother_resume(u->smoother, pa_rtclock_usec(), TRUE); break; @@ -545,7 +545,14 @@ int pa__init(pa_module*m) { u->module = m; m->userdata = u; u->fd = -1; - u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10); + u->smoother = pa_smoother_new( + PA_USEC_PER_SEC, + PA_USEC_PER_SEC*2, + TRUE, + TRUE, + 10, + 0, + FALSE); pa_memchunk_reset(&u->memchunk); u->offset = 0; diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 0dd22cbd..b6139e43 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -121,6 +121,7 @@ static const char *strip_udi(const char *udi) { enum alsa_type { ALSA_TYPE_PLAYBACK, ALSA_TYPE_CAPTURE, + ALSA_TYPE_CONTROL, ALSA_TYPE_OTHER }; @@ -141,6 +142,8 @@ static enum alsa_type hal_alsa_device_get_type(LibHalContext *context, const cha t = ALSA_TYPE_PLAYBACK; else if (pa_streq(type, "capture")) t = ALSA_TYPE_CAPTURE; + else if (pa_streq(type, "control")) + t = ALSA_TYPE_CONTROL; libhal_free_string(type); @@ -171,7 +174,8 @@ static pa_bool_t hal_alsa_device_is_modem(LibHalContext *context, const char *ud finish: if (dbus_error_is_set(&error)) { - pa_log_error("D-Bus error while parsing HAL ALSA data: %s: %s", error.name, error.message); + if (!dbus_error_has_name(&error, "org.freedesktop.Hal.NoSuchProperty")) + pa_log_error("D-Bus error while parsing HAL ALSA data: %s: %s", error.name, error.message); dbus_error_free(&error); } @@ -193,10 +197,23 @@ static int hal_device_load_alsa(struct userdata *u, const char *udi, struct devi /* We only care for PCM devices */ type = hal_alsa_device_get_type(u->context, udi); - if (type == ALSA_TYPE_OTHER) + + /* For each ALSA card that appears the control device will be the + * last one to be created, this is considered part of the ALSA + * usperspace API. We rely on this and load our modules only when + * the control device is available assuming that *all* device + * nodes have been properly created and assigned the right ACLs at + * that time. Also see: + * + * http://mailman.alsa-project.org/pipermail/alsa-devel/2009-April/015958.html + * + * and the associated thread.*/ + + if (type != ALSA_TYPE_CONTROL) goto fail; - /* We don't care for modems */ + /* We don't care for modems -- this is most likely not set for + * control devices, so kind of pointless here. */ if (hal_alsa_device_is_modem(u->context, udi)) goto fail; @@ -411,9 +428,10 @@ static int hal_device_add_all(struct userdata *u) { for (i = 0; i < n; i++) { struct device *d; - if ((d = hal_device_add(u, udis[i]))) + if ((d = hal_device_add(u, udis[i]))) { count++; - else + pa_log_debug("Loaded device %s", udis[i]); + } else pa_log_debug("Not loaded device %s", udis[i]); } } @@ -449,6 +467,8 @@ static void device_added_cb(LibHalContext *context, const char *udi) { if (!hal_device_add(u, udi)) pa_log_debug("Not loaded device %s", udi); + else + pa_log_debug("Loaded device %s", udi); finish: if (dbus_error_is_set(&error)) { diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index e619acd3..44052c9c 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -235,7 +235,7 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) { if (amount > 0) { unsigned c; - pa_memblockq_seek(u->memblockq, - (int64_t) amount, PA_SEEK_RELATIVE); + pa_memblockq_seek(u->memblockq, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE); pa_log_debug("Resetting plugin"); diff --git a/src/modules/module-raop-discover.c b/src/modules/module-raop-discover.c index 5c2e0623..eaeb77fc 100644 --- a/src/modules/module-raop-discover.c +++ b/src/modules/module-raop-discover.c @@ -258,7 +258,7 @@ static void browser_cb( pa_log("avahi_service_resolver_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); /* We ignore the returned resolver object here, since the we don't - * need to attach any special data to it, and we can still destory + * need to attach any special data to it, and we can still destroy * it from the callback */ } else if (event == AVAHI_BROWSER_REMOVE) { diff --git a/src/modules/module-raop-sink.c b/src/modules/module-raop-sink.c index d8ddf184..4d68b1b0 100644 --- a/src/modules/module-raop-sink.c +++ b/src/modules/module-raop-sink.c @@ -192,7 +192,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse case PA_SINK_RUNNING: if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { - pa_smoother_resume(u->smoother, pa_rtclock_usec()); + pa_smoother_resume(u->smoother, pa_rtclock_usec(), TRUE); /* The connection can be closed when idle, so check to see if we need to reestablish it */ @@ -540,7 +540,14 @@ int pa__init(pa_module*m) { u->module = m; m->userdata = u; u->fd = -1; - u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10); + u->smoother = pa_smoother_new( + PA_USEC_PER_SEC, + PA_USEC_PER_SEC*2, + TRUE, + TRUE, + 10, + 0, + FALSE); pa_memchunk_reset(&u->raw_memchunk); pa_memchunk_reset(&u->encoded_memchunk); u->offset = 0; diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 1d658ba0..5ea58aa0 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -405,7 +405,7 @@ static void check_smoother_status(struct userdata *u, pa_bool_t past) { if (u->remote_suspended || u->remote_corked) pa_smoother_pause(u->smoother, x); else - pa_smoother_resume(u->smoother, x); + pa_smoother_resume(u->smoother, x, TRUE); } /* Called from IO thread context */ @@ -1815,7 +1815,14 @@ int pa__init(pa_module*m) { u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; u->source = NULL; #endif - u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10); + u->smoother = pa_smoother_new( + PA_USEC_PER_SEC, + PA_USEC_PER_SEC*2, + TRUE, + TRUE, + 10, + pa_rtclock_usec(), + FALSE); u->ctag = 1; u->device_index = u->channel = PA_INVALID_INDEX; u->time_event = NULL; @@ -1933,8 +1940,6 @@ int pa__init(pa_module*m) { u->fragsize = (uint32_t) -1; #endif - pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec()); - if (!(u->thread = pa_thread_new(thread_func, u))) { pa_log("Failed to create thread."); goto fail; diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index 7d71067b..83e69d1b 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -136,7 +136,7 @@ static void x11_kill_cb(pa_x11_wrapper *w, void *userdata) { int pa__init(pa_module*m) { struct userdata *u; pa_modargs *ma = NULL; - char hn[256], un[128]; + char *mid; char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; const char *t; @@ -164,10 +164,10 @@ int pa__init(pa_module*m) { if (!(u->x11_wrapper = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL)))) goto fail; - if (!pa_get_fqdn(hn, sizeof(hn)) || !pa_get_user_name(un, sizeof(un))) - goto fail; + mid = pa_machine_id(); + u->id = pa_sprintf_malloc("%lu@%s/%lu", (unsigned long) getuid(), mid, (unsigned long) getpid()); + pa_xfree(mid); - u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid()); pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID", u->id); publish_servers(u, pa_native_protocol_servers(u->protocol)); diff --git a/src/modules/module-zeroconf-discover.c b/src/modules/module-zeroconf-discover.c index 3da946e0..1fdc1f46 100644 --- a/src/modules/module-zeroconf-discover.c +++ b/src/modules/module-zeroconf-discover.c @@ -279,7 +279,7 @@ static void browser_cb( pa_log("avahi_service_resolver_new() failed: %s", avahi_strerror(avahi_client_errno(u->client))); /* We ignore the returned resolver object here, since the we don't - * need to attach any special data to it, and we can still destory + * need to attach any special data to it, and we can still destroy * it from the callback */ } else if (event == AVAHI_BROWSER_REMOVE) { diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index 33e23af2..e7749cdd 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -229,7 +229,7 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) { } } - /* Check wheter there was a timestamp overflow */ + /* Check whether there was a timestamp overflow */ k = (int64_t) s->rtp_context.timestamp - (int64_t) s->offset; j = (int64_t) 0x100000000LL - (int64_t) s->offset + (int64_t) s->rtp_context.timestamp; @@ -238,7 +238,7 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) { else delta = j; - pa_memblockq_seek(s->memblockq, delta * (int64_t) s->rtp_context.frame_size, PA_SEEK_RELATIVE); + pa_memblockq_seek(s->memblockq, delta * (int64_t) s->rtp_context.frame_size, PA_SEEK_RELATIVE, TRUE); pa_rtclock_get(&now); @@ -246,7 +246,7 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) { if (pa_memblockq_push(s->memblockq, &chunk) < 0) { pa_log_warn("Queue overrun"); - pa_memblockq_seek(s->memblockq, (int64_t) chunk.length, PA_SEEK_RELATIVE); + pa_memblockq_seek(s->memblockq, (int64_t) chunk.length, PA_SEEK_RELATIVE, TRUE); } /* pa_log("blocks in q: %u", pa_memblockq_get_nblocks(s->memblockq)); */ @@ -430,8 +430,14 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in s->sdp_info = *sdp_info; s->rtpoll_item = NULL; s->intended_latency = LATENCY_USEC; - s->smoother = pa_smoother_new(PA_USEC_PER_SEC*5, PA_USEC_PER_SEC*2, TRUE, 10); - pa_smoother_set_time_offset(s->smoother, pa_timeval_load(&now)); + s->smoother = pa_smoother_new( + PA_USEC_PER_SEC*5, + PA_USEC_PER_SEC*2, + TRUE, + TRUE, + 10, + pa_timeval_load(&now), + FALSE); s->last_rate_update = pa_timeval_load(&now); pa_atomic_store(&s->timestamp, (int) now.tv_sec); diff --git a/src/modules/rtp/rtsp_client.c b/src/modules/rtp/rtsp_client.c index 98db05dd..629328ad 100644 --- a/src/modules/rtp/rtsp_client.c +++ b/src/modules/rtp/rtsp_client.c @@ -211,7 +211,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) { } if (!strlen(s2)) { /* End of headers */ - /* We will have a header left from our looping itteration, so add it in :) */ + /* We will have a header left from our looping iteration, so add it in :) */ if (c->last_header) { /* This is not a continuation header so let's dump it into our proplist */ pa_headerlist_puts(c->response_headers, c->last_header, pa_strbuf_tostring_free(c->header_buffer)); @@ -488,7 +488,7 @@ int pa_rtsp_record(pa_rtsp_client* c, uint16_t* seq, uint32_t* rtptime) { pa_assert(c); if (!c->session) { - /* No seesion in progres */ + /* No session in progress */ return -1; } diff --git a/src/pulse/channelmap.h b/src/pulse/channelmap.h index eef0ac17..d4db45b0 100644 --- a/src/pulse/channelmap.h +++ b/src/pulse/channelmap.h @@ -50,7 +50,7 @@ * \li pa_channel_map_init_stereo() - Create a standard stereo mapping. * \li pa_channel_map_init_auto() - Create a standard channel map for a specific number of channels * \li pa_channel_map_init_extend() - Similar to - * pa_channel_map_init_auto() but synthesize a channel map if noone + * pa_channel_map_init_auto() but synthesize a channel map if no * predefined one is known for the specified number of channels. * * \section conv_sec Convenience Functions @@ -251,7 +251,7 @@ typedef struct pa_channel_map { * pa_channel_map_valid() will fail for it. */ pa_channel_map* pa_channel_map_init(pa_channel_map *m); -/** Initialize the specified channel map for monoaural audio and return a pointer to it */ +/** Initialize the specified channel map for monaural audio and return a pointer to it */ pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); /** Initialize the specified channel map for stereophonic audio and return a pointer to it */ @@ -282,7 +282,7 @@ const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos); * it might become part of an ABI. */ #define PA_CHANNEL_MAP_SNPRINT_MAX 336 -/** Make a humand readable string from the specified channel map */ +/** Make a human readable string from the specified channel map */ char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); /** Parse a channel position list or well-known mapping name into a diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h index 78844a12..ab97dc6a 100644 --- a/src/pulse/client-conf.h +++ b/src/pulse/client-conf.h @@ -38,7 +38,7 @@ typedef struct pa_client_conf { pa_client_conf *pa_client_conf_new(void); void pa_client_conf_free(pa_client_conf *c); -/* Load the configuration data from the speicified file, overwriting +/* Load the configuration data from the specified file, overwriting * the current settings in *c. When the filename is NULL, the * default client configuration file name is used. */ int pa_client_conf_load(pa_client_conf *c, const char *filename); diff --git a/src/pulse/context.c b/src/pulse/context.c index 28d17191..991a886f 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -364,10 +364,10 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o if ((s = pa_dynarray_get(c->record_streams, channel))) { if (chunk->memblock) { - pa_memblockq_seek(s->record_memblockq, offset, seek); + pa_memblockq_seek(s->record_memblockq, offset, seek, TRUE); pa_memblockq_push_align(s->record_memblockq, chunk); } else - pa_memblockq_seek(s->record_memblockq, offset+chunk->length, seek); + pa_memblockq_seek(s->record_memblockq, offset+chunk->length, seek, TRUE); if (s->read_callback) { size_t l; diff --git a/src/pulse/def.h b/src/pulse/def.h index cae08942..d5bbefe3 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -71,7 +71,7 @@ typedef enum pa_stream_state { PA_STREAM_UNCONNECTED, /**< The stream is not yet connected to any sink or source */ PA_STREAM_CREATING, /**< The stream is being created */ PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ - PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ + PA_STREAM_FAILED, /**< An error occurred that made the stream invalid */ PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ } pa_stream_state_t; @@ -216,7 +216,7 @@ typedef enum pa_stream_flags { * sink/device. Useful if you use any of the PA_STREAM_FIX_ flags * and want to make sure that resampling never takes place -- * which might happen if the stream is moved to another - * sink/source whith a different sample spec/channel map. Only + * sink/source with a different sample spec/channel map. Only * supported when the server is at least PA 0.9.8. It is ignored * on older servers. \since 0.9.8 */ @@ -250,7 +250,7 @@ typedef enum pa_stream_flags { * asking for less new data than this value will be made to the * client it will also guarantee that requests are generated as * early as this limit is reached. This flag should only be set in - * very few situations where compatiblity with a fragment-based + * very few situations where compatibility with a fragment-based * playback model needs to be kept and the client applications * cannot deal with data requests that are delayed to the latest * moment possible. (Usually these are programs that use usleep() @@ -326,12 +326,12 @@ typedef struct pa_buffer_attr { * plus the playback buffer size is configured to this value. Set * PA_STREAM_ADJUST_LATENCY if you are interested in adjusting the * overall latency. Don't set it if you are interested in - * configuring the server-sider per-stream playback buffer + * configuring the server-side per-stream playback buffer * size. */ uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with - * playback before at least prebug bytes are available in the + * playback before at least prebuf bytes are available in the * buffer. It is recommended to set this to (uint32_t) -1, which * will initialize this to the same value as tlength, whatever * that may be. Initialize to 0 to enable manual start/stop @@ -352,7 +352,7 @@ typedef struct pa_buffer_attr { uint32_t fragsize; /**< Recording only: fragment size. The server sends data in - * blocks of fragsize bytes size. Large values deminish + * blocks of fragsize bytes size. Large values diminish * interactivity with other operations on the connection context * but decrease control overhead. It is recommended to set this to * (uint32_t) -1, which will initialize this to a value that is @@ -392,7 +392,7 @@ enum { PA_ERR_NOEXTENSION, /**< Extension does not exist. \since 0.9.12 */ PA_ERR_OBSOLETE, /**< Obsolete functionality. \since 0.9.15 */ PA_ERR_NOTIMPLEMENTED, /**< Missing implementation. \since 0.9.15 */ - PA_ERR_FORKED, /**< The caler forked without calling execve() and tried to reuse the context. \since 0.9.15 */ + PA_ERR_FORKED, /**< The caller forked without calling execve() and tried to reuse the context. \since 0.9.15 */ PA_ERR_MAX /**< Not really an error but the first invalid error code */ }; @@ -490,7 +490,7 @@ typedef enum pa_subscription_event_type { /**< Event type: Sample cache item */ PA_SUBSCRIPTION_EVENT_SERVER = 0x0007U, - /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. */ + /**< Event type: Global server change, only occurring with PA_SUBSCRIPTION_EVENT_CHANGE. */ /** \cond fulldocs */ PA_SUBSCRIPTION_EVENT_AUTOLOAD = 0x0008U, @@ -576,7 +576,7 @@ typedef struct pa_timing_info { /**< Non-zero if the local and the remote machine have * synchronized clocks. If synchronized clocks are detected * transport_usec becomes much more reliable. However, the code - * that detects synchronized clocks is very limited und unreliable + * that detects synchronized clocks is very limited and unreliable * itself. */ pa_usec_t sink_usec; diff --git a/src/pulse/internal.h b/src/pulse/internal.h index cf362d99..344e6399 100644 --- a/src/pulse/internal.h +++ b/src/pulse/internal.h @@ -140,7 +140,7 @@ struct pa_stream { uint32_t syncid; uint32_t stream_index; - uint32_t requested_bytes; + int64_t requested_bytes; pa_buffer_attr buffer_attr; uint32_t device_index; @@ -160,7 +160,7 @@ struct pa_stream { uint32_t write_index_not_before; uint32_t read_index_not_before; - /* Data about individual timing update correctoins */ + /* Data about individual timing update corrections */ pa_index_correction write_index_corrections[PA_MAX_WRITE_INDEX_CORRECTIONS]; int current_write_index_correction; diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index d7ef1c0c..117880c8 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -454,7 +454,7 @@ typedef struct pa_sink_input_info { pa_cvolume volume; /**< The volume of this sink input */ pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ - const char *resample_method; /**< Thre resampling method used by this sink input. */ + const char *resample_method; /**< The resampling method used by this sink input. */ const char *driver; /**< Driver name */ int mute; /**< Stream muted \since 0.9.7 */ pa_proplist *proplist; /**< Property list \since 0.9.11 */ @@ -501,7 +501,7 @@ typedef struct pa_source_output_info { pa_channel_map channel_map; /**< Channel map */ pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. */ pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. */ - const char *resample_method; /**< Thre resampling method used by this source output. */ + const char *resample_method; /**< The resampling method used by this source output. */ const char *driver; /**< Driver name */ pa_proplist *proplist; /**< Property list \since 0.9.11 */ } pa_source_output_info; @@ -539,7 +539,7 @@ pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_cont * any new release. */ typedef struct pa_stat_info { uint32_t memblock_total; /**< Currently allocated memory blocks */ - uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ + uint32_t memblock_total_size; /**< Current total size of allocated memory blocks */ uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ uint32_t scache_size; /**< Total size of all sample cache entries. */ diff --git a/src/pulse/mainloop.h b/src/pulse/mainloop.h index 3a03ac9a..4a83ebe8 100644 --- a/src/pulse/mainloop.h +++ b/src/pulse/mainloop.h @@ -50,7 +50,7 @@ struct pollfd; * * -# Prepare - Build a list of file descriptors * that need to be monitored and calculate the next timeout. - * -# Poll - Execute the actuall poll() system call. + * -# Poll - Execute the actual poll() system call. * -# Dispatch - Dispatch any events that have fired. * * When using the main loop, the application can either execute each diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h index d5f5bc04..2e7e5ad0 100644 --- a/src/pulse/proplist.h +++ b/src/pulse/proplist.h @@ -259,7 +259,7 @@ int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t * /** Update mode enum for pa_proplist_update(). \since 0.9.11 */ typedef enum pa_update_mode { PA_UPDATE_SET - /**< Replace the entirey property list with the new one. Don't keep + /**< Replace the entire property list with the new one. Don't keep * any of the old data around */, PA_UPDATE_MERGE diff --git a/src/pulse/pulseaudio.h b/src/pulse/pulseaudio.h index 5086783d..aa369e69 100644 --- a/src/pulse/pulseaudio.h +++ b/src/pulse/pulseaudio.h @@ -59,7 +59,7 @@ * \section intro_sec Introduction * * This document describes the client API for the PulseAudio sound - * server. The API comes in two flavours to accomodate different styles + * server. The API comes in two flavours to accommodate different styles * of applications and different needs in complexity: * * \li The complete but somewhat complicated to use asynchronous API diff --git a/src/pulse/sample.h b/src/pulse/sample.h index aef34b6b..138f13cf 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -71,7 +71,7 @@ * * \section chan_sec Channels * - * PulseAudio supports up to 32 individiual channels. The order of the + * PulseAudio supports up to 32 individual channels. The order of the * channels is up to the application, but they must be continous. To map * channels to speakers, see \ref channelmap. * @@ -221,7 +221,7 @@ typedef enum pa_sample_format { #define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE /** \cond fulldocs */ -/* Allow clients to check with #ifdef for thse sample formats */ +/* Allow clients to check with #ifdef for these sample formats */ #define PA_SAMPLE_U8 PA_SAMPLE_U8 #define PA_SAMPLE_ALAW PA_SAMPLE_ALAW #define PA_SAMPLE_ULAW PA_SAMPLE_ULAW diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 16342cad..339a89e5 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -380,20 +380,13 @@ static void check_smoother_status(pa_stream *s, pa_bool_t aposteriori, pa_bool_t x -= s->timing_info.transport_usec; else x += s->timing_info.transport_usec; - - if (s->direction == PA_STREAM_PLAYBACK) - /* it takes a while until the pause/resume is actually - * audible */ - x += s->timing_info.sink_usec; - else - /* Data froma while back will be dropped */ - x -= s->timing_info.source_usec; } 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); + pa_smoother_resume(s->smoother, x, TRUE); + /* Please note that we have no idea if playback actually started * if prebuf is non-zero! */ @@ -729,7 +722,7 @@ void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tag s->requested_bytes += bytes; if (s->requested_bytes > 0 && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); + s->write_callback(s, (size_t) s->requested_bytes, s->write_userdata); finish: pa_context_unref(c); @@ -826,7 +819,7 @@ static void create_stream_complete(pa_stream *s) { pa_stream_set_state(s, PA_STREAM_READY); if (s->requested_bytes > 0 && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); + s->write_callback(s, (size_t) s->requested_bytes, s->write_userdata); if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { struct timeval tv; @@ -874,6 +867,7 @@ static void automatic_buffer_attr(pa_stream *s, pa_buffer_attr *attr, const pa_s void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_stream *s = userdata; + uint32_t requested_bytes; pa_assert(pd); pa_assert(s); @@ -893,11 +887,13 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, if (pa_tagstruct_getu32(t, &s->channel) < 0 || s->channel == PA_INVALID_INDEX || ((s->direction != PA_STREAM_UPLOAD) && (pa_tagstruct_getu32(t, &s->stream_index) < 0 || s->stream_index == PA_INVALID_INDEX)) || - ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0)) { + ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &requested_bytes) < 0)) { pa_context_fail(s->context, PA_ERR_PROTOCOL); goto finish; } + s->requested_bytes = (int64_t) requested_bytes; + if (s->context->version >= 9) { if (s->direction == PA_STREAM_PLAYBACK) { if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || @@ -1061,14 +1057,17 @@ static int create_stream( if (flags & PA_STREAM_INTERPOLATE_TIMING) { pa_usec_t x; - if (s->smoother) - pa_smoother_free(s->smoother); - - s->smoother = pa_smoother_new(SMOOTHER_ADJUST_TIME, SMOOTHER_HISTORY_TIME, !(flags & PA_STREAM_NOT_MONOTONIC), SMOOTHER_MIN_HISTORY); - x = pa_rtclock_usec(); - pa_smoother_set_time_offset(s->smoother, x); - pa_smoother_pause(s->smoother, x); + + pa_assert(!s->smoother); + s->smoother = pa_smoother_new( + SMOOTHER_ADJUST_TIME, + SMOOTHER_HISTORY_TIME, + !(flags & PA_STREAM_NOT_MONOTONIC), + TRUE, + SMOOTHER_MIN_HISTORY, + x, + TRUE); } if (!dev) @@ -1258,12 +1257,9 @@ int pa_stream_write( if (free_cb && pa_pstream_get_shm(s->context->pstream)) free_cb((void*) data); - if (length < s->requested_bytes) - s->requested_bytes -= (uint32_t) length; - else - s->requested_bytes = 0; - - /* FIXME!!! ^^^ will break when offset is != 0 and mode is not RELATIVE*/ + /* This is obviously wrong since we ignore the seeking index . But + * that's OK, the server side applies the same error */ + s->requested_bytes -= (seek == PA_SEEK_RELATIVE ? offset : 0) + (int64_t) length; if (s->direction == PA_STREAM_PLAYBACK) { @@ -1359,7 +1355,7 @@ size_t pa_stream_writable_size(pa_stream *s) { PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); - return s->requested_bytes; + return s->requested_bytes > 0 ? (size_t) s->requested_bytes : 0; } size_t pa_stream_readable_size(pa_stream *s) { @@ -1623,7 +1619,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, pa_smoother_put(o->stream->smoother, u, calc_time(o->stream, TRUE)); if (i->playing) - pa_smoother_resume(o->stream->smoother, x); + pa_smoother_resume(o->stream->smoother, x, TRUE); } } diff --git a/src/pulse/subscribe.h b/src/pulse/subscribe.h index a93510ad..44ed24ae 100644 --- a/src/pulse/subscribe.h +++ b/src/pulse/subscribe.h @@ -35,7 +35,7 @@ * \section overv_sec Overview * * The application can be notified, asynchronously, whenever the internal - * layout of the server changes. Possible notifications are desribed in the + * layout of the server changes. Possible notifications are described in the * \ref pa_subscription_event_type and \ref pa_subscription_mask * enumerations. * diff --git a/src/pulse/timeval.h b/src/pulse/timeval.h index 2b3faf16..651da953 100644 --- a/src/pulse/timeval.h +++ b/src/pulse/timeval.h @@ -60,7 +60,7 @@ struct timeval *pa_gettimeofday(struct timeval *tv); * structs. */ pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) PA_GCC_PURE; -/** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ +/** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwise */ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) PA_GCC_PURE; /** Return the time difference between now and the specified timestamp */ diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index b122feee..1e31d076 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -190,7 +190,7 @@ int pa_authkey_load_auto(const char *fn, void *data, size_t length) { return pa_authkey_load(p, data, length); } -/* Store the specified cookie in the speicified cookie file */ +/* Store the specified cookie in the specified cookie file */ int pa_authkey_save(const char *fn, const void *data, size_t length) { int fd = -1; int unlock = 0, ret = -1; diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 4b093c0e..56253391 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -326,7 +326,7 @@ ssize_t pa_write(int fd, const void *buf, size_t count, int *type) { } /** Calls read() in a loop. Makes sure that as much as 'size' bytes, - * unless EOF is reached or an error occured */ + * unless EOF is reached or an error occurred */ ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) { ssize_t ret = 0; int _type; @@ -1242,7 +1242,7 @@ int pa_lock_lockfile(const char *fn) { goto fail; } - /* Check wheter the file has been removed meanwhile. When yes, + /* Check whether the file has been removed meanwhile. When yes, * restart this loop, otherwise, we're done */ if (st.st_nlink >= 1) break; diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index 750d73b7..60ea9c59 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -262,7 +262,7 @@ void pa_log_levelv_meta( /* We don't use dynamic memory allocation here to minimize the hit * in RT threads */ - char text[4096], location[128], timestamp[32]; + char text[16*1024], location[128], timestamp[32]; pa_assert(level < PA_LOG_LEVEL_MAX); pa_assert(format); diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index e6e7b736..d12d13a8 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -601,7 +601,7 @@ size_t pa_memblockq_missing(pa_memblockq *bq) { return l >= bq->minreq ? l : 0; } -void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { +void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek, pa_bool_t account) { int64_t old, delta; pa_assert(bq); @@ -628,12 +628,14 @@ void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { delta = bq->write_index - old; - if (delta >= (int64_t) bq->requested) { - delta -= (int64_t) bq->requested; - bq->requested = 0; - } else if (delta >= 0) { - bq->requested -= (size_t) delta; - delta = 0; + if (account) { + if (delta >= (int64_t) bq->requested) { + delta -= (int64_t) bq->requested; + bq->requested = 0; + } else if (delta >= 0) { + bq->requested -= (size_t) delta; + delta = 0; + } } bq->missing -= delta; @@ -895,7 +897,7 @@ int pa_memblockq_splice(pa_memblockq *bq, pa_memblockq *source) { pa_memblock_unref(chunk.memblock); } else - pa_memblockq_seek(bq, (int64_t) chunk.length, PA_SEEK_RELATIVE); + pa_memblockq_seek(bq, (int64_t) chunk.length, PA_SEEK_RELATIVE, TRUE); pa_memblockq_drop(bq, chunk.length); } diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index e315b831..146d261b 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -85,7 +85,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk); int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk); /* Manipulate the write pointer */ -void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek); +void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek, pa_bool_t account); /* Return a copy of the next memory chunk in the queue. It is not * removed from the queue. There are two reasons this function might diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c index c5cd7fe7..5b531220 100644 --- a/src/pulsecore/parseaddr.c +++ b/src/pulsecore/parseaddr.c @@ -87,13 +87,15 @@ int pa_parse_address(const char *name, pa_parsed_address *ret_p) { ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO; if (*name == '{') { - char hn[256], *pfx; - /* The URL starts with a host specification for detecting local connections */ + char *id, *pfx; - if (!pa_get_host_name(hn, sizeof(hn))) + /* The URL starts with a host id for detecting local connections */ + if (!(id = pa_machine_id())) return -1; - pfx = pa_sprintf_malloc("{%s}", hn); + pfx = pa_sprintf_malloc("{%s}", id); + pa_xfree(id); + if (!pa_startswith(name, pfx)) { pa_xfree(pfx); /* Not local */ diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index e11d7a6c..59e5d80e 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -86,7 +86,15 @@ typedef struct record_stream { pa_bool_t early_requests:1; pa_buffer_attr buffer_attr; - pa_usec_t source_latency; + + pa_atomic_t on_the_fly; + pa_usec_t configured_source_latency; + size_t drop_initial; + + /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */ + size_t on_the_fly_snapshot; + pa_usec_t current_monitor_latency; + pa_usec_t current_source_latency; } record_stream; PA_DECLARE_CLASS(record_stream); @@ -119,12 +127,14 @@ typedef struct playback_stream { uint32_t syncid; pa_atomic_t missing; - pa_usec_t sink_latency; + pa_usec_t configured_sink_latency; pa_buffer_attr buffer_attr; /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */ int64_t read_index, write_index; size_t render_memblockq_length; + pa_usec_t current_sink_latency; + uint64_t playing_for, underrun_for; } playback_stream; PA_DECLARE_CLASS(playback_stream); @@ -182,6 +192,10 @@ struct pa_native_protocol { }; enum { + SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX +}; + +enum { SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */ SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */ SINK_INPUT_MESSAGE_FLUSH, @@ -230,6 +244,7 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o); static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl); static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); +static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -474,6 +489,10 @@ static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, i case RECORD_STREAM_MESSAGE_POST_DATA: + /* We try to keep up to date with how many bytes are + * currently on the fly */ + pa_atomic_sub(&s->on_the_fly, chunk->length); + if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { /* pa_log_warn("Failed to push data into output queue."); */ return -1; @@ -537,29 +556,29 @@ static void fix_record_buffer_attr_pre(record_stream *s) { /* Ok, the user didn't ask us to adjust the latency, hence we * don't */ - source_usec = 0; + source_usec = (pa_usec_t) -1; } - if (source_usec > 0) - s->source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec); + if (source_usec != (pa_usec_t) -1) + s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec); else - s->source_latency = 0; + s->configured_source_latency = 0; if (s->early_requests) { /* Ok, we didn't necessarily get what we were asking for, so * let's tell the user */ - fragsize_usec = s->source_latency; + fragsize_usec = s->configured_source_latency; } else if (s->adjust_latency) { /* Now subtract what we actually got */ - if (fragsize_usec >= s->source_latency*2) - fragsize_usec -= s->source_latency; + if (fragsize_usec >= s->configured_source_latency*2) + fragsize_usec -= s->configured_source_latency; else - fragsize_usec = s->source_latency; + fragsize_usec = s->configured_source_latency; } if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) != @@ -645,7 +664,9 @@ static record_stream* record_stream_new( s->buffer_attr = *attr; s->adjust_latency = adjust_latency; s->early_requests = early_requests; + pa_atomic_store(&s->on_the_fly, 0); + s->source_output->parent.process_msg = source_output_process_msg; s->source_output->push = source_output_push_cb; s->source_output->kill = source_output_kill_cb; s->source_output->get_latency = source_output_get_latency_cb; @@ -675,9 +696,9 @@ static record_stream* record_stream_new( pa_idxset_put(c->record_streams, s, &s->index); pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms", - ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->source_latency) / PA_USEC_PER_MSEC, + ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC, (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC, - (double) s->source_latency / PA_USEC_PER_MSEC); + (double) s->configured_source_latency / PA_USEC_PER_MSEC); pa_source_output_put(s->source_output); return s; @@ -738,24 +759,21 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, switch (code) { case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: { pa_tagstruct *t; - uint32_t l = 0; + int l = 0; for (;;) { - if ((l = (uint32_t) pa_atomic_load(&s->missing)) <= 0) - break; + if ((l = pa_atomic_load(&s->missing)) <= 0) + return 0; - if (pa_atomic_cmpxchg(&s->missing, (int) l, 0)) + if (pa_atomic_cmpxchg(&s->missing, l, 0)) break; } - if (l <= 0) - break; - t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ pa_tagstruct_putu32(t, s->index); - pa_tagstruct_putu32(t, l); + pa_tagstruct_putu32(t, (uint32_t) l); pa_pstream_send_tagstruct(s->connection->pstream, t); /* pa_log("Requesting %lu bytes", (unsigned long) l); */ @@ -820,7 +838,7 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, pa_tagstruct_putu32(t, s->buffer_attr.tlength); pa_tagstruct_putu32(t, s->buffer_attr.prebuf); pa_tagstruct_putu32(t, s->buffer_attr.minreq); - pa_tagstruct_put_usec(t, s->sink_latency); + pa_tagstruct_put_usec(t, s->configured_sink_latency); pa_pstream_send_tagstruct(s->connection->pstream, t); break; @@ -918,14 +936,14 @@ static void fix_playback_buffer_attr(playback_stream *s) { pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq."); } - s->sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec); + s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec); if (s->early_requests) { /* Ok, we didn't necessarily get what we were asking for, so * let's tell the user */ - minreq_usec = s->sink_latency; + minreq_usec = s->configured_sink_latency; } else if (s->adjust_latency) { @@ -933,14 +951,14 @@ static void fix_playback_buffer_attr(playback_stream *s) { * let's subtract from what we asked for for the remaining * buffer space */ - if (tlength_usec >= s->sink_latency) - tlength_usec -= s->sink_latency; + if (tlength_usec >= s->configured_sink_latency) + tlength_usec -= s->configured_sink_latency; } /* FIXME: This is actually larger than necessary, since not all of * the sink latency is actually rewritable. */ - if (tlength_usec < s->sink_latency + 2*minreq_usec) - tlength_usec = s->sink_latency + 2*minreq_usec; + if (tlength_usec < s->configured_sink_latency + 2*minreq_usec) + tlength_usec = s->configured_sink_latency + 2*minreq_usec; if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) != pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec)) @@ -1086,10 +1104,10 @@ static playback_stream* playback_stream_new( pa_idxset_put(c->output_streams, s, &s->index); pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms", - ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->sink_latency) / PA_USEC_PER_MSEC, + ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC, (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC, (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC, - (double) s->sink_latency / PA_USEC_PER_MSEC); + (double) s->configured_sink_latency / PA_USEC_PER_MSEC); pa_sink_input_put(s->sink_input); return s; @@ -1097,7 +1115,8 @@ static playback_stream* playback_stream_new( /* Called from IO context */ static void playback_stream_request_bytes(playback_stream *s) { - size_t m, previous_missing, minreq; + size_t m, minreq; + int previous_missing; playback_stream_assert_ref(s); @@ -1108,11 +1127,11 @@ static void playback_stream_request_bytes(playback_stream *s) { /* pa_log("request_bytes(%lu)", (unsigned long) m); */ - previous_missing = (size_t) pa_atomic_add(&s->missing, (int) m); + previous_missing = pa_atomic_add(&s->missing, (int) m); minreq = pa_memblockq_get_minreq(s->memblockq); if (pa_memblockq_prebuf_active(s->memblockq) || - (previous_missing < minreq && previous_missing+m >= minreq)) + (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq)) pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); } @@ -1297,7 +1316,12 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int int64_t windex; windex = pa_memblockq_get_write_index(s->memblockq); - pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata)); + + /* The client side is incapable of accounting correctly + * for seeks of a type != PA_SEEK_RELATIVE. We need to be + * able to deal with that. */ + + pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE); handle_seek(s, windex); return 0; @@ -1315,7 +1339,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { pa_log_warn("Failed to push data into queue"); pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL); - pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE); + pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE); } handle_seek(s, windex); @@ -1384,10 +1408,14 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int } case SINK_INPUT_MESSAGE_UPDATE_LATENCY: - + /* Atomically get a snapshot of all timing parameters... */ s->read_index = pa_memblockq_get_read_index(s->memblockq); s->write_index = pa_memblockq_get_write_index(s->memblockq); s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq); + s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink); + s->underrun_for = s->sink_input->thread_info.underrun_for; + s->playing_for = s->sink_input->thread_info.playing_for; + return 0; case PA_SINK_INPUT_MESSAGE_SET_STATE: { @@ -1600,7 +1628,7 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { pa_tagstruct_putu32(t, s->buffer_attr.tlength); pa_tagstruct_putu32(t, s->buffer_attr.prebuf); pa_tagstruct_putu32(t, s->buffer_attr.minreq); - pa_tagstruct_put_usec(t, s->sink_latency); + pa_tagstruct_put_usec(t, s->configured_sink_latency); } pa_pstream_send_tagstruct(s->connection->pstream, t); @@ -1609,6 +1637,27 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { /*** source_output callbacks ***/ /* Called from thread context */ +static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { + pa_source_output *o = PA_SOURCE_OUTPUT(_o); + record_stream *s; + + pa_source_output_assert_ref(o); + s = RECORD_STREAM(o->userdata); + record_stream_assert_ref(s); + + switch (code) { + case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY: + /* Atomically get a snapshot of all timing parameters... */ + s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0; + s->current_source_latency = pa_source_get_latency_within_thread(o->source); + s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly); + return 0; + } + + return pa_source_output_process_msg(_o, code, userdata, offset, chunk); +} + +/* Called from thread context */ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { record_stream *s; @@ -1617,6 +1666,7 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) record_stream_assert_ref(s); pa_assert(chunk); + pa_atomic_add(&s->on_the_fly, chunk->length); pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); } @@ -1712,7 +1762,7 @@ static void source_output_moving_cb(pa_source_output *o, pa_source *dest) { if (s->connection->version >= 13) { pa_tagstruct_putu32(t, s->buffer_attr.maxlength); pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - pa_tagstruct_put_usec(t, s->source_latency); + pa_tagstruct_put_usec(t, s->configured_source_latency); } pa_pstream_send_tagstruct(s->connection->pstream, t); @@ -1935,7 +1985,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u } if (c->version >= 13) - pa_tagstruct_put_usec(reply, s->sink_latency); + pa_tagstruct_put_usec(reply, s->configured_sink_latency); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2182,7 +2232,7 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin } if (c->version >= 13) - pa_tagstruct_put_usec(reply, s->source_latency); + pa_tagstruct_put_usec(reply, s->configured_source_latency); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -2469,7 +2519,6 @@ static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uin playback_stream *s; struct timeval tv, now; uint32_t idx; - pa_usec_t latency; pa_native_connection_assert_ref(c); pa_assert(t); @@ -2485,25 +2534,27 @@ static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uin s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); - CHECK_VALIDITY(c->pstream, pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0, tag, PA_ERR_NOENTITY) - - reply = reply_new(tag); - - latency = pa_sink_get_latency(s->sink_input->sink); - latency += pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sample_spec); - pa_tagstruct_put_usec(reply, latency); + /* Get an atomic snapshot of all timing parameters */ + pa_assert_se(pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0); + reply = reply_new(tag); + pa_tagstruct_put_usec(reply, + s->current_sink_latency + + pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sample_spec)); pa_tagstruct_put_usec(reply, 0); - pa_tagstruct_put_boolean(reply, s->sink_input->thread_info.playing_for > 0); + pa_tagstruct_put_boolean(reply, + s->playing_for > 0 && + pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING && + pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING); pa_tagstruct_put_timeval(reply, &tv); pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); pa_tagstruct_puts64(reply, s->write_index); pa_tagstruct_puts64(reply, s->read_index); if (c->version >= 13) { - pa_tagstruct_putu64(reply, s->sink_input->thread_info.underrun_for); - pa_tagstruct_putu64(reply, s->sink_input->thread_info.playing_for); + pa_tagstruct_putu64(reply, s->underrun_for); + pa_tagstruct_putu64(reply, s->playing_for); } pa_pstream_send_tagstruct(c->pstream, reply); @@ -2530,10 +2581,17 @@ static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint3 s = pa_idxset_get_by_index(c->record_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); + /* Get an atomic snapshot of all timing parameters */ + pa_assert_se(pa_asyncmsgq_send(s->source_output->source->asyncmsgq, PA_MSGOBJECT(s->source_output), SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0); + reply = reply_new(tag); - pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0); - pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source)); - pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING); + pa_tagstruct_put_usec(reply, s->current_monitor_latency); + pa_tagstruct_put_usec(reply, + s->current_source_latency + + pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->sample_spec)); + pa_tagstruct_put_boolean(reply, + pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING && + pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING); pa_tagstruct_put_timeval(reply, &tv); pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); @@ -3511,7 +3569,7 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u pa_tagstruct_putu32(reply, s->buffer_attr.minreq); if (c->version >= 13) - pa_tagstruct_put_usec(reply, s->sink_latency); + pa_tagstruct_put_usec(reply, s->configured_sink_latency); } else { record_stream *s; @@ -3547,7 +3605,7 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u pa_tagstruct_putu32(reply, s->buffer_attr.fragsize); if (c->version >= 13) - pa_tagstruct_put_usec(reply, s->source_latency); + pa_tagstruct_put_usec(reply, s->configured_source_latency); } pa_pstream_send_tagstruct(c->pstream, reply); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 0ed16dd8..1fdb3fa6 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -631,7 +631,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p * data, so let's just hand out silence */ pa_atomic_store(&i->thread_info.drained, 1); - pa_memblockq_seek(i->thread_info.render_memblockq, (int64_t) slength, PA_SEEK_RELATIVE); + pa_memblockq_seek(i->thread_info.render_memblockq, (int64_t) slength, PA_SEEK_RELATIVE, TRUE); i->thread_info.playing_for = 0; if (i->thread_info.underrun_for != (uint64_t) -1) i->thread_info.underrun_for += ilength; @@ -776,7 +776,7 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam if (amount > 0) /* Ok, now update the write pointer */ - pa_memblockq_seek(i->thread_info.render_memblockq, - ((int64_t) amount), PA_SEEK_RELATIVE); + pa_memblockq_seek(i->thread_info.render_memblockq, - ((int64_t) amount), PA_SEEK_RELATIVE, TRUE); if (i->thread_info.rewrite_flush) pa_memblockq_silence(i->thread_info.render_memblockq); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index e7a555df..0dd5e9aa 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -121,7 +121,7 @@ struct pa_sink_input { * changes. Called from IO context. */ void (*update_max_rewind) (pa_sink_input *i, size_t nbytes); /* may be NULL */ - /* Called whenever the maxiumum request size of the sink + /* Called whenever the maximum request size of the sink * changes. Called from IO context. */ void (*update_max_request) (pa_sink_input *i, size_t nbytes); /* may be NULL */ diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 73ad247d..a0f0ea7e 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -958,6 +958,32 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) { return usec; } +/* Called from IO thread */ +pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) { + pa_usec_t usec = 0; + pa_msgobject *o; + + pa_sink_assert_ref(s); + pa_assert(PA_SINK_IS_LINKED(s->thread_info.state)); + + /* The returned value is supposed to be in the time domain of the sound card! */ + + if (s->thread_info.state == PA_SINK_SUSPENDED) + return 0; + + if (!(s->flags & PA_SINK_LATENCY)) + return 0; + + o = PA_MSGOBJECT(s); + + /* We probably should make this a proper vtable callback instead of going through process_msg() */ + + if (o->process_msg(o, PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) + return -1; + + return usec; +} + /* Called from main thread */ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) { pa_sink_input *i; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 7d1e11ef..634bf3ef 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -295,4 +295,6 @@ void pa_sink_request_rewind(pa_sink*s, size_t nbytes); void pa_sink_invalidate_requested_latency(pa_sink *s); +pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s); + #endif diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index 6a4405e3..8147b27f 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -467,11 +467,13 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port)); } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) { - char hn[256]; - if (!pa_get_host_name(hn, sizeof(hn))) + char *id; + + if (!(id = pa_machine_id())) return NULL; - pa_snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port)); + pa_snprintf(c, l, "{%s}tcp6:localhost:%u", id, (unsigned) ntohs(sa.sin6_port)); + pa_xfree(id); } else { char ip[INET6_ADDRSTRLEN]; @@ -503,11 +505,13 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { pa_snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port)); } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) { - char hn[256]; - if (!pa_get_host_name(hn, sizeof(hn))) + char *id; + + if (!(id = pa_machine_id())) return NULL; - pa_snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port)); + pa_snprintf(c, l, "{%s}tcp:localhost:%u", id, (unsigned) ntohs(sa.sin_port)); + pa_xfree(id); } else { char ip[INET_ADDRSTRLEN]; @@ -523,15 +527,15 @@ char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) { } case SOCKET_SERVER_UNIX: { - char hn[256]; + char *id; if (!s->filename) return NULL; - if (!pa_get_host_name(hn, sizeof(hn))) + if (!(id = pa_machine_id())) return NULL; - pa_snprintf(c, l, "{%s}unix:%s", hn, s->filename); + pa_snprintf(c, l, "{%s}unix:%s", id, s->filename); return c; } diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 27f24cd1..1c37be93 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -434,7 +434,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { if (pa_memblockq_push(o->thread_info.delay_memblockq, chunk) < 0) { pa_log_debug("Delay queue overflow!"); - pa_memblockq_seek(o->thread_info.delay_memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE); + pa_memblockq_seek(o->thread_info.delay_memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE); } limit = o->process_rewind ? 0 : o->source->thread_info.max_rewind; diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 1c3377be..252e23ab 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -617,6 +617,32 @@ pa_usec_t pa_source_get_latency(pa_source *s) { return usec; } +/* Called from IO thread */ +pa_usec_t pa_source_get_latency_within_thread(pa_source *s) { + pa_usec_t usec = 0; + pa_msgobject *o; + + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); + + /* The returned value is supposed to be in the time domain of the sound card! */ + + if (s->thread_info.state == PA_SOURCE_SUSPENDED) + return 0; + + if (!(s->flags & PA_SOURCE_LATENCY)) + return 0; + + o = PA_MSGOBJECT(s); + + /* We probably should make this a proper vtable callback instead of going through process_msg() */ + + if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) + return -1; + + return usec; +} + /* Called from main thread */ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) { pa_cvolume old_virtual_volume; diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 210f5340..652783ef 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -267,5 +267,6 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten /*** To be called exclusively by source output drivers, from IO context */ void pa_source_invalidate_requested_latency(pa_source *s); +pa_usec_t pa_source_get_latency_within_thread(pa_source *s); #endif diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index 65621948..55ac8687 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -78,17 +78,26 @@ struct pa_smoother { /* Cached parameters for our interpolation polynomial y=ax^3+b^2+cx */ double a, b, c; - pa_bool_t abc_valid; + pa_bool_t abc_valid:1; pa_bool_t monotonic:1; pa_bool_t paused:1; + pa_bool_t smoothing:1; /* If FALSE we skip the polonyomial interpolation step */ pa_usec_t pause_time; unsigned min_history; }; -pa_smoother* pa_smoother_new(pa_usec_t adjust_time, pa_usec_t history_time, pa_bool_t monotonic, unsigned min_history) { +pa_smoother* pa_smoother_new( + pa_usec_t adjust_time, + pa_usec_t history_time, + pa_bool_t monotonic, + pa_bool_t smoothing, + unsigned min_history, + pa_usec_t time_offset, + pa_bool_t paused) { + pa_smoother *s; pa_assert(adjust_time > 0); @@ -116,9 +125,13 @@ pa_smoother* pa_smoother_new(pa_usec_t adjust_time, pa_usec_t history_time, pa_b 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; + return s; } @@ -278,7 +291,7 @@ static void estimate(pa_smoother *s, pa_usec_t x, pa_usec_t *y, double *deriv) { pa_assert(s); pa_assert(y); - if (x >= s->px) { + if (!s->smoothing || x >= s->px) { int64_t t; /* The requested point is right of the point where we wanted @@ -348,7 +361,6 @@ void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y) { * we can adjust our position smoothly from this one */ estimate(s, x, &ney, &nde); s->ex = x; s->ey = ney; s->de = nde; - s->ry = y; } @@ -359,8 +371,13 @@ void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y) { s->dp = avg_gradient(s, x); /* And calculate when we want to be on track again */ - s->px = s->ex + s->adjust_time; - s->py = s->ry + (pa_usec_t) llrint(s->dp * (double) s->adjust_time); + if (s->smoothing) { + s->px = s->ex + s->adjust_time; + s->py = s->ry + (pa_usec_t) llrint(s->dp * (double) s->adjust_time); + } else { + s->px = s->ex; + s->py = s->ry; + } s->abc_valid = FALSE; @@ -420,7 +437,7 @@ void pa_smoother_pause(pa_smoother *s, pa_usec_t x) { s->pause_time = x; } -void pa_smoother_resume(pa_smoother *s, pa_usec_t x) { +void pa_smoother_resume(pa_smoother *s, pa_usec_t x, pa_bool_t fix_now) { pa_assert(s); if (!s->paused) @@ -433,6 +450,16 @@ void pa_smoother_resume(pa_smoother *s, pa_usec_t x) { s->paused = FALSE; s->time_offset += x - s->pause_time; + + if (fix_now) + pa_smoother_fix_now(s); +} + +void pa_smoother_fix_now(pa_smoother *s) { + pa_assert(s); + + s->px = s->ex; + s->py = s->ry; } pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay) { diff --git a/src/pulsecore/time-smoother.h b/src/pulsecore/time-smoother.h index 2051e640..5244a7e7 100644 --- a/src/pulsecore/time-smoother.h +++ b/src/pulsecore/time-smoother.h @@ -27,7 +27,15 @@ typedef struct pa_smoother pa_smoother; -pa_smoother* pa_smoother_new(pa_usec_t x_adjust_time, pa_usec_t x_history_time, pa_bool_t monotonic, unsigned min_history); +pa_smoother* pa_smoother_new( + pa_usec_t x_adjust_time, + pa_usec_t x_history_time, + pa_bool_t monotonic, + pa_bool_t smoothing, + unsigned min_history, + pa_usec_t x_offset, + pa_bool_t paused); + void pa_smoother_free(pa_smoother* s); /* Adds a new value to our dataset. x = local/system time, y = remote time */ @@ -42,8 +50,10 @@ pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay); 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); +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_fix_now(pa_smoother *s); + #endif diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index dd24e829..c103a493 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -36,6 +36,8 @@ #include <pulsecore/thread.h> +#define INTERPOLATE + static pa_context *context = NULL; static pa_stream *stream = NULL; static pa_mainloop_api *mainloop_api = NULL; @@ -58,6 +60,15 @@ static void stream_read_cb(pa_stream *p, size_t nbytes, void *userdata) { } } +static void stream_latency_cb(pa_stream *p, void *userdata) { +#ifndef INTERPOLATE + pa_operation *o; + + o = pa_stream_update_timing_info(p, NULL, NULL); + pa_operation_unref(o); +#endif +} + /* This is called whenever the context status changes */ static void context_state_callback(pa_context *c, void *userdata) { assert(c); @@ -69,6 +80,7 @@ static void context_state_callback(pa_context *c, void *userdata) { break; case PA_CONTEXT_READY: { + pa_stream_flags_t flags = PA_STREAM_AUTO_TIMING_UPDATE; static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, @@ -76,19 +88,25 @@ static void context_state_callback(pa_context *c, void *userdata) { .channels = 2 }; +#ifdef INTERPOLATE + flags |= PA_STREAM_INTERPOLATE_TIMING; +#endif + fprintf(stderr, "Connection established.\n"); stream = pa_stream_new(c, "interpol-test", &ss, NULL); assert(stream); if (playback) { - pa_assert_se(pa_stream_connect_playback(stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) == 0); + pa_assert_se(pa_stream_connect_playback(stream, NULL, NULL, 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, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE) == 0); + pa_assert_se(pa_stream_connect_record(stream, NULL, NULL, flags) == 0); pa_stream_set_read_callback(stream, stream_read_cb, NULL); } + pa_stream_set_latency_update_callback(stream, stream_latency_cb, NULL); + break; } @@ -109,6 +127,8 @@ int main(int argc, char *argv[]) { pa_usec_t old_t = 0, old_rtc = 0; pa_bool_t corked = FALSE; + pa_log_set_level(PA_LOG_DEBUG); + playback = argc <= 1 || !pa_streq(argv[1], "-r"); /* Set up a new main loop */ @@ -162,11 +182,12 @@ int main(int argc, char *argv[]) { pa_bool_t cork_now; rtc = pa_timeval_diff(&now, &start); - printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\t%u\n", k, + printf("%i\t%llu\t%llu\t%llu\t%llu\t%lli\t%u\t%u\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); diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index 127fb197..ec3f5426 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -105,45 +105,45 @@ int main(int argc, char *argv[]) { ret = pa_memblockq_push(bq, &chunk4); assert(ret == 0); - pa_memblockq_seek(bq, -6, 0); + pa_memblockq_seek(bq, -6, 0, TRUE); ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); - pa_memblockq_seek(bq, -2, 0); + pa_memblockq_seek(bq, -2, 0, TRUE); ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); - pa_memblockq_seek(bq, -10, 0); + pa_memblockq_seek(bq, -10, 0, TRUE); ret = pa_memblockq_push(bq, &chunk4); assert(ret == 0); - pa_memblockq_seek(bq, 10, 0); + pa_memblockq_seek(bq, 10, 0, TRUE); ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); - pa_memblockq_seek(bq, -6, 0); + pa_memblockq_seek(bq, -6, 0, TRUE); ret = pa_memblockq_push(bq, &chunk2); assert(ret == 0); /* Test splitting */ - pa_memblockq_seek(bq, -12, 0); + pa_memblockq_seek(bq, -12, 0, TRUE); ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); - pa_memblockq_seek(bq, 20, 0); + pa_memblockq_seek(bq, 20, 0, TRUE); /* Test merging */ ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); - pa_memblockq_seek(bq, -2, 0); + pa_memblockq_seek(bq, -2, 0, TRUE); chunk3.index += 2; chunk3.length -= 2; ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); - pa_memblockq_seek(bq, 30, PA_SEEK_RELATIVE); + pa_memblockq_seek(bq, 30, PA_SEEK_RELATIVE, TRUE); dump(bq); diff --git a/src/tests/smoother-test.c b/src/tests/smoother-test.c index 798dfed5..2cc9f58b 100644 --- a/src/tests/smoother-test.c +++ b/src/tests/smoother-test.c @@ -45,10 +45,12 @@ int main(int argc, char*argv[]) { srand(0); + pa_log_set_level(PA_LOG_DEBUG); + for (m = 0, u = 0; u < PA_ELEMENTSOF(msec); u+= 2) { msec[u] = m+1 + (rand() % 100) - 50; - msec[u+1] = m + (rand() % 2000) - 1000; + msec[u+1] = m + (rand() % 2000) - 1000 + 5000; m += rand() % 100; @@ -59,7 +61,7 @@ int main(int argc, char*argv[]) { msec[u+1] = 0; } - s = pa_smoother_new(700*PA_USEC_PER_MSEC, 2000*PA_USEC_PER_MSEC, TRUE, 6); + s = pa_smoother_new(700*PA_USEC_PER_MSEC, 2000*PA_USEC_PER_MSEC, FALSE, TRUE, 6, 0, TRUE); for (x = 0, u = 0; x < PA_USEC_PER_SEC * 10; x += PA_USEC_PER_MSEC) { @@ -67,6 +69,8 @@ int main(int argc, char*argv[]) { pa_smoother_put(s, (pa_usec_t) msec[u] * PA_USEC_PER_MSEC, (pa_usec_t) msec[u+1] * PA_USEC_PER_MSEC); printf("%i\t\t%i\n", msec[u], msec[u+1]); u += 2; + + pa_smoother_resume(s, (pa_usec_t) msec[u] * PA_USEC_PER_MSEC, TRUE); } printf("%llu\t%llu\n", (unsigned long long) (x/PA_USEC_PER_MSEC), (unsigned long long) (pa_smoother_get(s, x)/PA_USEC_PER_MSEC)); |