summaryrefslogtreecommitdiffstats
path: root/audio/pcm_bluetooth.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/pcm_bluetooth.c')
-rw-r--r--audio/pcm_bluetooth.c206
1 files changed, 113 insertions, 93 deletions
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) {