mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-01 22:58:47 -04:00
alsa-mixer: select nearest alsa volume step in sync-volume mode
This commit is contained in:
parent
1e7c4dd3e6
commit
4eb513cbf4
4 changed files with 76 additions and 14 deletions
|
|
@ -849,7 +849,59 @@ static long decibel_fix_get_step(pa_alsa_decibel_fix *db_fix, long *db_value, in
|
|||
return i + db_fix->min_step;
|
||||
}
|
||||
|
||||
static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v, pa_bool_t write_to_hw) {
|
||||
/* Alsa lib documentation says for snd_mixer_selem_set_playback_dB() direction argument,
|
||||
* that "-1 = accurate or first below, 0 = accurate, 1 = accurate or first above".
|
||||
* But even with accurate nearest dB volume step is not selected, so that is why we need
|
||||
* this function. Returns 0 and nearest selectable volume in *value_dB on success or
|
||||
* negative error code if fails. */
|
||||
static int element_get_nearest_alsa_dB(snd_mixer_elem_t *me, snd_mixer_selem_channel_id_t c, pa_alsa_direction_t d, long *value_dB) {
|
||||
|
||||
long alsa_val;
|
||||
long value_high;
|
||||
long value_low;
|
||||
int r = -1;
|
||||
|
||||
pa_assert(me);
|
||||
pa_assert(value_dB);
|
||||
|
||||
if (d == PA_ALSA_DIRECTION_OUTPUT) {
|
||||
if ((r = snd_mixer_selem_ask_playback_dB_vol(me, *value_dB, +1, &alsa_val)) >= 0)
|
||||
r = snd_mixer_selem_ask_playback_vol_dB(me, alsa_val, &value_high);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (value_high == *value_dB)
|
||||
return r;
|
||||
|
||||
if ((r = snd_mixer_selem_ask_playback_dB_vol(me, *value_dB, -1, &alsa_val)) >= 0)
|
||||
r = snd_mixer_selem_ask_playback_vol_dB(me, alsa_val, &value_low);
|
||||
} else {
|
||||
if ((r = snd_mixer_selem_ask_capture_dB_vol(me, *value_dB, +1, &alsa_val)) >= 0)
|
||||
r = snd_mixer_selem_ask_capture_vol_dB(me, alsa_val, &value_high);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (value_high == *value_dB)
|
||||
return r;
|
||||
|
||||
if ((r = snd_mixer_selem_ask_capture_dB_vol(me, *value_dB, -1, &alsa_val)) >= 0)
|
||||
r = snd_mixer_selem_ask_capture_vol_dB(me, alsa_val, &value_low);
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (labs(value_high - *value_dB) < labs(value_low - *value_dB))
|
||||
*value_dB = value_high;
|
||||
else
|
||||
*value_dB = value_low;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v, pa_bool_t sync_volume, pa_bool_t write_to_hw) {
|
||||
|
||||
snd_mixer_selem_id_t *sid;
|
||||
pa_cvolume rv;
|
||||
|
|
@ -914,8 +966,13 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
|
|||
|
||||
} else {
|
||||
if (write_to_hw) {
|
||||
if (sync_volume) {
|
||||
if ((r = element_get_nearest_alsa_dB(me, c, PA_ALSA_DIRECTION_OUTPUT, &value)) >= 0)
|
||||
r = snd_mixer_selem_set_playback_dB(me, c, value, 0);
|
||||
} else {
|
||||
if ((r = snd_mixer_selem_set_playback_dB(me, c, value, rounding)) >= 0)
|
||||
r = snd_mixer_selem_get_playback_dB(me, c, &value);
|
||||
}
|
||||
} else {
|
||||
long alsa_val;
|
||||
if ((r = snd_mixer_selem_ask_playback_dB_vol(me, value, rounding, &alsa_val)) >= 0)
|
||||
|
|
@ -937,8 +994,13 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
|
|||
|
||||
} else {
|
||||
if (write_to_hw) {
|
||||
if (sync_volume) {
|
||||
if ((r = element_get_nearest_alsa_dB(me, c, PA_ALSA_DIRECTION_INPUT, &value)) >= 0)
|
||||
r = snd_mixer_selem_set_capture_dB(me, c, value, 0);
|
||||
} else {
|
||||
if ((r = snd_mixer_selem_set_capture_dB(me, c, value, rounding)) >= 0)
|
||||
r = snd_mixer_selem_get_capture_dB(me, c, &value);
|
||||
}
|
||||
} else {
|
||||
long alsa_val;
|
||||
if ((r = snd_mixer_selem_ask_capture_dB_vol(me, value, rounding, &alsa_val)) >= 0)
|
||||
|
|
@ -999,7 +1061,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
|
|||
return 0;
|
||||
}
|
||||
|
||||
int pa_alsa_path_set_volume(pa_alsa_path *p, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v, pa_bool_t write_to_hw) {
|
||||
int pa_alsa_path_set_volume(pa_alsa_path *p, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v, pa_bool_t sync_volume, pa_bool_t write_to_hw) {
|
||||
|
||||
pa_alsa_element *e;
|
||||
pa_cvolume rv;
|
||||
|
|
@ -1025,7 +1087,7 @@ int pa_alsa_path_set_volume(pa_alsa_path *p, snd_mixer_t *m, const pa_channel_ma
|
|||
pa_assert(!p->has_dB || e->has_dB);
|
||||
|
||||
ev = rv;
|
||||
if (element_set_volume(e, m, cm, &ev, write_to_hw) < 0)
|
||||
if (element_set_volume(e, m, cm, &ev, sync_volume, write_to_hw) < 0)
|
||||
return -1;
|
||||
|
||||
if (!p->has_dB) {
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB);
|
|||
void pa_alsa_path_dump(pa_alsa_path *p);
|
||||
int pa_alsa_path_get_volume(pa_alsa_path *p, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v);
|
||||
int pa_alsa_path_get_mute(pa_alsa_path *path, snd_mixer_t *m, pa_bool_t *muted);
|
||||
int pa_alsa_path_set_volume(pa_alsa_path *path, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v, pa_bool_t write_to_hw);
|
||||
int pa_alsa_path_set_volume(pa_alsa_path *path, snd_mixer_t *m, const pa_channel_map *cm, pa_cvolume *v, pa_bool_t sync_volume, pa_bool_t write_to_hw);
|
||||
int pa_alsa_path_set_mute(pa_alsa_path *path, snd_mixer_t *m, pa_bool_t muted);
|
||||
int pa_alsa_path_select(pa_alsa_path *p, snd_mixer_t *m);
|
||||
void pa_alsa_path_set_callback(pa_alsa_path *p, snd_mixer_t *m, snd_mixer_elem_callback_t cb, void *userdata);
|
||||
|
|
|
|||
|
|
@ -1253,7 +1253,7 @@ static void sink_set_volume_cb(pa_sink *s) {
|
|||
struct userdata *u = s->userdata;
|
||||
pa_cvolume r;
|
||||
char vol_str_pcnt[PA_CVOLUME_SNPRINT_MAX];
|
||||
pa_bool_t write_to_hw = (s->flags & PA_SINK_SYNC_VOLUME) ? FALSE : TRUE;
|
||||
pa_bool_t sync_volume = !!(s->flags & PA_SINK_SYNC_VOLUME);
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->mixer_path);
|
||||
|
|
@ -1262,7 +1262,7 @@ static void sink_set_volume_cb(pa_sink *s) {
|
|||
/* Shift up by the base volume */
|
||||
pa_sw_cvolume_divide_scalar(&r, &s->real_volume, s->base_volume);
|
||||
|
||||
if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &r, write_to_hw) < 0)
|
||||
if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &r, sync_volume, !sync_volume) < 0)
|
||||
return;
|
||||
|
||||
/* Shift down by the base volume, so that 0dB becomes maximum volume */
|
||||
|
|
@ -1319,7 +1319,7 @@ static void sink_write_volume_cb(pa_sink *s) {
|
|||
/* Shift up by the base volume */
|
||||
pa_sw_cvolume_divide_scalar(&hw_vol, &hw_vol, s->base_volume);
|
||||
|
||||
if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &hw_vol, TRUE) < 0)
|
||||
if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &hw_vol, TRUE, TRUE) < 0)
|
||||
pa_log_error("Writing HW volume failed");
|
||||
else {
|
||||
pa_cvolume tmp_vol;
|
||||
|
|
|
|||
|
|
@ -1129,7 +1129,7 @@ static void source_set_volume_cb(pa_source *s) {
|
|||
struct userdata *u = s->userdata;
|
||||
pa_cvolume r;
|
||||
char vol_str_pcnt[PA_CVOLUME_SNPRINT_MAX];
|
||||
pa_bool_t write_to_hw = (s->flags & PA_SOURCE_SYNC_VOLUME) ? FALSE : TRUE;
|
||||
pa_bool_t sync_volume = !!(s->flags & PA_SOURCE_SYNC_VOLUME);
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->mixer_path);
|
||||
|
|
@ -1138,7 +1138,7 @@ static void source_set_volume_cb(pa_source *s) {
|
|||
/* Shift up by the base volume */
|
||||
pa_sw_cvolume_divide_scalar(&r, &s->real_volume, s->base_volume);
|
||||
|
||||
if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &r, write_to_hw) < 0)
|
||||
if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &r, sync_volume, !sync_volume) < 0)
|
||||
return;
|
||||
|
||||
/* Shift down by the base volume, so that 0dB becomes maximum volume */
|
||||
|
|
@ -1195,7 +1195,7 @@ static void source_write_volume_cb(pa_source *s) {
|
|||
/* Shift up by the base volume */
|
||||
pa_sw_cvolume_divide_scalar(&hw_vol, &hw_vol, s->base_volume);
|
||||
|
||||
if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &hw_vol, TRUE) < 0)
|
||||
if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle, &s->channel_map, &hw_vol, TRUE, TRUE) < 0)
|
||||
pa_log_error("Writing HW volume failed");
|
||||
else {
|
||||
pa_cvolume tmp_vol;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue