mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 19:20:35 +00:00
ext/alsa/: Improve and fix mixer track handling, in particular better handling of alsa's pvolume/pswitch/cvolume/cswi...
Original commit message from CVS: Patch by: Viktor Peters <viktor dot peters at gmail dot com> * ext/alsa/gstalsamixer.c: (gst_alsa_mixer_ensure_track_list), (gst_alsa_mixer_update), (gst_alsa_mixer_get_volume), (gst_alsa_mixer_set_volume), (gst_alsa_mixer_set_mute), (gst_alsa_mixer_set_record): * ext/alsa/gstalsamixertrack.c: (gst_alsa_mixer_track_update_alsa_capabilities), (alsa_track_has_cap), (gst_alsa_mixer_track_new), (gst_alsa_mixer_track_update): * ext/alsa/gstalsamixertrack.h: Improve and fix mixer track handling, in particular better handling of alsa's pvolume/pswitch/cvolume/cswitch capabilities; create separate track objects for tracks that have both capture and playback volume (and label them differently as well so they're not mistakenly assumed to be duplicates); classify mixer tracks that only affect the audible volume of something (rather than the capture volume) as playback tracks. Redefine/fix meaning of RECORD and MUTE flags for capture tracks to correspond to alsa-pswitch alsa-cswitch (following the meaning documented in the mixer interface header file); add support for alsa's exclusive cswitch groups; update/sync state/flags better if mixer settings are changed by another application. Fixes #336075.
This commit is contained in:
parent
8332201367
commit
6fdb8262a7
4 changed files with 431 additions and 157 deletions
26
ChangeLog
26
ChangeLog
|
@ -1,3 +1,29 @@
|
|||
2006-08-29 Tim-Philipp Müller <tim at centricular dot net>
|
||||
|
||||
Patch by: Viktor Peters <viktor dot peters at gmail dot com>
|
||||
|
||||
* ext/alsa/gstalsamixer.c: (gst_alsa_mixer_ensure_track_list),
|
||||
(gst_alsa_mixer_update), (gst_alsa_mixer_get_volume),
|
||||
(gst_alsa_mixer_set_volume), (gst_alsa_mixer_set_mute),
|
||||
(gst_alsa_mixer_set_record):
|
||||
* ext/alsa/gstalsamixertrack.c:
|
||||
(gst_alsa_mixer_track_update_alsa_capabilities),
|
||||
(alsa_track_has_cap), (gst_alsa_mixer_track_new),
|
||||
(gst_alsa_mixer_track_update):
|
||||
* ext/alsa/gstalsamixertrack.h:
|
||||
Improve and fix mixer track handling, in particular better handling
|
||||
of alsa's pvolume/pswitch/cvolume/cswitch capabilities; create separate
|
||||
track objects for tracks that have both capture and playback volume
|
||||
(and label them differently as well so they're not mistakenly
|
||||
assumed to be duplicates); classify mixer tracks that only affect
|
||||
the audible volume of something (rather than the capture volume)
|
||||
as playback tracks. Redefine/fix meaning of RECORD and MUTE flags
|
||||
for capture tracks to correspond to alsa-pswitch alsa-cswitch
|
||||
(following the meaning documented in the mixer interface header
|
||||
file); add support for alsa's exclusive cswitch groups; update/sync
|
||||
state/flags better if mixer settings are changed by another
|
||||
application. Fixes #336075.
|
||||
|
||||
2006-08-29 Tim-Philipp Müller <tim at centricular dot net>
|
||||
|
||||
* gst/playback/gstplaybin.c:
|
||||
|
|
|
@ -123,8 +123,6 @@ gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer)
|
|||
{
|
||||
gint i, count;
|
||||
snd_mixer_elem_t *element;
|
||||
GstMixerTrack *track;
|
||||
GstMixerOptions *opts;
|
||||
gboolean first = TRUE;
|
||||
|
||||
g_return_if_fail (mixer->handle != NULL);
|
||||
|
@ -135,21 +133,20 @@ gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer)
|
|||
count = snd_mixer_get_count (mixer->handle);
|
||||
element = snd_mixer_first_elem (mixer->handle);
|
||||
|
||||
/* build track list */
|
||||
for (i = 0; i < count; i++) {
|
||||
GList *item;
|
||||
gint channels = 0, samename = 0;
|
||||
gint flags = GST_MIXER_TRACK_OUTPUT;
|
||||
gboolean got_it = FALSE;
|
||||
/* build track list
|
||||
*
|
||||
* Some ALSA tracks may have playback and capture capabilities.
|
||||
* Here we model them as two separate GStreamer tracks.
|
||||
*/
|
||||
|
||||
if (snd_mixer_selem_has_capture_switch (element)) {
|
||||
if (!(mixer->dir & GST_ALSA_MIXER_CAPTURE))
|
||||
goto next;
|
||||
flags = GST_MIXER_TRACK_INPUT;
|
||||
} else {
|
||||
if (!(mixer->dir & GST_ALSA_MIXER_PLAYBACK))
|
||||
goto next;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
GstMixerTrack *play_track = NULL;
|
||||
GstMixerTrack *cap_track = NULL;
|
||||
const gchar *name;
|
||||
GList *item;
|
||||
gint samename = 0;
|
||||
|
||||
name = snd_mixer_selem_get_name (element);
|
||||
|
||||
/* prevent dup names */
|
||||
for (item = mixer->tracklist; item != NULL; item = item->next) {
|
||||
|
@ -160,54 +157,82 @@ gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer)
|
|||
else
|
||||
temp = GST_ALSA_MIXER_TRACK (item->data)->element;
|
||||
|
||||
if (!strcmp (snd_mixer_selem_get_name (element),
|
||||
snd_mixer_selem_get_name (temp)))
|
||||
if (strcmp (name, snd_mixer_selem_get_name (temp)) == 0)
|
||||
samename++;
|
||||
}
|
||||
|
||||
if (snd_mixer_selem_has_capture_volume (element)) {
|
||||
while (snd_mixer_selem_has_capture_channel (element, channels))
|
||||
channels++;
|
||||
track = gst_alsa_mixer_track_new (element, samename,
|
||||
i, channels, flags, GST_ALSA_MIXER_TRACK_CAPTURE);
|
||||
mixer->tracklist = g_list_append (mixer->tracklist, track);
|
||||
got_it = TRUE;
|
||||
GST_LOG ("[%s] probing element #%u, mixer->dir=%u", name, i, mixer->dir);
|
||||
|
||||
/* there might be another volume slider; make that playback */
|
||||
flags &= ~GST_MIXER_TRACK_INPUT;
|
||||
flags |= GST_MIXER_TRACK_OUTPUT;
|
||||
}
|
||||
if (mixer->dir & GST_ALSA_MIXER_PLAYBACK) {
|
||||
gboolean has_playback_switch, has_playback_volume;
|
||||
|
||||
if (snd_mixer_selem_has_playback_volume (element)) {
|
||||
while (snd_mixer_selem_has_playback_channel (element, channels))
|
||||
channels++;
|
||||
if (first) {
|
||||
first = FALSE;
|
||||
flags |= GST_MIXER_TRACK_MASTER;
|
||||
}
|
||||
track = gst_alsa_mixer_track_new (element, samename,
|
||||
i, channels, flags, GST_ALSA_MIXER_TRACK_PLAYBACK);
|
||||
mixer->tracklist = g_list_append (mixer->tracklist, track);
|
||||
got_it = TRUE;
|
||||
}
|
||||
has_playback_switch = snd_mixer_selem_has_playback_switch (element);
|
||||
has_playback_volume = snd_mixer_selem_has_playback_volume (element);
|
||||
|
||||
if (snd_mixer_selem_is_enumerated (element)) {
|
||||
opts = gst_alsa_mixer_options_new (element, i);
|
||||
mixer->tracklist = g_list_append (mixer->tracklist, opts);
|
||||
got_it = TRUE;
|
||||
}
|
||||
GST_LOG ("[%s] PLAYBACK: has_playback_volume=%d, has_playback_switch=%d",
|
||||
name, has_playback_volume, has_playback_switch);
|
||||
|
||||
if (!got_it) {
|
||||
if (flags == GST_MIXER_TRACK_OUTPUT &&
|
||||
snd_mixer_selem_has_playback_switch (element)) {
|
||||
if (has_playback_volume) {
|
||||
gint flags = GST_MIXER_TRACK_OUTPUT;
|
||||
|
||||
if (first) {
|
||||
first = FALSE;
|
||||
flags |= GST_MIXER_TRACK_MASTER;
|
||||
}
|
||||
play_track = gst_alsa_mixer_track_new (element, samename, i,
|
||||
flags, FALSE, NULL, FALSE);
|
||||
|
||||
} else if (has_playback_switch) {
|
||||
/* simple mute switch */
|
||||
track = gst_alsa_mixer_track_new (element, samename,
|
||||
i, 0, flags, GST_ALSA_MIXER_TRACK_PLAYBACK);
|
||||
mixer->tracklist = g_list_append (mixer->tracklist, track);
|
||||
play_track = gst_alsa_mixer_track_new (element, samename, i,
|
||||
GST_MIXER_TRACK_OUTPUT, TRUE, NULL, FALSE);
|
||||
}
|
||||
|
||||
if (snd_mixer_selem_is_enumerated (element)) {
|
||||
GstMixerOptions *opts = gst_alsa_mixer_options_new (element, i);
|
||||
|
||||
GST_LOG ("[%s] is enumerated (%d)", name, i);
|
||||
mixer->tracklist = g_list_append (mixer->tracklist, opts);
|
||||
}
|
||||
}
|
||||
|
||||
next:
|
||||
if (mixer->dir & GST_ALSA_MIXER_CAPTURE) {
|
||||
gboolean has_capture_switch, has_common_switch;
|
||||
gboolean has_capture_volume, has_common_volume;
|
||||
|
||||
has_capture_switch = snd_mixer_selem_has_capture_switch (element);
|
||||
has_common_switch = snd_mixer_selem_has_common_switch (element);
|
||||
has_capture_volume = snd_mixer_selem_has_capture_volume (element);
|
||||
has_common_volume = snd_mixer_selem_has_common_volume (element);
|
||||
|
||||
GST_LOG ("[%s] CAPTURE: has_capture_volume=%d, has_common_volume=%d, "
|
||||
"has_capture_switch=%d, has_common_switch=%d, play_track=%p", name,
|
||||
has_capture_volume, has_common_volume, has_capture_switch,
|
||||
has_common_switch, play_track);
|
||||
|
||||
if (has_capture_volume && !(play_track && has_common_volume)) {
|
||||
cap_track = gst_alsa_mixer_track_new (element, samename, i,
|
||||
GST_MIXER_TRACK_INPUT, FALSE, NULL, play_track != NULL);
|
||||
} else if (has_capture_switch && !(play_track && has_common_switch)) {
|
||||
cap_track = gst_alsa_mixer_track_new (element, samename, i,
|
||||
GST_MIXER_TRACK_INPUT, TRUE, NULL, play_track != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (play_track && cap_track) {
|
||||
GST_ALSA_MIXER_TRACK (play_track)->shared_mute =
|
||||
GST_ALSA_MIXER_TRACK (cap_track);
|
||||
GST_ALSA_MIXER_TRACK (cap_track)->shared_mute =
|
||||
GST_ALSA_MIXER_TRACK (play_track);
|
||||
}
|
||||
|
||||
if (play_track)
|
||||
mixer->tracklist = g_list_append (mixer->tracklist, play_track);
|
||||
|
||||
if (cap_track)
|
||||
mixer->tracklist = g_list_append (mixer->tracklist, cap_track);
|
||||
|
||||
element = snd_mixer_elem_next (element);
|
||||
}
|
||||
}
|
||||
|
@ -282,30 +307,13 @@ gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer)
|
|||
static void
|
||||
gst_alsa_mixer_update (GstAlsaMixer * mixer, GstAlsaMixerTrack * alsa_track)
|
||||
{
|
||||
GstMixerTrack *track = (GstMixerTrack *) alsa_track;
|
||||
int v = 0;
|
||||
|
||||
snd_mixer_handle_events (mixer->handle);
|
||||
if (!alsa_track)
|
||||
return;
|
||||
|
||||
/* Any updates in flags? */
|
||||
if (snd_mixer_selem_has_playback_switch (alsa_track->element)) {
|
||||
snd_mixer_selem_get_playback_switch (alsa_track->element, 0, &v);
|
||||
if (v)
|
||||
track->flags &= ~GST_MIXER_TRACK_MUTE;
|
||||
else
|
||||
track->flags |= GST_MIXER_TRACK_MUTE;
|
||||
}
|
||||
if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CAPTURE) {
|
||||
snd_mixer_selem_get_capture_switch (alsa_track->element, 0, &v);
|
||||
if (!v)
|
||||
track->flags &= ~GST_MIXER_TRACK_RECORD;
|
||||
else
|
||||
track->flags |= GST_MIXER_TRACK_RECORD;
|
||||
}
|
||||
if (alsa_track)
|
||||
gst_alsa_mixer_track_update (alsa_track);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gst_alsa_mixer_get_volume (GstAlsaMixer * mixer, GstMixerTrack * track,
|
||||
gint * volumes)
|
||||
|
@ -317,21 +325,36 @@ gst_alsa_mixer_get_volume (GstAlsaMixer * mixer, GstMixerTrack * track,
|
|||
|
||||
gst_alsa_mixer_update (mixer, alsa_track);
|
||||
|
||||
if (track->flags & GST_MIXER_TRACK_MUTE &&
|
||||
!snd_mixer_selem_has_playback_switch (alsa_track->element)) {
|
||||
for (i = 0; i < track->num_channels; i++)
|
||||
volumes[i] = alsa_track->volumes[i];
|
||||
} else {
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
long tmp = 0;
|
||||
if (track->flags & GST_MIXER_TRACK_OUTPUT) { /* return playback volume */
|
||||
|
||||
/* Is emulated mute flag activated? */
|
||||
if (track->flags & GST_MIXER_TRACK_MUTE &&
|
||||
!(alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PSWITCH)) {
|
||||
for (i = 0; i < track->num_channels; i++)
|
||||
volumes[i] = alsa_track->volumes[i];
|
||||
} else {
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
long tmp = 0;
|
||||
|
||||
if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PLAYBACK) {
|
||||
snd_mixer_selem_get_playback_volume (alsa_track->element, i, &tmp);
|
||||
} else if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CAPTURE) {
|
||||
snd_mixer_selem_get_capture_volume (alsa_track->element, i, &tmp);
|
||||
alsa_track->volumes[i] = volumes[i] = (gint) tmp;
|
||||
}
|
||||
}
|
||||
|
||||
alsa_track->volumes[i] = volumes[i] = (gint) tmp;
|
||||
} else if (track->flags & GST_MIXER_TRACK_INPUT) { /* return capture volume */
|
||||
|
||||
/* Is emulated record flag activated? */
|
||||
if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH ||
|
||||
track->flags & GST_MIXER_TRACK_RECORD) {
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
long tmp = 0;
|
||||
|
||||
snd_mixer_selem_get_capture_volume (alsa_track->element, i, &tmp);
|
||||
alsa_track->volumes[i] = volumes[i] = (gint) tmp;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < track->num_channels; i++)
|
||||
volumes[i] = alsa_track->volumes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,27 +363,41 @@ void
|
|||
gst_alsa_mixer_set_volume (GstAlsaMixer * mixer, GstMixerTrack * track,
|
||||
gint * volumes)
|
||||
{
|
||||
gint i;
|
||||
GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track);
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (mixer->handle != NULL);
|
||||
|
||||
gst_alsa_mixer_update (mixer, alsa_track);
|
||||
|
||||
/* only set the volume with ALSA lib if the track isn't muted. */
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
alsa_track->volumes[i] = volumes[i];
|
||||
if (track->flags & GST_MIXER_TRACK_OUTPUT) {
|
||||
|
||||
if (!(track->flags & GST_MIXER_TRACK_MUTE) ||
|
||||
snd_mixer_selem_has_playback_switch (alsa_track->element)) {
|
||||
if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PLAYBACK) {
|
||||
/* Is emulated mute flag activated? */
|
||||
if (track->flags & GST_MIXER_TRACK_MUTE &&
|
||||
!(alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PSWITCH)) {
|
||||
for (i = 0; i < track->num_channels; i++)
|
||||
alsa_track->volumes[i] = volumes[i];
|
||||
} else {
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
alsa_track->volumes[i] = volumes[i];
|
||||
snd_mixer_selem_set_playback_volume (alsa_track->element, i,
|
||||
(long) volumes[i]);
|
||||
} else if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CAPTURE) {
|
||||
snd_mixer_selem_set_capture_volume (alsa_track->element, i,
|
||||
(long) volumes[i]);
|
||||
volumes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (track->flags & GST_MIXER_TRACK_INPUT) {
|
||||
|
||||
/* Is emulated record flag activated? */
|
||||
if (track->flags & GST_MIXER_TRACK_RECORD ||
|
||||
alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH) {
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
alsa_track->volumes[i] = volumes[i];
|
||||
snd_mixer_selem_set_capture_volume (alsa_track->element, i, volumes[i]);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < track->num_channels; i++)
|
||||
alsa_track->volumes[i] = volumes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,30 +405,46 @@ void
|
|||
gst_alsa_mixer_set_mute (GstAlsaMixer * mixer, GstMixerTrack * track,
|
||||
gboolean mute)
|
||||
{
|
||||
gint i;
|
||||
GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track);
|
||||
|
||||
g_return_if_fail (mixer->handle != NULL);
|
||||
|
||||
gst_alsa_mixer_update (mixer, alsa_track);
|
||||
|
||||
if (!!(mute) == !!(track->flags & GST_MIXER_TRACK_MUTE))
|
||||
return;
|
||||
|
||||
if (mute) {
|
||||
track->flags |= GST_MIXER_TRACK_MUTE;
|
||||
|
||||
if (alsa_track->shared_mute)
|
||||
((GstMixerTrack *) (alsa_track->shared_mute))->flags |=
|
||||
GST_MIXER_TRACK_MUTE;
|
||||
} else {
|
||||
track->flags &= ~GST_MIXER_TRACK_MUTE;
|
||||
|
||||
if (alsa_track->shared_mute)
|
||||
((GstMixerTrack *) (alsa_track->shared_mute))->flags &=
|
||||
~GST_MIXER_TRACK_MUTE;
|
||||
}
|
||||
|
||||
if (snd_mixer_selem_has_playback_switch (alsa_track->element)) {
|
||||
if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PSWITCH) {
|
||||
snd_mixer_selem_set_playback_switch_all (alsa_track->element, mute ? 0 : 1);
|
||||
} else {
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
long vol = mute ? 0 : alsa_track->volumes[i];
|
||||
gint i;
|
||||
GstAlsaMixerTrack *ctrl_track;
|
||||
|
||||
if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CAPTURE) {
|
||||
snd_mixer_selem_set_capture_volume (alsa_track->element, i, vol);
|
||||
} else if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PLAYBACK) {
|
||||
snd_mixer_selem_set_playback_volume (alsa_track->element, i, vol);
|
||||
}
|
||||
if ((track->flags & GST_MIXER_TRACK_INPUT)
|
||||
&& alsa_track->shared_mute != NULL)
|
||||
ctrl_track = alsa_track->shared_mute;
|
||||
else
|
||||
ctrl_track = alsa_track;
|
||||
|
||||
for (i = 0; i < ((GstMixerTrack *) ctrl_track)->num_channels; i++) {
|
||||
long vol =
|
||||
mute ? ((GstMixerTrack *) ctrl_track)->min_volume : ctrl_track->
|
||||
volumes[i];
|
||||
snd_mixer_selem_set_playback_volume (ctrl_track->element, i, vol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -406,13 +459,45 @@ gst_alsa_mixer_set_record (GstAlsaMixer * mixer,
|
|||
|
||||
gst_alsa_mixer_update (mixer, alsa_track);
|
||||
|
||||
if (!!(record) == !!(track->flags & GST_MIXER_TRACK_RECORD))
|
||||
return;
|
||||
|
||||
if (record) {
|
||||
track->flags |= GST_MIXER_TRACK_RECORD;
|
||||
} else {
|
||||
track->flags &= ~GST_MIXER_TRACK_RECORD;
|
||||
}
|
||||
|
||||
snd_mixer_selem_set_capture_switch_all (alsa_track->element, record ? 1 : 0);
|
||||
if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH) {
|
||||
snd_mixer_selem_set_capture_switch_all (alsa_track->element,
|
||||
record ? 1 : 0);
|
||||
|
||||
/* update all tracks in same exlusive cswitch group */
|
||||
if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH_EXCL) {
|
||||
GList *item;
|
||||
|
||||
for (item = mixer->tracklist; item != NULL; item = item->next) {
|
||||
|
||||
if (GST_IS_ALSA_MIXER_TRACK (item->data)) {
|
||||
GstAlsaMixerTrack *item_alsa_track =
|
||||
GST_ALSA_MIXER_TRACK (item->data);
|
||||
|
||||
if (item_alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH_EXCL &&
|
||||
item_alsa_track->capture_group == alsa_track->capture_group) {
|
||||
gst_alsa_mixer_update (mixer, item_alsa_track);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
long vol = record ? alsa_track->volumes[i] : track->min_volume;
|
||||
|
||||
snd_mixer_selem_set_capture_volume (alsa_track->element, i, vol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -68,10 +68,57 @@ gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track)
|
|||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_alsa_mixer_track_update_alsa_capabilities (GstAlsaMixerTrack * alsa_track)
|
||||
{
|
||||
alsa_track->alsa_flags = 0;
|
||||
alsa_track->capture_group = -1;
|
||||
|
||||
if (snd_mixer_selem_has_common_volume (alsa_track->element))
|
||||
alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_VOLUME;
|
||||
|
||||
if (snd_mixer_selem_has_playback_volume (alsa_track->element))
|
||||
alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PVOLUME;
|
||||
|
||||
if (snd_mixer_selem_has_capture_volume (alsa_track->element))
|
||||
alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CVOLUME;
|
||||
|
||||
if (snd_mixer_selem_has_common_switch (alsa_track->element))
|
||||
alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_SWITCH;
|
||||
|
||||
if (snd_mixer_selem_has_playback_switch (alsa_track->element))
|
||||
alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PSWITCH;
|
||||
|
||||
if (snd_mixer_selem_has_capture_switch (alsa_track->element)) {
|
||||
alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH;
|
||||
|
||||
if (snd_mixer_selem_has_capture_switch_exclusive (alsa_track->element)) {
|
||||
alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH_EXCL;
|
||||
alsa_track->capture_group =
|
||||
snd_mixer_selem_get_capture_group (alsa_track->element);
|
||||
}
|
||||
}
|
||||
|
||||
GST_LOG ("[%s] alsa_flags=0x%08x, capture_group=%d",
|
||||
snd_mixer_selem_get_name (alsa_track->element),
|
||||
alsa_track->alsa_flags, alsa_track->capture_group);
|
||||
}
|
||||
|
||||
inline static gboolean
|
||||
alsa_track_has_cap (GstAlsaMixerTrack * alsa_track, guint32 flag)
|
||||
{
|
||||
return ((alsa_track->alsa_flags & flag) != 0);
|
||||
}
|
||||
|
||||
GstMixerTrack *
|
||||
gst_alsa_mixer_track_new (snd_mixer_elem_t * element,
|
||||
gint num, gint track_num, gint channels, gint flags, gint alsa_flags)
|
||||
gint num, gint track_num, gint flags, gboolean sw,
|
||||
GstAlsaMixerTrack * shared_mute_track, gboolean append_capture)
|
||||
{
|
||||
GstAlsaMixerTrack *alsa_track;
|
||||
GstMixerTrack *track;
|
||||
const gchar *name;
|
||||
const gchar *label;
|
||||
gint i;
|
||||
long min = 0, max = 0;
|
||||
const struct
|
||||
|
@ -93,71 +140,177 @@ gst_alsa_mixer_track_new (snd_mixer_elem_t * element,
|
|||
"Capture", N_("Capture")}
|
||||
};
|
||||
|
||||
GstMixerTrack *track = g_object_new (GST_ALSA_MIXER_TRACK_TYPE, NULL);
|
||||
GstAlsaMixerTrack *alsa_track = (GstAlsaMixerTrack *) track;
|
||||
name = snd_mixer_selem_get_name (element);
|
||||
|
||||
/* set basic information */
|
||||
if (num == 0)
|
||||
track->label = g_strdup (snd_mixer_selem_get_name (element));
|
||||
GST_LOG ("[%s] num=%d,track_num=%d,flags=0x%08x,sw=%s,shared_mute_track=%p",
|
||||
name, num, track_num, flags, (sw) ? "true" : "false", shared_mute_track);
|
||||
|
||||
track = (GstMixerTrack *) g_object_new (GST_ALSA_MIXER_TRACK_TYPE, NULL);
|
||||
alsa_track = (GstAlsaMixerTrack *) track;
|
||||
|
||||
GST_LOG ("[%s] created new mixer track %p", name, track);
|
||||
|
||||
/* This reflects the assumptions used for GstAlsaMixerTrack */
|
||||
if (!(!!(flags & GST_MIXER_TRACK_OUTPUT) ^ !!(flags & GST_MIXER_TRACK_INPUT))) {
|
||||
GST_ERROR ("Mixer track must be either output or input!");
|
||||
g_return_val_if_reached (NULL);
|
||||
}
|
||||
|
||||
track->flags = flags;
|
||||
alsa_track->element = element;
|
||||
alsa_track->shared_mute = shared_mute_track;
|
||||
alsa_track->track_num = track_num;
|
||||
alsa_track->alsa_channels = 0;
|
||||
|
||||
gst_alsa_mixer_track_update_alsa_capabilities (alsa_track);
|
||||
|
||||
if (flags & GST_MIXER_TRACK_OUTPUT) {
|
||||
while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
|
||||
snd_mixer_selem_has_playback_channel (element,
|
||||
alsa_track->alsa_channels)) {
|
||||
alsa_track->alsa_channels++;
|
||||
}
|
||||
GST_LOG ("[%s] %d output channels", name, alsa_track->alsa_channels);
|
||||
} else if (flags & GST_MIXER_TRACK_INPUT) {
|
||||
while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
|
||||
snd_mixer_selem_has_capture_channel (element,
|
||||
alsa_track->alsa_channels)) {
|
||||
alsa_track->alsa_channels++;
|
||||
}
|
||||
GST_LOG ("[%s] %d input channels", name, alsa_track->alsa_channels);
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
if (sw)
|
||||
track->num_channels = 0;
|
||||
else
|
||||
track->label = g_strdup_printf ("%s %d",
|
||||
snd_mixer_selem_get_name (element), num + 1);
|
||||
track->num_channels = alsa_track->alsa_channels;
|
||||
|
||||
/* translate the name if we can */
|
||||
label = name;
|
||||
for (i = 0; i < G_N_ELEMENTS (alsa_track_labels); ++i) {
|
||||
if (!g_utf8_collate (snd_mixer_selem_get_name (element),
|
||||
alsa_track_labels[i].orig)) {
|
||||
g_free (track->label);
|
||||
if (num == 0)
|
||||
track->label = g_strdup (_(alsa_track_labels[i].trans));
|
||||
else
|
||||
track->label = g_strdup_printf ("%s %d",
|
||||
_(alsa_track_labels[i].trans), num);
|
||||
if (g_utf8_collate (label, alsa_track_labels[i].orig) == 0) {
|
||||
label = _(alsa_track_labels[i].trans);
|
||||
break;
|
||||
}
|
||||
}
|
||||
track->num_channels = channels;
|
||||
track->flags = flags;
|
||||
alsa_track->element = element;
|
||||
alsa_track->alsa_flags = alsa_flags;
|
||||
alsa_track->track_num = track_num;
|
||||
|
||||
if (num == 0) {
|
||||
track->label = g_strdup_printf ("%s%s%s", label,
|
||||
append_capture ? " " : "", append_capture ? _("Capture") : "");
|
||||
} else {
|
||||
track->label = g_strdup_printf ("%s%s%s %d", label,
|
||||
append_capture ? " " : "", append_capture ? _("Capture") : "", num);
|
||||
}
|
||||
|
||||
/* set volume information */
|
||||
if (channels) {
|
||||
if (alsa_flags & GST_ALSA_MIXER_TRACK_PLAYBACK) {
|
||||
if (track->num_channels > 0) {
|
||||
if ((flags & GST_MIXER_TRACK_OUTPUT))
|
||||
snd_mixer_selem_get_playback_volume_range (element, &min, &max);
|
||||
} else if (alsa_flags & GST_ALSA_MIXER_TRACK_CAPTURE) {
|
||||
else
|
||||
snd_mixer_selem_get_capture_volume_range (element, &min, &max);
|
||||
}
|
||||
}
|
||||
track->min_volume = (gint) min;
|
||||
track->max_volume = (gint) max;
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
long tmp = 0;
|
||||
|
||||
if (alsa_flags & GST_ALSA_MIXER_TRACK_PLAYBACK) {
|
||||
if (flags & GST_MIXER_TRACK_OUTPUT)
|
||||
snd_mixer_selem_get_playback_volume (element, i, &tmp);
|
||||
} else if (alsa_flags & GST_ALSA_MIXER_TRACK_CAPTURE) {
|
||||
else
|
||||
snd_mixer_selem_get_capture_volume (element, i, &tmp);
|
||||
}
|
||||
|
||||
alsa_track->volumes[i] = (gint) tmp;
|
||||
}
|
||||
|
||||
if (snd_mixer_selem_has_playback_switch (element)) {
|
||||
int val = 1;
|
||||
|
||||
snd_mixer_selem_get_playback_switch (element, 0, &val);
|
||||
if (!val)
|
||||
track->flags |= GST_MIXER_TRACK_MUTE;
|
||||
}
|
||||
|
||||
if (flags & GST_MIXER_TRACK_INPUT) {
|
||||
int val = 0;
|
||||
|
||||
snd_mixer_selem_get_capture_switch (element, 0, &val);
|
||||
if (val)
|
||||
track->flags |= GST_MIXER_TRACK_RECORD;
|
||||
}
|
||||
gst_alsa_mixer_track_update (alsa_track);
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
void
|
||||
gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track)
|
||||
{
|
||||
GstMixerTrack *track = (GstMixerTrack *) alsa_track;
|
||||
gint i;
|
||||
gint audible = !(track->flags & GST_MIXER_TRACK_MUTE);
|
||||
|
||||
/* Any updates in flags? */
|
||||
if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PSWITCH)) {
|
||||
int v = 0;
|
||||
|
||||
audible = 0;
|
||||
for (i = 0; i < alsa_track->alsa_channels; ++i) {
|
||||
snd_mixer_selem_get_playback_switch (alsa_track->element, i, &v);
|
||||
audible += v;
|
||||
}
|
||||
|
||||
} else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME) &&
|
||||
track->flags & GST_MIXER_TRACK_MUTE) {
|
||||
/* check if user has raised volume with a parallel running application */
|
||||
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
long vol = 0;
|
||||
|
||||
snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol);
|
||||
|
||||
if (vol > track->min_volume) {
|
||||
audible = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!!(audible) != !(track->flags & GST_MIXER_TRACK_MUTE)) {
|
||||
if (audible) {
|
||||
track->flags &= ~GST_MIXER_TRACK_MUTE;
|
||||
|
||||
if (alsa_track->shared_mute)
|
||||
((GstMixerTrack *) (alsa_track->shared_mute))->flags &=
|
||||
~GST_MIXER_TRACK_MUTE;
|
||||
} else {
|
||||
track->flags |= GST_MIXER_TRACK_MUTE;
|
||||
|
||||
if (alsa_track->shared_mute)
|
||||
((GstMixerTrack *) (alsa_track->shared_mute))->flags |=
|
||||
GST_MIXER_TRACK_MUTE;
|
||||
}
|
||||
}
|
||||
|
||||
if (track->flags & GST_MIXER_TRACK_INPUT) {
|
||||
gint recording = track->flags & GST_MIXER_TRACK_RECORD;
|
||||
|
||||
if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CSWITCH)) {
|
||||
int v = 0;
|
||||
|
||||
recording = 0;
|
||||
for (i = 0; i < alsa_track->alsa_channels; ++i) {
|
||||
snd_mixer_selem_get_capture_switch (alsa_track->element, i, &v);
|
||||
recording += v;
|
||||
}
|
||||
|
||||
} else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME) &&
|
||||
!(track->flags & GST_MIXER_TRACK_RECORD)) {
|
||||
/* check if user has raised volume with a parallel running application */
|
||||
|
||||
for (i = 0; i < track->num_channels; i++) {
|
||||
long vol = 0;
|
||||
|
||||
snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol);
|
||||
|
||||
if (vol > track->min_volume) {
|
||||
recording = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (recording)
|
||||
track->flags |= GST_MIXER_TRACK_RECORD;
|
||||
else
|
||||
track->flags &= ~GST_MIXER_TRACK_RECORD;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,15 +38,24 @@ G_BEGIN_DECLS
|
|||
typedef struct _GstAlsaMixerTrack GstAlsaMixerTrack;
|
||||
typedef struct _GstAlsaMixerTrackClass GstAlsaMixerTrackClass;
|
||||
|
||||
#define GST_ALSA_MIXER_TRACK_CAPTURE (1<<0)
|
||||
#define GST_ALSA_MIXER_TRACK_PLAYBACK (1<<1)
|
||||
#define GST_ALSA_MIXER_TRACK_VOLUME (1<<0) /* common volume */
|
||||
#define GST_ALSA_MIXER_TRACK_PVOLUME (1<<1)
|
||||
#define GST_ALSA_MIXER_TRACK_CVOLUME (1<<2)
|
||||
#define GST_ALSA_MIXER_TRACK_SWITCH (1<<3) /* common switch */
|
||||
#define GST_ALSA_MIXER_TRACK_PSWITCH (1<<4)
|
||||
#define GST_ALSA_MIXER_TRACK_CSWITCH (1<<5)
|
||||
#define GST_ALSA_MIXER_TRACK_CSWITCH_EXCL (1<<6)
|
||||
|
||||
#define GST_ALSA_MAX_CHANNELS (SND_MIXER_SCHN_LAST+1)
|
||||
|
||||
#define GST_ALSA_MAX_CHANNELS 32 /* tracks can have up to 32 channels */
|
||||
struct _GstAlsaMixerTrack {
|
||||
GstMixerTrack parent;
|
||||
snd_mixer_elem_t *element; /* the ALSA mixer element for this track */
|
||||
snd_mixer_elem_t *element; /* the ALSA mixer element for this track */
|
||||
GstAlsaMixerTrack *shared_mute;
|
||||
gint track_num;
|
||||
gint alsa_flags;
|
||||
guint32 alsa_flags; /* alsa track capabilities */
|
||||
gint alsa_channels;
|
||||
gint capture_group;
|
||||
gint volumes[GST_ALSA_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
|
@ -58,10 +67,11 @@ GType gst_alsa_mixer_track_get_type (void);
|
|||
GstMixerTrack * gst_alsa_mixer_track_new (snd_mixer_elem_t * element,
|
||||
gint num,
|
||||
gint track_num,
|
||||
gint channels,
|
||||
gint flags,
|
||||
gint alsa_flags);
|
||||
|
||||
gboolean sw, /* is simple switch? */
|
||||
GstAlsaMixerTrack * shared_mute_track,
|
||||
gboolean label_append_capture);
|
||||
void gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
Loading…
Reference in a new issue