[Spice-commits] 4 commits - playback.js webm.js

Jeremy White jwhite at kemper.freedesktop.org
Mon Oct 3 14:41:01 UTC 2016


 playback.js |   82 +++++++++++++++++++++++++++++++++++-------------------------
 webm.js     |    1 
 2 files changed, 50 insertions(+), 33 deletions(-)

New commits:
commit 9468cf2a9b7c6a5f4a91429bdd1d1ffbf4b99417
Author: Jeremy White <jwhite at codeweavers.com>
Date:   Wed Sep 28 09:17:51 2016 -0500

    Implement support for the playback stop message.
    
    This allows audio processing to be more robust in Firefox.

diff --git a/playback.js b/playback.js
index 55dc0e8..48d4cdd 100644
--- a/playback.js
+++ b/playback.js
@@ -158,7 +158,22 @@ SpicePlaybackConn.prototype.process_channel_message = function(msg)
 
     if (msg.type == SPICE_MSG_PLAYBACK_STOP)
     {
-        return true;
+        PLAYBACK_DEBUG > 0 && console.log("PlaybackStop");
+        if (this.source_buffer)
+        {
+            document.getElementById(this.parent.screen_id).removeChild(this.audio);
+            window.URL.revokeObjectURL(this.audio.src);
+
+            delete this.source_buffer;
+            delete this.media_source;
+            delete this.audio;
+
+            this.append_okay = false;
+            this.queue = new Array();
+            this.start_time = 0;
+
+            return true;
+        }
     }
 
     if (msg.type == SPICE_MSG_PLAYBACK_VOLUME)
commit 3633675e4b4f202773eceec69c5a43158a93b37d
Author: Jeremy White <jwhite at codeweavers.com>
Date:   Wed Sep 28 09:16:51 2016 -0500

    Rely on the auto play attribute.
    
    Browsers now reliably autoplay, and issuing play prematurely
    can generate an error in both Firefox and Chrome.
    
    Hence we can simply remove this call and audio seems to work fine.

diff --git a/playback.js b/playback.js
index f10a071..55dc0e8 100644
--- a/playback.js
+++ b/playback.js
@@ -142,9 +142,6 @@ SpicePlaybackConn.prototype.process_channel_message = function(msg)
         else
             this.simple_block(data, false);
 
-        if (this.audio.paused)
-            this.audio.play();
-
         return true;
     }
 
commit dc5fd91f0c657ff5c87d0bf02d9be4235ca43e9f
Author: Jeremy White <jwhite at codeweavers.com>
Date:   Wed Sep 28 09:14:25 2016 -0500

    Revise sound packet time sequencing for a more recent Firefox.
    
    Around version 45, Firefox started being very particular about the
    time stamps put into the Opus stream.  The time stamps from the Spice server are
    somewhat irregular.  They mostly arrive every 10 ms, but sometimes it is 11, or sometimes
    with two time stamps the same in a row.  The previous logic resulted in fuzzy and/or
    distorted audio streams in Firefox in a row.
    
    Thus, we end up with an inelegant hack.  Essentially, we force every packet to have
    a 10ms time delta, unless there is an obvious gap in time stream, in which case we
    will resync.
    
    This replaces logic that mitigated only the duplicated time packets.
    
    The long term solution would appear to be 'sequence' mode, but I cannot get
    Firefox to use that mode (and MDN suggests that for codecs such as VP8 with time
    stamps in line, that Firefox will not accept it).

diff --git a/playback.js b/playback.js
index 1d89719..f10a071 100644
--- a/playback.js
+++ b/playback.js
@@ -89,15 +89,6 @@ SpicePlaybackConn.prototype.process_channel_message = function(msg)
     {
         var data = new SpiceMsgPlaybackData(msg.data);
 
-        // If this packet has the same time as the last, just bump up by one.
-        if (this.last_data_time && data.time <= this.last_data_time)
-        {
-            // FIXME - this is arguably wrong.  But delaying the transmission was worse,
-            //          in initial testing.  Could use more research.
-            PLAYBACK_DEBUG > 1 && console.log("Hacking time of " + data.time + " to " + this.last_data_time + 1);
-            data.time = this.last_data_time + 1;
-        }
-
         if (! this.source_buffer)
             return true;
 
@@ -110,8 +101,35 @@ SpicePlaybackConn.prototype.process_channel_message = function(msg)
             this.audio.currentTime = this.audio.buffered.start(this.audio.buffered.length - 1);
         }
 
-        this.last_data_time = data.time;
+        /* Around version 45, Firefox started being very particular about the
+           time stamps put into the Opus stream.  The time stamps from the Spice server are
+           somewhat irregular.  They mostly arrive every 10 ms, but sometimes it is 11, or sometimes
+           with two time stamps the same in a row.  The previous logic resulted in fuzzy and/or
+           distorted audio streams in Firefox in a row.
+
+           In theory, the sequence mode should be appropriate for us, but as of 09/27/2016,
+           I was unable to make sequence mode work with Firefox.
 
+           Thus, we end up with an inelegant hack.  Essentially, we force every packet to have
+           a 10ms time delta, unless there is an obvious gap in time stream, in which case we
+           will resync.
+        */
+
+        if (this.start_time != 0 && data.time != (this.last_data_time + EXPECTED_PACKET_DURATION))
+        {
+            if (Math.abs(data.time - (EXPECTED_PACKET_DURATION + this.last_data_time)) < MAX_CLUSTER_TIME)
+            {
+                PLAYBACK_DEBUG > 1 && console.log("Hacking time of " + data.time + " to " +
+                                      (this.last_data_time + EXPECTED_PACKET_DURATION));
+                data.time = this.last_data_time + EXPECTED_PACKET_DURATION;
+            }
+            else
+            {
+                PLAYBACK_DEBUG > 1 && console.log("Apparent gap in audio time; now is " + data.time + " last was " + this.last_data_time);
+            }
+        }
+
+        this.last_data_time = data.time;
 
         PLAYBACK_DEBUG > 1 && console.log("PlaybackData; time " + data.time + "; length " + data.data.byteLength);
 
diff --git a/webm.js b/webm.js
index 8faa8e7..789da14 100644
--- a/webm.js
+++ b/webm.js
@@ -84,6 +84,7 @@ var OPUS_CHANNELS                           = 2;
 var SPICE_PLAYBACK_CODEC                    = 'audio/webm; codecs="opus"';
 var MAX_CLUSTER_TIME                        = 1000;
 
+var EXPECTED_PACKET_DURATION                = 10;
 var GAP_DETECTION_THRESHOLD                 = 50;
 
 var SPICE_VP8_CODEC                         = 'video/webm; codecs="vp8"';
commit 245a476bd98aaf5b9b05c965a47fd9342768daaf
Author: Jeremy White <jwhite at codeweavers.com>
Date:   Mon Sep 26 15:29:14 2016 -0500

    Use modern browser information to detect underrun.
    
    We previously had a fairly crude 'gap detection', but browsers
    are largely supporting the modern buffer semantics, and we can
    now rely on them to detect under runs for us.
    
    This improves audio in Chrome while playing large videos.

diff --git a/playback.js b/playback.js
index e5f4661..1d89719 100644
--- a/playback.js
+++ b/playback.js
@@ -29,8 +29,6 @@ function SpicePlaybackConn()
     this.queue = new Array();
     this.append_okay = false;
     this.start_time = 0;
-    this.skip_until = 0;
-    this.gap_time = 0;
 }
 
 SpicePlaybackConn.prototype = Object.create(SpiceConn.prototype);
@@ -103,19 +101,13 @@ SpicePlaybackConn.prototype.process_channel_message = function(msg)
         if (! this.source_buffer)
             return true;
 
-        /* Gap detection:  If there has been a delay since our last packet, then audio must
-             have paused.  Handling that gets tricky.  In Chrome, you can seek forward,
-             but you cannot in Firefox.  And seeking forward in Chrome is nice, as it keeps
-             Chrome from being overly cautious in it's buffer strategy.
-
-             So we do two things.  First, we seek forward.  Second, we compute how much of a gap
-             there would have been, and essentially eliminate it.
-        */
-        if (this.last_data_time && data.time >= (this.last_data_time + GAP_DETECTION_THRESHOLD))
+        if (this.audio.readyState >= 3 && this.audio.buffered.length > 1 &&
+            this.audio.currentTime == this.audio.buffered.end(0) &&
+            this.audio.currentTime < this.audio.buffered.start(this.audio.buffered.length - 1))
         {
-            this.skip_until = data.time;
-            this.gap_time = (data.time - this.start_time) -
-              (this.source_buffer.buffered.end(this.source_buffer.buffered.end.length - 1) * 1000.0).toFixed(0);
+            console.log("Audio underrun: we appear to have fallen behind; advancing to " +
+                this.audio.buffered.start(this.audio.buffered.length - 1));
+            this.audio.currentTime = this.audio.buffered.start(this.audio.buffered.length - 1);
         }
 
         this.last_data_time = data.time;
@@ -126,18 +118,12 @@ SpicePlaybackConn.prototype.process_channel_message = function(msg)
         if (this.start_time == 0)
             this.start_playback(data);
 
-        else if (data.time - this.cluster_time >= MAX_CLUSTER_TIME || this.skip_until > 0)
+        else if (data.time - this.cluster_time >= MAX_CLUSTER_TIME)
             this.new_cluster(data);
 
         else
             this.simple_block(data, false);
 
-        if (this.skip_until > 0)
-        {
-            this.audio.currentTime = (this.skip_until - this.start_time - this.gap_time) / 1000.0;
-            this.skip_until = 0;
-        }
-
         if (this.audio.paused)
             this.audio.play();
 
@@ -205,7 +191,7 @@ SpicePlaybackConn.prototype.new_cluster = function(data)
 {
     this.cluster_time = data.time;
 
-    var c = new webm_Cluster(data.time - this.start_time - this.gap_time);
+    var c = new webm_Cluster(data.time - this.start_time);
 
     var mb = new ArrayBuffer(c.buffer_size());
     this.bytes_written += c.to_buffer(mb);


More information about the Spice-commits mailing list