diff options
| -rw-r--r-- | audio/gstavdtpsink.c | 100 | ||||
| -rw-r--r-- | audio/gstsbcenc.c | 13 | ||||
| -rw-r--r-- | audio/gstsbcutil.c | 8 | ||||
| -rw-r--r-- | audio/ipc.h | 2 | ||||
| -rw-r--r-- | audio/pcm_bluetooth.c | 206 | 
5 files changed, 156 insertions, 173 deletions
| diff --git a/audio/gstavdtpsink.c b/audio/gstavdtpsink.c index 2a97b559..8c8a7465 100644 --- a/audio/gstavdtpsink.c +++ b/audio/gstavdtpsink.c @@ -279,9 +279,7 @@ static gboolean gst_avdtp_sink_init_sbc_pkt_conf(GstAvdtpSink *sink,  	value = gst_structure_get_value(structure, "mode");  	pref = g_value_get_string(value); -	if (strcmp(pref, "auto") == 0) -		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_AUTO; -	else if (strcmp(pref, "mono") == 0) +	if (strcmp(pref, "mono") == 0)  		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;  	else if (strcmp(pref, "dual") == 0)  		cfg->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL; @@ -296,9 +294,7 @@ static gboolean gst_avdtp_sink_init_sbc_pkt_conf(GstAvdtpSink *sink,  	value = gst_structure_get_value(structure, "allocation");  	pref = g_value_get_string(value); -	if (strcmp(pref, "auto") == 0) -		cfg->allocation_method = BT_A2DP_ALLOCATION_AUTO; -	else if (strcmp(pref, "loudness") == 0) +	if (strcmp(pref, "loudness") == 0)  		cfg->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;  	else if (strcmp(pref, "snr") == 0)  		cfg->allocation_method = BT_A2DP_ALLOCATION_SNR; @@ -438,32 +434,21 @@ static GstStructure *gst_avdtp_sink_parse_sbc_caps(  	/* mode */  	list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); -	if (sbc->channel_mode == BT_A2DP_CHANNEL_MODE_AUTO) { -		g_value_set_static_string(value, "joint"); +	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) { +		g_value_set_static_string(value, "mono");  		gst_value_list_prepend_value(list, value); +	} +	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) {  		g_value_set_static_string(value, "stereo");  		gst_value_list_prepend_value(list, value); -		g_value_set_static_string(value, "mono"); -		gst_value_list_prepend_value(list, value); +	} +	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) {  		g_value_set_static_string(value, "dual");  		gst_value_list_prepend_value(list, value); -	} else { -		if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) { -			g_value_set_static_string(value, "mono"); -			gst_value_list_prepend_value(list, value); -		} -		if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) { -			g_value_set_static_string(value, "stereo"); -			gst_value_list_prepend_value(list, value); -		} -		if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) { -			g_value_set_static_string(value, "dual"); -			gst_value_list_prepend_value(list, value); -		} -		if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) { -			g_value_set_static_string(value, "joint"); -			gst_value_list_prepend_value(list, value); -		} +	} +	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) { +		g_value_set_static_string(value, "joint"); +		gst_value_list_prepend_value(list, value);  	}  	g_value_unset(value);  	if (list) { @@ -519,20 +504,13 @@ static GstStructure *gst_avdtp_sink_parse_sbc_caps(  	/* allocation */  	g_value_init(value, G_TYPE_STRING);  	list = g_value_init(g_new0(GValue,1), GST_TYPE_LIST); -	if (sbc->allocation_method == BT_A2DP_ALLOCATION_AUTO) { +	if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) {  		g_value_set_static_string(value, "loudness");  		gst_value_list_prepend_value(list, value); +	} +	if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) {  		g_value_set_static_string(value, "snr");  		gst_value_list_prepend_value(list, value); -	} else { -		if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) { -			g_value_set_static_string(value, "loudness"); -			gst_value_list_prepend_value(list, value); -		} -		if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) { -			g_value_set_static_string(value, "snr"); -			gst_value_list_prepend_value(list, value); -		}  	}  	g_value_unset(value);  	if (list) { @@ -576,37 +554,33 @@ static GstStructure *gst_avdtp_sink_parse_sbc_caps(  	g_value_unset(value);  	/* channels */ -	if (sbc->channel_mode == BT_A2DP_CHANNEL_MODE_AUTO) { +	mono = FALSE; +	stereo = FALSE; +	if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) +		mono = TRUE; +	if ((sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) || +			(sbc->channel_mode & +			BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) || +			(sbc->channel_mode & +			BT_A2DP_CHANNEL_MODE_JOINT_STEREO)) +		stereo = TRUE; + +	if (mono && stereo) {  		g_value_init(value, GST_TYPE_INT_RANGE);  		gst_value_set_int_range(value, 1, 2);  	} else { -		mono = FALSE; -		stereo = FALSE; -		if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) -			mono = TRUE; -		if ((sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) || -				(sbc->channel_mode & -				BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) || -				(sbc->channel_mode & -				BT_A2DP_CHANNEL_MODE_JOINT_STEREO)) -			stereo = TRUE; - -		if (mono && stereo) { -			g_value_init(value, GST_TYPE_INT_RANGE); -			gst_value_set_int_range(value, 1, 2); -		} else { -			g_value_init(value, G_TYPE_INT); -			if (mono) -				g_value_set_int(value, 1); -			else if (stereo) -				g_value_set_int(value, 2); -			else { -				GST_ERROR_OBJECT(self, -					"Unexpected number of channels"); -				g_value_set_int(value, 0); -			} +		g_value_init(value, G_TYPE_INT); +		if (mono) +			g_value_set_int(value, 1); +		else if (stereo) +			g_value_set_int(value, 2); +		else { +			GST_ERROR_OBJECT(self, +				"Unexpected number of channels"); +			g_value_set_int(value, 0);  		}  	} +  	gst_structure_set_value(structure, "channels", value);  	g_free(value); diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c index 918324b2..7777084c 100644 --- a/audio/gstsbcenc.c +++ b/audio/gstsbcenc.c @@ -31,10 +31,10 @@  #include "gstsbcenc.h"  #include "gstsbcutil.h" -#define SBC_ENC_DEFAULT_MODE BT_A2DP_CHANNEL_MODE_AUTO +#define SBC_ENC_DEFAULT_MODE BT_A2DP_CHANNEL_MODE_JOINT_STEREO  #define SBC_ENC_DEFAULT_BLOCKS 0  #define SBC_ENC_DEFAULT_SUB_BANDS 0 -#define SBC_ENC_DEFAULT_ALLOCATION BT_A2DP_ALLOCATION_AUTO +#define SBC_ENC_DEFAULT_ALLOCATION BT_A2DP_ALLOCATION_LOUDNESS  #define SBC_ENC_DEFAULT_RATE 0  #define SBC_ENC_DEFAULT_CHANNELS 0 @@ -73,7 +73,6 @@ static GType gst_sbc_allocation_get_type(void)  {  	static GType sbc_allocation_type = 0;  	static GEnumValue sbc_allocations[] = { -		{ BT_A2DP_ALLOCATION_AUTO,	"Auto",		"auto" },  		{ BT_A2DP_ALLOCATION_LOUDNESS,	"Loudness",	"loudness" },  		{ BT_A2DP_ALLOCATION_SNR,	"SNR",		"snr" },  		{ -1, NULL, NULL} @@ -201,7 +200,7 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc)  		gst_sbc_util_set_structure_int_param(structure, "bitpool",  			enc->bitpool, value); -	if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO) { +	if (enc->mode != SBC_ENC_DEFAULT_MODE) {  		enum_class = g_type_class_ref(GST_TYPE_SBC_MODE);  		enum_value = g_enum_get_value(enum_class, enc->mode);  		gst_sbc_util_set_structure_string_param(structure, "mode", @@ -209,7 +208,7 @@ static GstCaps* sbc_enc_generate_srcpad_caps(GstSbcEnc *enc)  		g_type_class_unref(enum_class);  	} -	if (enc->allocation != BT_A2DP_ALLOCATION_AUTO) { +	if (enc->allocation != SBC_ENC_DEFAULT_ALLOCATION) {  		enum_class = g_type_class_ref(GST_TYPE_SBC_ALLOCATION);  		enum_value = g_enum_get_value(enum_class, enc->allocation);  		gst_sbc_util_set_structure_string_param(structure, "allocation", @@ -341,10 +340,10 @@ gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps)  		goto fail;  	mode = gst_sbc_get_mode_int_from_sbc_t(&enc->sbc); -	if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO && mode != enc->mode) +	if (enc->mode != SBC_ENC_DEFAULT_MODE && mode != enc->mode)  		goto fail; -	if (enc->allocation != BT_A2DP_ALLOCATION_AUTO && +	if (enc->allocation != SBC_ENC_DEFAULT_ALLOCATION &&  				enc->sbc.allocation != enc->allocation)  		goto fail; diff --git a/audio/gstsbcutil.c b/audio/gstsbcutil.c index 075e3a4d..de48838f 100644 --- a/audio/gstsbcutil.c +++ b/audio/gstsbcutil.c @@ -131,8 +131,6 @@ gint gst_sbc_get_allocation_mode_int(const gchar *allocation)  		return BT_A2DP_ALLOCATION_LOUDNESS;  	else if (g_ascii_strcasecmp(allocation, "snr") == 0)  		return BT_A2DP_ALLOCATION_SNR; -	else if (g_ascii_strcasecmp(allocation, "auto") == 0) -		return BT_A2DP_ALLOCATION_AUTO;  	else  		return -1;  } @@ -147,8 +145,6 @@ gint gst_sbc_get_mode_int(const gchar *mode)  		return BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;  	else if (g_ascii_strcasecmp(mode, "mono") == 0)  		return BT_A2DP_CHANNEL_MODE_MONO; -	else if (g_ascii_strcasecmp(mode, "auto") == 0) -		return BT_A2DP_CHANNEL_MODE_AUTO;  	else  		return -1;  } @@ -190,8 +186,6 @@ const gchar *gst_sbc_get_mode_string(gint joint)  		return "stereo";  	case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:  		return "joint"; -	case BT_A2DP_CHANNEL_MODE_AUTO: -		return NULL; /* TODO what should be selected here? */  	default:  		return NULL;  	} @@ -204,8 +198,6 @@ const gchar *gst_sbc_get_allocation_string(gint alloc)  		return "loudness";  	case BT_A2DP_ALLOCATION_SNR:  		return "snr"; -	case BT_A2DP_ALLOCATION_AUTO: -		return "loudness"; /* TODO what should be selected here? */  	default:  		return NULL;  	} diff --git a/audio/ipc.h b/audio/ipc.h index 80deea57..c900fcd1 100644 --- a/audio/ipc.h +++ b/audio/ipc.h @@ -141,7 +141,6 @@ struct bt_getcapabilities_req {  #define BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL	(1 << 2)  #define BT_A2DP_CHANNEL_MODE_STEREO		(1 << 1)  #define BT_A2DP_CHANNEL_MODE_JOINT_STEREO	1 -#define BT_A2DP_CHANNEL_MODE_AUTO		0  #define BT_A2DP_BLOCK_LENGTH_4			(1 << 3)  #define BT_A2DP_BLOCK_LENGTH_8			(1 << 2) @@ -153,7 +152,6 @@ struct bt_getcapabilities_req {  #define BT_A2DP_ALLOCATION_SNR			(1 << 1)  #define BT_A2DP_ALLOCATION_LOUDNESS		1 -#define BT_A2DP_ALLOCATION_AUTO			0  #define BT_MPEG_SAMPLING_FREQ_16000		(1 << 5)  #define BT_MPEG_SAMPLING_FREQ_22050		(1 << 4) diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c index 565fa9ae..ef12b400 100644 --- a/audio/pcm_bluetooth.c +++ b/audio/pcm_bluetooth.c @@ -503,10 +503,16 @@ static uint8_t default_bitpool(uint8_t freq, uint8_t mode)  	}  } -static int select_sbc_params(sbc_capabilities_t *cap, unsigned int rate, -				unsigned int channels) +static int bluetooth_a2dp_init(struct bluetooth_data *data, +				snd_pcm_hw_params_t *params)  { -	unsigned int max_bitpool, min_bitpool; +	struct bluetooth_alsa_config *cfg = &data->alsa_config; +	sbc_capabilities_t *cap = &data->a2dp.sbc_capabilities; +	unsigned int max_bitpool, min_bitpool, rate, channels; +	int dir; + +	snd_pcm_hw_params_get_rate(params, &rate, &dir); +	snd_pcm_hw_params_get_channels(params, &channels);  	switch (rate) {  	case 48000: @@ -526,7 +532,9 @@ static int select_sbc_params(sbc_capabilities_t *cap, unsigned int rate,  		return -1;  	} -	if (channels == 2) { +	if (cfg->has_channel_mode) +		cap->channel_mode = cfg->channel_mode; +	else if (channels == 2) {  		if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)  			cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;  		else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) @@ -543,7 +551,9 @@ static int select_sbc_params(sbc_capabilities_t *cap, unsigned int rate,  		return -1;  	} -	if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16) +	if (cfg->has_block_length) +		cap->block_length = cfg->block_length; +	else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16)  		cap->block_length = BT_A2DP_BLOCK_LENGTH_16;  	else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_12)  		cap->block_length = BT_A2DP_BLOCK_LENGTH_12; @@ -556,6 +566,8 @@ static int select_sbc_params(sbc_capabilities_t *cap, unsigned int rate,  		return -1;  	} +	if (cfg->has_subbands) +		cap->subbands = cfg->subbands;  	if (cap->subbands & BT_A2DP_SUBBANDS_8)  		cap->subbands = BT_A2DP_SUBBANDS_8;  	else if (cap->subbands & BT_A2DP_SUBBANDS_4) @@ -565,14 +577,21 @@ static int select_sbc_params(sbc_capabilities_t *cap, unsigned int rate,  		return -1;  	} +	if (cfg->has_allocation_method) +		cap->allocation_method = cfg->allocation_method;  	if (cap->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS)  		cap->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;  	else if (cap->allocation_method & BT_A2DP_ALLOCATION_SNR)  		cap->allocation_method = BT_A2DP_ALLOCATION_SNR; -	min_bitpool = MAX(MIN_BITPOOL, cap->min_bitpool); -	max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode), -							cap->max_bitpool); +	if (cfg->has_bitpool) +		min_bitpool = max_bitpool = cfg->bitpool; +	else { +		min_bitpool = MAX(MIN_BITPOOL, cap->min_bitpool); +		max_bitpool = MIN(default_bitpool(cap->frequency, +					cap->channel_mode), +					cap->max_bitpool); +	}  	cap->min_bitpool = min_bitpool;  	cap->max_bitpool = max_bitpool; @@ -580,63 +599,10 @@ static int select_sbc_params(sbc_capabilities_t *cap, unsigned int rate,  	return 0;  } - -static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io, -					snd_pcm_hw_params_t *params) +static void bluetooth_a2dp_setup(struct bluetooth_a2dp *a2dp)  { -	struct bluetooth_data *data = io->private_data; -	struct bluetooth_a2dp *a2dp = &data->a2dp; -	char buf[BT_AUDIO_IPC_PACKET_SIZE]; -	bt_audio_rsp_msg_header_t *rsp_hdr = (void*) buf; -	struct bt_setconfiguration_req *setconf_req = (void*) buf; -	struct bt_setconfiguration_rsp *setconf_rsp = (void*) buf; -	unsigned int rate, channels; -	int err, dir; -	sbc_capabilities_t active_capabilities; +	sbc_capabilities_t active_capabilities = a2dp->sbc_capabilities; -	DBG("Preparing with io->period_size=%lu io->buffer_size=%lu", -					io->period_size, io->buffer_size); - -	/* FIXME: this needs to be really implemented (take into account -	real asoundrc settings + ALSA hw settings ) once server side sends us -	more than one possible configuration */ -	snd_pcm_hw_params_get_rate(params, &rate, &dir); -	snd_pcm_hw_params_get_channels(params, &channels); -	err = select_sbc_params(&a2dp->sbc_capabilities, rate, channels); -	if (err < 0) -		return err; - -	active_capabilities = a2dp->sbc_capabilities; - -	memset(setconf_req, 0, BT_AUDIO_IPC_PACKET_SIZE); -	setconf_req->h.msg_type = BT_SETCONFIGURATION_REQ; -	strncpy(setconf_req->device, data->alsa_config.device, 18); -	setconf_req->transport = BT_CAPABILITIES_TRANSPORT_A2DP; -	setconf_req->sbc_capabilities = active_capabilities; -	setconf_req->access_mode = (io->stream == SND_PCM_STREAM_PLAYBACK ? -			BT_CAPABILITIES_ACCESS_MODE_WRITE : -			BT_CAPABILITIES_ACCESS_MODE_READ); - -	err = audioservice_send(data->server.fd, &setconf_req->h); -	if (err < 0) -		return err; - -	err = audioservice_expect(data->server.fd, &rsp_hdr->msg_h, -					BT_SETCONFIGURATION_RSP); -	if (err < 0) -		return err; - -	if (rsp_hdr->posix_errno != 0) { -		SNDERR("BT_SETCONFIGURATION failed : %s(%d)", -					strerror(rsp_hdr->posix_errno), -					rsp_hdr->posix_errno); -		return -rsp_hdr->posix_errno; -	} - -	data->transport = setconf_rsp->transport; -	data->link_mtu = setconf_rsp->link_mtu; - -	/* Setup SBC encoder now we agree on parameters */  	if (a2dp->sbc_initialized)  		sbc_reinit(&a2dp->sbc, 0);  	else @@ -695,9 +661,58 @@ static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io,  	}  	a2dp->sbc.bitpool = active_capabilities.max_bitpool; -	a2dp->codesize = a2dp->sbc.subbands * a2dp->sbc.blocks * -						a2dp->sbc.channels * 2; +	a2dp->codesize = sbc_get_codesize(&a2dp->sbc);  	a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); +} + +static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io, +					snd_pcm_hw_params_t *params) +{ +	struct bluetooth_data *data = io->private_data; +	struct bluetooth_a2dp *a2dp = &data->a2dp; +	char buf[BT_AUDIO_IPC_PACKET_SIZE]; +	bt_audio_rsp_msg_header_t *rsp_hdr = (void*) buf; +	struct bt_setconfiguration_req *setconf_req = (void*) buf; +	struct bt_setconfiguration_rsp *setconf_rsp = (void*) buf; +	int err; + +	DBG("Preparing with io->period_size=%lu io->buffer_size=%lu", +					io->period_size, io->buffer_size); + +	err = bluetooth_a2dp_init(data, params); +	if (err < 0) +		return err; + +	memset(setconf_req, 0, BT_AUDIO_IPC_PACKET_SIZE); +	setconf_req->h.msg_type = BT_SETCONFIGURATION_REQ; +	strncpy(setconf_req->device, data->alsa_config.device, 18); +	setconf_req->transport = BT_CAPABILITIES_TRANSPORT_A2DP; +	setconf_req->sbc_capabilities = a2dp->sbc_capabilities; +	setconf_req->access_mode = (io->stream == SND_PCM_STREAM_PLAYBACK ? +			BT_CAPABILITIES_ACCESS_MODE_WRITE : +			BT_CAPABILITIES_ACCESS_MODE_READ); + +	err = audioservice_send(data->server.fd, &setconf_req->h); +	if (err < 0) +		return err; + +	err = audioservice_expect(data->server.fd, &rsp_hdr->msg_h, +					BT_SETCONFIGURATION_RSP); +	if (err < 0) +		return err; + +	if (rsp_hdr->posix_errno != 0) { +		SNDERR("BT_SETCONFIGURATION failed : %s(%d)", +					strerror(rsp_hdr->posix_errno), +					rsp_hdr->posix_errno); +		return -rsp_hdr->posix_errno; +	} + +	data->transport = setconf_rsp->transport; +	data->link_mtu = setconf_rsp->link_mtu; + +	/* Setup SBC encoder now we agree on parameters */ +	bluetooth_a2dp_setup(a2dp);  	DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",  		a2dp->sbc.allocation, a2dp->sbc.subbands, a2dp->sbc.blocks, @@ -1172,6 +1187,7 @@ static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io)  {  	struct bluetooth_data *data = io->private_data;  	struct bluetooth_a2dp *a2dp = &data->a2dp; +	struct bluetooth_alsa_config *cfg = &data->alsa_config;  	snd_pcm_access_t access_list[] = {  		SND_PCM_ACCESS_RW_INTERLEAVED,  		/* Mmap access is really useless fo this driver, but we @@ -1204,12 +1220,17 @@ static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io)  		return err;  	/* supported channels */ -	if (a2dp->sbc_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO) +	if (cfg->has_channel_mode) +		a2dp->sbc_capabilities.channel_mode = cfg->channel_mode; + +	if (a2dp->sbc_capabilities.channel_mode & +			BT_A2DP_CHANNEL_MODE_MONO)  		min_channels = 1;  	else  		min_channels = 2; -	if (a2dp->sbc_capabilities.channel_mode & (~BT_A2DP_CHANNEL_MODE_MONO)) +	if (a2dp->sbc_capabilities.channel_mode & +			(~BT_A2DP_CHANNEL_MODE_MONO))  		max_channels = 2;  	else  		max_channels = 1; @@ -1234,28 +1255,33 @@ static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io)  	/* supported rates */  	rate_count = 0; -	if (a2dp->sbc_capabilities.frequency & -			BT_SBC_SAMPLING_FREQ_16000) { -		rate_list[rate_count] = 16000; +	if (cfg->has_rate) { +		rate_list[rate_count] = cfg->rate;  		rate_count++; -	} +	} else { +		if (a2dp->sbc_capabilities.frequency & +				BT_SBC_SAMPLING_FREQ_16000) { +			rate_list[rate_count] = 16000; +			rate_count++; +		} -	if (a2dp->sbc_capabilities.frequency & -			BT_SBC_SAMPLING_FREQ_32000) { -		rate_list[rate_count] = 32000; -		rate_count++; -	} +		if (a2dp->sbc_capabilities.frequency & +				BT_SBC_SAMPLING_FREQ_32000) { +			rate_list[rate_count] = 32000; +			rate_count++; +		} -	if (a2dp->sbc_capabilities.frequency & -			BT_SBC_SAMPLING_FREQ_44100) { -		rate_list[rate_count] = 44100; -		rate_count++; -	} +		if (a2dp->sbc_capabilities.frequency & +				BT_SBC_SAMPLING_FREQ_44100) { +			rate_list[rate_count] = 44100; +			rate_count++; +		} -	if (a2dp->sbc_capabilities.frequency & -			BT_SBC_SAMPLING_FREQ_48000) { -		rate_list[rate_count] = 48000; -		rate_count++; +		if (a2dp->sbc_capabilities.frequency & +				BT_SBC_SAMPLING_FREQ_48000) { +			rate_list[rate_count] = 48000; +			rate_count++; +		}  	}  	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE, @@ -1348,10 +1374,7 @@ static int bluetooth_parse_config(snd_config_t *conf,  				return -EINVAL;  			} -			if (strcmp(value, "auto") == 0) { -				bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_AUTO; -				bt_config->has_channel_mode = 1; -			} else if (strcmp(value, "mono") == 0) { +			if (strcmp(value, "mono") == 0) {  				bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;  				bt_config->has_channel_mode = 1;  			} else if (strcmp(value, "dual") == 0) { @@ -1373,10 +1396,7 @@ static int bluetooth_parse_config(snd_config_t *conf,  				return -EINVAL;  			} -			if (strcmp(value, "auto") == 0) { -				bt_config->allocation_method = BT_A2DP_ALLOCATION_AUTO; -				bt_config->has_allocation_method = 1; -			} else if (strcmp(value, "loudness") == 0) { +			if (strcmp(value, "loudness") == 0) {  				bt_config->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;  				bt_config->has_allocation_method = 1;  			} else if (strcmp(value, "snr") == 0) { | 
