| /** @file |
| * @brief Advance Audio Distribution Profile. |
| */ |
| |
| /* |
| * Copyright (c) 2015-2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/kernel.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <zephyr/sys/atomic.h> |
| #include <zephyr/sys/byteorder.h> |
| #include <zephyr/sys/util.h> |
| #include <zephyr/sys/printk.h> |
| |
| #include <zephyr/bluetooth/bluetooth.h> |
| #include <zephyr/bluetooth/l2cap.h> |
| #include <zephyr/bluetooth/avdtp.h> |
| #include <zephyr/bluetooth/a2dp.h> |
| |
| #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_A2DP) |
| #define LOG_MODULE_NAME bt_a2dp |
| #include "common/log.h" |
| |
| #include "hci_core.h" |
| #include "conn_internal.h" |
| #include "avdtp_internal.h" |
| #include "a2dp_internal.h" |
| |
| #define A2DP_NO_SPACE (-1) |
| |
| struct bt_a2dp { |
| struct bt_avdtp session; |
| }; |
| |
| /* Connections */ |
| static struct bt_a2dp connection[CONFIG_BT_MAX_CONN]; |
| |
| void a2d_reset(struct bt_a2dp *a2dp_conn) |
| { |
| (void)memset(a2dp_conn, 0, sizeof(struct bt_a2dp)); |
| } |
| |
| struct bt_a2dp *get_new_connection(struct bt_conn *conn) |
| { |
| int8_t i, free; |
| |
| free = A2DP_NO_SPACE; |
| |
| if (!conn) { |
| BT_ERR("Invalid Input (err: %d)", -EINVAL); |
| return NULL; |
| } |
| |
| /* Find a space */ |
| for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { |
| if (connection[i].session.br_chan.chan.conn == conn) { |
| BT_DBG("Conn already exists"); |
| return NULL; |
| } |
| |
| if (!connection[i].session.br_chan.chan.conn && |
| free == A2DP_NO_SPACE) { |
| free = i; |
| } |
| } |
| |
| if (free == A2DP_NO_SPACE) { |
| BT_DBG("More connection cannot be supported"); |
| return NULL; |
| } |
| |
| /* Clean the memory area before returning */ |
| a2d_reset(&connection[free]); |
| |
| return &connection[free]; |
| } |
| |
| int a2dp_accept(struct bt_conn *conn, struct bt_avdtp **session) |
| { |
| struct bt_a2dp *a2dp_conn; |
| |
| a2dp_conn = get_new_connection(conn); |
| if (!a2dp_conn) { |
| return -ENOMEM; |
| } |
| |
| *session = &(a2dp_conn->session); |
| BT_DBG("session: %p", &(a2dp_conn->session)); |
| |
| return 0; |
| } |
| |
| /* Callback for incoming requests */ |
| static struct bt_avdtp_ind_cb cb_ind = { |
| /*TODO*/ |
| }; |
| |
| /* The above callback structures need to be packed and passed to AVDTP */ |
| static struct bt_avdtp_event_cb avdtp_cb = { |
| .ind = &cb_ind, |
| .accept = a2dp_accept |
| }; |
| |
| int bt_a2dp_init(void) |
| { |
| int err; |
| |
| /* Register event handlers with AVDTP */ |
| err = bt_avdtp_register(&avdtp_cb); |
| if (err < 0) { |
| BT_ERR("A2DP registration failed"); |
| return err; |
| } |
| |
| BT_DBG("A2DP Initialized successfully."); |
| return 0; |
| } |
| |
| struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn) |
| { |
| struct bt_a2dp *a2dp_conn; |
| int err; |
| |
| a2dp_conn = get_new_connection(conn); |
| if (!a2dp_conn) { |
| BT_ERR("Cannot allocate memory"); |
| return NULL; |
| } |
| |
| err = bt_avdtp_connect(conn, &(a2dp_conn->session)); |
| if (err < 0) { |
| /* If error occurs, undo the saving and return the error */ |
| a2d_reset(a2dp_conn); |
| BT_DBG("AVDTP Connect failed"); |
| return NULL; |
| } |
| |
| BT_DBG("Connect request sent"); |
| return a2dp_conn; |
| } |
| |
| int bt_a2dp_register_endpoint(struct bt_a2dp_endpoint *endpoint, |
| uint8_t media_type, uint8_t role) |
| { |
| int err; |
| |
| BT_ASSERT(endpoint); |
| |
| err = bt_avdtp_register_sep(media_type, role, &(endpoint->info)); |
| if (err < 0) { |
| return err; |
| } |
| |
| /* TODO: Register SDP record */ |
| |
| return 0; |
| } |