Home | History | Annotate | Download | only in audio
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2006-2007  Nokia Corporation
      6  *  Copyright (C) 2004-2009  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 "logging.h"
     37 #include "telephony.h"
     38 
     39 static const char *chld_str = "0,1,1x,2,2x,3,4";
     40 static char *subscriber_number = NULL;
     41 static char *active_call_number = NULL;
     42 static int active_call_status = 0;
     43 static int active_call_dir = 0;
     44 
     45 static gboolean events_enabled = FALSE;
     46 
     47 /* Response and hold state
     48  * -1 = none
     49  *  0 = incoming call is put on hold in the AG
     50  *  1 = held incoming call is accepted in the AG
     51  *  2 = held incoming call is rejected in the AG
     52  */
     53 static int response_and_hold = -1;
     54 
     55 static struct indicator dummy_indicators[] =
     56 {
     57 	{ "battchg",	"0-5",	5,	TRUE },
     58 	{ "signal",	"0-5",	5,	TRUE },
     59 	{ "service",	"0,1",	1,	TRUE },
     60 	{ "call",	"0,1",	0,	TRUE },
     61 	{ "callsetup",	"0-3",	0,	TRUE },
     62 	{ "callheld",	"0-2",	0,	FALSE },
     63 	{ "roam",	"0,1",	0,	TRUE },
     64 	{ NULL }
     65 };
     66 
     67 static inline DBusMessage *invalid_args(DBusMessage *msg)
     68 {
     69 	return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
     70 					"Invalid arguments in method call");
     71 }
     72 
     73 void telephony_device_connected(void *telephony_device)
     74 {
     75 	debug("telephony-dummy: device %p connected", telephony_device);
     76 }
     77 
     78 void telephony_device_disconnected(void *telephony_device)
     79 {
     80 	debug("telephony-dummy: device %p disconnected", telephony_device);
     81 	events_enabled = FALSE;
     82 }
     83 
     84 void telephony_event_reporting_req(void *telephony_device, int ind)
     85 {
     86 	events_enabled = ind == 1 ? TRUE : FALSE;
     87 
     88 	telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
     89 }
     90 
     91 void telephony_response_and_hold_req(void *telephony_device, int rh)
     92 {
     93 	response_and_hold = rh;
     94 
     95 	telephony_response_and_hold_ind(response_and_hold);
     96 
     97 	telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NONE);
     98 }
     99 
    100 void telephony_last_dialed_number_req(void *telephony_device)
    101 {
    102 	telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NONE);
    103 
    104 	/* Notify outgoing call set-up successfully initiated */
    105 	telephony_update_indicator(dummy_indicators, "callsetup",
    106 					EV_CALLSETUP_OUTGOING);
    107 	telephony_update_indicator(dummy_indicators, "callsetup",
    108 					EV_CALLSETUP_ALERTING);
    109 
    110 	active_call_status = CALL_STATUS_ALERTING;
    111 	active_call_dir = CALL_DIR_OUTGOING;
    112 }
    113 
    114 void telephony_terminate_call_req(void *telephony_device)
    115 {
    116 	g_free(active_call_number);
    117 	active_call_number = NULL;
    118 
    119 	telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
    120 
    121 	if (telephony_get_indicator(dummy_indicators, "callsetup") > 0)
    122 		telephony_update_indicator(dummy_indicators, "callsetup",
    123 						EV_CALLSETUP_INACTIVE);
    124 	else
    125 		telephony_update_indicator(dummy_indicators, "call",
    126 						EV_CALL_INACTIVE);
    127 }
    128 
    129 void telephony_answer_call_req(void *telephony_device)
    130 {
    131 	telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
    132 
    133 	telephony_update_indicator(dummy_indicators, "call", EV_CALL_ACTIVE);
    134 	telephony_update_indicator(dummy_indicators, "callsetup",
    135 					EV_CALLSETUP_INACTIVE);
    136 
    137 	active_call_status = CALL_STATUS_ACTIVE;
    138 }
    139 
    140 void telephony_dial_number_req(void *telephony_device, const char *number)
    141 {
    142 	g_free(active_call_number);
    143 	active_call_number = g_strdup(number);
    144 
    145 	debug("telephony-dummy: dial request to %s", active_call_number);
    146 
    147 	telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
    148 
    149 	/* Notify outgoing call set-up successfully initiated */
    150 	telephony_update_indicator(dummy_indicators, "callsetup",
    151 					EV_CALLSETUP_OUTGOING);
    152 	telephony_update_indicator(dummy_indicators, "callsetup",
    153 					EV_CALLSETUP_ALERTING);
    154 
    155 	active_call_status = CALL_STATUS_ALERTING;
    156 	active_call_dir = CALL_DIR_OUTGOING;
    157 }
    158 
    159 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
    160 {
    161 	debug("telephony-dummy: transmit dtmf: %c", tone);
    162 	telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
    163 }
    164 
    165 void telephony_subscriber_number_req(void *telephony_device)
    166 {
    167 	debug("telephony-dummy: subscriber number request");
    168 	if (subscriber_number)
    169 		telephony_subscriber_number_ind(subscriber_number,
    170 						NUMBER_TYPE_TELEPHONY,
    171 						SUBSCRIBER_SERVICE_VOICE);
    172 	telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
    173 }
    174 
    175 void telephony_list_current_calls_req(void *telephony_device)
    176 {
    177 	debug("telephony-dummy: list current calls request");
    178 	if (active_call_number)
    179 		telephony_list_current_call_ind(1, active_call_dir,
    180 						active_call_status,
    181 						CALL_MODE_VOICE,
    182 						CALL_MULTIPARTY_NO,
    183 						active_call_number,
    184 						NUMBER_TYPE_TELEPHONY);
    185 	telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
    186 }
    187 
    188 void telephony_operator_selection_req(void *telephony_device)
    189 {
    190 	telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "DummyOperator");
    191 	telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
    192 }
    193 
    194 void telephony_call_hold_req(void *telephony_device, const char *cmd)
    195 {
    196 	debug("telephony-dymmy: got call hold request %s", cmd);
    197 	telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
    198 }
    199 
    200 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
    201 {
    202 	debug("telephony-dummy: got %s NR and EC request",
    203 			enable ? "enable" : "disable");
    204 
    205 	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
    206 }
    207 
    208 void telephony_key_press_req(void *telephony_device, const char *keys)
    209 {
    210 	debug("telephony-dummy: got key press request for %s", keys);
    211 	telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
    212 }
    213 
    214 /* D-Bus method handlers */
    215 static DBusMessage *outgoing_call(DBusConnection *conn, DBusMessage *msg,
    216 					void *data)
    217 {
    218 	const char *number;
    219 
    220 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
    221 						DBUS_TYPE_INVALID))
    222 		return invalid_args(msg);
    223 
    224 	debug("telephony-dummy: outgoing call to %s", number);
    225 
    226 	g_free(active_call_number);
    227 	active_call_number = g_strdup(number);
    228 
    229 	telephony_update_indicator(dummy_indicators, "callsetup",
    230 					EV_CALLSETUP_OUTGOING);
    231 	telephony_update_indicator(dummy_indicators, "callsetup",
    232 					EV_CALLSETUP_ALERTING);
    233 
    234 	active_call_status = CALL_STATUS_ALERTING;
    235 	active_call_dir = CALL_DIR_OUTGOING;
    236 
    237 	return dbus_message_new_method_return(msg);
    238 }
    239 
    240 static DBusMessage *incoming_call(DBusConnection *conn, DBusMessage *msg,
    241 					void *data)
    242 {
    243 	const char *number;
    244 
    245 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
    246 						DBUS_TYPE_INVALID))
    247 		return invalid_args(msg);
    248 
    249 	debug("telephony-dummy: incoming call to %s", number);
    250 
    251 	g_free(active_call_number);
    252 	active_call_number = g_strdup(number);
    253 
    254 	telephony_update_indicator(dummy_indicators, "callsetup",
    255 					EV_CALLSETUP_INCOMING);
    256 
    257 	active_call_status = CALL_STATUS_INCOMING;
    258 	active_call_dir = CALL_DIR_INCOMING;
    259 
    260 	telephony_incoming_call_ind(number, NUMBER_TYPE_TELEPHONY);
    261 
    262 	return dbus_message_new_method_return(msg);
    263 }
    264 
    265 static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg,
    266 					void *data)
    267 {
    268 	debug("telephony-dummy: cancel call");
    269 
    270 	g_free(active_call_number);
    271 	active_call_number = NULL;
    272 
    273 	if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) {
    274 		telephony_update_indicator(dummy_indicators, "callsetup",
    275 						EV_CALLSETUP_INACTIVE);
    276 		telephony_calling_stopped_ind();
    277 	}
    278 
    279 	if (telephony_get_indicator(dummy_indicators, "call") > 0)
    280 		telephony_update_indicator(dummy_indicators, "call",
    281 						EV_CALL_INACTIVE);
    282 
    283 	return dbus_message_new_method_return(msg);
    284 }
    285 
    286 static DBusMessage *signal_strength(DBusConnection *conn, DBusMessage *msg,
    287 					void *data)
    288 {
    289 	dbus_uint32_t strength;
    290 
    291 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &strength,
    292 						DBUS_TYPE_INVALID))
    293 		return invalid_args(msg);
    294 
    295 	if (strength > 5)
    296 		return invalid_args(msg);
    297 
    298 	telephony_update_indicator(dummy_indicators, "signal", strength);
    299 
    300 	debug("telephony-dummy: signal strength set to %u", strength);
    301 
    302 	return dbus_message_new_method_return(msg);
    303 }
    304 
    305 static DBusMessage *battery_level(DBusConnection *conn, DBusMessage *msg,
    306 					void *data)
    307 {
    308 	dbus_uint32_t level;
    309 
    310 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &level,
    311 						DBUS_TYPE_INVALID))
    312 		return invalid_args(msg);
    313 
    314 	if (level > 5)
    315 		return invalid_args(msg);
    316 
    317 	telephony_update_indicator(dummy_indicators, "battchg", level);
    318 
    319 	debug("telephony-dummy: battery level set to %u", level);
    320 
    321 	return dbus_message_new_method_return(msg);
    322 }
    323 
    324 static DBusMessage *roaming_status(DBusConnection *conn, DBusMessage *msg,
    325 					void *data)
    326 {
    327 	dbus_bool_t roaming;
    328 	int val;
    329 
    330 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &roaming,
    331 						DBUS_TYPE_INVALID))
    332 		return invalid_args(msg);
    333 
    334 	val = roaming ? EV_ROAM_ACTIVE : EV_ROAM_INACTIVE;
    335 
    336 	telephony_update_indicator(dummy_indicators, "roam", val);
    337 
    338 	debug("telephony-dummy: roaming status set to %d", val);
    339 
    340 	return dbus_message_new_method_return(msg);
    341 }
    342 
    343 static DBusMessage *registration_status(DBusConnection *conn, DBusMessage *msg,
    344 					void *data)
    345 {
    346 	dbus_bool_t registration;
    347 	int val;
    348 
    349 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &registration,
    350 						DBUS_TYPE_INVALID))
    351 		return invalid_args(msg);
    352 
    353 	val = registration ? EV_SERVICE_PRESENT : EV_SERVICE_NONE;
    354 
    355 	telephony_update_indicator(dummy_indicators, "service", val);
    356 
    357 	debug("telephony-dummy: registration status set to %d", val);
    358 
    359 	return dbus_message_new_method_return(msg);
    360 }
    361 
    362 static DBusMessage *set_subscriber_number(DBusConnection *conn,
    363 						DBusMessage *msg,
    364 						void *data)
    365 {
    366 	const char *number;
    367 
    368 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
    369 						DBUS_TYPE_INVALID))
    370 		return invalid_args(msg);
    371 
    372 	g_free(subscriber_number);
    373 	subscriber_number = g_strdup(number);
    374 
    375 	debug("telephony-dummy: subscriber number set to %s", number);
    376 
    377 	return dbus_message_new_method_return(msg);
    378 }
    379 
    380 static GDBusMethodTable dummy_methods[] = {
    381 	{ "OutgoingCall",	"s",	"",	outgoing_call		},
    382 	{ "IncomingCall",	"s",	"",	incoming_call		},
    383 	{ "CancelCall",		"",	"",	cancel_call		},
    384 	{ "SignalStrength",	"u",	"",	signal_strength		},
    385 	{ "BatteryLevel",	"u",	"",	battery_level		},
    386 	{ "RoamingStatus",	"b",	"",	roaming_status		},
    387 	{ "RegistrationStatus",	"b",	"",	registration_status	},
    388 	{ "SetSubscriberNumber","s",	"",	set_subscriber_number	},
    389 	{ }
    390 };
    391 
    392 static DBusConnection *connection = NULL;
    393 
    394 int telephony_init(void)
    395 {
    396 	uint32_t features = AG_FEATURE_REJECT_A_CALL |
    397 				AG_FEATURE_ENHANCED_CALL_STATUS |
    398 				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
    399 
    400 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
    401 
    402 	g_dbus_register_interface(connection, "/org/bluez/test",
    403 					"org.bluez.TelephonyTest",
    404 					dummy_methods, NULL,
    405 					NULL, NULL, NULL);
    406 
    407 	telephony_ready_ind(features, dummy_indicators, response_and_hold,
    408 				chld_str);
    409 
    410 	return 0;
    411 }
    412 
    413 void telephony_exit(void)
    414 {
    415 	dbus_connection_unref(connection);
    416 	connection = NULL;
    417 }
    418