Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
40 changes: 40 additions & 0 deletions doc/voicecallmanager-api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
15 changes: 15 additions & 0 deletions drivers/rilmodem/voicecall.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand Down
14 changes: 14 additions & 0 deletions gril/grilunsol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

2 changes: 2 additions & 0 deletions gril/grilunsol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions include/voicecall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/ofono.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<allow send_interface="org.ofono.PushNotificationAgent"/>
<allow send_interface="org.ofono.SmartMessagingAgent"/>
<allow send_interface="org.ofono.PositioningRequestAgent"/>
<allow send_interface="org.ofono.VoiceCallAgent"/>
</policy>

<policy at_console="true">
Expand Down
80 changes: 80 additions & 0 deletions src/voicecall.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -38,6 +39,7 @@
#include "simutil.h"
#include "smsutil.h"
#include "storage.h"
#include "voicecallagent.h"

#define MAX_VOICE_CALLS 16

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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}" }),
Expand Down Expand Up @@ -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) },
{ }
};

Expand Down Expand Up @@ -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;
Expand Down
133 changes: 133 additions & 0 deletions src/voicecallagent.c
Original file line number Diff line number Diff line change
@@ -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 <glib.h>
#include <gdbus.h>

#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;
}
Loading