static int bluetooth_a2dp_hw_params(struct bluetooth_data *data) { char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_open_req *open_req = (void *) buf; struct bt_open_rsp *open_rsp = (void *) buf; struct bt_set_configuration_req *setconf_req = (void*) buf; struct bt_set_configuration_rsp *setconf_rsp = (void*) buf; int err; memset(open_req, 0, BT_SUGGESTED_BUFFER_SIZE); open_req->h.type = BT_REQUEST; open_req->h.name = BT_OPEN; open_req->h.length = sizeof(*open_req); strncpy(open_req->destination, data->address, 18); open_req->seid = data->sbc_capabilities.capability.seid; open_req->lock = BT_WRITE_LOCK; err = audioservice_send(data, &open_req->h); if (err < 0) return err; open_rsp->h.length = sizeof(*open_rsp); err = audioservice_expect(data, &open_rsp->h, BT_OPEN); if (err < 0) return err; err = bluetooth_a2dp_init(data); if (err < 0) return err; memset(setconf_req, 0, BT_SUGGESTED_BUFFER_SIZE); setconf_req->h.type = BT_REQUEST; setconf_req->h.name = BT_SET_CONFIGURATION; setconf_req->h.length = sizeof(*setconf_req); memcpy(&setconf_req->codec, &data->sbc_capabilities, sizeof(data->sbc_capabilities)); setconf_req->codec.transport = BT_CAPABILITIES_TRANSPORT_A2DP; setconf_req->codec.length = sizeof(data->sbc_capabilities); setconf_req->h.length += setconf_req->codec.length - sizeof(setconf_req->codec); DBG("bluetooth_a2dp_hw_params sending configuration:\n"); switch (data->sbc_capabilities.channel_mode) { case BT_A2DP_CHANNEL_MODE_MONO: DBG("\tchannel_mode: MONO\n"); break; case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL: DBG("\tchannel_mode: DUAL CHANNEL\n"); break; case BT_A2DP_CHANNEL_MODE_STEREO: DBG("\tchannel_mode: STEREO\n"); break; case BT_A2DP_CHANNEL_MODE_JOINT_STEREO: DBG("\tchannel_mode: JOINT STEREO\n"); break; default: DBG("\tchannel_mode: UNKNOWN (%d)\n", data->sbc_capabilities.channel_mode); } switch (data->sbc_capabilities.frequency) { case BT_SBC_SAMPLING_FREQ_16000: DBG("\tfrequency: 16000\n"); break; case BT_SBC_SAMPLING_FREQ_32000: DBG("\tfrequency: 32000\n"); break; case BT_SBC_SAMPLING_FREQ_44100: DBG("\tfrequency: 44100\n"); break; case BT_SBC_SAMPLING_FREQ_48000: DBG("\tfrequency: 48000\n"); break; default: DBG("\tfrequency: UNKNOWN (%d)\n", data->sbc_capabilities.frequency); } switch (data->sbc_capabilities.allocation_method) { case BT_A2DP_ALLOCATION_SNR: DBG("\tallocation_method: SNR\n"); break; case BT_A2DP_ALLOCATION_LOUDNESS: DBG("\tallocation_method: LOUDNESS\n"); break; default: DBG("\tallocation_method: UNKNOWN (%d)\n", data->sbc_capabilities.allocation_method); } switch (data->sbc_capabilities.subbands) { case BT_A2DP_SUBBANDS_4: DBG("\tsubbands: 4\n"); break; case BT_A2DP_SUBBANDS_8: DBG("\tsubbands: 8\n"); break; default: DBG("\tsubbands: UNKNOWN (%d)\n", data->sbc_capabilities.subbands); } switch (data->sbc_capabilities.block_length) { case BT_A2DP_BLOCK_LENGTH_4: DBG("\tblock_length: 4\n"); break; case BT_A2DP_BLOCK_LENGTH_8: DBG("\tblock_length: 8\n"); break; case BT_A2DP_BLOCK_LENGTH_12: DBG("\tblock_length: 12\n"); break; case BT_A2DP_BLOCK_LENGTH_16: DBG("\tblock_length: 16\n"); break; default: DBG("\tblock_length: UNKNOWN (%d)\n", data->sbc_capabilities.block_length); } DBG("\tmin_bitpool: %d\n", data->sbc_capabilities.min_bitpool); DBG("\tmax_bitpool: %d\n", data->sbc_capabilities.max_bitpool); err = audioservice_send(data, &setconf_req->h); if (err < 0) return err; err = audioservice_expect(data, &setconf_rsp->h, BT_SET_CONFIGURATION); if (err < 0) return err; data->link_mtu = setconf_rsp->link_mtu; #ifdef TN_JPN_NTT_BT_SCMS-T if (setconf_rsp->content_protection == CP_TYPE_SCMS_T) { data->sizeof_scms_t = 1; data->scms_t_cp_header = SCMS_T_COPY_NOT_ALLOWED; } else { data->sizeof_scms_t = 0; data->scms_t_cp_header = SCMS_T_COPY_ALLOWED; } DBG("MTU: %d -- SCMS-T Enabled: %d", data->link_mtu, setconf_rsp->content_protection); #else DBG("MTU: %d", data->link_mtu); #endif /* Setup SBC encoder now we agree on parameters */ bluetooth_a2dp_setup(data); DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n", data->sbc.allocation, data->sbc.subbands, data->sbc.blocks, data->sbc.bitpool); return 0; }
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_SUGGESTED_BUFFER_SIZE]; struct bt_open_req *open_req = (void *) buf; struct bt_open_rsp *open_rsp = (void *) buf; struct bt_set_configuration_req *req = (void *) buf; struct bt_set_configuration_rsp *rsp = (void *) buf; int err; DBG("Preparing with io->period_size=%lu io->buffer_size=%lu", io->period_size, io->buffer_size); memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); open_req->h.type = BT_REQUEST; open_req->h.name = BT_OPEN; open_req->h.length = sizeof(*open_req); strncpy(open_req->destination, data->alsa_config.device, 18); open_req->seid = a2dp->sbc_capabilities.capability.seid; open_req->lock = (io->stream == SND_PCM_STREAM_PLAYBACK ? BT_WRITE_LOCK : BT_READ_LOCK); err = audioservice_send(data->server.fd, &open_req->h); if (err < 0) return err; open_rsp->h.length = sizeof(*open_rsp); err = audioservice_expect(data->server.fd, &open_rsp->h, BT_OPEN); if (err < 0) return err; err = bluetooth_a2dp_init(data, params); if (err < 0) return err; memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); req->h.type = BT_REQUEST; req->h.name = BT_SET_CONFIGURATION; req->h.length = sizeof(*req); memcpy(&req->codec, &a2dp->sbc_capabilities, sizeof(a2dp->sbc_capabilities)); req->codec.transport = BT_CAPABILITIES_TRANSPORT_A2DP; req->codec.length = sizeof(a2dp->sbc_capabilities); req->h.length += req->codec.length - sizeof(req->codec); err = audioservice_send(data->server.fd, &req->h); if (err < 0) return err; rsp->h.length = sizeof(*rsp); err = audioservice_expect(data->server.fd, &rsp->h, BT_SET_CONFIGURATION); if (err < 0) return err; data->transport = BT_CAPABILITIES_TRANSPORT_A2DP; data->link_mtu = 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, a2dp->sbc.bitpool); return 0; }