Commit cb46f83e authored by Rafaël Carré's avatar Rafaël Carré

* #6738 : make history loading faster

general client cleanup / refactor
thread-safe clock updater thread stopping
fix double free on client exit
parent ef005a20
...@@ -250,6 +250,7 @@ sflphone_hung_up (callable_obj_t * c) ...@@ -250,6 +250,7 @@ sflphone_hung_up (callable_obj_t * c)
#if GTK_CHECK_VERSION(2,10,0) #if GTK_CHECK_VERSION(2,10,0)
status_tray_icon_blink (FALSE); status_tray_icon_blink (FALSE);
#endif #endif
stop_call_clock(c); stop_call_clock(c);
calltree_update_clock(); calltree_update_clock();
} }
...@@ -385,9 +386,9 @@ void sflphone_fill_ip2ip_profile (void) ...@@ -385,9 +386,9 @@ void sflphone_fill_ip2ip_profile (void)
ip2ip_profile = (GHashTable *) dbus_get_ip2_ip_details(); ip2ip_profile = (GHashTable *) dbus_get_ip2_ip_details();
} }
void sflphone_get_ip2ip_properties (GHashTable **properties) GHashTable *sflphone_get_ip2ip_properties(void)
{ {
*properties = ip2ip_profile; return ip2ip_profile;
} }
void void
...@@ -416,7 +417,7 @@ sflphone_hang_up() ...@@ -416,7 +417,7 @@ sflphone_hang_up()
dbus_hang_up (selectedCall); dbus_hang_up (selectedCall);
call_remove_all_errors (selectedCall); call_remove_all_errors (selectedCall);
selectedCall->_state = CALL_STATE_DIALING; selectedCall->_state = CALL_STATE_DIALING;
set_timestamp (&selectedCall->_time_stop); time (&selectedCall->_time_stop);
//if ( (im_window_get_nb_tabs() > 1) && selectedCall->_im_widget && //if ( (im_window_get_nb_tabs() > 1) && selectedCall->_im_widget &&
// ! (IM_WIDGET (selectedCall->_im_widget)->containText)) // ! (IM_WIDGET (selectedCall->_im_widget)->containText))
...@@ -440,7 +441,7 @@ sflphone_hang_up() ...@@ -440,7 +441,7 @@ sflphone_hang_up()
case CALL_STATE_TRANSFERT: case CALL_STATE_TRANSFERT:
dbus_hang_up (selectedCall); dbus_hang_up (selectedCall);
call_remove_all_errors (selectedCall); call_remove_all_errors (selectedCall);
set_timestamp (&selectedCall->_time_stop); time (&selectedCall->_time_stop);
break; break;
default: default:
WARN ("Should not happen in sflphone_hang_up()!"); WARN ("Should not happen in sflphone_hang_up()!");
...@@ -453,78 +454,57 @@ sflphone_hang_up() ...@@ -453,78 +454,57 @@ sflphone_hang_up()
calltree_update_call (history, selectedCall, NULL); calltree_update_call (history, selectedCall, NULL);
if (selectedCall)
stop_call_clock (selectedCall);
calltree_update_clock(); calltree_update_clock();
} }
void
sflphone_conference_hang_up()
{
conference_obj_t * selectedConf = calltab_get_selected_conf(current_calls);
if (selectedConf) {
dbus_hang_up_conference (selectedConf);
}
}
void void
sflphone_pick_up() sflphone_pick_up()
{ {
callable_obj_t * selectedCall = NULL; callable_obj_t *selectedCall = calltab_get_selected_call (active_calltree);
selectedCall = calltab_get_selected_call (active_calltree);
DEBUG("SFLphone: Pick up"); DEBUG("SFLphone: Pick up");
if (selectedCall) { if (!selectedCall) {
switch (selectedCall->_state) { sflphone_new_call();
case CALL_STATE_DIALING: return;
sflphone_place_call (selectedCall); }
switch (selectedCall->_state) {
case CALL_STATE_DIALING:
sflphone_place_call (selectedCall);
// if instant messaging window is visible, create new tab (deleted automatically if not used) // if instant messaging window is visible, create new tab (deleted automatically if not used)
if (im_window_is_visible()) if (im_window_is_visible())
im_widget_display ( (IMWidget **) (&selectedCall->_im_widget), NULL, selectedCall->_callID, NULL); im_widget_display ( (IMWidget **) (&selectedCall->_im_widget), NULL, selectedCall->_callID, NULL);
break; break;
case CALL_STATE_INCOMING: case CALL_STATE_INCOMING:
selectedCall->_history_state = INCOMING; selectedCall->_history_state = INCOMING;
calltree_update_call (history, selectedCall, NULL); calltree_update_call (history, selectedCall, NULL);
// if instant messaging window is visible, create new tab (deleted automatically if not used) // if instant messaging window is visible, create new tab (deleted automatically if not used)
if (selectedCall->_im_widget && im_window_is_visible()) { if (selectedCall->_im_widget && im_window_is_visible()) {
im_widget_display ( (IMWidget **) (&selectedCall->_im_widget), NULL, selectedCall->_callID, NULL); im_widget_display ( (IMWidget **) (&selectedCall->_im_widget), NULL, selectedCall->_callID, NULL);
} }
dbus_accept (selectedCall); dbus_accept (selectedCall);
stop_notification(); stop_notification();
break; break;
case CALL_STATE_HOLD: case CALL_STATE_TRANSFERT:
sflphone_new_call(); dbus_transfert (selectedCall);
break; time (&selectedCall->_time_stop);
case CALL_STATE_TRANSFERT: calltree_remove_call(current_calls, selectedCall, NULL);
dbus_transfert (selectedCall); calllist_remove_call(current_calls, selectedCall->_callID);
set_timestamp (&selectedCall->_time_stop); break;
calltree_remove_call(current_calls, selectedCall, NULL); case CALL_STATE_CURRENT:
calllist_remove_call(current_calls, selectedCall->_callID); case CALL_STATE_HOLD:
break; case CALL_STATE_RECORD:
case CALL_STATE_CURRENT: case CALL_STATE_RINGING:
case CALL_STATE_RECORD: sflphone_new_call();
sflphone_new_call(); break;
break; default:
case CALL_STATE_RINGING: WARN ("Should not happen in sflphone_pick_up()!");
sflphone_new_call(); break;
break;
default:
WARN ("Should not happen in sflphone_pick_up()!");
break;
}
} else {
sflphone_new_call();
} }
} }
void void
...@@ -597,7 +577,7 @@ sflphone_current (callable_obj_t * c) ...@@ -597,7 +577,7 @@ sflphone_current (callable_obj_t * c)
{ {
if (c->_state != CALL_STATE_HOLD) if (c->_state != CALL_STATE_HOLD)
set_timestamp (&c->_time_start); time (&c->_time_start);
c->_state = CALL_STATE_CURRENT; c->_state = CALL_STATE_CURRENT;
calltree_update_call (current_calls, c, NULL); calltree_update_call (current_calls, c, NULL);
...@@ -608,7 +588,7 @@ void ...@@ -608,7 +588,7 @@ void
sflphone_record (callable_obj_t * c) sflphone_record (callable_obj_t * c)
{ {
if (c->_state != CALL_STATE_HOLD) if (c->_state != CALL_STATE_HOLD)
set_timestamp (&c->_time_start); time (&c->_time_start);
c->_state = CALL_STATE_RECORD; c->_state = CALL_STATE_RECORD;
calltree_update_call (current_calls, c, NULL); calltree_update_call (current_calls, c, NULL);
...@@ -804,7 +784,7 @@ sflphone_keypad (guint keyval, gchar * key) ...@@ -804,7 +784,7 @@ sflphone_keypad (guint keyval, gchar * key)
switch (keyval) { switch (keyval) {
case 65307: /* ESCAPE */ case 65307: /* ESCAPE */
dbus_hang_up (c); dbus_hang_up (c);
set_timestamp (&c->_time_stop); time (&c->_time_stop);
calltree_update_call (history, c, NULL); calltree_update_call (history, c, NULL);
break; break;
default: default:
...@@ -839,7 +819,7 @@ sflphone_keypad (guint keyval, gchar * key) ...@@ -839,7 +819,7 @@ sflphone_keypad (guint keyval, gchar * key)
case 65293: /* ENTER */ case 65293: /* ENTER */
case 65421: /* ENTER numpad */ case 65421: /* ENTER numpad */
dbus_transfert (c); dbus_transfert (c);
set_timestamp (&c->_time_stop); time (&c->_time_stop);
calltree_remove_call(current_calls, c, NULL); calltree_remove_call(current_calls, c, NULL);
calllist_remove_call(current_calls, c->_callID); calllist_remove_call(current_calls, c->_callID);
break; break;
...@@ -1066,7 +1046,7 @@ sflphone_add_participant (const gchar* callID, const gchar* confID) ...@@ -1066,7 +1046,7 @@ sflphone_add_participant (const gchar* callID, const gchar* confID)
return; return;
} }
set_timestamp(&call->_time_added); time(&call->_time_added);
iter = calltree_get_gtkiter_from_id(history, (gchar *)confID); iter = calltree_get_gtkiter_from_id(history, (gchar *)confID);
...@@ -1397,7 +1377,7 @@ void sflphone_save_history (void) ...@@ -1397,7 +1377,7 @@ void sflphone_save_history (void)
ERROR("SFLphone: Error: Unknown type for serialization"); ERROR("SFLphone: Error: Unknown type for serialization");
break; break;
} }
gchar *key = convert_timestamp_to_gchar (current->elem.call->_time_start); gchar *key = g_strdup_printf ("%i", (int) current->elem.call->_time_start);
g_hash_table_replace (result, (gpointer) key, g_hash_table_replace (result, (gpointer) key,
g_slist_append(g_hash_table_lookup(result, key),(gpointer) value)); g_slist_append(g_hash_table_lookup(result, key),(gpointer) value));
...@@ -1412,7 +1392,7 @@ void sflphone_save_history (void) ...@@ -1412,7 +1392,7 @@ void sflphone_save_history (void)
} }
gchar *value = serialize_history_conference_entry(conf); gchar *value = serialize_history_conference_entry(conf);
gchar *key = convert_timestamp_to_gchar(conf->_time_start); gchar *key = g_strdup_printf ("%i", (int) conf->_time_start);
g_hash_table_replace(result, (gpointer) key, g_hash_table_replace(result, (gpointer) key,
g_slist_append(g_hash_table_lookup(result, key), (gpointer) value)); g_slist_append(g_hash_table_lookup(result, key), (gpointer) value));
...@@ -1427,7 +1407,6 @@ void sflphone_save_history (void) ...@@ -1427,7 +1407,6 @@ void sflphone_save_history (void)
void void
sflphone_srtp_sdes_on (callable_obj_t * c) sflphone_srtp_sdes_on (callable_obj_t * c)
{ {
c->_srtp_state = SRTP_STATE_SDES_SUCCESS; c->_srtp_state = SRTP_STATE_SDES_SUCCESS;
calltree_update_call (current_calls, c, NULL); calltree_update_call (current_calls, c, NULL);
......
...@@ -172,7 +172,7 @@ void sflphone_fill_ip2ip_profile (void); ...@@ -172,7 +172,7 @@ void sflphone_fill_ip2ip_profile (void);
* @return The internal hash table representing * @return The internal hash table representing
* the settings for the ip2ip profile. * the settings for the ip2ip profile.
*/ */
void sflphone_get_ip2ip_properties (GHashTable **properties); GHashTable *sflphone_get_ip2ip_properties(void);
/** /**
* Initialize the accounts data structure * Initialize the accounts data structure
...@@ -314,6 +314,4 @@ void sflphone_fill_conference_list (void); ...@@ -314,6 +314,4 @@ void sflphone_fill_conference_list (void);
void sflphone_conference_on_hold (const conference_obj_t * c); void sflphone_conference_on_hold (const conference_obj_t * c);
void sflphone_conference_hang_up();
#endif #endif
...@@ -33,67 +33,61 @@ ...@@ -33,67 +33,61 @@
#include <sflphone_const.h> #include <sflphone_const.h>
#include <time.h> #include <time.h>
#include "contacts/calltree.h" #include "contacts/calltree.h"
#include <unistd.h> #include <unistd.h>
#include <assert.h>
gint get_state_callstruct (gconstpointer a, gconstpointer b) gint get_state_callstruct (gconstpointer a, gconstpointer b)
{ {
callable_obj_t * c = (callable_obj_t*) a; callable_obj_t * c = (callable_obj_t*) a;
call_state_t state = *((call_state_t*)b);
if (c->_state == * ( (call_state_t*) b)) { return c->_state == state ? 0 : 1;
return 0;
} else {
return 1;
}
} }
gchar* call_get_peer_name (const gchar *format) gchar* call_get_peer_name (const gchar *format)
{ {
const gchar *end, *name; const gchar *end = g_strrstr (format, "<");
return g_strndup (format, end ? end - format : 0);
DEBUG (" callable_obj: %s", format);
end = g_strrstr (format, "<");
if (!end) {
return g_strndup (format, 0);
} else {
name = format;
return g_strndup (name, end - name);
}
} }
gchar* call_get_peer_number (const gchar *format) gchar* call_get_peer_number (const gchar *format)
{ {
DEBUG (" callable_obj: %s", format); gchar *number = g_strrstr (format, "<") + 1;
gchar *end = g_strrstr (format, ">");
gchar * number = g_strrstr (format, "<") + 1;
gchar * end = g_strrstr (format, ">");
if (end && number) if (end && number)
number = g_strndup (number, end - number); return g_strndup (number, end - number);
else else
number = g_strdup (format); return g_strdup (format);
return number;
} }
gchar* call_get_audio_codec (callable_obj_t *obj) gchar* call_get_audio_codec (callable_obj_t *obj)
{ {
if (obj) { gchar *ret = NULL;
gchar * const audio_codec = dbus_get_current_audio_codec_name (obj); gchar *audio_codec = NULL;
account_t *acc = account_list_get_by_id(obj->_accountID); if (!obj)
if (acc) { goto out;
const codec_t * const codec = codec_list_get_by_name (audio_codec, acc->codecs);
if (codec) { audio_codec = dbus_get_current_audio_codec_name (obj);
gchar *result = g_markup_printf_escaped ("%s/%i", audio_codec, codec->sample_rate); if (!audio_codec)
g_free (audio_codec); goto out;
return result;
} account_t *acc = account_list_get_by_id(obj->_accountID);
} if (!acc)
} goto out;
return g_strdup(""); const codec_t *const codec = codec_list_get_by_name (audio_codec, acc->codecs);
if (!codec)
goto out;
ret = g_strdup_printf("%s/%i", audio_codec, codec->sample_rate);
out:
g_free(audio_codec);
if (ret == NULL)
return g_strdup("");
return ret;
} }
void call_add_error (callable_obj_t * call, gpointer dialog) void call_add_error (callable_obj_t * call, gpointer dialog)
...@@ -111,44 +105,16 @@ void call_remove_all_errors (callable_obj_t * call) ...@@ -111,44 +105,16 @@ void call_remove_all_errors (callable_obj_t * call)
g_ptr_array_foreach (call->_error_dialogs, (GFunc) gtk_widget_destroy, NULL); g_ptr_array_foreach (call->_error_dialogs, (GFunc) gtk_widget_destroy, NULL);
} }
void threaded_clock_incrementer (void *pc) static void threaded_clock_incrementer (void *pc)
{ {
callable_obj_t *call = (callable_obj_t *) pc; callable_obj_t *call = (callable_obj_t *) pc;
for(;;) {
while (call->clockStarted) {
int duration;
time_t start, current;
gdk_threads_enter (); gdk_threads_enter ();
set_timestamp (& (call->_time_current)); int duration = difftime (time(NULL), call->_time_start);
start = call->_time_start;
current = call->_time_current;
if (current == start) {
g_snprintf (call->_timestr, 20, "00:00");
}
duration = (int) difftime (current, start); g_snprintf (call->_timestr, 20, "%.2d:%.2d", duration % 60, duration / 60);
if (duration / 60 == 0) {
if (duration < 10) {
g_snprintf (call->_timestr, 20, "00:0%d", duration);
} else {
g_snprintf (call->_timestr, 20, "00:%d", duration);
}
} else {
if (duration%60 < 10) {
g_snprintf (call->_timestr, 20, "0%d:0%d", duration/60, duration%60);
} else {
g_snprintf (call->_timestr, 20, "%d:%d", duration/60, duration%60);
}
}
// Update clock only if call is active (current, hold, recording transfer) // Update clock only if call is active (current, hold, recording transfer)
if ( (call->_state != CALL_STATE_INVALID) && if ( (call->_state != CALL_STATE_INVALID) &&
...@@ -160,23 +126,37 @@ void threaded_clock_incrementer (void *pc) ...@@ -160,23 +126,37 @@ void threaded_clock_incrementer (void *pc)
calltree_update_clock(); calltree_update_clock();
} }
// gdk_flush();
gdk_threads_leave (); gdk_threads_leave ();
GTimeVal abs_time;
g_get_current_time(&abs_time);
g_time_val_add(&abs_time, 1000000);
g_mutex_lock(call->mutex);
g_cond_timed_wait(call->cond, call->mutex, &abs_time);
gboolean ret = call->exitClockThread;
g_mutex_unlock(call->mutex);
usleep (1000000); if (ret == TRUE)
break;
} }
DEBUG ("CallableObj: Stopping Thread");
g_thread_exit (NULL); g_thread_exit (NULL);
} }
void stop_call_clock (callable_obj_t *c) void stop_call_clock (callable_obj_t *c)
{ {
if (c->_type == CALL && c->clockStarted) assert(c->_type == CALL);
c->clockStarted = 0;
g_mutex_lock(c->mutex);
c->exitClockThread = TRUE;
g_cond_signal(c->cond);
g_mutex_unlock(c->mutex);
g_thread_join(c->clock_thread);
g_mutex_free(c->mutex);
g_cond_free(c->cond);
c->clock_thread = NULL;
} }
callable_obj_t *create_new_call (callable_type_t type, call_state_t state, callable_obj_t *create_new_call (callable_type_t type, call_state_t state,
...@@ -187,41 +167,26 @@ callable_obj_t *create_new_call (callable_type_t type, call_state_t state, ...@@ -187,41 +167,26 @@ callable_obj_t *create_new_call (callable_type_t type, call_state_t state,
{ {
DEBUG ("CallableObj: Create new call (Account: %s)", accountID); DEBUG ("CallableObj: Create new call (Account: %s)", accountID);
// Allocate memory
callable_obj_t *obj = g_new0 (callable_obj_t, 1); callable_obj_t *obj = g_new0 (callable_obj_t, 1);
obj->_error_dialogs = g_ptr_array_new(); obj->_error_dialogs = g_ptr_array_new();
// Set fields
obj->_type = type; obj->_type = type;
obj->_state = state; obj->_state = state;
obj->_callID = *callID ? g_strdup (callID) : g_strdup_printf("%d", rand());
if (g_strcasecmp (callID, "") == 0)
{
obj->_callID = g_new0 (gchar, 30);
if (obj->_callID)
g_sprintf (obj->_callID, "%d", rand());
}
else
obj->_callID = g_strdup (callID);
obj->_accountID = g_strdup (accountID); obj->_accountID = g_strdup (accountID);
set_timestamp (& (obj->_time_start)); time (&obj->_time_start);
set_timestamp (& (obj->_time_current)); time (&obj->_time_stop);
set_timestamp (& (obj->_time_stop));
obj->_peer_name = g_strdup (peer_name); obj->_peer_name = g_strdup (peer_name);
obj->_peer_number = g_strdup (peer_number); obj->_peer_number = g_strdup (peer_number);
obj->_peer_info = get_peer_info (peer_name, peer_number); obj->_peer_info = get_peer_info (peer_name, peer_number);
obj->clockStarted = 1;
if (obj->_type == CALL) { if (obj->_type == CALL) {
GError *err1 = NULL ; obj->mutex = g_mutex_new();
if (!g_thread_create ( (GThreadFunc) threaded_clock_incrementer, (void *) obj, TRUE, &err1)) { obj->cond = g_cond_new();
DEBUG ("Thread creation failed!"); obj->exitClockThread = FALSE;
g_error_free (err1) ; obj->clock_thread = g_thread_create((GThreadFunc) threaded_clock_incrementer, (void *) obj, TRUE, NULL);
}
} }
return obj; return obj;
...@@ -238,23 +203,21 @@ callable_obj_t *create_new_call_from_details (const gchar *call_id, GHashTable * ...@@ -238,23 +203,21 @@ callable_obj_t *create_new_call_from_details (const gchar *call_id, GHashTable *
if (g_strcasecmp (state_str, "CURRENT") == 0) if (g_strcasecmp (state_str, "CURRENT") == 0)
state = CALL_STATE_CURRENT; state = CALL_STATE_CURRENT;
else if (g_strcasecmp (state_str, "RINGING") == 0) else if (g_strcasecmp (state_str, "RINGING") == 0)
state = CALL_STATE_RINGING; state = CALL_STATE_RINGING;
else if (g_strcasecmp (state_str, "INCOMING") == 0) else if (g_strcasecmp (state_str, "INCOMING") == 0)
state = CALL_STATE_INCOMING; state = CALL_STATE_INCOMING