1 /* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include <string.h> 7 #include <stdlib.h> 8 #include <syslog.h> 9 10 #include <dbus/dbus.h> 11 12 #include "cras_telephony.h" 13 #include "cras_hfp_ag_profile.h" 14 #include "cras_hfp_slc.h" 15 16 #define CRAS_TELEPHONY_INTERFACE "org.chromium.cras.Telephony" 17 #define CRAS_TELEPHONY_OBJECT_PATH "/org/chromium/cras/telephony" 18 #define TELEPHONY_INTROSPECT_XML \ 19 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ 20 "<node>\n" \ 21 " <interface name=\"" CRAS_TELEPHONY_INTERFACE "\">\n" \ 22 " <method name=\"AnswerCall\">\n" \ 23 " </method>\n" \ 24 " <method name=\"IncomingCall\">\n" \ 25 " <arg name=\"value\" type=\"s\" direction=\"in\"/>\n" \ 26 " </method>\n" \ 27 " <method name=\"TerminateCall\">\n" \ 28 " </method>\n" \ 29 " <method name=\"SetBatteryLevel\">\n" \ 30 " <arg name=\"value\" type=\"i\" direction=\"in\"/>\n" \ 31 " </method>\n" \ 32 " <method name=\"SetSignalStrength\">\n" \ 33 " <arg name=\"value\" type=\"i\" direction=\"in\"/>\n" \ 34 " </method>\n" \ 35 " <method name=\"SetServiceAvailability\">\n" \ 36 " <arg name=\"value\" type=\"i\" direction=\"in\"/>\n" \ 37 " </method>\n" \ 38 " <method name=\"SetDialNumber\">\n" \ 39 " <arg name=\"value\" type=\"s\" direction=\"in\"/>\n" \ 40 " </method>\n" \ 41 " <method name=\"SetCallheld\">\n" \ 42 " <arg name=\"value\" type=\"i\" direction=\"in\"/>\n" \ 43 " </method>\n" \ 44 " </interface>\n" \ 45 " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n" \ 46 " <method name=\"Introspect\">\n" \ 47 " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \ 48 " </method>\n" \ 49 " </interface>\n" \ 50 "</node>\n" 51 52 static struct cras_telephony_handle telephony_handle; 53 54 /* Helper to extract a single argument from a DBus message. */ 55 static DBusHandlerResult get_single_arg(DBusMessage *message, 56 int dbus_type, void *arg) 57 { 58 DBusError dbus_error; 59 60 dbus_error_init(&dbus_error); 61 62 if (!dbus_message_get_args(message, &dbus_error, 63 dbus_type, arg, 64 DBUS_TYPE_INVALID)) { 65 syslog(LOG_WARNING, 66 "Bad method received: %s", 67 dbus_error.message); 68 dbus_error_free(&dbus_error); 69 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 70 } 71 72 return DBUS_HANDLER_RESULT_HANDLED; 73 } 74 75 /* Helper to send an empty reply. */ 76 static void send_empty_reply(DBusConnection *conn, DBusMessage *message) 77 { 78 DBusMessage *reply; 79 dbus_uint32_t serial = 0; 80 81 reply = dbus_message_new_method_return(message); 82 if (!reply) 83 return; 84 85 dbus_connection_send(conn, reply, &serial); 86 87 dbus_message_unref(reply); 88 } 89 90 static DBusHandlerResult handle_incoming_call(DBusConnection *conn, 91 DBusMessage *message, 92 void *arg) 93 { 94 struct hfp_slc_handle *handle; 95 DBusHandlerResult rc; 96 const char* number; 97 98 rc = get_single_arg(message, DBUS_TYPE_STRING, &number); 99 if (rc != DBUS_HANDLER_RESULT_HANDLED) 100 return rc; 101 102 handle = cras_hfp_ag_get_active_handle(); 103 104 telephony_handle.callsetup = 1; 105 106 if (handle) { 107 hfp_event_update_callsetup(handle); 108 hfp_event_incoming_call(handle, number, 129); 109 } 110 111 send_empty_reply(conn, message); 112 return DBUS_HANDLER_RESULT_HANDLED; 113 } 114 115 static DBusHandlerResult handle_terminate_call(DBusConnection *conn, 116 DBusMessage *message, 117 void *arg) 118 { 119 cras_telephony_event_terminate_call(); 120 121 send_empty_reply(conn, message); 122 return DBUS_HANDLER_RESULT_HANDLED; 123 } 124 125 static DBusHandlerResult handle_answer_call(DBusConnection *conn, 126 DBusMessage *message, 127 void *arg) 128 { 129 cras_telephony_event_answer_call(); 130 131 send_empty_reply(conn, message); 132 return DBUS_HANDLER_RESULT_HANDLED; 133 } 134 135 static DBusHandlerResult handle_set_dial_number(DBusConnection *conn, 136 DBusMessage *message, 137 void *arg) 138 { 139 DBusHandlerResult rc; 140 const char *number; 141 142 rc = get_single_arg(message, DBUS_TYPE_STRING, &number); 143 if (rc != DBUS_HANDLER_RESULT_HANDLED) 144 return rc; 145 146 cras_telephony_store_dial_number(strlen(number), number); 147 148 send_empty_reply(conn, message); 149 return DBUS_HANDLER_RESULT_HANDLED; 150 } 151 152 static DBusHandlerResult handle_set_battery(DBusConnection *conn, 153 DBusMessage *message, 154 void *arg) 155 { 156 struct hfp_slc_handle *handle; 157 DBusHandlerResult rc; 158 int value; 159 160 rc = get_single_arg(message, DBUS_TYPE_INT32, &value); 161 if (rc != DBUS_HANDLER_RESULT_HANDLED) 162 return rc; 163 164 handle = cras_hfp_ag_get_active_handle(); 165 if (handle) 166 hfp_event_set_battery(handle, value); 167 168 send_empty_reply(conn, message); 169 return DBUS_HANDLER_RESULT_HANDLED; 170 } 171 172 static DBusHandlerResult handle_set_signal(DBusConnection *conn, 173 DBusMessage *message, 174 void *arg) 175 { 176 struct hfp_slc_handle *handle; 177 DBusHandlerResult rc; 178 int value; 179 180 rc = get_single_arg(message, DBUS_TYPE_INT32, &value); 181 if (rc != DBUS_HANDLER_RESULT_HANDLED) 182 return rc; 183 184 handle = cras_hfp_ag_get_active_handle(); 185 if (handle) 186 hfp_event_set_signal(handle, value); 187 188 send_empty_reply(conn, message); 189 return DBUS_HANDLER_RESULT_HANDLED; 190 } 191 192 static DBusHandlerResult handle_set_service(DBusConnection *conn, 193 DBusMessage *message, 194 void *arg) 195 { 196 struct hfp_slc_handle *handle; 197 DBusHandlerResult rc; 198 int value; 199 200 rc = get_single_arg(message, DBUS_TYPE_INT32, &value); 201 if (rc != DBUS_HANDLER_RESULT_HANDLED) 202 return rc; 203 204 handle = cras_hfp_ag_get_active_handle(); 205 if (handle) 206 hfp_event_set_service(handle, value); 207 208 send_empty_reply(conn, message); 209 return DBUS_HANDLER_RESULT_HANDLED; 210 } 211 212 static DBusHandlerResult handle_set_callheld(DBusConnection *conn, 213 DBusMessage *message, 214 void *arg) 215 { 216 struct hfp_slc_handle *handle; 217 DBusHandlerResult rc; 218 int value; 219 220 rc = get_single_arg(message, DBUS_TYPE_INT32, &value); 221 if (rc != DBUS_HANDLER_RESULT_HANDLED) 222 return rc; 223 224 telephony_handle.callheld = value; 225 handle = cras_hfp_ag_get_active_handle(); 226 if (handle) 227 hfp_event_update_callheld(handle); 228 229 send_empty_reply(conn, message); 230 return DBUS_HANDLER_RESULT_HANDLED; 231 } 232 233 /* Handle incoming messages. */ 234 static DBusHandlerResult handle_telephony_message(DBusConnection *conn, 235 DBusMessage *message, 236 void *arg) 237 { 238 syslog(LOG_ERR, "Telephony message: %s %s %s", 239 dbus_message_get_path(message), 240 dbus_message_get_interface(message), 241 dbus_message_get_member(message)); 242 243 if (dbus_message_is_method_call(message, 244 DBUS_INTERFACE_INTROSPECTABLE, 245 "Introspect")) { 246 DBusMessage *reply; 247 const char *xml = TELEPHONY_INTROSPECT_XML; 248 249 reply = dbus_message_new_method_return(message); 250 if (!reply) 251 return DBUS_HANDLER_RESULT_NEED_MEMORY; 252 if (!dbus_message_append_args(reply, 253 DBUS_TYPE_STRING, &xml, 254 DBUS_TYPE_INVALID)) 255 return DBUS_HANDLER_RESULT_NEED_MEMORY; 256 if (!dbus_connection_send(conn, reply, NULL)) 257 return DBUS_HANDLER_RESULT_NEED_MEMORY; 258 259 dbus_message_unref(reply); 260 return DBUS_HANDLER_RESULT_HANDLED; 261 } else if (dbus_message_is_method_call(message, 262 CRAS_TELEPHONY_INTERFACE, 263 "IncomingCall")) { 264 return handle_incoming_call(conn, message, arg); 265 } else if (dbus_message_is_method_call(message, 266 CRAS_TELEPHONY_INTERFACE, 267 "TerminateCall")) { 268 return handle_terminate_call(conn, message, arg); 269 } else if (dbus_message_is_method_call(message, 270 CRAS_TELEPHONY_INTERFACE, 271 "AnswerCall")) { 272 return handle_answer_call(conn, message, arg); 273 } else if (dbus_message_is_method_call(message, 274 CRAS_TELEPHONY_INTERFACE, 275 "SetDialNumber")) { 276 return handle_set_dial_number(conn, message, arg); 277 } else if (dbus_message_is_method_call(message, 278 CRAS_TELEPHONY_INTERFACE, 279 "SetBatteryLevel")) { 280 return handle_set_battery(conn, message, arg); 281 } else if (dbus_message_is_method_call(message, 282 CRAS_TELEPHONY_INTERFACE, 283 "SetSignalStrength")) { 284 return handle_set_signal(conn, message, arg); 285 } else if (dbus_message_is_method_call(message, 286 CRAS_TELEPHONY_INTERFACE, 287 "SetServiceAvailability")) { 288 return handle_set_service(conn, message, arg); 289 } else if (dbus_message_is_method_call(message, 290 CRAS_TELEPHONY_INTERFACE, 291 "SetCallheld")) { 292 return handle_set_callheld(conn, message, arg); 293 } 294 295 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 296 } 297 298 /* Exported Interface */ 299 300 void cras_telephony_start(DBusConnection *conn) 301 { 302 static const DBusObjectPathVTable control_vtable = { 303 .message_function = handle_telephony_message, 304 }; 305 306 DBusError dbus_error; 307 308 telephony_handle.dbus_conn = conn; 309 dbus_connection_ref(telephony_handle.dbus_conn); 310 311 if (!dbus_connection_register_object_path(conn, 312 CRAS_TELEPHONY_OBJECT_PATH, 313 &control_vtable, 314 &dbus_error)) { 315 syslog(LOG_ERR, 316 "Couldn't register telephony control: %s: %s", 317 CRAS_TELEPHONY_OBJECT_PATH, dbus_error.message); 318 dbus_error_free(&dbus_error); 319 return; 320 } 321 } 322 323 void cras_telephony_stop() 324 { 325 if (!telephony_handle.dbus_conn) 326 return; 327 328 dbus_connection_unregister_object_path(telephony_handle.dbus_conn, 329 CRAS_TELEPHONY_OBJECT_PATH); 330 dbus_connection_unref(telephony_handle.dbus_conn); 331 telephony_handle.dbus_conn = NULL; 332 } 333 334 struct cras_telephony_handle* cras_telephony_get() 335 { 336 return &telephony_handle; 337 } 338 339 /* Procedure to answer a call from AG. 340 * 341 * HF(hands-free) AG(audio gateway) 342 * <-- Call answered 343 * <-- +CIEV: (call = 1) 344 * <-- +CIEV: (callsetup = 0) 345 */ 346 int cras_telephony_event_answer_call() 347 { 348 int rc; 349 350 struct hfp_slc_handle *handle; 351 352 handle = cras_hfp_ag_get_active_handle(); 353 354 if (telephony_handle.call == 0) { 355 telephony_handle.call = 1; 356 if (handle) { 357 rc = hfp_event_update_call(handle); 358 if (rc) 359 return rc; 360 } 361 } 362 363 telephony_handle.callsetup = 0; 364 if (handle) { 365 rc = hfp_event_update_callsetup(handle); 366 if (rc) 367 return rc; 368 } 369 370 return 0; 371 } 372 373 /* Procedure to terminate a call from AG. 374 * 375 * HF(hands-free) AG(audio gateway) 376 * <-- Call dropped 377 * <-- +CIEV: (call = 0) 378 */ 379 int cras_telephony_event_terminate_call() 380 { 381 int rc; 382 struct hfp_slc_handle *handle; 383 384 handle = cras_hfp_ag_get_active_handle(); 385 386 if (telephony_handle.call) { 387 telephony_handle.call = 0; 388 if (handle) { 389 rc = hfp_event_update_call(handle); 390 if (rc) 391 return rc; 392 } 393 } 394 if (telephony_handle.callsetup) { 395 telephony_handle.callsetup = 0; 396 if (handle) { 397 rc = hfp_event_update_callsetup(handle); 398 if (rc) 399 return rc; 400 } 401 } 402 return 0; 403 } 404 405 void cras_telephony_store_dial_number(int len, 406 const char *number) 407 { 408 if (telephony_handle.dial_number != NULL) { 409 free(telephony_handle.dial_number); 410 telephony_handle.dial_number = NULL; 411 } 412 413 if (len == 0) 414 return ; 415 416 telephony_handle.dial_number = 417 (char *) calloc(len + 1, 418 sizeof(*telephony_handle.dial_number)); 419 strncpy(telephony_handle.dial_number, number, len); 420 421 syslog(LOG_ERR, 422 "store dial_number: \"%s\"", telephony_handle.dial_number); 423 } 424