[empathy] Display the file transfer speed and calculate remaining time more dynamically.



commit 063625395264373ce915fac0ac03562527c7bf51
Author: Xavier Claessens <xclaesse gmail com>
Date:   Thu Apr 23 18:54:21 2009 +0200

    Display the file transfer speed and calculate remaining time more dynamically.
---
 libempathy/empathy-tp-file.c |   90 ++++++++++++++++++++++++++++++++++++------
 libempathy/empathy-tp-file.h |    1 +
 src/empathy-ft-manager.c     |   24 +++++++----
 3 files changed, 93 insertions(+), 22 deletions(-)

diff --git a/libempathy/empathy-tp-file.c b/libempathy/empathy-tp-file.c
index 6796f5a..3723f35 100644
--- a/libempathy/empathy-tp-file.c
+++ b/libempathy/empathy-tp-file.c
@@ -69,6 +69,7 @@
 
 #define N_BUFFERS 2
 #define BUFFER_SIZE 4096
+#define STALLED_TIMEOUT 5
 
 typedef struct {
   GInputStream *in;
@@ -298,7 +299,11 @@ struct _EmpathyTpFilePriv {
 
   gboolean incoming;
   TpFileTransferStateChangeReason state_change_reason;
-  time_t start_time;
+  time_t last_update_time;
+  guint64 last_update_transferred_bytes;
+  gdouble speed;
+  gint remaining_time;
+  guint stalled_id;
   GValue *socket_address;
   GCancellable *cancellable;
 };
@@ -317,6 +322,13 @@ enum {
   PROP_CONTENT_HASH,
 };
 
+enum {
+	REFRESH,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
 G_DEFINE_TYPE (EmpathyTpFile, empathy_tp_file, G_TYPE_OBJECT);
 
 static void
@@ -391,9 +403,25 @@ tp_file_finalize (GObject *object)
   if (tp_file->priv->cancellable)
     g_object_unref (tp_file->priv->cancellable);
 
+  if (tp_file->priv->stalled_id != 0)
+    g_source_remove (tp_file->priv->stalled_id);
+
   G_OBJECT_CLASS (empathy_tp_file_parent_class)->finalize (object);
 }
 
+static gboolean
+tp_file_stalled_cb (EmpathyTpFile *tp_file)
+{
+  /* We didn't get transferred bytes update for a while, the transfer is
+   * stalled. */
+
+  tp_file->priv->speed = 0;
+  tp_file->priv->remaining_time = -1;
+  g_signal_emit (tp_file, signals[REFRESH], 0);
+
+  return FALSE;
+}
+
 static void
 tp_file_start_transfer (EmpathyTpFile *tp_file)
 {
@@ -425,7 +453,11 @@ tp_file_start_transfer (EmpathyTpFile *tp_file)
 
   DEBUG ("Start the transfer");
 
-  tp_file->priv->start_time = empathy_time_get_current ();
+  tp_file->priv->last_update_time = empathy_time_get_current ();
+  tp_file->priv->last_update_transferred_bytes = tp_file->priv->transferred_bytes;
+  tp_file->priv->stalled_id = g_timeout_add_seconds (STALLED_TIMEOUT,
+    (GSourceFunc) tp_file_stalled_cb, tp_file);
+
   tp_file->priv->cancellable = g_cancellable_new ();
   if (tp_file->priv->incoming)
     {
@@ -487,12 +519,40 @@ tp_file_transferred_bytes_changed_cb (TpChannel *channel,
                                       GObject *weak_object)
 {
   EmpathyTpFile *tp_file = EMPATHY_TP_FILE (weak_object);
+  time_t curr_time, elapsed_time;
+  guint64 transferred_bytes;
 
+  /* If we didn't progress since last update, return */
   if (tp_file->priv->transferred_bytes == count)
     return;
 
+  /* Update the transferred bytes count */
   tp_file->priv->transferred_bytes = count;
   g_object_notify (G_OBJECT (tp_file), "transferred-bytes");
+
+  /* We got a progress, reset the stalled timeout */
+  if (tp_file->priv->stalled_id != 0)
+    g_source_remove (tp_file->priv->stalled_id);
+  tp_file->priv->stalled_id = g_timeout_add_seconds (STALLED_TIMEOUT,
+    (GSourceFunc) tp_file_stalled_cb, tp_file);
+
+  /* Calculate the transfer speed and remaining time estimation. We recalculate
+   * that each second to get more dynamic values that react faster to network
+   * changes. This is better than calculating the average from the begining of
+   * the transfer, I think. */
+  curr_time = empathy_time_get_current ();
+  elapsed_time = curr_time - tp_file->priv->last_update_time;
+  if (elapsed_time > 1)
+    {
+      transferred_bytes = count - tp_file->priv->last_update_transferred_bytes;
+      tp_file->priv->speed = (gdouble) transferred_bytes / (gdouble) elapsed_time;
+      tp_file->priv->remaining_time = (tp_file->priv->size - count) /
+        tp_file->priv->speed;
+      tp_file->priv->last_update_transferred_bytes = count;
+      tp_file->priv->last_update_time = curr_time;
+
+      g_signal_emit (tp_file, signals[REFRESH], 0);
+    }
 }
 
 static void
@@ -986,10 +1046,6 @@ empathy_tp_file_get_transferred_bytes (EmpathyTpFile *tp_file)
 gint
 empathy_tp_file_get_remaining_time (EmpathyTpFile *tp_file)
 {
-  time_t curr_time, elapsed_time;
-  gdouble time_per_byte;
-  gdouble remaining_time;
-
   g_return_val_if_fail (EMPATHY_IS_TP_FILE (tp_file), -1);
 
   if (tp_file->priv->size == EMPATHY_TP_FILE_UNKNOWN_SIZE)
@@ -998,14 +1054,18 @@ empathy_tp_file_get_remaining_time (EmpathyTpFile *tp_file)
   if (tp_file->priv->transferred_bytes == tp_file->priv->size)
     return 0;
 
-  curr_time = empathy_time_get_current ();
-  elapsed_time = curr_time - tp_file->priv->start_time;
-  time_per_byte = (gdouble) elapsed_time /
-      (gdouble) tp_file->priv->transferred_bytes;
-  remaining_time = time_per_byte * (tp_file->priv->size -
-      tp_file->priv->transferred_bytes);
+  return tp_file->priv->remaining_time;
+}
 
-  return (gint) remaining_time;
+gdouble
+empathy_tp_file_get_speed (EmpathyTpFile *tp_file)
+{
+  g_return_val_if_fail (EMPATHY_IS_TP_FILE (tp_file), 0);
+
+  if (tp_file->priv->transferred_bytes == tp_file->priv->size)
+    return 0;
+
+  return tp_file->priv->speed;
 }
 
 const gchar *
@@ -1144,6 +1204,10 @@ empathy_tp_file_class_init (EmpathyTpFileClass *klass)
           0,
           G_PARAM_READWRITE));
 
+  signals[REFRESH] = g_signal_new ("refresh", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
   g_type_class_add_private (object_class, sizeof (EmpathyTpFilePriv));
 }
 
diff --git a/libempathy/empathy-tp-file.h b/libempathy/empathy-tp-file.h
index 5f239c8..357372f 100644
--- a/libempathy/empathy-tp-file.h
+++ b/libempathy/empathy-tp-file.h
@@ -80,6 +80,7 @@ TpFileTransferState empathy_tp_file_get_state (
 guint64 empathy_tp_file_get_size (EmpathyTpFile *tp_file);
 guint64 empathy_tp_file_get_transferred_bytes (EmpathyTpFile *tp_file);
 gint empathy_tp_file_get_remaining_time (EmpathyTpFile *tp_file);
+gdouble empathy_tp_file_get_speed (EmpathyTpFile *tp_file);
 const gchar *empathy_tp_file_get_content_type (EmpathyTpFile *tp_file);
 gboolean empathy_tp_file_is_ready (EmpathyTpFile *tp_file);
 
diff --git a/src/empathy-ft-manager.c b/src/empathy-ft-manager.c
index 98e58d4..d3d22fb 100644
--- a/src/empathy-ft-manager.c
+++ b/src/empathy-ft-manager.c
@@ -200,6 +200,7 @@ ft_manager_update_ft_row (EmpathyFTManager *ft_manager,
   TpFileTransferState state;
   TpFileTransferStateChangeReason reason;
   gboolean incoming;
+  gdouble speed;
 
   row_ref = ft_manager_get_row_from_tp_file (ft_manager, tp_file);
   g_return_if_fail (row_ref != NULL);
@@ -210,6 +211,7 @@ ft_manager_update_ft_row (EmpathyFTManager *ft_manager,
   total_size = empathy_tp_file_get_size (tp_file);
   state = empathy_tp_file_get_state (tp_file, &reason);
   incoming = empathy_tp_file_is_incoming (tp_file);
+  speed = empathy_tp_file_get_speed (tp_file);
 
   switch (state)
     {
@@ -234,6 +236,7 @@ ft_manager_update_ft_row (EmpathyFTManager *ft_manager,
           {
             gchar *total_size_str;
             gchar *transferred_bytes_str;
+            gchar *speed_str;
 
             if (total_size == EMPATHY_TP_FILE_UNKNOWN_SIZE)
               total_size_str = g_strdup (C_("file size", "Unknown"));
@@ -241,13 +244,15 @@ ft_manager_update_ft_row (EmpathyFTManager *ft_manager,
               total_size_str = g_format_size_for_display (total_size);
 
             transferred_bytes_str = g_format_size_for_display (transferred_bytes);
+            speed_str = g_format_size_for_display (speed);
 
             /* translators: first %s is the transferred size, second %s is
              * the total file size */
-            second_line = g_strdup_printf (_("%s of %s"), transferred_bytes_str,
-                total_size_str);
+            second_line = g_strdup_printf (_("%s of %s at %s/s"),
+                transferred_bytes_str, total_size_str, speed_str);
             g_free (transferred_bytes_str);
             g_free (total_size_str);
+            g_free (speed_str);
 
           }
         else
@@ -301,8 +306,10 @@ ft_manager_update_ft_row (EmpathyFTManager *ft_manager,
 
   if (remaining < 0)
     {
-      if (state != TP_FILE_TRANSFER_STATE_COMPLETED &&
-          state != TP_FILE_TRANSFER_STATE_CANCELLED)
+      if (state == TP_FILE_TRANSFER_STATE_OPEN)
+        remaining_str = g_strdup (C_("remaining time", "Stalled"));      
+      else if (state != TP_FILE_TRANSFER_STATE_COMPLETED &&
+               state != TP_FILE_TRANSFER_STATE_CANCELLED)
         remaining_str = g_strdup (C_("remaining time", "Unknown"));
     }
   else
@@ -334,9 +341,8 @@ ft_manager_update_ft_row (EmpathyFTManager *ft_manager,
 }
 
 static void
-ft_manager_transferred_bytes_changed_cb (EmpathyTpFile *tp_file,
-                                         GParamSpec *pspec,
-                                         EmpathyFTManager *ft_manager)
+ft_manager_refresh_cb (EmpathyTpFile *tp_file,
+                       EmpathyFTManager *ft_manager)
 {
   ft_manager_update_ft_row (ft_manager, tp_file);
 }
@@ -840,8 +846,8 @@ ft_manager_add_tp_file_to_list (EmpathyFTManager *ft_manager,
   ft_manager_update_ft_row (ft_manager, tp_file);
   g_signal_connect (tp_file, "notify::state",
       G_CALLBACK (ft_manager_state_changed_cb), ft_manager);
-  g_signal_connect (tp_file, "notify::transferred-bytes",
-      G_CALLBACK (ft_manager_transferred_bytes_changed_cb), ft_manager);
+  g_signal_connect (tp_file, "refresh",
+      G_CALLBACK (ft_manager_refresh_cb), ft_manager);
 
   gtk_window_present (GTK_WINDOW (ft_manager->priv->window));
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]