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. */
get_single_arg(DBusMessage * message,int dbus_type,void * arg)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. */
send_empty_reply(DBusConnection * conn,DBusMessage * message)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
handle_incoming_call(DBusConnection * conn,DBusMessage * message,void * arg)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
handle_terminate_call(DBusConnection * conn,DBusMessage * message,void * arg)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
handle_answer_call(DBusConnection * conn,DBusMessage * message,void * arg)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
handle_set_dial_number(DBusConnection * conn,DBusMessage * message,void * arg)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
handle_set_battery(DBusConnection * conn,DBusMessage * message,void * arg)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
handle_set_signal(DBusConnection * conn,DBusMessage * message,void * arg)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
handle_set_service(DBusConnection * conn,DBusMessage * message,void * arg)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
handle_set_callheld(DBusConnection * conn,DBusMessage * message,void * arg)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. */
handle_telephony_message(DBusConnection * conn,DBusMessage * message,void * arg)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
cras_telephony_start(DBusConnection * conn)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
cras_telephony_stop()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
cras_telephony_get()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 */
cras_telephony_event_answer_call()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 */
cras_telephony_event_terminate_call()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
cras_telephony_store_dial_number(int len,const char * number)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