Beispiel #1
0
 def __init__(self, src_type=DEFAULT_SRC, src_options={}, codec=MP3, encoder_options={}):
     assert src_type in SOURCES
     encoder, fmt = get_encoder_formatter(codec)
     SoundPipeline.__init__(self, codec)
     self.add_signals(self.__generic_signals__)
     self.src_type = src_type
     source_str = plugin_str(src_type, src_options)
     encoder_str = plugin_str(encoder, encoder_options)
     pipeline_els = [source_str]
     if AUDIOCONVERT:
         pipeline_els += ["audioconvert"]
     if AUDIORESAMPLE:
         pipeline_els += [
                      "audioresample",
                      "audio/x-raw-int,rate=44100,channels=2"]
     pipeline_els += [encoder_str,
                     fmt,
                     "appsink name=sink"]
     self.setup_pipeline_and_bus(pipeline_els)
     self.sink = self.pipeline.get_by_name("sink")
     self.sink.set_property("emit-signals", True)
     self.sink.set_property("max-buffers", 10)
     self.sink.set_property("drop", False)
     self.sink.set_property("sync", True)
     self.sink.set_property("qos", False)
     self.sink.connect("new-buffer", self.on_new_buffer)
     self.sink.connect("new-preroll", self.on_new_preroll)
Beispiel #2
0
 def cleanup(self):
     if self.volume_timer != 0:
         glib.source_remove(self.volume_timer)
         self.volume_timer = 0
     SoundPipeline.cleanup(self)
     self.sink_type = ""
     self.src = None
Beispiel #3
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)
Beispiel #4
0
 def __init__(self, src_type=DEFAULT_SRC, src_options={}, codec=MP3, volume=1.0, encoder_options={}):
     assert src_type in SOURCES
     encoder, fmt = get_encoder_formatter(codec)
     SoundPipeline.__init__(self, codec)
     self.src_type = src_type
     source_str = plugin_str(src_type, src_options)
     encoder_str = plugin_str(encoder, encoder_options)
     fmt_str = plugin_str(fmt, MUXER_DEFAULT_OPTIONS.get(fmt, {}))
     pipeline_els = [source_str]
     if AUDIOCONVERT:
         pipeline_els += ["audioconvert"]
     if AUDIORESAMPLE:
         pipeline_els += [
                      "audioresample",
                      "audio/x-raw-int,rate=44100,channels=2"]
     pipeline_els.append("volume name=volume volume=%s" % volume)
     pipeline_els += [encoder_str,
                     fmt_str,
                     "appsink name=sink"]
     self.setup_pipeline_and_bus(pipeline_els)
     self.volume = self.pipeline.get_by_name("volume")
     self.sink = self.pipeline.get_by_name("sink")
     self.sink.set_property("emit-signals", True)
     self.sink.set_property("max-buffers", 10)
     self.sink.set_property("drop", False)
     self.sink.set_property("sync", True)
     self.sink.set_property("qos", False)
     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)
Beispiel #5
0
 def __init__(self,
              src_type=DEFAULT_SRC,
              src_options={},
              codec=MP3,
              encoder_options={}):
     assert src_type in SOURCES
     encoder, fmt = get_encoder_formatter(codec)
     SoundPipeline.__init__(self, codec)
     self.src_type = src_type
     source_str = plugin_str(src_type, src_options)
     encoder_str = plugin_str(encoder, encoder_options)
     pipeline_els = [source_str]
     if AUDIOCONVERT:
         pipeline_els += ["audioconvert"]
     if AUDIORESAMPLE:
         pipeline_els += [
             "audioresample", "audio/x-raw-int,rate=44100,channels=2"
         ]
     pipeline_els += [encoder_str, fmt, "appsink name=sink"]
     self.setup_pipeline_and_bus(pipeline_els)
     self.sink = self.pipeline.get_by_name("sink")
     self.sink.set_property("emit-signals", True)
     self.sink.set_property("max-buffers", 10)
     self.sink.set_property("drop", False)
     self.sink.set_property("sync", True)
     self.sink.set_property("qos", False)
     self.sink.connect("new-buffer", self.on_new_buffer)
     self.sink.connect("new-preroll", self.on_new_preroll)
Beispiel #6
0
 def cleanup(self):
     if self.volume_timer!=0:
         glib.source_remove(self.volume_timer)
         self.volume_timer = 0
     SoundPipeline.cleanup(self)
     self.sink_type = ""
     self.src = None
Beispiel #7
0
 def __init__(self,
              src_type=DEFAULT_SRC,
              src_options={},
              codec=MP3,
              encoder_options={}):
     assert src_type in SOURCES
     encoders = get_encoders(codec)
     assert len(encoders) > 0, "no encoders found for %s" % codec
     SoundPipeline.__init__(self, codec)
     self.src_type = src_type
     source_str = plugin_str(src_type, src_options)
     encoder = encoders[0]
     encoder_str = plugin_str(encoder, encoder_options)
     pipeline_els = [source_str]
     pipeline_els += [
         "audioconvert", "audioresample", encoder_str, "appsink name=sink"
     ]
     self.setup_pipeline_and_bus(pipeline_els)
     self.sink = self.pipeline.get_by_name("sink")
     self.sink.set_property("emit-signals", True)
     self.sink.set_property("max-buffers", 10)
     self.sink.set_property("drop", False)
     self.sink.set_property("sync", True)
     self.sink.set_property("qos", False)
     self.sink.connect("new-buffer", self.on_new_buffer)
     self.sink.connect("new-preroll", self.on_new_preroll)
Beispiel #8
0
 def cleanup(self):
     SoundPipeline.cleanup(self)
     self.src_type = ""
     self.sink = None
     self.caps = None
     f = self.file
     if f:
         self.file = None
         f.close()
Beispiel #9
0
 def cleanup(self):
     SoundPipeline.cleanup(self)
     self.src_type = ""
     self.sink = None
     self.caps = None
     f = self.file
     if f:
         self.file = None
         f.close()
Beispiel #10
0
    def __init__(self, sink_type=None, sink_options={}, codecs=CODECS, codec_options={}, volume=1.0):
        if not sink_type:
            sink_type = DEFAULT_SINK
        assert sink_type in SINKS, "invalid sink: %s" % sink_type
        matching = [x for x in CODEC_ORDER if (x in codecs and x in CODECS)]
        log("SoundSink(..) found matching codecs %s", matching)
        assert len(matching) > 0, "no matching codecs between arguments %s and supported list %s" % (codecs, CODECS)
        codec = matching[0]
        decoder, parser = get_decoder_parser(codec)
        SoundPipeline.__init__(self, codec)
        self.sink_type = sink_type
        decoder_str = plugin_str(decoder, codec_options)
        pipeline_els = []
        pipeline_els.append(
            "appsrc"
            + " name=src"
            + " emit-signals=0"
            + " block=0"
            + " is-live=0"
            + " stream-type=stream"
            + " format=%s" % GST_FORMAT_BUFFERS
        )
        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=%s" % QUEUE_MIN_TIME,
            "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

        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.queue_state = "starting"
        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)
Beispiel #11
0
 def __init__(self, sink_type=None, sink_options={}, codecs=CODECS, codec_options={}, volume=1.0):
     if not sink_type:
         sink_type = DEFAULT_SINK
     assert sink_type in SINKS, "invalid sink: %s" % sink_type
     matching = [x for x in CODEC_ORDER if (x in codecs and x in CODECS)]
     log("SoundSink(..) found matching codecs %s", matching)
     assert len(matching)>0, "no matching codecs between arguments %s and supported list %s" % (codecs, CODECS)
     codec = matching[0]
     decoder, parser = get_decoder_parser(codec)
     SoundPipeline.__init__(self, codec)
     self.sink_type = sink_type
     decoder_str = plugin_str(decoder, codec_options)
     pipeline_els = []
     pipeline_els.append("appsrc"+
                         " name=src"+
                         " emit-signals=0"+
                         " block=0"+
                         " is-live=0"+
                         " stream-type=stream"+
                         " format=%s" % GST_FORMAT_BUFFERS)
     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=%s" % QUEUE_MIN_TIME,
                 "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
     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.queue_state = "starting"
     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)
Beispiel #12
0
    def __init__(self,
                 sink_type=DEFAULT_SINK,
                 options={},
                 codec=MP3,
                 decoder_options={}):
        assert sink_type in SINKS, "invalid sink: %s" % sink_type
        decoder, parser = get_decoder_parser(codec)
        SoundPipeline.__init__(self, codec)
        self.sink_type = sink_type
        decoder_str = plugin_str(decoder, decoder_options)
        pipeline_els = []
        pipeline_els.append("appsrc name=src")
        pipeline_els.append(parser)
        pipeline_els.append(decoder_str)
        if VOLUME:
            pipeline_els.append("volume name=volume")
        pipeline_els.append("audioconvert")
        pipeline_els.append("audioresample")
        if QUEUE:
            if QUEUE_TIME > 0:
                pipeline_els.append(
                    "queue name=queue max-size-time=%s leaky=%s" %
                    (QUEUE_TIME, QUEUE_LEAK))
            else:
                pipeline_els.append("queue leaky=%s" % QUEUE_LEAK)
        pipeline_els.append(sink_type)
        self.setup_pipeline_and_bus(pipeline_els)
        self.volume = self.pipeline.get_by_name("volume")
        self.src = self.pipeline.get_by_name("src")
        self.src.set_property('emit-signals', True)
        self.src.set_property('stream-type', 'stream')
        self.src.set_property('block', False)
        self.src.set_property('format', 4)
        self.src.set_property('is-live', True)
        if QUEUE:
            self.queue = self.pipeline.get_by_name("queue")

            def overrun(*args):
                debug("sound sink queue overrun")

            def underrun(*args):
                debug("sound sink queue underrun")

            self.queue.connect("overrun", overrun)
            self.queue.connect("underrun", underrun)
        else:
            self.queue = None
        self.src.connect("need-data", self.need_data)
        self.src.connect("enough-data", self.on_enough_data)
Beispiel #13
0
 def get_info(self) -> dict:
     info = SoundPipeline.get_info(self)
     if QUEUE_TIME>0 and self.queue:
         clt = self.queue.get_property("current-level-time")
         qmax = self.queue.get_property("max-size-time")
         qmin = self.queue.get_property("min-threshold-time")
         info["queue"] = {
                          "min"          : qmin//MS_TO_NS,
                          "max"          : qmax//MS_TO_NS,
                          "cur"          : clt//MS_TO_NS,
                          "pct"          : min(QUEUE_TIME, clt)*100//qmax,
                          "overruns"     : self.overruns,
                          "underruns"    : self.underruns,
                          "state"        : self.queue_state,
                          }
     info["sink"] = self.get_element_properties(
         self.sink,
         "buffer-time", "latency-time",
         #"next_sample", "eos_rendering",
         "async", "blocksize",
         "enable-last-sample",
         "max-bitrate", "max-lateness",
         #"processing-deadline",
         "qos", "render-delay", "sync",
         "throttle-time", "ts-offset",
         )
     return info
Beispiel #14
0
 def get_info(self) -> dict:
     info = SoundPipeline.get_info(self)
     if QUEUE_TIME>0 and self.queue:
         clt = self.queue.get_property("current-level-time")
         qmax = self.queue.get_property("max-size-time")
         qmin = self.queue.get_property("min-threshold-time")
         info["queue"] = {
                          "min"          : qmin//MS_TO_NS,
                          "max"          : qmax//MS_TO_NS,
                          "cur"          : clt//MS_TO_NS,
                          "pct"          : min(QUEUE_TIME, clt)*100//qmax,
                          "overruns"     : self.overruns,
                          "underruns"    : self.underruns,
                          "state"        : self.queue_state,
                          }
     sink_info = info.setdefault("sink", {})
     for x in (
         "buffer-time", "latency-time",
         #"next_sample", "eos_rendering",
         "async", "blocksize",
         "enable-last-sample",
         "max-bitrate", "max-lateness", "processing-deadline",
         "qos", "render-delay", "sync",
         "throttle-time", "ts-offset",
         ):
         try:
             v = self.sink.get_property(x)
             if v>=0:
                 sink_info[x] = v
         except Exception as e:
             log.warn("Warning: %s", e)
     return info
Beispiel #15
0
 def get_info(self) -> dict:
     info = SoundPipeline.get_info(self)
     if self.queue:
         info["queue"] = {
             "cur":
             self.queue.get_property("current-level-time") // MS_TO_NS
         }
     if CUTTER_THRESHOLD > 0 and (self.min_timestamp or self.max_timestamp):
         info["cutter.min-timestamp"] = self.min_timestamp
         info["cutter.max-timestamp"] = self.max_timestamp
     if self.buffer_latency:
         for x in ("actual-buffer-time", "actual-latency-time"):
             v = self.src.get_property(x)
             if v >= 0:
                 info[x] = v
     src_info = info.setdefault("src", {})
     for x in (
             "actual-buffer-time",
             "actual-latency-time",
             "buffer-time",
             "latency-time",
             "provide-clock",
     ):
         try:
             v = self.src.get_property(x)
             if v >= 0:
                 src_info[x] = v
         except Exception as e:
             log.warn("Warning: %s", e)
     return info
Beispiel #16
0
 def get_info(self):
     info = SoundPipeline.get_info(self)
     if QUEUE_TIME>0:
         clt = self.queue.get_property("current-level-time")
         info["queue.used_pct"] = int(min(QUEUE_TIME, clt)*100.0/QUEUE_TIME)
         info["queue.overruns"] = self.overruns
         info["queue.state"] = self.queue_state
     return info
Beispiel #17
0
    def __init__(self, sink_type=DEFAULT_SINK, options={}, codec=MP3, decoder_options={}):
        assert sink_type in SINKS, "invalid sink: %s" % sink_type
        decoder, parser = get_decoder_parser(codec)
        SoundPipeline.__init__(self, codec)
        self.sink_type = sink_type
        decoder_str = plugin_str(decoder, decoder_options)
        pipeline_els = []
        pipeline_els.append("appsrc"+
                            " name=src"+
                            " max-bytes=32768"+
                            " emit-signals=0"+
                            " block=0"+
                            " is-live=0"+
                            " stream-type=stream"+
                            " format=4")
        pipeline_els.append(parser)
        pipeline_els.append(decoder_str)
        pipeline_els.append("audioconvert")
        pipeline_els.append("audioresample")
        queue_el =  ["queue",
                    "name=queue",
                    "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))
        pipeline_els.append(sink_type)
        self.setup_pipeline_and_bus(pipeline_els)
        self.src = self.pipeline.get_by_name("src")
        self.queue = self.pipeline.get_by_name("queue")
        self.overruns = 0
        self.queue_state = "starting"
        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)
        if FAKE_OVERRUN>0:
 	    def fake_overrun(*args):
 	        self.emit("overrun", 500)
 	    gobject.timeout_add(FAKE_OVERRUN*1000, fake_overrun)
Beispiel #18
0
 def get_info(self):
     info = SoundPipeline.get_info(self)
     if self.queue:
         info["queue"] = {"cur" : self.queue.get_property("current-level-time")//MS_TO_NS}
     if self.buffer_latency:
         for x in ("actual-buffer-time", "actual-latency-time"):
             v = self.src.get_property(x)
             if v>=0:
                 info[x] = v
     return info
Beispiel #19
0
 def get_info(self):
     info = SoundPipeline.get_info(self)
     if self.queue:
         info["queue"] = {"cur" : self.queue.get_property("current-level-time")//MS_TO_NS}
     if self.buffer_latency:
         for x in ("actual-buffer-time", "actual-latency-time"):
             v = self.src.get_property(x)
             if v>=0:
                 info[x] = v
     return info
Beispiel #20
0
 def get_info(self):
     info = SoundPipeline.get_info(self)
     if QUEUE_TIME>0:
         clt = self.queue.get_property("current-level-time")
         updict(info, "queue", {
             "time"          : int(QUEUE_TIME/MS_TO_NS),
             "min_time"      : int(QUEUE_MIN_TIME/MS_TO_NS),
             "used_pct"      : int(min(QUEUE_TIME, clt)*100.0/QUEUE_TIME),
             "used"          : int(clt/MS_TO_NS),
             "overruns"      : self.overruns,
             "state"         : self.queue_state})
     return info
Beispiel #21
0
 def __init__(self, sink_type=DEFAULT_SINK, options={}, codec=MP3, decoder_options={}):
     assert sink_type in SINKS, "invalid sink: %s" % sink_type
     decoder, parser = get_decoder_parser(codec)
     SoundPipeline.__init__(self, codec)
     self.sink_type = sink_type
     decoder_str = plugin_str(decoder, decoder_options)
     pipeline_els = []
     pipeline_els.append("appsrc name=src")
     pipeline_els.append(parser)
     pipeline_els.append(decoder_str)
     if VOLUME:
         pipeline_els.append("volume name=volume")
     pipeline_els.append("audioconvert")
     pipeline_els.append("audioresample")
     if QUEUE:
         if QUEUE_TIME>0:
             pipeline_els.append("queue name=queue max-size-time=%s leaky=%s" % (QUEUE_TIME, QUEUE_LEAK))
         else:
             pipeline_els.append("queue leaky=%s" % QUEUE_LEAK)
     pipeline_els.append(sink_type)
     self.setup_pipeline_and_bus(pipeline_els)
     self.volume = self.pipeline.get_by_name("volume")
     self.src = self.pipeline.get_by_name("src")
     self.src.set_property('emit-signals', True)
     self.src.set_property('stream-type', 'stream')
     self.src.set_property('block', False)
     self.src.set_property('format', 4)
     self.src.set_property('is-live', True)
     if QUEUE:
         self.queue = self.pipeline.get_by_name("queue")
         def overrun(*args):
             debug("sound sink queue overrun")
         def underrun(*args):
             debug("sound sink queue underrun")
         self.queue.connect("overrun", overrun)
         self.queue.connect("underrun", underrun)
     else:
         self.queue = None
     self.src.connect("need-data", self.need_data)
     self.src.connect("enough-data", self.on_enough_data)
Beispiel #22
0
 def __init__(self, sink_type=DEFAULT_SINK, options={}, codec=MP3, decoder_options={}):
     assert sink_type in SINKS, "invalid sink: %s" % sink_type
     decoder, parser = get_decoder_parser(codec)
     SoundPipeline.__init__(self, codec)
     self.add_signals(self.__generic_signals__)
     self.sink_type = sink_type
     decoder_str = plugin_str(decoder, decoder_options)
     pipeline_els = []
     pipeline_els.append("appsrc"+
                         " name=src"+
                         " max-bytes=32768"+
                         " emit-signals=0"+
                         " block=0"+
                         " is-live=0"+
                         " stream-type=stream"+
                         " format=4")
     pipeline_els.append(parser)
     pipeline_els.append(decoder_str)
     pipeline_els.append("audioconvert")
     pipeline_els.append("audioresample")
     queue_el =  "queue" + \
                 " name=queue"+ \
                 " 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(queue_el)
     pipeline_els.append(sink_type)
     self.setup_pipeline_and_bus(pipeline_els)
     self.src = self.pipeline.get_by_name("src")
     self.queue = self.pipeline.get_by_name("queue")
     self.overruns = 0
     self.queue_state = "starting"
     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)
Beispiel #23
0
 def get_info(self) -> dict:
     info = SoundPipeline.get_info(self)
     if self.queue:
         info["queue"] = {"cur" : self.queue.get_property("current-level-time")//MS_TO_NS}
     if CUTTER_THRESHOLD>0 and (self.min_timestamp or self.max_timestamp):
         info["cutter.min-timestamp"] = self.min_timestamp
         info["cutter.max-timestamp"] = self.max_timestamp
     if self.buffer_latency:
         for x in ("actual-buffer-time", "actual-latency-time"):
             v = self.src.get_property(x)
             if v>=0:
                 info[x] = v
     return info
Beispiel #24
0
 def __init__(self, src_type=DEFAULT_SRC, src_options={}, codec=MP3, encoder_options={}):
     assert src_type in SOURCES
     encoders = get_encoders(codec)
     assert len(encoders)>0, "no encoders found for %s" % codec
     SoundPipeline.__init__(self, codec)
     self.src_type = src_type
     source_str = plugin_str(src_type, src_options)
     encoder = encoders[0]
     encoder_str = plugin_str(encoder, encoder_options)
     pipeline_els = [source_str]
     pipeline_els += ["audioconvert",
                      "audioresample",
                     encoder_str,
                     "appsink name=sink"]
     self.setup_pipeline_and_bus(pipeline_els)
     self.sink = self.pipeline.get_by_name("sink")
     self.sink.set_property("emit-signals", True)
     self.sink.set_property("max-buffers", 10)
     self.sink.set_property("drop", False)
     self.sink.set_property("sync", True)
     self.sink.set_property("qos", False)
     self.sink.connect("new-buffer", self.on_new_buffer)
     self.sink.connect("new-preroll", self.on_new_preroll)
Beispiel #25
0
 def get_info(self):
     info = SoundPipeline.get_info(self)
     if QUEUE_TIME>0:
         clt = self.queue.get_property("current-level-time")
         qmax = self.queue.get_property("max-size-time")
         qmin = self.queue.get_property("min-threshold-time")
         updict(info, "queue", {
             "min"           : qmin//MS_TO_NS,
             "max"           : qmax//MS_TO_NS,
             "cur"           : clt//MS_TO_NS,
             "pct"           : min(QUEUE_TIME, clt)*100//qmax,
             "overruns"      : self.overruns,
             "underruns"     : self.underruns,
             "state"         : self.queue_state})
     return info
Beispiel #26
0
 def get_info(self):
     info = SoundPipeline.get_info(self)
     if QUEUE_TIME > 0:
         clt = self.queue.get_property("current-level-time")
         updict(
             info,
             "queue",
             {
                 "time": int(QUEUE_TIME / MS_TO_NS),
                 "min_time": int(QUEUE_MIN_TIME / MS_TO_NS),
                 "used_pct": int(min(QUEUE_TIME, clt) * 100.0 / QUEUE_TIME),
                 "used": int(clt / MS_TO_NS),
                 "overruns": self.overruns,
                 "state": self.queue_state,
             },
         )
     return info
Beispiel #27
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)
     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.level_lock = Lock()
     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=%s" % STREAM_TYPE,
                  "format=%s" % BUFFER_FORMAT]
     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=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)
Beispiel #28
0
 def cleanup(self):
     SoundPipeline.cleanup(self)
     self.sink_type = ""
     self.src = None
Beispiel #29
0
 def __init__(self, src_type=None, src_options={}, codecs=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 - will use a test source")
             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: %s", monitor_device)
             src_type = "pulsesrc"
             default_src_options = {"device" : monitor_device}
         src_options = default_src_options
         src_options.update(src_options)
     assert src_type in get_source_plugins(), "invalid source plugin '%s'" % src_type
     matching = [x for x in CODEC_ORDER if (x in codecs and x in CODECS)]
     log("SoundSource(..) found matching codecs %s", matching)
     assert len(matching)>0, "no matching codecs between arguments %s and supported list %s" % (codecs, CODECS)
     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)
     encoder_str = plugin_str(encoder, codec_options)
     fmt_str = plugin_str(fmt, MUXER_DEFAULT_OPTIONS.get(fmt, {}))
     pipeline_els = [source_str]
     if AUDIOCONVERT:
         pipeline_els += ["audioconvert"]
     if AUDIORESAMPLE:
         pipeline_els += [
                      "audioresample",
                      "audio/x-raw-int,rate=44100,channels=2"]
     pipeline_els.append("volume name=volume volume=%s" % volume)
     if QUEUE_TIME>0:
         queue_el =  ["queue",
                      "name=queue",
                      "max-size-buffers=0",
                      "max-size-bytes=0",
                      "max-size-time=%s" % QUEUE_TIME,
                      "leaky=%s" % QUEUE_LEAK]
         pipeline_els.append(" ".join(queue_el))
     pipeline_els += [encoder_str,
                     fmt_str,
                     "appsink name=sink"]
     self.setup_pipeline_and_bus(pipeline_els)
     self.volume = self.pipeline.get_by_name("volume")
     self.sink = self.pipeline.get_by_name("sink")
     self.sink.set_property("emit-signals", True)
     self.sink.set_property("max-buffers", 10)       #0?
     self.sink.set_property("drop", False)
     self.sink.set_property("sync", True)            #False?
     self.sink.set_property("qos", False)
     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)
Beispiel #30
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)
Beispiel #31
0
 def start(self):
     SoundPipeline.start(self)
     self.timeout_add(UNMUTE_DELAY, self.start_adjust_volume)
Beispiel #32
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()
     #anything older than this may cause problems (ie: centos 6.x)
     #because the attributes may not exist
     sink_attributes.update(SINK_DEFAULT_ATTRIBUTES.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 self.queue:
         if QUEUE_SILENT:
             self.queue.set_property("silent", False)
         else:
             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)
Beispiel #33
0
 def cleanup(self):
     SoundPipeline.cleanup(self)
     self.sink_type = ""
     self.src = None
Beispiel #34
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)
Beispiel #35
0
 def start(self):
     SoundPipeline.start(self)
     self.timeout_add(UNMUTE_DELAY, self.start_adjust_volume)
Beispiel #36
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)
Beispiel #37
0
 def cleanup(self):
     SoundPipeline.cleanup(self)
     self.src_type = ""
     self.sink = None
     self.caps = None
Beispiel #38
0
 def cleanup(self):
     SoundPipeline.cleanup(self)
     self.cancel_volume_timer()
     self.sink_type = ""
     self.src = None
Beispiel #39
0
 def get_info(self):
     info = SoundPipeline.get_info(self)
     if self.caps:
         info["caps"] = self.caps
     return info
Beispiel #40
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.refill = True
     self.last_max_update = monotonic_time()
     self.last_min_update = monotonic_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")
     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
         ]))
     pipeline_els.append("volume name=volume volume=0")
     sink_attributes = SINK_SHARED_DEFAULT_ATTRIBUTES.copy()
     #anything older than this may cause problems (ie: centos 6.x)
     #because the attributes may not exist
     sink_attributes.update(SINK_DEFAULT_ATTRIBUTES.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 self.queue:
         if QUEUE_SILENT:
             self.queue.set_property("silent", False)
         else:
             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)
Beispiel #41
0
 def __init__(self,
              src_type=None,
              src_options={},
              codecs=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 - will use a test source"
             )
             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: %s", monitor_device)
             src_type = "pulsesrc"
             default_src_options = {"device": monitor_device}
         src_options = default_src_options
         src_options.update(src_options)
     assert src_type in get_source_plugins(
     ), "invalid source plugin '%s'" % src_type
     matching = [x for x in CODEC_ORDER if (x in codecs and x in CODECS)]
     log("SoundSource(..) found matching codecs %s", matching)
     assert len(
         matching
     ) > 0, "no matching codecs between arguments %s and supported list %s" % (
         codecs, CODECS)
     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)
     encoder_str = plugin_str(encoder, codec_options)
     fmt_str = plugin_str(fmt, MUXER_DEFAULT_OPTIONS.get(fmt, {}))
     pipeline_els = [source_str]
     if AUDIOCONVERT:
         pipeline_els += ["audioconvert"]
     if AUDIORESAMPLE:
         pipeline_els += [
             "audioresample", "audio/x-raw-int,rate=44100,channels=2"
         ]
     pipeline_els.append("volume name=volume volume=%s" % volume)
     if QUEUE_TIME > 0:
         queue_el = [
             "queue", "name=queue", "max-size-buffers=0",
             "max-size-bytes=0",
             "max-size-time=%s" % QUEUE_TIME,
             "leaky=%s" % QUEUE_LEAK
         ]
         pipeline_els.append(" ".join(queue_el))
     pipeline_els += [encoder_str, fmt_str, "appsink name=sink"]
     self.setup_pipeline_and_bus(pipeline_els)
     self.volume = self.pipeline.get_by_name("volume")
     self.sink = self.pipeline.get_by_name("sink")
     self.sink.set_property("emit-signals", True)
     self.sink.set_property("max-buffers", 10)  #0?
     self.sink.set_property("drop", False)
     self.sink.set_property("sync", True)  #False?
     self.sink.set_property("qos", False)
     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)