1d5ac70f0Sopenharmony_ci/*
2d5ac70f0Sopenharmony_ci * channel mapping API test program
3d5ac70f0Sopenharmony_ci */
4d5ac70f0Sopenharmony_ci
5d5ac70f0Sopenharmony_ci#include "config.h"
6d5ac70f0Sopenharmony_ci#include <stdio.h>
7d5ac70f0Sopenharmony_ci#include <stdlib.h>
8d5ac70f0Sopenharmony_ci#include <string.h>
9d5ac70f0Sopenharmony_ci#include <ctype.h>
10d5ac70f0Sopenharmony_ci#include <getopt.h>
11d5ac70f0Sopenharmony_ci#include "../include/asoundlib.h"
12d5ac70f0Sopenharmony_ci
13d5ac70f0Sopenharmony_cistatic void usage(void)
14d5ac70f0Sopenharmony_ci{
15d5ac70f0Sopenharmony_ci	printf("usage: chmap [options] query\n"
16d5ac70f0Sopenharmony_ci	       "       chmap [options] get\n"
17d5ac70f0Sopenharmony_ci	       "       chmap [options] set CH0 CH1 CH2...\n"
18d5ac70f0Sopenharmony_ci	       "options:\n"
19d5ac70f0Sopenharmony_ci	       "  -D device     Specify PCM device to handle\n"
20d5ac70f0Sopenharmony_ci	       "  -s stream     Specify PCM stream direction (playback/capture)\n"
21d5ac70f0Sopenharmony_ci	       "  -f format     PCM format\n"
22d5ac70f0Sopenharmony_ci	       "  -c channels   Channels\n"
23d5ac70f0Sopenharmony_ci	       "  -r rate       Sample rate\n");
24d5ac70f0Sopenharmony_ci}
25d5ac70f0Sopenharmony_ci
26d5ac70f0Sopenharmony_cistatic void print_channels(const snd_pcm_chmap_t *map)
27d5ac70f0Sopenharmony_ci{
28d5ac70f0Sopenharmony_ci	char tmp[128];
29d5ac70f0Sopenharmony_ci	if (snd_pcm_chmap_print(map, sizeof(tmp), tmp) > 0)
30d5ac70f0Sopenharmony_ci		printf("  %s\n", tmp);
31d5ac70f0Sopenharmony_ci}
32d5ac70f0Sopenharmony_ci
33d5ac70f0Sopenharmony_cistatic int query_chmaps(snd_pcm_t *pcm)
34d5ac70f0Sopenharmony_ci{
35d5ac70f0Sopenharmony_ci	snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps(pcm);
36d5ac70f0Sopenharmony_ci	snd_pcm_chmap_query_t **p, *v;
37d5ac70f0Sopenharmony_ci
38d5ac70f0Sopenharmony_ci	if (!maps) {
39d5ac70f0Sopenharmony_ci		printf("Cannot query maps\n");
40d5ac70f0Sopenharmony_ci		return 1;
41d5ac70f0Sopenharmony_ci	}
42d5ac70f0Sopenharmony_ci	for (p = maps; (v = *p) != NULL; p++) {
43d5ac70f0Sopenharmony_ci		printf("Type = %s, Channels = %d\n",
44d5ac70f0Sopenharmony_ci		       snd_pcm_chmap_type_name(v->type),
45d5ac70f0Sopenharmony_ci		       v->map.channels);
46d5ac70f0Sopenharmony_ci		print_channels(&v->map);
47d5ac70f0Sopenharmony_ci	}
48d5ac70f0Sopenharmony_ci	snd_pcm_free_chmaps(maps);
49d5ac70f0Sopenharmony_ci	return 0;
50d5ac70f0Sopenharmony_ci}
51d5ac70f0Sopenharmony_ci
52d5ac70f0Sopenharmony_cistatic int setup_pcm(snd_pcm_t *pcm, int format, int channels, int rate)
53d5ac70f0Sopenharmony_ci{
54d5ac70f0Sopenharmony_ci	snd_pcm_hw_params_t *params;
55d5ac70f0Sopenharmony_ci
56d5ac70f0Sopenharmony_ci	snd_pcm_hw_params_alloca(&params);
57d5ac70f0Sopenharmony_ci	if (snd_pcm_hw_params_any(pcm, params) < 0) {
58d5ac70f0Sopenharmony_ci		printf("Cannot init hw_params\n");
59d5ac70f0Sopenharmony_ci		return -1;
60d5ac70f0Sopenharmony_ci	}
61d5ac70f0Sopenharmony_ci	if (format != SND_PCM_FORMAT_UNKNOWN) {
62d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_set_format(pcm, params, format) < 0) {
63d5ac70f0Sopenharmony_ci			printf("Cannot set format %s\n",
64d5ac70f0Sopenharmony_ci			       snd_pcm_format_name(format));
65d5ac70f0Sopenharmony_ci			return -1;
66d5ac70f0Sopenharmony_ci		}
67d5ac70f0Sopenharmony_ci	}
68d5ac70f0Sopenharmony_ci	if (channels > 0) {
69d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_set_channels(pcm, params, channels) < 0) {
70d5ac70f0Sopenharmony_ci			printf("Cannot set channels %d\n", channels);
71d5ac70f0Sopenharmony_ci			return -1;
72d5ac70f0Sopenharmony_ci		}
73d5ac70f0Sopenharmony_ci	}
74d5ac70f0Sopenharmony_ci	if (rate > 0) {
75d5ac70f0Sopenharmony_ci		if (snd_pcm_hw_params_set_rate_near(pcm, params, (unsigned int *)&rate, 0) < 0) {
76d5ac70f0Sopenharmony_ci			printf("Cannot set rate %d\n", rate);
77d5ac70f0Sopenharmony_ci			return -1;
78d5ac70f0Sopenharmony_ci		}
79d5ac70f0Sopenharmony_ci	}
80d5ac70f0Sopenharmony_ci	if (snd_pcm_hw_params(pcm, params) < 0) {
81d5ac70f0Sopenharmony_ci		printf("Cannot set hw_params\n");
82d5ac70f0Sopenharmony_ci		return -1;
83d5ac70f0Sopenharmony_ci	}
84d5ac70f0Sopenharmony_ci	return 0;
85d5ac70f0Sopenharmony_ci}
86d5ac70f0Sopenharmony_ci
87d5ac70f0Sopenharmony_cistatic int get_chmap(snd_pcm_t *pcm, int format, int channels, int rate)
88d5ac70f0Sopenharmony_ci{
89d5ac70f0Sopenharmony_ci	snd_pcm_chmap_t *map;
90d5ac70f0Sopenharmony_ci
91d5ac70f0Sopenharmony_ci	if (setup_pcm(pcm, format, channels, rate))
92d5ac70f0Sopenharmony_ci		return 1;
93d5ac70f0Sopenharmony_ci	map = snd_pcm_get_chmap(pcm);
94d5ac70f0Sopenharmony_ci	if (!map) {
95d5ac70f0Sopenharmony_ci		printf("Cannot get chmap\n");
96d5ac70f0Sopenharmony_ci		return 1;
97d5ac70f0Sopenharmony_ci	}
98d5ac70f0Sopenharmony_ci	printf("Channels = %d\n", map->channels);
99d5ac70f0Sopenharmony_ci	print_channels(map);
100d5ac70f0Sopenharmony_ci	free(map);
101d5ac70f0Sopenharmony_ci	return 0;
102d5ac70f0Sopenharmony_ci}
103d5ac70f0Sopenharmony_ci
104d5ac70f0Sopenharmony_cistatic int set_chmap(snd_pcm_t *pcm, int format, int channels, int rate,
105d5ac70f0Sopenharmony_ci		     int nargs, char **arg)
106d5ac70f0Sopenharmony_ci{
107d5ac70f0Sopenharmony_ci	int i;
108d5ac70f0Sopenharmony_ci	snd_pcm_chmap_t *map;
109d5ac70f0Sopenharmony_ci
110d5ac70f0Sopenharmony_ci	if (channels && channels != nargs) {
111d5ac70f0Sopenharmony_ci		printf("Inconsistent channels %d vs %d\n", channels, nargs);
112d5ac70f0Sopenharmony_ci		return 1;
113d5ac70f0Sopenharmony_ci	}
114d5ac70f0Sopenharmony_ci	if (!channels) {
115d5ac70f0Sopenharmony_ci		if (!nargs) {
116d5ac70f0Sopenharmony_ci			printf("No channels are given\n");
117d5ac70f0Sopenharmony_ci			return 1;
118d5ac70f0Sopenharmony_ci		}
119d5ac70f0Sopenharmony_ci		channels = nargs;
120d5ac70f0Sopenharmony_ci	}
121d5ac70f0Sopenharmony_ci	if (setup_pcm(pcm, format, channels, rate))
122d5ac70f0Sopenharmony_ci		return 1;
123d5ac70f0Sopenharmony_ci	map = malloc(sizeof(int) * (channels + 1));
124d5ac70f0Sopenharmony_ci	if (!map) {
125d5ac70f0Sopenharmony_ci		printf("cannot malloc\n");
126d5ac70f0Sopenharmony_ci		return 1;
127d5ac70f0Sopenharmony_ci	}
128d5ac70f0Sopenharmony_ci	map->channels = channels;
129d5ac70f0Sopenharmony_ci	for (i = 0; i < channels; i++) {
130d5ac70f0Sopenharmony_ci		int val = snd_pcm_chmap_from_string(arg[i]);
131d5ac70f0Sopenharmony_ci		if (val < 0)
132d5ac70f0Sopenharmony_ci			val = SND_CHMAP_UNKNOWN;
133d5ac70f0Sopenharmony_ci		map->pos[i] = val;
134d5ac70f0Sopenharmony_ci	}
135d5ac70f0Sopenharmony_ci	if (snd_pcm_set_chmap(pcm, map) < 0) {
136d5ac70f0Sopenharmony_ci		printf("Cannot set chmap\n");
137d5ac70f0Sopenharmony_ci		return 1;
138d5ac70f0Sopenharmony_ci	}
139d5ac70f0Sopenharmony_ci	free(map);
140d5ac70f0Sopenharmony_ci
141d5ac70f0Sopenharmony_ci	map = snd_pcm_get_chmap(pcm);
142d5ac70f0Sopenharmony_ci	if (!map) {
143d5ac70f0Sopenharmony_ci		printf("Cannot get chmap\n");
144d5ac70f0Sopenharmony_ci		return 1;
145d5ac70f0Sopenharmony_ci	}
146d5ac70f0Sopenharmony_ci	printf("Get channels = %d\n", map->channels);
147d5ac70f0Sopenharmony_ci	print_channels(map);
148d5ac70f0Sopenharmony_ci	free(map);
149d5ac70f0Sopenharmony_ci	return 0;
150d5ac70f0Sopenharmony_ci}
151d5ac70f0Sopenharmony_ci
152d5ac70f0Sopenharmony_ciint main(int argc, char **argv)
153d5ac70f0Sopenharmony_ci{
154d5ac70f0Sopenharmony_ci	char *device = NULL;
155d5ac70f0Sopenharmony_ci	int stream = SND_PCM_STREAM_PLAYBACK;
156d5ac70f0Sopenharmony_ci	int format = SND_PCM_FORMAT_UNKNOWN;
157d5ac70f0Sopenharmony_ci	int channels = 0;
158d5ac70f0Sopenharmony_ci	int rate = 0;
159d5ac70f0Sopenharmony_ci	snd_pcm_t *pcm;
160d5ac70f0Sopenharmony_ci	int c;
161d5ac70f0Sopenharmony_ci
162d5ac70f0Sopenharmony_ci	while ((c = getopt(argc, argv, "D:s:f:c:r:")) != -1) {
163d5ac70f0Sopenharmony_ci		switch (c) {
164d5ac70f0Sopenharmony_ci		case 'D':
165d5ac70f0Sopenharmony_ci			device = optarg;
166d5ac70f0Sopenharmony_ci			break;
167d5ac70f0Sopenharmony_ci		case 's':
168d5ac70f0Sopenharmony_ci			if (*optarg == 'c' || *optarg == 'C')
169d5ac70f0Sopenharmony_ci				stream = SND_PCM_STREAM_CAPTURE;
170d5ac70f0Sopenharmony_ci			else
171d5ac70f0Sopenharmony_ci				stream = SND_PCM_STREAM_PLAYBACK;
172d5ac70f0Sopenharmony_ci			break;
173d5ac70f0Sopenharmony_ci		case 'f':
174d5ac70f0Sopenharmony_ci			format = snd_pcm_format_value(optarg);
175d5ac70f0Sopenharmony_ci			break;
176d5ac70f0Sopenharmony_ci		case 'c':
177d5ac70f0Sopenharmony_ci			channels = atoi(optarg);
178d5ac70f0Sopenharmony_ci			break;
179d5ac70f0Sopenharmony_ci		case 'r':
180d5ac70f0Sopenharmony_ci			rate = atoi(optarg);
181d5ac70f0Sopenharmony_ci			break;
182d5ac70f0Sopenharmony_ci		default:
183d5ac70f0Sopenharmony_ci			usage();
184d5ac70f0Sopenharmony_ci			return 1;
185d5ac70f0Sopenharmony_ci		}
186d5ac70f0Sopenharmony_ci	}
187d5ac70f0Sopenharmony_ci
188d5ac70f0Sopenharmony_ci	if (argc <= optind) {
189d5ac70f0Sopenharmony_ci		usage();
190d5ac70f0Sopenharmony_ci		return 1;
191d5ac70f0Sopenharmony_ci	}
192d5ac70f0Sopenharmony_ci
193d5ac70f0Sopenharmony_ci	if (!device) {
194d5ac70f0Sopenharmony_ci		printf("No device is specified\n");
195d5ac70f0Sopenharmony_ci		return 1;
196d5ac70f0Sopenharmony_ci	}
197d5ac70f0Sopenharmony_ci
198d5ac70f0Sopenharmony_ci	if (snd_pcm_open(&pcm, device, stream, SND_PCM_NONBLOCK) < 0) {
199d5ac70f0Sopenharmony_ci		printf("Cannot open PCM stream %s for %s\n", device,
200d5ac70f0Sopenharmony_ci		       snd_pcm_stream_name(stream));
201d5ac70f0Sopenharmony_ci		return 1;
202d5ac70f0Sopenharmony_ci	}
203d5ac70f0Sopenharmony_ci
204d5ac70f0Sopenharmony_ci	switch (*argv[optind]) {
205d5ac70f0Sopenharmony_ci	case 'q':
206d5ac70f0Sopenharmony_ci		return query_chmaps(pcm);
207d5ac70f0Sopenharmony_ci	case 'g':
208d5ac70f0Sopenharmony_ci		return get_chmap(pcm, format, channels, rate);
209d5ac70f0Sopenharmony_ci	case 's':
210d5ac70f0Sopenharmony_ci		return set_chmap(pcm, format, channels, rate,
211d5ac70f0Sopenharmony_ci				 argc - optind - 1, argv + optind + 1);
212d5ac70f0Sopenharmony_ci	}
213d5ac70f0Sopenharmony_ci	usage();
214d5ac70f0Sopenharmony_ci	return 1;
215d5ac70f0Sopenharmony_ci}
216