xpra icon
Bug tracker and wiki

Ticket #999: bandwidth-hacks.patch

File bandwidth-hacks.patch, 12.4 KB (added by Antoine Martin, 21 months ago)

with these hacks, it becomes possible to run glxspheres on a 1Mbps connection

  • xpra/server/window/batch_delay_calculator.py

     
    146146
    147147    #ensure we decode at a reasonable speed (for slow / low-power clients)
    148148    #maybe this should be configurable?
    149     target_decode_speed = 8*1000*1000.0      #8 MPixels/s
     149    target_decode_speed = 4*1000*1000.0      #target in MPixels/s
    150150    dec_lat = 0.0
    151151    if statistics.avg_decode_speed>0:
    152152        dec_lat = target_decode_speed/(statistics.avg_decode_speed or target_decode_speed)
  • xpra/server/window/video_subregion.py

     
    7979        #keep track of how much extra we batch non-video regions (milliseconds):
    8080        self.non_max_wait = 150
    8181        self.min_time = monotonic_time()
     82        self.min_refresh_time = 0
    8283
    8384    def reset(self):
    8485        self.cancel_refresh_timer()
     
    150151                     "set-at"       : self.set_at,
    151152                     "time"         : int(self.time),
    152153                     "min-time"     : int(self.min_time),
     154                     "min-refresh-time"  : int(self.min_refresh_time),
    153155                     "non-max-wait" : self.non_max_wait,
    154156                     "in-out"       : self.inout,
    155157                     "score"        : self.score,
     
    191193        for r in self.refresh_regions:
    192194            if not rect.contains_rect(r):
    193195                non_video += r.substract_rect(rect)
    194         delay = max(150, self.auto_refresh_delay)
     196        now = monotonic_time()
     197        delay = max(150, self.min_refresh_time-now, self.auto_refresh_delay)
    195198        if non_video:
    196199            #refresh via timeout_add so this will run in the UI thread:
    197200            self.timeout_add(delay, self.refresh_cb, non_video)
     
    200203            self.refresh_regions = [r for r in inrect if r is not None]
    201204        #re-schedule the video region refresh (if we have regions to fresh):
    202205        if self.refresh_regions:
    203             self.refresh_timer = self.timeout_add(delay, self.refresh)
     206            pass
     207            #self.refresh_timer = self.timeout_add(delay, self.refresh)
    204208
    205209    def refresh(self):
    206210        #runs via timeout_add, safe to call UI!
     
    216220        refreshlog("refresh() calling %s with regions=%s", self.refresh_cb, regions)
    217221        self.refresh_cb(regions)
    218222
     223    def reschedule_refresh(self):
     224        rt = self.refresh_timer
     225        if rt:
     226            self.source_remove(rt)
     227            now = monotonic_time()
     228            delay = max(150, self.min_refresh_time-now, self.auto_refresh_delay)
     229            self.refresh_timer = self.timeout_add(delay, self.refresh)
    219230
     231
    220232    def novideoregion(self, msg="", *args):
    221233        sslog("novideoregion: "+msg, *args)
    222234        self.rectangle = None
  • xpra/server/window/window_source.py

     
    219219        self._fixed_min_speed = default_encoding_options.get("min-speed", 0)
    220220        #will be overriden by update_quality() and update_speed() called from update_encoding_selection()
    221221        #just here for clarity:
    222         self._current_quality = 50
    223         self._current_speed = 50
     222        self._current_quality = 25
     223        self._current_speed = 25
    224224        self._want_alpha = False
    225225        self._lossless_threshold_base = 85
    226226        self._lossless_threshold_pixel_boost = 20
     
    749749            are = self.client_refresh_encodings
    750750        else:
    751751            #sane defaults:
    752             ropts = set(("png", "rgb24", "rgb32"))          #default encodings for auto-refresh
    753             if AUTO_REFRESH_QUALITY<100 and self.image_depth>16:
    754                 ropts.add("jpeg")
     752            #ropts = set(("png", "rgb24", "rgb32"))          #default encodings for auto-refresh
     753            #if AUTO_REFRESH_QUALITY<100 and self.image_depth>16:
     754            #    ropts.add("jpeg")
     755            ropts = ("jpeg",)
    755756            are = [x for x in PREFERED_ENCODING_ORDER if x in ropts]
    756757        self.auto_refresh_encodings = [x for x in are if x in self.common_encodings]
    757758        log("update_encoding_selection: auto_refresh_encodings=%s", self.auto_refresh_encodings)
     
    858859    def get_auto_encoding(self, pixel_count, ww, wh, speed, quality, *_args):
    859860        if pixel_count<self._rgb_auto_threshold:
    860861            return "rgb24"
    861         if "png" in self.common_encodings and ((quality>=80 and speed<80) or self.image_depth<=16):
    862             return "png"
     862        #if "png" in self.common_encodings and ((quality>=80 and speed<80) or self.image_depth<=16):
     863        #    return "png"
    863864        if "jpeg" in self.common_encodings:
    864865            return "jpeg"
    865866        return [x for x in self.common_encodings if x!="rgb"][0]
     
    990991        self.may_update_av_sync_delay()
    991992
    992993    def update_speed(self):
    993         if self.suspended or self._mmap:
     994        if self.suspended or self._mmap or self._sequence<10:
    994995            return
    995996        speed = self._fixed_speed
    996997        if speed<=0:
     
    10041005            info = {}
    10051006            speed = min(100, speed)
    10061007        self._current_speed = int(speed)
    1007         statslog("update_speed() info=%s, speed=%s", info, self._current_speed)
     1008        statslog.info("update_speed() wid=%s, info=%s, speed=%s", self.wid, info, self._current_speed)
    10081009        self._encoding_speed.append((monotonic_time(), info, self._current_speed))
    10091010
    10101011    def set_min_speed(self, min_speed):
     
    10221023
    10231024
    10241025    def update_quality(self):
    1025         statslog("update_quality() suspended=%s, mmap=%s, encoding=%s", self.suspended, self._mmap, self.encoding)
    1026         if self.suspended or self._mmap:
     1026        statslog("update_quality() wid=%i, suspended=%s, mmap=%s, encoding=%s", self.wid, self.suspended, self._mmap, self.encoding)
     1027        if self.suspended or self._mmap or self._sequence<10:
    10271028            return
    10281029        if self.encoding in ("rgb", "png", "png/P", "png/L"):
    10291030            #the user has selected an encoding which does not use quality
     
    10421043            info = {}
    10431044            quality = min(100, quality)
    10441045        self._current_quality = int(quality)
    1045         statslog("update_quality() info=%s, quality=%s", info, self._current_quality)
     1046        statslog.info("update_quality() wid=%i, info=%s, quality=%s", self.wid, info, self._current_quality)
    10461047        self._encoding_quality.append((monotonic_time(), info, self._current_quality))
    10471048
    10481049    def set_min_quality(self, min_quality):
     
    13691370        def get_encoding(pixel_count):
    13701371            return get_best_encoding(pixel_count, ww, wh, speed, quality, coding)
    13711372
     1373        def pngcheck(actual_encoding):
     1374            if actual_encoding=="png":
     1375                log.error("send_full_window_update() %s(%i)=%s, get_best_encoding=%s, options=%s", get_encoding, ww*wh, actual_encoding, get_best_encoding, options)
     1376                import traceback
     1377                traceback.print_stack(limit=5)
     1378
    13721379        def send_full_window_update():
    13731380            actual_encoding = get_encoding(ww*wh)
     1381            pngcheck(actual_encoding)
    13741382            log("send_delayed_regions: using full window update %sx%s with %s", ww, wh, actual_encoding)
    13751383            assert actual_encoding is not None
    13761384            self.process_damage_region(damage_time, 0, 0, ww, wh, actual_encoding, options)
     
    14311439            if len(regions)>1 and exclude_region is None:
    14321440                pixel_count = sum(rect.width*rect.height for rect in regions)
    14331441                actual_encoding = get_encoding(pixel_count)
     1442                pngcheck(actual_encoding)
    14341443                log("send_delayed_regions: %s regions with %s pixels (encoding=%s, actual=%s)", len(regions), pixel_count, coding, actual_encoding)
    14351444                if pixel_count>=ww*wh or self.must_encode_full_frame(actual_encoding):
    14361445                    #use full screen dimensions:
     
    14511460        i_reg_enc = []
    14521461        for i,region in enumerate(regions):
    14531462            actual_encoding = get_encoding(region.width*region.height)
     1463            pngcheck(actual_encoding)
    14541464            if self.must_encode_full_frame(actual_encoding):
    14551465                log("send_delayed_regions: using full frame for %s encoding of %ix%i", actual_encoding, region.width, region.height)
    14561466                self.process_damage_region(damage_time, 0, 0, ww, wh, actual_encoding, options)
     
    15481558
    15491559
    15501560    def schedule_auto_refresh(self, packet, options):
    1551         if not self.can_refresh():
     1561        if not self.can_refresh() or False:
    15521562            self.cancel_refresh_timer()
    15531563            return
    15541564        encoding = packet[6]
     
    18081818            statslog("record_congestion_event(%i) %iKbps", late_pct, send_speed/1024)
    18091819            gs.congestion_send_speed.append((now, late_pct, send_speed))
    18101820            gs.last_congestion_time = now
     1821        self.delay_refresh(5)
    18111822
     1823    def delay_refresh(self, delay):
     1824        log.info("delay_refresh(%i)", delay)
     1825        #push it back:
     1826        rtt = self.refresh_target_time
     1827        if rtt:
     1828            self.refresh_target_time = rtt+delay
     1829
     1830
    18121831    def damage_packet_acked(self, damage_packet_sequence, width, height, decode_time, message):
    18131832        """
    18141833            The client is acknowledging a damage packet,
  • xpra/server/window/window_video_source.py

     
    366366        def nonvideo(q=quality, info=""):
    367367            s = max(0, min(100, speed))
    368368            q = max(0, min(100, q))
    369             log("nonvideo(%i, %s)", q, info)
     369            log.info("nonvideo(%i, %s)", q, info)
    370370            return self.get_best_nonvideo_encoding(pixel_count, ww, wh, s, q, self.non_video_encodings[0], self.non_video_encodings)
    371371
    372372        def lossless(reason):
     
    398398            return lossless("low pixel count")
    399399
    400400        if current_encoding!="auto" and current_encoding not in self.common_video_encodings:
     401            if current_encoding=="png":
     402                import traceback
     403                traceback.print_stack()
    401404            return nonvideo(info="%s not a supported video encoding" % current_encoding)
    402405
    403406        if cww*cwh<=MAX_NONVIDEO_PIXELS:
     
    419422            return nonvideo(quality+30, "not the video region")
    420423
    421424        lde = list(self.statistics.last_damage_events)
    422         lim = now-2
    423         pixels_last_2secs = sum(w*h for when,_,_,w,h in lde if when>lim)
    424         if pixels_last_2secs<5*videomin:
     425        lim = now-4
     426        pixels_last_4secs = sum(w*h for when,_,_,w,h in lde if when>lim)
     427        if pixels_last_4secs<3*videomin:
    425428            #less than 5 full frames in last 2 seconds
    426429            return nonvideo(quality+30, "not enough frames")
    427         lim = now-0.5
    428         pixels_last_05secs = sum(w*h for when,_,_,w,h in lde if when>lim)
    429         if pixels_last_05secs<pixels_last_2secs//8:
     430        lim = now-1
     431        pixels_last_sec = sum(w*h for when,_,_,w,h in lde if when>lim)
     432        if pixels_last_sec<pixels_last_4secs//8:
    430433            #framerate is dropping?
    431434            return nonvideo(quality+30, "framerate lowered")
    432435
     
    463466        #take into account how many pixels need to be encoded:
    464467        #more pixels means we switch to lossless more easily
    465468        lossless_q = min(100, self._lossless_threshold_base + self._lossless_threshold_pixel_boost * pixel_count / (ww*wh))
    466         if quality<lossless_q and self.image_depth>16 and "jpeg" in options:
     469        if quality<100 and self.image_depth>16 and "jpeg" in options:
    467470            #assume that we have "turbojpeg",
    468471            #which beats everything in terms of efficiency for lossy compression:
    469472            return "jpeg"
     
    541544        WindowSource.timer_full_refresh(self)
    542545
    543546
     547    def delay_refresh(self, delay):
     548        WindowSource.delay_refresh(self, delay)
     549        self.video_subregion.min_refresh_time = monotonic_time()+delay
     550        self.video_subregion.reschedule_refresh()
     551
     552
    544553    def get_refresh_exclude(self):
    545554        #exclude video region (if any) from lossless refresh:
    546555        return self.video_subregion.rectangle