1 /* PipeWire
2  *
3  * Copyright © 2020 Wim Taymans
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <spa/utils/string.h>
26 #include <spa/debug/types.h>
27 #include <spa/param/audio/format.h>
28 #include <spa/param/audio/format-utils.h>
29 #include <spa/param/audio/raw.h>
30 #include <spa/utils/json.h>
31 
32 #include "format.h"
33 
34 static const struct format audio_formats[] = {
35 	[SAMPLE_U8] = { SAMPLE_U8, SPA_AUDIO_FORMAT_U8, "u8", 1 },
36 	[SAMPLE_ALAW] = { SAMPLE_ALAW, SPA_AUDIO_FORMAT_ALAW, "aLaw", 1 },
37 	[SAMPLE_ULAW] = { SAMPLE_ULAW, SPA_AUDIO_FORMAT_ULAW, "uLaw", 1 },
38 	[SAMPLE_S16LE] = { SAMPLE_S16LE, SPA_AUDIO_FORMAT_S16_LE, "s16le", 2 },
39 	[SAMPLE_S16BE] = { SAMPLE_S16BE, SPA_AUDIO_FORMAT_S16_BE, "s16be", 2 },
40 	[SAMPLE_FLOAT32LE] = { SAMPLE_FLOAT32LE, SPA_AUDIO_FORMAT_F32_LE, "float32le", 4 },
41 	[SAMPLE_FLOAT32BE] = { SAMPLE_FLOAT32BE, SPA_AUDIO_FORMAT_F32_BE, "float32be", 4 },
42 	[SAMPLE_S32LE] = { SAMPLE_S32LE, SPA_AUDIO_FORMAT_S32_LE, "s32le", 4 },
43 	[SAMPLE_S32BE] = { SAMPLE_S32BE, SPA_AUDIO_FORMAT_S32_BE, "s32be", 4 },
44 	[SAMPLE_S24LE] = { SAMPLE_S24LE, SPA_AUDIO_FORMAT_S24_LE, "s24le", 3 },
45 	[SAMPLE_S24BE] = { SAMPLE_S24BE, SPA_AUDIO_FORMAT_S24_BE, "s24be", 3 },
46 	[SAMPLE_S24_32LE] = { SAMPLE_S24_32LE, SPA_AUDIO_FORMAT_S24_32_LE, "s24-32le", 4 },
47 	[SAMPLE_S24_32BE] = { SAMPLE_S24_32BE, SPA_AUDIO_FORMAT_S24_32_BE, "s24-32be", 4 },
48 
49 #if __BYTE_ORDER == __BIG_ENDIAN
50 	{ SAMPLE_S16BE, SPA_AUDIO_FORMAT_S16_BE, "s16ne", 2 },
51 	{ SAMPLE_FLOAT32BE, SPA_AUDIO_FORMAT_F32_BE, "float32ne", 4 },
52 	{ SAMPLE_S32BE, SPA_AUDIO_FORMAT_S32_BE, "s32ne", 4 },
53 	{ SAMPLE_S24BE, SPA_AUDIO_FORMAT_S24_BE, "s24ne", 3 },
54 	{ SAMPLE_S24_32BE, SPA_AUDIO_FORMAT_S24_32_BE, "s24-32ne", 4 },
55 #elif __BYTE_ORDER == __LITTLE_ENDIAN
56 	{ SAMPLE_S16LE, SPA_AUDIO_FORMAT_S16_LE, "s16ne", 2 },
57 	{ SAMPLE_FLOAT32LE, SPA_AUDIO_FORMAT_F32_LE, "float32ne", 4 },
58 	{ SAMPLE_S32LE, SPA_AUDIO_FORMAT_S32_LE, "s32ne", 4 },
59 	{ SAMPLE_S24LE, SPA_AUDIO_FORMAT_S24_LE, "s24ne", 3 },
60 	{ SAMPLE_S24_32LE, SPA_AUDIO_FORMAT_S24_32_LE, "s24-32ne", 4 },
61 #endif
62 	/* planar formats, we just report them as interleaved */
63 	{ SAMPLE_U8, SPA_AUDIO_FORMAT_U8P, "u8ne", 1 },
64 	{ SAMPLE_S16NE, SPA_AUDIO_FORMAT_S16P, "s16ne", 2 },
65 	{ SAMPLE_S24_32NE, SPA_AUDIO_FORMAT_S24_32P, "s24-32ne", 4 },
66 	{ SAMPLE_S32NE, SPA_AUDIO_FORMAT_S32P, "s32ne", 4 },
67 	{ SAMPLE_S24NE, SPA_AUDIO_FORMAT_S24P, "s24ne", 3 },
68 	{ SAMPLE_FLOAT32NE, SPA_AUDIO_FORMAT_F32P, "float32ne", 4 },
69 };
70 
71 static const struct channel audio_channels[] = {
72 	[CHANNEL_POSITION_MONO] = { SPA_AUDIO_CHANNEL_MONO, "mono", },
73 
74 	[CHANNEL_POSITION_FRONT_LEFT] = { SPA_AUDIO_CHANNEL_FL, "front-left", },
75 	[CHANNEL_POSITION_FRONT_RIGHT] = { SPA_AUDIO_CHANNEL_FR, "front-right", },
76 	[CHANNEL_POSITION_FRONT_CENTER] = { SPA_AUDIO_CHANNEL_FC, "front-center", },
77 
78 	[CHANNEL_POSITION_REAR_CENTER] = { SPA_AUDIO_CHANNEL_RC, "rear-center", },
79 	[CHANNEL_POSITION_REAR_LEFT] = { SPA_AUDIO_CHANNEL_RL, "rear-left", },
80 	[CHANNEL_POSITION_REAR_RIGHT] = { SPA_AUDIO_CHANNEL_RR, "rear-right", },
81 
82 	[CHANNEL_POSITION_LFE] = { SPA_AUDIO_CHANNEL_LFE, "lfe", },
83 	[CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = { SPA_AUDIO_CHANNEL_FLC, "front-left-of-center", },
84 	[CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = { SPA_AUDIO_CHANNEL_FRC, "front-right-of-center", },
85 
86 	[CHANNEL_POSITION_SIDE_LEFT] = { SPA_AUDIO_CHANNEL_SL, "side-left", },
87 	[CHANNEL_POSITION_SIDE_RIGHT] = { SPA_AUDIO_CHANNEL_SR, "side-right", },
88 
89 	[CHANNEL_POSITION_AUX0] = { SPA_AUDIO_CHANNEL_AUX0, "aux0", },
90 	[CHANNEL_POSITION_AUX1] = { SPA_AUDIO_CHANNEL_AUX1, "aux1", },
91 	[CHANNEL_POSITION_AUX2] = { SPA_AUDIO_CHANNEL_AUX2, "aux2", },
92 	[CHANNEL_POSITION_AUX3] = { SPA_AUDIO_CHANNEL_AUX3, "aux3", },
93 	[CHANNEL_POSITION_AUX4] = { SPA_AUDIO_CHANNEL_AUX4, "aux4", },
94 	[CHANNEL_POSITION_AUX5] = { SPA_AUDIO_CHANNEL_AUX5, "aux5", },
95 	[CHANNEL_POSITION_AUX6] = { SPA_AUDIO_CHANNEL_AUX6, "aux6", },
96 	[CHANNEL_POSITION_AUX7] = { SPA_AUDIO_CHANNEL_AUX7, "aux7", },
97 	[CHANNEL_POSITION_AUX8] = { SPA_AUDIO_CHANNEL_AUX8, "aux8", },
98 	[CHANNEL_POSITION_AUX9] = { SPA_AUDIO_CHANNEL_AUX9, "aux9", },
99 	[CHANNEL_POSITION_AUX10] = { SPA_AUDIO_CHANNEL_AUX10, "aux10", },
100 	[CHANNEL_POSITION_AUX11] = { SPA_AUDIO_CHANNEL_AUX11, "aux11", },
101 	[CHANNEL_POSITION_AUX12] = { SPA_AUDIO_CHANNEL_AUX12, "aux12", },
102 	[CHANNEL_POSITION_AUX13] = { SPA_AUDIO_CHANNEL_AUX13, "aux13", },
103 	[CHANNEL_POSITION_AUX14] = { SPA_AUDIO_CHANNEL_AUX14, "aux14", },
104 	[CHANNEL_POSITION_AUX15] = { SPA_AUDIO_CHANNEL_AUX15, "aux15", },
105 	[CHANNEL_POSITION_AUX16] = { SPA_AUDIO_CHANNEL_AUX16, "aux16", },
106 	[CHANNEL_POSITION_AUX17] = { SPA_AUDIO_CHANNEL_AUX17, "aux17", },
107 	[CHANNEL_POSITION_AUX18] = { SPA_AUDIO_CHANNEL_AUX18, "aux18", },
108 	[CHANNEL_POSITION_AUX19] = { SPA_AUDIO_CHANNEL_AUX19, "aux19", },
109 	[CHANNEL_POSITION_AUX20] = { SPA_AUDIO_CHANNEL_AUX20, "aux20", },
110 	[CHANNEL_POSITION_AUX21] = { SPA_AUDIO_CHANNEL_AUX21, "aux21", },
111 	[CHANNEL_POSITION_AUX22] = { SPA_AUDIO_CHANNEL_AUX22, "aux22", },
112 	[CHANNEL_POSITION_AUX23] = { SPA_AUDIO_CHANNEL_AUX23, "aux23", },
113 	[CHANNEL_POSITION_AUX24] = { SPA_AUDIO_CHANNEL_AUX24, "aux24", },
114 	[CHANNEL_POSITION_AUX25] = { SPA_AUDIO_CHANNEL_AUX25, "aux25", },
115 	[CHANNEL_POSITION_AUX26] = { SPA_AUDIO_CHANNEL_AUX26, "aux26", },
116 	[CHANNEL_POSITION_AUX27] = { SPA_AUDIO_CHANNEL_AUX27, "aux27", },
117 	[CHANNEL_POSITION_AUX28] = { SPA_AUDIO_CHANNEL_AUX28, "aux28", },
118 	[CHANNEL_POSITION_AUX29] = { SPA_AUDIO_CHANNEL_AUX29, "aux29", },
119 	[CHANNEL_POSITION_AUX30] = { SPA_AUDIO_CHANNEL_AUX30, "aux30", },
120 	[CHANNEL_POSITION_AUX31] = { SPA_AUDIO_CHANNEL_AUX31, "aux31", },
121 
122 	[CHANNEL_POSITION_TOP_CENTER] = { SPA_AUDIO_CHANNEL_TC, "top-center", },
123 
124 	[CHANNEL_POSITION_TOP_FRONT_LEFT] = { SPA_AUDIO_CHANNEL_TFL, "top-front-left", },
125 	[CHANNEL_POSITION_TOP_FRONT_RIGHT] = { SPA_AUDIO_CHANNEL_TFR, "top-front-right", },
126 	[CHANNEL_POSITION_TOP_FRONT_CENTER] = { SPA_AUDIO_CHANNEL_TFC, "top-front-center", },
127 
128 	[CHANNEL_POSITION_TOP_REAR_LEFT] = { SPA_AUDIO_CHANNEL_TRL, "top-rear-left", },
129 	[CHANNEL_POSITION_TOP_REAR_RIGHT] = { SPA_AUDIO_CHANNEL_TRR, "top-rear-right", },
130 	[CHANNEL_POSITION_TOP_REAR_CENTER] = { SPA_AUDIO_CHANNEL_TRC, "top-rear-center", },
131 };
132 
format_pa2id(enum sample_format format)133 uint32_t format_pa2id(enum sample_format format)
134 {
135 	if (format < 0 || format >= SAMPLE_MAX)
136 		return SPA_AUDIO_FORMAT_UNKNOWN;
137 	return audio_formats[format].id;
138 }
139 
format_id2name(uint32_t format)140 const char *format_id2name(uint32_t format)
141 {
142 	int i;
143 	for (i = 0; spa_type_audio_format[i].name; i++) {
144 		if (spa_type_audio_format[i].type == format)
145 			return spa_debug_type_short_name(spa_type_audio_format[i].name);
146 	}
147 	return "UNKNOWN";
148 }
149 
format_name2id(const char * name)150 uint32_t format_name2id(const char *name)
151 {
152 	int i;
153 	for (i = 0; spa_type_audio_format[i].name; i++) {
154 		if (spa_streq(name, spa_debug_type_short_name(spa_type_audio_format[i].name)))
155 			return spa_type_audio_format[i].type;
156 	}
157 	return SPA_AUDIO_CHANNEL_UNKNOWN;
158 }
159 
format_paname2id(const char * name,size_t size)160 uint32_t format_paname2id(const char *name, size_t size)
161 {
162 	size_t i;
163 	for (i = 0; i < SPA_N_ELEMENTS(audio_formats); i++) {
164 		if (audio_formats[i].name != NULL &&
165 		    strncmp(name, audio_formats[i].name, size) == 0)
166 			return audio_formats[i].id;
167 	}
168 	return SPA_AUDIO_FORMAT_UNKNOWN;
169 }
170 
format_id2pa(uint32_t id)171 enum sample_format format_id2pa(uint32_t id)
172 {
173 	size_t i;
174 	for (i = 0; i < SPA_N_ELEMENTS(audio_formats); i++) {
175 		if (id == audio_formats[i].id)
176 			return audio_formats[i].pa;
177 	}
178 	return SAMPLE_INVALID;
179 }
180 
format_id2paname(uint32_t id)181 const char *format_id2paname(uint32_t id)
182 {
183 	size_t i;
184 	for (i = 0; i < SPA_N_ELEMENTS(audio_formats); i++) {
185 		if (id == audio_formats[i].id &&
186 		    audio_formats[i].name != NULL)
187 			return audio_formats[i].name;
188 	}
189 	return "invalid";
190 }
191 
sample_spec_frame_size(const struct sample_spec * ss)192 uint32_t sample_spec_frame_size(const struct sample_spec *ss)
193 {
194 	switch (ss->format) {
195 	case SPA_AUDIO_FORMAT_U8:
196 	case SPA_AUDIO_FORMAT_ULAW:
197 	case SPA_AUDIO_FORMAT_ALAW:
198 		return ss->channels;
199 	case SPA_AUDIO_FORMAT_S16_LE:
200 	case SPA_AUDIO_FORMAT_S16_BE:
201 	case SPA_AUDIO_FORMAT_S16P:
202 		return 2 * ss->channels;
203 	case SPA_AUDIO_FORMAT_S24_LE:
204 	case SPA_AUDIO_FORMAT_S24_BE:
205 	case SPA_AUDIO_FORMAT_S24P:
206 		return 3 * ss->channels;
207 	case SPA_AUDIO_FORMAT_F32_LE:
208 	case SPA_AUDIO_FORMAT_F32_BE:
209 	case SPA_AUDIO_FORMAT_F32P:
210 	case SPA_AUDIO_FORMAT_S32_LE:
211 	case SPA_AUDIO_FORMAT_S32_BE:
212 	case SPA_AUDIO_FORMAT_S32P:
213 	case SPA_AUDIO_FORMAT_S24_32_LE:
214 	case SPA_AUDIO_FORMAT_S24_32_BE:
215 	case SPA_AUDIO_FORMAT_S24_32P:
216 		return 4 * ss->channels;
217 	default:
218 		return 0;
219 	}
220 }
221 
sample_spec_valid(const struct sample_spec * ss)222 bool sample_spec_valid(const struct sample_spec *ss)
223 {
224 	return (sample_spec_frame_size(ss) > 0 &&
225 	    ss->rate > 0 && ss->rate <= RATE_MAX &&
226 	    ss->channels > 0 && ss->channels <= CHANNELS_MAX);
227 }
228 
channel_pa2id(enum channel_position channel)229 uint32_t channel_pa2id(enum channel_position channel)
230 {
231 	if (channel < 0 || (size_t)channel >= SPA_N_ELEMENTS(audio_channels))
232 		return SPA_AUDIO_CHANNEL_UNKNOWN;
233 
234 	return audio_channels[channel].channel;
235 }
236 
channel_id2name(uint32_t channel)237 const char *channel_id2name(uint32_t channel)
238 {
239 	int i;
240 	for (i = 0; spa_type_audio_channel[i].name; i++) {
241 		if (spa_type_audio_channel[i].type == channel)
242 			return spa_debug_type_short_name(spa_type_audio_channel[i].name);
243 	}
244 	return "UNK";
245 }
246 
channel_name2id(const char * name)247 uint32_t channel_name2id(const char *name)
248 {
249 	int i;
250 	for (i = 0; spa_type_audio_channel[i].name; i++) {
251 		if (strcmp(name, spa_debug_type_short_name(spa_type_audio_channel[i].name)) == 0)
252 			return spa_type_audio_channel[i].type;
253 	}
254 	return SPA_AUDIO_CHANNEL_UNKNOWN;
255 }
256 
channel_id2pa(uint32_t id,uint32_t * aux)257 enum channel_position channel_id2pa(uint32_t id, uint32_t *aux)
258 {
259 	size_t i;
260 	for (i = 0; i < SPA_N_ELEMENTS(audio_channels); i++) {
261 		if (id == audio_channels[i].channel)
262 			return i;
263 	}
264 	return CHANNEL_POSITION_AUX0 + ((*aux)++ & 31);
265 }
266 
channel_id2paname(uint32_t id,uint32_t * aux)267 const char *channel_id2paname(uint32_t id, uint32_t *aux)
268 {
269 	size_t i;
270 	for (i = 0; i < SPA_N_ELEMENTS(audio_channels); i++) {
271 		if (id == audio_channels[i].channel &&
272 		    audio_channels[i].name != NULL)
273 			return audio_channels[i].name;
274 	}
275 	return audio_channels[CHANNEL_POSITION_AUX0 + ((*aux)++ & 31)].name;
276 }
277 
channel_paname2id(const char * name,size_t size)278 uint32_t channel_paname2id(const char *name, size_t size)
279 {
280 	size_t i;
281 	for (i = 0; i < SPA_N_ELEMENTS(audio_channels); i++) {
282 		if (strncmp(name, audio_channels[i].name, size) == 0)
283 			return audio_channels[i].channel;
284 	}
285 	return SPA_AUDIO_CHANNEL_UNKNOWN;
286 }
287 
288 
channel_map_to_positions(const struct channel_map * map,uint32_t * pos)289 void channel_map_to_positions(const struct channel_map *map, uint32_t *pos)
290 {
291 	int i;
292 	for (i = 0; i < map->channels; i++)
293 		pos[i] = map->map[i];
294 }
295 
channel_map_parse(const char * str,struct channel_map * map)296 void channel_map_parse(const char *str, struct channel_map *map)
297 {
298 	const char *p = str;
299 	size_t len;
300 
301 	if (spa_streq(p, "stereo")) {
302 		*map = (struct channel_map) {
303 			.channels = 2,
304 			.map[0] = SPA_AUDIO_CHANNEL_FL,
305 			.map[1] = SPA_AUDIO_CHANNEL_FR,
306 		};
307 	} else if (spa_streq(p, "surround-21")) {
308 		*map = (struct channel_map) {
309 			.channels = 3,
310 			.map[0] = SPA_AUDIO_CHANNEL_FL,
311 			.map[1] = SPA_AUDIO_CHANNEL_FR,
312 			.map[2] = SPA_AUDIO_CHANNEL_LFE,
313 		};
314 	} else if (spa_streq(p, "surround-40")) {
315 		*map = (struct channel_map) {
316 			.channels = 4,
317 			.map[0] = SPA_AUDIO_CHANNEL_FL,
318 			.map[1] = SPA_AUDIO_CHANNEL_FR,
319 			.map[2] = SPA_AUDIO_CHANNEL_RL,
320 			.map[3] = SPA_AUDIO_CHANNEL_RR,
321 		};
322 	} else if (spa_streq(p, "surround-41")) {
323 		*map = (struct channel_map) {
324 			.channels = 5,
325 			.map[0] = SPA_AUDIO_CHANNEL_FL,
326 			.map[1] = SPA_AUDIO_CHANNEL_FR,
327 			.map[2] = SPA_AUDIO_CHANNEL_RL,
328 			.map[3] = SPA_AUDIO_CHANNEL_RR,
329 			.map[4] = SPA_AUDIO_CHANNEL_LFE,
330 		};
331 	} else if (spa_streq(p, "surround-50")) {
332 		*map = (struct channel_map) {
333 			.channels = 5,
334 			.map[0] = SPA_AUDIO_CHANNEL_FL,
335 			.map[1] = SPA_AUDIO_CHANNEL_FR,
336 			.map[2] = SPA_AUDIO_CHANNEL_RL,
337 			.map[3] = SPA_AUDIO_CHANNEL_RR,
338 			.map[4] = SPA_AUDIO_CHANNEL_FC,
339 		};
340 	} else if (spa_streq(p, "surround-51")) {
341 		*map = (struct channel_map) {
342 			.channels = 6,
343 			.map[0] = SPA_AUDIO_CHANNEL_FL,
344 			.map[1] = SPA_AUDIO_CHANNEL_FR,
345 			.map[2] = SPA_AUDIO_CHANNEL_RL,
346 			.map[3] = SPA_AUDIO_CHANNEL_RR,
347 			.map[4] = SPA_AUDIO_CHANNEL_FC,
348 			.map[5] = SPA_AUDIO_CHANNEL_LFE,
349 		};
350 	} else if (spa_streq(p, "surround-71")) {
351 		*map = (struct channel_map) {
352 			.channels = 8,
353 			.map[0] = SPA_AUDIO_CHANNEL_FL,
354 			.map[1] = SPA_AUDIO_CHANNEL_FR,
355 			.map[2] = SPA_AUDIO_CHANNEL_RL,
356 			.map[3] = SPA_AUDIO_CHANNEL_RR,
357 			.map[4] = SPA_AUDIO_CHANNEL_FC,
358 			.map[5] = SPA_AUDIO_CHANNEL_LFE,
359 			.map[6] = SPA_AUDIO_CHANNEL_SL,
360 			.map[7] = SPA_AUDIO_CHANNEL_SR,
361 		};
362 	} else {
363 		map->channels = 0;
364 		while (*p && map->channels < SPA_AUDIO_MAX_CHANNELS) {
365 			if ((len = strcspn(p, ",")) == 0)
366 				break;
367 			map->map[map->channels++] = channel_paname2id(p, len);
368 			p += len + strspn(p+len, ",");
369 		}
370 	}
371 }
372 
channel_map_valid(const struct channel_map * map)373 bool channel_map_valid(const struct channel_map *map)
374 {
375 	uint8_t i;
376 	uint32_t aux = 0;
377 	if (map->channels == 0 || map->channels > CHANNELS_MAX)
378 		return false;
379 	for (i = 0; i < map->channels; i++)
380 		if (channel_id2pa(map->map[i], &aux) >= CHANNEL_POSITION_MAX)
381 			return false;
382 	return true;
383 }
384 
385 struct encoding_info {
386 	const char *name;
387 	uint32_t id;
388 };
389 
390 static const struct encoding_info encoding_names[] = {
391 	[ENCODING_ANY] = { "ANY", 0 },
392 	[ENCODING_PCM] = { "PCM", SPA_AUDIO_IEC958_CODEC_PCM },
393 	[ENCODING_AC3_IEC61937] = { "AC3-IEC61937", SPA_AUDIO_IEC958_CODEC_AC3 },
394 	[ENCODING_EAC3_IEC61937] = { "EAC3-IEC61937", SPA_AUDIO_IEC958_CODEC_EAC3 },
395 	[ENCODING_MPEG_IEC61937] = { "MPEG-IEC61937", SPA_AUDIO_IEC958_CODEC_MPEG },
396 	[ENCODING_DTS_IEC61937] = { "DTS-IEC61937", SPA_AUDIO_IEC958_CODEC_DTS },
397 	[ENCODING_MPEG2_AAC_IEC61937] = { "MPEG2-AAC-IEC61937", SPA_AUDIO_IEC958_CODEC_MPEG2_AAC },
398 	[ENCODING_TRUEHD_IEC61937] = { "TRUEHD-IEC61937", SPA_AUDIO_IEC958_CODEC_TRUEHD },
399 	[ENCODING_DTSHD_IEC61937] = { "DTSHD-IEC61937", SPA_AUDIO_IEC958_CODEC_DTSHD },
400 };
401 
format_encoding2name(enum encoding enc)402 const char *format_encoding2name(enum encoding enc)
403 {
404 	if (enc >= 0 && enc < (int)SPA_N_ELEMENTS(encoding_names) &&
405 	    encoding_names[enc].name != NULL)
406 		return encoding_names[enc].name;
407 	return "INVALID";
408 }
format_encoding2id(enum encoding enc)409 uint32_t format_encoding2id(enum encoding enc)
410 {
411 	if (enc >= 0 && enc < (int)SPA_N_ELEMENTS(encoding_names) &&
412 	    encoding_names[enc].name != NULL)
413 		return encoding_names[enc].id;
414 	return SPA_ID_INVALID;
415 }
416 
format_encoding_from_id(uint32_t id)417 static enum encoding format_encoding_from_id(uint32_t id)
418 {
419 	int i;
420 	for (i = 0; i < (int)SPA_N_ELEMENTS(encoding_names); i++) {
421 		if (encoding_names[i].id == id)
422 			return i;
423 	}
424 	return ENCODING_ANY;
425 }
426 
427 static inline int
audio_raw_parse_opt(const struct spa_pod * format,struct spa_audio_info_raw * info)428 audio_raw_parse_opt(const struct spa_pod *format, struct spa_audio_info_raw *info)
429 {
430 	struct spa_pod *position = NULL;
431 	int res;
432 	info->flags = 0;
433 	res = spa_pod_parse_object(format,
434 			SPA_TYPE_OBJECT_Format, NULL,
435 			SPA_FORMAT_AUDIO_format,        SPA_POD_OPT_Id(&info->format),
436 			SPA_FORMAT_AUDIO_rate,          SPA_POD_OPT_Int(&info->rate),
437 			SPA_FORMAT_AUDIO_channels,      SPA_POD_OPT_Int(&info->channels),
438 			SPA_FORMAT_AUDIO_position,      SPA_POD_OPT_Pod(&position));
439 	if (position == NULL ||
440 	    !spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS))
441 		SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
442 
443 	return res;
444 }
445 
format_parse_param(const struct spa_pod * param,struct sample_spec * ss,struct channel_map * map,const struct sample_spec * def_ss,const struct channel_map * def_map)446 int format_parse_param(const struct spa_pod *param, struct sample_spec *ss, struct channel_map *map,
447 		const struct sample_spec *def_ss, const struct channel_map *def_map)
448 {
449 	struct spa_audio_info info = { 0 };
450 	uint32_t i;
451 
452 	if (spa_format_parse(param, &info.media_type, &info.media_subtype) < 0)
453 		return -ENOTSUP;
454 
455 	if (info.media_type != SPA_MEDIA_TYPE_audio)
456                 return -ENOTSUP;
457 
458 	switch (info.media_subtype) {
459 	case SPA_MEDIA_SUBTYPE_raw:
460 		if (def_ss != NULL) {
461 			if (ss != NULL)
462 				*ss = *def_ss;
463 			if (audio_raw_parse_opt(param, &info.info.raw) < 0)
464 		                return -ENOTSUP;
465 		} else {
466 			if (spa_format_audio_raw_parse(param, &info.info.raw) < 0)
467 		                return -ENOTSUP;
468 		}
469 		break;
470 	case SPA_MEDIA_SUBTYPE_iec958:
471 	{
472 		struct spa_audio_info_iec958 iec;
473 
474 		if (spa_format_audio_iec958_parse(param, &iec) < 0)
475 			return -ENOTSUP;
476 
477 		info.info.raw.format = SPA_AUDIO_FORMAT_S16;
478 		info.info.raw.channels = 2;
479 		info.info.raw.rate = iec.rate;
480 		info.info.raw.position[0] = SPA_AUDIO_CHANNEL_FL;
481 		info.info.raw.position[1] = SPA_AUDIO_CHANNEL_FR;
482 		break;
483 	}
484 	default:
485 		return -ENOTSUP;
486         }
487 	if (ss) {
488 		if (info.info.raw.format)
489 		        ss->format = info.info.raw.format;
490 		if (info.info.raw.rate)
491 		        ss->rate = info.info.raw.rate;
492 		if (info.info.raw.channels)
493 		        ss->channels = info.info.raw.channels;
494 	}
495 	if (map) {
496 		map->channels = info.info.raw.channels;
497 		for (i = 0; i < map->channels; i++)
498 			map->map[i] = info.info.raw.position[i];
499 	}
500 	return 0;
501 }
502 
format_build_param(struct spa_pod_builder * b,uint32_t id,const struct sample_spec * spec,const struct channel_map * map)503 const struct spa_pod *format_build_param(struct spa_pod_builder *b, uint32_t id,
504 		const struct sample_spec *spec, const struct channel_map *map)
505 {
506 	struct spa_pod_frame f;
507 
508 	spa_pod_builder_push_object(b, &f, SPA_TYPE_OBJECT_Format, id);
509 	spa_pod_builder_add(b,
510 			SPA_FORMAT_mediaType,		SPA_POD_Id(SPA_MEDIA_TYPE_audio),
511 			SPA_FORMAT_mediaSubtype,	SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
512 			0);
513 	if (spec->format != SPA_AUDIO_FORMAT_UNKNOWN)
514 		spa_pod_builder_add(b,
515 			SPA_FORMAT_AUDIO_format,        SPA_POD_Id(spec->format), 0);
516 	else {
517 		spa_pod_builder_add(b,
518 			SPA_FORMAT_AUDIO_format,	SPA_POD_CHOICE_ENUM_Id(14,
519 								SPA_AUDIO_FORMAT_F32,
520 								SPA_AUDIO_FORMAT_F32,
521 								SPA_AUDIO_FORMAT_F32_OE,
522 								SPA_AUDIO_FORMAT_S32,
523 								SPA_AUDIO_FORMAT_S32_OE,
524 								SPA_AUDIO_FORMAT_S24_32,
525 								SPA_AUDIO_FORMAT_S24_32_OE,
526 								SPA_AUDIO_FORMAT_S24,
527 								SPA_AUDIO_FORMAT_S24_OE,
528 								SPA_AUDIO_FORMAT_S16,
529 								SPA_AUDIO_FORMAT_S16_OE,
530 								SPA_AUDIO_FORMAT_ULAW,
531 								SPA_AUDIO_FORMAT_ALAW,
532 								SPA_AUDIO_FORMAT_U8),
533 			0);
534 
535 	}
536 
537         if (spec->rate != 0)
538 		spa_pod_builder_add(b,
539 			SPA_FORMAT_AUDIO_rate,          SPA_POD_Int(spec->rate), 0);
540 	if (spec->channels != 0) {
541 		spa_pod_builder_add(b,
542 			SPA_FORMAT_AUDIO_channels,      SPA_POD_Int(spec->channels), 0);
543 
544 		if (map && map->channels == spec->channels) {
545 			uint32_t positions[SPA_AUDIO_MAX_CHANNELS];
546 			channel_map_to_positions(map, positions);
547                         spa_pod_builder_add(b, SPA_FORMAT_AUDIO_position,
548                                 SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id,
549                                         spec->channels, positions), 0);
550                 }
551         }
552         return spa_pod_builder_pop(b, &f);
553 }
554 
format_info_from_spec(struct format_info * info,const struct sample_spec * ss,const struct channel_map * map)555 int format_info_from_spec(struct format_info *info, const struct sample_spec *ss,
556 			  const struct channel_map *map)
557 {
558 	spa_zero(*info);
559 	info->encoding = ENCODING_PCM;
560 	if ((info->props = pw_properties_new(NULL, NULL)) == NULL)
561 		return -errno;
562 
563 	pw_properties_setf(info->props, "format.sample_format", "\"%s\"",
564 			format_id2paname(ss->format));
565 	pw_properties_setf(info->props, "format.rate", "%d", ss->rate);
566 	pw_properties_setf(info->props, "format.channels", "%d", ss->channels);
567 	if (map && map->channels == ss->channels) {
568 		char chmap[1024] = "";
569 		int i, o, r;
570 		uint32_t aux = 0;
571 
572 		for (i = 0, o = 0; i < map->channels; i++) {
573 			r = snprintf(chmap+o, sizeof(chmap)-o, "%s%s", i == 0 ? "" : ",",
574 					channel_id2paname(map->map[i], &aux));
575 			if (r < 0 || o + r >= (int)sizeof(chmap))
576 				return -ENOSPC;
577 			o += r;
578 		}
579 		pw_properties_setf(info->props, "format.channel_map", "\"%s\"", chmap);
580 	}
581 	return 0;
582 }
583 
add_int(struct format_info * info,const char * k,struct spa_pod * param,uint32_t key)584 static int add_int(struct format_info *info, const char *k, struct spa_pod *param,
585 		uint32_t key)
586 {
587 	const struct spa_pod_prop *prop;
588 	struct spa_pod *val;
589 	uint32_t i, n_values, choice;
590 	int32_t *values;
591 
592 	prop = spa_pod_find_prop(param, NULL, key);
593 	if (prop == NULL)
594 		return -ENOENT;
595 
596 	val = spa_pod_get_values(&prop->value, &n_values, &choice);
597 	if (val->type != SPA_TYPE_Int)
598 		return -ENOTSUP;
599 
600 	values = SPA_POD_BODY(val);
601 
602 	switch (choice) {
603 	case SPA_CHOICE_None:
604 		pw_properties_setf(info->props, k, "%d", values[0]);
605 		break;
606 	case SPA_CHOICE_Range:
607 		pw_properties_setf(info->props, k, "{ \"min\": %d, \"max\": %d }",
608 				values[1], values[2]);
609 		break;
610 	case SPA_CHOICE_Enum:
611 	{
612 		char *ptr;
613 		size_t size;
614 		FILE *f;
615 
616 		f = open_memstream(&ptr, &size);
617 		fprintf(f, "[");
618 		for (i = 1; i < n_values; i++)
619 			fprintf(f, "%s %d", i == 1 ? "" : ",", values[i]);
620 		fprintf(f, " ]");
621 		fclose(f);
622 
623 		pw_properties_set(info->props, k, ptr);
624 		free(ptr);
625 		break;
626 	}
627 	default:
628 		return -ENOTSUP;
629 	}
630 	return 0;
631 }
632 
format_info_pcm_from_param(struct format_info * info,struct spa_pod * param,uint32_t index)633 static int format_info_pcm_from_param(struct format_info *info, struct spa_pod *param, uint32_t index)
634 {
635 	if (index > 0)
636 		return -ENOENT;
637 
638 	info->encoding = ENCODING_PCM;
639 	/* don't add params here yet, pulseaudio doesn't do that either */
640 	return 0;
641 }
642 
format_info_iec958_from_param(struct format_info * info,struct spa_pod * param,uint32_t index)643 static int format_info_iec958_from_param(struct format_info *info, struct spa_pod *param, uint32_t index)
644 {
645 	const struct spa_pod_prop *prop;
646 	struct spa_pod *val;
647 	uint32_t n_values, *values, choice;
648 
649 	prop = spa_pod_find_prop(param, NULL, SPA_FORMAT_AUDIO_iec958Codec);
650 	if (prop == NULL)
651 		return -ENOENT;
652 
653 	val = spa_pod_get_values(&prop->value, &n_values, &choice);
654 	if (val->type != SPA_TYPE_Id)
655 		return -ENOTSUP;
656 
657 	if (index >= n_values)
658 		return -ENOENT;
659 
660 	values = SPA_POD_BODY(val);
661 
662 	switch (choice) {
663 	case SPA_CHOICE_None:
664 		info->encoding = format_encoding_from_id(values[index]);
665 		break;
666 	case SPA_CHOICE_Enum:
667 		info->encoding = format_encoding_from_id(values[index+1]);
668 		break;
669 	default:
670 		return -ENOTSUP;
671 	}
672 
673 	if ((info->props = pw_properties_new(NULL, NULL)) == NULL)
674 		return -errno;
675 
676 	add_int(info, "format.rate", param, SPA_FORMAT_AUDIO_rate);
677 
678 	return 0;
679 }
680 
format_info_from_param(struct format_info * info,struct spa_pod * param,uint32_t index)681 int format_info_from_param(struct format_info *info, struct spa_pod *param, uint32_t index)
682 {
683 	uint32_t media_type, media_subtype;
684 	int res;
685 
686 	if (spa_format_parse(param, &media_type, &media_subtype) < 0)
687 		return -ENOTSUP;
688 
689 	if (media_type != SPA_MEDIA_TYPE_audio)
690                 return -ENOTSUP;
691 
692 	switch(media_subtype) {
693 	case SPA_MEDIA_SUBTYPE_raw:
694 		res = format_info_pcm_from_param(info, param, index);
695 		break;
696 	case SPA_MEDIA_SUBTYPE_iec958:
697 		res = format_info_iec958_from_param(info, param, index);
698 		break;
699 	default:
700 		return -ENOTSUP;
701 	}
702 	return res;
703 }
704 
format_info_get_format(const struct format_info * info)705 static uint32_t format_info_get_format(const struct format_info *info)
706 {
707 	const char *str, *val;
708 	struct spa_json it[2];
709 	int len;
710 
711 	if ((str = pw_properties_get(info->props, "format.sample_format")) == NULL)
712 		return SPA_AUDIO_FORMAT_UNKNOWN;
713 
714 	spa_json_init(&it[0], str, strlen(str));
715 	if ((len = spa_json_next(&it[0], &val)) <= 0)
716 		return SPA_AUDIO_FORMAT_UNKNOWN;
717 
718 	if (spa_json_is_string(val, len))
719 		return format_paname2id(val+1, len-2);
720 
721 	return SPA_AUDIO_FORMAT_UNKNOWN;
722 }
723 
format_info_get_rate(const struct format_info * info)724 static int format_info_get_rate(const struct format_info *info)
725 {
726 	const char *str, *val;
727 	struct spa_json it[2];
728 	int len, v;
729 
730 	if ((str = pw_properties_get(info->props, "format.rate")) == NULL)
731 		return -ENOENT;
732 
733 	spa_json_init(&it[0], str, strlen(str));
734 	if ((len = spa_json_next(&it[0], &val)) <= 0)
735 		return -EINVAL;
736 	if (spa_json_is_int(val, len)) {
737 		if (spa_json_parse_int(val, len, &v) <= 0)
738 			return -EINVAL;
739 		return v;
740 	}
741 	return -ENOTSUP;
742 }
743 
format_info_to_spec(const struct format_info * info,struct sample_spec * ss,struct channel_map * map)744 int format_info_to_spec(const struct format_info *info, struct sample_spec *ss,
745 			  struct channel_map *map)
746 {
747 	const char *str, *val;
748 	struct spa_json it[2];
749 	float f;
750 	int res, len;
751 
752 	spa_zero(*ss);
753 	spa_zero(*map);
754 
755 	if (info->encoding != ENCODING_PCM)
756 		return -ENOTSUP;
757 	if (info->props == NULL)
758 		return -ENOENT;
759 
760 	if ((ss->format = format_info_get_format(info)) == SPA_AUDIO_FORMAT_UNKNOWN)
761 		return -ENOTSUP;
762 
763 	if ((res = format_info_get_rate(info)) < 0)
764 		return res;
765 	ss->rate = res;
766 
767 	if ((str = pw_properties_get(info->props, "format.channels")) == NULL)
768 		return -ENOENT;
769 
770 	spa_json_init(&it[0], str, strlen(str));
771 	if ((len = spa_json_next(&it[0], &val)) <= 0)
772 		return -EINVAL;
773 	if (spa_json_is_float(val, len)) {
774 		if (spa_json_parse_float(val, len, &f) <= 0)
775 			return -EINVAL;
776 		ss->channels = f;
777 	} else if (spa_json_is_array(val, len)) {
778 		return -ENOTSUP;
779 	} else if (spa_json_is_object(val, len)) {
780 		return -ENOTSUP;
781 	} else
782 		return -ENOTSUP;
783 
784 	if ((str = pw_properties_get(info->props, "format.channel_map")) != NULL) {
785 		spa_json_init(&it[0], str, strlen(str));
786 		if ((len = spa_json_next(&it[0], &val)) <= 0)
787 			return -EINVAL;
788 		if (!spa_json_is_string(val, len))
789 			return -EINVAL;
790 		while ((*str == '\"' || *str == ',') &&
791 		    (len = strcspn(++str, "\",")) > 0) {
792 			map->map[map->channels++] = channel_paname2id(str, len);
793 			str += len;
794 		}
795 	}
796 	return 0;
797 }
798 
format_info_build_param(struct spa_pod_builder * b,uint32_t id,const struct format_info * info,uint32_t * rate)799 const struct spa_pod *format_info_build_param(struct spa_pod_builder *b, uint32_t id,
800 		const struct format_info *info, uint32_t *rate)
801 {
802 	struct sample_spec ss;
803 	struct channel_map map;
804 	const struct spa_pod *param = NULL;
805 	int res;
806 
807 	switch (info->encoding) {
808 	case ENCODING_PCM:
809 		if ((res = format_info_to_spec(info, &ss, &map)) < 0) {
810 			errno = -res;
811 			return NULL;
812 		}
813 		*rate = ss.rate;
814 		param = format_build_param(b, id, &ss, &map);
815 		break;
816 	case ENCODING_AC3_IEC61937:
817 	case ENCODING_EAC3_IEC61937:
818 	case ENCODING_MPEG_IEC61937:
819 	case ENCODING_DTS_IEC61937:
820 	case ENCODING_MPEG2_AAC_IEC61937:
821 	case ENCODING_TRUEHD_IEC61937:
822 	case ENCODING_DTSHD_IEC61937:
823 	{
824 		struct spa_audio_info_iec958 i = { 0 };
825 		i.codec = format_encoding2id(info->encoding);
826 		if ((res = format_info_get_rate(info)) <= 0) {
827 			errno = -res;
828 			return NULL;
829 		}
830 		i.rate = res;
831 		param = spa_format_audio_iec958_build(b, id, &i);
832 		break;
833 	}
834 	default:
835 		errno = ENOTSUP;
836 		break;
837 	}
838 	return param;
839 }
840