[Spice-devel] [PATCH spice-gtk 4/8] channel-display: video stream quality report

Yonit Halperin yhalperi at redhat.com
Tue Feb 26 10:04:54 PST 2013


handle MSG_STREAM_ACTIVIATE_REPORT and send MSGC_STREAM_REPORT
periodically, or when the playback is out of sync.
---
 gtk/channel-display-priv.h |  10 ++++
 gtk/channel-display.c      | 116 ++++++++++++++++++++++++++++++++++++++++-----
 spice-common               |   2 +-
 3 files changed, 114 insertions(+), 14 deletions(-)

diff --git a/gtk/channel-display-priv.h b/gtk/channel-display-priv.h
index f57dc6e..49f82fe 100644
--- a/gtk/channel-display-priv.h
+++ b/gtk/channel-display-priv.h
@@ -88,6 +88,16 @@ typedef struct display_stream {
     GArray               *drops_seqs_stats_arr;
     uint32_t             num_drops_seqs;
 
+    /* playback quality report to server */
+    gboolean report_is_active;
+    uint32_t report_id;
+    uint32_t report_max_window;
+    uint32_t report_timeout;
+    uint64_t report_start_time;
+    uint32_t report_start_frame_time;
+    uint32_t report_num_frames;
+    uint32_t report_num_drops;
+    uint32_t report_drops_seq_len;
 } display_stream;
 
 void stream_get_dimensions(display_stream *st, int *width, int *height);
diff --git a/gtk/channel-display.c b/gtk/channel-display.c
index ab4d3bd..efb9aec 100644
--- a/gtk/channel-display.c
+++ b/gtk/channel-display.c
@@ -687,6 +687,7 @@ static void spice_display_channel_reset_capabilities(SpiceChannel *channel)
     spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_MONITORS_CONFIG);
     spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_COMPOSITE);
     spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_A8_SURFACE);
+    spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_STREAM_REPORT);
 }
 
 static void spice_display_channel_init(SpiceDisplayChannel *channel)
@@ -1238,6 +1239,65 @@ static gboolean display_stream_render(display_stream *st)
     return FALSE;
 }
 
+#define STREAM_REPORT_DROP_SEQ_LEN_LIMIT 3 /* after a sequence of 3 drops, push a report to the server, even
+                                              if the report window is bigger */
+
+static void display_update_stream_report(SpiceDisplayChannel *channel, uint32_t stream_id,
+                                         uint32_t frame_time, int32_t latency)
+{
+    display_stream *st = channel->priv->streams[stream_id];
+    guint64 now;
+
+    if (!st->report_is_active) {
+        return;
+    }
+    now = g_get_monotonic_time();
+
+    if (st->report_num_frames == 0) {
+        st->report_start_frame_time = frame_time;
+        st->report_start_time = now;
+    }
+    st->report_num_frames++;
+
+    if (latency < 0) { // drop
+        st->report_num_drops++;
+        st->report_drops_seq_len++;
+    } else {
+        st->report_drops_seq_len = 0;
+    }
+
+    if (st->report_num_frames >= st->report_max_window ||
+        now - st->report_start_time >= st->report_timeout ||
+        st->report_drops_seq_len >= STREAM_REPORT_DROP_SEQ_LEN_LIMIT) {
+        SpiceMsgcDisplayStreamReport report;
+        SpiceSession *session = spice_channel_get_session(SPICE_CHANNEL(channel));
+        SpiceMsgOut *msg;
+
+        report.stream_id = stream_id;
+        report.unique_id = st->report_id;
+        report.start_frame_mm_time = st->report_start_frame_time;
+        report.end_frame_mm_time = frame_time;
+        report.num_frames = st->report_num_frames;
+        report.num_drops = st-> report_num_drops;
+        report.last_frame_delay = latency;
+        if (spice_session_is_playback_active(session)) {
+            report.audio_delay = spice_session_get_playback_latency(session);
+        } else {
+            report.audio_delay = UINT_MAX;
+        }
+
+        msg = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_DISPLAY_STREAM_REPORT);
+        msg->marshallers->msgc_display_stream_report(msg->marshaller, &report);
+        spice_msg_out_send(msg);
+
+        st->report_start_time = 0;
+        st->report_start_frame_time = 0;
+        st->report_num_frames = 0;
+        st->report_num_drops = 0;
+        st->report_drops_seq_len = 0;
+    }
+}
+
 /* coroutine context */
 static void display_handle_stream_data(SpiceChannel *channel, SpiceMsgIn *in)
 {
@@ -1245,6 +1305,7 @@ static void display_handle_stream_data(SpiceChannel *channel, SpiceMsgIn *in)
     SpiceStreamDataHeader *op = spice_msg_in_parsed(in);
     display_stream *st;
     guint32 mmtime;
+    int32_t latency;
 
     g_return_if_fail(c != NULL);
     g_return_if_fail(c->streams != NULL);
@@ -1266,7 +1327,9 @@ static void display_handle_stream_data(SpiceChannel *channel, SpiceMsgIn *in)
         st->first_frame_mm_time = op->multi_media_time;
     }
     st->num_input_frames++;
-    if (op->multi_media_time < mmtime) {
+
+    latency = op->multi_media_time - mmtime;
+    if (latency < 0) {
         CHANNEL_DEBUG(channel, "stream data too late by %u ms (ts: %u, mmtime: %u), dropin",
                       mmtime - op->multi_media_time, op->multi_media_time, mmtime);
         st->arrive_late_time += mmtime - op->multi_media_time;
@@ -1275,19 +1338,20 @@ static void display_handle_stream_data(SpiceChannel *channel, SpiceMsgIn *in)
             st->cur_drops_seq_stats.start_mm_time = op->multi_media_time;
         }
         st->cur_drops_seq_stats.len++;
-        return;
-    }
-
-    spice_msg_in_ref(in);
-    g_queue_push_tail(st->msgq, in);
-    display_stream_schedule(st);
-    if (st->cur_drops_seq_stats.len) {
-        st->cur_drops_seq_stats.duration = op->multi_media_time -
-                                           st->cur_drops_seq_stats.start_mm_time;
-        g_array_append_val(st->drops_seqs_stats_arr, st->cur_drops_seq_stats);
-        memset(&st->cur_drops_seq_stats, 0, sizeof(st->cur_drops_seq_stats));
-        st->num_drops_seqs++;
+    } else {
+        spice_msg_in_ref(in);
+        g_queue_push_tail(st->msgq, in);
+        display_stream_schedule(st);
+        if (st->cur_drops_seq_stats.len) {
+            st->cur_drops_seq_stats.duration = op->multi_media_time -
+                                               st->cur_drops_seq_stats.start_mm_time;
+            g_array_append_val(st->drops_seqs_stats_arr, st->cur_drops_seq_stats);
+            memset(&st->cur_drops_seq_stats, 0, sizeof(st->cur_drops_seq_stats));
+            st->num_drops_seqs++;
+        }
     }
+    display_update_stream_report(SPICE_DISPLAY_CHANNEL(channel), op->id,
+                                 op->multi_media_time, latency);
 }
 
 /* coroutine context */
@@ -1406,6 +1470,31 @@ static void display_handle_stream_destroy_all(SpiceChannel *channel, SpiceMsgIn
     clear_streams(channel);
 }
 
+/* coroutine context */
+static void display_handle_stream_activate_report(SpiceChannel *channel, SpiceMsgIn *in)
+{
+    SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(channel)->priv;
+    SpiceMsgDisplayStreamActivateReport *op = spice_msg_in_parsed(in);
+    display_stream *st;
+
+    g_return_if_fail(c != NULL);
+    g_return_if_fail(c->streams != NULL);
+    g_return_if_fail(c->nstreams > op->stream_id);
+
+    st = c->streams[op->stream_id];
+    g_return_if_fail(st != NULL);
+
+    st->report_is_active = TRUE;
+    st->report_id = op->unique_id;
+    st->report_max_window = op->max_window_size;
+    st->report_timeout = op->timeout_ms * 1000;
+    st->report_start_time = 0;
+    st->report_start_frame_time = 0;
+    st->report_num_frames = 0;
+    st->report_num_drops = 0;
+    st->report_drops_seq_len = 0;
+}
+
 /* ------------------------------------------------------------------ */
 
 /* coroutine context */
@@ -1627,6 +1716,7 @@ static const spice_msg_handler display_handlers[] = {
     [ SPICE_MSG_DISPLAY_STREAM_DESTROY ]     = display_handle_stream_destroy,
     [ SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL ] = display_handle_stream_destroy_all,
     [ SPICE_MSG_DISPLAY_STREAM_DATA_SIZED ]  = display_handle_stream_data,
+    [ SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT ] = display_handle_stream_activate_report,
 
     [ SPICE_MSG_DISPLAY_DRAW_FILL ]          = display_handle_draw_fill,
     [ SPICE_MSG_DISPLAY_DRAW_OPAQUE ]        = display_handle_draw_opaque,
diff --git a/spice-common b/spice-common
index 149bb89..09f88f4 160000
--- a/spice-common
+++ b/spice-common
@@ -1 +1 @@
-Subproject commit 149bb89adb0d7676c41085b3e41f07113e05c880
+Subproject commit 09f88f4a688a156b48c2058dac7a8c0f35e96abd
-- 
1.8.1



More information about the Spice-devel mailing list