xref: /freebsd/lib/virtual_oss/bt/avdtp.c (revision 9cab9fde5edad9b409dd2317a2aec7815e6d6bed)
1*9cab9fdeSChristos Margiolis /* $NetBSD$ */
2*9cab9fdeSChristos Margiolis 
3*9cab9fdeSChristos Margiolis /*-
4*9cab9fdeSChristos Margiolis  * Copyright (c) 2015-2016 Nathanial Sloss <nathanialsloss@yahoo.com.au>
5*9cab9fdeSChristos Margiolis  * Copyright (c) 2016-2019 Hans Petter Selasky <hps@selasky.org>
6*9cab9fdeSChristos Margiolis  * Copyright (c) 2019 Google LLC, written by Richard Kralovic <riso@google.com>
7*9cab9fdeSChristos Margiolis  *
8*9cab9fdeSChristos Margiolis  *		This software is dedicated to the memory of -
9*9cab9fdeSChristos Margiolis  *	   Baron James Anlezark (Barry) - 1 Jan 1949 - 13 May 2012.
10*9cab9fdeSChristos Margiolis  *
11*9cab9fdeSChristos Margiolis  *		Barry was a man who loved his music.
12*9cab9fdeSChristos Margiolis  *
13*9cab9fdeSChristos Margiolis  * Redistribution and use in source and binary forms, with or without
14*9cab9fdeSChristos Margiolis  * modification, are permitted provided that the following conditions
15*9cab9fdeSChristos Margiolis  * are met:
16*9cab9fdeSChristos Margiolis  * 1. Redistributions of source code must retain the above copyright
17*9cab9fdeSChristos Margiolis  *    notice, this list of conditions and the following disclaimer.
18*9cab9fdeSChristos Margiolis  * 2. Redistributions in binary form must reproduce the above copyright
19*9cab9fdeSChristos Margiolis  *    notice, this list of conditions and the following disclaimer in the
20*9cab9fdeSChristos Margiolis  *    documentation and/or other materials provided with the distribution.
21*9cab9fdeSChristos Margiolis  *
22*9cab9fdeSChristos Margiolis  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23*9cab9fdeSChristos Margiolis  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24*9cab9fdeSChristos Margiolis  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25*9cab9fdeSChristos Margiolis  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26*9cab9fdeSChristos Margiolis  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27*9cab9fdeSChristos Margiolis  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28*9cab9fdeSChristos Margiolis  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29*9cab9fdeSChristos Margiolis  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30*9cab9fdeSChristos Margiolis  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31*9cab9fdeSChristos Margiolis  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32*9cab9fdeSChristos Margiolis  * POSSIBILITY OF SUCH DAMAGE.
33*9cab9fdeSChristos Margiolis  */
34*9cab9fdeSChristos Margiolis 
35*9cab9fdeSChristos Margiolis #include <sys/uio.h>
36*9cab9fdeSChristos Margiolis 
37*9cab9fdeSChristos Margiolis #include <stdio.h>
38*9cab9fdeSChristos Margiolis #include <errno.h>
39*9cab9fdeSChristos Margiolis #include <stdlib.h>
40*9cab9fdeSChristos Margiolis #include <string.h>
41*9cab9fdeSChristos Margiolis #include <unistd.h>
42*9cab9fdeSChristos Margiolis 
43*9cab9fdeSChristos Margiolis #include "avdtp_signal.h"
44*9cab9fdeSChristos Margiolis #include "bt.h"
45*9cab9fdeSChristos Margiolis 
46*9cab9fdeSChristos Margiolis #define	DPRINTF(...) printf("backend_bt: " __VA_ARGS__)
47*9cab9fdeSChristos Margiolis 
48*9cab9fdeSChristos Margiolis struct avdtpGetPacketInfo {
49*9cab9fdeSChristos Margiolis 	uint8_t buffer_data[512];
50*9cab9fdeSChristos Margiolis 	uint16_t buffer_len;
51*9cab9fdeSChristos Margiolis 	uint8_t trans;
52*9cab9fdeSChristos Margiolis 	uint8_t signalID;
53*9cab9fdeSChristos Margiolis };
54*9cab9fdeSChristos Margiolis 
55*9cab9fdeSChristos Margiolis static int avdtpAutoConfig(struct bt_config *);
56*9cab9fdeSChristos Margiolis 
57*9cab9fdeSChristos Margiolis /* Return received message type if success, < 0 if failure. */
58*9cab9fdeSChristos Margiolis static int
avdtpGetPacket(int fd,struct avdtpGetPacketInfo * info)59*9cab9fdeSChristos Margiolis avdtpGetPacket(int fd, struct avdtpGetPacketInfo *info)
60*9cab9fdeSChristos Margiolis {
61*9cab9fdeSChristos Margiolis 	uint8_t *pos = info->buffer_data;
62*9cab9fdeSChristos Margiolis 	uint8_t *end = info->buffer_data + sizeof(info->buffer_data);
63*9cab9fdeSChristos Margiolis 	uint8_t message_type;
64*9cab9fdeSChristos Margiolis 	int len;
65*9cab9fdeSChristos Margiolis 
66*9cab9fdeSChristos Margiolis 	memset(info, 0, sizeof(*info));
67*9cab9fdeSChristos Margiolis 
68*9cab9fdeSChristos Margiolis 	/* Handle fragmented packets */
69*9cab9fdeSChristos Margiolis 	for (int remaining = 1; remaining > 0; --remaining) {
70*9cab9fdeSChristos Margiolis 		len = read(fd, pos, end - pos);
71*9cab9fdeSChristos Margiolis 
72*9cab9fdeSChristos Margiolis 		if (len < AVDTP_LEN_SUCCESS)
73*9cab9fdeSChristos Margiolis 			return (-1);
74*9cab9fdeSChristos Margiolis 		if (len == (int)(end - pos))
75*9cab9fdeSChristos Margiolis 			return (-1);	/* buffer too small */
76*9cab9fdeSChristos Margiolis 
77*9cab9fdeSChristos Margiolis 		uint8_t trans = (pos[0] & TRANSACTIONLABEL) >> TRANSACTIONLABEL_S;
78*9cab9fdeSChristos Margiolis 		uint8_t packet_type = (pos[0] & PACKETTYPE) >> PACKETTYPE_S;
79*9cab9fdeSChristos Margiolis 		uint8_t current_message_type = (info->buffer_data[0] & MESSAGETYPE);
80*9cab9fdeSChristos Margiolis 		uint8_t shift;
81*9cab9fdeSChristos Margiolis 		if (pos == info->buffer_data) {
82*9cab9fdeSChristos Margiolis 			info->trans = trans;
83*9cab9fdeSChristos Margiolis 			message_type = current_message_type;
84*9cab9fdeSChristos Margiolis 			if (packet_type == singlePacket) {
85*9cab9fdeSChristos Margiolis 				info->signalID = (pos[1] & SIGNALID_MASK);
86*9cab9fdeSChristos Margiolis 				shift = 2;
87*9cab9fdeSChristos Margiolis 			} else {
88*9cab9fdeSChristos Margiolis 				if (packet_type != startPacket)
89*9cab9fdeSChristos Margiolis 					return (-1);
90*9cab9fdeSChristos Margiolis 				remaining = pos[1];
91*9cab9fdeSChristos Margiolis 				info->signalID = (pos[2] & SIGNALID_MASK);
92*9cab9fdeSChristos Margiolis 				shift = 3;
93*9cab9fdeSChristos Margiolis 			}
94*9cab9fdeSChristos Margiolis 		} else {
95*9cab9fdeSChristos Margiolis 			if (info->trans != trans ||
96*9cab9fdeSChristos Margiolis 			    message_type != current_message_type ||
97*9cab9fdeSChristos Margiolis 			    (remaining == 1 && packet_type != endPacket) ||
98*9cab9fdeSChristos Margiolis 			    (remaining > 1 && packet_type != continuePacket)) {
99*9cab9fdeSChristos Margiolis 				return (-1);
100*9cab9fdeSChristos Margiolis 			}
101*9cab9fdeSChristos Margiolis 			shift = 1;
102*9cab9fdeSChristos Margiolis 		}
103*9cab9fdeSChristos Margiolis 		memmove(pos, pos + shift, len);
104*9cab9fdeSChristos Margiolis 		pos += len;
105*9cab9fdeSChristos Margiolis 	}
106*9cab9fdeSChristos Margiolis 	info->buffer_len = pos - info->buffer_data;
107*9cab9fdeSChristos Margiolis 	return (message_type);
108*9cab9fdeSChristos Margiolis }
109*9cab9fdeSChristos Margiolis 
110*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
111*9cab9fdeSChristos Margiolis static int
avdtpSendPacket(int fd,uint8_t command,uint8_t trans,uint8_t type,uint8_t * data0,int datasize0,uint8_t * data1,int datasize1)112*9cab9fdeSChristos Margiolis avdtpSendPacket(int fd, uint8_t command, uint8_t trans, uint8_t type,
113*9cab9fdeSChristos Margiolis     uint8_t * data0, int datasize0, uint8_t * data1,
114*9cab9fdeSChristos Margiolis     int datasize1)
115*9cab9fdeSChristos Margiolis {
116*9cab9fdeSChristos Margiolis 	struct iovec iov[3];
117*9cab9fdeSChristos Margiolis 	uint8_t header[2];
118*9cab9fdeSChristos Margiolis 	int retval;
119*9cab9fdeSChristos Margiolis 
120*9cab9fdeSChristos Margiolis 	/* fill out command header */
121*9cab9fdeSChristos Margiolis 	header[0] = (trans << 4) | (type & 3);
122*9cab9fdeSChristos Margiolis 	if (command != 0)
123*9cab9fdeSChristos Margiolis 		header[1] = command & 0x3f;
124*9cab9fdeSChristos Margiolis 	else
125*9cab9fdeSChristos Margiolis 		header[1] = 3;
126*9cab9fdeSChristos Margiolis 
127*9cab9fdeSChristos Margiolis 	iov[0].iov_base = header;
128*9cab9fdeSChristos Margiolis 	iov[0].iov_len = 2;
129*9cab9fdeSChristos Margiolis 	iov[1].iov_base = data0;
130*9cab9fdeSChristos Margiolis 	iov[1].iov_len = datasize0;
131*9cab9fdeSChristos Margiolis 	iov[2].iov_base = data1;
132*9cab9fdeSChristos Margiolis 	iov[2].iov_len = datasize1;
133*9cab9fdeSChristos Margiolis 
134*9cab9fdeSChristos Margiolis 	retval = writev(fd, iov, 3);
135*9cab9fdeSChristos Margiolis 	if (retval != (2 + datasize0 + datasize1))
136*9cab9fdeSChristos Margiolis 		return (-EINVAL);
137*9cab9fdeSChristos Margiolis 	else
138*9cab9fdeSChristos Margiolis 		return (0);
139*9cab9fdeSChristos Margiolis }
140*9cab9fdeSChristos Margiolis 
141*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
142*9cab9fdeSChristos Margiolis static int
avdtpSendSyncCommand(int fd,struct avdtpGetPacketInfo * info,uint8_t command,uint8_t type,uint8_t * data0,int datasize0,uint8_t * data1,int datasize1)143*9cab9fdeSChristos Margiolis avdtpSendSyncCommand(int fd, struct avdtpGetPacketInfo *info,
144*9cab9fdeSChristos Margiolis     uint8_t command, uint8_t type, uint8_t * data0,
145*9cab9fdeSChristos Margiolis     int datasize0, uint8_t * data1, int datasize1)
146*9cab9fdeSChristos Margiolis {
147*9cab9fdeSChristos Margiolis 	static uint8_t transLabel;
148*9cab9fdeSChristos Margiolis 	uint8_t trans;
149*9cab9fdeSChristos Margiolis 	int retval;
150*9cab9fdeSChristos Margiolis 
151*9cab9fdeSChristos Margiolis 	alarm(8);			/* set timeout */
152*9cab9fdeSChristos Margiolis 
153*9cab9fdeSChristos Margiolis 	trans = (transLabel++) & 0xF;
154*9cab9fdeSChristos Margiolis 
155*9cab9fdeSChristos Margiolis 	retval = avdtpSendPacket(fd, command, trans, type,
156*9cab9fdeSChristos Margiolis 	    data0, datasize0, data1, datasize1);
157*9cab9fdeSChristos Margiolis 	if (retval)
158*9cab9fdeSChristos Margiolis 		goto done;
159*9cab9fdeSChristos Margiolis retry:
160*9cab9fdeSChristos Margiolis 	switch (avdtpGetPacket(fd, info)) {
161*9cab9fdeSChristos Margiolis 	case RESPONSEACCEPT:
162*9cab9fdeSChristos Margiolis 		if (info->trans != trans)
163*9cab9fdeSChristos Margiolis 			goto retry;
164*9cab9fdeSChristos Margiolis 		retval = 0;
165*9cab9fdeSChristos Margiolis 		break;
166*9cab9fdeSChristos Margiolis 	case RESPONSEREJECT:
167*9cab9fdeSChristos Margiolis 		if (info->trans != trans)
168*9cab9fdeSChristos Margiolis 			goto retry;
169*9cab9fdeSChristos Margiolis 		retval = -EINVAL;
170*9cab9fdeSChristos Margiolis 		break;
171*9cab9fdeSChristos Margiolis 	case COMMAND:
172*9cab9fdeSChristos Margiolis 		retval = avdtpSendReject(fd, info->trans, info->signalID);
173*9cab9fdeSChristos Margiolis 		if (retval == 0)
174*9cab9fdeSChristos Margiolis 			goto retry;
175*9cab9fdeSChristos Margiolis 		break;
176*9cab9fdeSChristos Margiolis 	default:
177*9cab9fdeSChristos Margiolis 		retval = -ENXIO;
178*9cab9fdeSChristos Margiolis 		break;
179*9cab9fdeSChristos Margiolis 	}
180*9cab9fdeSChristos Margiolis done:
181*9cab9fdeSChristos Margiolis 	alarm(0);			/* clear timeout */
182*9cab9fdeSChristos Margiolis 
183*9cab9fdeSChristos Margiolis 	return (retval);
184*9cab9fdeSChristos Margiolis }
185*9cab9fdeSChristos Margiolis 
186*9cab9fdeSChristos Margiolis /*
187*9cab9fdeSChristos Margiolis  * Variant for acceptor role: We support any frequency, blocks, bands, and
188*9cab9fdeSChristos Margiolis  * allocation. Returns 0 on success, < 0 on failure.
189*9cab9fdeSChristos Margiolis  */
190*9cab9fdeSChristos Margiolis static int
avdtpSendCapabilitiesResponseSBCForACP(int fd,int trans)191*9cab9fdeSChristos Margiolis avdtpSendCapabilitiesResponseSBCForACP(int fd, int trans)
192*9cab9fdeSChristos Margiolis {
193*9cab9fdeSChristos Margiolis 	uint8_t data[10];
194*9cab9fdeSChristos Margiolis 
195*9cab9fdeSChristos Margiolis 	data[0] = mediaTransport;
196*9cab9fdeSChristos Margiolis 	data[1] = 0;
197*9cab9fdeSChristos Margiolis 	data[2] = mediaCodec;
198*9cab9fdeSChristos Margiolis 	data[3] = 0x6;
199*9cab9fdeSChristos Margiolis 	data[4] = mediaTypeAudio;
200*9cab9fdeSChristos Margiolis 	data[5] = SBC_CODEC_ID;
201*9cab9fdeSChristos Margiolis 	data[6] =
202*9cab9fdeSChristos Margiolis 	    (1 << (3 - MODE_STEREO)) |
203*9cab9fdeSChristos Margiolis 	    (1 << (3 - MODE_JOINT)) |
204*9cab9fdeSChristos Margiolis 	    (1 << (3 - MODE_DUAL)) |
205*9cab9fdeSChristos Margiolis 	    (1 << (3 - MODE_MONO)) |
206*9cab9fdeSChristos Margiolis 	    (1 << (7 - FREQ_44_1K)) |
207*9cab9fdeSChristos Margiolis 	    (1 << (7 - FREQ_48K)) |
208*9cab9fdeSChristos Margiolis 	    (1 << (7 - FREQ_32K)) |
209*9cab9fdeSChristos Margiolis 	    (1 << (7 - FREQ_16K));
210*9cab9fdeSChristos Margiolis 	data[7] =
211*9cab9fdeSChristos Margiolis 	    (1 << (7 - BLOCKS_4)) |
212*9cab9fdeSChristos Margiolis 	    (1 << (7 - BLOCKS_8)) |
213*9cab9fdeSChristos Margiolis 	    (1 << (7 - BLOCKS_12)) |
214*9cab9fdeSChristos Margiolis 	    (1 << (7 - BLOCKS_16)) |
215*9cab9fdeSChristos Margiolis 	    (1 << (3 - BANDS_4)) |
216*9cab9fdeSChristos Margiolis 	    (1 << (3 - BANDS_8)) | (1 << ALLOC_LOUDNESS) | (1 << ALLOC_SNR);
217*9cab9fdeSChristos Margiolis 	data[8] = MIN_BITPOOL;
218*9cab9fdeSChristos Margiolis 	data[9] = DEFAULT_MAXBPOOL;
219*9cab9fdeSChristos Margiolis 
220*9cab9fdeSChristos Margiolis 	return (avdtpSendPacket(fd, AVDTP_GET_CAPABILITIES, trans,
221*9cab9fdeSChristos Margiolis 	    RESPONSEACCEPT, data, sizeof(data), NULL, 0));
222*9cab9fdeSChristos Margiolis }
223*9cab9fdeSChristos Margiolis 
224*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
225*9cab9fdeSChristos Margiolis int
avdtpSendAccept(int fd,uint8_t trans,uint8_t myCommand)226*9cab9fdeSChristos Margiolis avdtpSendAccept(int fd, uint8_t trans, uint8_t myCommand)
227*9cab9fdeSChristos Margiolis {
228*9cab9fdeSChristos Margiolis 	return (avdtpSendPacket(fd, myCommand, trans, RESPONSEACCEPT,
229*9cab9fdeSChristos Margiolis 	    NULL, 0, NULL, 0));
230*9cab9fdeSChristos Margiolis }
231*9cab9fdeSChristos Margiolis 
232*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
233*9cab9fdeSChristos Margiolis int
avdtpSendReject(int fd,uint8_t trans,uint8_t myCommand)234*9cab9fdeSChristos Margiolis avdtpSendReject(int fd, uint8_t trans, uint8_t myCommand)
235*9cab9fdeSChristos Margiolis {
236*9cab9fdeSChristos Margiolis 	uint8_t value = 0;
237*9cab9fdeSChristos Margiolis 
238*9cab9fdeSChristos Margiolis 	return (avdtpSendPacket(fd, myCommand, trans, RESPONSEREJECT,
239*9cab9fdeSChristos Margiolis 	    &value, 1, NULL, 0));
240*9cab9fdeSChristos Margiolis }
241*9cab9fdeSChristos Margiolis 
242*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
243*9cab9fdeSChristos Margiolis int
avdtpSendDiscResponseAudio(int fd,uint8_t trans,uint8_t mySep,uint8_t is_sink)244*9cab9fdeSChristos Margiolis avdtpSendDiscResponseAudio(int fd, uint8_t trans,
245*9cab9fdeSChristos Margiolis     uint8_t mySep, uint8_t is_sink)
246*9cab9fdeSChristos Margiolis {
247*9cab9fdeSChristos Margiolis 	uint8_t data[2];
248*9cab9fdeSChristos Margiolis 
249*9cab9fdeSChristos Margiolis 	data[0] = mySep << 2;
250*9cab9fdeSChristos Margiolis 	data[1] = mediaTypeAudio << 4 | (is_sink ? (1 << 3) : 0);
251*9cab9fdeSChristos Margiolis 
252*9cab9fdeSChristos Margiolis 	return (avdtpSendPacket(fd, AVDTP_DISCOVER, trans, RESPONSEACCEPT,
253*9cab9fdeSChristos Margiolis 	    data, 2, NULL, 0));
254*9cab9fdeSChristos Margiolis }
255*9cab9fdeSChristos Margiolis 
256*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
257*9cab9fdeSChristos Margiolis int
avdtpDiscoverAndConfig(struct bt_config * cfg,bool isSink)258*9cab9fdeSChristos Margiolis avdtpDiscoverAndConfig(struct bt_config *cfg, bool isSink)
259*9cab9fdeSChristos Margiolis {
260*9cab9fdeSChristos Margiolis 	struct avdtpGetPacketInfo info;
261*9cab9fdeSChristos Margiolis 	uint16_t offset;
262*9cab9fdeSChristos Margiolis 	uint8_t chmode = cfg->chmode;
263*9cab9fdeSChristos Margiolis 	uint8_t aacMode1 = cfg->aacMode1;
264*9cab9fdeSChristos Margiolis 	uint8_t aacMode2 = cfg->aacMode2;
265*9cab9fdeSChristos Margiolis 	int retval;
266*9cab9fdeSChristos Margiolis 
267*9cab9fdeSChristos Margiolis 	retval = avdtpSendSyncCommand(cfg->hc, &info, AVDTP_DISCOVER, 0,
268*9cab9fdeSChristos Margiolis 	    NULL, 0, NULL, 0);
269*9cab9fdeSChristos Margiolis 	if (retval)
270*9cab9fdeSChristos Margiolis 		return (retval);
271*9cab9fdeSChristos Margiolis 
272*9cab9fdeSChristos Margiolis 	retval = -EBUSY;
273*9cab9fdeSChristos Margiolis 	for (offset = 0; offset + 2 <= info.buffer_len; offset += 2) {
274*9cab9fdeSChristos Margiolis 		cfg->sep = info.buffer_data[offset] >> 2;
275*9cab9fdeSChristos Margiolis 		cfg->media_Type = info.buffer_data[offset + 1] >> 4;
276*9cab9fdeSChristos Margiolis 		cfg->chmode = chmode;
277*9cab9fdeSChristos Margiolis 		cfg->aacMode1 = aacMode1;
278*9cab9fdeSChristos Margiolis 		cfg->aacMode2 = aacMode2;
279*9cab9fdeSChristos Margiolis 		if (info.buffer_data[offset] & DISCOVER_SEP_IN_USE)
280*9cab9fdeSChristos Margiolis 			continue;
281*9cab9fdeSChristos Margiolis 		if (info.buffer_data[offset + 1] & DISCOVER_IS_SINK) {
282*9cab9fdeSChristos Margiolis 			if (!isSink)
283*9cab9fdeSChristos Margiolis 				continue;
284*9cab9fdeSChristos Margiolis 		} else {
285*9cab9fdeSChristos Margiolis 			if (isSink)
286*9cab9fdeSChristos Margiolis 				continue;
287*9cab9fdeSChristos Margiolis 		}
288*9cab9fdeSChristos Margiolis 		/* try to configure SBC */
289*9cab9fdeSChristos Margiolis 		retval = avdtpAutoConfig(cfg);
290*9cab9fdeSChristos Margiolis 		if (retval == 0)
291*9cab9fdeSChristos Margiolis 			return (0);
292*9cab9fdeSChristos Margiolis 	}
293*9cab9fdeSChristos Margiolis 	return (retval);
294*9cab9fdeSChristos Margiolis }
295*9cab9fdeSChristos Margiolis 
296*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
297*9cab9fdeSChristos Margiolis static int
avdtpGetCapabilities(int fd,uint8_t sep,struct avdtpGetPacketInfo * info)298*9cab9fdeSChristos Margiolis avdtpGetCapabilities(int fd, uint8_t sep, struct avdtpGetPacketInfo *info)
299*9cab9fdeSChristos Margiolis {
300*9cab9fdeSChristos Margiolis 	uint8_t address = (sep << 2);
301*9cab9fdeSChristos Margiolis 
302*9cab9fdeSChristos Margiolis 	return (avdtpSendSyncCommand(fd, info,
303*9cab9fdeSChristos Margiolis 	    AVDTP_GET_CAPABILITIES, 0, &address, 1,
304*9cab9fdeSChristos Margiolis 	    NULL, 0));
305*9cab9fdeSChristos Margiolis }
306*9cab9fdeSChristos Margiolis 
307*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
308*9cab9fdeSChristos Margiolis int
avdtpSetConfiguration(int fd,uint8_t sep,uint8_t * data,int datasize)309*9cab9fdeSChristos Margiolis avdtpSetConfiguration(int fd, uint8_t sep, uint8_t * data, int datasize)
310*9cab9fdeSChristos Margiolis {
311*9cab9fdeSChristos Margiolis 	struct avdtpGetPacketInfo info;
312*9cab9fdeSChristos Margiolis 	uint8_t configAddresses[2];
313*9cab9fdeSChristos Margiolis 
314*9cab9fdeSChristos Margiolis 	configAddresses[0] = sep << 2;
315*9cab9fdeSChristos Margiolis 	configAddresses[1] = INTSEP << 2;
316*9cab9fdeSChristos Margiolis 
317*9cab9fdeSChristos Margiolis 	return (avdtpSendSyncCommand(fd, &info, AVDTP_SET_CONFIGURATION, 0,
318*9cab9fdeSChristos Margiolis 	    configAddresses, 2, data, datasize));
319*9cab9fdeSChristos Margiolis }
320*9cab9fdeSChristos Margiolis 
321*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
322*9cab9fdeSChristos Margiolis int
avdtpOpen(int fd,uint8_t sep)323*9cab9fdeSChristos Margiolis avdtpOpen(int fd, uint8_t sep)
324*9cab9fdeSChristos Margiolis {
325*9cab9fdeSChristos Margiolis 	struct avdtpGetPacketInfo info;
326*9cab9fdeSChristos Margiolis 	uint8_t address = sep << 2;
327*9cab9fdeSChristos Margiolis 
328*9cab9fdeSChristos Margiolis 	return (avdtpSendSyncCommand(fd, &info, AVDTP_OPEN, 0,
329*9cab9fdeSChristos Margiolis 	    &address, 1, NULL, 0));
330*9cab9fdeSChristos Margiolis }
331*9cab9fdeSChristos Margiolis 
332*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
333*9cab9fdeSChristos Margiolis int
avdtpStart(int fd,uint8_t sep)334*9cab9fdeSChristos Margiolis avdtpStart(int fd, uint8_t sep)
335*9cab9fdeSChristos Margiolis {
336*9cab9fdeSChristos Margiolis 	struct avdtpGetPacketInfo info;
337*9cab9fdeSChristos Margiolis 	uint8_t address = sep << 2;
338*9cab9fdeSChristos Margiolis 
339*9cab9fdeSChristos Margiolis 	return (avdtpSendSyncCommand(fd, &info, AVDTP_START, 0,
340*9cab9fdeSChristos Margiolis 	    &address, 1, NULL, 0));
341*9cab9fdeSChristos Margiolis }
342*9cab9fdeSChristos Margiolis 
343*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
344*9cab9fdeSChristos Margiolis int
avdtpClose(int fd,uint8_t sep)345*9cab9fdeSChristos Margiolis avdtpClose(int fd, uint8_t sep)
346*9cab9fdeSChristos Margiolis {
347*9cab9fdeSChristos Margiolis 	struct avdtpGetPacketInfo info;
348*9cab9fdeSChristos Margiolis 	uint8_t address = sep << 2;
349*9cab9fdeSChristos Margiolis 
350*9cab9fdeSChristos Margiolis 	return (avdtpSendSyncCommand(fd, &info, AVDTP_CLOSE, 0,
351*9cab9fdeSChristos Margiolis 	    &address, 1, NULL, 0));
352*9cab9fdeSChristos Margiolis }
353*9cab9fdeSChristos Margiolis 
354*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
355*9cab9fdeSChristos Margiolis int
avdtpSuspend(int fd,uint8_t sep)356*9cab9fdeSChristos Margiolis avdtpSuspend(int fd, uint8_t sep)
357*9cab9fdeSChristos Margiolis {
358*9cab9fdeSChristos Margiolis 	struct avdtpGetPacketInfo info;
359*9cab9fdeSChristos Margiolis 	uint8_t address = sep << 2;
360*9cab9fdeSChristos Margiolis 
361*9cab9fdeSChristos Margiolis 	return (avdtpSendSyncCommand(fd, &info, AVDTP_SUSPEND, 0,
362*9cab9fdeSChristos Margiolis 	    &address, 1, NULL, 0));
363*9cab9fdeSChristos Margiolis }
364*9cab9fdeSChristos Margiolis 
365*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
366*9cab9fdeSChristos Margiolis int
avdtpAbort(int fd,uint8_t sep)367*9cab9fdeSChristos Margiolis avdtpAbort(int fd, uint8_t sep)
368*9cab9fdeSChristos Margiolis {
369*9cab9fdeSChristos Margiolis 	struct avdtpGetPacketInfo info;
370*9cab9fdeSChristos Margiolis 	uint8_t address = sep << 2;
371*9cab9fdeSChristos Margiolis 
372*9cab9fdeSChristos Margiolis 	return (avdtpSendSyncCommand(fd, &info, AVDTP_ABORT, 0,
373*9cab9fdeSChristos Margiolis 	    &address, 1, NULL, 0));
374*9cab9fdeSChristos Margiolis }
375*9cab9fdeSChristos Margiolis 
376*9cab9fdeSChristos Margiolis static int
avdtpAutoConfig(struct bt_config * cfg)377*9cab9fdeSChristos Margiolis avdtpAutoConfig(struct bt_config *cfg)
378*9cab9fdeSChristos Margiolis {
379*9cab9fdeSChristos Margiolis 	struct avdtpGetPacketInfo info;
380*9cab9fdeSChristos Margiolis 	uint8_t freqmode;
381*9cab9fdeSChristos Margiolis 	uint8_t blk_len_sb_alloc;
382*9cab9fdeSChristos Margiolis 	uint8_t availFreqMode = 0;
383*9cab9fdeSChristos Margiolis 	uint8_t availConfig = 0;
384*9cab9fdeSChristos Margiolis 	uint8_t supBitpoolMin = 0;
385*9cab9fdeSChristos Margiolis 	uint8_t supBitpoolMax = 0;
386*9cab9fdeSChristos Margiolis 	uint8_t aacMode1 = 0;
387*9cab9fdeSChristos Margiolis 	uint8_t aacMode2 = 0;
388*9cab9fdeSChristos Margiolis #ifdef HAVE_LIBAV
389*9cab9fdeSChristos Margiolis 	uint8_t aacBitrate3 = 0;
390*9cab9fdeSChristos Margiolis 	uint8_t aacBitrate4 = 0;
391*9cab9fdeSChristos Margiolis 	uint8_t aacBitrate5 = 0;
392*9cab9fdeSChristos Margiolis #endif
393*9cab9fdeSChristos Margiolis 	int retval;
394*9cab9fdeSChristos Margiolis 	int i;
395*9cab9fdeSChristos Margiolis 
396*9cab9fdeSChristos Margiolis 	retval = avdtpGetCapabilities(cfg->hc, cfg->sep, &info);
397*9cab9fdeSChristos Margiolis 	if (retval) {
398*9cab9fdeSChristos Margiolis 		DPRINTF("Cannot get capabilities\n");
399*9cab9fdeSChristos Margiolis 		return (retval);
400*9cab9fdeSChristos Margiolis 	}
401*9cab9fdeSChristos Margiolis retry:
402*9cab9fdeSChristos Margiolis 	for (i = 0; (i + 1) < info.buffer_len;) {
403*9cab9fdeSChristos Margiolis #if 0
404*9cab9fdeSChristos Margiolis 		DPRINTF("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
405*9cab9fdeSChristos Margiolis 		    info.buffer_data[i + 0],
406*9cab9fdeSChristos Margiolis 		    info.buffer_data[i + 1],
407*9cab9fdeSChristos Margiolis 		    info.buffer_data[i + 2],
408*9cab9fdeSChristos Margiolis 		    info.buffer_data[i + 3],
409*9cab9fdeSChristos Margiolis 		    info.buffer_data[i + 4], info.buffer_data[i + 5]);
410*9cab9fdeSChristos Margiolis #endif
411*9cab9fdeSChristos Margiolis 		if (i + 2 + info.buffer_data[i + 1] > info.buffer_len)
412*9cab9fdeSChristos Margiolis 			break;
413*9cab9fdeSChristos Margiolis 		switch (info.buffer_data[i]) {
414*9cab9fdeSChristos Margiolis 		case mediaTransport:
415*9cab9fdeSChristos Margiolis 			break;
416*9cab9fdeSChristos Margiolis 		case mediaCodec:
417*9cab9fdeSChristos Margiolis 			if (info.buffer_data[i + 1] < 2)
418*9cab9fdeSChristos Margiolis 				break;
419*9cab9fdeSChristos Margiolis 			/* check codec */
420*9cab9fdeSChristos Margiolis 			switch (info.buffer_data[i + 3]) {
421*9cab9fdeSChristos Margiolis 			case 0:			/* SBC */
422*9cab9fdeSChristos Margiolis 				if (info.buffer_data[i + 1] < 6)
423*9cab9fdeSChristos Margiolis 					break;
424*9cab9fdeSChristos Margiolis 				availFreqMode = info.buffer_data[i + 4];
425*9cab9fdeSChristos Margiolis 				availConfig = info.buffer_data[i + 5];
426*9cab9fdeSChristos Margiolis 				supBitpoolMin = info.buffer_data[i + 6];
427*9cab9fdeSChristos Margiolis 				supBitpoolMax = info.buffer_data[i + 7];
428*9cab9fdeSChristos Margiolis 				break;
429*9cab9fdeSChristos Margiolis 			case 2:			/* MPEG2/4 AAC */
430*9cab9fdeSChristos Margiolis 				if (info.buffer_data[i + 1] < 8)
431*9cab9fdeSChristos Margiolis 					break;
432*9cab9fdeSChristos Margiolis 				aacMode1 = info.buffer_data[i + 5];
433*9cab9fdeSChristos Margiolis 				aacMode2 = info.buffer_data[i + 6];
434*9cab9fdeSChristos Margiolis #ifdef HAVE_LIBAV
435*9cab9fdeSChristos Margiolis 				aacBitrate3 = info.buffer_data[i + 7];
436*9cab9fdeSChristos Margiolis 				aacBitrate4 = info.buffer_data[i + 8];
437*9cab9fdeSChristos Margiolis 				aacBitrate5 = info.buffer_data[i + 9];
438*9cab9fdeSChristos Margiolis #endif
439*9cab9fdeSChristos Margiolis 				break;
440*9cab9fdeSChristos Margiolis 			default:
441*9cab9fdeSChristos Margiolis 				break;
442*9cab9fdeSChristos Margiolis 			}
443*9cab9fdeSChristos Margiolis 		}
444*9cab9fdeSChristos Margiolis 		/* jump to next information element */
445*9cab9fdeSChristos Margiolis 		i += 2 + info.buffer_data[i + 1];
446*9cab9fdeSChristos Margiolis 	}
447*9cab9fdeSChristos Margiolis 	aacMode1 &= cfg->aacMode1;
448*9cab9fdeSChristos Margiolis 	aacMode2 &= cfg->aacMode2;
449*9cab9fdeSChristos Margiolis 
450*9cab9fdeSChristos Margiolis 	/* Try AAC first */
451*9cab9fdeSChristos Margiolis 	if (aacMode1 == cfg->aacMode1 && aacMode2 == cfg->aacMode2) {
452*9cab9fdeSChristos Margiolis #ifdef HAVE_LIBAV
453*9cab9fdeSChristos Margiolis 		uint8_t config[12] = { mediaTransport, 0x0, mediaCodec,
454*9cab9fdeSChristos Margiolis 			0x8, 0x0, 0x02, 0x80, aacMode1, aacMode2, aacBitrate3,
455*9cab9fdeSChristos Margiolis 			aacBitrate4, aacBitrate5
456*9cab9fdeSChristos Margiolis 		};
457*9cab9fdeSChristos Margiolis 
458*9cab9fdeSChristos Margiolis 		if (avdtpSetConfiguration
459*9cab9fdeSChristos Margiolis 		    (cfg->hc, cfg->sep, config, sizeof(config)) == 0) {
460*9cab9fdeSChristos Margiolis 			cfg->codec = CODEC_AAC;
461*9cab9fdeSChristos Margiolis 			return (0);
462*9cab9fdeSChristos Margiolis 		}
463*9cab9fdeSChristos Margiolis #endif
464*9cab9fdeSChristos Margiolis 	}
465*9cab9fdeSChristos Margiolis 	/* Try SBC second */
466*9cab9fdeSChristos Margiolis 	if (cfg->freq == FREQ_UNDEFINED)
467*9cab9fdeSChristos Margiolis 		goto auto_config_failed;
468*9cab9fdeSChristos Margiolis 
469*9cab9fdeSChristos Margiolis 	freqmode = (1 << (3 - cfg->freq + 4)) | (1 << (3 - cfg->chmode));
470*9cab9fdeSChristos Margiolis 
471*9cab9fdeSChristos Margiolis 	if ((availFreqMode & freqmode) != freqmode) {
472*9cab9fdeSChristos Margiolis 		DPRINTF("No frequency and mode match\n");
473*9cab9fdeSChristos Margiolis 		goto auto_config_failed;
474*9cab9fdeSChristos Margiolis 	}
475*9cab9fdeSChristos Margiolis 	for (i = 0; i != 4; i++) {
476*9cab9fdeSChristos Margiolis 		blk_len_sb_alloc = (1 << (i + 4)) |
477*9cab9fdeSChristos Margiolis 		    (1 << (1 - cfg->bands + 2)) | (1 << cfg->allocm);
478*9cab9fdeSChristos Margiolis 
479*9cab9fdeSChristos Margiolis 		if ((availConfig & blk_len_sb_alloc) == blk_len_sb_alloc)
480*9cab9fdeSChristos Margiolis 			break;
481*9cab9fdeSChristos Margiolis 	}
482*9cab9fdeSChristos Margiolis 	if (i == 4) {
483*9cab9fdeSChristos Margiolis 		DPRINTF("No bands available\n");
484*9cab9fdeSChristos Margiolis 		goto auto_config_failed;
485*9cab9fdeSChristos Margiolis 	}
486*9cab9fdeSChristos Margiolis 	cfg->blocks = (3 - i);
487*9cab9fdeSChristos Margiolis 
488*9cab9fdeSChristos Margiolis 	if (cfg->allocm == ALLOC_SNR)
489*9cab9fdeSChristos Margiolis 		supBitpoolMax &= ~1;
490*9cab9fdeSChristos Margiolis 
491*9cab9fdeSChristos Margiolis 	if (cfg->chmode == MODE_DUAL || cfg->chmode == MODE_MONO)
492*9cab9fdeSChristos Margiolis 		supBitpoolMax /= 2;
493*9cab9fdeSChristos Margiolis 
494*9cab9fdeSChristos Margiolis 	if (cfg->bands == BANDS_4)
495*9cab9fdeSChristos Margiolis 		supBitpoolMax /= 2;
496*9cab9fdeSChristos Margiolis 
497*9cab9fdeSChristos Margiolis 	if (supBitpoolMax > cfg->bitpool)
498*9cab9fdeSChristos Margiolis 		supBitpoolMax = cfg->bitpool;
499*9cab9fdeSChristos Margiolis 	else
500*9cab9fdeSChristos Margiolis 		cfg->bitpool = supBitpoolMax;
501*9cab9fdeSChristos Margiolis 
502*9cab9fdeSChristos Margiolis 	do {
503*9cab9fdeSChristos Margiolis 		uint8_t config[10] = { mediaTransport, 0x0, mediaCodec, 0x6,
504*9cab9fdeSChristos Margiolis 			0x0, 0x0, freqmode, blk_len_sb_alloc, supBitpoolMin,
505*9cab9fdeSChristos Margiolis 			supBitpoolMax
506*9cab9fdeSChristos Margiolis 		};
507*9cab9fdeSChristos Margiolis 
508*9cab9fdeSChristos Margiolis 		if (avdtpSetConfiguration
509*9cab9fdeSChristos Margiolis 		    (cfg->hc, cfg->sep, config, sizeof(config)) == 0) {
510*9cab9fdeSChristos Margiolis 			cfg->codec = CODEC_SBC;
511*9cab9fdeSChristos Margiolis 			return (0);
512*9cab9fdeSChristos Margiolis 		}
513*9cab9fdeSChristos Margiolis 	} while (0);
514*9cab9fdeSChristos Margiolis 
515*9cab9fdeSChristos Margiolis auto_config_failed:
516*9cab9fdeSChristos Margiolis 	if (cfg->chmode == MODE_STEREO) {
517*9cab9fdeSChristos Margiolis 		cfg->chmode = MODE_MONO;
518*9cab9fdeSChristos Margiolis 		cfg->aacMode2 ^= 0x0C;
519*9cab9fdeSChristos Margiolis 		goto retry;
520*9cab9fdeSChristos Margiolis 	}
521*9cab9fdeSChristos Margiolis 	return (-EINVAL);
522*9cab9fdeSChristos Margiolis }
523*9cab9fdeSChristos Margiolis 
524*9cab9fdeSChristos Margiolis void
avdtpACPFree(struct bt_config * cfg)525*9cab9fdeSChristos Margiolis avdtpACPFree(struct bt_config *cfg)
526*9cab9fdeSChristos Margiolis {
527*9cab9fdeSChristos Margiolis 	if (cfg->handle.sbc_enc) {
528*9cab9fdeSChristos Margiolis 		free(cfg->handle.sbc_enc);
529*9cab9fdeSChristos Margiolis 		cfg->handle.sbc_enc = NULL;
530*9cab9fdeSChristos Margiolis 	}
531*9cab9fdeSChristos Margiolis }
532*9cab9fdeSChristos Margiolis 
533*9cab9fdeSChristos Margiolis /* Returns 0 on success, < 0 on failure. */
534*9cab9fdeSChristos Margiolis static int
avdtpParseSBCConfig(uint8_t * data,struct bt_config * cfg)535*9cab9fdeSChristos Margiolis avdtpParseSBCConfig(uint8_t * data, struct bt_config *cfg)
536*9cab9fdeSChristos Margiolis {
537*9cab9fdeSChristos Margiolis 	if (data[0] & (1 << (7 - FREQ_48K))) {
538*9cab9fdeSChristos Margiolis 		cfg->freq = FREQ_48K;
539*9cab9fdeSChristos Margiolis 	} else if (data[0] & (1 << (7 - FREQ_44_1K))) {
540*9cab9fdeSChristos Margiolis 		cfg->freq = FREQ_44_1K;
541*9cab9fdeSChristos Margiolis 	} else if (data[0] & (1 << (7 - FREQ_32K))) {
542*9cab9fdeSChristos Margiolis 		cfg->freq = FREQ_32K;
543*9cab9fdeSChristos Margiolis 	} else if (data[0] & (1 << (7 - FREQ_16K))) {
544*9cab9fdeSChristos Margiolis 		cfg->freq = FREQ_16K;
545*9cab9fdeSChristos Margiolis 	} else {
546*9cab9fdeSChristos Margiolis 		return -EINVAL;
547*9cab9fdeSChristos Margiolis 	}
548*9cab9fdeSChristos Margiolis 
549*9cab9fdeSChristos Margiolis 	if (data[0] & (1 << (3 - MODE_STEREO))) {
550*9cab9fdeSChristos Margiolis 		cfg->chmode = MODE_STEREO;
551*9cab9fdeSChristos Margiolis 	} else if (data[0] & (1 << (3 - MODE_JOINT))) {
552*9cab9fdeSChristos Margiolis 		cfg->chmode = MODE_JOINT;
553*9cab9fdeSChristos Margiolis 	} else if (data[0] & (1 << (3 - MODE_DUAL))) {
554*9cab9fdeSChristos Margiolis 		cfg->chmode = MODE_DUAL;
555*9cab9fdeSChristos Margiolis 	} else if (data[0] & (1 << (3 - MODE_MONO))) {
556*9cab9fdeSChristos Margiolis 		cfg->chmode = MODE_MONO;
557*9cab9fdeSChristos Margiolis 	} else {
558*9cab9fdeSChristos Margiolis 		return -EINVAL;
559*9cab9fdeSChristos Margiolis 	}
560*9cab9fdeSChristos Margiolis 
561*9cab9fdeSChristos Margiolis 	if (data[1] & (1 << (7 - BLOCKS_16))) {
562*9cab9fdeSChristos Margiolis 		cfg->blocks = BLOCKS_16;
563*9cab9fdeSChristos Margiolis 	} else if (data[1] & (1 << (7 - BLOCKS_12))) {
564*9cab9fdeSChristos Margiolis 		cfg->blocks = BLOCKS_12;
565*9cab9fdeSChristos Margiolis 	} else if (data[1] & (1 << (7 - BLOCKS_8))) {
566*9cab9fdeSChristos Margiolis 		cfg->blocks = BLOCKS_8;
567*9cab9fdeSChristos Margiolis 	} else if (data[1] & (1 << (7 - BLOCKS_4))) {
568*9cab9fdeSChristos Margiolis 		cfg->blocks = BLOCKS_4;
569*9cab9fdeSChristos Margiolis 	} else {
570*9cab9fdeSChristos Margiolis 		return -EINVAL;
571*9cab9fdeSChristos Margiolis 	}
572*9cab9fdeSChristos Margiolis 
573*9cab9fdeSChristos Margiolis 	if (data[1] & (1 << (3 - BANDS_8))) {
574*9cab9fdeSChristos Margiolis 		cfg->bands = BANDS_8;
575*9cab9fdeSChristos Margiolis 	} else if (data[1] & (1 << (3 - BANDS_4))) {
576*9cab9fdeSChristos Margiolis 		cfg->bands = BANDS_4;
577*9cab9fdeSChristos Margiolis 	} else {
578*9cab9fdeSChristos Margiolis 		return -EINVAL;
579*9cab9fdeSChristos Margiolis 	}
580*9cab9fdeSChristos Margiolis 
581*9cab9fdeSChristos Margiolis 	if (data[1] & (1 << ALLOC_LOUDNESS)) {
582*9cab9fdeSChristos Margiolis 		cfg->allocm = ALLOC_LOUDNESS;
583*9cab9fdeSChristos Margiolis 	} else if (data[1] & (1 << ALLOC_SNR)) {
584*9cab9fdeSChristos Margiolis 		cfg->allocm = ALLOC_SNR;
585*9cab9fdeSChristos Margiolis 	} else {
586*9cab9fdeSChristos Margiolis 		return -EINVAL;
587*9cab9fdeSChristos Margiolis 	}
588*9cab9fdeSChristos Margiolis 	cfg->bitpool = data[3];
589*9cab9fdeSChristos Margiolis 	return 0;
590*9cab9fdeSChristos Margiolis }
591*9cab9fdeSChristos Margiolis 
592*9cab9fdeSChristos Margiolis int
avdtpACPHandlePacket(struct bt_config * cfg)593*9cab9fdeSChristos Margiolis avdtpACPHandlePacket(struct bt_config *cfg)
594*9cab9fdeSChristos Margiolis {
595*9cab9fdeSChristos Margiolis 	struct avdtpGetPacketInfo info;
596*9cab9fdeSChristos Margiolis 	int retval;
597*9cab9fdeSChristos Margiolis 
598*9cab9fdeSChristos Margiolis 	if (avdtpGetPacket(cfg->hc, &info) != COMMAND)
599*9cab9fdeSChristos Margiolis 		return (-ENXIO);
600*9cab9fdeSChristos Margiolis 
601*9cab9fdeSChristos Margiolis 	switch (info.signalID) {
602*9cab9fdeSChristos Margiolis 	case AVDTP_DISCOVER:
603*9cab9fdeSChristos Margiolis 		retval =
604*9cab9fdeSChristos Margiolis 		    avdtpSendDiscResponseAudio(cfg->hc, info.trans, ACPSEP, 1);
605*9cab9fdeSChristos Margiolis 		if (!retval)
606*9cab9fdeSChristos Margiolis 			retval = AVDTP_DISCOVER;
607*9cab9fdeSChristos Margiolis 		break;
608*9cab9fdeSChristos Margiolis 	case AVDTP_GET_CAPABILITIES:
609*9cab9fdeSChristos Margiolis 		retval =
610*9cab9fdeSChristos Margiolis 		    avdtpSendCapabilitiesResponseSBCForACP(cfg->hc, info.trans);
611*9cab9fdeSChristos Margiolis 		if (!retval)
612*9cab9fdeSChristos Margiolis 			retval = AVDTP_GET_CAPABILITIES;
613*9cab9fdeSChristos Margiolis 		break;
614*9cab9fdeSChristos Margiolis 	case AVDTP_SET_CONFIGURATION:
615*9cab9fdeSChristos Margiolis 		if (cfg->acceptor_state != acpInitial)
616*9cab9fdeSChristos Margiolis 			goto err;
617*9cab9fdeSChristos Margiolis 		cfg->sep = info.buffer_data[1] >> 2;
618*9cab9fdeSChristos Margiolis 		int is_configured = 0;
619*9cab9fdeSChristos Margiolis 		for (int i = 2; (i + 1) < info.buffer_len;) {
620*9cab9fdeSChristos Margiolis 			if (i + 2 + info.buffer_data[i + 1] > info.buffer_len)
621*9cab9fdeSChristos Margiolis 				break;
622*9cab9fdeSChristos Margiolis 			switch (info.buffer_data[i]) {
623*9cab9fdeSChristos Margiolis 			case mediaTransport:
624*9cab9fdeSChristos Margiolis 				break;
625*9cab9fdeSChristos Margiolis 			case mediaCodec:
626*9cab9fdeSChristos Margiolis 				if (info.buffer_data[i + 1] < 2)
627*9cab9fdeSChristos Margiolis 					break;
628*9cab9fdeSChristos Margiolis 				/* check codec */
629*9cab9fdeSChristos Margiolis 				switch (info.buffer_data[i + 3]) {
630*9cab9fdeSChristos Margiolis 				case 0:		/* SBC */
631*9cab9fdeSChristos Margiolis 					if (info.buffer_data[i + 1] < 6)
632*9cab9fdeSChristos Margiolis 						break;
633*9cab9fdeSChristos Margiolis 					retval =
634*9cab9fdeSChristos Margiolis 					    avdtpParseSBCConfig(info.buffer_data + i + 4, cfg);
635*9cab9fdeSChristos Margiolis 					if (retval)
636*9cab9fdeSChristos Margiolis 						return retval;
637*9cab9fdeSChristos Margiolis 					is_configured = 1;
638*9cab9fdeSChristos Margiolis 					break;
639*9cab9fdeSChristos Margiolis 				case 2:		/* MPEG2/4 AAC */
640*9cab9fdeSChristos Margiolis 					/* TODO: Add support */
641*9cab9fdeSChristos Margiolis 				default:
642*9cab9fdeSChristos Margiolis 					break;
643*9cab9fdeSChristos Margiolis 				}
644*9cab9fdeSChristos Margiolis 			}
645*9cab9fdeSChristos Margiolis 			/* jump to next information element */
646*9cab9fdeSChristos Margiolis 			i += 2 + info.buffer_data[i + 1];
647*9cab9fdeSChristos Margiolis 		}
648*9cab9fdeSChristos Margiolis 		if (!is_configured)
649*9cab9fdeSChristos Margiolis 			goto err;
650*9cab9fdeSChristos Margiolis 
651*9cab9fdeSChristos Margiolis 		retval =
652*9cab9fdeSChristos Margiolis 		    avdtpSendAccept(cfg->hc, info.trans, AVDTP_SET_CONFIGURATION);
653*9cab9fdeSChristos Margiolis 		if (retval)
654*9cab9fdeSChristos Margiolis 			return (retval);
655*9cab9fdeSChristos Margiolis 
656*9cab9fdeSChristos Margiolis 		/* TODO: Handle other codecs */
657*9cab9fdeSChristos Margiolis 		if (cfg->handle.sbc_enc == NULL) {
658*9cab9fdeSChristos Margiolis 			cfg->handle.sbc_enc = malloc(sizeof(*cfg->handle.sbc_enc));
659*9cab9fdeSChristos Margiolis 			if (cfg->handle.sbc_enc == NULL)
660*9cab9fdeSChristos Margiolis 				return (-ENOMEM);
661*9cab9fdeSChristos Margiolis 		}
662*9cab9fdeSChristos Margiolis 		memset(cfg->handle.sbc_enc, 0, sizeof(*cfg->handle.sbc_enc));
663*9cab9fdeSChristos Margiolis 
664*9cab9fdeSChristos Margiolis 		retval = AVDTP_SET_CONFIGURATION;
665*9cab9fdeSChristos Margiolis 		cfg->acceptor_state = acpConfigurationSet;
666*9cab9fdeSChristos Margiolis 		break;
667*9cab9fdeSChristos Margiolis 	case AVDTP_OPEN:
668*9cab9fdeSChristos Margiolis 		if (cfg->acceptor_state != acpConfigurationSet)
669*9cab9fdeSChristos Margiolis 			goto err;
670*9cab9fdeSChristos Margiolis 		retval = avdtpSendAccept(cfg->hc, info.trans, info.signalID);
671*9cab9fdeSChristos Margiolis 		if (retval)
672*9cab9fdeSChristos Margiolis 			return (retval);
673*9cab9fdeSChristos Margiolis 		retval = info.signalID;
674*9cab9fdeSChristos Margiolis 		cfg->acceptor_state = acpStreamOpened;
675*9cab9fdeSChristos Margiolis 		break;
676*9cab9fdeSChristos Margiolis 	case AVDTP_START:
677*9cab9fdeSChristos Margiolis 		if (cfg->acceptor_state != acpStreamOpened &&
678*9cab9fdeSChristos Margiolis 		    cfg->acceptor_state != acpStreamSuspended) {
679*9cab9fdeSChristos Margiolis 			goto err;
680*9cab9fdeSChristos Margiolis 		}
681*9cab9fdeSChristos Margiolis 		retval = avdtpSendAccept(cfg->hc, info.trans, info.signalID);
682*9cab9fdeSChristos Margiolis 		if (retval)
683*9cab9fdeSChristos Margiolis 			return retval;
684*9cab9fdeSChristos Margiolis 		retval = info.signalID;
685*9cab9fdeSChristos Margiolis 		cfg->acceptor_state = acpStreamStarted;
686*9cab9fdeSChristos Margiolis 		break;
687*9cab9fdeSChristos Margiolis 	case AVDTP_CLOSE:
688*9cab9fdeSChristos Margiolis 		if (cfg->acceptor_state != acpStreamOpened &&
689*9cab9fdeSChristos Margiolis 		    cfg->acceptor_state != acpStreamStarted &&
690*9cab9fdeSChristos Margiolis 		    cfg->acceptor_state != acpStreamSuspended) {
691*9cab9fdeSChristos Margiolis 			goto err;
692*9cab9fdeSChristos Margiolis 		}
693*9cab9fdeSChristos Margiolis 		retval = avdtpSendAccept(cfg->hc, info.trans, info.signalID);
694*9cab9fdeSChristos Margiolis 		if (retval)
695*9cab9fdeSChristos Margiolis 			return (retval);
696*9cab9fdeSChristos Margiolis 		retval = info.signalID;
697*9cab9fdeSChristos Margiolis 		cfg->acceptor_state = acpStreamClosed;
698*9cab9fdeSChristos Margiolis 		break;
699*9cab9fdeSChristos Margiolis 	case AVDTP_SUSPEND:
700*9cab9fdeSChristos Margiolis 		if (cfg->acceptor_state != acpStreamOpened &&
701*9cab9fdeSChristos Margiolis 		    cfg->acceptor_state != acpStreamStarted) {
702*9cab9fdeSChristos Margiolis 			goto err;
703*9cab9fdeSChristos Margiolis 		}
704*9cab9fdeSChristos Margiolis 		retval = avdtpSendAccept(cfg->hc, info.trans, info.signalID);
705*9cab9fdeSChristos Margiolis 		if (retval)
706*9cab9fdeSChristos Margiolis 			return (retval);
707*9cab9fdeSChristos Margiolis 		retval = info.signalID;
708*9cab9fdeSChristos Margiolis 		cfg->acceptor_state = acpStreamSuspended;
709*9cab9fdeSChristos Margiolis 		break;
710*9cab9fdeSChristos Margiolis 	case AVDTP_GET_CONFIGURATION:
711*9cab9fdeSChristos Margiolis 	case AVDTP_RECONFIGURE:
712*9cab9fdeSChristos Margiolis 	case AVDTP_ABORT:
713*9cab9fdeSChristos Margiolis 		/* TODO: Implement this. */
714*9cab9fdeSChristos Margiolis 	default:
715*9cab9fdeSChristos Margiolis err:
716*9cab9fdeSChristos Margiolis 		avdtpSendReject(cfg->hc, info.trans, info.signalID);
717*9cab9fdeSChristos Margiolis 		return (-ENXIO);
718*9cab9fdeSChristos Margiolis 	}
719*9cab9fdeSChristos Margiolis 	return (retval);
720*9cab9fdeSChristos Margiolis }
721