Home | History | Annotate | Download | only in server
      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