mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-31 22:25:33 -04:00
Rework ALSA mixer channel detection code. This time we actually care about the channel names the ALSA mixer exports for us
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2055 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
4c4761731d
commit
7462ab1aca
4 changed files with 192 additions and 48 deletions
|
|
@ -310,8 +310,10 @@ int pa_alsa_set_hw_params(
|
||||||
|
|
||||||
buffer_size = *periods * *period_size;
|
buffer_size = *periods * *period_size;
|
||||||
|
|
||||||
if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 ||
|
if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
|
||||||
(ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0)
|
goto finish;
|
||||||
|
|
||||||
|
if ((ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
if (_use_mmap) {
|
if (_use_mmap) {
|
||||||
|
|
@ -627,7 +629,7 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) {
|
||||||
pa_assert(dev);
|
pa_assert(dev);
|
||||||
|
|
||||||
if ((err = snd_mixer_attach(mixer, dev)) < 0) {
|
if ((err = snd_mixer_attach(mixer, dev)) < 0) {
|
||||||
pa_log_warn("Unable to attach to mixer %s: %s", dev, snd_strerror(err));
|
pa_log_info("Unable to attach to mixer %s: %s", dev, snd_strerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -641,6 +643,8 @@ int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pa_log_info("Successfully attached to mixer '%s'", dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -656,7 +660,7 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const
|
||||||
snd_mixer_selem_id_set_name(sid, name);
|
snd_mixer_selem_id_set_name(sid, name);
|
||||||
|
|
||||||
if (!(elem = snd_mixer_find_selem(mixer, sid))) {
|
if (!(elem = snd_mixer_find_selem(mixer, sid))) {
|
||||||
pa_log_warn("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid));
|
pa_log_info("Cannot find mixer control \"%s\".", snd_mixer_selem_id_get_name(sid));
|
||||||
|
|
||||||
if (fallback) {
|
if (fallback) {
|
||||||
snd_mixer_selem_id_set_name(sid, fallback);
|
snd_mixer_selem_id_set_name(sid, fallback);
|
||||||
|
|
@ -671,3 +675,123 @@ snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const
|
||||||
|
|
||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const snd_mixer_selem_channel_id_t alsa_channel_ids[PA_CHANNEL_POSITION_MAX] = {
|
||||||
|
[PA_CHANNEL_POSITION_MONO] = SND_MIXER_SCHN_MONO, /* The ALSA name is just an alias! */
|
||||||
|
|
||||||
|
[PA_CHANNEL_POSITION_FRONT_CENTER] = SND_MIXER_SCHN_FRONT_CENTER,
|
||||||
|
[PA_CHANNEL_POSITION_FRONT_LEFT] = SND_MIXER_SCHN_FRONT_LEFT,
|
||||||
|
[PA_CHANNEL_POSITION_FRONT_RIGHT] = SND_MIXER_SCHN_FRONT_RIGHT,
|
||||||
|
|
||||||
|
[PA_CHANNEL_POSITION_REAR_CENTER] = SND_MIXER_SCHN_REAR_CENTER,
|
||||||
|
[PA_CHANNEL_POSITION_REAR_LEFT] = SND_MIXER_SCHN_REAR_LEFT,
|
||||||
|
[PA_CHANNEL_POSITION_REAR_RIGHT] = SND_MIXER_SCHN_REAR_RIGHT,
|
||||||
|
|
||||||
|
[PA_CHANNEL_POSITION_LFE] = SND_MIXER_SCHN_WOOFER,
|
||||||
|
|
||||||
|
[PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
|
||||||
|
[PA_CHANNEL_POSITION_SIDE_LEFT] = SND_MIXER_SCHN_SIDE_LEFT,
|
||||||
|
[PA_CHANNEL_POSITION_SIDE_RIGHT] = SND_MIXER_SCHN_SIDE_RIGHT,
|
||||||
|
|
||||||
|
[PA_CHANNEL_POSITION_AUX0] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX1] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX2] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX3] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX4] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX5] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX6] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX7] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX8] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX9] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX10] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX11] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX12] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX13] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX14] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX15] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX16] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX17] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX18] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX19] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX20] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX21] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX22] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX23] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX24] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX25] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX26] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX27] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX28] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX29] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX30] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_AUX31] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
|
||||||
|
[PA_CHANNEL_POSITION_TOP_CENTER] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
|
||||||
|
[PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
|
||||||
|
[PA_CHANNEL_POSITION_TOP_REAR_CENTER] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_TOP_REAR_LEFT] = SND_MIXER_SCHN_UNKNOWN,
|
||||||
|
[PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = SND_MIXER_SCHN_UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel_map, snd_mixer_selem_channel_id_t mixer_map[], pa_bool_t playback) {
|
||||||
|
unsigned i;
|
||||||
|
pa_bool_t alsa_channel_used[SND_MIXER_SCHN_LAST];
|
||||||
|
pa_bool_t mono_used = FALSE;
|
||||||
|
|
||||||
|
pa_assert(elem);
|
||||||
|
pa_assert(channel_map);
|
||||||
|
pa_assert(mixer_map);
|
||||||
|
|
||||||
|
memset(&alsa_channel_used, 0, sizeof(alsa_channel_used));
|
||||||
|
|
||||||
|
if (channel_map->channels > 1 &&
|
||||||
|
((playback && snd_mixer_selem_has_playback_volume_joined(elem)) ||
|
||||||
|
(!playback && snd_mixer_selem_has_capture_volume_joined(elem)))) {
|
||||||
|
pa_log_info("ALSA device lacks independant volume controls for each channel, falling back to software volume control.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < channel_map->channels; i++) {
|
||||||
|
snd_mixer_selem_channel_id_t id;
|
||||||
|
pa_bool_t is_mono;
|
||||||
|
|
||||||
|
is_mono = channel_map->map[i] == PA_CHANNEL_POSITION_MONO;
|
||||||
|
id = alsa_channel_ids[channel_map->map[i]];
|
||||||
|
|
||||||
|
if (!is_mono && id == SND_MIXER_SCHN_UNKNOWN) {
|
||||||
|
pa_log_info("Configured channel map contains channel '%s' that is unknown to the ALSA mixer. Falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i]));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((is_mono && mono_used) || (!is_mono && alsa_channel_used[id])) {
|
||||||
|
pa_log_info("Channel map has duplicate channel '%s', failling back to software volume control.", pa_channel_position_to_string(channel_map->map[i]));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((playback && (!snd_mixer_selem_has_playback_channel(elem, id) || (is_mono && !snd_mixer_selem_is_playback_mono(elem)))) ||
|
||||||
|
(!playback && (!snd_mixer_selem_has_capture_channel(elem, id) || (is_mono && !snd_mixer_selem_is_capture_mono(elem))))) {
|
||||||
|
|
||||||
|
pa_log_info("ALSA device lacks separate volumes control for channel '%s', falling back to software volume control.", pa_channel_position_to_string(channel_map->map[i]));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_mono) {
|
||||||
|
mixer_map[i] = SND_MIXER_SCHN_MONO;
|
||||||
|
mono_used = TRUE;
|
||||||
|
} else {
|
||||||
|
mixer_map[i] = id;
|
||||||
|
alsa_channel_used[id] = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_log_info("All %u channels can be mapped to mixer channels. Using hardware volume control.", channel_map->channels);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,4 +71,6 @@ snd_pcm_t *pa_alsa_open_by_device_string(
|
||||||
snd_pcm_uframes_t *period_size,
|
snd_pcm_uframes_t *period_size,
|
||||||
pa_bool_t *use_mmap);
|
pa_bool_t *use_mmap);
|
||||||
|
|
||||||
|
int pa_alsa_calc_mixer_map(snd_mixer_elem_t *elem, const pa_channel_map *channel_map, snd_mixer_selem_channel_id_t mixer_map[], pa_bool_t playback);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ struct userdata {
|
||||||
pa_bool_t first;
|
pa_bool_t first;
|
||||||
|
|
||||||
pa_rtpoll_item *alsa_rtpoll_item;
|
pa_rtpoll_item *alsa_rtpoll_item;
|
||||||
|
|
||||||
|
snd_mixer_selem_channel_id_t mixer_map[SND_MIXER_SCHN_LAST];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* const valid_modargs[] = {
|
static const char* const valid_modargs[] = {
|
||||||
|
|
@ -505,9 +507,9 @@ static int sink_get_volume_cb(pa_sink *s) {
|
||||||
for (i = 0; i < s->sample_spec.channels; i++) {
|
for (i = 0; i < s->sample_spec.channels; i++) {
|
||||||
long set_vol, vol;
|
long set_vol, vol;
|
||||||
|
|
||||||
pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i));
|
pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, u->mixer_map[i]));
|
||||||
|
|
||||||
if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, i, &vol)) < 0)
|
if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, u->mixer_map[i], &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;
|
set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
|
||||||
|
|
@ -539,7 +541,7 @@ static int sink_set_volume_cb(pa_sink *s) {
|
||||||
long alsa_vol;
|
long alsa_vol;
|
||||||
pa_volume_t vol;
|
pa_volume_t vol;
|
||||||
|
|
||||||
pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i));
|
pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, u->mixer_map[i]));
|
||||||
|
|
||||||
vol = s->volume.values[i];
|
vol = s->volume.values[i];
|
||||||
|
|
||||||
|
|
@ -548,7 +550,7 @@ static int sink_set_volume_cb(pa_sink *s) {
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, i, alsa_vol)) < 0)
|
if ((err = snd_mixer_selem_set_playback_volume(u->mixer_elem, u->mixer_map[i], alsa_vol)) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -826,10 +828,25 @@ int pa__init(pa_module*m) {
|
||||||
if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0)
|
if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0)
|
||||||
pa_log_warn("Error opening mixer: %s", snd_strerror(err));
|
pa_log_warn("Error opening mixer: %s", snd_strerror(err));
|
||||||
else {
|
else {
|
||||||
|
pa_bool_t found = FALSE;
|
||||||
|
|
||||||
if ((pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) < 0) ||
|
if (pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) >= 0)
|
||||||
!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM"))) {
|
found = TRUE;
|
||||||
|
else {
|
||||||
|
char *md = pa_sprintf_malloc("hw:%s", dev_id);
|
||||||
|
|
||||||
|
if (strcmp(u->device_name, md))
|
||||||
|
if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0)
|
||||||
|
found = TRUE;
|
||||||
|
|
||||||
|
pa_xfree(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM")))
|
||||||
|
found = FALSE;
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
snd_mixer_close(u->mixer_handle);
|
snd_mixer_close(u->mixer_handle);
|
||||||
u->mixer_handle = NULL;
|
u->mixer_handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -863,7 +880,7 @@ int pa__init(pa_module*m) {
|
||||||
use_mmap ? " via DMA" : ""));
|
use_mmap ? " via DMA" : ""));
|
||||||
pa_xfree(t);
|
pa_xfree(t);
|
||||||
|
|
||||||
u->sink->flags = PA_SINK_HARDWARE|PA_SINK_HW_VOLUME_CTRL|PA_SINK_LATENCY;
|
u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY;
|
||||||
|
|
||||||
u->frame_size = frame_size;
|
u->frame_size = frame_size;
|
||||||
u->fragment_size = frag_size = period_size * frame_size;
|
u->fragment_size = frag_size = period_size * frame_size;
|
||||||
|
|
@ -875,35 +892,26 @@ int pa__init(pa_module*m) {
|
||||||
pa_memchunk_reset(&u->memchunk);
|
pa_memchunk_reset(&u->memchunk);
|
||||||
|
|
||||||
if (u->mixer_handle) {
|
if (u->mixer_handle) {
|
||||||
/* Initialize mixer code */
|
|
||||||
|
|
||||||
pa_assert(u->mixer_elem);
|
pa_assert(u->mixer_elem);
|
||||||
|
|
||||||
if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) {
|
if (snd_mixer_selem_has_playback_volume(u->mixer_elem))
|
||||||
int i;
|
if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, TRUE) >= 0) {
|
||||||
|
|
||||||
for (i = 0; i < ss.channels; i++)
|
|
||||||
if (!snd_mixer_selem_has_playback_channel(u->mixer_elem, i))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (i == ss.channels) {
|
|
||||||
pa_log_debug("ALSA device has separate volumes controls for all %u channels.", ss.channels);
|
|
||||||
u->sink->get_volume = sink_get_volume_cb;
|
u->sink->get_volume = sink_get_volume_cb;
|
||||||
u->sink->set_volume = sink_set_volume_cb;
|
u->sink->set_volume = sink_set_volume_cb;
|
||||||
snd_mixer_selem_get_playback_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max);
|
snd_mixer_selem_get_playback_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max);
|
||||||
} else
|
u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
|
||||||
pa_log_info("ALSA device lacks separate volumes controls for all %u channels (%u available), falling back to software volume control.", ss.channels, i+1);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (snd_mixer_selem_has_playback_switch(u->mixer_elem)) {
|
if (snd_mixer_selem_has_playback_switch(u->mixer_elem)) {
|
||||||
u->sink->get_mute = sink_get_mute_cb;
|
u->sink->get_mute = sink_get_mute_cb;
|
||||||
u->sink->set_mute = sink_set_mute_cb;
|
u->sink->set_mute = sink_set_mute_cb;
|
||||||
|
u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u->mixer_fdl = pa_alsa_fdlist_new();
|
u->mixer_fdl = pa_alsa_fdlist_new();
|
||||||
|
|
||||||
if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) {
|
if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) {
|
||||||
pa_log("failed to initialise file descriptor monitoring");
|
pa_log("Failed to initialize file descriptor monitoring");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,8 @@ struct userdata {
|
||||||
pa_bool_t use_mmap;
|
pa_bool_t use_mmap;
|
||||||
|
|
||||||
pa_rtpoll_item *alsa_rtpoll_item;
|
pa_rtpoll_item *alsa_rtpoll_item;
|
||||||
|
|
||||||
|
snd_mixer_selem_channel_id_t mixer_map[SND_MIXER_SCHN_LAST];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* const valid_modargs[] = {
|
static const char* const valid_modargs[] = {
|
||||||
|
|
@ -494,9 +496,9 @@ static int source_get_volume_cb(pa_source *s) {
|
||||||
for (i = 0; i < s->sample_spec.channels; i++) {
|
for (i = 0; i < s->sample_spec.channels; i++) {
|
||||||
long set_vol, vol;
|
long set_vol, vol;
|
||||||
|
|
||||||
pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, 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, i, &vol)) < 0)
|
if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, u->mixer_map[i], &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;
|
set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
|
||||||
|
|
@ -528,7 +530,7 @@ 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, i));
|
pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, u->mixer_map[i]));
|
||||||
|
|
||||||
vol = s->volume.values[i];
|
vol = s->volume.values[i];
|
||||||
|
|
||||||
|
|
@ -537,7 +539,7 @@ static int source_set_volume_cb(pa_source *s) {
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -753,6 +755,8 @@ int pa__init(pa_module*m) {
|
||||||
|
|
||||||
snd_config_update_free_global();
|
snd_config_update_free_global();
|
||||||
|
|
||||||
|
b = use_mmap;
|
||||||
|
|
||||||
if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) {
|
if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) {
|
||||||
|
|
||||||
if (!(u->pcm_handle = pa_alsa_open_by_device_id(
|
if (!(u->pcm_handle = pa_alsa_open_by_device_id(
|
||||||
|
|
@ -800,16 +804,28 @@ int pa__init(pa_module*m) {
|
||||||
/* 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);
|
||||||
|
|
||||||
if (ss.channels != map.channels)
|
|
||||||
/* Seems ALSA didn't like the channel number, so let's fix the channel map */
|
|
||||||
pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
|
|
||||||
|
|
||||||
if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0)
|
if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0)
|
||||||
pa_log("Error opening mixer: %s", snd_strerror(err));
|
pa_log("Error opening mixer: %s", snd_strerror(err));
|
||||||
else {
|
else {
|
||||||
|
pa_bool_t found = FALSE;
|
||||||
|
|
||||||
if ((pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) < 0) ||
|
if (pa_alsa_prepare_mixer(u->mixer_handle, u->device_name) >= 0)
|
||||||
!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", NULL))) {
|
found = TRUE;
|
||||||
|
else {
|
||||||
|
char *md = pa_sprintf_malloc("hw:%s", dev_id);
|
||||||
|
|
||||||
|
if (strcmp(u->device_name, md))
|
||||||
|
if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0)
|
||||||
|
found = TRUE;
|
||||||
|
|
||||||
|
pa_xfree(md);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
if (!(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic")))
|
||||||
|
found = FALSE;
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
snd_mixer_close(u->mixer_handle);
|
snd_mixer_close(u->mixer_handle);
|
||||||
u->mixer_handle = NULL;
|
u->mixer_handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -843,7 +859,7 @@ int pa__init(pa_module*m) {
|
||||||
use_mmap ? " via DMA" : ""));
|
use_mmap ? " via DMA" : ""));
|
||||||
pa_xfree(t);
|
pa_xfree(t);
|
||||||
|
|
||||||
u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL;
|
u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY;
|
||||||
|
|
||||||
u->frame_size = frame_size;
|
u->frame_size = frame_size;
|
||||||
u->fragment_size = frag_size = period_size * frame_size;
|
u->fragment_size = frag_size = period_size * frame_size;
|
||||||
|
|
@ -855,30 +871,24 @@ int pa__init(pa_module*m) {
|
||||||
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))
|
||||||
int i;
|
if (pa_alsa_calc_mixer_map(u->mixer_elem, &map, u->mixer_map, FALSE) >= 0) {
|
||||||
|
|
||||||
for (i = 0;i < ss.channels;i++) {
|
|
||||||
if (!snd_mixer_selem_has_capture_channel(u->mixer_elem, i))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == ss.channels) {
|
|
||||||
u->source->get_volume = source_get_volume_cb;
|
u->source->get_volume = source_get_volume_cb;
|
||||||
u->source->set_volume = source_set_volume_cb;
|
u->source->set_volume = source_set_volume_cb;
|
||||||
snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max);
|
snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max);
|
||||||
|
u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (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->mixer_fdl = pa_alsa_fdlist_new();
|
u->mixer_fdl = pa_alsa_fdlist_new();
|
||||||
|
|
||||||
if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) {
|
if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) {
|
||||||
pa_log("failed to initialise file descriptor monitoring");
|
pa_log("Failed to initialize file descriptor monitoring");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue