Ejemplo n.º 1
0
 def __init__(self, src_type=None, src_options={}, codecs=get_codecs(), codec_options={}, volume=1.0):
     if not src_type:
         from xpra.sound.pulseaudio_util import get_pa_device_options
         monitor_devices = get_pa_device_options(True, False)
         log.info("found pulseaudio monitor devices: %s", monitor_devices)
         if len(monitor_devices)==0:
             log.warn("could not detect any pulseaudio monitor devices")
             log.warn(" a test source will be used instead")
             src_type = "audiotestsrc"
             default_src_options = {"wave":2, "freq":100, "volume":0.4}
         else:
             monitor_device = monitor_devices.items()[0][0]
             log.info("using pulseaudio source device:")
             log.info(" '%s'", monitor_device)
             src_type = "pulsesrc"
             default_src_options = {"device" : monitor_device}
         src_options = default_src_options
     if src_type not in get_source_plugins():
         raise InitExit(1, "invalid source plugin '%s', valid options are: %s" % (src_type, ",".join(get_source_plugins())))
     matching = [x for x in CODEC_ORDER if (x in codecs and x in get_codecs())]
     log("SoundSource(..) found matching codecs %s", matching)
     if not matching:
         raise InitExit(1, "no matching codecs between arguments '%s' and supported list '%s'" % (csv(codecs), csv(get_codecs().keys())))
     codec = matching[0]
     encoder, fmt = get_encoder_formatter(codec)
     SoundPipeline.__init__(self, codec)
     self.src_type = src_type
     source_str = plugin_str(src_type, src_options)
     #FIXME: this is ugly and relies on the fact that we don't pass any codec options to work!
     encoder_str = plugin_str(encoder, codec_options or ENCODER_DEFAULT_OPTIONS.get(encoder, {}))
     fmt_str = plugin_str(fmt, MUXER_DEFAULT_OPTIONS.get(fmt, {}))
     pipeline_els = [source_str]
     if encoder in ENCODER_NEEDS_AUDIOCONVERT or src_type in SOURCE_NEEDS_AUDIOCONVERT:
         pipeline_els += ["audioconvert"]
     pipeline_els.append("volume name=volume volume=%s" % volume)
     pipeline_els += [encoder_str,
                     fmt_str,
                     APPSINK]
     self.setup_pipeline_and_bus(pipeline_els)
     self.volume = self.pipeline.get_by_name("volume")
     self.sink = self.pipeline.get_by_name("sink")
     try:
         if get_gst_version()<(1,0):
             self.sink.set_property("enable-last-buffer", False)
         else:
             self.sink.set_property("enable-last-sample", False)
     except Exception as e:
         log("failed to disable last buffer: %s", e)
     self.caps = None
     self.skipped_caps = set()
     if JITTER>0:
         self.jitter_queue = Queue()
     try:
         #Gst 1.0:
         self.sink.connect("new-sample", self.on_new_sample)
         self.sink.connect("new-preroll", self.on_new_preroll1)
     except:
         #Gst 0.10:
         self.sink.connect("new-buffer", self.on_new_buffer)
         self.sink.connect("new-preroll", self.on_new_preroll0)
Ejemplo n.º 2
0
 def __init__(self,
              sink_type=None,
              sink_options={},
              codecs=get_decoders(),
              codec_options={},
              volume=1.0):
     if not sink_type:
         sink_type = get_default_sink()
     if sink_type not in get_sink_plugins():
         raise InitExit(1, "invalid sink: %s" % sink_type)
     matching = [
         x for x in CODEC_ORDER if (x in codecs and x in get_decoders())
     ]
     log("SoundSink(..) found matching codecs %s", matching)
     if not matching:
         raise InitExit(
             1,
             "no matching codecs between arguments '%s' and supported list '%s'"
             % (csv(codecs), csv(get_decoders().keys())))
     codec = matching[0]
     decoder, parser, stream_compressor = get_decoder_elements(codec)
     SoundPipeline.__init__(self, codec)
     self.container_format = (parser
                              or "").replace("demux",
                                             "").replace("depay", "")
     self.sink_type = sink_type
     self.stream_compressor = stream_compressor
     log("container format=%s, stream_compressor=%s, sink type=%s",
         self.container_format, self.stream_compressor, self.sink_type)
     self.levels = deque(maxlen=100)
     self.volume = None
     self.src = None
     self.queue = None
     self.normal_volume = volume
     self.target_volume = volume
     self.volume_timer = 0
     self.overruns = 0
     self.underruns = 0
     self.overrun_events = deque(maxlen=100)
     self.queue_state = "starting"
     self.last_data = None
     self.last_underrun = 0
     self.last_overrun = 0
     self.last_max_update = time.time()
     self.last_min_update = time.time()
     self.level_lock = Lock()
     pipeline_els = []
     appsrc_el = [
         "appsrc", "do-timestamp=1", "name=src", "emit-signals=0",
         "block=0", "is-live=0",
         "stream-type=%s" % STREAM_TYPE,
         "format=%s" % BUFFER_FORMAT
     ]
     pipeline_els.append(" ".join(appsrc_el))
     if parser:
         pipeline_els.append(parser)
     if decoder:
         decoder_str = plugin_str(decoder, codec_options)
         pipeline_els.append(decoder_str)
     pipeline_els.append("audioconvert")
     pipeline_els.append("audioresample")
     pipeline_els.append("volume name=volume volume=0")
     if QUEUE_TIME > 0:
         pipeline_els.append(" ".join([
             "queue", "name=queue", "min-threshold-time=0",
             "max-size-buffers=0", "max-size-bytes=0",
             "max-size-time=%s" % QUEUE_TIME,
             "leaky=%s" % QUEUE_LEAK
         ]))
     sink_attributes = SINK_SHARED_DEFAULT_ATTRIBUTES.copy()
     from xpra.sound.gstreamer_util import gst_major_version, get_gst_version
     #anything older than this may cause problems (ie: centos 6.x)
     #because the attributes may not exist
     if get_gst_version() >= (0, 10, 36):
         sink_attributes.update(
             SINK_DEFAULT_ATTRIBUTES.get(gst_major_version,
                                         {}).get(sink_type, {}))
     get_options_cb = DEFAULT_SINK_PLUGIN_OPTIONS.get(
         sink_type.replace("sink", ""))
     if get_options_cb:
         v = get_options_cb()
         log("%s()=%s", get_options_cb, v)
         sink_attributes.update(v)
     sink_attributes.update(sink_options)
     sink_str = plugin_str(sink_type, sink_attributes)
     pipeline_els.append(sink_str)
     if not self.setup_pipeline_and_bus(pipeline_els):
         return
     self.volume = self.pipeline.get_by_name("volume")
     self.src = self.pipeline.get_by_name("src")
     self.queue = self.pipeline.get_by_name("queue")
     if get_gst_version() < (1, ):
         self.add_data = self.add_data0
     else:
         self.add_data = self.add_data1
     if self.queue:
         if not QUEUE_SILENT:
             if get_gst_version() < (1, ):
                 self.queue.connect("overrun", self.queue_overrun0)
                 self.queue.connect("underrun", self.queue_underrun0)
                 self.queue.connect("running", self.queue_running0)
                 self.queue.connect("pushing", self.queue_pushing0)
             else:
                 self.queue.connect("overrun", self.queue_overrun1)
                 self.queue.connect("underrun", self.queue_underrun1)
                 self.queue.connect("running", self.queue_running1)
                 self.queue.connect("pushing", self.queue_pushing1)
         else:
             #older versions may not have the "silent" attribute,
             #in which case we will emit the signals for nothing
             try:
                 self.queue.set_property("silent", False)
             except Exception as e:
                 log("cannot silence the queue %s: %s", self.queue, e)
Ejemplo n.º 3
0
 def __init__(self, src_type=None, src_options={}, codecs=get_codecs(), codec_options={}, volume=1.0):
     if not src_type:
         try:
             from xpra.sound.pulseaudio.pulseaudio_util import get_pa_device_options
             monitor_devices = get_pa_device_options(True, False)
             log.info("found pulseaudio monitor devices: %s", monitor_devices)
         except ImportError as e:
             log.warn("Warning: pulseaudio is not available!")
             log.warn(" %s", e)
             monitor_devices = []
         if len(monitor_devices)==0:
             log.warn("could not detect any pulseaudio monitor devices")
             log.warn(" a test source will be used instead")
             src_type = "audiotestsrc"
             default_src_options = {"wave":2, "freq":100, "volume":0.4}
         else:
             monitor_device = monitor_devices.items()[0][0]
             log.info("using pulseaudio source device:")
             log.info(" '%s'", monitor_device)
             src_type = "pulsesrc"
             default_src_options = {"device" : monitor_device}
         src_options = default_src_options
     if src_type not in get_source_plugins():
         raise InitExit(1, "invalid source plugin '%s', valid options are: %s" % (src_type, ",".join(get_source_plugins())))
     matching = [x for x in CODEC_ORDER if (x in codecs and x in get_codecs())]
     log("SoundSource(..) found matching codecs %s", matching)
     if not matching:
         raise InitExit(1, "no matching codecs between arguments '%s' and supported list '%s'" % (csv(codecs), csv(get_codecs().keys())))
     codec = matching[0]
     encoder, fmt = get_encoder_formatter(codec)
     self.queue = None
     self.caps = None
     self.volume = None
     self.sink = None
     self.src = None
     self.src_type = src_type
     self.buffer_latency = False
     self.jitter_queue = None
     self.file = None
     SoundPipeline.__init__(self, codec)
     src_options["name"] = "src"
     source_str = plugin_str(src_type, src_options)
     #FIXME: this is ugly and relies on the fact that we don't pass any codec options to work!
     encoder_str = plugin_str(encoder, codec_options or get_encoder_default_options(encoder))
     fmt_str = plugin_str(fmt, MUXER_DEFAULT_OPTIONS.get(fmt, {}))
     pipeline_els = [source_str]
     if SOURCE_QUEUE_TIME>0:
         queue_el = ["queue",
                     "name=queue",
                     "min-threshold-time=0",
                     "max-size-buffers=0",
                     "max-size-bytes=0",
                     "max-size-time=%s" % (SOURCE_QUEUE_TIME*MS_TO_NS),
                     "leaky=%s" % GST_QUEUE_LEAK_DOWNSTREAM]
         pipeline_els += [" ".join(queue_el)]
     if encoder in ENCODER_NEEDS_AUDIOCONVERT or src_type in SOURCE_NEEDS_AUDIOCONVERT:
         pipeline_els += ["audioconvert"]
     pipeline_els.append("volume name=volume volume=%s" % volume)
     pipeline_els += [encoder_str,
                     fmt_str,
                     APPSINK]
     if not self.setup_pipeline_and_bus(pipeline_els):
         return
     self.volume = self.pipeline.get_by_name("volume")
     self.sink = self.pipeline.get_by_name("sink")
     if SOURCE_QUEUE_TIME>0:
         self.queue  = self.pipeline.get_by_name("queue")
     if self.queue:
         try:
             self.queue.set_property("silent", True)
         except Exception as e:
             log("cannot make queue silent: %s", e)
     try:
         if get_gst_version()<(1,0):
             self.sink.set_property("enable-last-buffer", False)
         else:
             self.sink.set_property("enable-last-sample", False)
     except Exception as e:
         log("failed to disable last buffer: %s", e)
     self.skipped_caps = set()
     if JITTER>0:
         self.jitter_queue = Queue()
     try:
         #Gst 1.0:
         self.sink.connect("new-sample", self.on_new_sample)
         self.sink.connect("new-preroll", self.on_new_preroll1)
     except:
         #Gst 0.10:
         self.sink.connect("new-buffer", self.on_new_buffer)
         self.sink.connect("new-preroll", self.on_new_preroll0)
     self.src = self.pipeline.get_by_name("src")
     try:
         for x in ("actual-buffer-time", "actual-latency-time"):
             #don't comment this out, it is used to verify the attributes are present:
             gstlog("initial %s: %s", x, self.src.get_property(x))
         self.buffer_latency = True
     except Exception as e:
         log.info("source %s does not support 'buffer-time' or 'latency-time':", self.src_type)
         log.info(" %s", e)
     else:
         #if the env vars have been set, try to honour the settings:
         global BUFFER_TIME, LATENCY_TIME
         if BUFFER_TIME>0:
             if BUFFER_TIME<LATENCY_TIME:
                 log.warn("Warning: latency (%ims) must be lower than the buffer time (%ims)", LATENCY_TIME, BUFFER_TIME)
             else:
                 log("latency tuning for %s, will try to set buffer-time=%i, latency-time=%i", src_type, BUFFER_TIME, LATENCY_TIME)
                 def settime(attr, v):
                     try:
                         cval = self.src.get_property(attr)
                         gstlog("default: %s=%i", attr, cval//1000)
                         if v>=0:
                             self.src.set_property(attr, v*1000)
                             gstlog("overriding with: %s=%i", attr, v)
                     except Exception as e:
                         log.warn("source %s does not support '%s': %s", self.src_type, attr, e)
                 settime("buffer-time", BUFFER_TIME)
                 settime("latency-time", LATENCY_TIME)
     gen = generation.increase()
     if SAVE_TO_FILE is not None:
         parts = codec.split("+")
         if len(parts)>1:
             filename = SAVE_TO_FILE+str(gen)+"-"+parts[0]+".%s" % parts[1]
         else:
             filename = SAVE_TO_FILE+str(gen)+".%s" % codec
         self.file = open(filename, 'wb')
         log.info("saving %s stream to %s", codec, filename)
Ejemplo n.º 4
0
def run_sound(mode, error_cb, options, args):
    """ this function just parses command line arguments to feed into the sound subprocess class,
        which in turn just feeds them into the sound pipeline class (sink.py or src.py)
    """
    from xpra.gtk_common.gobject_compat import want_gtk3
    want_gtk3(True)
    gst = import_gst()
    if not gst:
        return 1
    info = mode.replace("_sound_", "")  #ie: "_sound_record" -> "record"
    from xpra.platform import program_context
    with program_context("Xpra-Audio-%s" % info, "Xpra Audio %s" % info):
        log("run_sound(%s, %s, %s, %s) gst=%s", mode, error_cb, options, args,
            gst)
        if mode == "_sound_record":
            subproc = sound_record
        elif mode == "_sound_play":
            subproc = sound_play
        elif mode == "_sound_query":
            plugins = get_all_plugin_names()
            sources = [x for x in get_source_plugins() if x in plugins]
            sinks = [x for x in get_sink_plugins() if x in plugins]
            from xpra.sound.gstreamer_util import get_gst_version, get_pygst_version
            d = {
                "encoders": can_encode(),
                "decoders": can_decode(),
                "sources": sources,
                "source.default": get_default_source() or "",
                "sinks": sinks,
                "sink.default": get_default_sink() or "",
                "muxers": get_muxers(),
                "demuxers": get_demuxers(),
                "gst.version": [int(x) for x in get_gst_version()],
                "pygst.version": get_pygst_version(),
                "plugins": plugins,
                "python.version": sys.version_info[:3],
                "python.bits": BITS,
            }
            if BUNDLE_METADATA:
                d["bundle-metadata"] = True
            for k, v in d.items():
                if type(v) in (list, tuple):
                    v = ",".join(str(x) for x in v)
                print("%s=%s" % (k, v))
            return 0
        else:
            log.error("unknown mode: %s" % mode)
            return 1
        assert len(args) >= 6, "not enough arguments"

        #the plugin to use (ie: 'pulsesrc' for src.py or 'autoaudiosink' for sink.py)
        plugin = args[2]
        #plugin options (ie: "device=monitor_device,something=value")
        options = parse_simple_dict(args[3])
        #codecs:
        codecs = [x.strip() for x in args[4].split(",")]
        #codec options:
        codec_options = parse_simple_dict(args[5])
        #volume (optional):
        try:
            volume = int(args[6])
        except:
            volume = 1.0

        ss = None
        try:
            ss = subproc(plugin, options, codecs, codec_options, volume)
            ss.start()
            return 0
        except InitExit as e:
            log.error("%s: %s", info, e)
            return e.status
        except InitException as e:
            log.error("%s: %s", info, e)
            return 1
        except Exception:
            log.error("run_sound%s error", (mode, error_cb, options, args),
                      exc_info=True)
            return 1
        finally:
            if ss:
                ss.stop()
Ejemplo n.º 5
0
 def __init__(self, sink_type=None, sink_options={}, codecs=get_codecs(), codec_options={}, volume=1.0):
     if not sink_type:
         sink_type = DEFAULT_SINK
     if sink_type not in SINKS:
         raise InitExit(1, "invalid sink: %s" % sink_type)
     matching = [x for x in CODEC_ORDER if (x in codecs and x in get_codecs())]
     log("SoundSink(..) found matching codecs %s", matching)
     if not matching:
         raise InitExit(1, "no matching codecs between arguments '%s' and supported list '%s'" % (csv(codecs), csv(get_codecs().keys())))
     codec = matching[0]
     decoder, parser = get_decoder_parser(codec)
     SoundPipeline.__init__(self, codec)
     self.sink_type = sink_type
     self.levels = deque(maxlen=100)
     decoder_str = plugin_str(decoder, codec_options)
     pipeline_els = []
     appsrc_el = ["appsrc",
                  "do-timestamp=1",
                  "name=src",
                  "emit-signals=0",
                  "block=0",
                  "is-live=0",
                  "stream-type=stream",
                  "format=%s" % GST_FORMAT_BUFFERS]
     pipeline_els.append(" ".join(appsrc_el))
     pipeline_els.append(parser)
     pipeline_els.append(decoder_str)
     pipeline_els.append("audioconvert")
     pipeline_els.append("audioresample")
     pipeline_els.append("volume name=volume volume=%s" % volume)
     queue_el = ["queue",
                 "name=queue",
                 "min-threshold-time=0",
                 "max-size-buffers=0",
                 "max-size-bytes=0",
                 "max-size-time=%s" % QUEUE_TIME,
                 "leaky=%s" % QUEUE_LEAK]
     if QUEUE_SILENT:
         queue_el.append("silent=%s" % QUEUE_SILENT)
     pipeline_els.append(" ".join(queue_el))
     sink_attributes = SINK_SHARED_DEFAULT_ATTRIBUTES.copy()
     from xpra.sound.gstreamer_util import gst_major_version, get_gst_version
     #anything older than this may cause problems (ie: centos 6.x)
     #because the attributes may not exist
     if get_gst_version()>=(0, 10, 36):
         sink_attributes.update(SINK_DEFAULT_ATTRIBUTES.get(gst_major_version, {}).get(sink_type, {}))
     sink_attributes.update(sink_options)
     sink_str = plugin_str(sink_type, sink_attributes)
     pipeline_els.append(sink_str)
     self.setup_pipeline_and_bus(pipeline_els)
     self.volume = self.pipeline.get_by_name("volume")
     self.src    = self.pipeline.get_by_name("src")
     self.queue  = self.pipeline.get_by_name("queue")
     self.overruns = 0
     self.underruns = 0
     self.overrun_events = deque(maxlen=100)
     self.underrun_events = deque(maxlen=100)
     self.queue_state = "starting"
     self.last_underrun = 0
     self.last_overrun = 0
     self.last_max_update = time.time()
     self.level_lock = Lock()
     if QUEUE_SILENT==0:
         self.queue.connect("overrun", self.queue_overrun)
         self.queue.connect("underrun", self.queue_underrun)
         self.queue.connect("running", self.queue_running)
         self.queue.connect("pushing", self.queue_pushing)
Ejemplo n.º 6
0
    def __init__(self,
                 src_type=None,
                 src_options={},
                 codecs=get_encoders(),
                 codec_options={},
                 volume=1.0):
        if not src_type:
            try:
                from xpra.sound.pulseaudio.pulseaudio_util import get_pa_device_options
                monitor_devices = get_pa_device_options(True, False)
                log.info("found pulseaudio monitor devices: %s",
                         monitor_devices)
            except ImportError as e:
                log.warn("Warning: pulseaudio is not available!")
                log.warn(" %s", e)
                monitor_devices = []
            if len(monitor_devices) == 0:
                log.warn("could not detect any pulseaudio monitor devices")
                log.warn(" a test source will be used instead")
                src_type = "audiotestsrc"
                default_src_options = {"wave": 2, "freq": 100, "volume": 0.4}
            else:
                monitor_device = monitor_devices.items()[0][0]
                log.info("using pulseaudio source device:")
                log.info(" '%s'", monitor_device)
                src_type = "pulsesrc"
                default_src_options = {"device": monitor_device}
            src_options = default_src_options
        if src_type not in get_source_plugins():
            raise InitExit(
                1, "invalid source plugin '%s', valid options are: %s" %
                (src_type, ",".join(get_source_plugins())))
        matching = [
            x for x in CODEC_ORDER if (x in codecs and x in get_encoders())
        ]
        log("SoundSource(..) found matching codecs %s", matching)
        if not matching:
            raise InitExit(
                1,
                "no matching codecs between arguments '%s' and supported list '%s'"
                % (csv(codecs), csv(get_encoders().keys())))
        codec = matching[0]
        encoder, fmt, stream_compressor = get_encoder_elements(codec)
        SoundPipeline.__init__(self, codec)
        self.queue = None
        self.caps = None
        self.volume = None
        self.sink = None
        self.src = None
        self.src_type = src_type
        self.pending_metadata = []
        self.buffer_latency = True
        self.jitter_queue = None
        self.file = None
        self.container_format = (fmt or "").replace("mux",
                                                    "").replace("pay", "")
        self.stream_compressor = stream_compressor
        src_options["name"] = "src"
        source_str = plugin_str(src_type, src_options)
        #FIXME: this is ugly and relies on the fact that we don't pass any codec options to work!
        pipeline_els = [source_str]
        if SOURCE_QUEUE_TIME > 0:
            queue_el = [
                "queue", "name=queue", "min-threshold-time=0",
                "max-size-buffers=0", "max-size-bytes=0",
                "max-size-time=%s" % (SOURCE_QUEUE_TIME * MS_TO_NS),
                "leaky=%s" % GST_QUEUE_LEAK_DOWNSTREAM
            ]
            pipeline_els += [" ".join(queue_el)]
        if encoder in ENCODER_NEEDS_AUDIOCONVERT or src_type in SOURCE_NEEDS_AUDIOCONVERT:
            pipeline_els += ["audioconvert"]
        pipeline_els.append("volume name=volume volume=%s" % volume)
        if encoder:
            encoder_str = plugin_str(
                encoder, codec_options or get_encoder_default_options(encoder))
            pipeline_els.append(encoder_str)
        if fmt:
            fmt_str = plugin_str(fmt, MUXER_DEFAULT_OPTIONS.get(fmt, {}))
            pipeline_els.append(fmt_str)
        pipeline_els.append(APPSINK)
        if not self.setup_pipeline_and_bus(pipeline_els):
            return
        self.volume = self.pipeline.get_by_name("volume")
        self.sink = self.pipeline.get_by_name("sink")
        if SOURCE_QUEUE_TIME > 0:
            self.queue = self.pipeline.get_by_name("queue")
        if self.queue:
            try:
                self.queue.set_property("silent", True)
            except Exception as e:
                log("cannot make queue silent: %s", e)
        try:
            if get_gst_version() < (1, 0):
                self.sink.set_property("enable-last-buffer", False)
            else:
                self.sink.set_property("enable-last-sample", False)
        except Exception as e:
            log("failed to disable last buffer: %s", e)
        self.skipped_caps = set()
        if JITTER > 0:
            self.jitter_queue = Queue()
        try:
            #Gst 1.0:
            self.sink.connect("new-sample", self.on_new_sample)
            self.sink.connect("new-preroll", self.on_new_preroll1)
        except:
            #Gst 0.10:
            self.sink.connect("new-buffer", self.on_new_buffer)
            self.sink.connect("new-preroll", self.on_new_preroll0)
        self.src = self.pipeline.get_by_name("src")
        try:
            for x in ("actual-buffer-time", "actual-latency-time"):
                #don't comment this out, it is used to verify the attributes are present:
                try:
                    gstlog("initial %s: %s", x, self.src.get_property(x))
                except Exception as e:
                    self.buffer_latency = False
        except Exception as e:
            log.info(
                "source %s does not support 'buffer-time' or 'latency-time':",
                self.src_type)
            log.info(" %s", e)
        else:
            #if the env vars have been set, try to honour the settings:
            global BUFFER_TIME, LATENCY_TIME
            if BUFFER_TIME > 0:
                if BUFFER_TIME < LATENCY_TIME:
                    log.warn(
                        "Warning: latency (%ims) must be lower than the buffer time (%ims)",
                        LATENCY_TIME, BUFFER_TIME)
                else:
                    log(
                        "latency tuning for %s, will try to set buffer-time=%i, latency-time=%i",
                        src_type, BUFFER_TIME, LATENCY_TIME)

                    def settime(attr, v):
                        try:
                            cval = self.src.get_property(attr)
                            gstlog("default: %s=%i", attr, cval // 1000)
                            if v >= 0:
                                self.src.set_property(attr, v * 1000)
                                gstlog("overriding with: %s=%i", attr, v)
                        except Exception as e:
                            log.warn("source %s does not support '%s': %s",
                                     self.src_type, attr, e)

                    settime("buffer-time", BUFFER_TIME)
                    settime("latency-time", LATENCY_TIME)
        gen = generation.increase()
        if SAVE_TO_FILE is not None:
            parts = codec.split("+")
            if len(parts) > 1:
                filename = SAVE_TO_FILE + str(
                    gen) + "-" + parts[0] + ".%s" % parts[1]
            else:
                filename = SAVE_TO_FILE + str(gen) + ".%s" % codec
            self.file = open(filename, 'wb')
            log.info("saving %s stream to %s", codec, filename)
Ejemplo n.º 7
0
 def __init__(self, sink_type=None, sink_options={}, codecs=get_decoders(), codec_options={}, volume=1.0):
     if not sink_type:
         sink_type = get_default_sink()
     if sink_type not in get_sink_plugins():
         raise InitExit(1, "invalid sink: %s" % sink_type)
     matching = [x for x in CODEC_ORDER if (x in codecs and x in get_decoders())]
     log("SoundSink(..) found matching codecs %s", matching)
     if not matching:
         raise InitExit(1, "no matching codecs between arguments '%s' and supported list '%s'" % (csv(codecs), csv(get_decoders().keys())))
     codec = matching[0]
     decoder, parser, self.stream_compressor = get_decoder_elements(codec)
     SoundPipeline.__init__(self, codec)
     self.container_format = (parser or "").replace("demux", "").replace("depay", "")
     self.sink_type = sink_type
     self.levels = deque(maxlen=100)
     self.volume = None
     self.src    = None
     self.queue  = None
     self.normal_volume = volume
     self.target_volume = volume
     self.volume_timer = 0
     self.overruns = 0
     self.underruns = 0
     self.overrun_events = deque(maxlen=100)
     self.queue_state = "starting"
     self.last_data = None
     self.last_underrun = 0
     self.last_overrun = 0
     self.last_max_update = time.time()
     self.last_min_update = time.time()
     self.level_lock = Lock()
     pipeline_els = []
     appsrc_el = ["appsrc",
                  "do-timestamp=1",
                  "name=src",
                  "emit-signals=0",
                  "block=0",
                  "is-live=0",
                  "stream-type=%s" % STREAM_TYPE,
                  "format=%s" % BUFFER_FORMAT]
     pipeline_els.append(" ".join(appsrc_el))
     if parser:
         pipeline_els.append(parser)
     if decoder:
         decoder_str = plugin_str(decoder, codec_options)
         pipeline_els.append(decoder_str)
     pipeline_els.append("audioconvert")
     pipeline_els.append("audioresample")
     pipeline_els.append("volume name=volume volume=0")
     if QUEUE_TIME>0:
         pipeline_els.append(" ".join(["queue",
                                       "name=queue",
                                       "min-threshold-time=0",
                                       "max-size-buffers=0",
                                       "max-size-bytes=0",
                                       "max-size-time=%s" % QUEUE_TIME,
                                       "leaky=%s" % QUEUE_LEAK]))
     sink_attributes = SINK_SHARED_DEFAULT_ATTRIBUTES.copy()
     from xpra.sound.gstreamer_util import gst_major_version, get_gst_version
     #anything older than this may cause problems (ie: centos 6.x)
     #because the attributes may not exist
     if get_gst_version()>=(0, 10, 36):
         sink_attributes.update(SINK_DEFAULT_ATTRIBUTES.get(gst_major_version, {}).get(sink_type, {}))
     get_options_cb = DEFAULT_SINK_PLUGIN_OPTIONS.get(sink_type.replace("sink", ""))
     if get_options_cb:
         v = get_options_cb()
         log("%s()=%s", get_options_cb, v)
         sink_attributes.update(v)
     sink_attributes.update(sink_options)
     sink_str = plugin_str(sink_type, sink_attributes)
     pipeline_els.append(sink_str)
     if not self.setup_pipeline_and_bus(pipeline_els):
         return
     self.volume = self.pipeline.get_by_name("volume")
     self.src    = self.pipeline.get_by_name("src")
     self.queue  = self.pipeline.get_by_name("queue")
     if get_gst_version()<(1, ):
         self.add_data = self.add_data0
     else:
         self.add_data = self.add_data1
     if self.queue:
         if not QUEUE_SILENT:
             if get_gst_version()<(1, ):
                 self.queue.connect("overrun", self.queue_overrun0)
                 self.queue.connect("underrun", self.queue_underrun0)
                 self.queue.connect("running", self.queue_running0)
                 self.queue.connect("pushing", self.queue_pushing0)
             else:
                 self.queue.connect("overrun", self.queue_overrun1)
                 self.queue.connect("underrun", self.queue_underrun1)
                 self.queue.connect("running", self.queue_running1)
                 self.queue.connect("pushing", self.queue_pushing1)
         else:
             #older versions may not have the "silent" attribute,
             #in which case we will emit the signals for nothing
             try:
                 self.queue.set_property("silent", False)
             except Exception as e:
                 log("cannot silence the queue %s: %s", self.queue, e)