summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy White <jwhite@codeweavers.com>2015-06-03 15:21:06 -0500
committerJeremy White <jwhite@codeweavers.com>2015-06-04 15:41:48 -0500
commitb76c734d1686bb6ba8395969dc98c407103d848c (patch)
tree9696a5efde587478f6a22dfe0d3cc4cf26c28bcb
parent84562db7e4d978486343fbc6146f93f82606d169 (diff)
Add support for stream reports.
This helps video playback do a slightly better job of keeping up in the browser. It's not a dramatic effect, but enough to start making video playback almost tolerable.
-rw-r--r--display.js67
-rw-r--r--enums.js1
-rw-r--r--main.js3
-rw-r--r--spiceconn.js3
-rw-r--r--spicemsg.js54
5 files changed, 116 insertions, 12 deletions
diff --git a/display.js b/display.js
index 7027230..7938527 100644
--- a/display.js
+++ b/display.js
@@ -477,31 +477,48 @@ SpiceDisplayConn.prototype.process_channel_message = function(msg)
return true;
}
- if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA)
+ if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA ||
+ msg.type == SPICE_MSG_DISPLAY_STREAM_DATA_SIZED)
{
- var m = new SpiceMsgDisplayStreamData(msg.data);
+ var m;
+ if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA_SIZED)
+ m = new SpiceMsgDisplayStreamDataSized(msg.data);
+ else
+ m = new SpiceMsgDisplayStreamData(msg.data);
+
if (!this.streams[m.base.id])
{
console.log("no stream for data");
return false;
}
+
+ var mmtime = (Date.now() - this.parent.our_mm_time) + this.parent.mm_time;
+ var latency = m.base.multi_media_time - mmtime;
+
if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG)
- {
- process_mjpeg_stream_data(this, m);
+ process_mjpeg_stream_data(this, m, latency);
+
+ if ("report" in this.streams[m.base.id])
+ process_stream_data_report(this, m, mmtime, latency);
- }
return true;
}
- if (msg.type == SPICE_MSG_DISPLAY_STREAM_DATA_SIZED)
+ if (msg.type == SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT)
{
- var m = new SpiceMsgDisplayStreamDataSized(msg.data);
- if (this.streams[m.base.id].codec_type === SPICE_VIDEO_CODEC_TYPE_MJPEG)
- process_mjpeg_stream_data(this, m);
+ var m = new SpiceMsgDisplayStreamActivateReport(msg.data);
+
+ var report = new SpiceMsgcDisplayStreamReport(m.stream_id, m.unique_id);
+ if (this.streams[m.stream_id])
+ {
+ this.streams[m.stream_id].report = report;
+ this.streams[m.stream_id].max_window_size = m.max_window_size;
+ this.streams[m.stream_id].timeout_ms = m.timeout_ms
+ }
+
return true;
}
-
if (msg.type == SPICE_MSG_DISPLAY_STREAM_CLIP)
{
var m = new SpiceMsgDisplayStreamClip(msg.data);
@@ -811,8 +828,15 @@ function handle_draw_jpeg_onload()
}
}
-function process_mjpeg_stream_data(sc, m)
+function process_mjpeg_stream_data(sc, m, latency)
{
+ if (latency < 0)
+ {
+ if ("report" in sc.streams[m.base.id])
+ sc.streams[m.base.id].report.num_drops++;
+ return;
+ }
+
var tmpstr = "data:image/jpeg,";
var img = new Image;
var i;
@@ -837,3 +861,24 @@ function process_mjpeg_stream_data(sc, m)
img.src = tmpstr;
}
+function process_stream_data_report(sc, m, mmtime, latency)
+{
+ sc.streams[m.base.id].report.num_frames++;
+ if (sc.streams[m.base.id].report.start_frame_mm_time == 0)
+ sc.streams[m.base.id].report.start_frame_mm_time = m.base.multi_media_time;
+
+ if (sc.streams[m.base.id].report.num_frames > sc.streams[m.base.id].max_window_size ||
+ (m.base.multi_media_time - sc.streams[m.base.id].report.start_frame_mm_time) > sc.streams[m.base.id].timeout_ms)
+ {
+ sc.streams[m.base.id].report.end_frame_mm_time = m.base.multi_media_time;
+ sc.streams[m.base.id].report.last_frame_delay = latency;
+
+ var msg = new SpiceMiniData();
+ msg.build_msg(SPICE_MSGC_DISPLAY_STREAM_REPORT, sc.streams[m.base.id].report);
+ sc.send_msg(msg);
+
+ sc.streams[m.base.id].report.start_frame_mm_time = 0;
+ sc.streams[m.base.id].report.num_frames = 0;
+ sc.streams[m.base.id].report.num_drops = 0;
+ }
+}
diff --git a/enums.js b/enums.js
index 7f55e46..6e94025 100644
--- a/enums.js
+++ b/enums.js
@@ -133,6 +133,7 @@ var SPICE_MSG_DISPLAY_DRAW_COMPOSITE = 318;
var SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT = 319;
var SPICE_MSGC_DISPLAY_INIT = 101;
+var SPICE_MSGC_DISPLAY_STREAM_REPORT = 102;
var SPICE_MSG_INPUTS_INIT = 101;
var SPICE_MSG_INPUTS_KEY_MODIFIERS = 102;
diff --git a/main.js b/main.js
index bfc102a..99b2274 100644
--- a/main.js
+++ b/main.js
@@ -86,6 +86,9 @@ SpiceMainConn.prototype.process_channel_message = function(msg)
" ; ram_hint " + this.main_init.ram_hint);
}
+ this.our_mm_time = Date.now();
+ this.mm_time = this.main_init.multi_media_time;
+
this.handle_mouse_mode(this.main_init.current_mouse_mode,
this.main_init.supported_mouse_modes);
diff --git a/spiceconn.js b/spiceconn.js
index b7043c0..f19b109 100644
--- a/spiceconn.js
+++ b/spiceconn.js
@@ -135,7 +135,8 @@ SpiceConn.prototype =
);
else if (msg.channel_type == SPICE_CHANNEL_DISPLAY)
msg.channel_caps.push(
- (1 << SPICE_DISPLAY_CAP_SIZED_STREAM)
+ (1 << SPICE_DISPLAY_CAP_SIZED_STREAM) |
+ (1 << SPICE_DISPLAY_CAP_STREAM_REPORT)
);
hdr.size = msg.buffer_size();
diff --git a/spicemsg.js b/spicemsg.js
index 4b78d94..db6625a 100644
--- a/spicemsg.js
+++ b/spicemsg.js
@@ -1201,6 +1201,60 @@ SpiceMsgDisplayStreamDestroy.prototype =
},
}
+function SpiceMsgDisplayStreamActivateReport(a, at)
+{
+ this.from_buffer(a, at);
+}
+
+SpiceMsgDisplayStreamActivateReport.prototype =
+{
+ from_buffer: function(a, at)
+ {
+ at = at || 0;
+ var dv = new SpiceDataView(a);
+ this.stream_id = dv.getUint32(at, true); at += 4;
+ this.unique_id = dv.getUint32(at, true); at += 4;
+ this.max_window_size = dv.getUint32(at, true); at += 4;
+ this.timeout_ms = dv.getUint32(at, true); at += 4;
+ },
+}
+
+function SpiceMsgcDisplayStreamReport(stream_id, unique_id)
+{
+ this.stream_id = stream_id;
+ this.unique_id = unique_id;
+ this.start_frame_mm_time = 0;
+ this.end_frame_mm_time = 0;
+ this.num_frames = 0;
+ this.num_drops = 0;
+ this.last_frame_delay = 0;
+
+ // TODO - Implement audio delay
+ this.audio_delay = -1;
+}
+
+SpiceMsgcDisplayStreamReport.prototype =
+{
+ to_buffer: function(a, at)
+ {
+ at = at || 0;
+ var dv = new SpiceDataView(a);
+ dv.setUint32(at, this.stream_id, true); at += 4;
+ dv.setUint32(at, this.unique_id, true); at += 4;
+ dv.setUint32(at, this.start_frame_mm_time, true); at += 4;
+ dv.setUint32(at, this.end_frame_mm_time, true); at += 4;
+ dv.setUint32(at, this.num_frames, true); at += 4;
+ dv.setUint32(at, this.num_drops, true); at += 4;
+ dv.setUint32(at, this.last_frame_delay, true); at += 4;
+ dv.setUint32(at, this.audio_delay, true); at += 4;
+ return at;
+ },
+ buffer_size: function()
+ {
+ return 8 * 4;
+ }
+}
+
function SpiceMsgDisplayInvalList(a, at)
{
this.count = 0;