move flat volume logic into the core. while doing so add n_volume_steps field to sinks/sources

This commit is contained in:
Lennart Poettering 2009-01-27 04:39:07 +01:00
parent 4bfa5d7d13
commit d5f46e824e
32 changed files with 562 additions and 361 deletions

View file

@ -757,7 +757,7 @@ static long to_alsa_volume(struct userdata *u, pa_volume_t vol) {
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;
@ -820,27 +820,24 @@ static int sink_get_volume_cb(pa_sink *s) {
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;
@ -857,7 +854,7 @@ static int sink_set_volume_cb(pa_sink *s) {
long alsa_vol;
pa_volume_t vol;
vol = s->volume.values[i];
vol = s->virtual_volume.values[i];
if (u->hw_dB_supported) {
@ -894,7 +891,7 @@ static int sink_set_volume_cb(pa_sink *s) {
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);
@ -911,7 +908,7 @@ static int sink_set_volume_cb(pa_sink *s) {
VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
#endif
pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
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);
@ -932,11 +929,9 @@ static int sink_set_volume_cb(pa_sink *s) {
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));
@ -945,17 +940,15 @@ static int sink_set_volume_cb(pa_sink *s) {
/* 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;
@ -964,15 +957,13 @@ static int sink_get_mute_cb(pa_sink *s) {
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;
@ -981,10 +972,8 @@ static int sink_set_mute_cb(pa_sink *s) {
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) {
@ -1552,6 +1541,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
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.");
}

View file

@ -703,7 +703,7 @@ static long to_alsa_volume(struct userdata *u, pa_volume_t vol) {
return PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
}
static int source_get_volume_cb(pa_source *s) {
static void source_get_volume_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err;
unsigned i;
@ -766,27 +766,24 @@ static int source_get_volume_cb(pa_source *s) {
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_source_set_soft_volume(s, &reset);
}
}
return 0;
return;
fail:
pa_log_error("Unable to read volume: %s", snd_strerror(err));
return -1;
}
static int source_set_volume_cb(pa_source *s) {
static void source_set_volume_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err;
unsigned i;
@ -803,7 +800,7 @@ static int source_set_volume_cb(pa_source *s) {
long alsa_vol;
pa_volume_t vol;
vol = s->volume.values[i];
vol = s->virtual_volume.values[i];
if (u->hw_dB_supported) {
@ -840,7 +837,7 @@ static int source_set_volume_cb(pa_source *s) {
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);
@ -857,7 +854,7 @@ static int source_set_volume_cb(pa_source *s) {
VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
#endif
pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
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);
@ -879,10 +876,9 @@ static int source_set_volume_cb(pa_source *s) {
/* Match exactly what the user requested by software */
pa_sw_cvolume_divide(&r, &s->volume, &r);
pa_source_set_soft_volume(s, &r);
pa_sw_cvolume_divide(&s->soft_volume, &s->virtual_volume, &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));
@ -891,17 +887,15 @@ static int source_set_volume_cb(pa_source *s) {
/* 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 source_get_mute_cb(pa_source *s) {
static void source_get_mute_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err, sw;
@ -910,15 +904,13 @@ static int source_get_mute_cb(pa_source *s) {
if ((err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw)) < 0) {
pa_log_error("Unable to get switch: %s", snd_strerror(err));
return -1;
return;
}
s->muted = !sw;
return 0;
}
static int source_set_mute_cb(pa_source *s) {
static void source_set_mute_cb(pa_source *s) {
struct userdata *u = s->userdata;
int err;
@ -927,10 +919,8 @@ static int source_set_mute_cb(pa_source *s) {
if ((err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->muted)) < 0) {
pa_log_error("Unable to set switch: %s", snd_strerror(err));
return -1;
return;
}
return 0;
}
static void source_update_requested_latency_cb(pa_source *s) {
@ -1372,6 +1362,9 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
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. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
if (!u->hw_dB_supported)
u->source->n_volume_steps = u->hw_volume_max - u->hw_volume_min + 1;
} else
pa_log_info("Using software volume control.");
}

View file

@ -135,7 +135,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_NORM;
}
pa_sink_set_volume(s, &cv);
pa_sink_set_volume(s, &cv, TRUE, TRUE);
break;
case DOWN:
@ -146,7 +146,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_MUTED;
}
pa_sink_set_volume(s, &cv);
pa_sink_set_volume(s, &cv, TRUE, TRUE);
break;
case MUTE:

View file

@ -126,7 +126,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_NORM;
}
pa_sink_set_volume(s, &cv);
pa_sink_set_volume(s, &cv, TRUE, TRUE);
break;
case DOWN:
@ -137,7 +137,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
cv.values[i] = PA_VOLUME_MUTED;
}
pa_sink_set_volume(s, &cv);
pa_sink_set_volume(s, &cv, TRUE, TRUE);
break;
case MUTE_TOGGLE:

View file

@ -101,23 +101,23 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_i
pa_log_debug("Positioning event sound '%s' at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f);
if (!data->volume_is_set) {
pa_cvolume_reset(&data->volume, data->sample_spec.channels);
data->volume_is_set = TRUE;
if (!data->virtual_volume_is_set) {
pa_cvolume_reset(&data->virtual_volume, data->sample_spec.channels);
data->virtual_volume_is_set = TRUE;
}
for (c = 0; c < data->sample_spec.channels; c++) {
if (is_left(data->channel_map.map[c]))
data->volume.values[c] =
pa_sw_volume_multiply(data->volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * (1.0 - f)));
data->virtual_volume.values[c] =
pa_sw_volume_multiply(data->virtual_volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * (1.0 - f)));
if (is_right(data->channel_map.map[c]))
data->volume.values[c] =
pa_sw_volume_multiply(data->volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * f));
data->virtual_volume.values[c] =
pa_sw_volume_multiply(data->virtual_volume.values[c], (pa_volume_t) (PA_VOLUME_NORM * f));
}
pa_log_debug("Final volume %s.", pa_cvolume_snprint(t, sizeof(t), &data->volume));
pa_log_debug("Final volume %s.", pa_cvolume_snprint(t, sizeof(t), &data->virtual_volume));
return PA_HOOK_OK;
}

View file

@ -255,20 +255,17 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
return pa_sink_process_msg(o, code, data, offset, chunk);
}
static int sink_get_volume_cb(pa_sink *s) {
static void sink_get_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int i;
pa_assert(u);
for (i = 0; i < s->sample_spec.channels; i++) {
s->volume.values[i] = u->volume;
}
return 0;
for (i = 0; i < s->sample_spec.channels; i++)
s->virtual_volume.values[i] = u->volume;
}
static int sink_set_volume_cb(pa_sink *s) {
static void sink_set_volume_cb(pa_sink *s) {
struct userdata *u = s->userdata;
int rv;
@ -276,39 +273,34 @@ static int sink_set_volume_cb(pa_sink *s) {
/* If we're muted, we fake it */
if (u->muted)
return 0;
return;
pa_assert(s->sample_spec.channels > 0);
/* Avoid pointless volume sets */
if (u->volume == s->volume.values[0])
return 0;
if (u->volume == s->virtual_volume.values[0])
return;
rv = pa_raop_client_set_volume(u->raop, s->volume.values[0]);
rv = pa_raop_client_set_volume(u->raop, s->virtual_volume.values[0]);
if (0 == rv)
u->volume = s->volume.values[0];
return rv;
u->volume = s->virtual_volume.values[0];
}
static int sink_get_mute_cb(pa_sink *s) {
static void sink_get_mute_cb(pa_sink *s) {
struct userdata *u = s->userdata;
pa_assert(u);
s->muted = u->muted;
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 rv;
pa_assert(u);
rv = pa_raop_client_set_volume(u->raop, (s->muted ? PA_VOLUME_MUTED : u->volume));
pa_raop_client_set_volume(u->raop, (s->muted ? PA_VOLUME_MUTED : u->volume));
u->muted = s->muted;
return rv;
}
static void thread_func(void *userdata) {

View file

@ -334,9 +334,9 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
if (u->restore_volume) {
if (!new_data->volume_is_set) {
if (!new_data->virtual_volume_is_set) {
pa_log_info("Restoring volume for sink input %s.", name);
pa_sink_input_new_data_set_volume(new_data, pa_cvolume_remap(&e->volume, &e->channel_map, &new_data->channel_map));
pa_sink_input_new_data_set_virtual_volume(new_data, pa_cvolume_remap(&e->volume, &e->channel_map, &new_data->channel_map));
} else
pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
}

View file

@ -1056,10 +1056,10 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag
pa_assert(u->sink);
if ((u->version < 11 || !!mute == !!u->sink->muted) &&
pa_cvolume_equal(&volume, &u->sink->volume))
pa_cvolume_equal(&volume, &u->sink->virtual_volume))
return;
memcpy(&u->sink->volume, &volume, sizeof(pa_cvolume));
memcpy(&u->sink->virtual_volume, &volume, sizeof(pa_cvolume));
if (u->version >= 11)
u->sink->muted = !!mute;
@ -1621,7 +1621,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata
#ifdef TUNNEL_SINK
/* Called from main context */
static int sink_set_volume(pa_sink *sink) {
static void sink_set_volume(pa_sink *sink) {
struct userdata *u;
pa_tagstruct *t;
uint32_t tag;
@ -1634,14 +1634,12 @@ static int sink_set_volume(pa_sink *sink) {
pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME);
pa_tagstruct_putu32(t, tag = u->ctag++);
pa_tagstruct_putu32(t, u->device_index);
pa_tagstruct_put_cvolume(t, &sink->volume);
pa_tagstruct_put_cvolume(t, &sink->virtual_volume);
pa_pstream_send_tagstruct(u->pstream, t);
return 0;
}
/* Called from main context */
static int sink_set_mute(pa_sink *sink) {
static void sink_set_mute(pa_sink *sink) {
struct userdata *u;
pa_tagstruct *t;
uint32_t tag;
@ -1651,7 +1649,7 @@ static int sink_set_mute(pa_sink *sink) {
pa_assert(u);
if (u->version < 11)
return -1;
return;
t = pa_tagstruct_new(NULL, 0);
pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_MUTE);
@ -1659,8 +1657,6 @@ static int sink_set_mute(pa_sink *sink) {
pa_tagstruct_putu32(t, u->device_index);
pa_tagstruct_put_boolean(t, !!sink->muted);
pa_pstream_send_tagstruct(u->pstream, t);
return 0;
}
#endif

View file

@ -443,7 +443,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
if (r->volume_is_set && data->sample_spec.channels == r->volume.channels) {
pa_log_info("Restoring volume for <%s>", r->name);
pa_sink_input_new_data_set_volume(data, &r->volume);
pa_sink_input_new_data_set_virtual_volume(data, &r->volume);
}
}

View file

@ -443,7 +443,6 @@ static pa_usec_t io_sink_get_latency(struct userdata *u) {
return r;
}
static pa_usec_t io_source_get_latency(struct userdata *u) {
pa_usec_t r = 0;
@ -527,9 +526,6 @@ static int suspend(struct userdata *u) {
return 0;
}
static int sink_get_volume(pa_sink *s);
static int source_get_volume(pa_source *s);
static int unsuspend(struct userdata *u) {
int m;
pa_sample_spec ss, *ss_original;
@ -620,10 +616,10 @@ static int unsuspend(struct userdata *u) {
build_pollfd(u);
if (u->sink && u->sink->get_volume)
u->sink->get_volume(u->sink);
if (u->source && u->source->get_volume)
u->source->get_volume(u->source);
if (u->sink)
pa_sink_get_volume(u->sink, TRUE);
if (u->source)
pa_source_get_volume(u->source, TRUE);
pa_log_info("Resumed successfully...");
@ -798,84 +794,76 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
return ret;
}
static int sink_get_volume(pa_sink *s) {
static void sink_get_volume(pa_sink *s) {
struct userdata *u;
int r;
pa_assert_se(u = s->userdata);
pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
if (u->mixer_devmask & SOUND_MASK_VOLUME)
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->volume)) >= 0)
return r;
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0)
return;
if (u->mixer_devmask & SOUND_MASK_PCM)
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->volume)) >= 0)
return r;
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->virtual_volume) >= 0)
return;
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
return -1;
}
static int sink_set_volume(pa_sink *s) {
static void sink_set_volume(pa_sink *s) {
struct userdata *u;
int r;
pa_assert_se(u = s->userdata);
pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
if (u->mixer_devmask & SOUND_MASK_VOLUME)
if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->volume)) >= 0)
return r;
if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->virtual_volume) >= 0)
return;
if (u->mixer_devmask & SOUND_MASK_PCM)
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->volume)) >= 0)
return r;
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->virtual_volume) >= 0)
return;
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
return -1;
}
static int source_get_volume(pa_source *s) {
static void source_get_volume(pa_source *s) {
struct userdata *u;
int r;
pa_assert_se(u = s->userdata);
pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
if (u->mixer_devmask & SOUND_MASK_IGAIN)
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume)) >= 0)
return r;
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->virtual_volume) >= 0)
return;
if (u->mixer_devmask & SOUND_MASK_RECLEV)
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume)) >= 0)
return r;
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->virtual_volume) >= 0)
return;
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
return -1;
}
static int source_set_volume(pa_source *s) {
static void source_set_volume(pa_source *s) {
struct userdata *u;
int r;
pa_assert_se(u = s->userdata);
pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
if (u->mixer_devmask & SOUND_MASK_IGAIN)
if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume)) >= 0)
return r;
if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->virtual_volume) >= 0)
return;
if (u->mixer_devmask & SOUND_MASK_RECLEV)
if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume)) >= 0)
return r;
if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->virtual_volume) >= 0)
return;
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
return -1;
}
static void thread_func(void *userdata) {
@ -1417,6 +1405,7 @@ int pa__init(pa_module*m) {
u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
u->sink->get_volume = sink_get_volume;
u->sink->set_volume = sink_set_volume;
u->sink->n_volume_steps = 101;
do_close = FALSE;
}
@ -1425,6 +1414,7 @@ int pa__init(pa_module*m) {
u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
u->source->get_volume = source_get_volume;
u->source->set_volume = source_set_volume;
u->source->n_volume_steps = 101;
do_close = FALSE;
}
}