Call Counters
cover Call Counters
Here a proposal for call counters implementation for keeping track of the total incoming and outgoing call duration counters. Each established call instance is contributing to either of the call duration counters. The 2 counters are updated periodically when there is an established call and the information is stored in a file. The bookkeeping of the call duration counters are per IMSI number.
The implementation makes use of the history framework which had to be expanded with a function for marking the beginning of a voice call. There is a D-Bus interface to call counters for reading and clearing the counters.
Andras Domokos (5):
history: expand history API include file
history: expand history API
voicecall: take into use the new history function
voicecall: add call counters
Makefile: add call counters to the build
Makefile.am | 3 + include/history.h | 3 + src/callcounters.c | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/history.c | 24 ++++ src/ofono.h | 4 + src/voicecall.c | 3 + 6 files changed, 425 insertions(+), 0 deletions(-) create mode 100644 src/callcounters.c
RFC PATCH 1/5 history: expand history API include file
--- include/history.h | 3 +++ src/ofono.h | 4 ++++ 2 files changed, 7 insertions(+), 0 deletions(-)
include/history.h +3 -0
@@ -49,6 +49,9 @@ struct ofono_history_driver {const char *name;int (*probe)(struct ofono_history_context *context);void (*remove)(struct ofono_history_context *context); +void (*call_started)(struct ofono_history_context *context, +const struct ofono_call *call, +time_t start);void (*call_ended)(struct ofono_history_context *context,const struct ofono_call *call,time_t start,time_t end);
src/ofono.h +4 -0
@@ -368,6 +368,10 @@ void __ofono_netreg_set_base_station_name(struct ofono_netreg *netreg,void __ofono_history_probe_drivers (struct ofono_modem *modem); +void __ofono_history_call_started (struct ofono_modem *modem, +const struct ofono_call *call, +time_t start); +void __ofono_history_call_ended (struct ofono_modem *modem,const struct ofono_call *call,time_t start,time_t end);
Signature · 1 line
1.7.0.4
RFC PATCH 2/5 history: expand history API
In reply to Andras Domokos--- src/history.c | 24 ++++++++++++++++++++++++ 1 files changed, 24 insertions(+), 0 deletions(-)
src/history.c +24 -0
@@ -114,6 +114,30 @@ void __ofono_history_probe_drivers(struct ofono_modem *modem) } } +static void history_call_started (struct ofono_atom *atom,void *data) +{ +struct ofono_history_context *context =__ofono_atom_get_data (atom); +struct history_call_foreach_data *hfd = data; + +if (context->driver->call_started ==NULL ) +return ; + + context->driver->call_started (context, hfd->call, hfd->start); +} + +void __ofono_history_call_started (struct ofono_modem *modem, +const struct ofono_call *call, +time_t start) +{ +struct history_call_foreach_data hfd; + + hfd.call = call; + hfd.start = start; + +__ofono_modem_foreach_atom (modem,OFONO_ATOM_TYPE_HISTORY , + history_call_started, &hfd); +} +static void history_call_ended (struct ofono_atom *atom,void *data) {struct ofono_history_context *context =__ofono_atom_get_data (atom);
Signature · 1 line
1.7.0.4
RFC PATCH 3/5 voicecall: take into use the new history function
In reply to Andras Domokos--- src/voicecall.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
src/voicecall.c +3 -0
@@ -630,6 +630,7 @@ static void voicecall_emit_multiparty(struct voicecall *call, gboolean mpty)static void voicecall_set_call_status (struct voicecall *call,int status) { +struct ofono_modem *modem =__ofono_atom_get_modem (call->vc->atom);DBusConnection *conn =ofono_dbus_get_connection ();const char *path;const char *status_str;
@@ -658,6 +659,8 @@ static void voicecall_set_call_status(struct voicecall *call, int status)const char *timestr; call->start_time =time (NULL ); +__ofono_history_call_started (modem, call->call, + call->start_time); timestr =time_to_str (&call->start_time); ofono_dbus_signal_property_changed(conn, path,
Signature · 1 line
1.7.0.4
RFC PATCH 4/5 voicecall: add call counters
In reply to Andras Domokos--- src/callcounters.c | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 388 insertions(+), 0 deletions(-) create mode 100644 src/callcounters.c
src/callcounters.c new file +388 -0
@@ -0,0 +1,388 @@ +/* +* +* oFono - Open Source Telephony +* +* Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). +* +* 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 +* +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <time.h> +#include <glib.h> +#include <gdbus.h> + +#include "ofono.h" + +#include "common.h" +#include "storage.h" + +#define CC_TIMEOUT 10000 +#define CC_STORE "callcounters" +#define CC_GROUP "CallCounters" +#define CC_INTERFACE "org.ofono.CallCounters" + +struct call_item { +unsigned int id; +int dir; +time_t start_time; +}; + +struct call_counters { +struct ofono_history_context *context; +const char *imsi; +GKeyFile *file; +time_t ibase; +time_t obase; +time_t incoming; +time_t outgoing; +gint timeout_source; +GSList *calls; +}; + +static time_t cc_time () +{ +struct timespec now; + +clock_gettime (CLOCK_MONOTONIC , &now); + +return now.tv_sec; +} + +static gboolean cc_no_calls (struct call_counters *cc) +{ +return cc->calls ==NULL ; +} + +static struct call_item *cc_find_ci (struct call_counters *cc,unsigned int id) +{ +struct call_item *ci; +GSList *l; + +for (l = cc->calls; l; l = l->next) { + ci = l->data; +if (ci->id == id) +return ci; + } + +return NULL ; +} + +static void cc_load (struct call_counters *cc) +{ +struct ofono_modem *modem = cc->context->modem; +struct ofono_atom *atom; +struct ofono_sim *sim; +GError *error1 =NULL , *error2 =NULL ; + + cc->incoming = cc->ibase =0 ; + cc->outgoing = cc->obase =0 ; + + atom =__ofono_modem_find_atom (modem,OFONO_ATOM_TYPE_SIM ); + sim =__ofono_atom_get_data (atom); + + cc->imsi =ofono_sim_get_imsi (sim); +if (cc->imsi ==NULL ) +return ; + + cc->file =storage_open (cc->imsi,CC_STORE ); +if (cc->file ==NULL ) +return ; + + cc->incoming =g_key_file_get_integer (cc->file,CC_GROUP , +"Incoming" , &error1); + +if (error1) { +g_key_file_set_integer (cc->file,CC_GROUP , +"Incoming" , cc->incoming); +storage_sync (cc->imsi,CC_STORE , cc->file); + } + + cc->ibase = cc->incoming; + + cc->outgoing =g_key_file_get_integer (cc->file,CC_GROUP , +"Outgoing" , &error2); + +if (error2) { +g_key_file_set_integer (cc->file,CC_GROUP , +"Outgoing" , cc->outgoing); + } + + cc->obase = cc->outgoing; + +if (error1 !=NULL || error2 !=NULL ) +storage_sync (cc->imsi,CC_STORE , cc->file); +} + +static void cc_save (struct call_counters *cc) +{ +if (cc->file ==NULL ) +return ; + +g_key_file_set_integer (cc->file,CC_GROUP , +"Incoming" , cc->incoming); +g_key_file_set_integer (cc->file,CC_GROUP , +"Outgoing" , cc->outgoing); +storage_sync (cc->imsi,CC_STORE , cc->file); +} + +static void cc_close (struct call_counters *cc) +{ +if (cc->file) +storage_close (cc->imsi,CC_STORE , cc->file, TRUE); + + cc->file =NULL ; +} + +static void cc_update (struct call_counters *cc,struct call_item *ci) +{ +time_t now =cc_time (); +time_t idiff =0 , odiff =0 ; +struct call_item *lci; +GSList *l; + +for (l = cc->calls; l; l = l->next) { + lci = l->data; +if (lci->dir ==CALL_DIRECTION_MOBILE_ORIGINATED ) { +if (lci != ci) + odiff += now - lci->start_time; +else + cc->obase += now - lci->start_time; + }else { +if (lci != ci) + idiff += now - lci->start_time; +else + cc->ibase += now - lci->start_time; + } + } + + cc->outgoing = cc->obase + odiff; + cc->incoming = cc->ibase + idiff; + +cc_save (cc); +} + +static gboolean cc_timeout (gpointer user_data) +{ +struct call_counters *cc = user_data; +cc_update (cc,NULL ); +return TRUE; +} + +static DBusMessage *cc_dbus_get (DBusConnection *conn, +DBusMessage *msg,void *data) +{ +struct call_counters *cc = data; +DBusMessage *reply; +DBusMessageIter iter; +DBusMessageIter dict; + +if (cc_no_calls (cc)) { +cc_load (cc); +cc_close (cc); + }else { +cc_update (cc,NULL ); + } + + reply =dbus_message_new_method_return (msg); +if (!reply) +return NULL ; + +dbus_message_iter_init_append (reply, &iter); +dbus_message_iter_open_container (&iter,DBUS_TYPE_ARRAY , +OFONO_PROPERTIES_ARRAY_SIGNATURE , + &dict); +ofono_dbus_dict_append (&dict,"Incoming" ,DBUS_TYPE_UINT32 , + &cc->incoming); +ofono_dbus_dict_append (&dict,"Outgoing" ,DBUS_TYPE_UINT32 , + &cc->outgoing); +dbus_message_iter_close_container (&iter, &dict); + +return reply; +} + +static DBusMessage *cc_dbus_clear (DBusConnection *conn, +DBusMessage *msg,void *data) +{ +struct call_counters *cc = data; +DBusMessage *reply; + +if (cc_no_calls (cc)) { +cc_load (cc); + cc->incoming = cc->ibase =0 ; + cc->outgoing = cc->obase =0 ; +cc_save (cc); +cc_close (cc); + reply =dbus_message_new_method_return (msg); + }else { + reply =__ofono_error_failed (msg); + } + +return reply; +} + +static GDBusMethodTable cc_methods[] = { + {"Get" ,"" ,"a{sv}" , cc_dbus_get}, + {"Clear" ,"" ,"" , cc_dbus_clear}, + { } +}; + +static void cc_dbus_register (struct call_counters *cc) +{ +DBusConnection *conn =ofono_dbus_get_connection (); +const char *path =ofono_modem_get_path (cc->context->modem); + +if (!g_dbus_register_interface (conn, path, +CC_INTERFACE , + cc_methods,NULL ,NULL , + cc,NULL )) { +ofono_error ("Could not create %s interface" ,CC_INTERFACE ); +return ; + } + +ofono_modem_add_interface (cc->context->modem,CC_INTERFACE ); +} + +static gboolean cc_dbus_unregister (struct call_counters *cc) +{ +DBusConnection *conn =ofono_dbus_get_connection (); +const char *path =ofono_modem_get_path (cc->context->modem); + +ofono_modem_remove_interface (cc->context->modem,CC_INTERFACE ); + +return g_dbus_unregister_interface (conn, path,CC_INTERFACE ); +} + +static int cc_probe (struct ofono_history_context *context) +{ +struct call_counters *cc; + +ofono_debug ("Call Counters probe for modem: %p" , context->modem); + + cc = g_try_new0(struct call_counters, 1); +if (cc ==NULL ) +return -1 ; + + context->data = cc; + cc->context = context; +cc_dbus_register (cc); + +return 0 ; +} + +static void cc_remove (struct ofono_history_context *context) +{ +struct call_counters *cc = context->data; + +ofono_debug ("Call Counters remove for modem: %p" , context->modem); + +cc_dbus_unregister (cc); + +if (cc->timeout_source !=0 ) +g_source_remove (cc->timeout_source); + +cc_update (cc,NULL ); +g_slist_free (cc->calls); + +if (cc->file) +storage_close (cc->imsi,CC_STORE , cc->file, TRUE); + +g_free (context->data); +} + +static void cc_call_started (struct ofono_history_context *context, +const struct ofono_call *call,time_t start) +{ +time_t now =cc_time (); +struct call_counters *cc = context->data; +struct call_item *ci; + +ofono_debug ("Call started on modem: %p" , context->modem); + +if (call->type !=0 ) +return ; + + ci = g_try_new0(struct call_item, 1); +if (ci ==NULL ) +return ; + +if (cc_no_calls (cc)) +cc_load (context->data); + + ci->id = call->id; + ci->dir = call->direction; + ci->start_time = now; + cc->calls =g_slist_append (cc->calls, ci); + +if (cc->timeout_source ==0 ) + cc->timeout_source =g_timeout_add (CC_TIMEOUT , cc_timeout, cc); +} + +static void cc_call_ended (struct ofono_history_context *context, +const struct ofono_call *call, +time_t start,time_t end) +{ +struct call_counters *cc = context->data; +struct call_item *ci =cc_find_ci (cc, call->id); + +ofono_debug ("Call ended on modem: %p" , context->modem); + +if (call->type !=0 ) +return ; + +if (ci ==NULL ) +return ; + +cc_update (cc, ci); + cc->calls =g_slist_remove (cc->calls, ci); + +if (cc_no_calls (cc)) { +if (cc->timeout_source !=0 ) +g_source_remove (cc->timeout_source); + + cc->timeout_source =0 ; + +if (cc->file) +storage_close (cc->imsi,CC_STORE , cc->file, TRUE); + + cc->file =NULL ; + } +} + +static struct ofono_history_driver cc_driver = { + .name ="Call Counters" , + .probe = cc_probe, + .remove = cc_remove, + .call_started = cc_call_started, + .call_ended = cc_call_ended, +}; + +static int cc_init (void ) +{ +return ofono_history_driver_register (&cc_driver); +} + +static void cc_exit (void ) +{ +ofono_history_driver_unregister (&cc_driver); +} + +OFONO_PLUGIN_DEFINE (cc,"Call Counters plugin" , +VERSION ,OFONO_PLUGIN_PRIORITY_DEFAULT , + cc_init, cc_exit)
Signature · 1 line
1.7.0.4
RFC PATCH 5/5 Makefile: add call counters to the build
In reply to Andras Domokos--- Makefile.am | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
Makefile.am +3 -0
@@ -295,6 +295,9 @@ builtin_modules += example_nettime builtin_sources += examples/nettime.c endif +builtin_modules += cc +builtin_sources += src/callcounters.c + builtin_modules += smart_messaging builtin_sources += plugins/smart-messaging.c
Signature · 1 line
1.7.0.4
Hi Andras,
Quoted 11 lines
Here a proposal for call counters implementation for keeping track of the total incoming and outgoing call duration counters. Each established call instance is contributing to either of the call duration counters. The 2 counters are updated periodically when there is an established call and the information is stored in a file. The bookkeeping of the call duration counters are per IMSI number.
The implementation makes use of the history framework which had to be expanded with a function for marking the beginning of a voice call. There is a D-Bus interface to call counters for reading and clearing the counters.
and where is the API documentation for such a D-Bus interface?
Regards
Marcel
Re: [RFC PATCH 5/5] Makefile: add call counters to the build
In reply to Andras DomokosHi Andras,
Quoted 8 lines
Makefile.am | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)Makefile.am +0
-0
Makefile.am builtin_modules += example_nettime · line 300
Quoted 6 lines
Makefile.am +3
-0@@ -295,6 +295,9 @@ builtin_modules += example_nettime builtin_sources += examples/nettime.c endif +builtin_modules += cc +builtin_sources += src/callcounters.c +
what is this? Plugins do not belong under src/. That is reserved for oFono core functionality only.
Regards
Marcel
Re: [RFC PATCH 1/5] history: expand history API include file
In reply to Andras DomokosHi Andras,
Quoted 10 lines · Andras Domokos
--- include/history.h | 3 +++ src/ofono.h | 4 ++++ 2 files changed, 7 insertions(+), 0 deletions(-)include/history.h +0
-0
include/history.h struct ofono_history_driver { · line 57
Quoted 9 lines
include/history.h +3
-0@@ -49,6 +49,9 @@ struct ofono_history_driver {const char *name;int (*probe)(struct ofono_history_context *context);void (*remove)(struct ofono_history_context *context); +void (*call_started)(struct ofono_history_context *context, +const struct ofono_call *call, +time_t start);void (*call_ended)(struct ofono_history_context *context,const struct ofono_call *call,time_t start,time_t end);
This belongs in a separate patch.
Quoted 5 lines
src/ofono.h +0
-0
src/ofono.h void __ofono_netreg_set_base_station_name(struct ofono_netreg *netreg, · line 377
Quoted 10 lines
src/ofono.h +4
-0@@ -368,6 +368,10 @@ void __ofono_netreg_set_base_station_name(struct ofono_netreg *netreg,void __ofono_history_probe_drivers (struct ofono_modem *modem); +void __ofono_history_call_started (struct ofono_modem *modem, +const struct ofono_call *call, +time_t start); +void __ofono_history_call_ended (struct ofono_modem *modem,const struct ofono_call *call,time_t start,time_t end);
This one should be grouped together with patch #2.
Regards,
-Denis
Re: [RFC PATCH 4/5] voicecall: add call counters
In reply to Andras DomokosHi Andras,
src/callcounters.c
Quoted 6 lines · Andras Domokos
--- src/callcounters.c | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 388 insertions(+), 0 deletions(-) create mode 100644 src/callcounters.csrc/callcounters.c +0
-0
This patch should go together with Patch 5. It is also missing the API documentation (which could be in a separate patch if you prefer).
This file should also be inside the plugins directory and not src.
Regards,
-Denis