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