1 /** @file
2 * @brief Advance Audio Distribution Profile.
3 */
4
5 /*
6 * Copyright (c) 2015-2016 Intel Corporation
7 *
8 * SPDX-License-Identifier: Apache-2.0
9 */
10
11 #include <zephyr/kernel.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <zephyr/sys/atomic.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/sys/util.h>
17 #include <zephyr/sys/printk.h>
18
19 #include <zephyr/bluetooth/bluetooth.h>
20 #include <zephyr/bluetooth/l2cap.h>
21 #include <zephyr/bluetooth/avdtp.h>
22 #include <zephyr/bluetooth/a2dp.h>
23
24 #include "common/assert.h"
25
26 #include "hci_core.h"
27 #include "conn_internal.h"
28 #include "avdtp_internal.h"
29 #include "a2dp_internal.h"
30
31 #define LOG_LEVEL CONFIG_BT_A2DP_LOG_LEVEL
32 #include <zephyr/logging/log.h>
33 LOG_MODULE_REGISTER(bt_a2dp);
34
35 #define A2DP_NO_SPACE (-1)
36
37 struct bt_a2dp {
38 struct bt_avdtp session;
39 };
40
41 /* Connections */
42 static struct bt_a2dp connection[CONFIG_BT_MAX_CONN];
43
a2d_reset(struct bt_a2dp * a2dp_conn)44 void a2d_reset(struct bt_a2dp *a2dp_conn)
45 {
46 (void)memset(a2dp_conn, 0, sizeof(struct bt_a2dp));
47 }
48
get_new_connection(struct bt_conn * conn)49 struct bt_a2dp *get_new_connection(struct bt_conn *conn)
50 {
51 int8_t i, free;
52
53 free = A2DP_NO_SPACE;
54
55 if (!conn) {
56 LOG_ERR("Invalid Input (err: %d)", -EINVAL);
57 return NULL;
58 }
59
60 /* Find a space */
61 for (i = 0; i < CONFIG_BT_MAX_CONN; i++) {
62 if (connection[i].session.br_chan.chan.conn == conn) {
63 LOG_DBG("Conn already exists");
64 return NULL;
65 }
66
67 if (!connection[i].session.br_chan.chan.conn &&
68 free == A2DP_NO_SPACE) {
69 free = i;
70 }
71 }
72
73 if (free == A2DP_NO_SPACE) {
74 LOG_DBG("More connection cannot be supported");
75 return NULL;
76 }
77
78 /* Clean the memory area before returning */
79 a2d_reset(&connection[free]);
80
81 return &connection[free];
82 }
83
a2dp_accept(struct bt_conn * conn,struct bt_avdtp ** session)84 int a2dp_accept(struct bt_conn *conn, struct bt_avdtp **session)
85 {
86 struct bt_a2dp *a2dp_conn;
87
88 a2dp_conn = get_new_connection(conn);
89 if (!a2dp_conn) {
90 return -ENOMEM;
91 }
92
93 *session = &(a2dp_conn->session);
94 LOG_DBG("session: %p", &(a2dp_conn->session));
95
96 return 0;
97 }
98
99 /* Callback for incoming requests */
100 static struct bt_avdtp_ind_cb cb_ind = {
101 /*TODO*/
102 };
103
104 /* The above callback structures need to be packed and passed to AVDTP */
105 static struct bt_avdtp_event_cb avdtp_cb = {
106 .ind = &cb_ind,
107 .accept = a2dp_accept
108 };
109
bt_a2dp_init(void)110 int bt_a2dp_init(void)
111 {
112 int err;
113
114 /* Register event handlers with AVDTP */
115 err = bt_avdtp_register(&avdtp_cb);
116 if (err < 0) {
117 LOG_ERR("A2DP registration failed");
118 return err;
119 }
120
121 LOG_DBG("A2DP Initialized successfully.");
122 return 0;
123 }
124
bt_a2dp_connect(struct bt_conn * conn)125 struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn)
126 {
127 struct bt_a2dp *a2dp_conn;
128 int err;
129
130 a2dp_conn = get_new_connection(conn);
131 if (!a2dp_conn) {
132 LOG_ERR("Cannot allocate memory");
133 return NULL;
134 }
135
136 err = bt_avdtp_connect(conn, &(a2dp_conn->session));
137 if (err < 0) {
138 /* If error occurs, undo the saving and return the error */
139 a2d_reset(a2dp_conn);
140 LOG_DBG("AVDTP Connect failed");
141 return NULL;
142 }
143
144 LOG_DBG("Connect request sent");
145 return a2dp_conn;
146 }
147
bt_a2dp_register_endpoint(struct bt_a2dp_endpoint * endpoint,uint8_t media_type,uint8_t role)148 int bt_a2dp_register_endpoint(struct bt_a2dp_endpoint *endpoint,
149 uint8_t media_type, uint8_t role)
150 {
151 int err;
152
153 BT_ASSERT(endpoint);
154
155 err = bt_avdtp_register_sep(media_type, role, &(endpoint->info));
156 if (err < 0) {
157 return err;
158 }
159
160 /* TODO: Register SDP record */
161
162 return 0;
163 }
164