From f1ca5f6c55279182f3d2a276fe5b9f2d180e3514 Mon Sep 17 00:00:00 2001 From: Martti Piirainen Date: Mon, 28 Jul 2014 09:42:42 +0300 Subject: [PATCH 1/5] doc: Add voicecall agent and ringback tone API --- doc/voicecallmanager-api.txt | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/doc/voicecallmanager-api.txt b/doc/voicecallmanager-api.txt index 34a9b25c5..5bb58071b 100644 --- a/doc/voicecallmanager-api.txt +++ b/doc/voicecallmanager-api.txt @@ -198,6 +198,25 @@ Methods dict GetProperties() [service].Error.InvalidFormat [service].Error.Failed + void RegisterVoicecallAgent(object path) + + Registers an agent which will be called whenever a + specific voice call related event requiring a client + action occurs. Currently, the only such action is + playing a ringback tone locally. + + Possible Errors: [service].Error.InProgress + [service].Error.InvalidArguments + [service].Error.InvalidFormat + [service].Error.Failed + + void UnregisterVoicecallAgent(object path) + + Unregisters an agent. + + Possible Errors: [service].Error.InvalidArguments + [service].Error.Failed + Signals CallAdded(object path, dict properties) Signal that is sent when a new call is added. It @@ -257,3 +276,24 @@ Properties array{string} EmergencyNumbers [readonly] of numbers provided by the specification and any extra numbers provisioned by the carrier on the SIM. + +VoiceCallAgent Hierarchy +======================== + +Service unique name +Interface org.ofono.VoiceCallAgent +Object path freely definable + +Methods void RingbackTone(boolean play_tone) + + Requests the client to generate an alerting tone locally + (3GPP 24.008; 5.2.1.5). This can happen when an outgoing voice call + is made and network is not providing the alerting tone. True stands + for "start playing ringback tone" and False for "stop playing + ringback tone". + + void Release() [noreply] + + Agent is being released, possibly because of oFono terminating, + voicecall interface is being torn down or modem is switched off. No + UnregisterVoiceCallManagerAgent call is needed. From 8089a353082fd34b4a2b04bc95f43fef27637190 Mon Sep 17 00:00:00 2001 From: Martti Piirainen Date: Mon, 28 Jul 2014 09:42:43 +0300 Subject: [PATCH 2/5] include: Add ringback tone notification --- include/voicecall.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/voicecall.h b/include/voicecall.h index 221366e57..ee3d903f5 100644 --- a/include/voicecall.h +++ b/include/voicecall.h @@ -164,6 +164,8 @@ void ofono_voicecall_ssn_mt_notify(struct ofono_voicecall *vc, unsigned int id, int code, int index, const struct ofono_phone_number *ph); +void ofono_voicecall_ringback_tone_notify(struct ofono_voicecall *vc, + const ofono_bool_t play_tone); #ifdef __cplusplus } #endif From 867cd875cd33d9a615a3cb85660b7c7de6a66997 Mon Sep 17 00:00:00 2001 From: Martti Piirainen Date: Mon, 28 Jul 2014 09:42:43 +0300 Subject: [PATCH 3/5] src: Implement voicecall agent functionality --- Makefile.am | 4 +- src/ofono.conf | 1 + src/voicecall.c | 80 ++++++++++++++++++++++++++ src/voicecallagent.c | 133 +++++++++++++++++++++++++++++++++++++++++++ src/voicecallagent.h | 40 +++++++++++++ 5 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 src/voicecallagent.c create mode 100644 src/voicecallagent.h diff --git a/Makefile.am b/Makefile.am index 1a3b0111c..6de5195f0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -577,7 +577,8 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) src/ofono.ver \ src/cdma-smsutil.h src/cdma-smsutil.c \ src/cdma-sms.c src/private-network.c src/cdma-netreg.c \ src/cdma-provision.c src/handsfree.c \ - src/sim-mnclength.c src/spn-table.c + src/sim-mnclength.c src/spn-table.c \ + src/voicecallagent.c src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ -ldl @@ -713,6 +714,7 @@ test_scripts = test/backtrace \ test/hold-and-answer \ test/hangup-multiparty \ test/hangup-call \ + test/test-voicecallagent \ test/rilmodem/test-hangup \ test/rilmodem/test-modem-offline \ test/rilmodem/test-sim-online diff --git a/src/ofono.conf b/src/ofono.conf index 8a83cd06b..16304bc49 100644 --- a/src/ofono.conf +++ b/src/ofono.conf @@ -14,6 +14,7 @@ + diff --git a/src/voicecall.c b/src/voicecall.c index ae76b91ff..7b8a8cc5d 100644 --- a/src/voicecall.c +++ b/src/voicecall.c @@ -3,6 +3,7 @@ * oFono - Open Source Telephony * * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2014 Jolla Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -38,6 +39,7 @@ #include "simutil.h" #include "smsutil.h" #include "storage.h" +#include "voicecallagent.h" #define MAX_VOICE_CALLS 16 @@ -75,6 +77,7 @@ struct ofono_voicecall { ofono_voicecall_cb_t release_queue_done_cb; struct ofono_emulator *pending_em; unsigned int pending_id; + struct voicecall_agent *vc_agent; }; struct voicecall { @@ -2140,6 +2143,72 @@ static DBusMessage *manager_get_calls(DBusConnection *conn, return reply; } +static void voicecall_agent_notify(gpointer user_data) +{ + struct ofono_voicecall *vc = user_data; + vc->vc_agent = NULL; +} + +static DBusMessage *voicecall_register_agent(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct ofono_voicecall *vc = data; + const char *agent_path; + + if (vc->vc_agent) + return __ofono_error_busy(msg); + + if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, + &agent_path, DBUS_TYPE_INVALID) == FALSE) + return __ofono_error_invalid_args(msg); + + if (!__ofono_dbus_valid_object_path(agent_path)) + return __ofono_error_invalid_format(msg); + + vc->vc_agent = voicecall_agent_new(agent_path, + dbus_message_get_sender(msg)); + + if (vc->vc_agent == NULL) + return __ofono_error_failed(msg); + + voicecall_agent_set_removed_notify(vc->vc_agent, + voicecall_agent_notify, vc); + + return dbus_message_new_method_return(msg); +} + +static DBusMessage *voicecall_unregister_agent(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct ofono_voicecall *vc = data; + const char *agent_path; + const char *agent_bus = dbus_message_get_sender(msg); + + if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &agent_path, + DBUS_TYPE_INVALID) == FALSE) + return __ofono_error_invalid_args(msg); + + if (vc->vc_agent == NULL) + return __ofono_error_failed(msg); + + if (!voicecall_agent_matches(vc->vc_agent, agent_path, agent_bus)) + return __ofono_error_access_denied(msg); + + if (vc->vc_agent) { + voicecall_agent_free(vc->vc_agent); + vc->vc_agent = NULL; + } + + return dbus_message_new_method_return(msg); +} + +void ofono_voicecall_ringback_tone_notify(struct ofono_voicecall *vc, + const ofono_bool_t play_tone) +{ + if (vc->vc_agent) + voicecall_agent_ringback_tone(vc->vc_agent, play_tone); +} + static const GDBusMethodTable manager_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), @@ -2172,6 +2241,12 @@ static const GDBusMethodTable manager_methods[] = { { GDBUS_METHOD("GetCalls", NULL, GDBUS_ARGS({ "calls_with_properties", "a(oa{sv})" }), manager_get_calls) }, + { GDBUS_ASYNC_METHOD("RegisterVoicecallAgent", + GDBUS_ARGS({ "path", "o" }), NULL, + voicecall_register_agent) }, + { GDBUS_ASYNC_METHOD("UnregisterVoicecallAgent", + GDBUS_ARGS({ "path", "o" }), NULL, + voicecall_unregister_agent) }, { } }; @@ -2704,6 +2779,11 @@ static void voicecall_unregister(struct ofono_atom *atom) voicecall_close_settings(vc); + if (vc->vc_agent) { + voicecall_agent_free(vc->vc_agent); + vc->vc_agent = NULL; + } + if (vc->sim_state_watch) { ofono_sim_remove_state_watch(vc->sim, vc->sim_state_watch); vc->sim_state_watch = 0; diff --git a/src/voicecallagent.c b/src/voicecallagent.c new file mode 100644 index 000000000..9ef12b9a0 --- /dev/null +++ b/src/voicecallagent.c @@ -0,0 +1,133 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2014 Jolla Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +#include "ofono.h" +#include "voicecallagent.h" + +#define OFONO_VOICECALL_AGENT_INTERFACE "org.ofono.VoiceCallAgent" + +struct voicecall_agent { + char *path; /* Agent Path */ + char *bus; /* Agent bus */ + guint disconnect_watch; /* DBus disconnect watch */ + ofono_destroy_func removed_cb; + void *removed_data; +}; + +void voicecall_agent_send_release(struct voicecall_agent *agent); + +void voicecall_agent_ringback_tone(struct voicecall_agent *agent, + const ofono_bool_t play_tone) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + DBusMessage *message = dbus_message_new_method_call( + agent->bus, agent->path, + OFONO_VOICECALL_AGENT_INTERFACE, + "RingbackTone"); + + if (message == NULL) + return; + + if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &play_tone, + DBUS_TYPE_INVALID)) + return; + + dbus_message_set_no_reply(message, TRUE); + g_dbus_send_message(conn, message); +} + +void voicecall_agent_send_release(struct voicecall_agent *agent) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + DBusMessage *message = dbus_message_new_method_call( + agent->bus, agent->path, + OFONO_VOICECALL_AGENT_INTERFACE, + "Release"); + + if (message == NULL) + return; + + dbus_message_set_no_reply(message, TRUE); + g_dbus_send_message(conn, message); +} + +void voicecall_agent_set_removed_notify(struct voicecall_agent *agent, + ofono_destroy_func destroy, + void *user_data) +{ + agent->removed_cb = destroy; + agent->removed_data = user_data; /* voicecall atom (not owned) */ +} + +void voicecall_agent_free(struct voicecall_agent *agent) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + + if (agent->disconnect_watch) { + voicecall_agent_send_release(agent); + g_dbus_remove_watch(conn, agent->disconnect_watch); + agent->disconnect_watch = 0; + } + + if (agent->removed_cb) + agent->removed_cb(agent->removed_data); + + g_free(agent->path); + g_free(agent->bus); + g_free(agent); +} + +ofono_bool_t voicecall_agent_matches(struct voicecall_agent *agent, + const char *path, const char *sender) +{ + return g_str_equal(agent->path, path) && + g_str_equal(agent->bus, sender); +} + +void voicecall_agent_disconnect_cb(DBusConnection *conn, void *user_data) +{ + struct voicecall_agent *agent = user_data; + + agent->disconnect_watch = 0; + voicecall_agent_free(agent); +} + +struct voicecall_agent *voicecall_agent_new(const char *path, + const char *sender) +{ + struct voicecall_agent *agent = g_try_new0(struct voicecall_agent, 1); + DBusConnection *conn = ofono_dbus_get_connection(); + + if (agent == NULL) + return NULL; + + agent->path = g_strdup(path); + agent->bus = g_strdup(sender); + + agent->disconnect_watch = g_dbus_add_disconnect_watch(conn, sender, + voicecall_agent_disconnect_cb, + agent, NULL); + + return agent; +} diff --git a/src/voicecallagent.h b/src/voicecallagent.h new file mode 100644 index 000000000..0cd07fc82 --- /dev/null +++ b/src/voicecallagent.h @@ -0,0 +1,40 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2014 Jolla Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +struct voicecall_agent; + +void voicecall_agent_ringback_tone(struct voicecall_agent *agent, + const ofono_bool_t play_tone); + +void voicecall_agent_set_removed_notify(struct voicecall_agent *agent, + ofono_destroy_func removed_cb, + void *user_data); + +void voicecall_agent_free(struct voicecall_agent *agent); + +ofono_bool_t voicecall_agent_matches(struct voicecall_agent *agent, + const char *path, const char *sender); + +struct voicecall_agent *voicecall_agent_new(const char *path, + const char *sender); + +void voicecall_agent_disconnect_cb(DBusConnection *conn, + void *user_data); From 45bda07d95d8571e394a3f74d53af747b567becc Mon Sep 17 00:00:00 2001 From: Martti Piirainen Date: Mon, 28 Jul 2014 09:42:43 +0300 Subject: [PATCH 4/5] rilmodem: Listen to ringback tone notifications --- drivers/rilmodem/voicecall.c | 15 +++++++++++++++ gril/grilunsol.c | 14 ++++++++++++++ gril/grilunsol.h | 2 ++ 3 files changed, 31 insertions(+) diff --git a/drivers/rilmodem/voicecall.c b/drivers/rilmodem/voicecall.c index d63dd6160..daa26743b 100644 --- a/drivers/rilmodem/voicecall.c +++ b/drivers/rilmodem/voicecall.c @@ -653,6 +653,17 @@ static gboolean enable_supp_svc(gpointer user_data) return FALSE; } +static void ril_ringback_tone_notify(struct ril_msg *message, + gpointer user_data) +{ + struct ofono_voicecall *vc = user_data; + struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc); + gboolean playTone = g_ril_unsol_parse_ringback_tone(vd->ril, message); + DBG("play ringback tone: %d", playTone); + ofono_voicecall_ringback_tone_notify(vc, playTone); + +} + static gboolean ril_delayed_register(gpointer user_data) { struct ofono_voicecall *vc = user_data; @@ -670,6 +681,10 @@ static gboolean ril_delayed_register(gpointer user_data) g_ril_register(vd->ril, RIL_UNSOL_SUPP_SVC_NOTIFICATION, ril_ss_notify, vc); + /* Register for ringback tone notifications */ + g_ril_register(vd->ril, RIL_UNSOL_RINGBACK_TONE, + ril_ringback_tone_notify, vc); + /* request supplementary service notifications*/ enable_supp_svc(vc); diff --git a/gril/grilunsol.c b/gril/grilunsol.c index e55623352..b02fc1ba9 100644 --- a/gril/grilunsol.c +++ b/gril/grilunsol.c @@ -577,3 +577,17 @@ struct unsol_ussd *g_ril_unsol_parse_ussd(GRil *gril, struct ril_msg *message) return NULL; } + +gboolean g_ril_unsol_parse_ringback_tone(GRil *gril, + struct ril_msg *message) +{ + struct parcel rilp; + gboolean playTone = FALSE; + + g_ril_init_parcel(message, &rilp); + if (parcel_r_int32(&rilp) > 0) + playTone = parcel_r_int32(&rilp); + + return playTone; +} + diff --git a/gril/grilunsol.h b/gril/grilunsol.h index a7ddfc942..9942fd21a 100644 --- a/gril/grilunsol.h +++ b/gril/grilunsol.h @@ -92,6 +92,8 @@ void g_ril_unsol_free_ussd(struct unsol_ussd *unsol); struct unsol_ussd *g_ril_unsol_parse_ussd(GRil *gril, struct ril_msg *message); +gboolean g_ril_unsol_parse_ringback_tone(GRil *gril, struct ril_msg *message); + #ifdef __cplusplus } #endif From b5d5942441b2be0702d609cabbcc39f0aecbc3f0 Mon Sep 17 00:00:00 2001 From: Martti Piirainen Date: Mon, 28 Jul 2014 09:42:43 +0300 Subject: [PATCH 5/5] test: Add voicecall agent test script --- test/test-voicecallagent | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100755 test/test-voicecallagent diff --git a/test/test-voicecallagent b/test/test-voicecallagent new file mode 100755 index 000000000..15caa38a8 --- /dev/null +++ b/test/test-voicecallagent @@ -0,0 +1,48 @@ +#!/usr/bin/python3 + +from gi.repository import GLib + +import sys +import dbus +import dbus.service +import dbus.mainloop.glib + +class VoiceCallAgent(dbus.service.Object): + @dbus.service.method("org.ofono.VoiceCallAgent", + in_signature="", out_signature="") + def Release(self): + print("Agent got Release") + mainloop.quit() + + @dbus.service.method("org.ofono.VoiceCallAgent", + in_signature="b", out_signature="") + def RingbackTone(self, play_tone): + print("Agent got play_tone notification: %d" % play_tone) + +if __name__ == '__main__': + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + bus = dbus.SystemBus() + manager = dbus.Interface(bus.get_object("org.ofono", "/"), + "org.ofono.Manager") + + modems = manager.GetModems() + + for path, properties in modems: + if "org.ofono.VoiceCallManager" not in properties["Interfaces"]: + continue + + vcm = dbus.Interface(bus.get_object('org.ofono', path), + 'org.ofono.VoiceCallManager') + + path = "/test/agent" + agent = VoiceCallAgent(bus, path) + vcm.RegisterVoicecallAgent(agent) + print("Agent registered") + mainloop = GLib.MainLoop() + + try: + mainloop.run() + except KeyboardInterrupt: + vcm.UnregisterVoicecallAgent(path) + print("Agent unregistered (interrupt)")