[Spice-devel] [PATCH spice-server 22/28] reds: support mm_time latency adjustments

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


When there is no audio playback, we set the mm_time in the client to be older
than the one in the server by at least the requested latency (the delta is
actually bigger, due to the network latency).
When there is an audio playback, we adjust the mm_time in the client by
adjusting the playback buffer using SPICE_MSG_PLAYBACK_LATENCY.
---
 server/main_dispatcher.c | 32 ++++++++++++++++++++++++++++++++
 server/main_dispatcher.h |  1 +
 server/reds-private.h    |  2 ++
 server/reds.c            | 28 +++++++++++++++++++++++++++-
 server/reds.h            |  2 ++
 5 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/server/main_dispatcher.c b/server/main_dispatcher.c
index 1126ec0..8402402 100644
--- a/server/main_dispatcher.c
+++ b/server/main_dispatcher.c
@@ -40,6 +40,7 @@ MainDispatcher main_dispatcher;
 enum {
     MAIN_DISPATCHER_CHANNEL_EVENT = 0,
     MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
+    MAIN_DISPATCHER_SET_MM_TIME_LATENCY,
 
     MAIN_DISPATCHER_NUM_MESSAGES
 };
@@ -53,6 +54,11 @@ typedef struct MainDispatcherMigrateSeamlessDstCompleteMessage {
     RedClient *client;
 } MainDispatcherMigrateSeamlessDstCompleteMessage;
 
+typedef struct MainDispatcherMmTimeLatencyMessage {
+    RedClient *client;
+    uint32_t latency;
+} MainDispatcherMmTimeLatencyMessage;
+
 /* channel_event - calls core->channel_event, must be done in main thread */
 static void main_dispatcher_self_handle_channel_event(
                                                 int event,
@@ -96,6 +102,13 @@ static void main_dispatcher_handle_migrate_complete(void *opaque,
     reds_on_client_seamless_migrate_complete(mig_complete->client);
 }
 
+static void main_dispatcher_handle_mm_time_latency(void *opaque,
+                                                   void *payload)
+{
+    MainDispatcherMmTimeLatencyMessage *msg = payload;
+    reds_set_client_mm_time_latency(msg->client, msg->latency);
+}
+
 void main_dispatcher_seamless_migrate_dst_complete(RedClient *client)
 {
     MainDispatcherMigrateSeamlessDstCompleteMessage msg;
@@ -109,6 +122,22 @@ void main_dispatcher_seamless_migrate_dst_complete(RedClient *client)
     dispatcher_send_message(&main_dispatcher.base, MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
                             &msg);
 }
+
+void main_dispatcher_set_mm_time_latency(RedClient *client, uint32_t latency)
+{
+    MainDispatcherMmTimeLatencyMessage msg;
+
+    if (pthread_self() == main_dispatcher.base.self) {
+        reds_set_client_mm_time_latency(client, latency);
+        return;
+    }
+
+    msg.client = client;
+    msg.latency = latency;
+    dispatcher_send_message(&main_dispatcher.base, MAIN_DISPATCHER_SET_MM_TIME_LATENCY,
+                            &msg);
+}
+
 static void dispatcher_handle_read(int fd, int event, void *opaque)
 {
     Dispatcher *dispatcher = opaque;
@@ -129,4 +158,7 @@ void main_dispatcher_init(SpiceCoreInterface *core)
     dispatcher_register_handler(&main_dispatcher.base, MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
                                 main_dispatcher_handle_migrate_complete,
                                 sizeof(MainDispatcherMigrateSeamlessDstCompleteMessage), 0 /* no ack */);
+    dispatcher_register_handler(&main_dispatcher.base, MAIN_DISPATCHER_SET_MM_TIME_LATENCY,
+                                main_dispatcher_handle_mm_time_latency,
+                                sizeof(MainDispatcherMmTimeLatencyMessage), 0 /* no ack */);
 }
diff --git a/server/main_dispatcher.h b/server/main_dispatcher.h
index d44ee3a..0c79ca8 100644
--- a/server/main_dispatcher.h
+++ b/server/main_dispatcher.h
@@ -6,6 +6,7 @@
 
 void main_dispatcher_channel_event(int event, SpiceChannelEventInfo *info);
 void main_dispatcher_seamless_migrate_dst_complete(RedClient *client);
+void main_dispatcher_set_mm_time_latency(RedClient *client, uint32_t latency);
 void main_dispatcher_init(SpiceCoreInterface *core);
 
 #endif //MAIN_DISPATCHER_H
diff --git a/server/reds-private.h b/server/reds-private.h
index 3db6565..9358d27 100644
--- a/server/reds-private.h
+++ b/server/reds-private.h
@@ -177,6 +177,8 @@ typedef struct RedsState {
     int allow_multiple_clients;
 
     RedsClientMonitorsConfig client_monitors_config;
+    int mm_timer_enabled;
+    uint32_t mm_time_latency;
 } RedsState;
 
 #endif
diff --git a/server/reds.c b/server/reds.c
index ec80e9e..d74f465 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3015,6 +3015,29 @@ listen:
     return slisten;
 }
 
+static void reds_send_mm_time(void)
+{
+    main_channel_push_multi_media_time(reds->main_channel,
+                                       reds_get_mm_time() - reds->mm_time_latency);
+}
+
+void reds_set_client_mm_time_latency(RedClient *client, uint32_t latency)
+{
+    // todo: multi-client support for mm_time
+    if (reds->mm_timer_enabled) {
+        // todo: consider network latency
+        if (latency > reds->mm_time_latency) {
+            reds->mm_time_latency = latency;
+            reds_send_mm_time();
+        } else {
+            spice_debug("new latency %u is smaller than existing %u",
+                        latency, reds->mm_time_latency);
+        }
+    } else {
+        snd_set_playback_latency(client, latency);
+    }
+}
+
 static int reds_init_net(void)
 {
     if (spice_port != -1) {
@@ -3447,12 +3470,15 @@ void reds_enable_mm_timer(void)
     if (!reds_main_channel_connected()) {
         return;
     }
-    main_channel_push_multi_media_time(reds->main_channel, reds_get_mm_time() - MM_TIME_DELTA);
+    reds->mm_timer_enabled = TRUE;
+    reds->mm_time_latency = MM_TIME_DELTA;
+    reds_send_mm_time();
 }
 
 void reds_disable_mm_timer(void)
 {
     core->timer_cancel(reds->mm_timer);
+    reds->mm_timer_enabled = FALSE;
 }
 
 static void mm_timer_proc(void *opaque)
diff --git a/server/reds.h b/server/reds.h
index f8e8d56..59f13ce 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -164,4 +164,6 @@ void reds_on_client_seamless_migrate_complete(RedClient *client);
 void reds_on_main_channel_migrate(MainChannelClient *mcc);
 void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev);
 
+void reds_set_client_mm_time_latency(RedClient *client, uint32_t latency);
+
 #endif
-- 
1.8.1



More information about the Spice-devel mailing list