From cdfcf6654cb826682812e9d1096dcfbac77900eb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 3 Apr 2008 13:40:55 +0000 Subject: [PATCH] - deprecate autoload stuff - allow setting of the requested latency of a sink input/source output before _put() is called - allow sinks/sources to have a "minimal" latency which applies to all requested latencies by sink inputs/source outputs - add new client library flags PA_STREAM_ADJUST_LATENCY, PA_STREAM_START_MUTED - allow client library to fill in 0 to buffer_attr fields - update module-alsa-source following module-alsa-sink - other cleanups and fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2215 fefdeb5f-60dc-0310-8127-8f9354f1896f --- PROTOCOL | 11 +- src/modules/module-alsa-sink.c | 77 +++++++------- src/modules/module-alsa-source.c | 206 +++++++++++++++++++++++++++++--------- src/modules/oss-util.c | 4 +- src/modules/oss-util.h | 4 +- src/pulse/def.h | 73 ++++++++++++-- src/pulse/introspect.c | 36 ++++++- src/pulse/introspect.h | 210 +++++++++++++++++++++++++-------------- src/pulse/stream.c | 63 ++++++++---- src/pulsecore/cli-command.c | 16 ++- src/pulsecore/macro.h | 13 +++ src/pulsecore/memblockq.c | 24 ++--- src/pulsecore/module.c | 6 +- src/pulsecore/module.h | 4 +- src/pulsecore/protocol-native.c | 160 +++++++++++++++++++++++------ src/pulsecore/shm.c | 4 +- src/pulsecore/sink-input.c | 13 ++- src/pulsecore/sink-input.h | 2 +- src/pulsecore/sink.c | 4 + src/pulsecore/sink.h | 2 + src/pulsecore/source-output.c | 13 ++- src/pulsecore/source-output.h | 2 +- src/pulsecore/source.c | 5 + src/pulsecore/source.h | 2 + src/pulsecore/tagstruct.c | 10 +- src/pulsecore/tagstruct.h | 4 +- 26 files changed, 708 insertions(+), 260 deletions(-) diff --git a/PROTOCOL b/PROTOCOL index 40863fc..74c08b4 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -79,7 +79,7 @@ New opcodes for notifications: PA_COMMAND_PLAYBACK_STREAM_MOVED PA_COMMAND_CAPTURE_STREAM_MOVED -### v13, implemented by >= 0.9.10 +### v13, implemented by >= 0.9.11 New fields for PA_COMMAND_CREATE_PLAYBACK_STREAM, PA_COMMAND_CREATE_RECORD_STREAM request at the end: @@ -113,7 +113,14 @@ New opcodes for proplist modifications New field for PA_COMMAND_PLAY_SAMPLE: proplist - + New field for PA_COMMAND_PLAY_SAMPLE response: idx + +New field for PA_COMMAND_CREATE_PLAYBACK_STREAM at the end: + + start_muted + +Buffer attributes for PA_COMMAND_CREATE_PLAYBACK_STREAM and +PA_COMMAND_CREATE_RECORD_STREAM may now be 0 for default values. diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c index 7e60cea..1dccf67 100644 --- a/src/modules/module-alsa-sink.c +++ b/src/modules/module-alsa-sink.c @@ -73,8 +73,8 @@ PA_MODULE_USAGE( "tsched_buffer_watermark="); #define DEFAULT_DEVICE "default" -#define DEFAULT_TSCHED_BUFFER_USEC (3*PA_USEC_PER_SEC) -#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC) +#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC) +#define DEFAULT_TSCHED_WATERMARK_USEC (10*PA_USEC_PER_MSEC) struct userdata { pa_core *core; @@ -325,7 +325,7 @@ static int unix_write(struct userdata *u) { } static int update_smoother(struct userdata *u) { - snd_pcm_sframes_t delay; + snd_pcm_sframes_t delay = 0; int64_t frames; int err; pa_usec_t now1, now2; @@ -334,6 +334,7 @@ static int update_smoother(struct userdata *u) { pa_assert(u->pcm_handle); /* Let's update the time smoother */ + snd_pcm_avail_update(u->pcm_handle); if (PA_UNLIKELY((err = snd_pcm_delay(u->pcm_handle, &delay)) < 0)) { @@ -441,6 +442,31 @@ static pa_usec_t hw_sleep_time(struct userdata *u) { return usec; } +static void update_hwbuf_unused_frames(struct userdata *u) { + pa_usec_t usec; + size_t b; + + pa_assert(u); + + if ((usec = pa_sink_get_requested_latency(u->sink)) <= 0) { + /* Use the full buffer if noone asked us for anything + * specific */ + u->hwbuf_unused_frames = 0; + return; + } + + b = pa_usec_to_bytes(usec, &u->sink->sample_spec); + + /* We need at least one sample in our buffer */ + + if (PA_UNLIKELY(b < u->frame_size)) + b = u->frame_size; + + u->hwbuf_unused_frames = + PA_LIKELY(b < u->hwbuf_size) ? + ((u->hwbuf_size - b) / u->frame_size) : 0; +} + static int update_sw_params(struct userdata *u) { size_t avail_min; int err; @@ -465,6 +491,8 @@ static int update_sw_params(struct userdata *u) { return err; } + update_hwbuf_unused_frames(u); + return 0; } @@ -535,29 +563,6 @@ fail: return -1; } -static void update_hwbuf_unused_frames(struct userdata *u) { - pa_usec_t usec; - size_t b; - - pa_assert(u); - - if ((usec = pa_sink_get_requested_latency(u->sink)) <= 0) { - /* Use the full buffer if noone asked us for anything - * specific */ - u->hwbuf_unused_frames = 0; - return; - } - - b = pa_usec_to_bytes(usec, &u->sink->sample_spec); - - /* We need at least one sample in our buffer */ - - if (PA_UNLIKELY(b < u->frame_size)) - b = u->frame_size; - - u->hwbuf_unused_frames = PA_LIKELY(b < u->hwbuf_size) ? ((u->hwbuf_size - b) / u->frame_size) : 0; -} - static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; @@ -608,13 +613,13 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse break; - case PA_SINK_MESSAGE_ADD_INPUT: - case PA_SINK_MESSAGE_REMOVE_INPUT: - case PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER: { - int r = pa_sink_process_msg(o, code, data, offset, chunk); - update_hwbuf_unused_frames(u); - return r; - } +/* case PA_SINK_MESSAGE_ADD_INPUT: */ +/* case PA_SINK_MESSAGE_REMOVE_INPUT: */ +/* case PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER: { */ +/* int r = pa_sink_process_msg(o, code, data, offset, chunk); */ +/* update_hwbuf_unused_frames(u); */ +/* return r; */ +/* } */ } return pa_sink_process_msg(o, code, data, offset, chunk); @@ -703,6 +708,7 @@ static int sink_set_volume_cb(pa_sink *s) { } u->hw_dB_supported = FALSE; + } alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; @@ -776,7 +782,7 @@ static void thread_func(void *userdata) { pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); - update_hwbuf_unused_frames(u); +/* update_hwbuf_unused_frames(u); */ for (;;) { int ret; @@ -1174,6 +1180,9 @@ int pa__init(pa_module*m) { u->sink->thread_info.max_rewind = use_tsched ? u->hwbuf_size : 0; + if (!use_tsched) + u->sink->min_latency = pa_bytes_to_usec(u->hwbuf_size, &ss); + pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms", nfrags, (long unsigned) u->fragment_size, (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC); diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c index b2d0d43..af20f81 100644 --- a/src/modules/module-alsa-source.c +++ b/src/modules/module-alsa-source.c @@ -92,6 +92,8 @@ struct userdata { snd_mixer_t *mixer_handle; snd_mixer_elem_t *mixer_elem; long hw_volume_max, hw_volume_min; + long hw_dB_max, hw_dB_min; + pa_bool_t hw_dB_supported; size_t frame_size, fragment_size, hwbuf_size, tsched_watermark; unsigned nfragments; @@ -288,25 +290,28 @@ static int unix_read(struct userdata *u) { } static int update_smoother(struct userdata *u) { - snd_pcm_status_t *status; + snd_pcm_sframes_t delay = 0; int64_t frames; int err; + pa_usec_t now1, now2; pa_assert(u); pa_assert(u->pcm_handle); - snd_pcm_status_alloca(&status); - /* Let's update the time smoother */ - if (PA_UNLIKELY((err = snd_pcm_status(u->pcm_handle, status)) < 0)) { + snd_pcm_avail_update(u->pcm_handle); + + if (PA_UNLIKELY((err = snd_pcm_delay(u->pcm_handle, &delay)) < 0)) { pa_log("Failed to get delay: %s", snd_strerror(err)); return -1; } - frames = u->frame_index + snd_pcm_status_get_delay(status); + frames = u->frame_index + delay; - pa_smoother_put(u->smoother, pa_rtclock_usec(), pa_bytes_to_usec(frames * u->frame_size, &u->source->sample_spec)); + now1 = pa_rtclock_usec(); + now2 = pa_bytes_to_usec(frames * u->frame_size, &u->source->sample_spec); + pa_smoother_put(u->smoother, now1, now2); return 0; } @@ -373,7 +378,7 @@ static int suspend(struct userdata *u) { } static pa_usec_t hw_sleep_time(struct userdata *u) { - pa_usec_t usec; + pa_usec_t wm, usec; pa_assert(u); @@ -382,11 +387,17 @@ static pa_usec_t hw_sleep_time(struct userdata *u) { if (usec <= 0) usec = pa_bytes_to_usec(u->hwbuf_size, &u->source->sample_spec); - if (usec >= u->tsched_watermark) - usec -= u->tsched_watermark; + pa_log_debug("hw buffer time: %u ms", (unsigned) (usec / PA_USEC_PER_MSEC)); + + wm = pa_bytes_to_usec(u->tsched_watermark, &u->source->sample_spec); + + if (usec >= wm) + usec -= wm; else usec /= 2; + pa_log_debug("after watermark: %u ms", (unsigned) (usec / PA_USEC_PER_MSEC)); + return usec; } @@ -470,7 +481,6 @@ 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_log_info("Resumed successfully..."); @@ -568,18 +578,24 @@ static int source_get_volume_cb(pa_source *s) { pa_assert(u->mixer_elem); for (i = 0; i < s->sample_spec.channels; i++) { - long set_vol, vol; + long alsa_vol; pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i])); - if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &vol)) < 0) - goto fail; + if (u->hw_dB_supported) { - set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + if ((err = snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) >= 0) { + s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0); + continue; + } + + u->hw_dB_supported = FALSE; + } - /* Try to avoid superfluous volume changes */ - if (set_vol != vol) - s->volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); + if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0) + goto fail; + + s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); } return 0; @@ -587,8 +603,6 @@ static int source_get_volume_cb(pa_source *s) { fail: pa_log_error("Unable to read volume: %s", snd_strerror(err)); - s->get_volume = NULL; - s->set_volume = NULL; return -1; } @@ -604,17 +618,36 @@ static int source_set_volume_cb(pa_source *s) { long alsa_vol; pa_volume_t vol; + pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i])); - vol = s->volume.values[i]; + vol = PA_MIN(s->volume.values[i], PA_VOLUME_NORM); + + if (u->hw_dB_supported) { + alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100); + alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_dB_min, u->hw_dB_max); + + + if ((err = snd_mixer_selem_set_capture_dB(u->mixer_elem, u->mixer_map[i], alsa_vol, -1)) >= 0) { + + if (snd_mixer_selem_get_capture_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0) + s->volume.values[i] = pa_sw_volume_from_dB(alsa_vol / 100.0); + + continue; + } + + u->hw_dB_supported = FALSE; + } - if (vol > PA_VOLUME_NORM) - vol = PA_VOLUME_NORM; alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; + alsa_vol = PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max); if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0) goto fail; + + if (snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol) >= 0) + s->volume.values[i] = (pa_volume_t) roundf(((float) (alsa_vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min)); } return 0; @@ -622,8 +655,6 @@ static int source_set_volume_cb(pa_source *s) { fail: pa_log_error("Unable to set volume: %s", snd_strerror(err)); - s->get_volume = NULL; - s->set_volume = NULL; return -1; } @@ -636,9 +667,6 @@ static int source_get_mute_cb(pa_source *s) { if ((err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw)) < 0) { pa_log_error("Unable to get switch: %s", snd_strerror(err)); - - s->get_mute = NULL; - s->set_mute = NULL; return -1; } @@ -656,15 +684,20 @@ static int source_set_mute_cb(pa_source *s) { if ((err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->muted)) < 0) { pa_log_error("Unable to set switch: %s", snd_strerror(err)); - - s->get_mute = NULL; - s->set_mute = NULL; return -1; } return 0; } +static void source_update_requested_latency_cb(pa_source *s) { + struct userdata *u = s->userdata; + + pa_assert(u); + + update_sw_params(u); +} + static void thread_func(void *userdata) { struct userdata *u = userdata; @@ -694,10 +727,11 @@ static void thread_func(void *userdata) { goto fail; } - if (update_smoother(u) < 0) - goto fail; + if (work_done) + if (update_smoother(u) < 0) + goto fail; - if (u->use_tsched && work_done) { + if (u->use_tsched) { pa_usec_t usec, cusec; /* OK, the capture buffer is now empty, let's @@ -716,6 +750,10 @@ static void thread_func(void *userdata) { /* We don't trust the conversion, so we wake up whatever comes first */ pa_rtpoll_set_timer_relative(u->rtpoll, PA_MIN(usec, cusec)); } + } else if (u->use_tsched) { + + /* OK, we're in an invalid state, let's disable our timers */ + pa_rtpoll_set_timer_disabled(u->rtpoll); } /* Hmm, nothing to do. Let's sleep */ @@ -797,7 +835,7 @@ int pa__init(pa_module*m) { const char *dev_id; pa_sample_spec ss; pa_channel_map map; - uint32_t nfrags, frag_size, tsched_size, tsched_watermark; + uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark; snd_pcm_uframes_t period_frames, tsched_frames; size_t frame_size; snd_pcm_info_t *pcm_info = NULL; @@ -846,6 +884,7 @@ int pa__init(pa_module*m) { goto fail; } + hwbuf_size = frag_size * nfrags; period_frames = frag_size/frame_size; tsched_frames = tsched_size/frame_size; @@ -874,6 +913,7 @@ int pa__init(pa_module*m) { u->rtpoll = pa_rtpoll_new(); u->alsa_rtpoll_item = NULL; pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); + u->smoother = pa_smoother_new(DEFAULT_TSCHED_WATERMARK_USEC, DEFAULT_TSCHED_WATERMARK_USEC, TRUE); pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec()); @@ -929,9 +969,6 @@ int pa__init(pa_module*m) { goto fail; } - if (update_sw_params(u) < 0) - goto fail; - /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); @@ -996,6 +1033,7 @@ int pa__init(pa_module*m) { } u->source->parent.process_msg = source_process_msg; + u->source->update_requested_latency = source_update_requested_latency_cb; u->source->userdata = u; pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); @@ -1007,24 +1045,85 @@ int pa__init(pa_module*m) { u->hwbuf_size = u->fragment_size * nfrags; u->tsched_watermark = tsched_watermark; u->frame_index = 0; + u->hw_dB_supported = FALSE; + u->hw_dB_min = u->hw_dB_max = 0; + u->hw_volume_min = u->hw_volume_max = 0; + + if (!use_tsched) + u->source->min_latency = pa_bytes_to_usec(u->hwbuf_size, &ss); + + pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms", + nfrags, (long unsigned) u->fragment_size, + (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC); + + if (use_tsched) + pa_log_info("Time scheduling watermark is %0.2fms", + (double) pa_bytes_to_usec(u->tsched_watermark, &ss) / PA_USEC_PER_MSEC); - pa_log_info("Using %u fragments of size %lu bytes.", nfrags, (long unsigned) u->fragment_size); + if (update_sw_params(u) < 0) + goto fail; if (u->mixer_handle) { pa_assert(u->mixer_elem); if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) - if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0) { - u->source->get_volume = source_get_volume_cb; - u->source->set_volume = source_set_volume_cb; - snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max); - u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; + if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0 && + snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) >= 0) { + + pa_bool_t suitable = TRUE; + + pa_log_info("Volume ranges from %li to %li.", u->hw_volume_min, u->hw_volume_max); + + if (u->hw_volume_min > u->hw_volume_max) { + + pa_log_info("Minimal volume %li larger than maximum volume %li. Strange stuff Falling back to software volume control.", u->hw_volume_min, u->hw_volume_max); + suitable = FALSE; + + } else if (u->hw_volume_max - u->hw_volume_min < 3) { + + pa_log_info("Device has less than 4 volume levels. Falling back to software volume control."); + suitable = FALSE; + + } else if (snd_mixer_selem_get_playback_dB_range(u->mixer_elem, &u->hw_dB_min, &u->hw_dB_max) >= 0) { + + pa_log_info("Volume ranges from %0.2f dB to %0.2f dB.", u->hw_dB_min/100.0, u->hw_dB_max/100.0); + + /* Let's see if this thing actually is useful for muting */ + if (u->hw_dB_min > -6000) { + pa_log_info("Device cannot attenuate for more than -60 dB (only %0.2f dB supported), falling back to software volume control.", ((double) u->hw_dB_min) / 100); + + suitable = FALSE; + } else if (u->hw_dB_max < 0) { + + pa_log_info("Device is still attenuated at maximum volume setting (%0.2f dB is maximum). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_max) / 100); + suitable = FALSE; + + } else if (u->hw_dB_min >= u->hw_dB_max) { + + pa_log_info("Minimal dB (%0.2f) larger or equal to maximum dB (%0.2f). Strange stuff. Falling back to software volume control.", ((double) u->hw_dB_min) / 100, ((double) u->hw_dB_max) / 100); + suitable = FALSE; + + } else + u->hw_dB_supported = TRUE; + } + + if (suitable) { + u->source->get_volume = source_get_volume_cb; + u->source->set_volume = source_set_volume_cb; + u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SOURCE_DECIBEL_VOLUME : 0); + pa_log_info("Using hardware volume control. %s dB scale.", u->hw_dB_supported ? "Using" : "Not using"); + + } else { + pa_log_info("Using software volume control. Trying to reset sound card to 0 dB."); + pa_alsa_0dB_capture(u->mixer_elem); + } } + if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) { u->source->get_mute = source_get_mute_cb; u->source->set_mute = source_set_mute_cb; - u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; + u->source->flags |= PA_SOURCE_HW_MUTE_CTRL; } u->mixer_fdl = pa_alsa_fdlist_new(); @@ -1044,10 +1143,21 @@ int pa__init(pa_module*m) { goto fail; } /* Get initial mixer settings */ - if (u->source->get_volume) - u->source->get_volume(u->source); - if (u->source->get_mute) - u->source->get_mute(u->source); + if (data.volume_is_set) { + if (u->source->set_volume) + u->source->set_volume(u->source); + } else { + if (u->source->get_volume) + u->source->get_volume(u->source); + } + + if (data.muted_is_set) { + if (u->source->set_mute) + u->source->set_mute(u->source); + } else { + if (u->source->get_mute) + u->source->get_mute(u->source); + } pa_source_put(u->source); diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c index 9598fee..e29f0ed 100644 --- a/src/modules/oss-util.c +++ b/src/modules/oss-util.c @@ -251,7 +251,7 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) { return 0; } -int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume) { +int pa_oss_get_volume(int fd, unsigned long mixer, const pa_sample_spec *ss, pa_cvolume *volume) { char cv[PA_CVOLUME_SNPRINT_MAX]; unsigned vol; @@ -273,7 +273,7 @@ int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *v return 0; } -int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvolume *volume) { +int pa_oss_set_volume(int fd, unsigned long mixer, const pa_sample_spec *ss, const pa_cvolume *volume) { char cv[PA_CVOLUME_SNPRINT_MAX]; unsigned vol; pa_volume_t l, r; diff --git a/src/modules/oss-util.h b/src/modules/oss-util.h index 259a622..8fea805 100644 --- a/src/modules/oss-util.h +++ b/src/modules/oss-util.h @@ -33,8 +33,8 @@ int pa_oss_auto_format(int fd, pa_sample_spec *ss); int pa_oss_set_fragments(int fd, int frags, int frag_size); -int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvolume *volume); -int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume); +int pa_oss_set_volume(int fd, unsigned long mixer, const pa_sample_spec *ss, const pa_cvolume *volume); +int pa_oss_get_volume(int fd, unsigned long mixer, const pa_sample_spec *ss, pa_cvolume *volume); int pa_oss_get_hw_description(const char *dev, char *name, size_t l); diff --git a/src/pulse/def.h b/src/pulse/def.h index edda792..ae76660 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -210,16 +210,68 @@ typedef enum pa_stream_flags { * on older servers. \since * 0.9.8 */ PA_STREAM_PEAK_DETECT = 2048, /**< Find peaks instead of - * resampling. \since 0.9.9 */ + * resampling. \since 0.9.11 */ + + PA_STREAM_START_MUTED = 4096, /**< Create in muted state. \since 0.9.11 */ + + + PA_STREAM_ADJUST_LATENCY = 8192, /**< Try to adjust the latency of + * the sink/source based on the + * requested buffer metrics and + * adjust buffer metrics + * accordingly. \since 0.9.11 */ } pa_stream_flags_t; /** Playback and record buffer metrics */ typedef struct pa_buffer_attr { - uint32_t maxlength; /**< Maximum length of the buffer */ - uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ - uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ - uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ - uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ + uint32_t maxlength; /**< Maximum length of the + * buffer. Setting this to 0 will + * initialize this to the maximum value + * supported by server, which is + * recommended. */ + uint32_t tlength; /**< Playback only: target length of the + * buffer. The server tries to assure + * that at least tlength bytes are always + * available in the buffer. It is + * recommended to set this to 0, which + * will initialize this to a value that + * is deemed sensible by the + * server. However, this value will + * default to something like 2s, i.e. for + * applications that have specific + * latency requirements this value should + * be set to the maximum latency that the + * application can deal with. */ + uint32_t prebuf; /**< Playback only: pre-buffering. The + * server does not start with playback + * before at least prebug bytes are + * available in the buffer. It is + * recommended to set this to 0, which + * will initialize this to the same value + * as tlength, whatever that may be. */ + uint32_t minreq; /**< Playback only: minimum request. The + * server does not request less than + * minreq bytes from the client, instead + * waits until the buffer is free enough + * to request more bytes at once. It is + * recommended to set this to 0, which + * will initialize this to a value that + * is deemed sensible by the server. */ + uint32_t fragsize; /**< Recording only: fragment size. The + * server sends data in blocks of + * fragsize bytes size. Large values + * deminish interactivity with other + * operations on the connection context + * but decrease control overhead. It is + * recommended to set this to 0, which + * will initialize this to a value that + * is deemed sensible by the + * server. However, this value will + * default to something like 2s, i.e. for + * applications that have specific + * latency requirements this value should + * be set to the maximum latency that the + * application can deal with. */ } pa_buffer_attr; /** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ @@ -299,7 +351,9 @@ typedef enum pa_subscription_event_type { * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of * sign issues!) When connected to a monitor source sink_usec contains * the latency of the owning sink. The two latency estimations - * described here are implemented in pa_stream_get_latency().*/ + * described here are implemented in pa_stream_get_latency(). Please + * note that this structure can be extended as part of evolutionary + * API updates at any time in any new release.*/ typedef struct pa_timing_info { struct timeval timestamp; /**< The time when this timing info structure was current */ int synchronized_clocks; /**< Non-zero if the local and the @@ -346,6 +400,11 @@ typedef struct pa_timing_info { * want to use it. Consider using * PA_SEEK_RELATIVE_ON_READ * instead. \since 0.8 */ + + pa_usec_t max_sink_usec; /**< The static configure latency for + * the sink. \since 0.9.10 */ + pa_usec_t max_source_usec; /**< The static configure latency for + * the source. \since 0.9.10 */ } pa_timing_info; /** A structure for the spawn api. This may be used to integrate auto diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index 4b282bd..633ee55 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -149,6 +149,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P while (!pa_tagstruct_eof(t)) { pa_sink_info i; + pa_bool_t mute = FALSE; memset(&i, 0, sizeof(i)); i.proplist = pa_proplist_new(); @@ -160,7 +161,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_boolean(t, &i.mute) < 0 || + pa_tagstruct_get_boolean(t, &mute) < 0 || pa_tagstruct_getu32(t, &i.monitor_source) < 0 || pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || @@ -173,6 +174,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P goto finish; } + i.mute = (int) mute; i.flags = (pa_sink_flags_t) flags; if (o->callback) { @@ -266,6 +268,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, while (!pa_tagstruct_eof(t)) { pa_source_info i; uint32_t flags; + pa_bool_t mute = FALSE; memset(&i, 0, sizeof(i)); i.proplist = pa_proplist_new(); @@ -277,7 +280,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_boolean(t, &i.mute) < 0 || + pa_tagstruct_get_boolean(t, &mute) < 0 || pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || pa_tagstruct_get_usec(t, &i.latency) < 0 || @@ -290,6 +293,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, goto finish; } + i.mute = (int) mute; i.flags = (pa_source_flags_t) flags; if (o->callback) { @@ -464,17 +468,20 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, while (!pa_tagstruct_eof(t)) { pa_module_info i; + pa_bool_t auto_unload = FALSE; memset(&i, 0, sizeof(i)); if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_gets(t, &i.argument) < 0 || pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { + pa_tagstruct_get_boolean(t, &auto_unload) < 0) { pa_context_fail(o->context, PA_ERR_PROTOCOL); goto finish; } + i.auto_unload = (int) auto_unload; + if (o->callback) { pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); @@ -540,6 +547,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm while (!pa_tagstruct_eof(t)) { pa_sink_input_info i; + pa_bool_t mute = FALSE; memset(&i, 0, sizeof(i)); i.proplist = pa_proplist_new(); @@ -556,7 +564,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || pa_tagstruct_gets(t, &i.resample_method) < 0 || pa_tagstruct_gets(t, &i.driver) < 0 || - (o->context->version >= 11 && pa_tagstruct_get_boolean(t, &i.mute) < 0) || + (o->context->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0) || (o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0)) { pa_context_fail(o->context, PA_ERR_PROTOCOL); @@ -564,6 +572,8 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm goto finish; } + i.mute = (int) mute; + if (o->callback) { pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); @@ -961,6 +971,7 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, while (!pa_tagstruct_eof(t)) { pa_sample_info i; + pa_bool_t lazy = FALSE; memset(&i, 0, sizeof(i)); i.proplist = pa_proplist_new(); @@ -972,7 +983,7 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_getu32(t, &i.bytes) < 0 || - pa_tagstruct_get_boolean(t, &i.lazy) < 0 || + pa_tagstruct_get_boolean(t, &lazy) < 0 || pa_tagstruct_gets(t, &i.filename) < 0 || (o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0)) { @@ -980,6 +991,8 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, goto finish; } + i.lazy = (int) lazy; + if (o->callback) { pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; cb(o->context, &i, 0, o->userdata); @@ -1192,6 +1205,8 @@ finish: pa_operation_unref(o); } +PA_WARN_REFERENCE(pa_context_get_autoload_info_by_name, "Autoload will no longer be implemented by future versions of the PulseAudio server."); + pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; @@ -1216,6 +1231,8 @@ pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *na return o; } +PA_WARN_REFERENCE(pa_context_get_autoload_info_by_index, "Autoload will no longer be implemented by future versions of the PulseAudio server."); + pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) { pa_tagstruct *t; pa_operation *o; @@ -1238,10 +1255,15 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, return o; } + +PA_WARN_REFERENCE(pa_context_get_autoload_info_list, "Autoload will no longer be implemented by future versions of the PulseAudio server."); + pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) { return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_cb_t) cb, userdata); } +PA_WARN_REFERENCE(pa_context_add_autoload, "Autoload will no longer be implemented by future versions of the PulseAudio server."); + pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t cb, void* userdata) { pa_operation *o; pa_tagstruct *t; @@ -1268,6 +1290,8 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo return o; } +PA_WARN_REFERENCE(pa_context_remove_autoload_by_name, "Autoload will no longer be implemented by future versions of the PulseAudio server."); + pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata) { pa_operation *o; pa_tagstruct *t; @@ -1291,6 +1315,8 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name return o; } +PA_WARN_REFERENCE(pa_context_remove_autoload_by_index, "Autoload will no longer be implemented by future versions of the PulseAudio server."); + pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) { pa_operation *o; pa_tagstruct *t; diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index 91f738d..bc78996 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -212,7 +212,11 @@ PA_C_DECL_BEGIN #define PA_PORT_ANALOG_5_1 "analog-5-1" #define PA_PORT_ANALOG_4_0 "analog-4-0" -/** Stores information about sinks */ +/** @{ \name Sinks */ + +/** Stores information about sinks. Please note that this structure + * can be extended as part of evolutionary API updates at any time in + * any new release. */ typedef struct pa_sink_info { const char *name; /**< Name of the sink */ uint32_t index; /**< Index of the sink */ @@ -224,10 +228,11 @@ typedef struct pa_sink_info { int mute; /**< Mute switch of the sink \since 0.8 */ uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ const char *monitor_source_name; /**< The name of the monitor source */ - pa_usec_t latency; /**< Length of filled playback buffer of this sink */ + pa_usec_t latency; /**< Length of queued audio in the output buffer. */ const char *driver; /**< Driver name. \since 0.8 */ pa_sink_flags_t flags; /**< Flags \since 0.8 */ - pa_proplist *proplist; /**< Property list \since 0.9.10 */ + pa_proplist *proplist; /**< Property list \since 0.9.11 */ + pa_usec_t max_latency; /**< The static latency this device has been configured to. \since 0.9.11 */ } pa_sink_info; /** Callback prototype for pa_context_get_sink_info_by_name() and friends */ @@ -242,7 +247,31 @@ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, pa_s /** Get the complete sink list */ pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata); -/** Stores information about sources */ +/** Set the volume of a sink device specified by its index */ +pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the volume of a sink device specified by its name */ +pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a sink device specified by its index \since 0.8 */ +pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a sink device specified by its name \since 0.8 */ +pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Suspend/Resume a sink. \since 0.9.7 */ +pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata); + +/** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */ +pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); + +/** @} */ + +/** @{ \name Sources */ + +/** Stores information about sources. Please note that this structure + * can be extended as part of evolutionary API updates at any time in + * any new release. */ typedef struct pa_source_info { const char *name; /**< Name of the source */ uint32_t index; /**< Index of the source */ @@ -258,6 +287,7 @@ typedef struct pa_source_info { const char *driver; /**< Driver name \since 0.8 */ pa_source_flags_t flags; /**< Flags \since 0.8 */ pa_proplist *proplist; /**< Property list \since 0.9.10 */ + pa_usec_t max_latency; /**< The static latency this device has been configured to. \since 0.9.11 */ } pa_source_info; /** Callback prototype for pa_context_get_source_info_by_name() and friends */ @@ -272,7 +302,25 @@ pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, pa /** Get the complete source list */ pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata); -/** Server information */ +/** Set the volume of a source device specified by its index \since 0.8 */ +pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the volume of a source device specified by its name \since 0.8 */ +pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a source device specified by its index \since 0.8 */ +pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a source device specified by its name \since 0.8 */ +pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); + +/** @} */ + +/** @{ \name Server */ + +/** Server information. Please note that this structure can be + * extended as part of evolutionary API updates at any time in any new + * release. */ typedef struct pa_server_info { const char *user_name; /**< User name of the daemon process */ const char *host_name; /**< Host name the daemon is running on */ @@ -290,7 +338,13 @@ typedef void (*pa_server_info_cb_t) (pa_context *c, const pa_server_info*i, void /** Get some information about the server */ pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata); -/** Stores information about modules */ +/** @} */ + +/** @{ \name Modules */ + +/** Stores information about modules. Please note that this structure + * can be extended as part of evolutionary API updates at any time in + * any new release. */ typedef struct pa_module_info { uint32_t index; /**< Index of the module */ const char*name, /**< Name of the module */ @@ -308,7 +362,22 @@ pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_ /** Get the complete list of currently loaded modules */ pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata); -/** Stores information about clients */ +/** Callback prototype for pa_context_load_module() */ +typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdata); + +/** Load a module. \since 0.5 */ +pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata); + +/** Unload a module. \since 0.5 */ +pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); + +/** @} */ + +/** @{ \name Clients */ + +/** Stores information about clients. Please note that this structure + * can be extended as part of evolutionary API updates at any time in + * any new release. */ typedef struct pa_client_info { uint32_t index; /**< Index of this client */ const char *name; /**< Name of this client */ @@ -326,7 +395,16 @@ pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_ /** Get the complete client list */ pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata); -/** Stores information about sink inputs */ +/** Kill a client. \since 0.5 */ +pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); + +/** @} */ + +/** @{ \name Sink Inputs */ + +/** Stores information about sink inputs. Please note that this structure + * can be extended as part of evolutionary API updates at any time in + * any new release. */ typedef struct pa_sink_input_info { uint32_t index; /**< Index of the sink input */ const char *name; /**< Name of the sink input */ @@ -353,7 +431,28 @@ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sin /** Get the complete sink input list */ pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata); -/** Stores information about source outputs */ +/** Move the specified sink input to a different sink. \since 0.9.5 */ +pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, char *sink_name, pa_context_success_cb_t cb, void* userdata); + +/** Move the specified sink input to a different sink. \since 0.9.5 */ +pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void* userdata); + +/** Set the volume of a sink input stream */ +pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); + +/** Set the mute switch of a sink input stream \since 0.9.7 */ +pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); + +/** Kill a sink input. \since 0.5 */ +pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); + +/** @} */ + +/** @{ \name Source Outputs */ + +/** Stores information about source outputs. Please note that this structure + * can be extended as part of evolutionary API updates at any time in + * any new release. */ typedef struct pa_source_output_info { uint32_t index; /**< Index of the sink input */ const char *name; /**< Name of the sink input */ @@ -378,37 +477,28 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_ /** Get the complete list of source outputs */ pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata); -/** Set the volume of a sink device specified by its index */ -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the volume of a sink device specified by its name */ -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a sink device specified by its index \since 0.8 */ -pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a sink device specified by its name \since 0.8 */ -pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); +/** Move the specified source output to a different source. \since 0.9.5 */ +pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, char *source_name, pa_context_success_cb_t cb, void* userdata); -/** Set the volume of a sink input stream */ -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +/** Move the specified source output to a different source. \since 0.9.5 */ +pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata); -/** Set the mute switch of a sink input stream \since 0.9.7 */ -pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); +/** Suspend/Resume a source. \since 0.9.7 */ +pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata); -/** Set the volume of a source device specified by its index \since 0.8 */ -pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +/** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */ +pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); -/** Set the volume of a source device specified by its name \since 0.8 */ -pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); +/** Kill a source output. \since 0.5 */ +pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); -/** Set the mute switch of a source device specified by its index \since 0.8 */ -pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); +/** @} */ -/** Set the mute switch of a source device specified by its name \since 0.8 */ -pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); +/** @{ \name Statistics */ -/** Memory block statistics */ +/** Memory block statistics. Please note that this structure + * can be extended as part of evolutionary API updates at any time in + * 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 */ @@ -423,7 +513,13 @@ typedef void (*pa_stat_info_cb_t) (pa_context *c, const pa_stat_info *i, void *u /** Get daemon memory block statistics */ pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata); -/** Stores information about sample cache entries */ +/** @} */ + +/** @{ \name Cached Samples */ + +/** Stores information about sample cache entries. Please note that this structure + * can be extended as part of evolutionary API updates at any time in + * any new release. */ typedef struct pa_sample_info { uint32_t index; /**< Index of this entry */ const char *name; /**< Name of this entry */ @@ -449,23 +545,11 @@ pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, p /** Get the complete list of samples stored in the daemon. */ pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata); -/** Kill a client. \since 0.5 */ -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Kill a sink input. \since 0.5 */ -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Kill a source output. \since 0.5 */ -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Callback prototype for pa_context_load_module() and pa_context_add_autoload() */ -typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdata); +/** @} */ -/** Load a module. \since 0.5 */ -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata); +/** \cond fulldocs */ -/** Unload a module. \since 0.5 */ -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); +/** @{ \name Autoload Entries */ /** Type of an autoload entry. \since 0.5 */ typedef enum pa_autoload_type { @@ -473,7 +557,9 @@ typedef enum pa_autoload_type { PA_AUTOLOAD_SOURCE = 1 } pa_autoload_type_t; -/** Stores information about autoload entries. \since 0.5 */ +/** Stores information about autoload entries. Please note that this structure + * can be extended as part of evolutionary API updates at any time in + * any new release. \since 0.5 */ typedef struct pa_autoload_info { uint32_t index; /**< Index of this autoload entry */ const char *name; /**< Name of the sink or source */ @@ -503,29 +589,9 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name /** Remove an autoload entry. \since 0.6 */ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata); -/** Move the specified sink input to a different sink. \since 0.9.5 */ -pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, char *sink_name, pa_context_success_cb_t cb, void* userdata); - -/** Move the specified sink input to a different sink. \since 0.9.5 */ -pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void* userdata); +/** @} */ -/** Move the specified source output to a different source. \since 0.9.5 */ -pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, char *source_name, pa_context_success_cb_t cb, void* userdata); - -/** Move the specified source output to a different source. \since 0.9.5 */ -pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata); - -/** Suspend/Resume a sink. \since 0.9.7 */ -pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata); - -/** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */ -pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); - -/** Suspend/Resume a source. \since 0.9.7 */ -pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata); - -/** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */ -pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata); +/** \endcond */ PA_C_DECL_END diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 321f222..fb96523 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -292,7 +292,7 @@ void pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED u pa_stream *s; uint32_t channel; const char *dn; - int suspended; + pa_bool_t suspended; uint32_t di; pa_assert(pd); @@ -342,7 +342,7 @@ void pa_command_stream_suspended(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUS pa_context *c = userdata; pa_stream *s; uint32_t channel; - int suspended; + pa_bool_t suspended; pa_assert(pd); pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_SUSPENDED || command == PA_COMMAND_RECORD_STREAM_SUSPENDED); @@ -543,15 +543,31 @@ static void create_stream_complete(pa_stream *s) { } } -static void automatic_buffer_attr(pa_buffer_attr *attr, pa_sample_spec *ss) { +static void automatic_buffer_attr(pa_stream *s, pa_buffer_attr *attr, const pa_sample_spec *ss) { + pa_assert(s); pa_assert(attr); pa_assert(ss); - attr->tlength = pa_bytes_per_second(ss)/2; - attr->maxlength = (attr->tlength*3)/2; - attr->minreq = attr->tlength/50; - attr->prebuf = attr->tlength - attr->minreq; - attr->fragsize = attr->tlength/50; + if (s->context->version >= 13) + return; + + /* Version older than 0.9.10 didn't do server side buffer_attr + * selection, hence we have to fake it on the client side */ + + if (!attr->maxlength <= 0) + attr->maxlength = 4*1024*1024; /* 4MB is the maximum queue length PulseAudio <= 0.9.9 supported. */ + + if (!attr->tlength <= 0) + attr->tlength = pa_bytes_per_second(ss)*2; /* 2s of buffering */ + + if (!attr->minreq <= 0) + attr->minreq = (9*attr->tlength)/10; /* Ask for more data when there are only 200ms left in the playback buffer */ + + if (!attr->prebuf) + attr->prebuf = attr->tlength; /* Start to play only when the playback is fully filled up once */ + + if (!attr->fragsize) + attr->fragsize = attr->tlength; /* Pass data to the app only when the buffer is filled up once */ } void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -601,7 +617,7 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_sample_spec ss; pa_channel_map cm; const char *dn = NULL; - int suspended; + pa_bool_t suspended; if (pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_get_channel_map(t, &cm) < 0 || @@ -631,7 +647,8 @@ void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_buffer_attr attr; pa_operation *o; - automatic_buffer_attr(&attr, &ss); + memset(&attr, 0, sizeof(attr)); + automatic_buffer_attr(s, &attr, &ss); /* If we need to update the buffer metrics, we wait for * the the OK for that call before we go to @@ -718,7 +735,9 @@ static int create_stream( PA_STREAM_FIX_CHANNELS| PA_STREAM_DONT_MOVE| PA_STREAM_VARIABLE_RATE| - PA_STREAM_PEAK_DETECT)), PA_ERR_INVALID); + PA_STREAM_PEAK_DETECT| + PA_STREAM_START_MUTED| + PA_STREAM_ADJUST_LATENCY)), PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, s->context->version >= 12 || !(flags & PA_STREAM_VARIABLE_RATE), PA_ERR_NOTSUPPORTED); PA_CHECK_VALIDITY(s->context, s->context->version >= 13 || !(flags & PA_STREAM_PEAK_DETECT), PA_ERR_NOTSUPPORTED); @@ -727,6 +746,8 @@ static int create_stream( * when they are passed but actually not supported. This makes * client development easier */ + PA_CHECK_VALIDITY(s->context, direction != PA_STREAM_PLAYBACK || !(flags & (PA_STREAM_START_MUTED)), PA_ERR_INVALID); + PA_CHECK_VALIDITY(s->context, direction != PA_STREAM_RECORD || !(flags & (PA_STREAM_PEAK_DETECT)), PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); @@ -742,15 +763,12 @@ static int create_stream( s->buffer_attr = *attr; s->manual_buffer_attr = TRUE; } else { - /* half a second, with minimum request of 10 ms */ - s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; - s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; - s->buffer_attr.minreq = s->buffer_attr.tlength/50; - s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; - s->buffer_attr.fragsize = s->buffer_attr.tlength/50; + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); s->manual_buffer_attr = FALSE; } + automatic_buffer_attr(s, &s->buffer_attr, &s->sample_spec); + if (!dev) dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source; @@ -805,11 +823,16 @@ static int create_stream( if (s->context->version >= 13) { + if (s->direction == PA_STREAM_PLAYBACK) + pa_tagstruct_put_boolean(t, flags & PA_STREAM_START_MUTED); + else + pa_tagstruct_put_boolean(t, flags & PA_STREAM_PEAK_DETECT); + pa_init_proplist(s->proplist); pa_tagstruct_put( t, - PA_TAG_BOOLEAN, flags & PA_STREAM_PEAK_DETECT, + PA_TAG_BOOLEAN, flags & PA_STREAM_ADJUST_LATENCY, PA_TAG_PROPLIST, s->proplist, PA_TAG_INVALID); } @@ -1023,6 +1046,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, pa_operation *o = userdata; struct timeval local, remote, now; pa_timing_info *i; + pa_bool_t playing = FALSE; pa_assert(pd); pa_assert(o); @@ -1047,7 +1071,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, } else if (pa_tagstruct_get_usec(t, &i->sink_usec) < 0 || pa_tagstruct_get_usec(t, &i->source_usec) < 0 || - pa_tagstruct_get_boolean(t, &i->playing) < 0 || + pa_tagstruct_get_boolean(t, &playing) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || pa_tagstruct_gets64(t, &i->write_index) < 0 || @@ -1058,6 +1082,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, } else { o->stream->timing_info_valid = 1; + i->playing = (int) playing; pa_gettimeofday(&now); diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 20510fc..ca4be59 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -155,10 +155,10 @@ static const struct command commands[] = { { "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2}, { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, { "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1}, - { "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4}, - { "add-autoload-source", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, module name, arguments)", 4}, - { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2}, - { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2}, + { "add-autoload-sink", pa_cli_command_autoload_add, NULL /*"Add autoload entry for a sink (args: sink, module name, arguments)"*/, 4}, + { "add-autoload-source", pa_cli_command_autoload_add, NULL /*"Add autoload entry for a source (args: source, module name, arguments)"*/, 4}, + { "remove-autoload-sink", pa_cli_command_autoload_remove, NULL /*"Remove autoload entry for a sink (args: name)"*/, 2}, + { "remove-autoload-source", pa_cli_command_autoload_remove, NULL /*"Remove autoload entry for a source (args: name)"*/, 2}, { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, { "list-props", pa_cli_command_list_props, NULL, 1}, { "move-sink-input", pa_cli_command_move_sink_input, "Move sink input to another sink (args: index, sink)", 3}, @@ -367,7 +367,7 @@ static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b pa_cli_command_sink_inputs(c, t, buf, fail); pa_cli_command_source_outputs(c, t, buf, fail); pa_cli_command_scache_list(c, t, buf, fail); - pa_cli_command_autoload_list(c, t, buf, fail); +/* pa_cli_command_autoload_list(c, t, buf, fail); */ return 0; } @@ -905,6 +905,8 @@ static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *b pa_assert(buf); pa_assert(fail); + pa_log_warn("Autoload will no longer be implemented by future versions of the PulseAudio server."); + if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) { pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n"); return -1; @@ -923,6 +925,8 @@ static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf pa_assert(buf); pa_assert(fail); + pa_log_warn("Autoload will no longer be implemented by future versions of the PulseAudio server."); + if (!(name = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a device name\n"); return -1; @@ -944,6 +948,8 @@ static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf * pa_assert(buf); pa_assert(fail); + pa_log_warn("Autoload will no longer be implemented by future versions of the PulseAudio server."); + pa_assert_se(s = pa_autoload_list_to_string(c)); pa_strbuf_puts(buf, s); pa_xfree(s); diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index 1bf2cfb..a301bba 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -204,4 +204,17 @@ static inline const char *pa_strnull(const char *x) { return x ? x : "(null)"; } +#ifdef __GNUC__ + +#define PA_WARN_REFERENCE(sym,msg) \ + __asm__(".section .gnu.warning.sym"); \ + __asm__(".asciz \"msg\""); \ + __asm__(".previous") + +#else + +#define PA_WARN_REFERENCE(sym,msg) + +#endif + #endif diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index cc5e9e1..1d9583e 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -138,7 +138,7 @@ static void fix_current_read(pa_memblockq *bq) { break; /* Scan right */ - while (PA_LIKELY(bq->current_read != NULL) && PA_UNLIKELY(bq->current_read->index + bq->current_read->chunk.length <= bq->read_index)) + while (PA_LIKELY(bq->current_read != NULL) && PA_UNLIKELY(bq->current_read->index + (int64_t) bq->current_read->chunk.length <= bq->read_index)) bq->current_read = bq->current_read->next; /* At this point current_read will either point at or left of the @@ -158,7 +158,7 @@ static void fix_current_write(pa_memblockq *bq) { bq->current_write = bq->blocks_tail; /* Scan right */ - while (PA_UNLIKELY(bq->current_write->index + bq->current_write->chunk.length <= bq->write_index)) + while (PA_UNLIKELY(bq->current_write->index + (int64_t) bq->current_write->chunk.length <= bq->write_index)) if (bq->current_write->next) bq->current_write = bq->current_write->next; @@ -214,7 +214,7 @@ static void drop_backlog(pa_memblockq *bq) { boundary = bq->read_index - bq->maxrewind; - while (bq->blocks && (bq->blocks->index + bq->blocks->chunk.length <= boundary)) + while (bq->blocks && (bq->blocks->index + (int64_t) bq->blocks->chunk.length <= boundary)) drop_block(bq, bq->blocks); } @@ -232,10 +232,10 @@ static pa_bool_t can_push(pa_memblockq *bq, size_t l) { return TRUE; } - end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : bq->write_index; + end = bq->blocks_tail ? bq->blocks_tail->index + (int64_t) bq->blocks_tail->chunk.length : bq->write_index; /* Make sure that the list doesn't get too long */ - if (bq->write_index + l > end) + if (bq->write_index + (int64_t) l > end) if (bq->write_index + l - bq->read_index > bq->maxlength) return FALSE; @@ -269,7 +269,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { * write to */ if (q) { - while (bq->write_index + chunk.length > q->index) + while (bq->write_index + (int64_t) chunk.length > q->index) if (q->next) q = q->next; else @@ -284,10 +284,10 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { while (q) { - if (bq->write_index >= q->index + q->chunk.length) + if (bq->write_index >= q->index + (int64_t) q->chunk.length) /* We found the entry where we need to place the new entry immediately after */ break; - else if (bq->write_index + chunk.length <= q->index) { + else if (bq->write_index + (int64_t) chunk.length <= q->index) { /* This entry isn't touched at all, let's skip it */ q = q->prev; } else if (bq->write_index <= q->index && @@ -407,7 +407,7 @@ finish: delta = bq->write_index - old; - if (delta >= bq->requested) { + if (delta >= (int64_t) bq->requested) { delta -= bq->requested; bq->requested = 0; } else { @@ -526,7 +526,7 @@ void pa_memblockq_drop(pa_memblockq *bq, size_t length) { pa_assert(p >= bq->read_index); d = p - bq->read_index; - if (d > length) + if (d > (int64_t) length) d = length; bq->read_index += d; @@ -606,7 +606,7 @@ void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { delta = bq->write_index - old; - if (delta >= bq->requested) { + if (delta >= (int64_t) bq->requested) { delta -= bq->requested; bq->requested = 0; } else if (delta >= 0) { @@ -633,7 +633,7 @@ void pa_memblockq_flush(pa_memblockq *bq) { delta = bq->write_index - old; - if (delta >= bq->requested) { + if (delta >= (int64_t) bq->requested) { delta -= bq->requested; bq->requested = 0; } else if (delta >= 0) { diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index ae140ff..8e5bd2d 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -109,8 +109,8 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { m->userdata = NULL; m->core = c; m->n_used = -1; - m->auto_unload = 0; - m->unload_requested = 0; + m->auto_unload = FALSE; + m->unload_requested = FALSE; if (m->init(m) < 0) { pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : ""); @@ -281,7 +281,7 @@ static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) { void pa_module_unload_request(pa_module *m) { pa_assert(m); - m->unload_requested = 1; + m->unload_requested = TRUE; if (!m->core->module_defer_unload_event) m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core); diff --git a/src/pulsecore/module.h b/src/pulsecore/module.h index 25f122d..68c7238 100644 --- a/src/pulsecore/module.h +++ b/src/pulsecore/module.h @@ -45,10 +45,10 @@ struct pa_module { void *userdata; int n_used; - int auto_unload; + pa_bool_t auto_unload; time_t last_used_time; - int unload_requested; + pa_bool_t unload_requested; }; pa_module* pa_module_load(pa_core *c, const char *name, const char*argument); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 0ac3ec1..59d1612 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -71,6 +71,8 @@ #define MAX_CONNECTIONS 64 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */ +#define DEFAULT_TLENGTH_MSEC 2000 /* 2s */ +#define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC typedef struct connection connection; struct pa_protocol_native; @@ -469,9 +471,10 @@ static record_stream* record_stream_new( pa_channel_map *map, const char *name, uint32_t *maxlength, - uint32_t fragment_size, + uint32_t *fragsize, pa_source_output_flags_t flags, - pa_proplist *p) { + pa_proplist *p, + pa_bool_t adjust_latency) { record_stream *s; pa_source_output *source_output; @@ -482,7 +485,6 @@ static record_stream* record_stream_new( pa_assert(ss); pa_assert(name); pa_assert(maxlength); - pa_assert(*maxlength > 0); pa_assert(p); pa_source_output_new_data_init(&data); @@ -508,6 +510,7 @@ static record_stream* record_stream_new( s->parent.process_msg = record_stream_process_msg; s->connection = c; s->source_output = source_output; + 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; @@ -515,11 +518,36 @@ static record_stream* record_stream_new( s->source_output->suspend = source_output_suspend_cb; s->source_output->userdata = s; + if (*maxlength <= 0 || *maxlength > MAX_MEMBLOCKQ_LENGTH) + *maxlength = MAX_MEMBLOCKQ_LENGTH; + if (*fragsize <= 0) + *fragsize = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*1000, &source_output->sample_spec); + + if (adjust_latency) { + pa_usec_t fragsize_usec, source_latency; + + /* So, the user asked us to adjust the latency according to + * the what the source can provide. Half the latency will be + * spent on the hw buffer, half of it in the async buffer + * queue we maintain for each client. */ + + fragsize_usec = pa_bytes_to_usec(*fragsize, &source_output->sample_spec); + + source_latency = pa_source_output_set_requested_latency(source_output, fragsize_usec/2); + + if (fragsize_usec >= source_latency*2) + fragsize_usec -= source_latency; + else + fragsize_usec = source_latency; + + *fragsize = pa_usec_to_bytes(fragsize_usec, &source_output->sample_spec); + } + s->memblockq = pa_memblockq_new( 0, *maxlength, 0, - base = pa_frame_size(&s->source_output->sample_spec), + base = pa_frame_size(&source_output->sample_spec), 1, 0, 0, @@ -527,13 +555,15 @@ static record_stream* record_stream_new( *maxlength = pa_memblockq_get_maxlength(s->memblockq); - s->fragment_size = (fragment_size/base)*base; + s->fragment_size = (*fragsize/base)*base; if (s->fragment_size <= 0) s->fragment_size = base; if (s->fragment_size > *maxlength) s->fragment_size = *maxlength; + *fragsize = s->fragment_size; + *ss = s->source_output->sample_spec; *map = s->source_output->channel_map; @@ -658,10 +688,12 @@ static playback_stream* playback_stream_new( uint32_t *prebuf, uint32_t *minreq, pa_cvolume *volume, + pa_bool_t muted, uint32_t syncid, uint32_t *missing, pa_sink_input_flags_t flags, - pa_proplist *p) { + pa_proplist *p, + pa_bool_t adjust_latency) { playback_stream *s, *ssync; pa_sink_input *sink_input; @@ -674,6 +706,11 @@ static playback_stream* playback_stream_new( pa_assert(ss); pa_assert(name); pa_assert(maxlength); + pa_assert(tlength); + pa_assert(prebuf); + pa_assert(minreq); + pa_assert(volume); + pa_assert(missing); pa_assert(p); /* Find syncid group */ @@ -706,6 +743,7 @@ static playback_stream* playback_stream_new( pa_sink_input_new_data_set_sample_spec(&data, ss); pa_sink_input_new_data_set_channel_map(&data, map); pa_sink_input_new_data_set_volume(&data, volume); + pa_sink_input_new_data_set_muted(&data, muted); data.sync_base = ssync ? ssync->sink_input : NULL; sink_input = pa_sink_input_new(c->protocol->core, &data, flags); @@ -732,13 +770,49 @@ static playback_stream* playback_stream_new( start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0; - silence = pa_silence_memblock_new(c->protocol->core->mempool, &s->sink_input->sample_spec, 0); + if (*maxlength <= 0 || *maxlength > MAX_MEMBLOCKQ_LENGTH) + *maxlength = MAX_MEMBLOCKQ_LENGTH; + if (*tlength <= 0) + *tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*1000, &sink_input->sample_spec); + if (*minreq <= 0) + *minreq = (*tlength*9)/10; + if (*prebuf <= 0) + *prebuf = *tlength; + + if (adjust_latency) { + pa_usec_t tlength_usec, minreq_usec, sink_latency; + + /* So, the user asked us to adjust the latency according to + * the what the sink can provide. Half the latency will be + * spent on the hw buffer, half of it in the async buffer + * queue we maintain for each client. */ + + tlength_usec = pa_bytes_to_usec(*tlength, &sink_input->sample_spec); + minreq_usec = pa_bytes_to_usec(*minreq, &sink_input->sample_spec); + + sink_latency = pa_sink_input_set_requested_latency(sink_input, tlength_usec/2); + + if (tlength_usec >= sink_latency*2) + tlength_usec -= sink_latency; + else + tlength_usec = sink_latency; + + if (minreq_usec >= sink_latency*2) + minreq_usec -= sink_latency; + else + minreq_usec = sink_latency; + + *tlength = pa_usec_to_bytes(tlength_usec, &sink_input->sample_spec); + *minreq = pa_usec_to_bytes(minreq_usec, &sink_input->sample_spec); + } + + silence = pa_silence_memblock_new(c->protocol->core->mempool, &sink_input->sample_spec, 0); s->memblockq = pa_memblockq_new( start_index, *maxlength, *tlength, - pa_frame_size(&s->sink_input->sample_spec), + pa_frame_size(&sink_input->sample_spec), *prebuf, *minreq, 0, @@ -762,7 +836,6 @@ static playback_stream* playback_stream_new( pa_idxset_put(c->output_streams, s, &s->index); pa_sink_input_put(s->sink_input); - return s; } @@ -1230,8 +1303,18 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_tagstruct *reply; pa_sink *sink = NULL; pa_cvolume volume; - int corked; - int no_remap = 0, no_remix = 0, fix_format = 0, fix_rate = 0, fix_channels = 0, no_move = 0, variable_rate = 0; + pa_bool_t + corked = FALSE, + no_remap = FALSE, + no_remix = FALSE, + fix_format = FALSE, + fix_rate = FALSE, + fix_channels = FALSE, + no_move = FALSE, + variable_rate = FALSE, + muted = FALSE, + adjust_latency = FALSE; + pa_sink_input_flags_t flags = 0; pa_proplist *p; @@ -1264,8 +1347,6 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); p = pa_proplist_new(); @@ -1291,7 +1372,9 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC if (c->version >= 13) { - if (pa_tagstruct_get_proplist(t, p) < 0) { + if (pa_tagstruct_get_boolean(t, &muted) < 0 || + pa_tagstruct_get_boolean(t, &adjust_latency) < 0 || + pa_tagstruct_get_proplist(t, p) < 0) { protocol_error(c); pa_proplist_free(p); return; @@ -1331,7 +1414,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) | (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0); - s = playback_stream_new(c, sink, &ss, &map, name, &maxlength, &tlength, &prebuf, &minreq, &volume, syncid, &missing, flags, p); + s = playback_stream_new(c, sink, &ss, &map, name, &maxlength, &tlength, &prebuf, &minreq, &volume, muted, syncid, &missing, flags, p, adjust_latency); pa_proplist_free(p); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -1438,8 +1521,16 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_channel_map map; pa_tagstruct *reply; pa_source *source = NULL; - int corked; - int no_remap = 0, no_remix = 0, fix_format = 0, fix_rate = 0, fix_channels = 0, no_move = 0, variable_rate = 0; + pa_bool_t + corked = FALSE, + no_remap = FALSE, + no_remix = FALSE, + fix_format = FALSE, + fix_rate = FALSE, + fix_channels = FALSE, + no_move = FALSE, + variable_rate = FALSE, + adjust_latency = FALSE; pa_source_output_flags_t flags = 0; pa_proplist *p; @@ -1463,8 +1554,6 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || (*source_name && pa_utf8_valid(source_name)), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); p = pa_proplist_new(); @@ -1490,7 +1579,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ if (c->version >= 13) { - if (pa_tagstruct_get_proplist(t, p) < 0) { + if (pa_tagstruct_get_boolean(t, &adjust_latency) < 0 || + pa_tagstruct_get_proplist(t, p) < 0) { protocol_error(c); pa_proplist_free(p); return; @@ -1530,7 +1620,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) | (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0); - s = record_stream_new(c, source, &ss, &map, name, &maxlength, fragment_size, flags, p); + s = record_stream_new(c, source, &ss, &map, name, &maxlength, &fragment_size, flags, p, adjust_latency); pa_proplist_free(p); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -1544,7 +1634,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ /* Since 0.9 we support sending the buffer metrics back to the client */ pa_tagstruct_putu32(reply, (uint32_t) maxlength); - pa_tagstruct_putu32(reply, (uint32_t) s->fragment_size); + pa_tagstruct_putu32(reply, (uint32_t) fragment_size); } if (c->version >= 12) { @@ -1873,7 +1963,7 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN 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, 0); + pa_tagstruct_put_boolean(reply, FALSE); 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)); @@ -2511,7 +2601,7 @@ static void command_set_mute( connection *c = CONNECTION(userdata); uint32_t idx; - int mute; + pa_bool_t mute; pa_sink *sink = NULL; pa_source *source = NULL; pa_sink_input *si = NULL; @@ -2574,7 +2664,7 @@ static void command_set_mute( static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { connection *c = CONNECTION(userdata); uint32_t idx; - int b; + pa_bool_t b; playback_stream *s; connection_assert_ref(c); @@ -2641,7 +2731,7 @@ static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN connection *c = CONNECTION(userdata); uint32_t idx; record_stream *s; - int b; + pa_bool_t b; connection_assert_ref(c); pa_assert(t); @@ -2719,8 +2809,14 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u return; } - CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); + if (maxlength <= 0 || maxlength > MAX_MEMBLOCKQ_LENGTH) + maxlength = MAX_MEMBLOCKQ_LENGTH; + if (tlength <= 0) + tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*1000, &s->sink_input->sample_spec); + if (minreq <= 0) + minreq = (tlength*9)/10; + if (prebuf <= 0) + prebuf = tlength; pa_memblockq_set_maxlength(s->memblockq, maxlength); pa_memblockq_set_tlength(s->memblockq, tlength); @@ -2751,8 +2847,10 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u return; } - CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); + if (maxlength <= 0 || maxlength > MAX_MEMBLOCKQ_LENGTH) + maxlength = MAX_MEMBLOCKQ_LENGTH; + if (fragsize <= 0) + fragsize = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*1000, &s->source_output->sample_spec); pa_memblockq_set_maxlength(s->memblockq, maxlength); @@ -3336,7 +3434,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa connection *c = CONNECTION(userdata); uint32_t idx = PA_INVALID_INDEX; const char *name = NULL; - int b; + pa_bool_t b; connection_assert_ref(c); pa_assert(t); diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 7c764e3..59341f0 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -282,7 +282,9 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) { goto fail; } - if (st.st_size <= 0 || st.st_size > MAX_SHM_SIZE+PA_ALIGN(sizeof(struct shm_marker)) || PA_ALIGN(st.st_size) != st.st_size) { + if (st.st_size <= 0 || + st.st_size > (off_t) (MAX_SHM_SIZE+PA_ALIGN(sizeof(struct shm_marker))) || + PA_ALIGN((size_t) st.st_size) != (size_t) st.st_size) { pa_log("Invalid shared memory segment size"); goto fail; } diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index e15aa7b..de69945 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -665,11 +665,18 @@ void pa_sink_input_set_max_rewind(pa_sink_input *i, size_t nbytes /* in the sin i->set_max_rewind(i, i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, nbytes) : nbytes); } -void pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) { +pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) { pa_sink_input_assert_ref(i); - pa_assert(PA_SINK_INPUT_LINKED(i->state)); - pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL); + if (usec < i->sink->min_latency) + usec = i->sink->min_latency; + + if (PA_SINK_INPUT_LINKED(i->state)) + pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL); + else + i->thread_info.requested_sink_latency = usec; + + return usec; } void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index c74b891..62464ca 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -226,7 +226,7 @@ void pa_sink_input_unlink(pa_sink_input* i); void pa_sink_input_set_name(pa_sink_input *i, const char *name); -void pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec); +pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec); /* Request that the specified number of bytes already written out to the hw device is rewritten, if possible. If this function is used you diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index cded6ba..39ce83f 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,7 @@ #define MAX_MIX_CHANNELS 32 #define MIX_BUFFER_LENGTH (PA_PAGE_SIZE) +#define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC) static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject); @@ -185,6 +187,8 @@ pa_sink* pa_sink_new( s->rtpoll = NULL; s->silence = pa_silence_memblock_new(core->mempool, &s->sample_spec, 0); + s->min_latency = DEFAULT_MIN_LATENCY; + s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); s->thread_info.soft_volume = s->volume; s->thread_info.soft_muted = s->muted; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 3f16995..23f02c4 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -91,6 +91,8 @@ struct pa_sink { pa_memblock *silence; + pa_usec_t min_latency; /* we won't go below this latency setting */ + int (*set_state)(pa_sink *s, pa_sink_state_t state); /* may be NULL */ int (*set_volume)(pa_sink *s); /* dito */ int (*get_volume)(pa_sink *s); /* dito */ diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 45a8d74..d6c2a2b 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -360,13 +360,20 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_memblock_unref(rchunk.memblock); } -void pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) { +pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) { pa_source_output_assert_ref(o); pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); - pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL); -} + if (usec < o->source->min_latency) + usec = o->source->min_latency; + if (PA_SOURCE_OUTPUT_LINKED(o->state)) + pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL); + else + o->thread_info.requested_source_latency = usec; + + return usec; +} void pa_source_output_cork(pa_source_output *o, pa_bool_t b) { pa_source_output_assert_ref(o); diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index dc95217..0a2286b 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -174,7 +174,7 @@ void pa_source_output_unlink(pa_source_output*o); void pa_source_output_set_name(pa_source_output *i, const char *name); -void pa_source_output_set_requested_latency(pa_source_output *i, pa_usec_t usec); +pa_usec_t pa_source_output_set_requested_latency(pa_source_output *i, pa_usec_t usec); /* Callable by everyone */ diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index cc1c531..b150d8a 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -41,6 +42,8 @@ #include "source.h" +#define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC) + static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject); static void source_free(pa_object *o); @@ -162,6 +165,8 @@ pa_source* pa_source_new( s->muted = data->muted; s->refresh_volume = s->refresh_muted = FALSE; + s->min_latency = DEFAULT_MIN_LATENCY; + s->get_latency = NULL; s->set_volume = NULL; s->get_volume = NULL; diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index c880d3c..3ec8320 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -91,6 +91,8 @@ struct pa_source { pa_asyncmsgq *asyncmsgq; pa_rtpoll *rtpoll; + pa_usec_t min_latency; /* we won't go below this latency setting */ + int (*set_state)(pa_source*source, pa_source_state_t state); /* may be NULL */ int (*set_volume)(pa_source *s); /* dito */ int (*get_volume)(pa_source *s); /* dito */ diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c index 0017c38..92bace2 100644 --- a/src/pulsecore/tagstruct.c +++ b/src/pulsecore/tagstruct.c @@ -163,7 +163,7 @@ void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { t->length += 5+length; } -void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) { +void pa_tagstruct_put_boolean(pa_tagstruct*t, pa_bool_t b) { pa_assert(t); extend(t, 1); @@ -407,7 +407,7 @@ const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) { return t->data; } -int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { +int pa_tagstruct_get_boolean(pa_tagstruct*t, pa_bool_t *b) { pa_assert(t); pa_assert(b); @@ -415,9 +415,9 @@ int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) { return -1; if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE) - *b = 1; + *b = TRUE; else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE) - *b = 0; + *b = FALSE; else return -1; @@ -725,7 +725,7 @@ int pa_tagstruct_get(pa_tagstruct *t, ...) { case PA_TAG_BOOLEAN_TRUE: case PA_TAG_BOOLEAN_FALSE: - ret = pa_tagstruct_get_boolean(t, va_arg(va, int*)); + ret = pa_tagstruct_get_boolean(t, va_arg(va, pa_bool_t*)); break; case PA_TAG_TIMEVAL: diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h index 3b2ce7b..8846b30 100644 --- a/src/pulsecore/tagstruct.h +++ b/src/pulsecore/tagstruct.h @@ -72,7 +72,7 @@ void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t i); void pa_tagstruct_puts64(pa_tagstruct*t, int64_t i); void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss); void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length); -void pa_tagstruct_put_boolean(pa_tagstruct*t, int b); +void pa_tagstruct_put_boolean(pa_tagstruct*t, pa_bool_t b); void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv); void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map); @@ -88,7 +88,7 @@ int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *i); int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *i); int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss); int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length); -int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b); +int pa_tagstruct_get_boolean(pa_tagstruct *t, pa_bool_t *b); int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv); int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map); -- 2.7.4