1*9cab9fdeSChristos Margiolis /*-
2*9cab9fdeSChristos Margiolis * Copyright (c) 2015-2019 Hans Petter Selasky
3*9cab9fdeSChristos Margiolis * Copyright (c) 2015 Nathanial Sloss <nathanialsloss@yahoo.com.au>
4*9cab9fdeSChristos Margiolis * Copyright (c) 2006 Itronix Inc
5*9cab9fdeSChristos Margiolis *
6*9cab9fdeSChristos Margiolis * Redistribution and use in source and binary forms, with or without
7*9cab9fdeSChristos Margiolis * modification, are permitted provided that the following conditions
8*9cab9fdeSChristos Margiolis * are met:
9*9cab9fdeSChristos Margiolis * 1. Redistributions of source code must retain the above copyright
10*9cab9fdeSChristos Margiolis * notice, this list of conditions and the following disclaimer.
11*9cab9fdeSChristos Margiolis * 2. Redistributions in binary form must reproduce the above copyright
12*9cab9fdeSChristos Margiolis * notice, this list of conditions and the following disclaimer in the
13*9cab9fdeSChristos Margiolis * documentation and/or other materials provided with the distribution.
14*9cab9fdeSChristos Margiolis *
15*9cab9fdeSChristos Margiolis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*9cab9fdeSChristos Margiolis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*9cab9fdeSChristos Margiolis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*9cab9fdeSChristos Margiolis * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*9cab9fdeSChristos Margiolis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*9cab9fdeSChristos Margiolis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*9cab9fdeSChristos Margiolis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*9cab9fdeSChristos Margiolis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*9cab9fdeSChristos Margiolis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*9cab9fdeSChristos Margiolis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*9cab9fdeSChristos Margiolis * SUCH DAMAGE.
26*9cab9fdeSChristos Margiolis */
27*9cab9fdeSChristos Margiolis
28*9cab9fdeSChristos Margiolis #include <sys/queue.h>
29*9cab9fdeSChristos Margiolis #include <sys/filio.h>
30*9cab9fdeSChristos Margiolis #include <sys/soundcard.h>
31*9cab9fdeSChristos Margiolis
32*9cab9fdeSChristos Margiolis #include <stdio.h>
33*9cab9fdeSChristos Margiolis #include <stdint.h>
34*9cab9fdeSChristos Margiolis #include <stdlib.h>
35*9cab9fdeSChristos Margiolis #include <string.h>
36*9cab9fdeSChristos Margiolis #include <fcntl.h>
37*9cab9fdeSChristos Margiolis #include <unistd.h>
38*9cab9fdeSChristos Margiolis #include <err.h>
39*9cab9fdeSChristos Margiolis #define L2CAP_SOCKET_CHECKED
40*9cab9fdeSChristos Margiolis #include <bluetooth.h>
41*9cab9fdeSChristos Margiolis #include <sdp.h>
42*9cab9fdeSChristos Margiolis
43*9cab9fdeSChristos Margiolis #include "backend.h"
44*9cab9fdeSChristos Margiolis #include "int.h"
45*9cab9fdeSChristos Margiolis
46*9cab9fdeSChristos Margiolis #include "avdtp_signal.h"
47*9cab9fdeSChristos Margiolis #include "bt.h"
48*9cab9fdeSChristos Margiolis
49*9cab9fdeSChristos Margiolis #define DPRINTF(...) printf("backend_bt: " __VA_ARGS__)
50*9cab9fdeSChristos Margiolis
51*9cab9fdeSChristos Margiolis struct l2cap_info {
52*9cab9fdeSChristos Margiolis bdaddr_t laddr;
53*9cab9fdeSChristos Margiolis bdaddr_t raddr;
54*9cab9fdeSChristos Margiolis };
55*9cab9fdeSChristos Margiolis
56*9cab9fdeSChristos Margiolis static struct bt_config bt_play_cfg;
57*9cab9fdeSChristos Margiolis static struct bt_config bt_rec_cfg;
58*9cab9fdeSChristos Margiolis
59*9cab9fdeSChristos Margiolis int
bt_receive(struct bt_config * cfg,void * ptr,int len,int use_delay)60*9cab9fdeSChristos Margiolis bt_receive(struct bt_config *cfg, void *ptr, int len, int use_delay)
61*9cab9fdeSChristos Margiolis {
62*9cab9fdeSChristos Margiolis struct sbc_header *phdr = (struct sbc_header *)cfg->mtu_data;
63*9cab9fdeSChristos Margiolis struct sbc_encode *sbc = cfg->handle.sbc_enc;
64*9cab9fdeSChristos Margiolis uint8_t *tmp = ptr;
65*9cab9fdeSChristos Margiolis int old_len = len;
66*9cab9fdeSChristos Margiolis int delta;
67*9cab9fdeSChristos Margiolis int err;
68*9cab9fdeSChristos Margiolis
69*9cab9fdeSChristos Margiolis /* wait for service interval, if any */
70*9cab9fdeSChristos Margiolis if (use_delay)
71*9cab9fdeSChristos Margiolis virtual_oss_wait();
72*9cab9fdeSChristos Margiolis
73*9cab9fdeSChristos Margiolis switch (cfg->blocks) {
74*9cab9fdeSChristos Margiolis case BLOCKS_4:
75*9cab9fdeSChristos Margiolis sbc->blocks = 4;
76*9cab9fdeSChristos Margiolis break;
77*9cab9fdeSChristos Margiolis case BLOCKS_8:
78*9cab9fdeSChristos Margiolis sbc->blocks = 8;
79*9cab9fdeSChristos Margiolis break;
80*9cab9fdeSChristos Margiolis case BLOCKS_12:
81*9cab9fdeSChristos Margiolis sbc->blocks = 12;
82*9cab9fdeSChristos Margiolis break;
83*9cab9fdeSChristos Margiolis default:
84*9cab9fdeSChristos Margiolis sbc->blocks = 16;
85*9cab9fdeSChristos Margiolis break;
86*9cab9fdeSChristos Margiolis }
87*9cab9fdeSChristos Margiolis
88*9cab9fdeSChristos Margiolis switch (cfg->bands) {
89*9cab9fdeSChristos Margiolis case BANDS_4:
90*9cab9fdeSChristos Margiolis sbc->bands = 4;
91*9cab9fdeSChristos Margiolis break;
92*9cab9fdeSChristos Margiolis default:
93*9cab9fdeSChristos Margiolis sbc->bands = 8;
94*9cab9fdeSChristos Margiolis break;
95*9cab9fdeSChristos Margiolis }
96*9cab9fdeSChristos Margiolis
97*9cab9fdeSChristos Margiolis if (cfg->chmode != MODE_MONO) {
98*9cab9fdeSChristos Margiolis sbc->channels = 2;
99*9cab9fdeSChristos Margiolis } else {
100*9cab9fdeSChristos Margiolis sbc->channels = 1;
101*9cab9fdeSChristos Margiolis }
102*9cab9fdeSChristos Margiolis
103*9cab9fdeSChristos Margiolis while (1) {
104*9cab9fdeSChristos Margiolis delta = len & ~1;
105*9cab9fdeSChristos Margiolis if (delta > (int)(2 * sbc->rem_len))
106*9cab9fdeSChristos Margiolis delta = (2 * sbc->rem_len);
107*9cab9fdeSChristos Margiolis
108*9cab9fdeSChristos Margiolis /* copy out samples, if any */
109*9cab9fdeSChristos Margiolis memcpy(tmp, (char *)sbc->music_data + sbc->rem_off, delta);
110*9cab9fdeSChristos Margiolis tmp += delta;
111*9cab9fdeSChristos Margiolis len -= delta;
112*9cab9fdeSChristos Margiolis sbc->rem_off += delta / 2;
113*9cab9fdeSChristos Margiolis sbc->rem_len -= delta / 2;
114*9cab9fdeSChristos Margiolis if (len == 0)
115*9cab9fdeSChristos Margiolis break;
116*9cab9fdeSChristos Margiolis
117*9cab9fdeSChristos Margiolis if (sbc->rem_len == 0 &&
118*9cab9fdeSChristos Margiolis sbc->rem_data_frames != 0) {
119*9cab9fdeSChristos Margiolis err = sbc_decode_frame(cfg, sbc->rem_data_len * 8);
120*9cab9fdeSChristos Margiolis sbc->rem_data_frames--;
121*9cab9fdeSChristos Margiolis sbc->rem_data_ptr += err;
122*9cab9fdeSChristos Margiolis sbc->rem_data_len -= err;
123*9cab9fdeSChristos Margiolis continue;
124*9cab9fdeSChristos Margiolis }
125*9cab9fdeSChristos Margiolis /* TODO: Support fragmented SBC frames */
126*9cab9fdeSChristos Margiolis err = read(cfg->fd, cfg->mtu_data, cfg->mtu);
127*9cab9fdeSChristos Margiolis
128*9cab9fdeSChristos Margiolis if (err == 0) {
129*9cab9fdeSChristos Margiolis break;
130*9cab9fdeSChristos Margiolis } else if (err < 0) {
131*9cab9fdeSChristos Margiolis if (errno == EAGAIN || errno == EWOULDBLOCK)
132*9cab9fdeSChristos Margiolis break;
133*9cab9fdeSChristos Margiolis else
134*9cab9fdeSChristos Margiolis return (-1); /* disconnected */
135*9cab9fdeSChristos Margiolis }
136*9cab9fdeSChristos Margiolis
137*9cab9fdeSChristos Margiolis /* verify RTP header */
138*9cab9fdeSChristos Margiolis if (err < (int)sizeof(*phdr) || phdr->id != 0x80)
139*9cab9fdeSChristos Margiolis continue;
140*9cab9fdeSChristos Margiolis
141*9cab9fdeSChristos Margiolis sbc->rem_data_frames = phdr->numFrames;
142*9cab9fdeSChristos Margiolis sbc->rem_data_ptr = (uint8_t *)(phdr + 1);
143*9cab9fdeSChristos Margiolis sbc->rem_data_len = err - sizeof(*phdr);
144*9cab9fdeSChristos Margiolis }
145*9cab9fdeSChristos Margiolis return (old_len - len);
146*9cab9fdeSChristos Margiolis }
147*9cab9fdeSChristos Margiolis
148*9cab9fdeSChristos Margiolis static int
bt_set_format(int * format)149*9cab9fdeSChristos Margiolis bt_set_format(int *format)
150*9cab9fdeSChristos Margiolis {
151*9cab9fdeSChristos Margiolis int value;
152*9cab9fdeSChristos Margiolis
153*9cab9fdeSChristos Margiolis value = *format & AFMT_S16_NE;
154*9cab9fdeSChristos Margiolis if (value != 0) {
155*9cab9fdeSChristos Margiolis *format = value;
156*9cab9fdeSChristos Margiolis return (0);
157*9cab9fdeSChristos Margiolis }
158*9cab9fdeSChristos Margiolis return (-1);
159*9cab9fdeSChristos Margiolis }
160*9cab9fdeSChristos Margiolis
161*9cab9fdeSChristos Margiolis static void
bt_close(struct voss_backend * pbe)162*9cab9fdeSChristos Margiolis bt_close(struct voss_backend *pbe)
163*9cab9fdeSChristos Margiolis {
164*9cab9fdeSChristos Margiolis struct bt_config *cfg = pbe->arg;
165*9cab9fdeSChristos Margiolis
166*9cab9fdeSChristos Margiolis if (cfg->hc > 0) {
167*9cab9fdeSChristos Margiolis avdtpAbort(cfg->hc, cfg->sep);
168*9cab9fdeSChristos Margiolis avdtpClose(cfg->hc, cfg->sep);
169*9cab9fdeSChristos Margiolis close(cfg->hc);
170*9cab9fdeSChristos Margiolis cfg->hc = -1;
171*9cab9fdeSChristos Margiolis }
172*9cab9fdeSChristos Margiolis if (cfg->fd > 0) {
173*9cab9fdeSChristos Margiolis close(cfg->fd);
174*9cab9fdeSChristos Margiolis cfg->fd = -1;
175*9cab9fdeSChristos Margiolis }
176*9cab9fdeSChristos Margiolis }
177*9cab9fdeSChristos Margiolis
178*9cab9fdeSChristos Margiolis static void
bt_play_close(struct voss_backend * pbe)179*9cab9fdeSChristos Margiolis bt_play_close(struct voss_backend *pbe)
180*9cab9fdeSChristos Margiolis {
181*9cab9fdeSChristos Margiolis struct bt_config *cfg = pbe->arg;
182*9cab9fdeSChristos Margiolis
183*9cab9fdeSChristos Margiolis switch (cfg->codec) {
184*9cab9fdeSChristos Margiolis case CODEC_SBC:
185*9cab9fdeSChristos Margiolis if (cfg->handle.sbc_enc == NULL)
186*9cab9fdeSChristos Margiolis break;
187*9cab9fdeSChristos Margiolis free(cfg->handle.sbc_enc);
188*9cab9fdeSChristos Margiolis cfg->handle.sbc_enc = NULL;
189*9cab9fdeSChristos Margiolis break;
190*9cab9fdeSChristos Margiolis #ifdef HAVE_LIBAV
191*9cab9fdeSChristos Margiolis case CODEC_AAC:
192*9cab9fdeSChristos Margiolis if (cfg->handle.av.context == NULL)
193*9cab9fdeSChristos Margiolis break;
194*9cab9fdeSChristos Margiolis av_free(cfg->rem_in_data);
195*9cab9fdeSChristos Margiolis av_frame_free(&cfg->handle.av.frame);
196*9cab9fdeSChristos Margiolis avcodec_close(cfg->handle.av.context);
197*9cab9fdeSChristos Margiolis avformat_free_context(cfg->handle.av.format);
198*9cab9fdeSChristos Margiolis cfg->handle.av.context = NULL;
199*9cab9fdeSChristos Margiolis break;
200*9cab9fdeSChristos Margiolis #endif
201*9cab9fdeSChristos Margiolis default:
202*9cab9fdeSChristos Margiolis break;
203*9cab9fdeSChristos Margiolis }
204*9cab9fdeSChristos Margiolis return (bt_close(pbe));
205*9cab9fdeSChristos Margiolis }
206*9cab9fdeSChristos Margiolis
207*9cab9fdeSChristos Margiolis static void
bt_rec_close(struct voss_backend * pbe)208*9cab9fdeSChristos Margiolis bt_rec_close(struct voss_backend *pbe)
209*9cab9fdeSChristos Margiolis {
210*9cab9fdeSChristos Margiolis struct bt_config *cfg = pbe->arg;
211*9cab9fdeSChristos Margiolis
212*9cab9fdeSChristos Margiolis switch (cfg->codec) {
213*9cab9fdeSChristos Margiolis case CODEC_SBC:
214*9cab9fdeSChristos Margiolis break;
215*9cab9fdeSChristos Margiolis #ifdef HAVE_LIBAV
216*9cab9fdeSChristos Margiolis case CODEC_AAC:
217*9cab9fdeSChristos Margiolis break;
218*9cab9fdeSChristos Margiolis #endif
219*9cab9fdeSChristos Margiolis
220*9cab9fdeSChristos Margiolis default:
221*9cab9fdeSChristos Margiolis break;
222*9cab9fdeSChristos Margiolis }
223*9cab9fdeSChristos Margiolis return (bt_close(pbe));
224*9cab9fdeSChristos Margiolis }
225*9cab9fdeSChristos Margiolis
226*9cab9fdeSChristos Margiolis static const uint32_t bt_attrs[] = {
227*9cab9fdeSChristos Margiolis SDP_ATTR_RANGE(SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
228*9cab9fdeSChristos Margiolis SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
229*9cab9fdeSChristos Margiolis };
230*9cab9fdeSChristos Margiolis
231*9cab9fdeSChristos Margiolis #define BT_NUM_VALUES 32
232*9cab9fdeSChristos Margiolis #define BT_BUF_SIZE 32
233*9cab9fdeSChristos Margiolis
234*9cab9fdeSChristos Margiolis static int
bt_find_psm(const uint8_t * start,const uint8_t * end)235*9cab9fdeSChristos Margiolis bt_find_psm(const uint8_t *start, const uint8_t *end)
236*9cab9fdeSChristos Margiolis {
237*9cab9fdeSChristos Margiolis uint32_t type;
238*9cab9fdeSChristos Margiolis uint32_t len;
239*9cab9fdeSChristos Margiolis int protover = 0;
240*9cab9fdeSChristos Margiolis int psm = -1;
241*9cab9fdeSChristos Margiolis
242*9cab9fdeSChristos Margiolis if ((end - start) < 2)
243*9cab9fdeSChristos Margiolis return (-1);
244*9cab9fdeSChristos Margiolis
245*9cab9fdeSChristos Margiolis SDP_GET8(type, start);
246*9cab9fdeSChristos Margiolis switch (type) {
247*9cab9fdeSChristos Margiolis case SDP_DATA_SEQ8:
248*9cab9fdeSChristos Margiolis SDP_GET8(len, start);
249*9cab9fdeSChristos Margiolis break;
250*9cab9fdeSChristos Margiolis
251*9cab9fdeSChristos Margiolis case SDP_DATA_SEQ16:
252*9cab9fdeSChristos Margiolis SDP_GET16(len, start);
253*9cab9fdeSChristos Margiolis break;
254*9cab9fdeSChristos Margiolis
255*9cab9fdeSChristos Margiolis case SDP_DATA_SEQ32:
256*9cab9fdeSChristos Margiolis SDP_GET32(len, start);
257*9cab9fdeSChristos Margiolis break;
258*9cab9fdeSChristos Margiolis
259*9cab9fdeSChristos Margiolis default:
260*9cab9fdeSChristos Margiolis return (-1);
261*9cab9fdeSChristos Margiolis }
262*9cab9fdeSChristos Margiolis
263*9cab9fdeSChristos Margiolis while (start < end) {
264*9cab9fdeSChristos Margiolis SDP_GET8(type, start);
265*9cab9fdeSChristos Margiolis switch (type) {
266*9cab9fdeSChristos Margiolis case SDP_DATA_SEQ8:
267*9cab9fdeSChristos Margiolis SDP_GET8(len, start);
268*9cab9fdeSChristos Margiolis break;
269*9cab9fdeSChristos Margiolis
270*9cab9fdeSChristos Margiolis case SDP_DATA_SEQ16:
271*9cab9fdeSChristos Margiolis SDP_GET16(len, start);
272*9cab9fdeSChristos Margiolis break;
273*9cab9fdeSChristos Margiolis
274*9cab9fdeSChristos Margiolis case SDP_DATA_SEQ32:
275*9cab9fdeSChristos Margiolis SDP_GET32(len, start);
276*9cab9fdeSChristos Margiolis break;
277*9cab9fdeSChristos Margiolis
278*9cab9fdeSChristos Margiolis default:
279*9cab9fdeSChristos Margiolis return (-1);
280*9cab9fdeSChristos Margiolis }
281*9cab9fdeSChristos Margiolis /* check range */
282*9cab9fdeSChristos Margiolis if (len > (uint32_t)(end - start))
283*9cab9fdeSChristos Margiolis break;
284*9cab9fdeSChristos Margiolis
285*9cab9fdeSChristos Margiolis if (len >= 6) {
286*9cab9fdeSChristos Margiolis const uint8_t *ptr = start;
287*9cab9fdeSChristos Margiolis
288*9cab9fdeSChristos Margiolis SDP_GET8(type, ptr);
289*9cab9fdeSChristos Margiolis if (type == SDP_DATA_UUID16) {
290*9cab9fdeSChristos Margiolis uint16_t temp;
291*9cab9fdeSChristos Margiolis
292*9cab9fdeSChristos Margiolis SDP_GET16(temp, ptr);
293*9cab9fdeSChristos Margiolis switch (temp) {
294*9cab9fdeSChristos Margiolis case SDP_UUID_PROTOCOL_L2CAP:
295*9cab9fdeSChristos Margiolis SDP_GET8(type, ptr);
296*9cab9fdeSChristos Margiolis SDP_GET16(psm, ptr);
297*9cab9fdeSChristos Margiolis break;
298*9cab9fdeSChristos Margiolis case SDP_UUID_PROTOCOL_AVDTP:
299*9cab9fdeSChristos Margiolis SDP_GET8(type, ptr);
300*9cab9fdeSChristos Margiolis SDP_GET16(protover, ptr);
301*9cab9fdeSChristos Margiolis break;
302*9cab9fdeSChristos Margiolis default:
303*9cab9fdeSChristos Margiolis break;
304*9cab9fdeSChristos Margiolis }
305*9cab9fdeSChristos Margiolis }
306*9cab9fdeSChristos Margiolis }
307*9cab9fdeSChristos Margiolis start += len;
308*9cab9fdeSChristos Margiolis
309*9cab9fdeSChristos Margiolis if (protover >= 0x0100 && psm > -1)
310*9cab9fdeSChristos Margiolis return (htole16(psm));
311*9cab9fdeSChristos Margiolis }
312*9cab9fdeSChristos Margiolis return (-1);
313*9cab9fdeSChristos Margiolis }
314*9cab9fdeSChristos Margiolis
315*9cab9fdeSChristos Margiolis static int
bt_query(struct l2cap_info * info,uint16_t service_class)316*9cab9fdeSChristos Margiolis bt_query(struct l2cap_info *info, uint16_t service_class)
317*9cab9fdeSChristos Margiolis {
318*9cab9fdeSChristos Margiolis sdp_attr_t values[BT_NUM_VALUES];
319*9cab9fdeSChristos Margiolis uint8_t buffer[BT_NUM_VALUES][BT_BUF_SIZE];
320*9cab9fdeSChristos Margiolis void *ss;
321*9cab9fdeSChristos Margiolis int psm = -1;
322*9cab9fdeSChristos Margiolis int n;
323*9cab9fdeSChristos Margiolis
324*9cab9fdeSChristos Margiolis memset(buffer, 0, sizeof(buffer));
325*9cab9fdeSChristos Margiolis memset(values, 0, sizeof(values));
326*9cab9fdeSChristos Margiolis
327*9cab9fdeSChristos Margiolis ss = sdp_open(&info->laddr, &info->raddr);
328*9cab9fdeSChristos Margiolis if (ss == NULL || sdp_error(ss) != 0) {
329*9cab9fdeSChristos Margiolis DPRINTF("Could not open SDP\n");
330*9cab9fdeSChristos Margiolis sdp_close(ss);
331*9cab9fdeSChristos Margiolis return (psm);
332*9cab9fdeSChristos Margiolis }
333*9cab9fdeSChristos Margiolis /* Initialize attribute values array */
334*9cab9fdeSChristos Margiolis for (n = 0; n != BT_NUM_VALUES; n++) {
335*9cab9fdeSChristos Margiolis values[n].flags = SDP_ATTR_INVALID;
336*9cab9fdeSChristos Margiolis values[n].vlen = BT_BUF_SIZE;
337*9cab9fdeSChristos Margiolis values[n].value = buffer[n];
338*9cab9fdeSChristos Margiolis }
339*9cab9fdeSChristos Margiolis
340*9cab9fdeSChristos Margiolis /* Do SDP Service Search Attribute Request */
341*9cab9fdeSChristos Margiolis n = sdp_search(ss, 1, &service_class, 1, bt_attrs, BT_NUM_VALUES, values);
342*9cab9fdeSChristos Margiolis if (n != 0) {
343*9cab9fdeSChristos Margiolis DPRINTF("SDP search failed\n");
344*9cab9fdeSChristos Margiolis goto done;
345*9cab9fdeSChristos Margiolis }
346*9cab9fdeSChristos Margiolis /* Print attributes values */
347*9cab9fdeSChristos Margiolis for (n = 0; n != BT_NUM_VALUES; n++) {
348*9cab9fdeSChristos Margiolis if (values[n].flags != SDP_ATTR_OK)
349*9cab9fdeSChristos Margiolis break;
350*9cab9fdeSChristos Margiolis if (values[n].attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST)
351*9cab9fdeSChristos Margiolis continue;
352*9cab9fdeSChristos Margiolis psm = bt_find_psm(values[n].value, values[n].value + values[n].vlen);
353*9cab9fdeSChristos Margiolis if (psm > -1)
354*9cab9fdeSChristos Margiolis break;
355*9cab9fdeSChristos Margiolis }
356*9cab9fdeSChristos Margiolis done:
357*9cab9fdeSChristos Margiolis sdp_close(ss);
358*9cab9fdeSChristos Margiolis return (psm);
359*9cab9fdeSChristos Margiolis }
360*9cab9fdeSChristos Margiolis
361*9cab9fdeSChristos Margiolis static int
bt_open(struct voss_backend * pbe __unused,const char * devname,int samplerate,int bufsize __unused,int * pchannels,int * pformat,struct bt_config * cfg,int service_class,int isSink)362*9cab9fdeSChristos Margiolis bt_open(struct voss_backend *pbe __unused, const char *devname, int samplerate,
363*9cab9fdeSChristos Margiolis int bufsize __unused, int *pchannels, int *pformat, struct bt_config *cfg,
364*9cab9fdeSChristos Margiolis int service_class, int isSink)
365*9cab9fdeSChristos Margiolis {
366*9cab9fdeSChristos Margiolis struct sockaddr_l2cap addr;
367*9cab9fdeSChristos Margiolis struct l2cap_info info;
368*9cab9fdeSChristos Margiolis socklen_t mtusize = sizeof(uint16_t);
369*9cab9fdeSChristos Margiolis int tmpbitpool;
370*9cab9fdeSChristos Margiolis int l2cap_psm;
371*9cab9fdeSChristos Margiolis int temp;
372*9cab9fdeSChristos Margiolis
373*9cab9fdeSChristos Margiolis memset(&info, 0, sizeof(info));
374*9cab9fdeSChristos Margiolis
375*9cab9fdeSChristos Margiolis if (strstr(devname, "/dev/bluetooth/") != devname) {
376*9cab9fdeSChristos Margiolis printf("Invalid device name '%s'", devname);
377*9cab9fdeSChristos Margiolis goto error;
378*9cab9fdeSChristos Margiolis }
379*9cab9fdeSChristos Margiolis /* skip prefix */
380*9cab9fdeSChristos Margiolis devname += sizeof("/dev/bluetooth/") - 1;
381*9cab9fdeSChristos Margiolis
382*9cab9fdeSChristos Margiolis if (!bt_aton(devname, &info.raddr)) {
383*9cab9fdeSChristos Margiolis struct hostent *he = NULL;
384*9cab9fdeSChristos Margiolis
385*9cab9fdeSChristos Margiolis if ((he = bt_gethostbyname(devname)) == NULL) {
386*9cab9fdeSChristos Margiolis DPRINTF("Could not get host by name\n");
387*9cab9fdeSChristos Margiolis goto error;
388*9cab9fdeSChristos Margiolis }
389*9cab9fdeSChristos Margiolis bdaddr_copy(&info.raddr, (bdaddr_t *)he->h_addr);
390*9cab9fdeSChristos Margiolis }
391*9cab9fdeSChristos Margiolis switch (samplerate) {
392*9cab9fdeSChristos Margiolis case 8000:
393*9cab9fdeSChristos Margiolis cfg->freq = FREQ_UNDEFINED;
394*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0x80;
395*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x0C;
396*9cab9fdeSChristos Margiolis break;
397*9cab9fdeSChristos Margiolis case 11025:
398*9cab9fdeSChristos Margiolis cfg->freq = FREQ_UNDEFINED;
399*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0x40;
400*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x0C;
401*9cab9fdeSChristos Margiolis break;
402*9cab9fdeSChristos Margiolis case 12000:
403*9cab9fdeSChristos Margiolis cfg->freq = FREQ_UNDEFINED;
404*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0x20;
405*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x0C;
406*9cab9fdeSChristos Margiolis break;
407*9cab9fdeSChristos Margiolis case 16000:
408*9cab9fdeSChristos Margiolis cfg->freq = FREQ_16K;
409*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0x10;
410*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x0C;
411*9cab9fdeSChristos Margiolis break;
412*9cab9fdeSChristos Margiolis case 22050:
413*9cab9fdeSChristos Margiolis cfg->freq = FREQ_UNDEFINED;
414*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0x08;
415*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x0C;
416*9cab9fdeSChristos Margiolis break;
417*9cab9fdeSChristos Margiolis case 24000:
418*9cab9fdeSChristos Margiolis cfg->freq = FREQ_UNDEFINED;
419*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0x04;
420*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x0C;
421*9cab9fdeSChristos Margiolis break;
422*9cab9fdeSChristos Margiolis case 32000:
423*9cab9fdeSChristos Margiolis cfg->freq = FREQ_32K;
424*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0x02;
425*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x0C;
426*9cab9fdeSChristos Margiolis break;
427*9cab9fdeSChristos Margiolis case 44100:
428*9cab9fdeSChristos Margiolis cfg->freq = FREQ_44_1K;
429*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0x01;
430*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x0C;
431*9cab9fdeSChristos Margiolis break;
432*9cab9fdeSChristos Margiolis case 48000:
433*9cab9fdeSChristos Margiolis cfg->freq = FREQ_48K;
434*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0;
435*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x8C;
436*9cab9fdeSChristos Margiolis break;
437*9cab9fdeSChristos Margiolis case 64000:
438*9cab9fdeSChristos Margiolis cfg->freq = FREQ_UNDEFINED;
439*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0;
440*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x4C;
441*9cab9fdeSChristos Margiolis break;
442*9cab9fdeSChristos Margiolis case 88200:
443*9cab9fdeSChristos Margiolis cfg->freq = FREQ_UNDEFINED;
444*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0;
445*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x2C;
446*9cab9fdeSChristos Margiolis break;
447*9cab9fdeSChristos Margiolis case 96000:
448*9cab9fdeSChristos Margiolis cfg->freq = FREQ_UNDEFINED;
449*9cab9fdeSChristos Margiolis cfg->aacMode1 = 0;
450*9cab9fdeSChristos Margiolis cfg->aacMode2 = 0x1C;
451*9cab9fdeSChristos Margiolis break;
452*9cab9fdeSChristos Margiolis default:
453*9cab9fdeSChristos Margiolis DPRINTF("Invalid samplerate %d", samplerate);
454*9cab9fdeSChristos Margiolis goto error;
455*9cab9fdeSChristos Margiolis }
456*9cab9fdeSChristos Margiolis cfg->bands = BANDS_8;
457*9cab9fdeSChristos Margiolis cfg->bitpool = 0;
458*9cab9fdeSChristos Margiolis
459*9cab9fdeSChristos Margiolis switch (*pchannels) {
460*9cab9fdeSChristos Margiolis case 1:
461*9cab9fdeSChristos Margiolis cfg->aacMode2 &= 0xF8;
462*9cab9fdeSChristos Margiolis cfg->chmode = MODE_MONO;
463*9cab9fdeSChristos Margiolis break;
464*9cab9fdeSChristos Margiolis default:
465*9cab9fdeSChristos Margiolis cfg->aacMode2 &= 0xF4;
466*9cab9fdeSChristos Margiolis cfg->chmode = MODE_STEREO;
467*9cab9fdeSChristos Margiolis break;
468*9cab9fdeSChristos Margiolis }
469*9cab9fdeSChristos Margiolis
470*9cab9fdeSChristos Margiolis cfg->allocm = ALLOC_LOUDNESS;
471*9cab9fdeSChristos Margiolis
472*9cab9fdeSChristos Margiolis if (cfg->chmode == MODE_MONO || cfg->chmode == MODE_DUAL)
473*9cab9fdeSChristos Margiolis tmpbitpool = 16;
474*9cab9fdeSChristos Margiolis else
475*9cab9fdeSChristos Margiolis tmpbitpool = 32;
476*9cab9fdeSChristos Margiolis
477*9cab9fdeSChristos Margiolis if (cfg->bands == BANDS_8)
478*9cab9fdeSChristos Margiolis tmpbitpool *= 8;
479*9cab9fdeSChristos Margiolis else
480*9cab9fdeSChristos Margiolis tmpbitpool *= 4;
481*9cab9fdeSChristos Margiolis
482*9cab9fdeSChristos Margiolis if (tmpbitpool > DEFAULT_MAXBPOOL)
483*9cab9fdeSChristos Margiolis tmpbitpool = DEFAULT_MAXBPOOL;
484*9cab9fdeSChristos Margiolis
485*9cab9fdeSChristos Margiolis cfg->bitpool = tmpbitpool;
486*9cab9fdeSChristos Margiolis
487*9cab9fdeSChristos Margiolis if (bt_set_format(pformat)) {
488*9cab9fdeSChristos Margiolis DPRINTF("Unsupported sample format\n");
489*9cab9fdeSChristos Margiolis goto error;
490*9cab9fdeSChristos Margiolis }
491*9cab9fdeSChristos Margiolis l2cap_psm = bt_query(&info, service_class);
492*9cab9fdeSChristos Margiolis DPRINTF("PSM=0x%02x\n", l2cap_psm);
493*9cab9fdeSChristos Margiolis if (l2cap_psm < 0) {
494*9cab9fdeSChristos Margiolis DPRINTF("PSM not found\n");
495*9cab9fdeSChristos Margiolis goto error;
496*9cab9fdeSChristos Margiolis }
497*9cab9fdeSChristos Margiolis cfg->hc = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
498*9cab9fdeSChristos Margiolis if (cfg->hc < 0) {
499*9cab9fdeSChristos Margiolis DPRINTF("Could not create BT socket\n");
500*9cab9fdeSChristos Margiolis goto error;
501*9cab9fdeSChristos Margiolis }
502*9cab9fdeSChristos Margiolis memset(&addr, 0, sizeof(addr));
503*9cab9fdeSChristos Margiolis addr.l2cap_len = sizeof(addr);
504*9cab9fdeSChristos Margiolis addr.l2cap_family = AF_BLUETOOTH;
505*9cab9fdeSChristos Margiolis bdaddr_copy(&addr.l2cap_bdaddr, &info.laddr);
506*9cab9fdeSChristos Margiolis
507*9cab9fdeSChristos Margiolis if (bind(cfg->hc, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
508*9cab9fdeSChristos Margiolis DPRINTF("Could not bind to HC\n");
509*9cab9fdeSChristos Margiolis goto error;
510*9cab9fdeSChristos Margiolis }
511*9cab9fdeSChristos Margiolis bdaddr_copy(&addr.l2cap_bdaddr, &info.raddr);
512*9cab9fdeSChristos Margiolis addr.l2cap_psm = l2cap_psm;
513*9cab9fdeSChristos Margiolis if (connect(cfg->hc, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
514*9cab9fdeSChristos Margiolis DPRINTF("Could not connect to HC: %d\n", errno);
515*9cab9fdeSChristos Margiolis goto error;
516*9cab9fdeSChristos Margiolis }
517*9cab9fdeSChristos Margiolis if (avdtpDiscoverAndConfig(cfg, isSink)) {
518*9cab9fdeSChristos Margiolis DPRINTF("DISCOVER FAILED\n");
519*9cab9fdeSChristos Margiolis goto error;
520*9cab9fdeSChristos Margiolis }
521*9cab9fdeSChristos Margiolis if (avdtpOpen(cfg->hc, cfg->sep)) {
522*9cab9fdeSChristos Margiolis DPRINTF("OPEN FAILED\n");
523*9cab9fdeSChristos Margiolis goto error;
524*9cab9fdeSChristos Margiolis }
525*9cab9fdeSChristos Margiolis cfg->fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
526*9cab9fdeSChristos Margiolis if (cfg->fd < 0) {
527*9cab9fdeSChristos Margiolis DPRINTF("Could not create BT socket\n");
528*9cab9fdeSChristos Margiolis goto error;
529*9cab9fdeSChristos Margiolis }
530*9cab9fdeSChristos Margiolis memset(&addr, 0, sizeof(addr));
531*9cab9fdeSChristos Margiolis
532*9cab9fdeSChristos Margiolis addr.l2cap_len = sizeof(addr);
533*9cab9fdeSChristos Margiolis addr.l2cap_family = AF_BLUETOOTH;
534*9cab9fdeSChristos Margiolis bdaddr_copy(&addr.l2cap_bdaddr, &info.laddr);
535*9cab9fdeSChristos Margiolis
536*9cab9fdeSChristos Margiolis if (bind(cfg->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
537*9cab9fdeSChristos Margiolis DPRINTF("Could not bind\n");
538*9cab9fdeSChristos Margiolis goto error;
539*9cab9fdeSChristos Margiolis }
540*9cab9fdeSChristos Margiolis bdaddr_copy(&addr.l2cap_bdaddr, &info.raddr);
541*9cab9fdeSChristos Margiolis addr.l2cap_psm = l2cap_psm;
542*9cab9fdeSChristos Margiolis if (connect(cfg->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
543*9cab9fdeSChristos Margiolis DPRINTF("Could not connect: %d\n", errno);
544*9cab9fdeSChristos Margiolis goto error;
545*9cab9fdeSChristos Margiolis }
546*9cab9fdeSChristos Margiolis if (isSink) {
547*9cab9fdeSChristos Margiolis if (getsockopt(cfg->fd, SOL_L2CAP, SO_L2CAP_OMTU, &cfg->mtu, &mtusize) == -1) {
548*9cab9fdeSChristos Margiolis DPRINTF("Could not get MTU\n");
549*9cab9fdeSChristos Margiolis goto error;
550*9cab9fdeSChristos Margiolis }
551*9cab9fdeSChristos Margiolis temp = cfg->mtu * 16;
552*9cab9fdeSChristos Margiolis if (setsockopt(cfg->fd, SOL_SOCKET, SO_SNDBUF, &temp, sizeof(temp)) == -1) {
553*9cab9fdeSChristos Margiolis DPRINTF("Could not set send buffer size\n");
554*9cab9fdeSChristos Margiolis goto error;
555*9cab9fdeSChristos Margiolis }
556*9cab9fdeSChristos Margiolis temp = cfg->mtu;
557*9cab9fdeSChristos Margiolis if (setsockopt(cfg->fd, SOL_SOCKET, SO_SNDLOWAT, &temp, sizeof(temp)) == -1) {
558*9cab9fdeSChristos Margiolis DPRINTF("Could not set low water mark\n");
559*9cab9fdeSChristos Margiolis goto error;
560*9cab9fdeSChristos Margiolis }
561*9cab9fdeSChristos Margiolis } else {
562*9cab9fdeSChristos Margiolis if (getsockopt(cfg->fd, SOL_L2CAP, SO_L2CAP_IMTU, &cfg->mtu, &mtusize) == -1) {
563*9cab9fdeSChristos Margiolis DPRINTF("Could not get MTU\n");
564*9cab9fdeSChristos Margiolis goto error;
565*9cab9fdeSChristos Margiolis }
566*9cab9fdeSChristos Margiolis temp = cfg->mtu * 16;
567*9cab9fdeSChristos Margiolis if (setsockopt(cfg->fd, SOL_SOCKET, SO_RCVBUF, &temp, sizeof(temp)) == -1) {
568*9cab9fdeSChristos Margiolis DPRINTF("Could not set receive buffer size\n");
569*9cab9fdeSChristos Margiolis goto error;
570*9cab9fdeSChristos Margiolis }
571*9cab9fdeSChristos Margiolis temp = 1;
572*9cab9fdeSChristos Margiolis if (setsockopt(cfg->fd, SOL_SOCKET, SO_RCVLOWAT, &temp, sizeof(temp)) == -1) {
573*9cab9fdeSChristos Margiolis DPRINTF("Could not set low water mark\n");
574*9cab9fdeSChristos Margiolis goto error;
575*9cab9fdeSChristos Margiolis }
576*9cab9fdeSChristos Margiolis temp = 1;
577*9cab9fdeSChristos Margiolis if (ioctl(cfg->fd, FIONBIO, &temp) == -1) {
578*9cab9fdeSChristos Margiolis DPRINTF("Could not set non-blocking I/O for receive direction\n");
579*9cab9fdeSChristos Margiolis goto error;
580*9cab9fdeSChristos Margiolis }
581*9cab9fdeSChristos Margiolis }
582*9cab9fdeSChristos Margiolis
583*9cab9fdeSChristos Margiolis if (avdtpStart(cfg->hc, cfg->sep)) {
584*9cab9fdeSChristos Margiolis DPRINTF("START FAILED\n");
585*9cab9fdeSChristos Margiolis goto error;
586*9cab9fdeSChristos Margiolis }
587*9cab9fdeSChristos Margiolis switch (cfg->chmode) {
588*9cab9fdeSChristos Margiolis case MODE_MONO:
589*9cab9fdeSChristos Margiolis *pchannels = 1;
590*9cab9fdeSChristos Margiolis break;
591*9cab9fdeSChristos Margiolis default:
592*9cab9fdeSChristos Margiolis *pchannels = 2;
593*9cab9fdeSChristos Margiolis break;
594*9cab9fdeSChristos Margiolis }
595*9cab9fdeSChristos Margiolis return (0);
596*9cab9fdeSChristos Margiolis
597*9cab9fdeSChristos Margiolis error:
598*9cab9fdeSChristos Margiolis if (cfg->hc > 0) {
599*9cab9fdeSChristos Margiolis close(cfg->hc);
600*9cab9fdeSChristos Margiolis cfg->hc = -1;
601*9cab9fdeSChristos Margiolis }
602*9cab9fdeSChristos Margiolis if (cfg->fd > 0) {
603*9cab9fdeSChristos Margiolis close(cfg->fd);
604*9cab9fdeSChristos Margiolis cfg->fd = -1;
605*9cab9fdeSChristos Margiolis }
606*9cab9fdeSChristos Margiolis return (-1);
607*9cab9fdeSChristos Margiolis }
608*9cab9fdeSChristos Margiolis
609*9cab9fdeSChristos Margiolis static void
bt_init_cfg(struct bt_config * cfg)610*9cab9fdeSChristos Margiolis bt_init_cfg(struct bt_config *cfg)
611*9cab9fdeSChristos Margiolis {
612*9cab9fdeSChristos Margiolis memset(cfg, 0, sizeof(*cfg));
613*9cab9fdeSChristos Margiolis }
614*9cab9fdeSChristos Margiolis
615*9cab9fdeSChristos Margiolis static int
bt_rec_open(struct voss_backend * pbe,const char * devname,int samplerate,int bufsize,int * pchannels,int * pformat)616*9cab9fdeSChristos Margiolis bt_rec_open(struct voss_backend *pbe, const char *devname, int samplerate,
617*9cab9fdeSChristos Margiolis int bufsize, int *pchannels, int *pformat)
618*9cab9fdeSChristos Margiolis {
619*9cab9fdeSChristos Margiolis struct bt_config *cfg = pbe->arg;
620*9cab9fdeSChristos Margiolis int retval;
621*9cab9fdeSChristos Margiolis
622*9cab9fdeSChristos Margiolis bt_init_cfg(cfg);
623*9cab9fdeSChristos Margiolis
624*9cab9fdeSChristos Margiolis retval = bt_open(pbe, devname, samplerate, bufsize, pchannels, pformat,
625*9cab9fdeSChristos Margiolis cfg, SDP_SERVICE_CLASS_AUDIO_SOURCE, 0);
626*9cab9fdeSChristos Margiolis if (retval != 0)
627*9cab9fdeSChristos Margiolis return (retval);
628*9cab9fdeSChristos Margiolis return (0);
629*9cab9fdeSChristos Margiolis }
630*9cab9fdeSChristos Margiolis
631*9cab9fdeSChristos Margiolis static int
bt_play_open(struct voss_backend * pbe,const char * devname,int samplerate,int bufsize,int * pchannels,int * pformat)632*9cab9fdeSChristos Margiolis bt_play_open(struct voss_backend *pbe, const char *devname, int samplerate,
633*9cab9fdeSChristos Margiolis int bufsize, int *pchannels, int *pformat)
634*9cab9fdeSChristos Margiolis {
635*9cab9fdeSChristos Margiolis struct bt_config *cfg = pbe->arg;
636*9cab9fdeSChristos Margiolis int retval;
637*9cab9fdeSChristos Margiolis
638*9cab9fdeSChristos Margiolis bt_init_cfg(cfg);
639*9cab9fdeSChristos Margiolis
640*9cab9fdeSChristos Margiolis retval = bt_open(pbe, devname, samplerate, bufsize, pchannels, pformat,
641*9cab9fdeSChristos Margiolis cfg, SDP_SERVICE_CLASS_AUDIO_SINK, 1);
642*9cab9fdeSChristos Margiolis if (retval != 0)
643*9cab9fdeSChristos Margiolis return (retval);
644*9cab9fdeSChristos Margiolis
645*9cab9fdeSChristos Margiolis /* setup codec */
646*9cab9fdeSChristos Margiolis switch (cfg->codec) {
647*9cab9fdeSChristos Margiolis case CODEC_SBC:
648*9cab9fdeSChristos Margiolis cfg->handle.sbc_enc =
649*9cab9fdeSChristos Margiolis malloc(sizeof(*cfg->handle.sbc_enc));
650*9cab9fdeSChristos Margiolis if (cfg->handle.sbc_enc == NULL)
651*9cab9fdeSChristos Margiolis return (-1);
652*9cab9fdeSChristos Margiolis memset(cfg->handle.sbc_enc, 0, sizeof(*cfg->handle.sbc_enc));
653*9cab9fdeSChristos Margiolis break;
654*9cab9fdeSChristos Margiolis #ifdef HAVE_LIBAV
655*9cab9fdeSChristos Margiolis case CODEC_AAC:
656*9cab9fdeSChristos Margiolis cfg->handle.av.codec = __DECONST(AVCodec *,
657*9cab9fdeSChristos Margiolis avcodec_find_encoder_by_name("aac"));
658*9cab9fdeSChristos Margiolis if (cfg->handle.av.codec == NULL) {
659*9cab9fdeSChristos Margiolis DPRINTF("Codec AAC encoder not found\n");
660*9cab9fdeSChristos Margiolis goto av_error_0;
661*9cab9fdeSChristos Margiolis }
662*9cab9fdeSChristos Margiolis cfg->handle.av.format = avformat_alloc_context();
663*9cab9fdeSChristos Margiolis if (cfg->handle.av.format == NULL) {
664*9cab9fdeSChristos Margiolis DPRINTF("Could not allocate format context\n");
665*9cab9fdeSChristos Margiolis goto av_error_0;
666*9cab9fdeSChristos Margiolis }
667*9cab9fdeSChristos Margiolis cfg->handle.av.format->oformat =
668*9cab9fdeSChristos Margiolis av_guess_format("latm", NULL, NULL);
669*9cab9fdeSChristos Margiolis if (cfg->handle.av.format->oformat == NULL) {
670*9cab9fdeSChristos Margiolis DPRINTF("Could not guess output format\n");
671*9cab9fdeSChristos Margiolis goto av_error_1;
672*9cab9fdeSChristos Margiolis }
673*9cab9fdeSChristos Margiolis cfg->handle.av.stream = avformat_new_stream(
674*9cab9fdeSChristos Margiolis cfg->handle.av.format, cfg->handle.av.codec);
675*9cab9fdeSChristos Margiolis
676*9cab9fdeSChristos Margiolis if (cfg->handle.av.stream == NULL) {
677*9cab9fdeSChristos Margiolis DPRINTF("Could not create new stream\n");
678*9cab9fdeSChristos Margiolis goto av_error_1;
679*9cab9fdeSChristos Margiolis }
680*9cab9fdeSChristos Margiolis cfg->handle.av.context = avcodec_alloc_context3(cfg->handle.av.codec);
681*9cab9fdeSChristos Margiolis if (cfg->handle.av.context == NULL) {
682*9cab9fdeSChristos Margiolis DPRINTF("Could not allocate audio context\n");
683*9cab9fdeSChristos Margiolis goto av_error_1;
684*9cab9fdeSChristos Margiolis }
685*9cab9fdeSChristos Margiolis /*avcodec_get_context_defaults3(cfg->handle.av.context,*/
686*9cab9fdeSChristos Margiolis /*cfg->handle.av.codec);*/
687*9cab9fdeSChristos Margiolis
688*9cab9fdeSChristos Margiolis cfg->handle.av.context->bit_rate = 128000;
689*9cab9fdeSChristos Margiolis cfg->handle.av.context->sample_fmt = AV_SAMPLE_FMT_FLTP;
690*9cab9fdeSChristos Margiolis cfg->handle.av.context->sample_rate = samplerate;
691*9cab9fdeSChristos Margiolis switch (*pchannels) {
692*9cab9fdeSChristos Margiolis case 1:
693*9cab9fdeSChristos Margiolis cfg->handle.av.context->ch_layout = *(AVChannelLayout *)AV_CH_LAYOUT_MONO;
694*9cab9fdeSChristos Margiolis break;
695*9cab9fdeSChristos Margiolis default:
696*9cab9fdeSChristos Margiolis cfg->handle.av.context->ch_layout = *(AVChannelLayout *)AV_CH_LAYOUT_STEREO;
697*9cab9fdeSChristos Margiolis break;
698*9cab9fdeSChristos Margiolis }
699*9cab9fdeSChristos Margiolis
700*9cab9fdeSChristos Margiolis cfg->handle.av.context->profile = FF_PROFILE_AAC_LOW;
701*9cab9fdeSChristos Margiolis if (1) {
702*9cab9fdeSChristos Margiolis AVDictionary *opts = NULL;
703*9cab9fdeSChristos Margiolis
704*9cab9fdeSChristos Margiolis av_dict_set(&opts, "strict", "-2", 0);
705*9cab9fdeSChristos Margiolis av_dict_set_int(&opts, "latm", 1, 0);
706*9cab9fdeSChristos Margiolis
707*9cab9fdeSChristos Margiolis if (avcodec_open2(cfg->handle.av.context,
708*9cab9fdeSChristos Margiolis cfg->handle.av.codec, &opts) < 0) {
709*9cab9fdeSChristos Margiolis av_dict_free(&opts);
710*9cab9fdeSChristos Margiolis
711*9cab9fdeSChristos Margiolis DPRINTF("Could not open codec\n");
712*9cab9fdeSChristos Margiolis goto av_error_1;
713*9cab9fdeSChristos Margiolis }
714*9cab9fdeSChristos Margiolis av_dict_free(&opts);
715*9cab9fdeSChristos Margiolis }
716*9cab9fdeSChristos Margiolis cfg->handle.av.frame = av_frame_alloc();
717*9cab9fdeSChristos Margiolis if (cfg->handle.av.frame == NULL) {
718*9cab9fdeSChristos Margiolis DPRINTF("Could not allocate audio frame\n");
719*9cab9fdeSChristos Margiolis goto av_error_2;
720*9cab9fdeSChristos Margiolis }
721*9cab9fdeSChristos Margiolis cfg->handle.av.frame->nb_samples = cfg->handle.av.context->frame_size;
722*9cab9fdeSChristos Margiolis cfg->handle.av.frame->format = cfg->handle.av.context->sample_fmt;
723*9cab9fdeSChristos Margiolis cfg->handle.av.frame->ch_layout = cfg->handle.av.context->ch_layout;
724*9cab9fdeSChristos Margiolis cfg->rem_in_size = av_samples_get_buffer_size(NULL,
725*9cab9fdeSChristos Margiolis cfg->handle.av.context->ch_layout.nb_channels,
726*9cab9fdeSChristos Margiolis cfg->handle.av.context->frame_size,
727*9cab9fdeSChristos Margiolis cfg->handle.av.context->sample_fmt, 0);
728*9cab9fdeSChristos Margiolis
729*9cab9fdeSChristos Margiolis cfg->rem_in_data = av_malloc(cfg->rem_in_size);
730*9cab9fdeSChristos Margiolis if (cfg->rem_in_data == NULL) {
731*9cab9fdeSChristos Margiolis DPRINTF("Could not allocate %u bytes sample buffer\n",
732*9cab9fdeSChristos Margiolis (unsigned)cfg->rem_in_size);
733*9cab9fdeSChristos Margiolis goto av_error_3;
734*9cab9fdeSChristos Margiolis }
735*9cab9fdeSChristos Margiolis retval = avcodec_fill_audio_frame(cfg->handle.av.frame,
736*9cab9fdeSChristos Margiolis cfg->handle.av.context->ch_layout.nb_channels,
737*9cab9fdeSChristos Margiolis cfg->handle.av.context->sample_fmt,
738*9cab9fdeSChristos Margiolis cfg->rem_in_data, cfg->rem_in_size, 0);
739*9cab9fdeSChristos Margiolis if (retval < 0) {
740*9cab9fdeSChristos Margiolis DPRINTF("Could not setup audio frame\n");
741*9cab9fdeSChristos Margiolis goto av_error_4;
742*9cab9fdeSChristos Margiolis }
743*9cab9fdeSChristos Margiolis break;
744*9cab9fdeSChristos Margiolis av_error_4:
745*9cab9fdeSChristos Margiolis av_free(cfg->rem_in_data);
746*9cab9fdeSChristos Margiolis av_error_3:
747*9cab9fdeSChristos Margiolis av_frame_free(&cfg->handle.av.frame);
748*9cab9fdeSChristos Margiolis av_error_2:
749*9cab9fdeSChristos Margiolis avcodec_close(cfg->handle.av.context);
750*9cab9fdeSChristos Margiolis av_error_1:
751*9cab9fdeSChristos Margiolis avformat_free_context(cfg->handle.av.format);
752*9cab9fdeSChristos Margiolis cfg->handle.av.context = NULL;
753*9cab9fdeSChristos Margiolis av_error_0:
754*9cab9fdeSChristos Margiolis bt_close(pbe);
755*9cab9fdeSChristos Margiolis return (-1);
756*9cab9fdeSChristos Margiolis #endif
757*9cab9fdeSChristos Margiolis default:
758*9cab9fdeSChristos Margiolis bt_close(pbe);
759*9cab9fdeSChristos Margiolis return (-1);
760*9cab9fdeSChristos Margiolis }
761*9cab9fdeSChristos Margiolis return (0);
762*9cab9fdeSChristos Margiolis }
763*9cab9fdeSChristos Margiolis
764*9cab9fdeSChristos Margiolis static int
bt_rec_transfer(struct voss_backend * pbe,void * ptr,int len)765*9cab9fdeSChristos Margiolis bt_rec_transfer(struct voss_backend *pbe, void *ptr, int len)
766*9cab9fdeSChristos Margiolis {
767*9cab9fdeSChristos Margiolis return (bt_receive(pbe->arg, ptr, len, 1));
768*9cab9fdeSChristos Margiolis }
769*9cab9fdeSChristos Margiolis
770*9cab9fdeSChristos Margiolis static int
bt_play_sbc_transfer(struct voss_backend * pbe,void * ptr,int len)771*9cab9fdeSChristos Margiolis bt_play_sbc_transfer(struct voss_backend *pbe, void *ptr, int len)
772*9cab9fdeSChristos Margiolis {
773*9cab9fdeSChristos Margiolis struct bt_config *cfg = pbe->arg;
774*9cab9fdeSChristos Margiolis struct sbc_encode *sbc = cfg->handle.sbc_enc;
775*9cab9fdeSChristos Margiolis int rem_size = 1;
776*9cab9fdeSChristos Margiolis int old_len = len;
777*9cab9fdeSChristos Margiolis int err = 0;
778*9cab9fdeSChristos Margiolis
779*9cab9fdeSChristos Margiolis switch (cfg->blocks) {
780*9cab9fdeSChristos Margiolis case BLOCKS_4:
781*9cab9fdeSChristos Margiolis sbc->blocks = 4;
782*9cab9fdeSChristos Margiolis rem_size *= 4;
783*9cab9fdeSChristos Margiolis break;
784*9cab9fdeSChristos Margiolis case BLOCKS_8:
785*9cab9fdeSChristos Margiolis sbc->blocks = 8;
786*9cab9fdeSChristos Margiolis rem_size *= 8;
787*9cab9fdeSChristos Margiolis break;
788*9cab9fdeSChristos Margiolis case BLOCKS_12:
789*9cab9fdeSChristos Margiolis sbc->blocks = 12;
790*9cab9fdeSChristos Margiolis rem_size *= 12;
791*9cab9fdeSChristos Margiolis break;
792*9cab9fdeSChristos Margiolis default:
793*9cab9fdeSChristos Margiolis sbc->blocks = 16;
794*9cab9fdeSChristos Margiolis rem_size *= 16;
795*9cab9fdeSChristos Margiolis break;
796*9cab9fdeSChristos Margiolis }
797*9cab9fdeSChristos Margiolis
798*9cab9fdeSChristos Margiolis switch (cfg->bands) {
799*9cab9fdeSChristos Margiolis case BANDS_4:
800*9cab9fdeSChristos Margiolis rem_size *= 4;
801*9cab9fdeSChristos Margiolis sbc->bands = 4;
802*9cab9fdeSChristos Margiolis break;
803*9cab9fdeSChristos Margiolis default:
804*9cab9fdeSChristos Margiolis rem_size *= 8;
805*9cab9fdeSChristos Margiolis sbc->bands = 8;
806*9cab9fdeSChristos Margiolis break;
807*9cab9fdeSChristos Margiolis }
808*9cab9fdeSChristos Margiolis
809*9cab9fdeSChristos Margiolis /* store number of samples per frame */
810*9cab9fdeSChristos Margiolis sbc->framesamples = rem_size;
811*9cab9fdeSChristos Margiolis
812*9cab9fdeSChristos Margiolis if (cfg->chmode != MODE_MONO) {
813*9cab9fdeSChristos Margiolis rem_size *= 2;
814*9cab9fdeSChristos Margiolis sbc->channels = 2;
815*9cab9fdeSChristos Margiolis } else {
816*9cab9fdeSChristos Margiolis sbc->channels = 1;
817*9cab9fdeSChristos Margiolis }
818*9cab9fdeSChristos Margiolis
819*9cab9fdeSChristos Margiolis rem_size *= 2; /* 16-bit samples */
820*9cab9fdeSChristos Margiolis
821*9cab9fdeSChristos Margiolis while (len > 0) {
822*9cab9fdeSChristos Margiolis int delta = len;
823*9cab9fdeSChristos Margiolis
824*9cab9fdeSChristos Margiolis if (delta > (int)(rem_size - sbc->rem_len))
825*9cab9fdeSChristos Margiolis delta = (int)(rem_size - sbc->rem_len);
826*9cab9fdeSChristos Margiolis
827*9cab9fdeSChristos Margiolis /* copy in samples */
828*9cab9fdeSChristos Margiolis memcpy((char *)sbc->music_data + sbc->rem_len, ptr, delta);
829*9cab9fdeSChristos Margiolis
830*9cab9fdeSChristos Margiolis ptr = (char *)ptr + delta;
831*9cab9fdeSChristos Margiolis len -= delta;
832*9cab9fdeSChristos Margiolis sbc->rem_len += delta;
833*9cab9fdeSChristos Margiolis
834*9cab9fdeSChristos Margiolis /* check if buffer is full */
835*9cab9fdeSChristos Margiolis if ((int)sbc->rem_len == rem_size) {
836*9cab9fdeSChristos Margiolis struct sbc_header *phdr = (struct sbc_header *)cfg->mtu_data;
837*9cab9fdeSChristos Margiolis uint32_t pkt_len;
838*9cab9fdeSChristos Margiolis uint32_t rem;
839*9cab9fdeSChristos Margiolis
840*9cab9fdeSChristos Margiolis if (cfg->chmode == MODE_MONO)
841*9cab9fdeSChristos Margiolis sbc->channels = 1;
842*9cab9fdeSChristos Margiolis else
843*9cab9fdeSChristos Margiolis sbc->channels = 2;
844*9cab9fdeSChristos Margiolis
845*9cab9fdeSChristos Margiolis pkt_len = sbc_encode_frame(cfg);
846*9cab9fdeSChristos Margiolis
847*9cab9fdeSChristos Margiolis retry:
848*9cab9fdeSChristos Margiolis if (cfg->mtu_offset == 0) {
849*9cab9fdeSChristos Margiolis phdr->id = 0x80; /* RTP v2 */
850*9cab9fdeSChristos Margiolis phdr->id2 = 0x60; /* payload type 96. */
851*9cab9fdeSChristos Margiolis phdr->seqnumMSB = (uint8_t)(cfg->mtu_seqnumber >> 8);
852*9cab9fdeSChristos Margiolis phdr->seqnumLSB = (uint8_t)(cfg->mtu_seqnumber);
853*9cab9fdeSChristos Margiolis phdr->ts3 = (uint8_t)(cfg->mtu_timestamp >> 24);
854*9cab9fdeSChristos Margiolis phdr->ts2 = (uint8_t)(cfg->mtu_timestamp >> 16);
855*9cab9fdeSChristos Margiolis phdr->ts1 = (uint8_t)(cfg->mtu_timestamp >> 8);
856*9cab9fdeSChristos Margiolis phdr->ts0 = (uint8_t)(cfg->mtu_timestamp);
857*9cab9fdeSChristos Margiolis phdr->reserved0 = 0x01;
858*9cab9fdeSChristos Margiolis phdr->numFrames = 0;
859*9cab9fdeSChristos Margiolis
860*9cab9fdeSChristos Margiolis cfg->mtu_seqnumber++;
861*9cab9fdeSChristos Margiolis cfg->mtu_offset += sizeof(*phdr);
862*9cab9fdeSChristos Margiolis }
863*9cab9fdeSChristos Margiolis /* compute bytes left */
864*9cab9fdeSChristos Margiolis rem = cfg->mtu - cfg->mtu_offset;
865*9cab9fdeSChristos Margiolis
866*9cab9fdeSChristos Margiolis if (phdr->numFrames == 255 || rem < pkt_len) {
867*9cab9fdeSChristos Margiolis int xlen;
868*9cab9fdeSChristos Margiolis
869*9cab9fdeSChristos Margiolis if (phdr->numFrames == 0)
870*9cab9fdeSChristos Margiolis return (-1);
871*9cab9fdeSChristos Margiolis do {
872*9cab9fdeSChristos Margiolis xlen = write(cfg->fd, cfg->mtu_data, cfg->mtu_offset);
873*9cab9fdeSChristos Margiolis } while (xlen < 0 && errno == EAGAIN);
874*9cab9fdeSChristos Margiolis
875*9cab9fdeSChristos Margiolis if (xlen < 0)
876*9cab9fdeSChristos Margiolis return (-1);
877*9cab9fdeSChristos Margiolis
878*9cab9fdeSChristos Margiolis cfg->mtu_offset = 0;
879*9cab9fdeSChristos Margiolis goto retry;
880*9cab9fdeSChristos Margiolis }
881*9cab9fdeSChristos Margiolis memcpy(cfg->mtu_data + cfg->mtu_offset, sbc->data, pkt_len);
882*9cab9fdeSChristos Margiolis memset(sbc->data, 0, pkt_len);
883*9cab9fdeSChristos Margiolis cfg->mtu_offset += pkt_len;
884*9cab9fdeSChristos Margiolis cfg->mtu_timestamp += sbc->framesamples;
885*9cab9fdeSChristos Margiolis phdr->numFrames++;
886*9cab9fdeSChristos Margiolis
887*9cab9fdeSChristos Margiolis sbc->rem_len = 0;
888*9cab9fdeSChristos Margiolis }
889*9cab9fdeSChristos Margiolis }
890*9cab9fdeSChristos Margiolis if (err == 0)
891*9cab9fdeSChristos Margiolis return (old_len);
892*9cab9fdeSChristos Margiolis return (err);
893*9cab9fdeSChristos Margiolis }
894*9cab9fdeSChristos Margiolis
895*9cab9fdeSChristos Margiolis #ifdef HAVE_LIBAV
896*9cab9fdeSChristos Margiolis static int
bt_play_aac_transfer(struct voss_backend * pbe,void * ptr,int len)897*9cab9fdeSChristos Margiolis bt_play_aac_transfer(struct voss_backend *pbe, void *ptr, int len)
898*9cab9fdeSChristos Margiolis {
899*9cab9fdeSChristos Margiolis struct bt_config *cfg = pbe->arg;
900*9cab9fdeSChristos Margiolis struct aac_header {
901*9cab9fdeSChristos Margiolis uint8_t id;
902*9cab9fdeSChristos Margiolis uint8_t id2;
903*9cab9fdeSChristos Margiolis uint8_t seqnumMSB;
904*9cab9fdeSChristos Margiolis uint8_t seqnumLSB;
905*9cab9fdeSChristos Margiolis uint8_t ts3;
906*9cab9fdeSChristos Margiolis uint8_t ts2;
907*9cab9fdeSChristos Margiolis uint8_t ts1;
908*9cab9fdeSChristos Margiolis uint8_t ts0;
909*9cab9fdeSChristos Margiolis uint8_t sync3;
910*9cab9fdeSChristos Margiolis uint8_t sync2;
911*9cab9fdeSChristos Margiolis uint8_t sync1;
912*9cab9fdeSChristos Margiolis uint8_t sync0;
913*9cab9fdeSChristos Margiolis uint8_t fixed[8];
914*9cab9fdeSChristos Margiolis };
915*9cab9fdeSChristos Margiolis int old_len = len;
916*9cab9fdeSChristos Margiolis int err = 0;
917*9cab9fdeSChristos Margiolis
918*9cab9fdeSChristos Margiolis while (len > 0) {
919*9cab9fdeSChristos Margiolis int delta = len;
920*9cab9fdeSChristos Margiolis int rem;
921*9cab9fdeSChristos Margiolis
922*9cab9fdeSChristos Margiolis if (delta > (int)(cfg->rem_in_size - cfg->rem_in_len))
923*9cab9fdeSChristos Margiolis delta = (int)(cfg->rem_in_size - cfg->rem_in_len);
924*9cab9fdeSChristos Margiolis
925*9cab9fdeSChristos Margiolis memcpy(cfg->rem_in_data + cfg->rem_in_len, ptr, delta);
926*9cab9fdeSChristos Margiolis
927*9cab9fdeSChristos Margiolis ptr = (char *)ptr + delta;
928*9cab9fdeSChristos Margiolis len -= delta;
929*9cab9fdeSChristos Margiolis cfg->rem_in_len += delta;
930*9cab9fdeSChristos Margiolis
931*9cab9fdeSChristos Margiolis /* check if buffer is full */
932*9cab9fdeSChristos Margiolis if (cfg->rem_in_len == cfg->rem_in_size) {
933*9cab9fdeSChristos Margiolis struct aac_header *phdr = (struct aac_header *)cfg->mtu_data;
934*9cab9fdeSChristos Margiolis AVPacket *pkt;
935*9cab9fdeSChristos Margiolis uint8_t *pkt_buf;
936*9cab9fdeSChristos Margiolis int pkt_len;
937*9cab9fdeSChristos Margiolis
938*9cab9fdeSChristos Margiolis pkt = av_packet_alloc();
939*9cab9fdeSChristos Margiolis err = avcodec_send_frame(cfg->handle.av.context,
940*9cab9fdeSChristos Margiolis cfg->handle.av.frame);
941*9cab9fdeSChristos Margiolis if (err < 0) {
942*9cab9fdeSChristos Margiolis DPRINTF("Error encoding audio frame\n");
943*9cab9fdeSChristos Margiolis return (-1);
944*9cab9fdeSChristos Margiolis }
945*9cab9fdeSChristos Margiolis phdr->id = 0x80;/* RTP v2 */
946*9cab9fdeSChristos Margiolis phdr->id2 = 0x60; /* payload type 96. */
947*9cab9fdeSChristos Margiolis phdr->seqnumMSB = (uint8_t)(cfg->mtu_seqnumber >> 8);
948*9cab9fdeSChristos Margiolis phdr->seqnumLSB = (uint8_t)(cfg->mtu_seqnumber);
949*9cab9fdeSChristos Margiolis phdr->ts3 = (uint8_t)(cfg->mtu_timestamp >> 24);
950*9cab9fdeSChristos Margiolis phdr->ts2 = (uint8_t)(cfg->mtu_timestamp >> 16);
951*9cab9fdeSChristos Margiolis phdr->ts1 = (uint8_t)(cfg->mtu_timestamp >> 8);
952*9cab9fdeSChristos Margiolis phdr->ts0 = (uint8_t)(cfg->mtu_timestamp);
953*9cab9fdeSChristos Margiolis phdr->sync3 = 0;
954*9cab9fdeSChristos Margiolis phdr->sync2 = 0;
955*9cab9fdeSChristos Margiolis phdr->sync1 = 0;
956*9cab9fdeSChristos Margiolis phdr->sync0 = 0;
957*9cab9fdeSChristos Margiolis phdr->fixed[0] = 0xfc;
958*9cab9fdeSChristos Margiolis phdr->fixed[1] = 0x00;
959*9cab9fdeSChristos Margiolis phdr->fixed[2] = 0x00;
960*9cab9fdeSChristos Margiolis phdr->fixed[3] = 0xb0;
961*9cab9fdeSChristos Margiolis phdr->fixed[4] = 0x90;
962*9cab9fdeSChristos Margiolis phdr->fixed[5] = 0x80;
963*9cab9fdeSChristos Margiolis phdr->fixed[6] = 0x03;
964*9cab9fdeSChristos Margiolis phdr->fixed[7] = 0x00;
965*9cab9fdeSChristos Margiolis
966*9cab9fdeSChristos Margiolis cfg->mtu_seqnumber++;
967*9cab9fdeSChristos Margiolis cfg->mtu_offset = sizeof(*phdr);
968*9cab9fdeSChristos Margiolis
969*9cab9fdeSChristos Margiolis /* compute bytes left */
970*9cab9fdeSChristos Margiolis rem = cfg->mtu - cfg->mtu_offset;
971*9cab9fdeSChristos Margiolis
972*9cab9fdeSChristos Margiolis if (avio_open_dyn_buf(&cfg->handle.av.format->pb) == 0) {
973*9cab9fdeSChristos Margiolis static int once = 0;
974*9cab9fdeSChristos Margiolis
975*9cab9fdeSChristos Margiolis if (!once++)
976*9cab9fdeSChristos Margiolis (void)avformat_write_header(cfg->handle.av.format, NULL);
977*9cab9fdeSChristos Margiolis av_write_frame(cfg->handle.av.format, pkt);
978*9cab9fdeSChristos Margiolis av_packet_unref(pkt);
979*9cab9fdeSChristos Margiolis pkt_len = avio_close_dyn_buf(cfg->handle.av.format->pb, &pkt_buf);
980*9cab9fdeSChristos Margiolis if (rem < pkt_len)
981*9cab9fdeSChristos Margiolis DPRINTF("Out of buffer space\n");
982*9cab9fdeSChristos Margiolis if (pkt_len >= 3 && rem >= pkt_len) {
983*9cab9fdeSChristos Margiolis int xlen;
984*9cab9fdeSChristos Margiolis
985*9cab9fdeSChristos Margiolis memcpy(cfg->mtu_data + cfg->mtu_offset, pkt_buf + 3, pkt_len - 3);
986*9cab9fdeSChristos Margiolis
987*9cab9fdeSChristos Margiolis av_free(pkt_buf);
988*9cab9fdeSChristos Margiolis
989*9cab9fdeSChristos Margiolis cfg->mtu_offset += pkt_len - 3;
990*9cab9fdeSChristos Margiolis if (cfg->chmode != MODE_MONO)
991*9cab9fdeSChristos Margiolis cfg->mtu_timestamp += cfg->rem_in_size / 4;
992*9cab9fdeSChristos Margiolis else
993*9cab9fdeSChristos Margiolis cfg->mtu_timestamp += cfg->rem_in_size / 2;
994*9cab9fdeSChristos Margiolis do {
995*9cab9fdeSChristos Margiolis xlen = write(cfg->fd, cfg->mtu_data, cfg->mtu_offset);
996*9cab9fdeSChristos Margiolis } while (xlen < 0 && errno == EAGAIN);
997*9cab9fdeSChristos Margiolis
998*9cab9fdeSChristos Margiolis if (xlen < 0)
999*9cab9fdeSChristos Margiolis return (-1);
1000*9cab9fdeSChristos Margiolis } else {
1001*9cab9fdeSChristos Margiolis av_free(pkt_buf);
1002*9cab9fdeSChristos Margiolis }
1003*9cab9fdeSChristos Margiolis } else {
1004*9cab9fdeSChristos Margiolis av_packet_unref(pkt);
1005*9cab9fdeSChristos Margiolis }
1006*9cab9fdeSChristos Margiolis /* reset remaining length */
1007*9cab9fdeSChristos Margiolis cfg->rem_in_len = 0;
1008*9cab9fdeSChristos Margiolis }
1009*9cab9fdeSChristos Margiolis }
1010*9cab9fdeSChristos Margiolis if (err == 0)
1011*9cab9fdeSChristos Margiolis return (old_len);
1012*9cab9fdeSChristos Margiolis return (err);
1013*9cab9fdeSChristos Margiolis }
1014*9cab9fdeSChristos Margiolis
1015*9cab9fdeSChristos Margiolis #endif
1016*9cab9fdeSChristos Margiolis
1017*9cab9fdeSChristos Margiolis static int
bt_play_transfer(struct voss_backend * pbe,void * ptr,int len)1018*9cab9fdeSChristos Margiolis bt_play_transfer(struct voss_backend *pbe, void *ptr, int len)
1019*9cab9fdeSChristos Margiolis {
1020*9cab9fdeSChristos Margiolis struct bt_config *cfg = pbe->arg;
1021*9cab9fdeSChristos Margiolis
1022*9cab9fdeSChristos Margiolis switch (cfg->codec) {
1023*9cab9fdeSChristos Margiolis case CODEC_SBC:
1024*9cab9fdeSChristos Margiolis return (bt_play_sbc_transfer(pbe, ptr, len));
1025*9cab9fdeSChristos Margiolis #ifdef HAVE_LIBAV
1026*9cab9fdeSChristos Margiolis case CODEC_AAC:
1027*9cab9fdeSChristos Margiolis return (bt_play_aac_transfer(pbe, ptr, len));
1028*9cab9fdeSChristos Margiolis #endif
1029*9cab9fdeSChristos Margiolis default:
1030*9cab9fdeSChristos Margiolis return (-1);
1031*9cab9fdeSChristos Margiolis }
1032*9cab9fdeSChristos Margiolis }
1033*9cab9fdeSChristos Margiolis
1034*9cab9fdeSChristos Margiolis static void
bt_rec_delay(struct voss_backend * pbe __unused,int * pdelay)1035*9cab9fdeSChristos Margiolis bt_rec_delay(struct voss_backend *pbe __unused, int *pdelay)
1036*9cab9fdeSChristos Margiolis {
1037*9cab9fdeSChristos Margiolis *pdelay = -1;
1038*9cab9fdeSChristos Margiolis }
1039*9cab9fdeSChristos Margiolis
1040*9cab9fdeSChristos Margiolis static void
bt_play_delay(struct voss_backend * pbe __unused,int * pdelay)1041*9cab9fdeSChristos Margiolis bt_play_delay(struct voss_backend *pbe __unused, int *pdelay)
1042*9cab9fdeSChristos Margiolis {
1043*9cab9fdeSChristos Margiolis /* TODO */
1044*9cab9fdeSChristos Margiolis *pdelay = -1;
1045*9cab9fdeSChristos Margiolis }
1046*9cab9fdeSChristos Margiolis
1047*9cab9fdeSChristos Margiolis struct voss_backend voss_backend_bt_rec = {
1048*9cab9fdeSChristos Margiolis .open = bt_rec_open,
1049*9cab9fdeSChristos Margiolis .close = bt_rec_close,
1050*9cab9fdeSChristos Margiolis .transfer = bt_rec_transfer,
1051*9cab9fdeSChristos Margiolis .delay = bt_rec_delay,
1052*9cab9fdeSChristos Margiolis .arg = &bt_rec_cfg,
1053*9cab9fdeSChristos Margiolis };
1054*9cab9fdeSChristos Margiolis
1055*9cab9fdeSChristos Margiolis struct voss_backend voss_backend_bt_play = {
1056*9cab9fdeSChristos Margiolis .open = bt_play_open,
1057*9cab9fdeSChristos Margiolis .close = bt_play_close,
1058*9cab9fdeSChristos Margiolis .transfer = bt_play_transfer,
1059*9cab9fdeSChristos Margiolis .delay = bt_play_delay,
1060*9cab9fdeSChristos Margiolis .arg = &bt_play_cfg,
1061*9cab9fdeSChristos Margiolis };
1062