[alsa-devel] [RFCv3][PATCH 37/39] axfer: add a parser for channel map API

Takashi Sakamoto o-takashi at sakamocchi.jp
Mon Oct 2 02:19:38 CEST 2017


Current aplay has an option to use channel map API of alsa-lib. This API
allows applications to get/set channel position by a position array; e.g.
'FR,FL' and 'LFE,FL,FR'.

This commit adds support for the feature. However, neither alsa-lib
implementation nor ALSA PCM interface, configuring the channel map is not
supported. Therefore, this feature makes no sense except for displaying
current channel map.

Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
---
 axfer/options.c        | 29 ++++++++++++++++++++++++++---
 axfer/options.h        |  1 +
 axfer/xfer-libasound.c | 32 ++++++++++++++++++++++++++++++++
 axfer/xfer-libasound.h |  2 ++
 4 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/axfer/options.c b/axfer/options.c
index d4e7876b..7e112c42 100644
--- a/axfer/options.c
+++ b/axfer/options.c
@@ -205,7 +205,8 @@ static int apply_policies(struct context_options *opts,
 			  const char *sample_format_literal,
 			  const char *waiter_type_literal,
 			  const char *sched_type_literal,
-			  const char *vu_mode_literal)
+			  const char *vu_mode_literal,
+			  const char *chmap_literal)
 {
 	int err;
 
@@ -238,6 +239,21 @@ static int apply_policies(struct context_options *opts,
 			return err;
 	}
 
+	if (chmap_literal) {
+		snd_pcm_chmap_t *chmap;
+		chmap = snd_pcm_chmap_parse_string(chmap_literal);
+		if (chmap == NULL) {
+			fprintf(stderr,
+				"Unable to parse channel map string: '%s'\n",
+				chmap_literal);
+			return -EINVAL;
+		}
+		free(chmap);
+		opts->chmap_literal = strdup(chmap_literal);
+		if (opts->chmap_literal == NULL)
+			return -ENOMEM;
+	}
+
 	if (opts->samples_per_frame > 0) {
 		if (opts->samples_per_frame < 1 ||
 		    opts->samples_per_frame > 256) {
@@ -409,7 +425,7 @@ void context_options_calculate_duration(struct context_options *opts,
 int context_options_init(struct context_options *opts, int argc,
 			 char *const *argv, snd_pcm_stream_t direction)
 {
-	static const char *s_opts = "hvqd:s:t:ID:f:c:r:NMw:F:B:A:R:T:V:i";
+	static const char *s_opts = "hvqd:s:t:ID:f:c:r:NMw:F:B:A:R:T:V:im:";
 	static const struct option l_opts[] = {
 		/* For generic purposes. */
 		{"help",		0, 0, 'h'},
@@ -451,6 +467,7 @@ int context_options_init(struct context_options *opts, int argc,
 		/* Misc features. */
 		{"vumeter",		1, 0, 'V'},
 		{"interactive",		0, 0, 'i'},
+		{"chmap",		1, 0, 'm'},
 		/* Obsoleted. */
 		{"max-file-time",       1, 0, OPT_MAX_FILE_TIME},
 		{NULL,			0, 0, 0},
@@ -461,6 +478,7 @@ int context_options_init(struct context_options *opts, int argc,
 	const char *waiter_type_literal = NULL;
 	const char *sched_type_literal = NULL;
 	const char *vu_mode_literal = NULL;
+	const char *chmap_literal = NULL;
 	int l_index = 0;
 	int c;
 	int err = 0;
@@ -535,6 +553,8 @@ int context_options_init(struct context_options *opts, int argc,
 			vu_mode_literal = optarg;
 		else if (c == 'i')
 			opts->interactive = true;
+		else if (c == 'm')
+			chmap_literal = optarg;
 		else if (c == OPT_MAX_FILE_TIME) {
 			fprintf(stderr,
 				"An option '--%s' is obsoleted and has no "
@@ -555,7 +575,7 @@ int context_options_init(struct context_options *opts, int argc,
 	return apply_policies(opts, direction, cntr_format_literal,
 			      node_literal, sample_format_literal,
 			      waiter_type_literal, sched_type_literal,
-			      vu_mode_literal);
+			      vu_mode_literal, chmap_literal);
 }
 
 /*
@@ -909,6 +929,9 @@ void context_options_destroy(struct context_options *opts)
 	}
 	if (opts->node)
 		free(opts->node);
+	if (opts->chmap_literal)
+		free(opts->chmap_literal);
 	opts->paths = NULL;
 	opts->node = NULL;
+	opts->chmap_literal = NULL;
 }
diff --git a/axfer/options.h b/axfer/options.h
index fed9a40e..b8aba167 100644
--- a/axfer/options.h
+++ b/axfer/options.h
@@ -73,6 +73,7 @@ struct context_options {
 	/* Misc features. */
 	enum vumeter_mode vu_mode;
 	bool interactive;
+	char *chmap_literal;
 };
 
 int context_options_init(struct context_options *opts, int argc,
diff --git a/axfer/xfer-libasound.c b/axfer/xfer-libasound.c
index 92aba3c4..4e8c6e2e 100644
--- a/axfer/xfer-libasound.c
+++ b/axfer/xfer-libasound.c
@@ -84,6 +84,17 @@ static int disable_period_wakeup(struct libasound_state *state)
 	return err;
 }
 
+static void dump_chmap(struct libasound_state *state,
+		       const snd_pcm_chmap_t *chmap)
+{
+	int i;
+
+	logging(state, "    channels: %u\n", chmap->channels);
+	for (i = 0; i < chmap->channels; ++i)
+		logging(state, "      ch%u: %s\n",
+			i, snd_pcm_chmap_name(chmap->pos[i]));
+}
+
 static int xfer_libasound_init(struct xfer_context *xfer,
 			       snd_pcm_stream_t direction,
 			       struct context_options *opts)
@@ -152,6 +163,17 @@ static int xfer_libasound_init(struct xfer_context *xfer,
 		return 0;
 	}
 
+	if (opts->chmap_literal != NULL) {
+		state->chmap = snd_pcm_chmap_parse_string(opts->chmap_literal);
+		if (state->chmap == NULL)
+			return -ENOMEM;
+
+		if (xfer->verbose) {
+			logging(state, "Chmap argument:\n");
+			dump_chmap(state, state->chmap);
+		}
+	}
+
 	return set_access_hw_param(state->handle, state->hw_params, opts);
 }
 
@@ -238,6 +260,12 @@ static int configure_hw_params(struct libasound_state *state,
 			return err;
 		}
 	}
+	if (state->chmap && samples_per_frame != state->chmap->channels) {
+		logging(state,
+			_("Mismatch between channel number and given map: %u "
+			  "%u\n"),
+			samples_per_frame, state->chmap->channels);
+	}
 	err = snd_pcm_hw_params_set_channels(state->handle, state->hw_params,
 					     samples_per_frame);
 	if (err < 0) {
@@ -690,6 +718,10 @@ static void xfer_libasound_destroy(struct xfer_context *xfer)
 	if (state->log)
 		snd_output_close(state->log);
 	state->log = NULL;
+
+	if (state->chmap)
+		free(state->chmap);
+	state->chmap = NULL;
 }
 
 const struct xfer_data xfer_libasound = {
diff --git a/axfer/xfer-libasound.h b/axfer/xfer-libasound.h
index 004613fa..11e610d8 100644
--- a/axfer/xfer-libasound.h
+++ b/axfer/xfer-libasound.h
@@ -34,6 +34,8 @@ struct libasound_state {
 
 	bool verbose;
 	bool finish_at_xrun;
+
+	snd_pcm_chmap_t *chmap;
 };
 
 struct xfer_libasound_ops {
-- 
2.11.0



More information about the Alsa-devel mailing list