device.c revision 0094809955895c974fbe95f2d3ed13f420a6a6ed
1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2006-2007  Nokia Corporation
6 *  Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
7 *
8 *
9 *  This program is free software; you can redistribute it and/or modify
10 *  it under the terms of the GNU General Public License as published by
11 *  the Free Software Foundation; either version 2 of the License, or
12 *  (at your option) any later version.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 */
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28
29#include <stdio.h>
30#include <errno.h>
31#include <unistd.h>
32#include <sys/stat.h>
33#include <netinet/in.h>
34
35#include <bluetooth/bluetooth.h>
36#include <bluetooth/hci.h>
37#include <bluetooth/hci_lib.h>
38#include <bluetooth/sdp.h>
39#include <bluetooth/sdp_lib.h>
40
41#include <glib.h>
42#include <dbus/dbus.h>
43#include <gdbus.h>
44
45#include "logging.h"
46#include "textfile.h"
47
48#include "error.h"
49#include "ipc.h"
50#include "device.h"
51#include "avdtp.h"
52#include "control.h"
53#include "headset.h"
54#include "sink.h"
55
56static DBusHandlerResult device_get_address(DBusConnection *conn,
57						DBusMessage *msg, void *data)
58{
59	struct device *device = data;
60	DBusMessage *reply;
61	char address[18], *ptr = address;
62
63	reply = dbus_message_new_method_return(msg);
64	if (!reply)
65		return DBUS_HANDLER_RESULT_NEED_MEMORY;
66
67	ba2str(&device->dst, address);
68
69	dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,
70							DBUS_TYPE_INVALID);
71
72	return send_message_and_unref(conn, reply);
73}
74
75static char *get_dev_name(DBusConnection *conn, const bdaddr_t *src,
76			const bdaddr_t *bda)
77{
78	char address[18], filename[PATH_MAX + 1];
79
80	ba2str(src, address);
81
82	/* check if it is in the cache */
83	create_name(filename, PATH_MAX, STORAGEDIR, address, "names");
84
85	ba2str(bda, address);
86	return textfile_caseget(filename, address);
87}
88
89static DBusHandlerResult device_get_name(DBusConnection *conn,
90						DBusMessage *msg, void *data)
91{
92	struct device *dev = data;
93	DBusMessage *reply;
94	const char *name = dev->name ? dev->name : "";
95
96	reply = dbus_message_new_method_return(msg);
97	if (!reply)
98		return DBUS_HANDLER_RESULT_NEED_MEMORY;
99
100	dbus_message_append_args(reply, DBUS_TYPE_STRING, &name,
101					DBUS_TYPE_INVALID);
102
103	return send_message_and_unref(conn, reply);
104}
105
106static DBusHandlerResult device_get_adapter(DBusConnection *conn,
107						DBusMessage *msg, void *data)
108{
109	struct device *device = data;
110	DBusMessage *reply;
111	char address[18], *ptr = address;
112
113	reply = dbus_message_new_method_return(msg);
114	if (!reply)
115		return DBUS_HANDLER_RESULT_NEED_MEMORY;
116
117	ba2str(&device->src, address);
118
119	dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,
120							DBUS_TYPE_INVALID);
121
122	return send_message_and_unref(conn, reply);
123}
124
125
126static DBusHandlerResult device_get_connected(DBusConnection *conn,
127						DBusMessage *msg, void *data)
128{
129	DBusMessageIter iter, array_iter;
130	struct device *device = data;
131	DBusMessage *reply;
132	const char *iface;
133
134	reply = dbus_message_new_method_return(msg);
135	if (!reply)
136		return DBUS_HANDLER_RESULT_NEED_MEMORY;
137
138	dbus_message_iter_init_append(reply, &iter);
139
140	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
141						DBUS_TYPE_STRING_AS_STRING,
142						&array_iter);
143
144	if (device->headset &&
145			headset_get_state(device) >= HEADSET_STATE_CONNECTED) {
146		iface = AUDIO_HEADSET_INTERFACE;
147		dbus_message_iter_append_basic(&array_iter,
148						DBUS_TYPE_STRING, &iface);
149	}
150
151	dbus_message_iter_close_container(&iter, &array_iter);
152
153	return send_message_and_unref(conn, reply);
154}
155
156static DBusMethodVTable device_methods[] = {
157	{ "GetAddress",			device_get_address,	"",	"s" },
158	{ "GetName",			device_get_name,	"",	"s" },
159	{ "GetAdapter",			device_get_adapter,	"",	"s" },
160	{ "GetConnectedInterfaces",	device_get_connected,	"",	"as" },
161	{ NULL, NULL, NULL, NULL }
162};
163
164static void device_free(struct device *dev)
165{
166	if (dev->headset)
167		headset_free(dev);
168
169	if (dev->sink)
170		sink_free(dev);
171
172	if (dev->control)
173		control_free(dev);
174
175	if (dev->conn)
176		dbus_connection_unref(dev->conn);
177
178	g_free(dev->adapter_path);
179	g_free(dev->path);
180	g_free(dev->name);
181
182	g_free(dev);
183}
184
185static void device_unregister(DBusConnection *conn, void *data)
186{
187	struct device *device = data;
188
189	info("Unregistered device path:%s", device->path);
190
191	device_free(device);
192}
193
194struct device *device_register(DBusConnection *conn,
195					const char *path, const bdaddr_t *bda)
196{
197	struct device *dev;
198	bdaddr_t src;
199	int dev_id;
200
201	if (!conn || !path)
202		return NULL;
203
204	bacpy(&src, BDADDR_ANY);
205	dev_id = hci_get_route(&src);
206	if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))
207		return NULL;
208
209	dev = g_new0(struct device, 1);
210
211	/* FIXME just to maintain compatibility */
212	dev->adapter_path = g_strdup_printf("/org/bluez/hci%d", dev_id);
213	if (!dev->adapter_path) {
214		device_free(dev);
215		return NULL;
216	}
217
218	if (!dbus_connection_create_object_path(conn, path, dev,
219							device_unregister)) {
220		error("D-Bus failed to register %s path", path);
221		device_free(dev);
222		return NULL;
223	}
224
225	if (!dbus_connection_register_interface(conn, path,
226			AUDIO_DEVICE_INTERFACE, device_methods, NULL, NULL)) {
227		error("Failed to register %s interface to %s",
228					AUDIO_DEVICE_INTERFACE, path);
229		dbus_connection_destroy_object_path(conn, path);
230		return NULL;
231	}
232
233	dev->name = get_dev_name(conn, &src, bda);
234	dev->path = g_strdup(path);
235	bacpy(&dev->dst, bda);
236	bacpy(&dev->src, &src);
237	bacpy(&dev->store, &src);
238	dev->conn = dbus_connection_ref(conn);
239
240	return dev;
241}
242
243int device_store(struct device *dev, gboolean is_default)
244{
245	char value[64];
246	char filename[PATH_MAX + 1];
247	char src_addr[18], dst_addr[18];
248	int offset = 0;
249
250	if (!dev->path)
251		return -EINVAL;
252
253	ba2str(&dev->dst, dst_addr);
254	ba2str(&dev->store, src_addr);
255
256	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");
257	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
258
259	if (is_default)
260		textfile_put(filename, "default", dst_addr);
261	if (dev->headset) {
262		snprintf(value, 64, "headset ");
263		offset += strlen("headset ");
264	}
265	if (dev->gateway) {
266		snprintf(value + offset, 64 - offset, "gateway ");
267		offset += strlen("gateway ");
268	}
269	if (dev->sink) {
270		snprintf(value + offset, 64 - offset, "sink ");
271		offset += strlen("sink ");
272	}
273	if (dev->source) {
274		snprintf(value + offset, 64 - offset, "source ");
275		offset += strlen("source ");
276	}
277	if (dev->control) {
278		snprintf(value + offset, 64 - offset, "control ");
279		offset += strlen("control ");
280	}
281	if (dev->target)
282		snprintf(value + offset, 64 - offset, "target");
283
284	return textfile_put(filename, dst_addr, value);
285}
286
287int device_remove_stored(struct device *dev)
288{
289	char filename[PATH_MAX + 1];
290	char src_addr[18], dst_addr[18];
291
292	ba2str(&dev->dst, dst_addr);
293	ba2str(&dev->store, src_addr);
294
295	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");
296
297	return textfile_del(filename, dst_addr);
298}
299
300void device_finish_sdp_transaction(struct device *dev)
301{
302	char address[18], *addr_ptr = address;
303	DBusMessage *msg;
304
305	ba2str(&dev->dst, address);
306
307	msg = dbus_message_new_method_call("org.bluez", dev->adapter_path,
308						"org.bluez.Adapter",
309						"FinishRemoteServiceTransaction");
310	if (!msg) {
311		error("Unable to allocate new method call");
312		return;
313	}
314
315	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
316				 DBUS_TYPE_INVALID);
317
318	send_message_and_unref(dev->conn, msg);
319}
320
321#if 0
322static avdtp_state_t ipc_to_avdtp_state(uint8_t ipc_state)
323{
324	switch (ipc_state) {
325	case STATE_DISCONNECTED:
326		return AVDTP_STATE_IDLE;
327	case STATE_CONNECTING:
328		return AVDTP_STATE_CONFIGURED;
329	case STATE_CONNECTED:
330		return AVDTP_STATE_OPEN;
331	case STATE_STREAM_STARTING:
332	case STATE_STREAMING:
333		return AVDTP_STATE_STREAMING;
334	default:
335		error("Unknown ipc state");
336		return AVDTP_STATE_IDLE;
337	}
338}
339
340static headset_state_t ipc_to_hs_state(uint8_t ipc_state)
341{
342	switch (ipc_state) {
343	case STATE_DISCONNECTED:
344		return HEADSET_STATE_DISCONNECTED;
345	case STATE_CONNECTING:
346		return HEADSET_STATE_CONNECT_IN_PROGRESS;
347	case STATE_CONNECTED:
348		return HEADSET_STATE_CONNECTED;
349	case STATE_STREAM_STARTING:
350		return HEADSET_STATE_PLAY_IN_PROGRESS;
351	case STATE_STREAMING:
352		return HEADSET_STATE_PLAYING;
353	default:
354		error("Unknown ipc state");
355		return HEADSET_STATE_DISCONNECTED;
356	}
357}
358
359static uint8_t avdtp_to_ipc_state(avdtp_state_t state)
360{
361	switch (state) {
362	case AVDTP_STATE_IDLE:
363		return STATE_DISCONNECTED;
364	case AVDTP_STATE_CONFIGURED:
365		return STATE_CONNECTING;
366	case AVDTP_STATE_OPEN:
367		return STATE_CONNECTED;
368	case AVDTP_STATE_STREAMING:
369		return STATE_STREAMING;
370	default:
371		error("Unknown avdt state");
372		return AVDTP_STATE_IDLE;
373	}
374}
375
376static uint8_t hs_to_ipc_state(headset_state_t state)
377{
378	switch (state) {
379	case HEADSET_STATE_DISCONNECTED:
380		return STATE_DISCONNECTED;
381	case HEADSET_STATE_CONNECT_IN_PROGRESS:
382		return STATE_CONNECTING;
383	case HEADSET_STATE_CONNECTED:
384		return STATE_CONNECTED;
385	case HEADSET_STATE_PLAY_IN_PROGRESS:
386		return STATE_STREAMING;
387	default:
388		error("Unknown headset state");
389		return AVDTP_STATE_IDLE;
390	}
391}
392
393uint8_t device_get_state(struct device *dev)
394{
395	avdtp_state_t sink_state;
396	headset_state_t hs_state;
397
398	if (dev->sink && sink_is_active(dev)) {
399		sink_state = sink_get_state(dev);
400		return avdtp_to_ipc_state(sink_state);
401	}
402	else if (dev->headset && headset_is_active(dev)) {
403		hs_state = headset_get_state(dev);
404		return hs_to_ipc_state(hs_state);
405	}
406	else if (dev->control && control_is_active(dev))
407		return STATE_CONNECTED;
408
409	return STATE_DISCONNECTED;
410}
411#endif
412
413gboolean device_is_connected(struct device *dev, const char *interface)
414{
415	if (!interface) {
416		if ((dev->sink || dev->source) &&
417			avdtp_is_connected(&dev->src, &dev->dst))
418			return TRUE;
419
420		if (dev->headset && headset_is_active(dev))
421			return TRUE;
422	}
423	else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink &&
424			avdtp_is_connected(&dev->src, &dev->dst))
425		return TRUE;
426	else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source &&
427			avdtp_is_connected(&dev->src, &dev->dst))
428		return TRUE;
429	else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset &&
430			headset_is_active(dev))
431		return TRUE;
432	else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->headset &&
433			control_is_active(dev))
434		return TRUE;
435
436	return FALSE;
437}
438