if (PA_UNLIKELY(n <= u->hwbuf_unused_frames)) {
- if (polled)
+ if (polled && pa_log_ratelimit())
pa_log("ALSA woke us up to write new data to the device, but there was actually nothing to write! "
"Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers. "
"We were woken up with POLLOUT set -- however a subsequent snd_pcm_avail_update() returned 0.");
if (PA_UNLIKELY(n <= u->hwbuf_unused_frames)) {
- if (polled)
+ if (polled && pa_log_ratelimit())
pa_log("ALSA woke us up to write new data to the device, but there was actually nothing to write! "
"Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers. "
"We were woken up with POLLOUT set -- however a subsequent snd_pcm_avail_update() returned 0.");
case PA_SINK_UNLINKED:
case PA_SINK_INIT:
+ case PA_SINK_INVALID_STATE:
;
}
return PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
}
-static int sink_get_volume_cb(pa_sink *s) {
+static void sink_get_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err;
unsigned i;
if (!pa_cvolume_equal(&u->hardware_volume, &r)) {
- u->hardware_volume = s->volume = r;
+ s->virtual_volume = u->hardware_volume = r;
if (u->hw_dB_supported) {
pa_cvolume reset;
/* Hmm, so the hardware volume changed, let's reset our software volume */
-
pa_cvolume_reset(&reset, s->sample_spec.channels);
pa_sink_set_soft_volume(s, &reset);
}
}
- return 0;
+ return;
fail:
pa_log_error("Unable to read volume: %s", snd_strerror(err));
-
- return -1;
}
-static int sink_set_volume_cb(pa_sink *s) {
+static void sink_set_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err;
unsigned i;
long alsa_vol;
pa_volume_t vol;
- vol = s->volume.values[i];
+ vol = s->virtual_volume.values[i];
if (u->hw_dB_supported) {
if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
goto fail;
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
+#endif
+
r.values[i] = pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0);
} else {
pa_volume_t vol;
long alsa_vol;
- vol = pa_cvolume_max(&s->volume);
+ vol = pa_cvolume_max(&s->virtual_volume);
if (u->hw_dB_supported) {
alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
goto fail;
- pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
+#endif
+
+ pa_cvolume_set(&r, s->sample_spec.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
} else {
alsa_vol = to_alsa_volume(u, vol);
char t[PA_CVOLUME_SNPRINT_MAX];
/* Match exactly what the user requested by software */
+ pa_sw_cvolume_divide(&s->soft_volume, &s->virtual_volume, &r);
- pa_sw_cvolume_divide(&r, &s->volume, &r);
- pa_sink_set_soft_volume(s, &r);
-
- pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->volume));
+ pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->virtual_volume));
pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &u->hardware_volume));
pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
/* We can't match exactly what the user requested, hence let's
* at least tell the user about it */
- s->volume = r;
+ s->virtual_volume = r;
- return 0;
+ return;
fail:
pa_log_error("Unable to set volume: %s", snd_strerror(err));
-
- return -1;
}
-static int sink_get_mute_cb(pa_sink *s) {
+static void sink_get_mute_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err, sw;
if ((err = snd_mixer_selem_get_playback_switch(u->mixer_elem, 0, &sw)) < 0) {
pa_log_error("Unable to get switch: %s", snd_strerror(err));
- return -1;
+ return;
}
s->muted = !sw;
-
- return 0;
}
-static int sink_set_mute_cb(pa_sink *s) {
+static void sink_set_mute_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int err;
if ((err = snd_mixer_selem_set_playback_switch_all(u->mixer_elem, !s->muted)) < 0) {
pa_log_error("Unable to set switch: %s", snd_strerror(err));
- return -1;
+ return;
}
-
- return 0;
}
static void sink_update_requested_latency_cb(pa_sink *s) {
u->since_start = 0;
}
- if (revents && u->use_tsched)
+ if (revents && u->use_tsched && pa_log_ratelimit())
pa_log_debug("Wakeup from ALSA!%s%s", (revents & POLLIN) ? " INPUT" : "", (revents & POLLOUT) ? " OUTPUT" : "");
} else
revents = 0;
pa_log_debug("Thread shutting down");
}
-pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const pa_alsa_profile_info *profile) {
+static void set_sink_name(pa_sink_new_data *data, pa_modargs *ma, const char *device_id, const char *device_name) {
+ const char *n;
+ char *t;
+
+ pa_assert(data);
+ pa_assert(ma);
+ pa_assert(device_name);
+
+ if ((n = pa_modargs_get_value(ma, "sink_name", NULL))) {
+ pa_sink_new_data_set_name(data, n);
+ data->namereg_fail = TRUE;
+ return;
+ }
+
+ if ((n = pa_modargs_get_value(ma, "name", NULL)))
+ data->namereg_fail = TRUE;
+ else {
+ n = device_id ? device_id : device_name;
+ data->namereg_fail = FALSE;
+ }
+
+ t = pa_sprintf_malloc("alsa_output.%s", n);
+ pa_sink_new_data_set_name(data, t);
+ pa_xfree(t);
+}
+
+pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_card *card, const pa_alsa_profile_info *profile) {
struct userdata *u = NULL;
- const char *dev_id;
+ const char *dev_id = NULL;
pa_sample_spec ss;
pa_channel_map map;
uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark;
size_t frame_size;
snd_pcm_info_t *pcm_info = NULL;
int err;
- const char *name;
- char *name_buf = NULL;
- pa_bool_t namereg_fail;
pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d;
pa_usec_t usec;
pa_sink_new_data data;
snd_pcm_info_alloca(&pcm_info);
pa_assert(m);
+ pa_assert(ma);
ss = m->core->default_sample_spec;
if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) {
if (profile) {
+ if (!(dev_id = pa_modargs_get_value(ma, "device_id", NULL))) {
+ pa_log("device_id= not set");
+ goto fail;
+ }
+
if (!(u->pcm_handle = pa_alsa_open_by_device_id_profile(
dev_id,
&u->device_name,
if (snd_pcm_info(u->pcm_handle, info) >= 0) {
char *md;
- int card;
+ int card_idx;
- if ((card = snd_pcm_info_get_card(info)) >= 0) {
+ if ((card_idx = snd_pcm_info_get_card(info)) >= 0) {
- md = pa_sprintf_malloc("hw:%i", card);
+ md = pa_sprintf_malloc("hw:%i", card_idx);
if (strcmp(u->device_name, md))
if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0)
}
}
- if ((name = pa_modargs_get_value(ma, "sink_name", NULL)))
- namereg_fail = TRUE;
- else if ((name = pa_modargs_get_value(ma, "name", NULL))) {
- name = name_buf = pa_sprintf_malloc("alsa_output.%s", name);
- namereg_fail = TRUE;
- } else {
- name = name_buf = pa_sprintf_malloc("alsa_output.%s", u->device_name);
- namereg_fail = FALSE;
- }
-
pa_sink_new_data_init(&data);
- data.driver = __FILE__;
+ data.driver = driver;
data.module = m;
- pa_sink_new_data_set_name(&data, name);
- data.namereg_fail = namereg_fail;
+ data.card = card;
+ set_sink_name(&data, ma, dev_id, u->device_name);
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
- pa_alsa_init_proplist_pcm(data.proplist, pcm_info);
+ pa_alsa_init_proplist_pcm(m->core, data.proplist, pcm_info);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
pa_sink_new_data_done(&data);
- pa_xfree(name_buf);
if (!u->sink) {
pa_log("Failed to create sink object");
u->sink->flags |= PA_SINK_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SINK_DECIBEL_VOLUME : 0);
pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
+ if (!u->hw_dB_supported)
+ u->sink->n_volume_steps = u->hw_volume_max - u->hw_volume_min + 1;
} else
pa_log_info("Using software volume control.");
}