- 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
This commit is contained in:
Lennart Poettering 2008-04-03 13:40:55 +00:00
parent ecf6439661
commit cdfcf6654c
26 changed files with 708 additions and 260 deletions

View file

@ -79,7 +79,7 @@ New opcodes for notifications:
PA_COMMAND_PLAYBACK_STREAM_MOVED PA_COMMAND_PLAYBACK_STREAM_MOVED
PA_COMMAND_CAPTURE_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: 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: New field for PA_COMMAND_PLAY_SAMPLE:
proplist proplist
New field for PA_COMMAND_PLAY_SAMPLE response: New field for PA_COMMAND_PLAY_SAMPLE response:
idx 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.

View file

@ -73,8 +73,8 @@ PA_MODULE_USAGE(
"tsched_buffer_watermark=<lower fill watermark>"); "tsched_buffer_watermark=<lower fill watermark>");
#define DEFAULT_DEVICE "default" #define DEFAULT_DEVICE "default"
#define DEFAULT_TSCHED_BUFFER_USEC (3*PA_USEC_PER_SEC) #define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC)
#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC) #define DEFAULT_TSCHED_WATERMARK_USEC (10*PA_USEC_PER_MSEC)
struct userdata { struct userdata {
pa_core *core; pa_core *core;
@ -325,7 +325,7 @@ static int unix_write(struct userdata *u) {
} }
static int update_smoother(struct userdata *u) { static int update_smoother(struct userdata *u) {
snd_pcm_sframes_t delay; snd_pcm_sframes_t delay = 0;
int64_t frames; int64_t frames;
int err; int err;
pa_usec_t now1, now2; pa_usec_t now1, now2;
@ -334,6 +334,7 @@ static int update_smoother(struct userdata *u) {
pa_assert(u->pcm_handle); pa_assert(u->pcm_handle);
/* Let's update the time smoother */ /* Let's update the time smoother */
snd_pcm_avail_update(u->pcm_handle); snd_pcm_avail_update(u->pcm_handle);
if (PA_UNLIKELY((err = snd_pcm_delay(u->pcm_handle, &delay)) < 0)) { 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; 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) { static int update_sw_params(struct userdata *u) {
size_t avail_min; size_t avail_min;
int err; int err;
@ -465,6 +491,8 @@ static int update_sw_params(struct userdata *u) {
return err; return err;
} }
update_hwbuf_unused_frames(u);
return 0; return 0;
} }
@ -535,29 +563,6 @@ fail:
return -1; 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) { 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; 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; break;
case PA_SINK_MESSAGE_ADD_INPUT: /* case PA_SINK_MESSAGE_ADD_INPUT: */
case PA_SINK_MESSAGE_REMOVE_INPUT: /* case PA_SINK_MESSAGE_REMOVE_INPUT: */
case PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER: { /* case PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER: { */
int r = pa_sink_process_msg(o, code, data, offset, chunk); /* int r = pa_sink_process_msg(o, code, data, offset, chunk); */
update_hwbuf_unused_frames(u); /* update_hwbuf_unused_frames(u); */
return r; /* return r; */
} /* } */
} }
return pa_sink_process_msg(o, code, data, offset, chunk); 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; 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; 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_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll); pa_rtpoll_install(u->rtpoll);
update_hwbuf_unused_frames(u); /* update_hwbuf_unused_frames(u); */
for (;;) { for (;;) {
int ret; int ret;
@ -1174,6 +1180,9 @@ int pa__init(pa_module*m) {
u->sink->thread_info.max_rewind = use_tsched ? u->hwbuf_size : 0; 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", pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms",
nfrags, (long unsigned) u->fragment_size, nfrags, (long unsigned) u->fragment_size,
(double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC); (double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC);

View file

@ -92,6 +92,8 @@ struct userdata {
snd_mixer_t *mixer_handle; snd_mixer_t *mixer_handle;
snd_mixer_elem_t *mixer_elem; snd_mixer_elem_t *mixer_elem;
long hw_volume_max, hw_volume_min; 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; size_t frame_size, fragment_size, hwbuf_size, tsched_watermark;
unsigned nfragments; unsigned nfragments;
@ -288,25 +290,28 @@ static int unix_read(struct userdata *u) {
} }
static int update_smoother(struct userdata *u) { static int update_smoother(struct userdata *u) {
snd_pcm_status_t *status; snd_pcm_sframes_t delay = 0;
int64_t frames; int64_t frames;
int err; int err;
pa_usec_t now1, now2;
pa_assert(u); pa_assert(u);
pa_assert(u->pcm_handle); pa_assert(u->pcm_handle);
snd_pcm_status_alloca(&status);
/* Let's update the time smoother */ /* 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)); pa_log("Failed to get delay: %s", snd_strerror(err));
return -1; 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; return 0;
} }
@ -373,7 +378,7 @@ static int suspend(struct userdata *u) {
} }
static pa_usec_t hw_sleep_time(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); pa_assert(u);
@ -382,11 +387,17 @@ static pa_usec_t hw_sleep_time(struct userdata *u) {
if (usec <= 0) if (usec <= 0)
usec = pa_bytes_to_usec(u->hwbuf_size, &u->source->sample_spec); usec = pa_bytes_to_usec(u->hwbuf_size, &u->source->sample_spec);
if (usec >= u->tsched_watermark) pa_log_debug("hw buffer time: %u ms", (unsigned) (usec / PA_USEC_PER_MSEC));
usec -= u->tsched_watermark;
wm = pa_bytes_to_usec(u->tsched_watermark, &u->source->sample_spec);
if (usec >= wm)
usec -= wm;
else else
usec /= 2; usec /= 2;
pa_log_debug("after watermark: %u ms", (unsigned) (usec / PA_USEC_PER_MSEC));
return usec; return usec;
} }
@ -470,7 +481,6 @@ static int unsuspend(struct userdata *u) {
/* FIXME: We need to reload the volume somehow */ /* FIXME: We need to reload the volume somehow */
snd_pcm_start(u->pcm_handle); snd_pcm_start(u->pcm_handle);
pa_smoother_resume(u->smoother, pa_rtclock_usec()); pa_smoother_resume(u->smoother, pa_rtclock_usec());
pa_log_info("Resumed successfully..."); pa_log_info("Resumed successfully...");
@ -568,18 +578,24 @@ static int source_get_volume_cb(pa_source *s) {
pa_assert(u->mixer_elem); pa_assert(u->mixer_elem);
for (i = 0; i < s->sample_spec.channels; i++) { 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])); 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) if (u->hw_dB_supported) {
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;
}
if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
goto fail; goto fail;
set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min; 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));
/* 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));
} }
return 0; return 0;
@ -587,8 +603,6 @@ static int source_get_volume_cb(pa_source *s) {
fail: fail:
pa_log_error("Unable to read volume: %s", snd_strerror(err)); pa_log_error("Unable to read volume: %s", snd_strerror(err));
s->get_volume = NULL;
s->set_volume = NULL;
return -1; return -1;
} }
@ -604,17 +618,36 @@ static int source_set_volume_cb(pa_source *s) {
long alsa_vol; long alsa_vol;
pa_volume_t vol; pa_volume_t vol;
pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i])); 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 = (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) if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
goto fail; 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; return 0;
@ -622,8 +655,6 @@ static int source_set_volume_cb(pa_source *s) {
fail: fail:
pa_log_error("Unable to set volume: %s", snd_strerror(err)); pa_log_error("Unable to set volume: %s", snd_strerror(err));
s->get_volume = NULL;
s->set_volume = NULL;
return -1; 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) { 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)); pa_log_error("Unable to get switch: %s", snd_strerror(err));
s->get_mute = NULL;
s->set_mute = NULL;
return -1; 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) { 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)); pa_log_error("Unable to set switch: %s", snd_strerror(err));
s->get_mute = NULL;
s->set_mute = NULL;
return -1; return -1;
} }
return 0; 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) { static void thread_func(void *userdata) {
struct userdata *u = userdata; struct userdata *u = userdata;
@ -694,10 +727,11 @@ static void thread_func(void *userdata) {
goto fail; goto fail;
} }
if (update_smoother(u) < 0) if (work_done)
goto fail; if (update_smoother(u) < 0)
goto fail;
if (u->use_tsched && work_done) { if (u->use_tsched) {
pa_usec_t usec, cusec; pa_usec_t usec, cusec;
/* OK, the capture buffer is now empty, let's /* 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 */ /* We don't trust the conversion, so we wake up whatever comes first */
pa_rtpoll_set_timer_relative(u->rtpoll, PA_MIN(usec, cusec)); 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 */ /* Hmm, nothing to do. Let's sleep */
@ -797,7 +835,7 @@ int pa__init(pa_module*m) {
const char *dev_id; const char *dev_id;
pa_sample_spec ss; pa_sample_spec ss;
pa_channel_map map; 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; snd_pcm_uframes_t period_frames, tsched_frames;
size_t frame_size; size_t frame_size;
snd_pcm_info_t *pcm_info = NULL; snd_pcm_info_t *pcm_info = NULL;
@ -846,6 +884,7 @@ int pa__init(pa_module*m) {
goto fail; goto fail;
} }
hwbuf_size = frag_size * nfrags;
period_frames = frag_size/frame_size; period_frames = frag_size/frame_size;
tsched_frames = tsched_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->rtpoll = pa_rtpoll_new();
u->alsa_rtpoll_item = NULL; u->alsa_rtpoll_item = NULL;
pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); 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); u->smoother = pa_smoother_new(DEFAULT_TSCHED_WATERMARK_USEC, DEFAULT_TSCHED_WATERMARK_USEC, TRUE);
pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec()); pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());
@ -929,9 +969,6 @@ int pa__init(pa_module*m) {
goto fail; goto fail;
} }
if (update_sw_params(u) < 0)
goto fail;
/* ALSA might tweak the sample spec, so recalculate the frame size */ /* ALSA might tweak the sample spec, so recalculate the frame size */
frame_size = pa_frame_size(&ss); 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->parent.process_msg = source_process_msg;
u->source->update_requested_latency = source_update_requested_latency_cb;
u->source->userdata = u; u->source->userdata = u;
pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); 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->hwbuf_size = u->fragment_size * nfrags;
u->tsched_watermark = tsched_watermark; u->tsched_watermark = tsched_watermark;
u->frame_index = 0; 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;
pa_log_info("Using %u fragments of size %lu bytes.", nfrags, (long unsigned) u->fragment_size); 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);
if (update_sw_params(u) < 0)
goto fail;
if (u->mixer_handle) { if (u->mixer_handle) {
pa_assert(u->mixer_elem); pa_assert(u->mixer_elem);
if (snd_mixer_selem_has_capture_volume(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) { if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0 &&
u->source->get_volume = source_get_volume_cb; snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max) >= 0) {
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); pa_bool_t suitable = TRUE;
u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
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)) { if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) {
u->source->get_mute = source_get_mute_cb; u->source->get_mute = source_get_mute_cb;
u->source->set_mute = source_set_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(); u->mixer_fdl = pa_alsa_fdlist_new();
@ -1044,10 +1143,21 @@ int pa__init(pa_module*m) {
goto fail; goto fail;
} }
/* Get initial mixer settings */ /* Get initial mixer settings */
if (u->source->get_volume) if (data.volume_is_set) {
u->source->get_volume(u->source); if (u->source->set_volume)
if (u->source->get_mute) u->source->set_volume(u->source);
u->source->get_mute(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); pa_source_put(u->source);

View file

@ -251,7 +251,7 @@ int pa_oss_set_fragments(int fd, int nfrags, int frag_size) {
return 0; 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]; char cv[PA_CVOLUME_SNPRINT_MAX];
unsigned vol; 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; 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]; char cv[PA_CVOLUME_SNPRINT_MAX];
unsigned vol; unsigned vol;
pa_volume_t l, r; pa_volume_t l, r;

View file

@ -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_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_set_volume(int fd, unsigned 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_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); int pa_oss_get_hw_description(const char *dev, char *name, size_t l);

View file

@ -210,16 +210,68 @@ typedef enum pa_stream_flags {
* on older servers. \since * on older servers. \since
* 0.9.8 */ * 0.9.8 */
PA_STREAM_PEAK_DETECT = 2048, /**< Find peaks instead of 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; } pa_stream_flags_t;
/** Playback and record buffer metrics */ /** Playback and record buffer metrics */
typedef struct pa_buffer_attr { typedef struct pa_buffer_attr {
uint32_t maxlength; /**< Maximum length of the buffer */ uint32_t maxlength; /**< Maximum length of the
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 */ * buffer. Setting this to 0 will
uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ * initialize this to the maximum value
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 */ * supported by server, which is
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. */ * 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; } pa_buffer_attr;
/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ /** 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 * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of
* sign issues!) When connected to a monitor source sink_usec contains * sign issues!) When connected to a monitor source sink_usec contains
* the latency of the owning sink. The two latency estimations * 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 { typedef struct pa_timing_info {
struct timeval timestamp; /**< The time when this timing info structure was current */ struct timeval timestamp; /**< The time when this timing info structure was current */
int synchronized_clocks; /**< Non-zero if the local and the 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 * want to use it. Consider using
* PA_SEEK_RELATIVE_ON_READ * PA_SEEK_RELATIVE_ON_READ
* instead. \since 0.8 */ * 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; } pa_timing_info;
/** A structure for the spawn api. This may be used to integrate auto /** A structure for the spawn api. This may be used to integrate auto

View file

@ -149,6 +149,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P
while (!pa_tagstruct_eof(t)) { while (!pa_tagstruct_eof(t)) {
pa_sink_info i; pa_sink_info i;
pa_bool_t mute = FALSE;
memset(&i, 0, sizeof(i)); memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new(); 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_get_channel_map(t, &i.channel_map) < 0 ||
pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
pa_tagstruct_get_cvolume(t, &i.volume) < 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_getu32(t, &i.monitor_source) < 0 ||
pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
pa_tagstruct_get_usec(t, &i.latency) < 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; goto finish;
} }
i.mute = (int) mute;
i.flags = (pa_sink_flags_t) flags; i.flags = (pa_sink_flags_t) flags;
if (o->callback) { 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)) { while (!pa_tagstruct_eof(t)) {
pa_source_info i; pa_source_info i;
uint32_t flags; uint32_t flags;
pa_bool_t mute = FALSE;
memset(&i, 0, sizeof(i)); memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new(); 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_get_channel_map(t, &i.channel_map) < 0 ||
pa_tagstruct_getu32(t, &i.owner_module) < 0 || pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
pa_tagstruct_get_cvolume(t, &i.volume) < 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_getu32(t, &i.monitor_of_sink) < 0 ||
pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 ||
pa_tagstruct_get_usec(t, &i.latency) < 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; goto finish;
} }
i.mute = (int) mute;
i.flags = (pa_source_flags_t) flags; i.flags = (pa_source_flags_t) flags;
if (o->callback) { 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)) { while (!pa_tagstruct_eof(t)) {
pa_module_info i; pa_module_info i;
pa_bool_t auto_unload = FALSE;
memset(&i, 0, sizeof(i)); memset(&i, 0, sizeof(i));
if (pa_tagstruct_getu32(t, &i.index) < 0 || if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_gets(t, &i.name) < 0 ||
pa_tagstruct_gets(t, &i.argument) < 0 || pa_tagstruct_gets(t, &i.argument) < 0 ||
pa_tagstruct_getu32(t, &i.n_used) < 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); pa_context_fail(o->context, PA_ERR_PROTOCOL);
goto finish; goto finish;
} }
i.auto_unload = (int) auto_unload;
if (o->callback) { if (o->callback) {
pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata); 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)) { while (!pa_tagstruct_eof(t)) {
pa_sink_input_info i; pa_sink_input_info i;
pa_bool_t mute = FALSE;
memset(&i, 0, sizeof(i)); memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new(); 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_get_usec(t, &i.sink_usec) < 0 ||
pa_tagstruct_gets(t, &i.resample_method) < 0 || pa_tagstruct_gets(t, &i.resample_method) < 0 ||
pa_tagstruct_gets(t, &i.driver) < 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)) { (o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0)) {
pa_context_fail(o->context, PA_ERR_PROTOCOL); 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; goto finish;
} }
i.mute = (int) mute;
if (o->callback) { if (o->callback) {
pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata); 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)) { while (!pa_tagstruct_eof(t)) {
pa_sample_info i; pa_sample_info i;
pa_bool_t lazy = FALSE;
memset(&i, 0, sizeof(i)); memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new(); 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_sample_spec(t, &i.sample_spec) < 0 ||
pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 ||
pa_tagstruct_getu32(t, &i.bytes) < 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 || pa_tagstruct_gets(t, &i.filename) < 0 ||
(o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 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; goto finish;
} }
i.lazy = (int) lazy;
if (o->callback) { if (o->callback) {
pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata); cb(o->context, &i, 0, o->userdata);
@ -1192,6 +1205,8 @@ finish:
pa_operation_unref(o); 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_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_tagstruct *t;
pa_operation *o; pa_operation *o;
@ -1216,6 +1231,8 @@ pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *na
return o; 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_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_tagstruct *t;
pa_operation *o; pa_operation *o;
@ -1238,10 +1255,15 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx,
return o; 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) { 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); 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* 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_operation *o;
pa_tagstruct *t; pa_tagstruct *t;
@ -1268,6 +1290,8 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo
return o; 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* 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_operation *o;
pa_tagstruct *t; pa_tagstruct *t;
@ -1291,6 +1315,8 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name
return o; 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* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) {
pa_operation *o; pa_operation *o;
pa_tagstruct *t; pa_tagstruct *t;

View file

@ -212,7 +212,11 @@ PA_C_DECL_BEGIN
#define PA_PORT_ANALOG_5_1 "analog-5-1" #define PA_PORT_ANALOG_5_1 "analog-5-1"
#define PA_PORT_ANALOG_4_0 "analog-4-0" #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 { typedef struct pa_sink_info {
const char *name; /**< Name of the sink */ const char *name; /**< Name of the sink */
uint32_t index; /**< Index 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 */ int mute; /**< Mute switch of the sink \since 0.8 */
uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ uint32_t monitor_source; /**< Index of the monitor source connected to this sink */
const char *monitor_source_name; /**< The name of the monitor source */ 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 */ const char *driver; /**< Driver name. \since 0.8 */
pa_sink_flags_t flags; /**< Flags \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; } pa_sink_info;
/** Callback prototype for pa_context_get_sink_info_by_name() and friends */ /** 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 */ /** Get the complete sink list */
pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata); 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 { typedef struct pa_source_info {
const char *name; /**< Name of the source */ const char *name; /**< Name of the source */
uint32_t index; /**< Index 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 */ const char *driver; /**< Driver name \since 0.8 */
pa_source_flags_t flags; /**< Flags \since 0.8 */ pa_source_flags_t flags; /**< Flags \since 0.8 */
pa_proplist *proplist; /**< Property list \since 0.9.10 */ 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; } pa_source_info;
/** Callback prototype for pa_context_get_source_info_by_name() and friends */ /** 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 */ /** Get the complete source list */
pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata); 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 { typedef struct pa_server_info {
const char *user_name; /**< User name of the daemon process */ const char *user_name; /**< User name of the daemon process */
const char *host_name; /**< Host name the daemon is running on */ 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 */ /** Get some information about the server */
pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata); 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 { typedef struct pa_module_info {
uint32_t index; /**< Index of the module */ uint32_t index; /**< Index of the module */
const char*name, /**< Name 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 */ /** 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); 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 { typedef struct pa_client_info {
uint32_t index; /**< Index of this client */ uint32_t index; /**< Index of this client */
const char *name; /**< Name 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 */ /** Get the complete client list */
pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata); 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 { typedef struct pa_sink_input_info {
uint32_t index; /**< Index of the sink input */ uint32_t index; /**< Index of the sink input */
const char *name; /**< Name 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 */ /** 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); 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 { typedef struct pa_source_output_info {
uint32_t index; /**< Index of the sink input */ uint32_t index; /**< Index of the sink input */
const char *name; /**< Name 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 */ /** 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); 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 */ /** Move the specified source output to a different source. \since 0.9.5 */
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); 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 device specified by its name */ /** Move the specified source output to a different source. \since 0.9.5 */
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); 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 device specified by its index \since 0.8 */ /** Suspend/Resume a source. \since 0.9.7 */
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); 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 mute switch of a sink device specified by its name \since 0.8 */ /** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */
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); 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 sink input stream */ /** Kill a source output. \since 0.5 */
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); 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 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);
/** Set the volume of a source device specified by its index \since 0.8 */ /** @{ \name Statistics */
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 */ /** Memory block statistics. Please note that this structure
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); * can be extended as part of evolutionary API updates at any time in
* any new release. */
/** 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);
/** Memory block statistics */
typedef struct pa_stat_info { typedef struct pa_stat_info {
uint32_t memblock_total; /**< Currently allocated memory blocks */ 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; /**< 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 */ /** Get daemon memory block statistics */
pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata); 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 { typedef struct pa_sample_info {
uint32_t index; /**< Index of this entry */ uint32_t index; /**< Index of this entry */
const char *name; /**< Name 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. */ /** 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); 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 */ /** \cond fulldocs */
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 */ /** @{ \name Autoload Entries */
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);
/** 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);
/** Type of an autoload entry. \since 0.5 */ /** Type of an autoload entry. \since 0.5 */
typedef enum pa_autoload_type { typedef enum pa_autoload_type {
@ -473,7 +557,9 @@ typedef enum pa_autoload_type {
PA_AUTOLOAD_SOURCE = 1 PA_AUTOLOAD_SOURCE = 1
} pa_autoload_type_t; } 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 { typedef struct pa_autoload_info {
uint32_t index; /**< Index of this autoload entry */ uint32_t index; /**< Index of this autoload entry */
const char *name; /**< Name of the sink or source */ 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 */ /** 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); 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 */ /** \endcond */
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);
PA_C_DECL_END PA_C_DECL_END

View file

@ -292,7 +292,7 @@ void pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED u
pa_stream *s; pa_stream *s;
uint32_t channel; uint32_t channel;
const char *dn; const char *dn;
int suspended; pa_bool_t suspended;
uint32_t di; uint32_t di;
pa_assert(pd); 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_context *c = userdata;
pa_stream *s; pa_stream *s;
uint32_t channel; uint32_t channel;
int suspended; pa_bool_t suspended;
pa_assert(pd); pa_assert(pd);
pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_SUSPENDED || command == PA_COMMAND_RECORD_STREAM_SUSPENDED); 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(attr);
pa_assert(ss); pa_assert(ss);
attr->tlength = pa_bytes_per_second(ss)/2; if (s->context->version >= 13)
attr->maxlength = (attr->tlength*3)/2; return;
attr->minreq = attr->tlength/50;
attr->prebuf = attr->tlength - attr->minreq; /* Version older than 0.9.10 didn't do server side buffer_attr
attr->fragsize = attr->tlength/50; * 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) { 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_sample_spec ss;
pa_channel_map cm; pa_channel_map cm;
const char *dn = NULL; const char *dn = NULL;
int suspended; pa_bool_t suspended;
if (pa_tagstruct_get_sample_spec(t, &ss) < 0 || if (pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
pa_tagstruct_get_channel_map(t, &cm) < 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_buffer_attr attr;
pa_operation *o; 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 /* If we need to update the buffer metrics, we wait for
* the the OK for that call before we go to * the the OK for that call before we go to
@ -718,7 +735,9 @@ static int create_stream(
PA_STREAM_FIX_CHANNELS| PA_STREAM_FIX_CHANNELS|
PA_STREAM_DONT_MOVE| PA_STREAM_DONT_MOVE|
PA_STREAM_VARIABLE_RATE| 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 >= 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); 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 * when they are passed but actually not supported. This makes
* client development easier */ * 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, !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); 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->buffer_attr = *attr;
s->manual_buffer_attr = TRUE; s->manual_buffer_attr = TRUE;
} else { } else {
/* half a second, with minimum request of 10 ms */ memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
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;
s->manual_buffer_attr = FALSE; s->manual_buffer_attr = FALSE;
} }
automatic_buffer_attr(s, &s->buffer_attr, &s->sample_spec);
if (!dev) if (!dev)
dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source; 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->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_init_proplist(s->proplist);
pa_tagstruct_put( pa_tagstruct_put(
t, t,
PA_TAG_BOOLEAN, flags & PA_STREAM_PEAK_DETECT, PA_TAG_BOOLEAN, flags & PA_STREAM_ADJUST_LATENCY,
PA_TAG_PROPLIST, s->proplist, PA_TAG_PROPLIST, s->proplist,
PA_TAG_INVALID); PA_TAG_INVALID);
} }
@ -1023,6 +1046,7 @@ static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command,
pa_operation *o = userdata; pa_operation *o = userdata;
struct timeval local, remote, now; struct timeval local, remote, now;
pa_timing_info *i; pa_timing_info *i;
pa_bool_t playing = FALSE;
pa_assert(pd); pa_assert(pd);
pa_assert(o); 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 || } else if (pa_tagstruct_get_usec(t, &i->sink_usec) < 0 ||
pa_tagstruct_get_usec(t, &i->source_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, &local) < 0 ||
pa_tagstruct_get_timeval(t, &remote) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 ||
pa_tagstruct_gets64(t, &i->write_index) < 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 { } else {
o->stream->timing_info_valid = 1; o->stream->timing_info_valid = 1;
i->playing = (int) playing;
pa_gettimeofday(&now); pa_gettimeofday(&now);

View file

@ -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}, { "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}, { "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}, { "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-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, "Add autoload entry for a source (args: source, 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, "Remove autoload entry for a sink (args: name)", 2}, { "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, "Remove autoload entry for a source (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}, { "dump", pa_cli_command_dump, "Dump daemon configuration", 1},
{ "list-props", pa_cli_command_list_props, NULL, 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}, { "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_sink_inputs(c, t, buf, fail);
pa_cli_command_source_outputs(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_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; 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(buf);
pa_assert(fail); 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))) { 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"); pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n");
return -1; 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(buf);
pa_assert(fail); 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))) { if (!(name = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a device name\n"); pa_strbuf_puts(buf, "You need to specify a device name\n");
return -1; 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(buf);
pa_assert(fail); 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_assert_se(s = pa_autoload_list_to_string(c));
pa_strbuf_puts(buf, s); pa_strbuf_puts(buf, s);
pa_xfree(s); pa_xfree(s);

View file

@ -204,4 +204,17 @@ static inline const char *pa_strnull(const char *x) {
return x ? x : "(null)"; 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 #endif

View file

@ -138,7 +138,7 @@ static void fix_current_read(pa_memblockq *bq) {
break; break;
/* Scan right */ /* 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; bq->current_read = bq->current_read->next;
/* At this point current_read will either point at or left of the /* 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; bq->current_write = bq->blocks_tail;
/* Scan right */ /* 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) if (bq->current_write->next)
bq->current_write = 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; 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); drop_block(bq, bq->blocks);
} }
@ -232,10 +232,10 @@ static pa_bool_t can_push(pa_memblockq *bq, size_t l) {
return TRUE; 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 */ /* 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) if (bq->write_index + l - bq->read_index > bq->maxlength)
return FALSE; return FALSE;
@ -269,7 +269,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
* write to */ * write to */
if (q) { if (q) {
while (bq->write_index + chunk.length > q->index) while (bq->write_index + (int64_t) chunk.length > q->index)
if (q->next) if (q->next)
q = q->next; q = q->next;
else else
@ -284,10 +284,10 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
while (q) { 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 */ /* We found the entry where we need to place the new entry immediately after */
break; 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 */ /* This entry isn't touched at all, let's skip it */
q = q->prev; q = q->prev;
} else if (bq->write_index <= q->index && } else if (bq->write_index <= q->index &&
@ -407,7 +407,7 @@ finish:
delta = bq->write_index - old; delta = bq->write_index - old;
if (delta >= bq->requested) { if (delta >= (int64_t) bq->requested) {
delta -= bq->requested; delta -= bq->requested;
bq->requested = 0; bq->requested = 0;
} else { } else {
@ -526,7 +526,7 @@ void pa_memblockq_drop(pa_memblockq *bq, size_t length) {
pa_assert(p >= bq->read_index); pa_assert(p >= bq->read_index);
d = p - bq->read_index; d = p - bq->read_index;
if (d > length) if (d > (int64_t) length)
d = length; d = length;
bq->read_index += d; 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; delta = bq->write_index - old;
if (delta >= bq->requested) { if (delta >= (int64_t) bq->requested) {
delta -= bq->requested; delta -= bq->requested;
bq->requested = 0; bq->requested = 0;
} else if (delta >= 0) { } else if (delta >= 0) {
@ -633,7 +633,7 @@ void pa_memblockq_flush(pa_memblockq *bq) {
delta = bq->write_index - old; delta = bq->write_index - old;
if (delta >= bq->requested) { if (delta >= (int64_t) bq->requested) {
delta -= bq->requested; delta -= bq->requested;
bq->requested = 0; bq->requested = 0;
} else if (delta >= 0) { } else if (delta >= 0) {

View file

@ -109,8 +109,8 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
m->userdata = NULL; m->userdata = NULL;
m->core = c; m->core = c;
m->n_used = -1; m->n_used = -1;
m->auto_unload = 0; m->auto_unload = FALSE;
m->unload_requested = 0; m->unload_requested = FALSE;
if (m->init(m) < 0) { if (m->init(m) < 0) {
pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : ""); 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) { void pa_module_unload_request(pa_module *m) {
pa_assert(m); pa_assert(m);
m->unload_requested = 1; m->unload_requested = TRUE;
if (!m->core->module_defer_unload_event) 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); m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core);

View file

@ -45,10 +45,10 @@ struct pa_module {
void *userdata; void *userdata;
int n_used; int n_used;
int auto_unload; pa_bool_t auto_unload;
time_t last_used_time; 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); pa_module* pa_module_load(pa_core *c, const char *name, const char*argument);

View file

@ -71,6 +71,8 @@
#define MAX_CONNECTIONS 64 #define MAX_CONNECTIONS 64
#define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */ #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; typedef struct connection connection;
struct pa_protocol_native; struct pa_protocol_native;
@ -469,9 +471,10 @@ static record_stream* record_stream_new(
pa_channel_map *map, pa_channel_map *map,
const char *name, const char *name,
uint32_t *maxlength, uint32_t *maxlength,
uint32_t fragment_size, uint32_t *fragsize,
pa_source_output_flags_t flags, pa_source_output_flags_t flags,
pa_proplist *p) { pa_proplist *p,
pa_bool_t adjust_latency) {
record_stream *s; record_stream *s;
pa_source_output *source_output; pa_source_output *source_output;
@ -482,7 +485,6 @@ static record_stream* record_stream_new(
pa_assert(ss); pa_assert(ss);
pa_assert(name); pa_assert(name);
pa_assert(maxlength); pa_assert(maxlength);
pa_assert(*maxlength > 0);
pa_assert(p); pa_assert(p);
pa_source_output_new_data_init(&data); 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->parent.process_msg = record_stream_process_msg;
s->connection = c; s->connection = c;
s->source_output = source_output; s->source_output = source_output;
s->source_output->push = source_output_push_cb; s->source_output->push = source_output_push_cb;
s->source_output->kill = source_output_kill_cb; s->source_output->kill = source_output_kill_cb;
s->source_output->get_latency = source_output_get_latency_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->suspend = source_output_suspend_cb;
s->source_output->userdata = s; 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( s->memblockq = pa_memblockq_new(
0, 0,
*maxlength, *maxlength,
0, 0,
base = pa_frame_size(&s->source_output->sample_spec), base = pa_frame_size(&source_output->sample_spec),
1, 1,
0, 0,
0, 0,
@ -527,13 +555,15 @@ static record_stream* record_stream_new(
*maxlength = pa_memblockq_get_maxlength(s->memblockq); *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) if (s->fragment_size <= 0)
s->fragment_size = base; s->fragment_size = base;
if (s->fragment_size > *maxlength) if (s->fragment_size > *maxlength)
s->fragment_size = *maxlength; s->fragment_size = *maxlength;
*fragsize = s->fragment_size;
*ss = s->source_output->sample_spec; *ss = s->source_output->sample_spec;
*map = s->source_output->channel_map; *map = s->source_output->channel_map;
@ -658,10 +688,12 @@ static playback_stream* playback_stream_new(
uint32_t *prebuf, uint32_t *prebuf,
uint32_t *minreq, uint32_t *minreq,
pa_cvolume *volume, pa_cvolume *volume,
pa_bool_t muted,
uint32_t syncid, uint32_t syncid,
uint32_t *missing, uint32_t *missing,
pa_sink_input_flags_t flags, pa_sink_input_flags_t flags,
pa_proplist *p) { pa_proplist *p,
pa_bool_t adjust_latency) {
playback_stream *s, *ssync; playback_stream *s, *ssync;
pa_sink_input *sink_input; pa_sink_input *sink_input;
@ -674,6 +706,11 @@ static playback_stream* playback_stream_new(
pa_assert(ss); pa_assert(ss);
pa_assert(name); pa_assert(name);
pa_assert(maxlength); pa_assert(maxlength);
pa_assert(tlength);
pa_assert(prebuf);
pa_assert(minreq);
pa_assert(volume);
pa_assert(missing);
pa_assert(p); pa_assert(p);
/* Find syncid group */ /* 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_sample_spec(&data, ss);
pa_sink_input_new_data_set_channel_map(&data, map); 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_volume(&data, volume);
pa_sink_input_new_data_set_muted(&data, muted);
data.sync_base = ssync ? ssync->sink_input : NULL; data.sync_base = ssync ? ssync->sink_input : NULL;
sink_input = pa_sink_input_new(c->protocol->core, &data, flags); 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; 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( s->memblockq = pa_memblockq_new(
start_index, start_index,
*maxlength, *maxlength,
*tlength, *tlength,
pa_frame_size(&s->sink_input->sample_spec), pa_frame_size(&sink_input->sample_spec),
*prebuf, *prebuf,
*minreq, *minreq,
0, 0,
@ -762,7 +836,6 @@ static playback_stream* playback_stream_new(
pa_idxset_put(c->output_streams, s, &s->index); pa_idxset_put(c->output_streams, s, &s->index);
pa_sink_input_put(s->sink_input); pa_sink_input_put(s->sink_input);
return s; return s;
} }
@ -1230,8 +1303,18 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC
pa_tagstruct *reply; pa_tagstruct *reply;
pa_sink *sink = NULL; pa_sink *sink = NULL;
pa_cvolume volume; pa_cvolume volume;
int corked; pa_bool_t
int no_remap = 0, no_remix = 0, fix_format = 0, fix_rate = 0, fix_channels = 0, no_move = 0, variable_rate = 0; 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_sink_input_flags_t flags = 0;
pa_proplist *p; 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_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), 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, 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(); 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 (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); protocol_error(c);
pa_proplist_free(p); pa_proplist_free(p);
return; 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) | (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
(variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 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); pa_proplist_free(p);
CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); 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_channel_map map;
pa_tagstruct *reply; pa_tagstruct *reply;
pa_source *source = NULL; pa_source *source = NULL;
int corked; pa_bool_t
int no_remap = 0, no_remix = 0, fix_format = 0, fix_rate = 0, fix_channels = 0, no_move = 0, variable_rate = 0; 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_source_output_flags_t flags = 0;
pa_proplist *p; 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, 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, 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, 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(); 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 (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); protocol_error(c);
pa_proplist_free(p); pa_proplist_free(p);
return; 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) | (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
(variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 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); pa_proplist_free(p);
CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); 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 */ /* 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) maxlength);
pa_tagstruct_putu32(reply, (uint32_t) s->fragment_size); pa_tagstruct_putu32(reply, (uint32_t) fragment_size);
} }
if (c->version >= 12) { 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); 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, 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_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, &tv);
pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
@ -2511,7 +2601,7 @@ static void command_set_mute(
connection *c = CONNECTION(userdata); connection *c = CONNECTION(userdata);
uint32_t idx; uint32_t idx;
int mute; pa_bool_t mute;
pa_sink *sink = NULL; pa_sink *sink = NULL;
pa_source *source = NULL; pa_source *source = NULL;
pa_sink_input *si = 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) { 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); connection *c = CONNECTION(userdata);
uint32_t idx; uint32_t idx;
int b; pa_bool_t b;
playback_stream *s; playback_stream *s;
connection_assert_ref(c); 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); connection *c = CONNECTION(userdata);
uint32_t idx; uint32_t idx;
record_stream *s; record_stream *s;
int b; pa_bool_t b;
connection_assert_ref(c); connection_assert_ref(c);
pa_assert(t); pa_assert(t);
@ -2719,8 +2809,14 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
return; return;
} }
CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); if (maxlength <= 0 || maxlength > MAX_MEMBLOCKQ_LENGTH)
CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); 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_maxlength(s->memblockq, maxlength);
pa_memblockq_set_tlength(s->memblockq, tlength); 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; return;
} }
CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID); if (maxlength <= 0 || maxlength > MAX_MEMBLOCKQ_LENGTH)
CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID); 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); 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); connection *c = CONNECTION(userdata);
uint32_t idx = PA_INVALID_INDEX; uint32_t idx = PA_INVALID_INDEX;
const char *name = NULL; const char *name = NULL;
int b; pa_bool_t b;
connection_assert_ref(c); connection_assert_ref(c);
pa_assert(t); pa_assert(t);

View file

@ -282,7 +282,9 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) {
goto fail; 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"); pa_log("Invalid shared memory segment size");
goto fail; goto fail;
} }

View file

@ -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); 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_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) { void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) {

View file

@ -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_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 /* Request that the specified number of bytes already written out to
the hw device is rewritten, if possible. If this function is used you the hw device is rewritten, if possible. If this function is used you

View file

@ -33,6 +33,7 @@
#include <pulse/introspect.h> #include <pulse/introspect.h>
#include <pulse/utf8.h> #include <pulse/utf8.h>
#include <pulse/xmalloc.h> #include <pulse/xmalloc.h>
#include <pulse/timeval.h>
#include <pulsecore/sink-input.h> #include <pulsecore/sink-input.h>
#include <pulsecore/namereg.h> #include <pulsecore/namereg.h>
@ -47,6 +48,7 @@
#define MAX_MIX_CHANNELS 32 #define MAX_MIX_CHANNELS 32
#define MIX_BUFFER_LENGTH (PA_PAGE_SIZE) #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); static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
@ -185,6 +187,8 @@ pa_sink* pa_sink_new(
s->rtpoll = NULL; s->rtpoll = NULL;
s->silence = pa_silence_memblock_new(core->mempool, &s->sample_spec, 0); 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.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_volume = s->volume;
s->thread_info.soft_muted = s->muted; s->thread_info.soft_muted = s->muted;

View file

@ -91,6 +91,8 @@ struct pa_sink {
pa_memblock *silence; 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_state)(pa_sink *s, pa_sink_state_t state); /* may be NULL */
int (*set_volume)(pa_sink *s); /* dito */ int (*set_volume)(pa_sink *s); /* dito */
int (*get_volume)(pa_sink *s); /* dito */ int (*get_volume)(pa_sink *s); /* dito */

View file

@ -360,13 +360,20 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
pa_memblock_unref(rchunk.memblock); 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_source_output_assert_ref(o);
pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state)); 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) { void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
pa_source_output_assert_ref(o); pa_source_output_assert_ref(o);

View file

@ -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_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 */ /* Callable by everyone */

View file

@ -32,6 +32,7 @@
#include <pulse/utf8.h> #include <pulse/utf8.h>
#include <pulse/xmalloc.h> #include <pulse/xmalloc.h>
#include <pulse/timeval.h>
#include <pulsecore/source-output.h> #include <pulsecore/source-output.h>
#include <pulsecore/namereg.h> #include <pulsecore/namereg.h>
@ -41,6 +42,8 @@
#include "source.h" #include "source.h"
#define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject); static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
static void source_free(pa_object *o); static void source_free(pa_object *o);
@ -162,6 +165,8 @@ pa_source* pa_source_new(
s->muted = data->muted; s->muted = data->muted;
s->refresh_volume = s->refresh_muted = FALSE; s->refresh_volume = s->refresh_muted = FALSE;
s->min_latency = DEFAULT_MIN_LATENCY;
s->get_latency = NULL; s->get_latency = NULL;
s->set_volume = NULL; s->set_volume = NULL;
s->get_volume = NULL; s->get_volume = NULL;

View file

@ -91,6 +91,8 @@ struct pa_source {
pa_asyncmsgq *asyncmsgq; pa_asyncmsgq *asyncmsgq;
pa_rtpoll *rtpoll; 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_state)(pa_source*source, pa_source_state_t state); /* may be NULL */
int (*set_volume)(pa_source *s); /* dito */ int (*set_volume)(pa_source *s); /* dito */
int (*get_volume)(pa_source *s); /* dito */ int (*get_volume)(pa_source *s); /* dito */

View file

@ -163,7 +163,7 @@ void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
t->length += 5+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); pa_assert(t);
extend(t, 1); extend(t, 1);
@ -407,7 +407,7 @@ const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
return t->data; 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(t);
pa_assert(b); pa_assert(b);
@ -415,9 +415,9 @@ int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) {
return -1; return -1;
if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE) if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
*b = 1; *b = TRUE;
else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE) else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
*b = 0; *b = FALSE;
else else
return -1; return -1;
@ -725,7 +725,7 @@ int pa_tagstruct_get(pa_tagstruct *t, ...) {
case PA_TAG_BOOLEAN_TRUE: case PA_TAG_BOOLEAN_TRUE:
case PA_TAG_BOOLEAN_FALSE: 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; break;
case PA_TAG_TIMEVAL: case PA_TAG_TIMEVAL:

View file

@ -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_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_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_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_timeval(pa_tagstruct*t, const struct timeval *tv);
void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); 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); 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_gets64(pa_tagstruct*t, int64_t *i);
int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss); 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_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_timeval(pa_tagstruct*t, struct timeval *tv);
int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); 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); int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map);