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