diff options
Diffstat (limited to 'audio/pcm_bluetooth.c')
-rw-r--r-- | audio/pcm_bluetooth.c | 206 |
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) { |