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