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