3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2006-2010 Nokia Corporation
6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
7 * Copyright (C) 2011 Texas Instruments, Inc.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 #include <sys/types.h>
40 #include <bluetooth/bluetooth.h>
41 #include <bluetooth/sdp.h>
42 #include <bluetooth/sdp_lib.h>
45 #include <dbus/dbus.h>
55 #include "glib-helper.h"
56 #include "dbus-common.h"
58 static unsigned int avctp_id = 0;
61 struct audio_device *dev;
62 struct avctp *session;
67 static void state_changed(struct audio_device *dev, avctp_state_t old_state,
68 avctp_state_t new_state, void *user_data)
70 struct control *control = dev->control;
74 case AVCTP_STATE_DISCONNECTED:
75 control->session = NULL;
77 if (old_state != AVCTP_STATE_CONNECTED)
81 g_dbus_emit_signal(dev->conn, dev->path,
82 AUDIO_CONTROL_INTERFACE,
83 "Disconnected", DBUS_TYPE_INVALID);
84 emit_property_changed(dev->conn, dev->path,
85 AUDIO_CONTROL_INTERFACE, "Connected",
86 DBUS_TYPE_BOOLEAN, &value);
89 case AVCTP_STATE_CONNECTING:
93 control->session = avctp_get(&dev->src, &dev->dst);
96 case AVCTP_STATE_CONNECTED:
98 g_dbus_emit_signal(dev->conn, dev->path,
99 AUDIO_CONTROL_INTERFACE, "Connected",
101 emit_property_changed(dev->conn, dev->path,
102 AUDIO_CONTROL_INTERFACE, "Connected",
103 DBUS_TYPE_BOOLEAN, &value);
110 static DBusMessage *control_is_connected(DBusConnection *conn,
114 struct audio_device *device = data;
115 struct control *control = device->control;
117 dbus_bool_t connected;
119 reply = dbus_message_new_method_return(msg);
123 connected = (control->session != NULL);
125 dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
131 static DBusMessage *volume_up(DBusConnection *conn, DBusMessage *msg,
134 struct audio_device *device = data;
135 struct control *control = device->control;
138 if (!control->session)
139 return btd_error_not_connected(msg);
141 if (!control->target)
142 return btd_error_not_supported(msg);
144 err = avctp_send_passthrough(control->session, VOL_UP_OP);
146 return btd_error_failed(msg, strerror(-err));
148 return dbus_message_new_method_return(msg);
151 static DBusMessage *volume_down(DBusConnection *conn, DBusMessage *msg,
154 struct audio_device *device = data;
155 struct control *control = device->control;
158 if (!control->session)
159 return btd_error_not_connected(msg);
161 if (!control->target)
162 return btd_error_not_supported(msg);
164 err = avctp_send_passthrough(control->session, VOL_DOWN_OP);
166 return btd_error_failed(msg, strerror(-err));
168 return dbus_message_new_method_return(msg);
171 static DBusMessage *control_get_properties(DBusConnection *conn,
172 DBusMessage *msg, void *data)
174 struct audio_device *device = data;
176 DBusMessageIter iter;
177 DBusMessageIter dict;
180 reply = dbus_message_new_method_return(msg);
184 dbus_message_iter_init_append(reply, &iter);
186 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
187 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
188 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
189 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
192 value = (device->control->session != NULL);
193 dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
195 dbus_message_iter_close_container(&iter, &dict);
200 static GDBusMethodTable control_methods[] = {
201 { "IsConnected", "", "b", control_is_connected,
202 G_DBUS_METHOD_FLAG_DEPRECATED },
203 { "GetProperties", "", "a{sv}",control_get_properties },
204 { "VolumeUp", "", "", volume_up },
205 { "VolumeDown", "", "", volume_down },
206 { NULL, NULL, NULL, NULL }
209 static GDBusSignalTable control_signals[] = {
210 { "Connected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED},
211 { "Disconnected", "", G_DBUS_SIGNAL_FLAG_DEPRECATED},
212 { "PropertyChanged", "sv" },
216 static void path_unregister(void *data)
218 struct audio_device *dev = data;
219 struct control *control = dev->control;
221 DBG("Unregistered interface %s on path %s",
222 AUDIO_CONTROL_INTERFACE, dev->path);
224 if (control->session)
225 avctp_disconnect(control->session);
231 void control_unregister(struct audio_device *dev)
233 g_dbus_unregister_interface(dev->conn, dev->path,
234 AUDIO_CONTROL_INTERFACE);
237 void control_update(struct control *control, uint16_t uuid16)
239 if (uuid16 == AV_REMOTE_TARGET_SVCLASS_ID)
240 control->target = TRUE;
243 struct control *control_init(struct audio_device *dev, uint16_t uuid16)
245 struct control *control;
247 if (!g_dbus_register_interface(dev->conn, dev->path,
248 AUDIO_CONTROL_INTERFACE,
249 control_methods, control_signals, NULL,
250 dev, path_unregister))
253 DBG("Registered interface %s on path %s",
254 AUDIO_CONTROL_INTERFACE, dev->path);
256 control = g_new0(struct control, 1);
259 control_update(control, uuid16);
262 avctp_id = avctp_add_state_cb(state_changed, NULL);
267 gboolean control_is_active(struct audio_device *dev)
269 struct control *control = dev->control;
271 if (control && control->session)