Merge pull request #121 from glyptodon/improve-lag-compensation
GUAC-1389: Stretch RDP and VNC frames until client has caught up.
This commit is contained in:
commit
b8c5ccb321
@ -37,7 +37,7 @@
|
|||||||
* milliseconds. If the server is silent for at least this amount of time, the
|
* milliseconds. If the server is silent for at least this amount of time, the
|
||||||
* frame will be considered finished.
|
* frame will be considered finished.
|
||||||
*/
|
*/
|
||||||
#define GUAC_RDP_FRAME_TIMEOUT 10
|
#define GUAC_RDP_FRAME_TIMEOUT 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of time to wait for a new message from the RDP server when
|
* The amount of time to wait for a new message from the RDP server when
|
||||||
|
@ -829,9 +829,10 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
|
|
||||||
/* Connection complete */
|
/* Connection complete */
|
||||||
rdp_client->rdp_inst = rdp_inst;
|
rdp_client->rdp_inst = rdp_inst;
|
||||||
|
|
||||||
rdpChannels* channels = rdp_inst->context->channels;
|
rdpChannels* channels = rdp_inst->context->channels;
|
||||||
|
|
||||||
|
guac_timestamp last_frame_end = guac_timestamp_current();
|
||||||
|
|
||||||
/* Handle messages from RDP server while client is running */
|
/* Handle messages from RDP server while client is running */
|
||||||
while (client->state == GUAC_CLIENT_RUNNING) {
|
while (client->state == GUAC_CLIENT_RUNNING) {
|
||||||
|
|
||||||
@ -845,72 +846,88 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
/* Wait for data and construct a reasonable frame */
|
/* Wait for data and construct a reasonable frame */
|
||||||
int wait_result = rdp_guac_client_wait_for_messages(client,
|
int wait_result = rdp_guac_client_wait_for_messages(client,
|
||||||
GUAC_RDP_FRAME_START_TIMEOUT);
|
GUAC_RDP_FRAME_START_TIMEOUT);
|
||||||
guac_timestamp frame_start = guac_timestamp_current();
|
if (wait_result > 0) {
|
||||||
while (wait_result > 0) {
|
|
||||||
|
|
||||||
guac_timestamp frame_end;
|
int processing_lag = guac_client_get_processing_lag(client);
|
||||||
int frame_remaining;
|
guac_timestamp frame_start = guac_timestamp_current();
|
||||||
|
|
||||||
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
/* Read server messages until frame is built */
|
||||||
|
do {
|
||||||
|
|
||||||
/* Check the libfreerdp fds */
|
guac_timestamp frame_end;
|
||||||
if (!freerdp_check_fds(rdp_inst)) {
|
int frame_remaining;
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
|
||||||
"Error handling RDP file descriptors");
|
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check channel fds */
|
pthread_mutex_lock(&(rdp_client->rdp_lock));
|
||||||
if (!freerdp_channels_check_fds(channels, rdp_inst)) {
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
|
||||||
"Error handling RDP channel file descriptors");
|
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for channel events */
|
/* Check the libfreerdp fds */
|
||||||
wMessage* event = freerdp_channels_pop_event(channels);
|
if (!freerdp_check_fds(rdp_inst)) {
|
||||||
if (event) {
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
|
"Error handling RDP file descriptors");
|
||||||
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle channel events (clipboard and RAIL) */
|
/* Check channel fds */
|
||||||
|
if (!freerdp_channels_check_fds(channels, rdp_inst)) {
|
||||||
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
|
"Error handling RDP channel file descriptors");
|
||||||
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for channel events */
|
||||||
|
wMessage* event = freerdp_channels_pop_event(channels);
|
||||||
|
if (event) {
|
||||||
|
|
||||||
|
/* Handle channel events (clipboard and RAIL) */
|
||||||
#ifdef LEGACY_EVENT
|
#ifdef LEGACY_EVENT
|
||||||
if (event->event_class == CliprdrChannel_Class)
|
if (event->event_class == CliprdrChannel_Class)
|
||||||
guac_rdp_process_cliprdr_event(client, event);
|
guac_rdp_process_cliprdr_event(client, event);
|
||||||
else if (event->event_class == RailChannel_Class)
|
else if (event->event_class == RailChannel_Class)
|
||||||
guac_rdp_process_rail_event(client, event);
|
guac_rdp_process_rail_event(client, event);
|
||||||
#else
|
#else
|
||||||
if (GetMessageClass(event->id) == CliprdrChannel_Class)
|
if (GetMessageClass(event->id) == CliprdrChannel_Class)
|
||||||
guac_rdp_process_cliprdr_event(client, event);
|
guac_rdp_process_cliprdr_event(client, event);
|
||||||
else if (GetMessageClass(event->id) == RailChannel_Class)
|
else if (GetMessageClass(event->id) == RailChannel_Class)
|
||||||
guac_rdp_process_rail_event(client, event);
|
guac_rdp_process_rail_event(client, event);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
freerdp_event_free(event);
|
freerdp_event_free(event);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle RDP disconnect */
|
||||||
|
if (freerdp_shall_disconnect(rdp_inst)) {
|
||||||
|
guac_client_log(client, GUAC_LOG_INFO,
|
||||||
|
"RDP server closed connection");
|
||||||
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle RDP disconnect */
|
|
||||||
if (freerdp_shall_disconnect(rdp_inst)) {
|
|
||||||
guac_client_log(client, GUAC_LOG_INFO,
|
|
||||||
"RDP server closed connection");
|
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&(rdp_client->rdp_lock));
|
/* Calculate time remaining in frame */
|
||||||
|
frame_end = guac_timestamp_current();
|
||||||
|
frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION
|
||||||
|
- frame_end;
|
||||||
|
|
||||||
/* Calculate time remaining in frame */
|
/* Calculate time that client needs to catch up */
|
||||||
frame_end = guac_timestamp_current();
|
int time_elapsed = frame_end - last_frame_end;
|
||||||
frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION - frame_end;
|
int required_wait = processing_lag - time_elapsed;
|
||||||
|
|
||||||
/* Wait again if frame remaining */
|
/* Increase the duration of this frame if client is lagging */
|
||||||
if (frame_remaining > 0)
|
if (required_wait > GUAC_RDP_FRAME_TIMEOUT)
|
||||||
wait_result = rdp_guac_client_wait_for_messages(client,
|
wait_result = rdp_guac_client_wait_for_messages(client,
|
||||||
GUAC_RDP_FRAME_TIMEOUT*1000);
|
required_wait*1000);
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
/* Wait again if frame remaining */
|
||||||
|
else if (frame_remaining > 0)
|
||||||
|
wait_result = rdp_guac_client_wait_for_messages(client,
|
||||||
|
GUAC_RDP_FRAME_TIMEOUT*1000);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
} while (wait_result > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If an error occurred, fail */
|
/* If an error occurred, fail */
|
||||||
@ -923,6 +940,9 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
guac_client_end_frame(client);
|
guac_client_end_frame(client);
|
||||||
guac_socket_flush(client->socket);
|
guac_socket_flush(client->socket);
|
||||||
|
|
||||||
|
/* Record end of frame */
|
||||||
|
last_frame_end = guac_timestamp_current();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_INFO, "Internal RDP client disconnected");
|
guac_client_log(client, GUAC_LOG_INFO, "Internal RDP client disconnected");
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
* milliseconds. If the server is silent for at least this amount of time, the
|
* milliseconds. If the server is silent for at least this amount of time, the
|
||||||
* frame will be considered finished.
|
* frame will be considered finished.
|
||||||
*/
|
*/
|
||||||
#define GUAC_VNC_FRAME_TIMEOUT 10
|
#define GUAC_VNC_FRAME_TIMEOUT 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of time to wait for a new message from the VNC server when
|
* The amount of time to wait for a new message from the VNC server when
|
||||||
|
@ -345,6 +345,7 @@ void* guac_vnc_client_thread(void* data) {
|
|||||||
GUAC_VNC_FRAME_START_TIMEOUT);
|
GUAC_VNC_FRAME_START_TIMEOUT);
|
||||||
if (wait_result > 0) {
|
if (wait_result > 0) {
|
||||||
|
|
||||||
|
int processing_lag = guac_client_get_processing_lag(client);
|
||||||
guac_timestamp frame_start = guac_timestamp_current();
|
guac_timestamp frame_start = guac_timestamp_current();
|
||||||
|
|
||||||
/* Read server messages until frame is built */
|
/* Read server messages until frame is built */
|
||||||
@ -366,8 +367,17 @@ void* guac_vnc_client_thread(void* data) {
|
|||||||
frame_remaining = frame_start + GUAC_VNC_FRAME_DURATION
|
frame_remaining = frame_start + GUAC_VNC_FRAME_DURATION
|
||||||
- frame_end;
|
- frame_end;
|
||||||
|
|
||||||
|
/* Calculate time that client needs to catch up */
|
||||||
|
int time_elapsed = frame_end - last_frame_end;
|
||||||
|
int required_wait = processing_lag - time_elapsed;
|
||||||
|
|
||||||
|
/* Increase the duration of this frame if client is lagging */
|
||||||
|
if (required_wait > GUAC_VNC_FRAME_TIMEOUT)
|
||||||
|
wait_result = guac_vnc_wait_for_messages(rfb_client,
|
||||||
|
required_wait*1000);
|
||||||
|
|
||||||
/* Wait again if frame remaining */
|
/* Wait again if frame remaining */
|
||||||
if (frame_remaining > 0)
|
else if (frame_remaining > 0)
|
||||||
wait_result = guac_vnc_wait_for_messages(rfb_client,
|
wait_result = guac_vnc_wait_for_messages(rfb_client,
|
||||||
GUAC_VNC_FRAME_TIMEOUT*1000);
|
GUAC_VNC_FRAME_TIMEOUT*1000);
|
||||||
else
|
else
|
||||||
@ -386,17 +396,8 @@ void* guac_vnc_client_thread(void* data) {
|
|||||||
guac_client_end_frame(client);
|
guac_client_end_frame(client);
|
||||||
guac_socket_flush(client->socket);
|
guac_socket_flush(client->socket);
|
||||||
|
|
||||||
/* Calculate time since previous frame ended */
|
|
||||||
int current_frame_end = guac_timestamp_current();
|
|
||||||
int time_elapsed = current_frame_end - last_frame_end;
|
|
||||||
int processing_lag = guac_client_get_processing_lag(client);
|
|
||||||
|
|
||||||
/* Insert delays as necessary to allow client to catch up */
|
|
||||||
if (time_elapsed < processing_lag)
|
|
||||||
guac_timestamp_msleep(processing_lag - time_elapsed);
|
|
||||||
|
|
||||||
/* Record end of frame */
|
/* Record end of frame */
|
||||||
last_frame_end = current_frame_end;
|
last_frame_end = guac_timestamp_current();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user