xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #400: sound-netcompress.patch

File sound-netcompress.patch, 5.6 KB (added by Antoine Martin, 7 years ago)

allows us to compress raw WAV using the standard packet compressors (only saves about 25% with lz4, probably not worth it)

  • xpra/sound/gstreamer_util.py

     
    8888
    8989CODEC_ORDER = [MP3, WAVPACK, WAV, FLAC, SPEEX]
    9090#CODEC_ORDER = [MP3, FLAC, SPEEX]
     91NETCOMPRESS = [WAV]
    9192
    9293
    9394#code to temporarily redirect stderr and restore it afterwards, adapted from:
  • xpra/sound/sink.py

     
    6666        "eos"       : one_arg_signal,
    6767        })
    6868
    69     def __init__(self, sink_type=None, sink_options={}, codecs=CODECS, codec_options={}, volume=1.0):
     69    def __init__(self, sink_type=None, sink_options={}, codecs=CODECS, codec_options={}, volume=1.0, compressors=[]):
    7070        if not sink_type:
    7171            sink_type = DEFAULT_SINK
    7272        assert sink_type in SINKS, "invalid sink: %s" % sink_type
     
    7575        assert len(matching)>0, "no matching codecs between arguments %s and supported list %s" % (codecs, CODECS)
    7676        codec = matching[0]
    7777        decoder, parser = get_decoder_parser(codec)
    78         SoundPipeline.__init__(self, codec)
     78        SoundPipeline.__init__(self, codec, compressors)
    7979        self.sink_type = sink_type
    8080        decoder_str = plugin_str(decoder, codec_options)
    8181        pipeline_els = []
  • xpra/sound/sound_pipeline.py

     
    2424        "new-stream"        : one_arg_signal,
    2525        }
    2626
    27     def __init__(self, codec):
     27    def __init__(self, codec, compressors):
    2828        gobject.GObject.__init__(self)
    2929        self.codec = codec
     30        self.compressors = compressors
    3031        self.codec_description = codec
    3132        self.codec_mode = ""
    3233        self.bus = None
  • xpra/sound/src.py

     
    88import time
    99
    1010from xpra.os_util import SIGNAMES
     11from xpra.net.compression import compressed_wrapper
    1112from xpra.sound.sound_pipeline import SoundPipeline, gobject
    1213from xpra.gtk_common.gobject_util import n_arg_signal
    13 from xpra.sound.gstreamer_util import plugin_str, get_encoder_formatter, get_source_plugins, get_queue_time, normv, MP3, CODECS, CODEC_ORDER, QUEUE_LEAK
     14from xpra.sound.gstreamer_util import plugin_str, get_encoder_formatter, get_source_plugins, get_queue_time, normv, MP3, CODECS, CODEC_ORDER, QUEUE_LEAK, NETCOMPRESS
    1415from xpra.log import Logger
    1516log = Logger("sound")
    1617
     
    2728        "new-buffer"    : n_arg_signal(2),
    2829        })
    2930
    30     def __init__(self, src_type=None, src_options={}, codecs=CODECS, codec_options={}, volume=1.0):
     31    def __init__(self, src_type=None, src_options={}, codecs=CODECS, codec_options={}, volume=1.0, compressors=[]):
    3132        if not src_type:
    3233            from xpra.sound.pulseaudio_util import get_pa_device_options
    3334            monitor_devices = get_pa_device_options(True, False)
     
    4950        assert len(matching)>0, "no matching codecs between arguments %s and supported list %s" % (codecs, CODECS)
    5051        codec = matching[0]
    5152        encoder, fmt = get_encoder_formatter(codec)
    52         SoundPipeline.__init__(self, codec)
     53        SoundPipeline.__init__(self, codec, compressors)
    5354        self.src_type = src_type
    5455        source_str = plugin_str(src_type, src_options)
    5556        encoder_str = plugin_str(encoder, codec_options)
     
    149150        self.buffer_count += 1
    150151        self.byte_count += len(data)
    151152        metadata["time"] = int(time.time()*1000)
     153        if self.codec in NETCOMPRESS and self.compressors:
     154            osize = len(data)
     155            compressors = dict((c,True) for c in ("zlib", "lz4", "lzo") if c in self.compressors)
     156            cdata = compressed_wrapper(self.codec, data, level=1, **compressors)
     157            csize = len(cdata)
     158            log.info("%s sound buffer recompressed with %s, saved %s%% (from %s to %s bytes)", self.codec, cdata.algorithm, 100-100*csize/osize, osize, csize)
     159            if len(cdata)<osize:
     160                data = cdata
    152161        self.idle_emit("new-buffer", data, metadata)
    153162
    154163
  • xpra/sound/wrapper.py

     
    9191        sound_subprocess.__init__(self, sound_pipeline, ["add_data"], ["underrun", "overrun"])
    9292
    9393
    94 def run_sound(mode, error_cb, options, args):
     94def run_sound(mode, error_cb, cmdline_options, args):
    9595    """ this function just parses command line arguments to feed into the sound subprocess class,
    9696        which in turn just feeds them into the sound pipeline class (sink.py or src.py)
    9797    """
     
    103103    else:
    104104        raise Exception("unknown mode: %s" % mode)
    105105
     106    #compress args:
     107    log.info("compressors=%s", cmdline_options.compressors)
     108    compressors = [c for c in ("zlib", "lz4", "lzo") if c in cmdline_options.compressors]
     109    log("compress_args=%s", compressors)
    106110    #the plugin to use (ie: 'pulsesrc' for src.py or 'autoaudiosink' for sink.py)
    107111    plugin = args[2]
    108112    #plugin options (ie: "device=monitor_device,something=value")
     
    120124
    121125    ss = None
    122126    try:
    123         ss = subproc(plugin, options, codecs, codec_options, volume)
     127        ss = subproc(plugin, options, codecs, codec_options, volume, compressors)
    124128        ss.start()
    125129        return 0
    126130    except Exception: