Home | History | Annotate | Download | only in audio
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel (at) 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  */
     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  */
     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  */
     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  */
     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  */
     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  */
     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  */
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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  */
    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  */
    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 
    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