Home | History | Annotate | Download | only in audio
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2006-2010  Nokia Corporation
      6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel (at) holtmann.org>
      7  *
      8  *
      9  *  This program is free software; you can redistribute it and/or modify
     10  *  it under the terms of the GNU General Public License as published by
     11  *  the Free Software Foundation; either version 2 of the License, or
     12  *  (at your option) any later version.
     13  *
     14  *  This program is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *  GNU General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU General Public License
     20  *  along with this program; if not, write to the Free Software
     21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     22  *
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include <config.h>
     27 #endif
     28 
     29 #include <stdlib.h>
     30 #include <stdio.h>
     31 #include <stdint.h>
     32 #include <glib.h>
     33 #include <dbus/dbus.h>
     34 #include <gdbus.h>
     35 
     36 #include "log.h"
     37 #include "telephony.h"
     38 
     39 #define TELEPHONY_DUMMY_IFACE "org.bluez.TelephonyTest"
     40 #define TELEPHONY_DUMMY_PATH "/org/bluez/test"
     41 
     42 static DBusConnection *connection = NULL;
     43 
     44 static const char *chld_str = "0,1,1x,2,2x,3,4";
     45 static char *subscriber_number = NULL;
     46 static char *active_call_number = NULL;
     47 static int active_call_status = 0;
     48 static int active_call_dir = 0;
     49 
     50 static gboolean events_enabled = FALSE;
     51 
     52 /* Response and hold state
     53  * -1 = none
     54  *  0 = incoming call is put on hold in the AG
     55  *  1 = held incoming call is accepted in the AG
     56  *  2 = held incoming call is rejected in the AG
     57  */
     58 static int response_and_hold = -1;
     59 
     60 static struct indicator dummy_indicators[] =
     61 {
     62 	{ "battchg",	"0-5",	5,	TRUE },
     63 	{ "signal",	"0-5",	5,	TRUE },
     64 	{ "service",	"0,1",	1,	TRUE },
     65 	{ "call",	"0,1",	0,	TRUE },
     66 	{ "callsetup",	"0-3",	0,	TRUE },
     67 	{ "callheld",	"0-2",	0,	FALSE },
     68 	{ "roam",	"0,1",	0,	TRUE },
     69 	{ NULL }
     70 };
     71 
     72 static inline DBusMessage *invalid_args(DBusMessage *msg)
     73 {
     74 	return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
     75 					"Invalid arguments in method call");
     76 }
     77 
     78 void telephony_device_connected(void *telephony_device)
     79 {
     80 	DBG("telephony-dummy: device %p connected", telephony_device);
     81 }
     82 
     83 void telephony_device_disconnected(void *telephony_device)
     84 {
     85 	DBG("telephony-dummy: device %p disconnected", telephony_device);
     86 	events_enabled = FALSE;
     87 }
     88 
     89 void telephony_event_reporting_req(void *telephony_device, int ind)
     90 {
     91 	events_enabled = ind == 1 ? TRUE : FALSE;
     92 
     93 	telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
     94 }
     95 
     96 void telephony_response_and_hold_req(void *telephony_device, int rh)
     97 {
     98 	response_and_hold = rh;
     99 
    100 	telephony_response_and_hold_ind(response_and_hold);
    101 
    102 	telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NONE);
    103 }
    104 
    105 void telephony_last_dialed_number_req(void *telephony_device)
    106 {
    107 	telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NONE);
    108 
    109 	/* Notify outgoing call set-up successfully initiated */
    110 	telephony_update_indicator(dummy_indicators, "callsetup",
    111 					EV_CALLSETUP_OUTGOING);
    112 	telephony_update_indicator(dummy_indicators, "callsetup",
    113 					EV_CALLSETUP_ALERTING);
    114 
    115 	active_call_status = CALL_STATUS_ALERTING;
    116 	active_call_dir = CALL_DIR_OUTGOING;
    117 }
    118 
    119 void telephony_terminate_call_req(void *telephony_device)
    120 {
    121 	g_free(active_call_number);
    122 	active_call_number = NULL;
    123 
    124 	telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
    125 
    126 	if (telephony_get_indicator(dummy_indicators, "callsetup") > 0)
    127 		telephony_update_indicator(dummy_indicators, "callsetup",
    128 						EV_CALLSETUP_INACTIVE);
    129 	else
    130 		telephony_update_indicator(dummy_indicators, "call",
    131 						EV_CALL_INACTIVE);
    132 }
    133 
    134 void telephony_answer_call_req(void *telephony_device)
    135 {
    136 	telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
    137 
    138 	telephony_update_indicator(dummy_indicators, "call", EV_CALL_ACTIVE);
    139 	telephony_update_indicator(dummy_indicators, "callsetup",
    140 					EV_CALLSETUP_INACTIVE);
    141 
    142 	active_call_status = CALL_STATUS_ACTIVE;
    143 }
    144 
    145 void telephony_dial_number_req(void *telephony_device, const char *number)
    146 {
    147 	g_free(active_call_number);
    148 	active_call_number = g_strdup(number);
    149 
    150 	DBG("telephony-dummy: dial request to %s", active_call_number);
    151 
    152 	telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
    153 
    154 	/* Notify outgoing call set-up successfully initiated */
    155 	telephony_update_indicator(dummy_indicators, "callsetup",
    156 					EV_CALLSETUP_OUTGOING);
    157 	telephony_update_indicator(dummy_indicators, "callsetup",
    158 					EV_CALLSETUP_ALERTING);
    159 
    160 	active_call_status = CALL_STATUS_ALERTING;
    161 	active_call_dir = CALL_DIR_OUTGOING;
    162 }
    163 
    164 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
    165 {
    166 	DBG("telephony-dummy: transmit dtmf: %c", tone);
    167 	telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
    168 }
    169 
    170 void telephony_subscriber_number_req(void *telephony_device)
    171 {
    172 	DBG("telephony-dummy: subscriber number request");
    173 	if (subscriber_number)
    174 		telephony_subscriber_number_ind(subscriber_number,
    175 						NUMBER_TYPE_TELEPHONY,
    176 						SUBSCRIBER_SERVICE_VOICE);
    177 	telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
    178 }
    179 
    180 void telephony_list_current_calls_req(void *telephony_device)
    181 {
    182 	DBG("telephony-dummy: list current calls request");
    183 	if (active_call_number)
    184 		telephony_list_current_call_ind(1, active_call_dir,
    185 						active_call_status,
    186 						CALL_MODE_VOICE,
    187 						CALL_MULTIPARTY_NO,
    188 						active_call_number,
    189 						NUMBER_TYPE_TELEPHONY);
    190 	telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
    191 }
    192 
    193 void telephony_operator_selection_req(void *telephony_device)
    194 {
    195 	telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "DummyOperator");
    196 	telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
    197 }
    198 
    199 void telephony_call_hold_req(void *telephony_device, const char *cmd)
    200 {
    201 	DBG("telephony-dymmy: got call hold request %s", cmd);
    202 	telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
    203 }
    204 
    205 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
    206 {
    207 	DBG("telephony-dummy: got %s NR and EC request",
    208 			enable ? "enable" : "disable");
    209 
    210 	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
    211 }
    212 
    213 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
    214 {
    215 	DBG("telephony-dummy: got %s voice dial request",
    216 			enable ? "enable" : "disable");
    217 
    218 	g_dbus_emit_signal(connection, TELEPHONY_DUMMY_PATH,
    219 			TELEPHONY_DUMMY_IFACE, "VoiceDial",
    220 			DBUS_TYPE_INVALID);
    221 
    222 	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE);
    223 }
    224 
    225 void telephony_key_press_req(void *telephony_device, const char *keys)
    226 {
    227 	DBG("telephony-dummy: got key press request for %s", keys);
    228 	telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
    229 }
    230 
    231 /* D-Bus method handlers */
    232 static DBusMessage *outgoing_call(DBusConnection *conn, DBusMessage *msg,
    233 					void *data)
    234 {
    235 	const char *number;
    236 
    237 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
    238 						DBUS_TYPE_INVALID))
    239 		return invalid_args(msg);
    240 
    241 	DBG("telephony-dummy: outgoing call to %s", number);
    242 
    243 	g_free(active_call_number);
    244 	active_call_number = g_strdup(number);
    245 
    246 	telephony_update_indicator(dummy_indicators, "callsetup",
    247 					EV_CALLSETUP_OUTGOING);
    248 	telephony_update_indicator(dummy_indicators, "callsetup",
    249 					EV_CALLSETUP_ALERTING);
    250 
    251 	active_call_status = CALL_STATUS_ALERTING;
    252 	active_call_dir = CALL_DIR_OUTGOING;
    253 
    254 	return dbus_message_new_method_return(msg);
    255 }
    256 
    257 static DBusMessage *incoming_call(DBusConnection *conn, DBusMessage *msg,
    258 					void *data)
    259 {
    260 	const char *number;
    261 
    262 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
    263 						DBUS_TYPE_INVALID))
    264 		return invalid_args(msg);
    265 
    266 	DBG("telephony-dummy: incoming call to %s", number);
    267 
    268 	g_free(active_call_number);
    269 	active_call_number = g_strdup(number);
    270 
    271 	telephony_update_indicator(dummy_indicators, "callsetup",
    272 					EV_CALLSETUP_INCOMING);
    273 
    274 	active_call_status = CALL_STATUS_INCOMING;
    275 	active_call_dir = CALL_DIR_INCOMING;
    276 
    277 	telephony_incoming_call_ind(number, NUMBER_TYPE_TELEPHONY);
    278 
    279 	return dbus_message_new_method_return(msg);
    280 }
    281 
    282 static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg,
    283 					void *data)
    284 {
    285 	DBG("telephony-dummy: cancel call");
    286 
    287 	g_free(active_call_number);
    288 	active_call_number = NULL;
    289 
    290 	if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) {
    291 		telephony_update_indicator(dummy_indicators, "callsetup",
    292 						EV_CALLSETUP_INACTIVE);
    293 		telephony_calling_stopped_ind();
    294 	}
    295 
    296 	if (telephony_get_indicator(dummy_indicators, "call") > 0)
    297 		telephony_update_indicator(dummy_indicators, "call",
    298 						EV_CALL_INACTIVE);
    299 
    300 	return dbus_message_new_method_return(msg);
    301 }
    302 
    303 static DBusMessage *signal_strength(DBusConnection *conn, DBusMessage *msg,
    304 					void *data)
    305 {
    306 	dbus_uint32_t strength;
    307 
    308 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &strength,
    309 						DBUS_TYPE_INVALID))
    310 		return invalid_args(msg);
    311 
    312 	if (strength > 5)
    313 		return invalid_args(msg);
    314 
    315 	telephony_update_indicator(dummy_indicators, "signal", strength);
    316 
    317 	DBG("telephony-dummy: signal strength set to %u", strength);
    318 
    319 	return dbus_message_new_method_return(msg);
    320 }
    321 
    322 static DBusMessage *battery_level(DBusConnection *conn, DBusMessage *msg,
    323 					void *data)
    324 {
    325 	dbus_uint32_t level;
    326 
    327 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &level,
    328 						DBUS_TYPE_INVALID))
    329 		return invalid_args(msg);
    330 
    331 	if (level > 5)
    332 		return invalid_args(msg);
    333 
    334 	telephony_update_indicator(dummy_indicators, "battchg", level);
    335 
    336 	DBG("telephony-dummy: battery level set to %u", level);
    337 
    338 	return dbus_message_new_method_return(msg);
    339 }
    340 
    341 static DBusMessage *roaming_status(DBusConnection *conn, DBusMessage *msg,
    342 					void *data)
    343 {
    344 	dbus_bool_t roaming;
    345 	int val;
    346 
    347 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &roaming,
    348 						DBUS_TYPE_INVALID))
    349 		return invalid_args(msg);
    350 
    351 	val = roaming ? EV_ROAM_ACTIVE : EV_ROAM_INACTIVE;
    352 
    353 	telephony_update_indicator(dummy_indicators, "roam", val);
    354 
    355 	DBG("telephony-dummy: roaming status set to %d", val);
    356 
    357 	return dbus_message_new_method_return(msg);
    358 }
    359 
    360 static DBusMessage *registration_status(DBusConnection *conn, DBusMessage *msg,
    361 					void *data)
    362 {
    363 	dbus_bool_t registration;
    364 	int val;
    365 
    366 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &registration,
    367 						DBUS_TYPE_INVALID))
    368 		return invalid_args(msg);
    369 
    370 	val = registration ? EV_SERVICE_PRESENT : EV_SERVICE_NONE;
    371 
    372 	telephony_update_indicator(dummy_indicators, "service", val);
    373 
    374 	DBG("telephony-dummy: registration status set to %d", val);
    375 
    376 	return dbus_message_new_method_return(msg);
    377 }
    378 
    379 static DBusMessage *set_subscriber_number(DBusConnection *conn,
    380 						DBusMessage *msg,
    381 						void *data)
    382 {
    383 	const char *number;
    384 
    385 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
    386 						DBUS_TYPE_INVALID))
    387 		return invalid_args(msg);
    388 
    389 	g_free(subscriber_number);
    390 	subscriber_number = g_strdup(number);
    391 
    392 	DBG("telephony-dummy: subscriber number set to %s", number);
    393 
    394 	return dbus_message_new_method_return(msg);
    395 }
    396 
    397 static GDBusMethodTable dummy_methods[] = {
    398 	{ "OutgoingCall",	"s",	"",	outgoing_call		},
    399 	{ "IncomingCall",	"s",	"",	incoming_call		},
    400 	{ "CancelCall",		"",	"",	cancel_call		},
    401 	{ "SignalStrength",	"u",	"",	signal_strength		},
    402 	{ "BatteryLevel",	"u",	"",	battery_level		},
    403 	{ "RoamingStatus",	"b",	"",	roaming_status		},
    404 	{ "RegistrationStatus",	"b",	"",	registration_status	},
    405 	{ "SetSubscriberNumber","s",	"",	set_subscriber_number	},
    406 	{ }
    407 };
    408 
    409 static GDBusSignalTable dummy_signals[] = {
    410 	{ "VoiceDial",	"" },
    411 	{ }
    412 };
    413 
    414 int telephony_init(void)
    415 {
    416 	uint32_t features = AG_FEATURE_REJECT_A_CALL |
    417 				AG_FEATURE_ENHANCED_CALL_STATUS |
    418 				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
    419 
    420 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
    421 
    422 	if (g_dbus_register_interface(connection, TELEPHONY_DUMMY_PATH,
    423 					TELEPHONY_DUMMY_IFACE,
    424 					dummy_methods, dummy_signals,
    425 					NULL, NULL, NULL) == FALSE) {
    426 		error("telephony-dummy interface %s init failed on path %s",
    427 			TELEPHONY_DUMMY_IFACE, TELEPHONY_DUMMY_PATH);
    428 		return -1;
    429 	}
    430 
    431 	telephony_ready_ind(features, dummy_indicators, response_and_hold,
    432 				chld_str);
    433 
    434 	return 0;
    435 }
    436 
    437 void telephony_exit(void)
    438 {
    439 	dbus_connection_unref(connection);
    440 	connection = NULL;
    441 }
    442