+static int bt_transport_config_a2dp(struct userdata *u) {
+ const pa_bluetooth_transport *t;
+ struct a2dp_info *a2dp = &u->a2dp;
+ a2dp_sbc_t *config;
+
+ t = pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
+ pa_assert(t);
+
+ config = (a2dp_sbc_t *) t->config;
+
+ u->sample_spec.format = PA_SAMPLE_S16LE;
+
+ if (a2dp->sbc_initialized)
+ sbc_reinit(&a2dp->sbc, 0);
+ else
+ sbc_init(&a2dp->sbc, 0);
+ a2dp->sbc_initialized = TRUE;
+
+ switch (config->frequency) {
+ case BT_SBC_SAMPLING_FREQ_16000:
+ a2dp->sbc.frequency = SBC_FREQ_16000;
+ u->sample_spec.rate = 16000U;
+ break;
+ case BT_SBC_SAMPLING_FREQ_32000:
+ a2dp->sbc.frequency = SBC_FREQ_32000;
+ u->sample_spec.rate = 32000U;
+ break;
+ case BT_SBC_SAMPLING_FREQ_44100:
+ a2dp->sbc.frequency = SBC_FREQ_44100;
+ u->sample_spec.rate = 44100U;
+ break;
+ case BT_SBC_SAMPLING_FREQ_48000:
+ a2dp->sbc.frequency = SBC_FREQ_48000;
+ u->sample_spec.rate = 48000U;
+ break;
+ default:
+ pa_assert_not_reached();
+ }
+
+ switch (config->channel_mode) {
+ case BT_A2DP_CHANNEL_MODE_MONO:
+ a2dp->sbc.mode = SBC_MODE_MONO;
+ u->sample_spec.channels = 1;
+ break;
+ case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+ a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL;
+ u->sample_spec.channels = 2;
+ break;
+ case BT_A2DP_CHANNEL_MODE_STEREO:
+ a2dp->sbc.mode = SBC_MODE_STEREO;
+ u->sample_spec.channels = 2;
+ break;
+ case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
+ a2dp->sbc.mode = SBC_MODE_JOINT_STEREO;
+ u->sample_spec.channels = 2;
+ break;
+ default:
+ pa_assert_not_reached();
+ }
+
+ switch (config->allocation_method) {
+ case BT_A2DP_ALLOCATION_SNR:
+ a2dp->sbc.allocation = SBC_AM_SNR;
+ break;
+ case BT_A2DP_ALLOCATION_LOUDNESS:
+ a2dp->sbc.allocation = SBC_AM_LOUDNESS;
+ break;
+ default:
+ pa_assert_not_reached();
+ }
+
+ switch (config->subbands) {
+ case BT_A2DP_SUBBANDS_4:
+ a2dp->sbc.subbands = SBC_SB_4;
+ break;
+ case BT_A2DP_SUBBANDS_8:
+ a2dp->sbc.subbands = SBC_SB_8;
+ break;
+ default:
+ pa_assert_not_reached();
+ }
+
+ switch (config->block_length) {
+ case BT_A2DP_BLOCK_LENGTH_4:
+ a2dp->sbc.blocks = SBC_BLK_4;
+ break;
+ case BT_A2DP_BLOCK_LENGTH_8:
+ a2dp->sbc.blocks = SBC_BLK_8;
+ break;
+ case BT_A2DP_BLOCK_LENGTH_12:
+ a2dp->sbc.blocks = SBC_BLK_12;
+ break;
+ case BT_A2DP_BLOCK_LENGTH_16:
+ a2dp->sbc.blocks = SBC_BLK_16;
+ break;
+ default:
+ pa_assert_not_reached();
+ }
+
+ a2dp->min_bitpool = config->min_bitpool;
+ a2dp->max_bitpool = config->max_bitpool;
+
+ /* Set minimum bitpool for source to get the maximum possible block_size */
+ a2dp->sbc.bitpool = u->profile == PROFILE_A2DP ? a2dp->max_bitpool : a2dp->min_bitpool;
+ a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
+ a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc);
+
+ u->block_size =
+ ((u->link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
+ / a2dp->frame_length
+ * a2dp->codesize);
+
+ pa_log_info("SBC parameters:\n\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
+ a2dp->sbc.allocation, a2dp->sbc.subbands, a2dp->sbc.blocks, a2dp->sbc.bitpool);
+
+ return 0;
+}
+
+static int bt_transport_config(struct userdata *u) {
+ if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW) {
+ u->block_size = u->link_mtu;
+ u->sample_spec.format = PA_SAMPLE_S16LE;
+ u->sample_spec.channels = 1;
+ u->sample_spec.rate = 8000;
+ return 0;
+ }
+
+ return bt_transport_config_a2dp(u);
+}
+
+/* Run from main thread */
+static int bt_transport_open(struct userdata *u) {
+ if (bt_transport_acquire(u, FALSE) < 0)
+ return -1;
+
+ return bt_transport_config(u);
+}
+