ipctest.c revision e6522bd8c03008afa5ed3bf9c71c24702f064bad
1b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau/*
2b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
3b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  BlueZ - Bluetooth protocol stack for Linux
4b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
5b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau *  Copyright (C) 2006-2009  Nokia Corporation
6b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
7563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau *  Copyright (C) 2009	Lennart Poettering
8563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau *  Copyright (C) 2008	Joao Paulo Rechi Vita
9b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
10b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
11b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  This library is free software; you can redistribute it and/or
12b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  modify it under the terms of the GNU Lesser General Public
13b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  License as published by the Free Software Foundation; either
14b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  version 2.1 of the License, or (at your option) any later version.
15b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
16b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  This library is distributed in the hope that it will be useful,
17b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  Lesser General Public License for more details.
20b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
21b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  You should have received a copy of the GNU Lesser General Public
22b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  License along with this library; if not, write to the Free Software
23b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau *
25b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau */
26b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
27b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifdef HAVE_CONFIG_H
28b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <config.h>
29b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
30b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
31b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <stdlib.h>
32b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <stdio.h>
33b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <errno.h>
34b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <string.h>
35b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <assert.h>
36b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <libgen.h>
37b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#include <unistd.h>
38b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#include <fcntl.h>
39b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
40b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include <glib.h>
41b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
42b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include "ipc.h"
43b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#include "sbc.h"
44b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
45b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#define DBG(fmt, arg...)				\
46b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	printf("debug %s: " fmt "\n" , __FUNCTION__ , ## arg)
47b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#define ERR(fmt, arg...)				\
48b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	fprintf(stderr, "ERROR %s: " fmt "\n" , __FUNCTION__ , ## arg)
49b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
50b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
51b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
52b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifndef MIN
53b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau# define MIN(x, y) ((x) < (y) ? (x) : (y))
54b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
55b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
56b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifndef MAX
57b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau# define MAX(x, y) ((x) > (y) ? (x) : (y))
58b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
59b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
60b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifndef TRUE
61b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau# define TRUE (1)
62b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
63b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
64b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#ifndef FALSE
65b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau# define FALSE (0)
66b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#endif
67b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
68b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define YES_NO(t) ((t) ? "yes" : "no")
69b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
70b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#define BUFFER_SIZE 2048
71b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define MAX_BITPOOL 64
72b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define MIN_BITPOOL 2
73b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
74b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustruct a2dp_info {
75b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	sbc_capabilities_t sbc_capabilities;
76b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	sbc_t sbc; /* Codec data */
77b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int sbc_initialized; /* Keep track if the encoder is initialized */
78b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	size_t codesize; /* SBC codesize */
79b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
80b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	void* buffer; /* Codec transfer buffer */
81b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	size_t buffer_size; /* Size of the buffer */
82b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
83b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint16_t seq_num; /* Cumulative packet sequence */
84b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau};
85b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
86b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustruct hsp_info {
87b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	pcm_capabilities_t pcm_capabilities;
88b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau};
89b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
90b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustruct userdata {
91b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int service_fd;
92b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int stream_fd;
93b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	GIOChannel *stream_channel;
94b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	guint stream_watch;
95563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	GIOChannel *gin; /* dude, I am thirsty now */
96563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	guint gin_watch;
97b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int transport;
98b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint32_t rate;
99b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int channels;
10064989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau	char *address;
101b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	struct a2dp_info a2dp;
102b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	struct hsp_info hsp;
103b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	size_t link_mtu;
104b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	size_t block_size;
105454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	gboolean debug_stream_read : 1;
106454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	gboolean debug_stream_write : 1;
107b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau};
108b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
109b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic struct userdata data = {
110b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.service_fd = -1,
111b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.stream_fd = -1,
112b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.transport = BT_CAPABILITIES_TRANSPORT_A2DP,
113b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.rate = 48000,
114b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.channels = 2,
115b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	.address = NULL
116b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau};
117b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
118b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int start_stream(struct userdata *u);
119b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int stop_stream(struct userdata *u);
120563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureaustatic gboolean input_cb(GIOChannel *gin, GIOCondition condition, gpointer data);
121b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
122b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic GMainLoop *main_loop;
123b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
124b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int service_send(struct userdata *u, const bt_audio_msg_header_t *msg)
125b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
126b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int err;
127b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint16_t length;
128b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
129b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
130b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
131b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE;
132b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
133b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("sending %s:%s", bt_audio_strtype(msg->type),
134b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		bt_audio_strname(msg->name));
135b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
136b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (send(u->service_fd, msg, length, 0) > 0)
137b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		err = 0;
138b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else {
139b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		err = -errno;
140b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		ERR("Error sending data to audio service: %s(%d)",
141b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			strerror(errno), errno);
142b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
143b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
144b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return err;
145b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
146b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
147e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentzstatic int service_recv(struct userdata *u, bt_audio_msg_header_t *rsp)
148b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
149b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int err;
150b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	const char *type, *name;
151b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint16_t length;
152b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
153b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
154b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
155e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	length = rsp->length ? : BT_SUGGESTED_BUFFER_SIZE;
156b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
157b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("trying to receive msg from audio service...");
158b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (recv(u->service_fd, rsp, length, 0) > 0) {
159b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		type = bt_audio_strtype(rsp->type);
160b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		name = bt_audio_strname(rsp->name);
161b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (type && name) {
162b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("Received %s - %s", type, name);
163b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			err = 0;
164b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else {
165b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			err = -EINVAL;
166b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			ERR("Bogus message type %d - name %d"
167b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				"received from audio service",
168b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				rsp->type, rsp->name);
169b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
170b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else {
171b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		err = -errno;
172b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		ERR("Error receiving data from audio service: %s(%d)",
173b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			strerror(errno), errno);
174b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
175b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
176b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return err;
177b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
178b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
179e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentzstatic ssize_t service_expect(struct userdata *u, bt_audio_msg_header_t *rsp,
180e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz				uint8_t expected_name)
181b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
182b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int r;
183b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
184b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
185b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u->service_fd >= 0);
186b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(rsp);
187b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
188e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if ((r = service_recv(u, rsp)) < 0)
189b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return r;
190b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
191b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if ((rsp->type != BT_INDICATION && rsp->type != BT_RESPONSE) ||
192e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz			(rsp->name != expected_name)) {
193b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (rsp->type == BT_ERROR && rsp->length == sizeof(bt_audio_error_t))
194b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			ERR("Received error condition: %s",
195b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				strerror(((bt_audio_error_t*) rsp)->posix_errno));
196b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		else
197b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			ERR("Bogus message %s received while %s was expected",
198b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				bt_audio_strname(rsp->name),
199b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				bt_audio_strname(expected_name));
200b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
201b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
202b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
203b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
204b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
205b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
206b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int init_bt(struct userdata *u)
207b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
208b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
209b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
210b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->service_fd != -1)
211b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return 0;
212b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
213b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("bt_audio_service_open");
214b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
215b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	u->service_fd = bt_audio_service_open();
216b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->service_fd <= 0) {
217b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		perror(strerror(errno));
218b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return errno;
219b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
220b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
221b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
222b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
223b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
224b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *rsp)
225b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
226b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	uint16_t bytes_left;
227e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	codec_capabilities_t *codec;
228b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
229b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
230b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(rsp);
231b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
232b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	bytes_left = rsp->h.length - sizeof(*rsp);
233b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
234b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (bytes_left < sizeof(codec_capabilities_t)) {
235b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		ERR("Packet too small to store codec information.");
236b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
237b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
238b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
239e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	codec = (void *) rsp->data; /** ALIGNMENT? **/
240b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
241b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("Payload size is %lu %lu",
242b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		(unsigned long) bytes_left, (unsigned long) sizeof(*codec));
243b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
244b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->transport != codec->transport) {
245b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		ERR("Got capabilities for wrong codec.");
246b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
247b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
248b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
249b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->transport == BT_CAPABILITIES_TRANSPORT_SCO) {
250b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
251b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (bytes_left <= 0 ||
252b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			codec->length != sizeof(u->hsp.pcm_capabilities))
253b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
254b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
255b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(codec->type == BT_HFP_CODEC_PCM);
256b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
257b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		memcpy(&u->hsp.pcm_capabilities,
258b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			codec, sizeof(u->hsp.pcm_capabilities));
259b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
260b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("Has NREC: %s",
261b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			YES_NO(u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC));
262b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
263b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
264b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
265b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		while (bytes_left > 0) {
266e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz			if ((codec->type == BT_A2DP_CODEC_SBC) &&
267e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz					!(codec->lock & BT_WRITE_LOCK))
268b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				break;
269b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
270b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			bytes_left -= codec->length;
271e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz			codec = (void *) codec + codec->length;
272b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
273b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
274e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		DBG("bytes_left = %d, codec->length = %d", bytes_left, codec->length);
275e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
276b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (bytes_left <= 0 ||
277b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			codec->length != sizeof(u->a2dp.sbc_capabilities))
278b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
279b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
280b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(codec->type == BT_A2DP_CODEC_SBC);
281b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
282b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		memcpy(&u->a2dp.sbc_capabilities, codec,
283b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			sizeof(u->a2dp.sbc_capabilities));
284b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else {
285b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
286b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
287b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
288b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
289b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
290b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
291b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int get_caps(struct userdata *u)
292b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
293b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	union {
294b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		struct bt_get_capabilities_req getcaps_req;
295b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		struct bt_get_capabilities_rsp getcaps_rsp;
296b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		bt_audio_error_t error;
297b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
298b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} msg;
299b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
300b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
301b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
302b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	memset(&msg, 0, sizeof(msg));
303b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.h.type = BT_REQUEST;
304b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.h.name = BT_GET_CAPABILITIES;
305b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.h.length = sizeof(msg.getcaps_req);
306b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
307e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	strncpy(msg.getcaps_req.destination, u->address,
308e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz			sizeof(msg.getcaps_req.destination));
309b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.transport = u->transport;
310b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.getcaps_req.flags = BT_FLAG_AUTOCONNECT;
311b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
312b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (service_send(u, &msg.getcaps_req.h) < 0)
313b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
314b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
315e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.getcaps_rsp.h.length = 0;
316e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.getcaps_rsp.h, BT_GET_CAPABILITIES) < 0)
317b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
318b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
319b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return parse_caps(u, &msg.getcaps_rsp);
320b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
321b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
322b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode)
323b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
324b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (freq) {
325b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_16000:
326b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_32000:
327b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return 53;
328b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
329b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_44100:
330b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
331b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		switch (mode) {
332b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_MONO:
333b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
334b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 31;
335b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
336b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_STEREO:
337b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
338b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 53;
339b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
340b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		default:
341b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("Invalid channel mode %u", mode);
342b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 53;
343b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
344b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
345b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_48000:
346b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
347b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		switch (mode) {
348b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_MONO:
349b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
350b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 29;
351b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
352b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_STEREO:
353b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
354b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 51;
355b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
356b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		default:
357b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("Invalid channel mode %u", mode);
358b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return 51;
359b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
360b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
361b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
362b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("Invalid sampling freq %u", freq);
363b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return 53;
364b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
365b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
366b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
367b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int setup_a2dp(struct userdata *u)
368b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
369b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	sbc_capabilities_t *cap;
370b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int i;
371b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
372b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	static const struct {
373b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		uint32_t rate;
374b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		uint8_t cap;
375b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} freq_table[] = {
376b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		{ 16000U, BT_SBC_SAMPLING_FREQ_16000 },
377b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		{ 32000U, BT_SBC_SAMPLING_FREQ_32000 },
378b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		{ 44100U, BT_SBC_SAMPLING_FREQ_44100 },
379b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		{ 48000U, BT_SBC_SAMPLING_FREQ_48000 }
380b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	};
381b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
382b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
383b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u->transport == BT_CAPABILITIES_TRANSPORT_A2DP);
384b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
385b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	cap = &u->a2dp.sbc_capabilities;
386b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
387b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	/* Find the lowest freq that is at least as high as the requested
388b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	 * sampling rate */
389b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	for (i = 0; (unsigned) i < ARRAY_SIZE(freq_table); i++)
390b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (freq_table[i].rate >= u->rate &&
391b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			(cap->frequency & freq_table[i].cap)) {
392b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->rate = freq_table[i].rate;
393b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->frequency = freq_table[i].cap;
394b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			break;
395b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
396b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
397b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if ((unsigned) i >= ARRAY_SIZE(freq_table)) {
398b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		for (; i >= 0; i--) {
399b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			if (cap->frequency & freq_table[i].cap) {
400b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				u->rate = freq_table[i].rate;
401b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				cap->frequency = freq_table[i].cap;
402b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau				break;
403b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			}
404b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
405b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
406b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (i < 0) {
407b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("Not suitable sample rate");
408b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
409b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
410b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
411b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
412b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->channels <= 1) {
413b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
414b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
415b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->channels = 1;
416b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else
417b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->channels = 2;
418b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
419b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
420b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->channels >= 2) {
421b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->channels = 2;
422b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
423b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
424b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
425b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
426b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
427b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
428b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
429b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
430b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
431b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->channels = 1;
432b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else {
433b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("No supported channel modes");
434b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
435b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
436b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
437b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
438b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16)
439b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->block_length = BT_A2DP_BLOCK_LENGTH_16;
440b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_12)
441b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->block_length = BT_A2DP_BLOCK_LENGTH_12;
442b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_8)
443b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->block_length = BT_A2DP_BLOCK_LENGTH_8;
444b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_4)
445b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->block_length = BT_A2DP_BLOCK_LENGTH_4;
446b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else {
447b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("No supported block lengths");
448b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
449b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
450b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
451b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (cap->subbands & BT_A2DP_SUBBANDS_8)
452b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->subbands = BT_A2DP_SUBBANDS_8;
453b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->subbands & BT_A2DP_SUBBANDS_4)
454b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->subbands = BT_A2DP_SUBBANDS_4;
455b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else {
456b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("No supported subbands");
457b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
458b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
459b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
460b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (cap->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS)
461b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
462b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else if (cap->allocation_method & BT_A2DP_ALLOCATION_SNR)
463b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		cap->allocation_method = BT_A2DP_ALLOCATION_SNR;
464b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
465b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	cap->min_bitpool = (uint8_t) MAX(MIN_BITPOOL, cap->min_bitpool);
466b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	cap->max_bitpool = (uint8_t) MIN(
467b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		a2dp_default_bitpool(cap->frequency, cap->channel_mode),
468b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		cap->max_bitpool);
469b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
470b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
471b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
472b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
473b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic void setup_sbc(struct a2dp_info *a2dp)
474b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
475b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	sbc_capabilities_t *active_capabilities;
476b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
477b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(a2dp);
478b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
479b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	active_capabilities = &a2dp->sbc_capabilities;
480b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
481b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (a2dp->sbc_initialized)
482b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		sbc_reinit(&a2dp->sbc, 0);
483b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	else
484b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		sbc_init(&a2dp->sbc, 0);
485b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	a2dp->sbc_initialized = TRUE;
486b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
487b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->frequency) {
488b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_16000:
489b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.frequency = SBC_FREQ_16000;
490b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
491b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_32000:
492b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.frequency = SBC_FREQ_32000;
493b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
494b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_44100:
495b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.frequency = SBC_FREQ_44100;
496b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
497b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_SBC_SAMPLING_FREQ_48000:
498b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.frequency = SBC_FREQ_48000;
499b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
500b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
501b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
502b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
503b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
504b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->channel_mode) {
505b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_CHANNEL_MODE_MONO:
506b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.mode = SBC_MODE_MONO;
507b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
508b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
509b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL;
510b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
511b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_CHANNEL_MODE_STEREO:
512b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.mode = SBC_MODE_STEREO;
513b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
514b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
515b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.mode = SBC_MODE_JOINT_STEREO;
516b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
517b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
518b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
519b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
520b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
521b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->allocation_method) {
522b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_ALLOCATION_SNR:
523b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.allocation = SBC_AM_SNR;
524b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
525b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_ALLOCATION_LOUDNESS:
526b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.allocation = SBC_AM_LOUDNESS;
527b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
528b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
529b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
530b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
531b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
532b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->subbands) {
533b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_SUBBANDS_4:
534b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.subbands = SBC_SB_4;
535b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
536b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_SUBBANDS_8:
537b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.subbands = SBC_SB_8;
538b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
539b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
540b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
541b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
542b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
543b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	switch (active_capabilities->block_length) {
544b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_BLOCK_LENGTH_4:
545b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.blocks = SBC_BLK_4;
546b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
547b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_BLOCK_LENGTH_8:
548b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.blocks = SBC_BLK_8;
549b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
550b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_BLOCK_LENGTH_12:
551b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.blocks = SBC_BLK_12;
552b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
553b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	case BT_A2DP_BLOCK_LENGTH_16:
554b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		a2dp->sbc.blocks = SBC_BLK_16;
555b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		break;
556b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	default:
557b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(0);
558b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
559b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
560b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	a2dp->sbc.bitpool = active_capabilities->max_bitpool;
561b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	a2dp->codesize = (uint16_t) sbc_get_codesize(&a2dp->sbc);
562b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
563b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
564e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentzstatic int bt_open(struct userdata *u)
565e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz{
566e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	union {
567e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		struct bt_open_req open_req;
568e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		struct bt_open_rsp open_rsp;
569e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		bt_audio_error_t error;
570e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
571e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	} msg;
572e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
573e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	memset(&msg, 0, sizeof(msg));
574e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.h.type = BT_REQUEST;
575e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.h.name = BT_OPEN;
576e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.h.length = sizeof(msg.open_req);
577e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
578e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	strncpy(msg.open_req.destination, u->address,
579e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz			sizeof(msg.open_req.destination));
580e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.seid = u->transport == BT_CAPABILITIES_TRANSPORT_A2DP ?
581e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz				u->a2dp.sbc_capabilities.capability.seid :
582e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz				BT_A2DP_SEID_RANGE + 1;
583e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_req.lock = u->transport == BT_CAPABILITIES_TRANSPORT_A2DP ?
584e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz				BT_WRITE_LOCK : BT_READ_LOCK | BT_WRITE_LOCK;
585e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
586e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_send(u, &msg.open_req.h) < 0)
587e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		return -1;
588e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
589e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.open_rsp.h.length = sizeof(msg.open_rsp);
590e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.open_rsp.h, BT_OPEN) < 0)
591e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		return -1;
592e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
593e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	return 0;
594e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz}
595e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
596b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int set_conf(struct userdata *u)
597b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
598b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	union {
599b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		struct bt_set_configuration_req setconf_req;
600b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		struct bt_set_configuration_rsp setconf_rsp;
601b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		bt_audio_error_t error;
602b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
603b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} msg;
604b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
605b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
606b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (setup_a2dp(u) < 0)
607b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			return -1;
608b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
609b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
610b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	memset(&msg, 0, sizeof(msg));
611b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.setconf_req.h.type = BT_REQUEST;
612b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.setconf_req.h.name = BT_SET_CONFIGURATION;
613b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	msg.setconf_req.h.length = sizeof(msg.setconf_req);
614b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
615b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
616b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities,
617b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			sizeof(u->a2dp.sbc_capabilities));
618b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		msg.setconf_req.h.length += msg.setconf_req.codec.length -
619b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			sizeof(msg.setconf_req.codec);
620e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	} else {
621e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		msg.setconf_req.codec.transport = BT_CAPABILITIES_TRANSPORT_SCO;
622e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		msg.setconf_req.codec.seid = BT_A2DP_SEID_RANGE + 1;
623e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		msg.setconf_req.codec.length = sizeof(pcm_capabilities_t);
624b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
625b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
626b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (service_send(u, &msg.setconf_req.h) < 0)
627b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
628b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
629e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.setconf_rsp.h.length = sizeof(msg.setconf_rsp);
630e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.setconf_rsp.h, BT_SET_CONFIGURATION) < 0)
631b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
632b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
633b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	u->link_mtu = msg.setconf_rsp.link_mtu;
634b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
635b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	/* setup SBC encoder now we agree on parameters */
636b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
637b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		setup_sbc(&u->a2dp);
638b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->block_size = u->a2dp.codesize;
639b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("SBC parameters:\n\tallocation=%u\n"
640b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			"\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
641b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->a2dp.sbc.allocation, u->a2dp.sbc.subbands,
642b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->a2dp.sbc.blocks, u->a2dp.sbc.bitpool);
643b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else
644b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->block_size = u->link_mtu;
645b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
646b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
647b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
648b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
649b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int setup_bt(struct userdata *u)
650b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
651b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
652b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
653b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (get_caps(u) < 0)
654b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
655b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
656b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	DBG("Got device caps");
657b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
658e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (bt_open(u) < 0)
659e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		return -1;
660e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
661b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (set_conf(u) < 0)
662b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return -1;
663b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
664b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
665b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
666b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
667b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic int init_profile(struct userdata *u)
668b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
669b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
670b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
671b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return setup_bt(u);
672b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
673b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
674b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic void shutdown_bt(struct userdata *u)
675b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
676b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u);
677b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
678b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->stream_fd != -1) {
679482feece91818127ce4e6f39dfa555390a31d8abMarc-André Lureau		stop_stream(u);
680b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("close(stream_fd)");
681b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		close(u->stream_fd);
682b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->stream_fd = -1;
683b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
684b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
685b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (u->service_fd != -1) {
686b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("bt_audio_service_close");
687b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		bt_audio_service_close(u->service_fd);
688b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		u->service_fd = -1;
689b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
690b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
691b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
692b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic void make_fd_nonblock(int fd)
693b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
694b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int v;
695b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
696b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(fd >= 0);
697b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert((v = fcntl(fd, F_GETFL)) >= 0);
698b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
699b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (!(v & O_NONBLOCK))
700b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0);
701b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
702b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
703b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic void make_socket_low_delay(int fd)
704b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
705b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau/* FIXME: is this widely supported? */
706b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#ifdef SO_PRIORITY
707b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int priority;
708b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(fd >= 0);
709b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
710b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	priority = 6;
711b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority,
712b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			sizeof(priority)) < 0)
713b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		ERR("SO_PRIORITY failed: %s", strerror(errno));
714b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau#endif
715b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
716b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
717b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int read_stream(struct userdata *u)
718b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
719b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int ret = 0;
720b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	ssize_t l;
721b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	char *buf;
722b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
723b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u);
724b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u->stream_fd >= 0);
725b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
726b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	buf = alloca(u->link_mtu);
727b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
728b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	for (;;) {
729b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		l = read(u->stream_fd, buf, u->link_mtu);
730454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		if (u->debug_stream_read)
731454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			DBG("read from socket: %lli bytes", (long long) l);
732b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (l <= 0) {
733b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			if (l < 0 && errno == EINTR)
734b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				continue;
735b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			else {
736b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				ERR("Failed to read date from stream_fd: %s",
737b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau					ret < 0 ? strerror(errno) : "EOF");
738b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				ret = -1;
739b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			}
740b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		} else {
741b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			break;
742b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		}
743b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
744b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
745b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return ret;
746b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
747b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
748b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau/* It's what PulseAudio is doing, not sure it's necessary for this
749b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau * test */
750b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic ssize_t pa_write(int fd, const void *buf, size_t count)
751b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
752b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	ssize_t r;
753b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
754b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0)
755b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return r;
756b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
757b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (errno != ENOTSOCK)
758b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return r;
759b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
760b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return write(fd, buf, count);
761b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
762b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
763b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int write_stream(struct userdata *u)
764b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
765b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int ret = 0;
766b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	ssize_t l;
767b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	char *buf;
768b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
769b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u);
770b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u->stream_fd >= 0);
771b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	buf = alloca(u->link_mtu);
772b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
773b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	for (;;) {
774b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		l = pa_write(u->stream_fd, buf, u->link_mtu);
775454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		if (u->debug_stream_write)
776454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			DBG("written to socket: %lli bytes", (long long) l);
777b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(l != 0);
778b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (l < 0) {
779b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			if (errno == EINTR)
780b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				continue;
781b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			else {
782b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				ERR("Failed to write data: %s", strerror(errno));
783b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				ret = -1;
784b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau				break;
785b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			}
786b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		} else {
787b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			assert((size_t)l <= u->link_mtu);
788b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			break;
789b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		}
790b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
791b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
792b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return ret;
793b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
794b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
795b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic gboolean stream_cb(GIOChannel *gin, GIOCondition condition, gpointer data)
796b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
797b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	struct userdata *u;
798b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
799b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u = data);
800b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
801b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (condition & G_IO_IN) {
802b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (read_stream(u) < 0)
803b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			goto fail;
804b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	} else if (condition & G_IO_OUT) {
805b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		if (write_stream(u) < 0)
806b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau			goto fail;
807b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	} else {
808b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		DBG("Got %d", condition);
809b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		g_main_loop_quit(main_loop);
810b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return FALSE;
811b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
812b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
813b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return TRUE;
814b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
815b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaufail:
816b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	stop_stream(u);
817b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return FALSE;
818b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
819b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
820b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int start_stream(struct userdata *u)
821b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
822b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	union {
823b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		bt_audio_msg_header_t rsp;
824b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		struct bt_start_stream_req start_req;
825b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		struct bt_start_stream_rsp start_rsp;
826b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		struct bt_new_stream_ind streamfd_ind;
827b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		bt_audio_error_t error;
828b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
829b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	} msg;
830b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
831b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u);
8329645bf143db975256d3618594282f4ce3778db42Marc-André Lureau
8339645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	if (u->stream_fd >= 0)
8349645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		return 0;
8359645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	if (u->stream_watch != 0) {
8369645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		g_source_remove(u->stream_watch);
8379645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		u->stream_watch = 0;
8389645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	}
8399645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	if (u->stream_channel != 0) {
8409645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		g_io_channel_unref(u->stream_channel);
8419645bf143db975256d3618594282f4ce3778db42Marc-André Lureau		u->stream_channel = NULL;
8429645bf143db975256d3618594282f4ce3778db42Marc-André Lureau	}
843b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
844b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	memset(msg.buf, 0, BT_SUGGESTED_BUFFER_SIZE);
845b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	msg.start_req.h.type = BT_REQUEST;
846b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	msg.start_req.h.name = BT_START_STREAM;
847b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	msg.start_req.h.length = sizeof(msg.start_req);
848b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
849b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (service_send(u, &msg.start_req.h) < 0)
850b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return -1;
851b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
852e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.rsp.length = sizeof(msg.start_rsp);
853e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.rsp, BT_START_STREAM) < 0)
854b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return -1;
855b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
856e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.rsp.length = sizeof(msg.streamfd_ind);
857e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.rsp, BT_NEW_STREAM) < 0)
858b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return -1;
859b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
860b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if ((u->stream_fd = bt_audio_service_get_data_fd(u->service_fd)) < 0) {
861b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		DBG("Failed to get stream fd from audio service.");
862b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return -1;
863b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
864b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
865b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	make_fd_nonblock(u->stream_fd);
866b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	make_socket_low_delay(u->stream_fd);
867b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
868b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u->stream_channel = g_io_channel_unix_new(u->stream_fd));
869b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
870b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	u->stream_watch = g_io_add_watch(u->stream_channel,
871b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau					G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
872b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau					stream_cb, u);
873b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
874b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return 0;
875b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
876b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
877b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureaustatic int stop_stream(struct userdata *u)
878b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau{
879b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	union {
880b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		bt_audio_msg_header_t rsp;
881e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		struct bt_stop_stream_req stop_req;
882e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		struct bt_stop_stream_rsp stop_rsp;
883b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		bt_audio_error_t error;
884b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
885b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	} msg;
886b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	int r = 0;
887b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
888b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	if (u->stream_fd < 0)
889b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		return 0;
890b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
891b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u);
892b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(u->stream_channel);
893b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
894b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	g_source_remove(u->stream_watch);
895482feece91818127ce4e6f39dfa555390a31d8abMarc-André Lureau	u->stream_watch = 0;
896b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	g_io_channel_unref(u->stream_channel);
897b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	u->stream_channel = NULL;
898b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
899b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	memset(msg.buf, 0, BT_SUGGESTED_BUFFER_SIZE);
900e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.stop_req.h.type = BT_REQUEST;
901e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.stop_req.h.name = BT_STOP_STREAM;
902e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.stop_req.h.length = sizeof(msg.stop_req);
903e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz
904e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_send(u, &msg.stop_req.h) < 0) {
905e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		r = -1;
906e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz		goto done;
907e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	}
908b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
909e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	msg.rsp.length = sizeof(msg.stop_rsp);
910e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentz	if (service_expect(u, &msg.rsp, BT_STOP_STREAM) < 0)
911b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		r = -1;
912b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
913e6522bd8c03008afa5ed3bf9c71c24702f064badLuiz Augusto von Dentzdone:
914b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	close(u->stream_fd);
915b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	u->stream_fd = -1;
916b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
917b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	return r;
918b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau}
919b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
920563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureaustatic gboolean sleep_cb(gpointer data)
921563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau{
922563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	struct userdata *u;
923563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
924563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	assert(u = data);
925563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
926563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	u->gin_watch = g_io_add_watch(u->gin,
927563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, input_cb, data);
928563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
929563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	printf(">>> ");
930563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	fflush(stdout);
931563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
932563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau	return FALSE;
933563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau}
934563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau
935b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic gboolean input_cb(GIOChannel *gin, GIOCondition condition, gpointer data)
936b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
937454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	char *line, *tmp;
938b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	gsize term_pos;
939b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	GError *error = NULL;
940b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	struct userdata *u;
941b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	int success;
942b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
943b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	assert(u = data);
944b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (!(condition & G_IO_IN)) {
945b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("Got %d", condition);
946b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		g_main_loop_quit(main_loop);
947b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return FALSE;
948b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
949b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
950b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (g_io_channel_read_line(gin, &line, NULL, &term_pos, &error) !=
951b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		G_IO_STATUS_NORMAL)
952b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return FALSE;
953b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
954b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	line[term_pos] = '\0';
955b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	g_strstrip(line);
956454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	if ((tmp = strchr(line, '#')))
957454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		*tmp = '\0';
958b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	success = FALSE;
959b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
960b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau#define IF_CMD(cmd) \
961b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (!success && (success = (strncmp(line, #cmd, strlen(#cmd)) == 0)))
962b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
963b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(quit) {
964b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		g_main_loop_quit(main_loop);
965b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		return FALSE;
966b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
967b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
96864989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau	IF_CMD(sleep) {
96964989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		unsigned int seconds;
97064989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		if (sscanf(line, "%*s %d", &seconds) != 1)
97164989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau			DBG("sleep SECONDS");
972563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		else {
973563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau			g_source_remove(u->gin_watch);
974563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau			g_timeout_add_seconds(seconds, sleep_cb, u);
975563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau			return FALSE;
976563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		}
97764989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau	}
97864989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau
979454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	IF_CMD(debug) {
980454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		char *what = NULL;
981454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		int enable;
982454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau
983454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		if (sscanf(line, "%*s %as %d", &what, &enable) != 1)
984454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			DBG("debug [stream_read|stream_write] [0|1]");
985454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		if (strncmp(what, "stream_read", 12) == 0) {
986454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			u->debug_stream_read = enable;
987454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		} else if (strncmp(what, "stream_write", 13) == 0) {
988454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			u->debug_stream_write = enable;
989454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		} else {
990454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau			DBG("debug [stream_read|stream_write] [0|1]");
991454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau		}
992454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau	}
993454b5e87100311bdee18856f3aa6216dcedfe579Marc-André Lureau
994b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(init_bt) {
995b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("%d", init_bt(u));
996b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
997b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
998b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(init_profile) {
999b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("%d", init_profile(u));
1000b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1001b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1002b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	IF_CMD(start_stream) {
1003b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		DBG("%d", start_stream(u));
1004b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
1005b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1006b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	IF_CMD(stop_stream) {
1007b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		DBG("%d", stop_stream(u));
1008b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	}
1009b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1010b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(shutdown_bt) {
1011b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		shutdown_bt(u);
1012b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1013b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1014b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(rate) {
1015b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (sscanf(line, "%*s %d", &u->rate) != 1)
1016b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("set with rate RATE");
1017b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("rate %d", u->rate);
1018b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1019b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1020b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(btaddr) {
102164989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		if (u->address)
102264989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau			free(u->address);
102364989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		if (sscanf(line, "%*s %as", &u->address) != 1)
1024b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("set with btaddr BTADDR");
1025b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("btaddr %s", u->address);
1026b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1027b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1028b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	IF_CMD(profile) {
102964989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		char *profile = NULL;
1030b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
103164989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		if (sscanf(line, "%*s %as", &profile) != 1)
1032b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("set with profile [hsp|a2dp]");
1033b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (strncmp(profile, "hsp", 4) == 0) {
1034b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->transport = BT_CAPABILITIES_TRANSPORT_SCO;
1035b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else if (strncmp(profile, "a2dp", 5) == 0) {
1036b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			u->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
1037b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		} else {
1038b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			DBG("set with profile [hsp|a2dp]");
1039b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
1040b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
104164989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		if (profile)
104264989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau			free(profile);
1043b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("profile %s", u->transport == BT_CAPABILITIES_TRANSPORT_SCO ?
1044b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			"hsp" : "a2dp");
1045b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1046b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1047b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (!success && strlen(line) != 0) {
1048b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		DBG("%s, unknown command", line);
1049b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1050b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1051b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	printf(">>> ");
1052b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	fflush(stdout);
1053b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return TRUE;
1054b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
1055b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1056b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1057b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic void show_usage(char* prgname)
1058b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
1059b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	printf("%s: ipctest [--interactive] BTADDR\n", basename(prgname));
1060b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
1061b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1062b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureaustatic void sig_term(int sig)
1063b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
1064b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	g_main_loop_quit(main_loop);
1065b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
1066b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1067b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureauint main(int argc, char *argv[])
1068b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau{
1069b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (argc < 2) {
1070b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		show_usage(argv[0]);
1071b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		exit(EXIT_FAILURE);
1072b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1073b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1074b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	assert(main_loop = g_main_loop_new(NULL, FALSE));
1075b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1076b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	if (strncmp("--interactive", argv[1], 14) == 0) {
1077b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		if (argc < 3) {
1078b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			show_usage(argv[0]);
1079b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau			exit(EXIT_FAILURE);
1080b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		}
1081b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
108264989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		data.address = strdup(argv[2]);
1083b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1084b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		signal(SIGTERM, sig_term);
1085b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		signal(SIGINT, sig_term);
1086b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1087563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		assert(data.gin = g_io_channel_unix_new(fileno(stdin)));
1088b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1089563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau		data.gin_watch = g_io_add_watch(data.gin,
1090563a7c646d0ab4daed4f0ad17afafd18e5222460Marc-André Lureau			G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, input_cb, &data);
1091b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1092b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		printf(">>> ");
1093b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		fflush(stdout);
1094b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1095b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		g_main_loop_run(main_loop);
1096b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1097b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	} else {
109864989ac07ca0085556df4df96caf14ec0e7b086cMarc-André Lureau		data.address = strdup(argv[1]);
1099b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1100b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		assert(init_bt(&data) == 0);
1101b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1102b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(init_profile(&data) == 0);
1103b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1104b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(start_stream(&data) == 0);
1105b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1106b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		g_main_loop_run(main_loop);
1107b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1108b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau		assert(stop_stream(&data) == 0);
1109b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1110b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau		shutdown_bt(&data);
1111b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	}
1112b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1113b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau	g_main_loop_unref(main_loop);
1114b4c0e4acab4b61b4fc97ec27d3c666c273afee19Marc-André Lureau
1115b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	printf("\nExiting\n");
1116b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1117b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	exit(EXIT_SUCCESS);
1118b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau
1119b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau	return 0;
1120b7cad7d51ac8dfc0458dbd42478ae9be237472f8Marc-André Lureau}
1121