1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2009 Tanu Kaskinen 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of the License, 9 or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <dbus/dbus.h> 25 26#include <pulsecore/core-util.h> 27#include <pulsecore/dbus-util.h> 28 29#include "iface-device-port.h" 30 31#define OBJECT_NAME "port" 32 33static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata); 34static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata); 35static void handle_get_description(DBusConnection *conn, DBusMessage *msg, void *userdata); 36static void handle_get_priority(DBusConnection *conn, DBusMessage *msg, void *userdata); 37static void handle_get_available(DBusConnection *conn, DBusMessage *msg, void *userdata); 38 39static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata); 40 41struct pa_dbusiface_device_port { 42 uint32_t index; 43 pa_device_port *port; 44 char *path; 45 46 pa_hook_slot *available_changed_slot; 47 48 pa_dbus_protocol *dbus_protocol; 49}; 50 51enum property_handler_index { 52 PROPERTY_HANDLER_INDEX, 53 PROPERTY_HANDLER_NAME, 54 PROPERTY_HANDLER_DESCRIPTION, 55 PROPERTY_HANDLER_PRIORITY, 56 PROPERTY_HANDLER_AVAILABLE, 57 PROPERTY_HANDLER_MAX 58}; 59 60static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = { 61 [PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_get_index, .set_cb = NULL }, 62 [PROPERTY_HANDLER_NAME] = { .property_name = "Name", .type = "s", .get_cb = handle_get_name, .set_cb = NULL }, 63 [PROPERTY_HANDLER_DESCRIPTION] = { .property_name = "Description", .type = "s", .get_cb = handle_get_description, .set_cb = NULL }, 64 [PROPERTY_HANDLER_PRIORITY] = { .property_name = "Priority", .type = "u", .get_cb = handle_get_priority, .set_cb = NULL }, 65 [PROPERTY_HANDLER_AVAILABLE] = { .property_name = "Available", .type = "u", .get_cb = handle_get_available, .set_cb = NULL } 66}; 67 68enum signal_index { 69 SIGNAL_AVAILABLE_CHANGED, 70 SIGNAL_MAX 71}; 72 73static pa_dbus_arg_info available_changed_args[] = { { "available", "u", NULL } }; 74 75static pa_dbus_signal_info signals[SIGNAL_MAX] = { 76 [SIGNAL_AVAILABLE_CHANGED] = { .name = "AvailableChanged", .arguments = available_changed_args, .n_arguments = 1 } 77}; 78 79static pa_dbus_interface_info port_interface_info = { 80 .name = PA_DBUSIFACE_DEVICE_PORT_INTERFACE, 81 .method_handlers = NULL, 82 .n_method_handlers = 0, 83 .property_handlers = property_handlers, 84 .n_property_handlers = PROPERTY_HANDLER_MAX, 85 .get_all_properties_cb = handle_get_all, 86 .signals = signals, 87 .n_signals = SIGNAL_MAX 88}; 89 90static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) { 91 pa_dbusiface_device_port *p = userdata; 92 93 pa_assert(conn); 94 pa_assert(msg); 95 pa_assert(p); 96 97 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &p->index); 98} 99 100static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) { 101 pa_dbusiface_device_port *p = userdata; 102 103 pa_assert(conn); 104 pa_assert(msg); 105 pa_assert(p); 106 107 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &p->port->name); 108} 109 110static void handle_get_description(DBusConnection *conn, DBusMessage *msg, void *userdata) { 111 pa_dbusiface_device_port *p = userdata; 112 113 pa_assert(conn); 114 pa_assert(msg); 115 pa_assert(p); 116 117 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &p->port->description); 118} 119 120static void handle_get_priority(DBusConnection *conn, DBusMessage *msg, void *userdata) { 121 pa_dbusiface_device_port *p = userdata; 122 dbus_uint32_t priority = 0; 123 124 pa_assert(conn); 125 pa_assert(msg); 126 pa_assert(p); 127 128 priority = p->port->priority; 129 130 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &priority); 131} 132 133static void handle_get_available(DBusConnection *conn, DBusMessage *msg, void *userdata) { 134 pa_dbusiface_device_port *p = userdata; 135 dbus_uint32_t available = 0; 136 137 pa_assert(conn); 138 pa_assert(msg); 139 pa_assert(p); 140 141 available = p->port->available; 142 143 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &available); 144} 145 146 147static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) { 148 pa_dbusiface_device_port *p = userdata; 149 DBusMessage *reply = NULL; 150 DBusMessageIter msg_iter; 151 DBusMessageIter dict_iter; 152 dbus_uint32_t priority = 0; 153 154 pa_assert(conn); 155 pa_assert(msg); 156 pa_assert(p); 157 158 priority = p->port->priority; 159 160 pa_assert_se((reply = dbus_message_new_method_return(msg))); 161 162 dbus_message_iter_init_append(reply, &msg_iter); 163 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)); 164 165 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &p->index); 166 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &p->port->name); 167 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DESCRIPTION].property_name, DBUS_TYPE_STRING, &p->port->description); 168 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PRIORITY].property_name, DBUS_TYPE_UINT32, &priority); 169 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_AVAILABLE].property_name, DBUS_TYPE_UINT32, &p->port->available); 170 171 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter)); 172 173 pa_assert_se(dbus_connection_send(conn, reply, NULL)); 174 dbus_message_unref(reply); 175} 176 177static pa_hook_result_t available_changed_cb(void *hook_data, void *call_data, void *slot_data) { 178 pa_dbusiface_device_port *p = slot_data; 179 pa_device_port *port = call_data; 180 DBusMessage *signal_msg; 181 uint32_t available; 182 183 pa_assert(p); 184 pa_assert(port); 185 186 if(p->port != port) 187 return PA_HOOK_OK; 188 189 available = port->available; 190 191 pa_assert_se(signal_msg = dbus_message_new_signal(p->path, 192 PA_DBUSIFACE_DEVICE_PORT_INTERFACE, 193 signals[SIGNAL_AVAILABLE_CHANGED].name)); 194 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &available, DBUS_TYPE_INVALID)); 195 196 pa_dbus_protocol_send_signal(p->dbus_protocol, signal_msg); 197 dbus_message_unref(signal_msg); 198 199 return PA_HOOK_OK; 200} 201 202 203pa_dbusiface_device_port *pa_dbusiface_device_port_new( 204 pa_dbusiface_device *device, 205 pa_core *core, 206 pa_device_port *port, 207 uint32_t idx) { 208 pa_dbusiface_device_port *p = NULL; 209 210 pa_assert(device); 211 pa_assert(core); 212 pa_assert(port); 213 214 p = pa_xnew(pa_dbusiface_device_port, 1); 215 p->index = idx; 216 p->port = port; 217 p->path = pa_sprintf_malloc("%s/%s%u", pa_dbusiface_device_get_path(device), OBJECT_NAME, idx); 218 p->dbus_protocol = pa_dbus_protocol_get(core); 219 p->available_changed_slot = pa_hook_connect(&port->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], 220 PA_HOOK_NORMAL, available_changed_cb, p); 221 222 pa_assert_se(pa_dbus_protocol_add_interface(p->dbus_protocol, p->path, &port_interface_info, p) >= 0); 223 224 return p; 225} 226 227void pa_dbusiface_device_port_free(pa_dbusiface_device_port *p) { 228 pa_assert(p); 229 230 pa_assert_se(pa_dbus_protocol_remove_interface(p->dbus_protocol, p->path, port_interface_info.name) >= 0); 231 232 pa_hook_slot_free(p->available_changed_slot); 233 pa_dbus_protocol_unref(p->dbus_protocol); 234 235 pa_xfree(p->path); 236 pa_xfree(p); 237} 238 239const char *pa_dbusiface_device_port_get_path(pa_dbusiface_device_port *p) { 240 pa_assert(p); 241 242 return p->path; 243} 244 245const char *pa_dbusiface_device_port_get_name(pa_dbusiface_device_port *p) { 246 pa_assert(p); 247 248 return p->port->name; 249} 250