Exemple #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)
Exemple #2
0
 def do_wrap_socket(tcp_socket):
     assert tcp_socket
     ssllog("do_wrap_socket(%s)", tcp_socket)
     if WIN32:
         #on win32, setting the tcp socket to blocking doesn't work?
         #we still hit the following errors that we need to retry:
         from xpra.net import bytestreams
         bytestreams.CAN_RETRY_EXCEPTIONS = (ssl.SSLWantReadError,
                                             ssl.SSLWantWriteError)
     else:
         tcp_socket.setblocking(True)
     try:
         ssl_sock = wrap_socket(tcp_socket, **kwargs)
     except Exception as e:
         ssllog.debug("wrap_socket(%s, %s)",
                      tcp_socket,
                      kwargs,
                      exc_info=True)
         SSLEOFError = getattr(ssl, "SSLEOFError", None)
         if SSLEOFError and isinstance(e, SSLEOFError):
             return None
         raise InitExit(EXIT_SSL_FAILURE, "Cannot wrap socket %s: %s" %
                        (tcp_socket, e)) from None
     if not server_side:
         try:
             ssl_sock.do_handshake(True)
         except Exception as e:
             ssllog.debug("do_handshake", exc_info=True)
             SSLEOFError = getattr(ssl, "SSLEOFError", None)
             if SSLEOFError and isinstance(e, SSLEOFError):
                 return None
             status = EXIT_SSL_FAILURE
             SSLCertVerificationError = getattr(ssl,
                                                "SSLCertVerificationError",
                                                None)
             if SSLCertVerificationError and isinstance(
                     e, SSLCertVerificationError):
                 try:
                     msg = e.args[1].split(":", 2)[2]
                 except (ValueError, IndexError):
                     msg = str(e)
                 status = EXIT_SSL_CERTIFICATE_VERIFY_FAILURE
                 #ssllog.warn("host failed SSL verification: %s", msg)
             else:
                 msg = str(e)
             raise InitExit(status,
                            "SSL handshake failed: %s" % msg) from None
     return ssl_sock
Exemple #3
0
 def get_encryption_key(self):
     conn = self._protocol._conn
     keydata = parse_encoded_bin_data(conn.options.get("keydata", None))
     cryptolog("get_encryption_key() connection options keydata=%s", ellipsizer(keydata))
     if keydata:
         return keydata
     keyfile = conn.options.get("encryption-keyfile") or conn.options.get("keyfile") or self.encryption_keyfile
     if keyfile:
         if not os.path.isabs(keyfile):
             keyfile = os.path.abspath(keyfile)
         if os.path.exists(keyfile):
             key = filedata_nocrlf(keyfile)
             if key:
                 cryptolog("get_encryption_key() loaded %i bytes from '%s'",
                       len(key or ""), keyfile)
                 return key
             else:
                 cryptolog("get_encryption_key() keyfile '%s' is empty", keyfile)
         else:
             cryptolog("get_encryption_key() file '%s' does not exist", keyfile)
     XPRA_ENCRYPTION_KEY = "XPRA_ENCRYPTION_KEY"
     key = strtobytes(os.environ.get(XPRA_ENCRYPTION_KEY, ''))
     cryptolog("get_encryption_key() got %i bytes from '%s' environment variable",
               len(key or ""), XPRA_ENCRYPTION_KEY)
     if key:
         return key.strip(b"\n\r")
     raise InitExit(EXIT_ENCRYPTION, "no encryption key")
Exemple #4
0
 def get_encryption_key(self):
     conn = self._protocol._conn
     key = conn.options.get("keydata", None)
     cryptolog("get_encryption_key() connection options keydata=%s", key)
     if key:
         #may be specified as hex:
         if key.lower().startswith("0x"):
             import binascii
             return binascii.unhexlify(key[2:])
         return strtobytes(key)
     keyfile = conn.options.get("encryption-keyfile") or conn.options.get(
         "keyfile") or self.encryption_keyfile
     if keyfile:
         if os.path.exists(keyfile):
             key = filedata_nocrlf(keyfile)
             cryptolog("get_encryption_key() loaded %i bytes from '%s'",
                       len(key or ""), keyfile)
             return key
         cryptolog("get_encryption_key() file '%s' does not exist", keyfile)
     XPRA_ENCRYPTION_KEY = "XPRA_ENCRYPTION_KEY"
     key = strtobytes(os.environ.get(XPRA_ENCRYPTION_KEY, ''))
     cryptolog(
         "get_encryption_key() got %i bytes from '%s' environment variable",
         len(key or ""), XPRA_ENCRYPTION_KEY)
     if key:
         return key.strip(b"\n\r")
     raise InitExit(1, "no encryption key")
Exemple #5
0
def ssl_handshake(ssl_sock):
    from xpra.log import Logger
    ssllog = Logger("ssl")
    try:
        ssl_sock.do_handshake(True)
        ssllog.info("SSL handshake complete, %s", ssl_sock.version())
        log_ssl_info(ssl_sock)
    except Exception as e:
        ssllog("do_handshake", exc_info=True)
        log_ssl_info(ssl_sock)
        import ssl
        SSLEOFError = getattr(ssl, "SSLEOFError", None)
        if SSLEOFError and isinstance(e, SSLEOFError):
            return None
        status = EXIT_SSL_FAILURE
        SSLCertVerificationError = getattr(ssl, "SSLCertVerificationError", None)
        if SSLCertVerificationError and isinstance(e, SSLCertVerificationError):
            verify_code = getattr(e, "verify_code", 0)
            ssllog("verify_code=%s", SSL_VERIFY_CODES.get(verify_code, verify_code))
            try:
                msg = getattr(e, "verify_message") or (e.args[1].split(":", 2)[2])
            except (ValueError, IndexError):
                msg = str(e)
            status = EXIT_SSL_CERTIFICATE_VERIFY_FAILURE
            ssllog("host failed SSL verification: %s", msg)
            raise SSLVerifyFailure(status, msg, verify_code, ssl_sock) from None
        raise InitExit(status, "SSL handshake failed: %s" % str(e)) from None
    return ssl_sock
Exemple #6
0
def handle_socket_error(sockpath, sperms, e):
    log = get_network_logger()
    log("socket creation error", exc_info=True)
    if sockpath.startswith("/var/run/xpra") or sockpath.startswith("/run/xpra"):
        log.info("cannot create group socket '%s'", sockpath)
        log.info(" %s", e)
        dirname = sockpath[:sockpath.find("xpra")+len("xpra")]
        if not os.path.exists(dirname):
            log.info(" %s does not exist", dirname)
        #only show extra information if the socket permissions
        #would have been accessible by the group:
        elif POSIX and (sperms & 0o40):
            uid = getuid()
            username = get_username_for_uid(uid)
            groups = get_groups(username)
            log.info(" user '%s' is a member of groups: %s", username, csv(groups) or "no groups!")
            if "xpra" not in groups:
                log.info("  add 'xpra' group membership to enable group socket sharing")
            for x in path_permission_info(dirname):
                log.info("  %s", x)
    elif sockpath.startswith("/var/run/user") or sockpath.startswith("/run/user"):
        log.warn("Warning: cannot create socket '%s':", sockpath)
        log.warn(" %s", e)
        run_user = sockpath.split("/user")[0]+"/user"
        if not os.path.exists(run_user):
            log.warn(" %s does not exist", run_user)
        else:
            log.warn(" ($XDG_RUNTIME_DIR has not been created?)")
    else:
        log.error("Error: failed to create socket '%s':", sockpath)
        log.error(" %s", e)
        raise InitExit(EXIT_SOCKET_CREATION_ERROR,
                       "failed to create socket %s" % sockpath)
Exemple #7
0
 def get_encryption_key(self):
     key = load_binary_file(self.encryption_keyfile)
     if not key:
         key = os.environ.get('XPRA_ENCRYPTION_KEY')
     if not key:
         raise InitExit(1, "no encryption key")
     return key.strip("\n\r")
Exemple #8
0
 def checkstate(sockpath, state):
     if state not in (DotXpra.DEAD, DotXpra.UNKNOWN):
         if state==DotXpra.INACCESSIBLE:
             raise InitException("An xpra server is already running at %s\n" % (sockpath,))
         raise InitExit(EXIT_SERVER_ALREADY_EXISTS,
                        "You already have an xpra server running at %s\n"
                        "  (did you want 'xpra upgrade'?)"
                        % (sockpath,))
Exemple #9
0
def set_autostart(enabled):
    target = get_autostart_file()
    if enabled:
        #find the file to copy there:
        autostart = os.path.join(do_get_resources_dir(), "autostart.desktop")
        if not os.path.exists(autostart):
            raise InitExit(EXIT_FILE_NOT_FOUND,
                           "%s file not found" % autostart)
        copy2(autostart, target)
    else:
        os.unlink(target)
Exemple #10
0
 def get_encryption_key(self):
     key = None
     if os.path.exists(self.encryption_keyfile):
         key = load_binary_file(self.encryption_keyfile)
         cryptolog("get_encryption_key() loaded %i bytes from '%s'", len(key or ""), self.encryption_keyfile)
     if not key:
         XPRA_ENCRYPTION_KEY = "XPRA_ENCRYPTION_KEY"
         key = strtobytes(os.environ.get(XPRA_ENCRYPTION_KEY, ''))
         cryptolog("get_encryption_key() got %i bytes from '%s' environment variable", len(key or ""), XPRA_ENCRYPTION_KEY)
     if not key:
         raise InitExit(1, "no encryption key")
     return key.strip(b"\n\r")
Exemple #11
0
 def __init__(self):
     #sanity check:
     image = CG.CGWindowListCreateImage(CG.CGRectInfinite,
                 CG.kCGWindowListOptionOnScreenOnly,
                 CG.kCGNullWindowID,
                 CG.kCGWindowImageDefault)
     if image is None:
         from xpra.scripts.config import InitExit
         log("cannot grab test screenshot - maybe you need to run this command whilst logged in via the UI")
         raise InitExit(1, "cannot grab pixels from the screen, make sure this command is launched from a GUI session")
     patch_picture_encode()
     self.refresh_count = 0
     self.refresh_rectangle_count = 0
     self.refresh_registered = False
     GTKShadowServerBase.__init__(self)
Exemple #12
0
def setup_vsock_socket(cid, iport):
    log = get_network_logger()
    try:
        from xpra.net.vsock import bind_vsocket     #@UnresolvedImport
        vsock_socket = bind_vsocket(cid=cid, port=iport)
    except Exception as e:
        raise InitExit(EXIT_SOCKET_CREATION_ERROR,
                       "failed to setup vsock socket on %s:%s %s" % (cid, iport, e)) from None
    def cleanup_vsock_socket():
        log.info("closing vsock socket %s:%s", cid, iport)
        try:
            vsock_socket.close()
        except OSError:
            pass
    return "vsock", vsock_socket, (cid, iport), cleanup_vsock_socket
Exemple #13
0
 def get_encryption_key(self):
     key = load_binary_file(self.encryption_keyfile)
     if not key:
         key = os.environ.get('XPRA_ENCRYPTION_KEY')
     if not key and self.password_file:
         key = load_binary_file(self.password_file)
         if key:
             netlog("used password file as encryption key")
     if not key:
         key = os.environ.get('XPRA_PASSWORD')
         if key:
             netlog("used XPRA_PASSWORD as encryption key")
     if key is None:
         raise InitExit(1, "no encryption key")
     return key.strip("\n\r")
Exemple #14
0
 def __init__(self):
     #sanity check:
     check_display()
     image = CG.CGWindowListCreateImage(CG.CGRectInfinite,
                 CG.kCGWindowListOptionOnScreenOnly,
                 CG.kCGNullWindowID,
                 CG.kCGWindowImageDefault)
     if image is None:
         log("cannot grab test screenshot - maybe you need to run this command whilst logged in via the UI")
         raise InitExit(EXIT_FAILURE, "cannot grab pixels from the screen, make sure this command is launched from a GUI session")
     patch_pixels_to_bytes()
     self.refresh_count = 0
     self.refresh_rectangle_count = 0
     self.refresh_registered = False
     super().__init__()
Exemple #15
0
def run_pinentry(extra_args):
    messages = list(extra_args)

    def get_input():
        if not messages:
            return None
        return messages.pop(0)

    def process_output(message, line):
        if line.startswith(b"ERR "):
            log.error("Error: pinentry responded to '%s' with:", message)
            log.error(" %s", line.rstrip(b"\n\r").decode())
        else:
            log("pinentry sent %r", line)

    pinentry_cmd = get_pinentry_command() or "pinentry"
    proc = popen_pinentry(pinentry_cmd)
    if not proc:
        raise InitExit(EXIT_UNSUPPORTED, "cannot run pinentry")
    return do_run_pinentry(proc, get_input, process_output)
Exemple #16
0
def setup_udp_socket(host, iport, socktype="udp"):
    log = get_network_logger()
    try:
        udp_socket = create_udp_socket(host, iport)
    except Exception as e:
        log("create_udp_socket%s", (host, iport), exc_info=True)
        raise InitExit(EXIT_SOCKET_CREATION_ERROR,
                       "failed to setup %s socket on %s:%s %s" % (socktype, host, iport, e)) from None
    def cleanup_udp_socket():
        log.info("closing %s socket %s:%s", socktype, host, iport)
        try:
            udp_socket.close()
        except OSError:
            pass
    if iport==0:
        iport = udp_socket.getsockname()[1]
        log.info("allocated UDP port %i for %s", iport, host)
    log("%s: %s:%s : %s", socktype, host, iport, socket)
    log.info("created UDP socket %s:%s", host, iport)
    return socktype, udp_socket, (host, iport), cleanup_udp_socket
Exemple #17
0
def do_wrap_socket(tcp_socket, context, **kwargs):
    wrap_socket = context.wrap_socket
    assert tcp_socket
    from xpra.log import Logger
    ssllog = Logger("ssl")
    ssllog("do_wrap_socket(%s, %s)", tcp_socket, context)
    import ssl
    if WIN32:
        #on win32, setting the tcp socket to blocking doesn't work?
        #we still hit the following errors that we need to retry:
        from xpra.net import bytestreams
        bytestreams.CAN_RETRY_EXCEPTIONS = (ssl.SSLWantReadError, ssl.SSLWantWriteError)
    else:
        tcp_socket.setblocking(True)
    try:
        ssl_sock = wrap_socket(tcp_socket, **kwargs)
    except Exception as e:
        ssllog.debug("wrap_socket(%s, %s)", tcp_socket, kwargs, exc_info=True)
        SSLEOFError = getattr(ssl, "SSLEOFError", None)
        if SSLEOFError and isinstance(e, SSLEOFError):
            return None
        raise InitExit(EXIT_SSL_FAILURE, "Cannot wrap socket %s: %s" % (tcp_socket, e)) from None
    return ssl_sock
Exemple #18
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)
Exemple #19
0
    def __init__(self,
                 src_type=None,
                 src_options=None,
                 codecs=(),
                 codec_options=None,
                 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 not monitor_devices:
                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)
        super().__init__(codec)
        self.queue = None
        self.caps = None
        self.volume = None
        self.sink = None
        self.src = None
        self.src_type = src_type
        self.timestamp = None
        self.min_timestamp = 0
        self.max_timestamp = 0
        self.pending_metadata = []
        self.buffer_latency = True
        self.jitter_queue = None
        self.container_format = (fmt or "").replace("mux",
                                                    "").replace("pay", "")
        self.stream_compressor = stream_compressor
        if src_options is None:
            src_options = {}
        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]
        log("has plugin(timestamp)=%s", has_plugins("timestamp"))
        if has_plugins("timestamp"):
            pipeline_els.append("timestamp name=timestamp")
        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"]
        if CUTTER_THRESHOLD > 0 and encoder not in ENCODER_CANNOT_USE_CUTTER and not fmt:
            pipeline_els.append(
                "cutter threshold=%.4f run-length=%i pre-length=%i leaky=false name=cutter"
                % (CUTTER_THRESHOLD, CUTTER_RUN_LENGTH * MS_TO_NS,
                   CUTTER_PRE_LENGTH * MS_TO_NS))
            if encoder in CUTTER_NEEDS_CONVERT:
                pipeline_els.append("audioconvert")
            if encoder in CUTTER_NEEDS_RESAMPLE:
                pipeline_els.append("audioresample")
        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.timestamp = self.pipeline.get_by_name("timestamp")
        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)
        self.sink.set_property("enable-last-sample", False)
        self.skipped_caps = set()
        if JITTER > 0:
            self.jitter_queue = Queue()
        #Gst 1.0:
        self.sink.connect("new-sample", self.on_new_sample)
        self.sink.connect("new-preroll", self.on_new_preroll)
        self.src = self.pipeline.get_by_name("src")
        for x in ("actual-buffer-time", "actual-latency-time"):
            try:
                gstlog("initial %s: %s", x, self.src.get_property(x))
            except Exception as e:
                gstlog("no %s property on %s: %s", x, self.src, e)
                self.buffer_latency = False
        #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)
        self.init_file(codec)
Exemple #20
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)
Exemple #21
0
def setup_local_sockets(bind,
                        socket_dir,
                        socket_dirs,
                        display_name,
                        clobber,
                        mmap_group="auto",
                        socket_permissions="600",
                        username="",
                        uid=0,
                        gid=0):
    log = get_network_logger()
    log("setup_local_sockets%s",
        (bind, socket_dir, socket_dirs, display_name, clobber, mmap_group,
         socket_permissions, username, uid, gid))
    if not bind:
        return {}
    if not socket_dir and (not socket_dirs or
                           (len(socket_dirs) == 1 and not socket_dirs[0])):
        if WIN32:
            socket_dirs = [""]
        else:
            raise InitExit(
                EXIT_SOCKET_CREATION_ERROR,
                "at least one socket directory must be set to use unix domain sockets"
            )
    from xpra.platform.dotxpra import DotXpra, norm_makepath
    dotxpra = DotXpra(socket_dir or socket_dirs[0], socket_dirs, username, uid,
                      gid)
    if display_name is not None and not WIN32:
        display_name = normalize_local_display_name(display_name)
    defs = {}
    try:
        sockpaths = {}
        log("setup_local_sockets: bind=%s, dotxpra=%s", bind, dotxpra)
        for b in bind:
            if b in ("none", ""):
                continue
            parts = b.split(",")
            sockpath = parts[0]
            options = {}
            if len(parts) == 2:
                options = parse_simple_dict(parts[1])
            if sockpath == "auto":
                assert display_name is not None
                for sockpath in dotxpra.norm_socket_paths(display_name):
                    sockpaths[sockpath] = options
                log("sockpaths(%s)=%s (uid=%i, gid=%i)", display_name,
                    sockpaths, uid, gid)
            else:
                sockpath = dotxpra.osexpand(sockpath)
                if os.path.isabs(sockpath):
                    pass
                elif sockpath.endswith("/") or (os.path.exists(sockpath)
                                                and os.path.isdir(sockpath)):
                    assert display_name is not None
                    sockpath = os.path.abspath(sockpath)
                    if not os.path.exists(sockpath):
                        os.makedirs(sockpath)
                    sockpath = norm_makepath(sockpath, display_name)
                else:
                    sockpath = dotxpra.socket_path(sockpath)
                sockpaths[sockpath] = options
            assert sockpaths, "no socket paths to try for %s" % b
        #expand and remove duplicate paths:
        tmp = {}
        for tsp, options in sockpaths.items():
            sockpath = dotxpra.osexpand(tsp)
            if sockpath in tmp:
                log.warn("Warning: skipping duplicate bind path %s", sockpath)
                continue
            tmp[sockpath] = options
        sockpaths = tmp
        log("sockpaths=%s", sockpaths)
        #create listeners:
        if WIN32:
            from xpra.platform.win32.namedpipes.listener import NamedPipeListener
            from xpra.platform.win32.dotxpra import PIPE_PATH
            for sockpath, options in sockpaths.items():
                npl = NamedPipeListener(sockpath)
                ppath = sockpath
                if ppath.startswith(PIPE_PATH):
                    ppath = ppath[len(PIPE_PATH):]
                log.info("created named pipe '%s'", ppath)
                defs[("named-pipe", npl, sockpath, npl.stop)] = options
        else:

            def checkstate(sockpath, state):
                if state not in (DotXpra.DEAD, DotXpra.UNKNOWN):
                    if state == DotXpra.INACCESSIBLE:
                        raise InitException(
                            "An xpra server is already running at %s\n" %
                            (sockpath, ))
                    raise InitExit(
                        EXIT_SERVER_ALREADY_EXISTS,
                        "You already have an xpra server running at %s\n"
                        "  (did you want 'xpra upgrade'?)" % (sockpath, ))

            #remove exisiting sockets if clobber is set,
            #otherwise verify there isn't a server already running
            #and create the directories for the sockets:
            unknown = []
            for sockpath in sockpaths:
                if clobber and os.path.exists(sockpath):
                    os.unlink(sockpath)
                else:
                    state = dotxpra.get_server_state(sockpath, 1)
                    log("state(%s)=%s", sockpath, state)
                    checkstate(sockpath, state)
                    if state == dotxpra.UNKNOWN:
                        unknown.append(sockpath)
                d = os.path.dirname(sockpath)
                try:
                    kwargs = {}
                    if d in ("/var/run/xpra", "/run/xpra"):
                        #this is normally done by tmpfiles.d,
                        #but we may need to do it ourselves in some cases:
                        kwargs["mode"] = SOCKET_DIR_MODE
                        xpra_gid = get_group_id(SOCKET_DIR_GROUP)
                        if xpra_gid > 0:
                            kwargs["gid"] = xpra_gid
                    log("creating sockdir=%s, kwargs=%s" % (d, kwargs))
                    dotxpra.mksockdir(d, **kwargs)
                    log("%s permission mask: %s", d, oct(os.stat(d).st_mode))
                except Exception as e:
                    log.warn("Warning: failed to create socket directory '%s'",
                             d)
                    log.warn(" %s", e)
                    del e
            #wait for all the unknown ones:
            log("sockets in unknown state: %s", unknown)
            if unknown:
                #re-probe them using threads so we can do them in parallel:
                threads = []

                def timeout_probe(sockpath):
                    #we need a loop because "DEAD" sockets may return immediately
                    #(ie: when the server is starting up)
                    start = monotonic_time()
                    while monotonic_time() - start < WAIT_PROBE_TIMEOUT:
                        state = dotxpra.get_server_state(
                            sockpath, WAIT_PROBE_TIMEOUT)
                        log("timeout_probe() get_server_state(%s)=%s",
                            sockpath, state)
                        if state not in (DotXpra.UNKNOWN, DotXpra.DEAD):
                            break
                        sleep(1)

                log.warn(
                    "Warning: some of the sockets are in an unknown state:")
                for sockpath in unknown:
                    log.warn(" %s", sockpath)
                    t = start_thread(timeout_probe,
                                     "probe-%s" % sockpath,
                                     daemon=True,
                                     args=(sockpath, ))
                    threads.append(t)
                log.warn(
                    " please wait as we allow the socket probing to timeout")
                #wait for all the threads to do their job:
                for t in threads:
                    t.join(WAIT_PROBE_TIMEOUT + 1)
            if sockpaths:
                #now we can re-check quickly:
                #(they should all be DEAD or UNKNOWN):
                for sockpath in sockpaths:
                    state = dotxpra.get_server_state(sockpath, 1)
                    log("state(%s)=%s", sockpath, state)
                    checkstate(sockpath, state)
                    try:
                        if os.path.exists(sockpath):
                            os.unlink(sockpath)
                    except OSError:
                        pass
                #socket permissions:
                if mmap_group.lower() in TRUE_OPTIONS:
                    #when using the mmap group option, use '660'
                    sperms = 0o660
                else:
                    #parse octal mode given as config option:
                    try:
                        if isinstance(socket_permissions, int):
                            sperms = socket_permissions
                        else:
                            #assume octal string:
                            sperms = int(socket_permissions, 8)
                        assert 0 <= sperms <= 0o777, "invalid socket permission value %s" % oct(
                            sperms)
                    except ValueError:
                        raise ValueError("invalid socket permissions " +
                                         "(must be an octal number): '%s'" %
                                         socket_permissions) from None
                #now try to create all the sockets:
                for sockpath, options in sockpaths.items():
                    #create it:
                    try:
                        sock, cleanup_socket = create_unix_domain_socket(
                            sockpath, sperms)
                        log.info("created unix domain socket '%s'", sockpath)
                        defs[("unix-domain", sock, sockpath,
                              cleanup_socket)] = options
                    except Exception as e:
                        handle_socket_error(sockpath, sperms, e)
                        del e
    except Exception:
        for sock, cleanup_socket in defs.items():
            try:
                cleanup_socket()
            except Exception as e:
                log.error("Error cleaning up socket %s:", sock)
                log.error(" %s", e)
                del e
        raise
    return defs
Exemple #22
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)