From 76d807893cca68086cd7fb49649c55a7e3078c3c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Oct 2013 17:07:02 +0200 Subject: [PATCH] alsa: Add channel map API support The initial support for the new ALSA chmap API. Just translate the current chmap to GstAudioChannelPosition during the setup. No function to specify the channel map manually yet, so still impossible to assign any non-standard positions or to configure in a different order even if the hardware allows. https://bugzilla.gnome.org/show_bug.cgi?id=709755 --- ext/alsa/gstalsa.c | 52 ++++++++++++++++++++++++++++++++++++++++++ ext/alsa/gstalsa.h | 4 ++++ ext/alsa/gstalsasink.c | 12 ++++++++++ ext/alsa/gstalsasrc.c | 12 ++++++++++ 4 files changed, 80 insertions(+) diff --git a/ext/alsa/gstalsa.c b/ext/alsa/gstalsa.c index 0828110d33..d702a23a1e 100644 --- a/ext/alsa/gstalsa.c +++ b/ext/alsa/gstalsa.c @@ -707,3 +707,55 @@ const GstAudioChannelPosition alsa_position[][8] = { GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT} }; + +#ifdef SND_CHMAP_API_VERSION +/* +1 is to make zero as holes */ +#define ITEM(x, y) \ + [SND_CHMAP_ ## x] = GST_AUDIO_CHANNEL_POSITION_ ## y + 1 + +static GstAudioChannelPosition gst_pos[SND_CHMAP_LAST + 1] = { + ITEM(MONO, MONO), + ITEM(FL, FRONT_LEFT), + ITEM(FR, FRONT_RIGHT), + ITEM(FC, FRONT_CENTER), + ITEM(RL, REAR_LEFT), + ITEM(RR, REAR_RIGHT), + ITEM(RC, REAR_CENTER), + ITEM(LFE, LFE1), + ITEM(SL, SIDE_LEFT), + ITEM(SR, SIDE_RIGHT), + ITEM(FLC, FRONT_LEFT_OF_CENTER), + ITEM(FRC, FRONT_RIGHT_OF_CENTER), + ITEM(FLW, WIDE_LEFT), + ITEM(FRW, WIDE_RIGHT), + ITEM(TC, TOP_CENTER), + ITEM(TFL, TOP_FRONT_LEFT), + ITEM(TFR, TOP_FRONT_RIGHT), + ITEM(TFC, TOP_FRONT_CENTER), + ITEM(TRL, TOP_REAR_LEFT), + ITEM(TRR, TOP_REAR_RIGHT), + ITEM(TRC, TOP_REAR_CENTER), + ITEM(LLFE, LFE1), + ITEM(RLFE, LFE2), + ITEM(BC, BOTTOM_FRONT_CENTER), + ITEM(BLC, BOTTOM_FRONT_LEFT), + ITEM(BRC, BOTTOM_FRONT_LEFT), +}; +#undef ITEM + +gboolean alsa_chmap_to_channel_positions (const snd_pcm_chmap_t *chmap, + GstAudioChannelPosition *pos) +{ + int c; + + for (c = 0; c < chmap->channels; c++) { + if (chmap->pos[c] > SND_CHMAP_LAST) + return FALSE; + pos[c] = gst_pos[chmap->pos[c]]; + if (!pos[c]) + return FALSE; + pos[c]--; + } + return TRUE; +} +#endif /* SND_CHMAP_API_VERSION */ diff --git a/ext/alsa/gstalsa.h b/ext/alsa/gstalsa.h index b9000ded39..8026619d4c 100644 --- a/ext/alsa/gstalsa.h +++ b/ext/alsa/gstalsa.h @@ -71,5 +71,9 @@ void gst_alsa_add_channel_reorder_map (GstObject * obj, GstCaps * caps); extern const GstAudioChannelPosition alsa_position[][8]; +#ifdef SND_CHMAP_API_VERSION +gboolean alsa_chmap_to_channel_positions (const snd_pcm_chmap_t *chmap, + GstAudioChannelPosition *pos); +#endif #endif /* __GST_ALSA_H__ */ diff --git a/ext/alsa/gstalsasink.c b/ext/alsa/gstalsasink.c index 19dbd8bde6..38957499ca 100644 --- a/ext/alsa/gstalsasink.c +++ b/ext/alsa/gstalsasink.c @@ -896,6 +896,18 @@ gst_alsasink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec) snd_output_close (out_buf); } +#ifdef SND_CHMAP_API_VERSION + if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW && alsa->channels < 9) { + snd_pcm_chmap_t *chmap = snd_pcm_get_chmap (alsa->handle); + if (chmap && chmap->channels == alsa->channels) { + GstAudioChannelPosition pos[8]; + if (alsa_chmap_to_channel_positions (chmap, pos)) + gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SINK (alsa)->ringbuffer, pos); + } + free (chmap); + } +#endif /* SND_CHMAP_API_VERSION */ + return TRUE; /* ERRORS */ diff --git a/ext/alsa/gstalsasrc.c b/ext/alsa/gstalsasrc.c index fa4b5556bc..741f9f9fa2 100644 --- a/ext/alsa/gstalsasrc.c +++ b/ext/alsa/gstalsasrc.c @@ -783,6 +783,18 @@ gst_alsasrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) snd_output_close (out_buf); } +#ifdef SND_CHMAP_API_VERSION + if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW && alsa->channels < 9) { + snd_pcm_chmap_t *chmap = snd_pcm_get_chmap (alsa->handle); + if (chmap && chmap->channels == alsa->channels) { + GstAudioChannelPosition pos[8]; + if (alsa_chmap_to_channel_positions (chmap, pos)) + gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC (alsa)->ringbuffer, pos); + } + free (chmap); + } +#endif /* SND_CHMAP_API_VERSION */ + return TRUE; /* ERRORS */