[Spice-devel] [PATCH spice-server 17/28] red_worker: support SPICE_MSGC_DISPLAY_STREAM_REPORT

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


update mjpeg_encoder with reports from the client about
the playback quality.
---
 server/red_dispatcher.c |  1 +
 server/red_worker.c     | 86 +++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 97e9737..e054b5a 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -1143,6 +1143,7 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
         red_channel_register_client_cbs(display_channel, &client_cbs);
         red_channel_set_data(display_channel, red_dispatcher);
         red_channel_set_cap(display_channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
+        red_channel_set_cap(display_channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
         reds_register_channel(display_channel);
     }
 
diff --git a/server/red_worker.c b/server/red_worker.c
index 470ad7a..23f9ca5 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -117,6 +117,9 @@
 #define RED_STREAM_MIN_SIZE (96 * 96)
 #define RED_STREAM_INPUT_FPS_TIMEOUT (5 * 1000) // 5 sec
 #define RED_STREAM_CHANNEL_CAPACITY 0.8
+/* the client's stream report frequency the minimum of the 2 values bellow */
+#define RED_STREAM_CLIENT_REPORT_WINDOW 5 // #frames
+#define RED_STREAM_CLIENT_REPORT_TIMEOUT 1000 // milliseconds
 
 #define FPS_TEST_INTERVAL 1
 #define MAX_FPS 30
@@ -292,6 +295,7 @@ enum {
     PIPE_ITEM_TYPE_CREATE_SURFACE,
     PIPE_ITEM_TYPE_DESTROY_SURFACE,
     PIPE_ITEM_TYPE_MONITORS_CONFIG,
+    PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT,
 };
 
 typedef struct VerbItem {
@@ -351,6 +355,11 @@ typedef struct MonitorsConfigItem {
     MonitorsConfig *monitors_config;
 } MonitorsConfigItem;
 
+typedef struct StreamActivateReportItem {
+    PipeItem pipe_item;
+    uint32_t stream_id;
+} StreamActivateReportItem;
+
 typedef struct CursorItem {
     uint32_t group_id;
     int refs;
@@ -459,6 +468,8 @@ typedef struct StreamAgent {
     int frames;
     int drops;
     int fps;
+
+    uint32_t report_id;
 } StreamAgent;
 
 typedef struct StreamClipItem {
@@ -2917,6 +2928,17 @@ static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
         agent->mjpeg_encoder = mjpeg_encoder_new(FALSE, 0, NULL, NULL);
     }
     red_channel_client_pipe_add(&dcc->common.base, &agent->create_item);
+
+    if (red_channel_client_test_remote_cap(&dcc->common.base, SPICE_DISPLAY_CAP_STREAM_REPORT)) {
+        StreamActivateReportItem *report_pipe_item = spice_malloc0(sizeof(*report_pipe_item));
+
+        agent->report_id = rand();
+        red_channel_pipe_item_init(dcc->common.base.channel, &report_pipe_item->pipe_item,
+                                   PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
+        report_pipe_item->stream_id = get_stream_id(dcc->common.worker, stream);
+        red_channel_client_pipe_add(&dcc->common.base, &report_pipe_item->pipe_item);
+    }
+
 }
 
 static void red_stream_input_fps_timer_cb(void *opaque)
@@ -3007,7 +3029,8 @@ static void red_display_client_init_streams(DisplayChannelClient *dcc)
         red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
         red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
     }
-    dcc->use_mjpeg_encoder_rate_control = TRUE;
+    dcc->use_mjpeg_encoder_rate_control =
+        red_channel_client_test_remote_cap(&dcc->common.base, SPICE_DISPLAY_CAP_STREAM_REPORT);
 }
 
 static void red_display_destroy_streams(DisplayChannelClient *dcc)
@@ -8999,6 +9022,22 @@ static void red_marshall_monitors_config(RedChannelClient *rcc, SpiceMarshaller
     free(msg);
 }
 
+static void red_marshall_stream_activate_report(RedChannelClient *rcc,
+                                                SpiceMarshaller *base_marshaller,
+                                                uint32_t stream_id)
+{
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    StreamAgent *agent = &dcc->stream_agents[stream_id];
+    SpiceMsgDisplayStreamActivateReport msg;
+
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT, NULL);
+    msg.stream_id = stream_id;
+    msg.unique_id = agent->report_id;
+    msg.max_window_size = RED_STREAM_CLIENT_REPORT_WINDOW;
+    msg.timeout_ms = RED_STREAM_CLIENT_REPORT_TIMEOUT;
+    spice_marshall_msg_display_stream_activate_report(base_marshaller, &msg);
+}
+
 static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
 {
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
@@ -9069,6 +9108,13 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
         red_marshall_monitors_config(rcc, m, monconf_item->monitors_config);
         break;
     }
+    case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT: {
+        StreamActivateReportItem *report_item = SPICE_CONTAINEROF(pipe_item,
+                                                                  StreamActivateReportItem,
+                                                                  pipe_item);
+        red_marshall_stream_activate_report(rcc, m, report_item->stream_id);
+        break;
+    }
     default:
         spice_error("invalid pipe item type");
     }
@@ -9986,6 +10032,37 @@ static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t s
     return TRUE;
 }
 
+static int display_channel_handle_stream_report(DisplayChannelClient *dcc,
+                                                SpiceMsgcDisplayStreamReport *stream_report)
+{
+    StreamAgent *stream_agent;
+
+    if (stream_report->stream_id >= NUM_STREAMS) {
+        spice_warning("stream_report: invalid stream id %u", stream_report->stream_id);
+        return FALSE;
+    }
+    stream_agent = &dcc->stream_agents[stream_report->stream_id];
+    if (!stream_agent->mjpeg_encoder) {
+        spice_info("stream_report: no encoder for stream id %u."
+                    "Probably the stream has been destroyed", stream_report->stream_id);
+        return TRUE;
+    }
+
+    if (stream_report->unique_id != stream_agent->report_id) {
+        spice_warning("local reoprt-id (%u) != msg report-id (%u)",
+                      stream_agent->report_id, stream_report->unique_id);
+        return TRUE;
+    }
+    mjpeg_encoder_client_stream_report(stream_agent->mjpeg_encoder,
+                                       stream_report->num_frames,
+                                       stream_report->num_drops,
+                                       stream_report->start_frame_mm_time,
+                                       stream_report->end_frame_mm_time,
+                                       stream_report->last_frame_delay,
+                                       stream_report->audio_delay);
+    return TRUE;
+}
+
 static int display_channel_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type,
                                           void *message)
 {
@@ -9999,6 +10076,9 @@ static int display_channel_handle_message(RedChannelClient *rcc, uint32_t size,
         }
         dcc->expect_init = FALSE;
         return display_channel_init(dcc, (SpiceMsgcDisplayInit *)message);
+    case SPICE_MSGC_DISPLAY_STREAM_REPORT:
+        return display_channel_handle_stream_report(dcc,
+                                                    (SpiceMsgcDisplayStreamReport *)message);
     default:
         return red_channel_client_handle_message(rcc, size, type, message);
     }
@@ -10348,6 +10428,7 @@ static void display_channel_client_release_item_before_push(DisplayChannelClient
     case PIPE_ITEM_TYPE_PIXMAP_SYNC:
     case PIPE_ITEM_TYPE_PIXMAP_RESET:
     case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
+    case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT:
         free(item);
         break;
     default:
@@ -10517,7 +10598,7 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
     spice_info("zlib-over-glz %s", display_channel->enable_zlib_glz_wrap ? "enabled" : "disabled");
 
     guest_set_client_capabilities(worker);
-    
+
     // todo: tune level according to bandwidth
     display_channel->zlib_level = ZLIB_DEFAULT_COMPRESSION_LEVEL;
     red_display_client_init_streams(dcc);
@@ -11885,6 +11966,7 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
     if (!spice_timer_queue_create()) {
         spice_error("failed to create timer queue");
     }
+    srand(time(NULL));
 
     message = RED_WORKER_MESSAGE_READY;
     write_message(worker->channel, &message);
-- 
1.8.1



More information about the Spice-devel mailing list