• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2.1 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this library; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <math.h>
29 #include "gstsbcutil.h"
30 
31 /*
32  * Selects one rate from a list of possible rates
33  * TODO - use a better approach to this (it is selecting the last element)
34  */
gst_sbc_select_rate_from_list(const GValue * value)35 gint gst_sbc_select_rate_from_list(const GValue *value)
36 {
37 	guint size = gst_value_list_get_size(value);
38 	return g_value_get_int(gst_value_list_get_value(value, size-1));
39 }
40 
41 /*
42  * Selects one number of channels option from a range of possible numbers
43  * TODO - use a better approach to this (it is selecting the maximum value)
44  */
gst_sbc_select_channels_from_range(const GValue * value)45 gint gst_sbc_select_channels_from_range(const GValue *value)
46 {
47 	return gst_value_get_int_range_max(value);
48 }
49 
50 /*
51  * Selects one number of blocks from a list of possible blocks
52  * TODO - use a better approach to this (it is selecting the last element)
53  */
gst_sbc_select_blocks_from_list(const GValue * value)54 gint gst_sbc_select_blocks_from_list(const GValue *value)
55 {
56 	guint size = gst_value_list_get_size(value);
57 	return g_value_get_int(gst_value_list_get_value(value, size-1));
58 }
59 
60 /*
61  * Selects one number of subbands from a list
62  * TODO - use a better approach to this (it is selecting the last element)
63  */
gst_sbc_select_subbands_from_list(const GValue * value)64 gint gst_sbc_select_subbands_from_list(const GValue *value)
65 {
66 	guint size = gst_value_list_get_size(value);
67 	return g_value_get_int(gst_value_list_get_value(value, size-1));
68 }
69 
70 /*
71  * Selects one bitpool option from a range
72  * TODO - use a better approach to this (it is selecting the maximum value)
73  */
gst_sbc_select_bitpool_from_range(const GValue * value)74 gint gst_sbc_select_bitpool_from_range(const GValue *value)
75 {
76 	return gst_value_get_int_range_max(value);
77 }
78 
79 /*
80  * Selects one allocation mode from the ones on the list
81  * TODO - use a better approach
82  */
gst_sbc_get_allocation_from_list(const GValue * value)83 const gchar *gst_sbc_get_allocation_from_list(const GValue *value)
84 {
85 	guint size = gst_value_list_get_size(value);
86 	return g_value_get_string(gst_value_list_get_value(value, size-1));
87 }
88 
89 /*
90  * Selects one mode from the ones on the list
91  */
gst_sbc_get_mode_from_list(const GValue * list,gint channels)92 const gchar *gst_sbc_get_mode_from_list(const GValue *list, gint channels)
93 {
94 	unsigned int i;
95 	const GValue *value;
96 	const gchar *aux;
97 	gboolean joint, stereo, dual, mono;
98 	guint size = gst_value_list_get_size(list);
99 
100 	joint = stereo = dual = mono = FALSE;
101 
102 	for (i = 0; i < size; i++) {
103 		value = gst_value_list_get_value(list, i);
104 		aux = g_value_get_string(value);
105 		if (strcmp("joint", aux) == 0)
106 			joint = TRUE;
107 		else if (strcmp("stereo", aux) == 0)
108 			stereo = TRUE;
109 		else if (strcmp("dual", aux) == 0)
110 			dual = TRUE;
111 		else if (strcmp("mono", aux) == 0)
112 			mono = TRUE;
113 	}
114 
115 	if (channels == 1 && mono)
116 		return "mono";
117 	else if (channels == 2) {
118 		if (joint)
119 			return "joint";
120 		else if (stereo)
121 			return "stereo";
122 		else if (dual)
123 			return "dual";
124 	}
125 
126 	return NULL;
127 }
128 
gst_sbc_parse_rate_from_sbc(gint frequency)129 gint gst_sbc_parse_rate_from_sbc(gint frequency)
130 {
131 	switch (frequency) {
132 	case SBC_FREQ_16000:
133 		return 16000;
134 	case SBC_FREQ_32000:
135 		return 32000;
136 	case SBC_FREQ_44100:
137 		return 44100;
138 	case SBC_FREQ_48000:
139 		return 48000;
140 	default:
141 		return 0;
142 	}
143 }
144 
gst_sbc_parse_rate_to_sbc(gint rate)145 gint gst_sbc_parse_rate_to_sbc(gint rate)
146 {
147 	switch (rate) {
148 	case 16000:
149 		return SBC_FREQ_16000;
150 	case 32000:
151 		return SBC_FREQ_32000;
152 	case 44100:
153 		return SBC_FREQ_44100;
154 	case 48000:
155 		return SBC_FREQ_48000;
156 	default:
157 		return -1;
158 	}
159 }
160 
gst_sbc_get_channel_number(gint mode)161 gint gst_sbc_get_channel_number(gint mode)
162 {
163 	switch (mode) {
164 	case SBC_MODE_JOINT_STEREO:
165 	case SBC_MODE_STEREO:
166 	case SBC_MODE_DUAL_CHANNEL:
167 		return 2;
168 	case SBC_MODE_MONO:
169 		return 1;
170 	default:
171 		return 0;
172 	}
173 }
174 
gst_sbc_parse_subbands_from_sbc(gint subbands)175 gint gst_sbc_parse_subbands_from_sbc(gint subbands)
176 {
177 	switch (subbands) {
178 	case SBC_SB_4:
179 		return 4;
180 	case SBC_SB_8:
181 		return 8;
182 	default:
183 		return 0;
184 	}
185 }
186 
gst_sbc_parse_subbands_to_sbc(gint subbands)187 gint gst_sbc_parse_subbands_to_sbc(gint subbands)
188 {
189 	switch (subbands) {
190 	case 4:
191 		return SBC_SB_4;
192 	case 8:
193 		return SBC_SB_8;
194 	default:
195 		return -1;
196 	}
197 }
198 
gst_sbc_parse_blocks_from_sbc(gint blocks)199 gint gst_sbc_parse_blocks_from_sbc(gint blocks)
200 {
201 	switch (blocks) {
202 	case SBC_BLK_4:
203 		return 4;
204 	case SBC_BLK_8:
205 		return 8;
206 	case SBC_BLK_12:
207 		return 12;
208 	case SBC_BLK_16:
209 		return 16;
210 	default:
211 		return 0;
212 	}
213 }
214 
gst_sbc_parse_blocks_to_sbc(gint blocks)215 gint gst_sbc_parse_blocks_to_sbc(gint blocks)
216 {
217 	switch (blocks) {
218 	case 4:
219 		return SBC_BLK_4;
220 	case 8:
221 		return SBC_BLK_8;
222 	case 12:
223 		return SBC_BLK_12;
224 	case 16:
225 		return SBC_BLK_16;
226 	default:
227 		return -1;
228 	}
229 }
230 
gst_sbc_parse_mode_from_sbc(gint mode)231 const gchar *gst_sbc_parse_mode_from_sbc(gint mode)
232 {
233 	switch (mode) {
234 	case SBC_MODE_MONO:
235 		return "mono";
236 	case SBC_MODE_DUAL_CHANNEL:
237 		return "dual";
238 	case SBC_MODE_STEREO:
239 		return "stereo";
240 	case SBC_MODE_JOINT_STEREO:
241 	case SBC_MODE_AUTO:
242 		return "joint";
243 	default:
244 		return NULL;
245 	}
246 }
247 
gst_sbc_parse_mode_to_sbc(const gchar * mode)248 gint gst_sbc_parse_mode_to_sbc(const gchar *mode)
249 {
250 	if (g_ascii_strcasecmp(mode, "joint") == 0)
251 		return SBC_MODE_JOINT_STEREO;
252 	else if (g_ascii_strcasecmp(mode, "stereo") == 0)
253 		return SBC_MODE_STEREO;
254 	else if (g_ascii_strcasecmp(mode, "dual") == 0)
255 		return SBC_MODE_DUAL_CHANNEL;
256 	else if (g_ascii_strcasecmp(mode, "mono") == 0)
257 		return SBC_MODE_MONO;
258 	else if (g_ascii_strcasecmp(mode, "auto") == 0)
259 		return SBC_MODE_JOINT_STEREO;
260 	else
261 		return -1;
262 }
263 
gst_sbc_parse_allocation_from_sbc(gint alloc)264 const gchar *gst_sbc_parse_allocation_from_sbc(gint alloc)
265 {
266 	switch (alloc) {
267 	case SBC_AM_LOUDNESS:
268 		return "loudness";
269 	case SBC_AM_SNR:
270 		return "snr";
271 	case SBC_AM_AUTO:
272 		return "loudness";
273 	default:
274 		return NULL;
275 	}
276 }
277 
gst_sbc_parse_allocation_to_sbc(const gchar * allocation)278 gint gst_sbc_parse_allocation_to_sbc(const gchar *allocation)
279 {
280 	if (g_ascii_strcasecmp(allocation, "loudness") == 0)
281 		return SBC_AM_LOUDNESS;
282 	else if (g_ascii_strcasecmp(allocation, "snr") == 0)
283 		return SBC_AM_SNR;
284 	else
285 		return SBC_AM_LOUDNESS;
286 }
287 
gst_sbc_parse_caps_from_sbc(sbc_t * sbc)288 GstCaps *gst_sbc_parse_caps_from_sbc(sbc_t *sbc)
289 {
290 	GstCaps *caps;
291 	const gchar *mode_str;
292 	const gchar *allocation_str;
293 
294 	mode_str = gst_sbc_parse_mode_from_sbc(sbc->mode);
295 	allocation_str = gst_sbc_parse_allocation_from_sbc(sbc->allocation);
296 	caps = gst_caps_new_simple("audio/x-sbc",
297 				"rate", G_TYPE_INT,
298 				gst_sbc_parse_rate_from_sbc(sbc->frequency),
299 				"channels", G_TYPE_INT,
300 				gst_sbc_get_channel_number(sbc->mode),
301 				"mode", G_TYPE_STRING, mode_str,
302 				"subbands", G_TYPE_INT,
303 				gst_sbc_parse_subbands_from_sbc(sbc->subbands),
304 				"blocks", G_TYPE_INT,
305 				gst_sbc_parse_blocks_from_sbc(sbc->blocks),
306 				"allocation", G_TYPE_STRING, allocation_str,
307 				"bitpool", G_TYPE_INT, sbc->bitpool,
308 				NULL);
309 
310 	return caps;
311 }
312 
313 /*
314  * Given a GstCaps, this will return a fixed GstCaps on sucessfull conversion.
315  * If an error occurs, it will return NULL and error_message will contain the
316  * error message.
317  *
318  * error_message must be passed NULL, if an error occurs, the caller has the
319  * ownership of the error_message, it must be freed after use.
320  */
gst_sbc_util_caps_fixate(GstCaps * caps,gchar ** error_message)321 GstCaps *gst_sbc_util_caps_fixate(GstCaps *caps, gchar **error_message)
322 {
323 	GstCaps *result;
324 	GstStructure *structure;
325 	const GValue *value;
326 	gboolean error = FALSE;
327 	gint temp, rate, channels, blocks, subbands, bitpool;
328 	const gchar *allocation = NULL;
329 	const gchar *mode = NULL;
330 
331 	g_assert(*error_message == NULL);
332 
333 	structure = gst_caps_get_structure(caps, 0);
334 
335 	if (!gst_structure_has_field(structure, "rate")) {
336 		error = TRUE;
337 		*error_message = g_strdup("no rate");
338 		goto error;
339 	} else {
340 		value = gst_structure_get_value(structure, "rate");
341 		if (GST_VALUE_HOLDS_LIST(value))
342 			temp = gst_sbc_select_rate_from_list(value);
343 		else
344 			temp = g_value_get_int(value);
345 		rate = temp;
346 	}
347 
348 	if (!gst_structure_has_field(structure, "channels")) {
349 		error = TRUE;
350 		*error_message = g_strdup("no channels");
351 		goto error;
352 	} else {
353 		value = gst_structure_get_value(structure, "channels");
354 		if (GST_VALUE_HOLDS_INT_RANGE(value))
355 			temp = gst_sbc_select_channels_from_range(value);
356 		else
357 			temp = g_value_get_int(value);
358 		channels = temp;
359 	}
360 
361 	if (!gst_structure_has_field(structure, "blocks")) {
362 		error = TRUE;
363 		*error_message = g_strdup("no blocks.");
364 		goto error;
365 	} else {
366 		value = gst_structure_get_value(structure, "blocks");
367 		if (GST_VALUE_HOLDS_LIST(value))
368 			temp = gst_sbc_select_blocks_from_list(value);
369 		else
370 			temp = g_value_get_int(value);
371 		blocks = temp;
372 	}
373 
374 	if (!gst_structure_has_field(structure, "subbands")) {
375 		error = TRUE;
376 		*error_message = g_strdup("no subbands");
377 		goto error;
378 	} else {
379 		value = gst_structure_get_value(structure, "subbands");
380 		if (GST_VALUE_HOLDS_LIST(value))
381 			temp = gst_sbc_select_subbands_from_list(value);
382 		else
383 			temp = g_value_get_int(value);
384 		subbands = temp;
385 	}
386 
387 	if (!gst_structure_has_field(structure, "bitpool")) {
388 		error = TRUE;
389 		*error_message = g_strdup("no bitpool");
390 		goto error;
391 	} else {
392 		value = gst_structure_get_value(structure, "bitpool");
393 		if (GST_VALUE_HOLDS_INT_RANGE(value))
394 			temp = gst_sbc_select_bitpool_from_range(value);
395 		else
396 			temp = g_value_get_int(value);
397 		bitpool = temp;
398 	}
399 
400 	if (!gst_structure_has_field(structure, "allocation")) {
401 		error = TRUE;
402 		*error_message = g_strdup("no allocation");
403 		goto error;
404 	} else {
405 		value = gst_structure_get_value(structure, "allocation");
406 		if (GST_VALUE_HOLDS_LIST(value))
407 			allocation = gst_sbc_get_allocation_from_list(value);
408 		else
409 			allocation = g_value_get_string(value);
410 	}
411 
412 	if (!gst_structure_has_field(structure, "mode")) {
413 		error = TRUE;
414 		*error_message = g_strdup("no mode");
415 		goto error;
416 	} else {
417 		value = gst_structure_get_value(structure, "mode");
418 		if (GST_VALUE_HOLDS_LIST(value)) {
419 			mode = gst_sbc_get_mode_from_list(value, channels);
420 		} else
421 			mode = g_value_get_string(value);
422 	}
423 
424 	/* perform validation
425 	 * if channels is 1, we must have channel mode = mono
426 	 * if channels is 2, we can't have channel mode = mono */
427 	if ( (channels == 1 && (strcmp(mode, "mono") != 0) ) ||
428 			( channels == 2 && ( strcmp(mode, "mono") == 0))) {
429 		*error_message = g_strdup_printf("Invalid combination of "
430 					"channels (%d) and channel mode (%s)",
431 					channels, mode);
432 		error = TRUE;
433 	}
434 
435 error:
436 	if (error)
437 		return NULL;
438 
439 	result = gst_caps_new_simple("audio/x-sbc",
440 					"rate", G_TYPE_INT, rate,
441 					"channels", G_TYPE_INT, channels,
442 					"mode", G_TYPE_STRING, mode,
443 					"blocks", G_TYPE_INT, blocks,
444 					"subbands", G_TYPE_INT, subbands,
445 					"allocation", G_TYPE_STRING, allocation,
446 					"bitpool", G_TYPE_INT, bitpool,
447 					NULL);
448 
449 	return result;
450 }
451 
452 /**
453  * Sets the int field_value to the  param "field" on the structure.
454  * value is used to do the operation, it must be a uninitialized (zero-filled)
455  * GValue, it will be left unitialized at the end of the function.
456  */
gst_sbc_util_set_structure_int_param(GstStructure * structure,const gchar * field,gint field_value,GValue * value)457 void gst_sbc_util_set_structure_int_param(GstStructure *structure,
458 			const gchar *field, gint field_value,
459 			GValue *value)
460 {
461 	value = g_value_init(value, G_TYPE_INT);
462 	g_value_set_int(value, field_value);
463 	gst_structure_set_value(structure, field, value);
464 	g_value_unset(value);
465 }
466 
467 /**
468  * Sets the string field_value to the  param "field" on the structure.
469  * value is used to do the operation, it must be a uninitialized (zero-filled)
470  * GValue, it will be left unitialized at the end of the function.
471  */
gst_sbc_util_set_structure_string_param(GstStructure * structure,const gchar * field,const gchar * field_value,GValue * value)472 void gst_sbc_util_set_structure_string_param(GstStructure *structure,
473 			const gchar *field, const gchar *field_value,
474 			GValue *value)
475 {
476 	value = g_value_init(value, G_TYPE_STRING);
477 	g_value_set_string(value, field_value);
478 	gst_structure_set_value(structure, field, value);
479 	g_value_unset(value);
480 }
481 
gst_sbc_util_fill_sbc_params(sbc_t * sbc,GstCaps * caps)482 gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps)
483 {
484 	GstStructure *structure;
485 	gint rate, channels, subbands, blocks, bitpool;
486 	const gchar *mode;
487 	const gchar *allocation;
488 
489 	g_assert(gst_caps_is_fixed(caps));
490 
491 	structure = gst_caps_get_structure(caps, 0);
492 
493 	if (!gst_structure_get_int(structure, "rate", &rate))
494 		return FALSE;
495 	if (!gst_structure_get_int(structure, "channels", &channels))
496 		return FALSE;
497 	if (!gst_structure_get_int(structure, "subbands", &subbands))
498 		return FALSE;
499 	if (!gst_structure_get_int(structure, "blocks", &blocks))
500 		return FALSE;
501 	if (!gst_structure_get_int(structure, "bitpool", &bitpool))
502 		return FALSE;
503 
504 	if (!(mode = gst_structure_get_string(structure, "mode")))
505 		return FALSE;
506 	if (!(allocation = gst_structure_get_string(structure, "allocation")))
507 		return FALSE;
508 
509 	if (channels == 1 && strcmp(mode, "mono") != 0)
510 		return FALSE;
511 
512 	sbc->frequency = gst_sbc_parse_rate_to_sbc(rate);
513 	sbc->blocks = gst_sbc_parse_blocks_to_sbc(blocks);
514 	sbc->subbands = gst_sbc_parse_subbands_to_sbc(subbands);
515 	sbc->bitpool = bitpool;
516 	sbc->mode = gst_sbc_parse_mode_to_sbc(mode);
517 	sbc->allocation = gst_sbc_parse_allocation_to_sbc(allocation);
518 
519 	return TRUE;
520 }
521 
522