-static int service_send(struct userdata *u, const bt_audio_msg_header_t *msg) {
- ssize_t r;
-
- pa_assert(u);
- pa_assert(u->service_fd >= 0);
- pa_assert(msg);
- pa_assert(msg->length > 0);
-
- pa_log_debug("Sending %s -> %s",
- pa_strnull(bt_audio_strtype(msg->type)),
- pa_strnull(bt_audio_strname(msg->name)));
-
- if ((r = pa_loop_write(u->service_fd, msg, msg->length, &u->service_write_type)) == (ssize_t) msg->length)
- return 0;
-
- if (r < 0)
- pa_log_error("Error sending data to audio service: %s", pa_cstrerror(errno));
- else
- pa_log_error("Short write()");
-
- return -1;
-}
-
-static int service_recv(struct userdata *u, bt_audio_msg_header_t *msg, size_t room) {
- ssize_t r;
-
- pa_assert(u);
- pa_assert(u->service_fd >= 0);
- pa_assert(msg);
-
- if (room <= 0)
- room = BT_SUGGESTED_BUFFER_SIZE;
-
- pa_log_debug("Trying to receive message from audio service...");
-
- /* First, read the header */
- if ((r = pa_loop_read(u->service_fd, msg, sizeof(*msg), &u->service_read_type)) != sizeof(*msg))
- goto read_fail;
-
- if (msg->length < sizeof(*msg)) {
- pa_log_error("Invalid message size.");
- return -1;
- }
-
- /* Secondly, read the payload */
- if (msg->length > sizeof(*msg)) {
-
- size_t remains = msg->length - sizeof(*msg);
-
- if ((r = pa_loop_read(u->service_fd,
- (uint8_t*) msg + sizeof(*msg),
- remains,
- &u->service_read_type)) != (ssize_t) remains)
- goto read_fail;
- }
-
- pa_log_debug("Received %s <- %s",
- pa_strnull(bt_audio_strtype(msg->type)),
- pa_strnull(bt_audio_strname(msg->name)));
-
- return 0;
-
-read_fail:
-
- if (r < 0)
- pa_log_error("Error receiving data from audio service: %s", pa_cstrerror(errno));
- else
- pa_log_error("Short read()");
-
- return -1;
-}
-
-static ssize_t service_expect(struct userdata*u, bt_audio_msg_header_t *rsp, size_t room, uint8_t expected_name, size_t expected_size) {
- int r;
-
- pa_assert(u);
- pa_assert(u->service_fd >= 0);
- pa_assert(rsp);
-
- if ((r = service_recv(u, rsp, room)) < 0)
- return r;
-
- if ((rsp->type != BT_INDICATION && rsp->type != BT_RESPONSE) ||
- rsp->name != expected_name ||
- (expected_size > 0 && rsp->length != expected_size)) {
-
- if (rsp->type == BT_ERROR && rsp->length == sizeof(bt_audio_error_t))
- pa_log_error("Received error condition: %s", pa_cstrerror(((bt_audio_error_t*) rsp)->posix_errno));
- else
- pa_log_error("Bogus message %s received while %s was expected",
- pa_strnull(bt_audio_strname(rsp->name)),
- pa_strnull(bt_audio_strname(expected_name)));
- return -1;
- }
-
- return 0;
-}
-
-/* Run from main thread */
-static int parse_caps(struct userdata *u, uint8_t seid, const struct bt_get_capabilities_rsp *rsp) {
- uint16_t bytes_left;
- const codec_capabilities_t *codec;
-
- pa_assert(u);
- pa_assert(rsp);
-
- bytes_left = rsp->h.length - sizeof(*rsp);
-
- if (bytes_left < sizeof(codec_capabilities_t)) {
- pa_log_error("Packet too small to store codec information.");
- return -1;
- }
-
- codec = (codec_capabilities_t *) rsp->data; /** ALIGNMENT? **/
-
- pa_log_debug("Payload size is %lu %lu", (unsigned long) bytes_left, (unsigned long) sizeof(*codec));
-
- if ((u->profile == PROFILE_A2DP && codec->transport != BT_CAPABILITIES_TRANSPORT_A2DP) ||
- (u->profile == PROFILE_HSP && codec->transport != BT_CAPABILITIES_TRANSPORT_SCO)) {
- pa_log_error("Got capabilities for wrong codec.");
- return -1;
- }
-
- if (u->profile == PROFILE_HSP) {
-
- if (bytes_left <= 0 || codec->length != sizeof(u->hsp.pcm_capabilities))
- return -1;
-
- pa_assert(codec->type == BT_HFP_CODEC_PCM);
-
- if (codec->configured && seid == 0)
- return codec->seid;
-
- memcpy(&u->hsp.pcm_capabilities, codec, sizeof(u->hsp.pcm_capabilities));
-
- } else if (u->profile == PROFILE_A2DP) {
-
- while (bytes_left > 0) {
- if ((codec->type == BT_A2DP_SBC_SINK) && !codec->lock)
- break;
-
- bytes_left -= codec->length;
- codec = (const codec_capabilities_t*) ((const uint8_t*) codec + codec->length);
- }
-
- if (bytes_left <= 0 || codec->length != sizeof(u->a2dp.sbc_capabilities))
- return -1;
-
- pa_assert(codec->type == BT_A2DP_SBC_SINK);
-
- if (codec->configured && seid == 0)
- return codec->seid;
-
- memcpy(&u->a2dp.sbc_capabilities, codec, sizeof(u->a2dp.sbc_capabilities));
- }
-
- return 0;
-}
-
-/* Run from main thread */
-static int get_caps(struct userdata *u, uint8_t seid) {
- union {
- struct bt_get_capabilities_req getcaps_req;
- struct bt_get_capabilities_rsp getcaps_rsp;
- bt_audio_error_t error;
- uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
- } msg;
- int ret;
-
- pa_assert(u);
-
- memset(&msg, 0, sizeof(msg));
- msg.getcaps_req.h.type = BT_REQUEST;
- msg.getcaps_req.h.name = BT_GET_CAPABILITIES;
- msg.getcaps_req.h.length = sizeof(msg.getcaps_req);
- msg.getcaps_req.seid = seid;
-
- pa_strlcpy(msg.getcaps_req.object, u->path, sizeof(msg.getcaps_req.object));
- if (u->profile == PROFILE_A2DP)
- msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
- else {
- pa_assert(u->profile == PROFILE_HSP);
- msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_SCO;
- }
- msg.getcaps_req.flags = BT_FLAG_AUTOCONNECT;
-
- if (service_send(u, &msg.getcaps_req.h) < 0)
- return -1;
-
- if (service_expect(u, &msg.getcaps_rsp.h, sizeof(msg), BT_GET_CAPABILITIES, 0) < 0)
- return -1;
-
- ret = parse_caps(u, seid, &msg.getcaps_rsp);
- if (ret <= 0)
- return ret;
-
- return get_caps(u, ret);
-}
-
-/* Run from main thread */
-static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) {
-
- switch (freq) {
- case BT_SBC_SAMPLING_FREQ_16000:
- case BT_SBC_SAMPLING_FREQ_32000:
- return 53;
-
- case BT_SBC_SAMPLING_FREQ_44100:
-
- switch (mode) {
- case BT_A2DP_CHANNEL_MODE_MONO:
- case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
- return 31;
-
- case BT_A2DP_CHANNEL_MODE_STEREO:
- case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
- return 53;
-
- default:
- pa_log_warn("Invalid channel mode %u", mode);
- return 53;
- }
-
- case BT_SBC_SAMPLING_FREQ_48000:
-
- switch (mode) {
- case BT_A2DP_CHANNEL_MODE_MONO:
- case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
- return 29;
-
- case BT_A2DP_CHANNEL_MODE_STEREO:
- case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
- return 51;
-
- default:
- pa_log_warn("Invalid channel mode %u", mode);
- return 51;
- }
-
- default:
- pa_log_warn("Invalid sampling freq %u", freq);
- return 53;
- }
-}
-
-/* Run from main thread */
-static int setup_a2dp(struct userdata *u) {
- sbc_capabilities_t *cap;
- int i;
-
- static const struct {
- uint32_t rate;
- uint8_t cap;
- } freq_table[] = {
- { 16000U, BT_SBC_SAMPLING_FREQ_16000 },
- { 32000U, BT_SBC_SAMPLING_FREQ_32000 },
- { 44100U, BT_SBC_SAMPLING_FREQ_44100 },
- { 48000U, BT_SBC_SAMPLING_FREQ_48000 }
- };