def stop(self, reason="terminating", skip_proto=None): log("stop(%s, %s)", reason, skip_proto) log.info("stopping proxy instance: %s", reason) self.exit = True try: self.control_socket.close() except: pass csc = self.control_socket_cleanup if csc: self.control_socket_cleanup = None csc() self.main_queue.put(None) #empty the main queue: q = Queue() q.put(None) self.main_queue = q #empty the encode queue: q = Queue() q.put(None) self.encode_queue = q for proto in (self.client_protocol, self.server_protocol): if proto and proto != skip_proto: log("sending disconnect to %s", proto) proto.send_disconnect([SERVER_SHUTDOWN, reason])
def stop(self, reason="proxy terminating", skip_proto=None): log.info("stop(%s, %s)", reason, skip_proto) self.exit = True if self.control_socket_path: try: os.unlink(self.control_socket_path) except: pass self.control_socket_path = None try: self.control_socket.close() except: pass self.main_queue.put(None) #empty the main queue: q = Queue() q.put(None) self.main_queue = q #empty the encode queue: q = Queue() q.put(None) self.encode_queue = q for proto in (self.client_protocol, self.server_protocol): if proto and proto != skip_proto: log("sending disconnect to %s", proto) proto.flush_then_close(["disconnect", SERVER_SHUTDOWN, reason])
def run(self): log.info("started %s", self) log.info(" for client %s", self.client_protocol._conn) log.info(" and server %s", self.server_protocol._conn) self.video_init() #setup protocol wrappers: self.server_packets = Queue(PROXY_QUEUE_SIZE) self.client_packets = Queue(PROXY_QUEUE_SIZE) #server connection tweaks: for x in (b"input-devices", b"draw", b"window-icon", b"keymap-changed", b"server-settings"): self.server_protocol.large_packets.append(x) if self.caps.boolget("file-transfer"): for x in (b"send-file", b"send-file-chunk"): self.server_protocol.large_packets.append(x) self.client_protocol.large_packets.append(x) self.server_protocol.set_compression_level( self.session_options.get("compression_level", 0)) self.server_protocol.enable_default_encoder() self.lost_windows = set() self.encode_queue = Queue() self.encode_thread = start_thread(self.encode_loop, "encode") self.start_network_threads() if self.caps.boolget("ping-echo-sourceid"): self.schedule_client_ping() self.send_hello()
def __init__(self, scheduler, conn, process_packet_cb, get_packet_cb=None): """ You must call this constructor and source_has_more() from the main thread. """ assert scheduler is not None assert conn is not None self.timeout_add = scheduler.timeout_add self.idle_add = scheduler.idle_add self._conn = conn if FAKE_JITTER > 0: from xpra.net.fake_jitter import FakeJitter fj = FakeJitter(self.timeout_add, process_packet_cb) self._process_packet_cb = fj.process_packet_cb else: self._process_packet_cb = process_packet_cb self._write_queue = Queue(1) self._read_queue = Queue(20) self._read_queue_put = self.read_queue_put # Invariant: if .source is None, then _source_has_more == False self._get_packet_cb = get_packet_cb #counters: self.input_stats = {} self.input_packetcount = 0 self.input_raw_packetcount = 0 self.output_stats = {} self.output_packetcount = 0 self.output_raw_packetcount = 0 #initial value which may get increased by client/server after handshake: self.max_packet_size = 256 * 1024 self.abs_max_packet_size = 256 * 1024 * 1024 self.large_packets = ["hello", "window-metadata", "sound-data"] self.send_aliases = {} self.receive_aliases = {} self._log_stats = None #None here means auto-detect self._closed = False self.encoder = "none" self._encoder = self.noencode self.compressor = "none" self._compress = compression.nocompress self.compression_level = 0 self.cipher_in = None self.cipher_in_name = None self.cipher_in_block_size = 0 self.cipher_in_padding = INITIAL_PADDING self.cipher_out = None self.cipher_out_name = None self.cipher_out_block_size = 0 self.cipher_out_padding = INITIAL_PADDING self._write_lock = Lock() from xpra.make_thread import make_thread self._write_thread = make_thread(self._write_thread_loop, "write", daemon=True) self._read_thread = make_thread(self._read_thread_loop, "read", daemon=True) self._read_parser_thread = None #started when needed self._write_format_thread = None #started when needed self._source_has_more = Event()
def run(self): debug("ProxyProcess.run() pid=%s, uid=%s, gid=%s", os.getpid(), os.getuid(), os.getgid()) #change uid and gid: if os.getgid() != self.gid: os.setgid(self.gid) if os.getuid() != self.uid: os.setuid(self.uid) debug("ProxyProcess.run() new uid=%s, gid=%s", os.getuid(), os.getgid()) if self.env_options: #TODO: whitelist env update? os.environ.update(self.env_options) log.info("new proxy started for client %s and server %s", self.client_conn, self.server_conn) if not USE_THREADING: signal.signal(signal.SIGTERM, self.signal_quit) signal.signal(signal.SIGINT, self.signal_quit) debug("registered signal handler %s", self.signal_quit) make_daemon_thread(self.server_message_queue, "server message queue").start() self.main_queue = Queue() #setup protocol wrappers: self.server_packets = Queue(PROXY_QUEUE_SIZE) self.client_packets = Queue(PROXY_QUEUE_SIZE) self.client_protocol = Protocol(self, self.client_conn, self.process_client_packet, self.get_client_packet) self.client_protocol.restore_state(self.client_state) self.server_protocol = Protocol(self, self.server_conn, self.process_server_packet, self.get_server_packet) #server connection tweaks: self.server_protocol.large_packets.append("draw") self.server_protocol.large_packets.append("keymap-changed") self.server_protocol.large_packets.append("server-settings") self.server_protocol.set_compression_level( self.session_options.get("compression_level", 0)) debug("starting network threads") self.server_protocol.start() self.client_protocol.start() #forward the hello packet: hello_packet = ("hello", self.filter_client_caps(self.caps)) self.queue_server_packet(hello_packet) try: try: self.run_queue() except KeyboardInterrupt, e: self.stop(str(e)) finally: debug("ProxyProcess.run() ending %s", os.getpid())
def __init__(self, scheduler, conn, process_packet_cb, get_packet_cb=None): """ You must call this constructor and source_has_more() from the main thread. """ assert scheduler is not None assert conn is not None self.timeout_add = scheduler.timeout_add self.idle_add = scheduler.idle_add self._conn = conn if FAKE_JITTER > 0: fj = FakeJitter(self.timeout_add, process_packet_cb) self._process_packet_cb = fj.process_packet_cb else: self._process_packet_cb = process_packet_cb self._write_queue = Queue(1) self._read_queue = Queue(20) # Invariant: if .source is None, then _source_has_more == False self._get_packet_cb = get_packet_cb #counters: self.input_stats = {} self.input_packetcount = 0 self.input_raw_packetcount = 0 self.output_stats = {} self.output_packetcount = 0 self.output_raw_packetcount = 0 #initial value which may get increased by client/server after handshake: self.max_packet_size = 32 * 1024 self.abs_max_packet_size = 256 * 1024 * 1024 self.large_packets = ["hello"] self.send_aliases = {} self.receive_aliases = {} self._log_stats = None #None here means auto-detect self._closed = False self._encoder = self.noencode self._compress = zcompress self.compression_level = 0 self.cipher_in = None self.cipher_in_name = None self.cipher_in_block_size = 0 self.cipher_out = None self.cipher_out_name = None self.cipher_out_block_size = 0 self._write_lock = Lock() self._write_thread = make_daemon_thread(self._write_thread_loop, "write") self._read_thread = make_daemon_thread(self._read_thread_loop, "read") self._read_parser_thread = make_daemon_thread( self._read_parse_thread_loop, "parse") self._write_format_thread = make_daemon_thread( self._write_format_thread_loop, "format") self._source_has_more = threading.Event() self.enable_default_encoder()
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)
def __init__(self, core_encodings, encodings, default_encoding, scaling_control, default_quality, default_min_quality, default_speed, default_min_speed): log("ServerSource%s", (core_encodings, encodings, default_encoding, scaling_control, default_quality, default_min_quality, default_speed, default_min_speed)) self.server_core_encodings = core_encodings self.server_encodings = encodings self.default_encoding = default_encoding self.scaling_control = scaling_control self.default_quality = default_quality #default encoding quality for lossy encodings self.default_min_quality = default_min_quality #default minimum encoding quality self.default_speed = default_speed #encoding speed (only used by x264) self.default_min_speed = default_min_speed #default minimum encoding speed self.default_batch_config = DamageBatchConfig( ) #contains default values, some of which may be supplied by the client self.global_batch_config = self.default_batch_config.clone( ) #global batch config self.vrefresh = -1 self.supports_transparency = False self.encoding = None #the default encoding for all windows self.encodings = () #all the encodings supported by the client self.core_encodings = () self.window_icon_encodings = ["premult_argb32"] self.rgb_formats = ("RGB", ) self.encoding_options = typedict() self.icons_encoding_options = typedict() self.default_encoding_options = typedict() self.auto_refresh_delay = 0 self.zlib = True self.lz4 = use_lz4 self.lzo = use_lzo #for managing the recalculate_delays work: self.calculate_window_pixels = {} self.calculate_window_ids = set() self.calculate_timer = 0 self.calculate_last_time = 0 #if we "proxy video", we will modify the video helper to add #new encoders, so we must make a deep copy to preserve the original #which may be used by other clients (other ServerSource instances) self.video_helper = getVideoHelper().clone() # the queues of damage requests we work through: self.encode_work_queue = Queue( ) #holds functions to call to compress data (pixels, clipboard) #items placed in this queue are picked off by the "encode" thread, #the functions should add the packets they generate to the 'packet_queue' self.packet_queue = deque( ) #holds actual packets ready for sending (already encoded) #these packets are picked off by the "protocol" via 'next_packet()' #format: packet, wid, pixels, start_send_cb, end_send_cb #(only packet is required - the rest can be 0/None for clipboard packets) self.encode_thread = start_thread(self.encode_loop, "encode")
def __init__(self, scheduler, conn, auth, process_packet_cb, get_rfb_pixelformat, session_name="Xpra"): """ You must call this constructor and source_has_more() from the main thread. """ assert scheduler is not None assert conn is not None self.timeout_add = scheduler.timeout_add self.idle_add = scheduler.idle_add self._conn = conn self._authenticator = auth self._process_packet_cb = process_packet_cb self._get_rfb_pixelformat = get_rfb_pixelformat self.session_name = session_name self._write_queue = Queue() self._buffer = b"" self._challenge = None self.share = False #counters: self.input_packetcount = 0 self.input_raw_packetcount = 0 self.output_packetcount = 0 self.output_raw_packetcount = 0 self._protocol_version = () self._closed = False self._packet_parser = self._parse_protocol_handshake self._write_thread = None self._read_thread = make_thread(self._read_thread_loop, "read", daemon=True)
def terminate_queue_threads(self): log("terminate_queue_threads()") #the format thread will exit: self._get_packet_cb = None self._source_has_more.set() #make all the queue based threads exit by adding the empty marker: exit_queue = Queue() for _ in range(10): #just 2 should be enough! exit_queue.put(None) try: owq = self._write_queue self._write_queue = exit_queue #discard all elements in the old queue and push the None marker: try: while owq.qsize() > 0: owq.read(False) except: pass owq.put_nowait(None) except: pass try: orq = self._read_queue self._read_queue = exit_queue #discard all elements in the old queue and push the None marker: try: while orq.qsize() > 0: orq.read(False) except: pass orq.put_nowait(None) except: pass #just in case the read thread is waiting again: self._source_has_more.set()
def start_tcp_proxy(self, proto, data): log("start_tcp_proxy(%s, %s)", proto, data[:10]) #any buffers read after we steal the connection will be placed in this temporary queue: temp_read_buffer = Queue() client_connection = proto.steal_connection(temp_read_buffer.put) try: self._potential_protocols.remove(proto) except: pass #might already have been removed by now #connect to web server: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) host, port = self._tcp_proxy.split(":", 1) try: web_server_connection = _socket_connect(sock, (host, int(port)), "web-proxy-for-%s" % proto, "tcp") except: log.warn("failed to connect to proxy: %s:%s", host, port) proto.gibberish("invalid packet header", data) return log("proxy connected to tcp server at %s:%s : %s", host, port, web_server_connection) sock.settimeout(self._socket_timeout) ioe = proto.wait_for_io_threads_exit(0.5 + self._socket_timeout) if not ioe: log.warn("proxy failed to stop all existing network threads!") self.disconnect_protocol(proto, "internal threading error") return #now that we own it, we can start it again: client_connection.set_active(True) #and we can use blocking sockets: self.set_socket_timeout(client_connection, None) #prevent deadlocks on exit: sock.settimeout(1) log("pushing initial buffer to its new destination: %s", repr_ellipsized(data)) web_server_connection.write(data) while not temp_read_buffer.empty(): buf = temp_read_buffer.get() if buf: log("pushing read buffer to its new destination: %s", repr_ellipsized(buf)) web_server_connection.write(buf) p = XpraProxy(client_connection, web_server_connection) self._tcp_proxy_clients.append(p) def run_proxy(): p.run() log("run_proxy() %s ended", p) if p in self._tcp_proxy_clients: self._tcp_proxy_clients.remove(p) t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto) t.start() log.info("client %s forwarded to proxy server %s:%s", client_connection, host, port)
def stop_encode_thread(self): #empty the encode queue: q = self.encode_queue if q: q.put_nowait(None) q = Queue() q.put(None) self.encode_queue = q
def start_queue_encode(self, item): #start the encode work queue: #holds functions to call to compress data (pixels, clipboard) #items placed in this queue are picked off by the "encode" thread, #the functions should add the packets they generate to the 'packet_queue' self.encode_work_queue = Queue() self.queue_encode = self.encode_work_queue.put self.queue_encode(item) self.encode_thread = start_thread(self.encode_loop, "encode")
def __init__(self, conn, process_packet_cb, get_packet_cb=None): """ You must call this constructor and source_has_more() from the main thread. """ assert conn is not None self._conn = conn if FAKE_JITTER > 0: fj = FakeJitter(process_packet_cb) self._process_packet_cb = fj.process_packet_cb else: self._process_packet_cb = process_packet_cb self._write_queue = Queue(1) self._read_queue = Queue(20) # Invariant: if .source is None, then _source_has_more == False self._get_packet_cb = get_packet_cb #counters: self.input_packetcount = 0 self.input_raw_packetcount = 0 self.output_packetcount = 0 self.output_raw_packetcount = 0 #initial value which may get increased by client/server after handshake: self.max_packet_size = 32 * 1024 self.large_packets = ["hello"] self.aliases = {} self.chunked_compression = True self._closed = False self._encoder = self.bencode self._decompressor = decompressobj() self._compression_level = 0 self.cipher_in = None self.cipher_in_name = None self.cipher_in_block_size = 0 self.cipher_out = None self.cipher_out_name = None self.cipher_out_block_size = 0 self._write_lock = Lock() self._write_thread = make_daemon_thread(self._write_thread_loop, "write") self._read_thread = make_daemon_thread(self._read_thread_loop, "read") self._read_parser_thread = make_daemon_thread( self._read_parse_thread_loop, "parse") self._write_format_thread = make_daemon_thread( self._write_format_thread_loop, "format") self._source_has_more = threading.Event()
def stop(self, reason="proxy terminating", skip_proto=None): debug("stop(%s, %s)", reason, skip_proto) self.main_queue.put(None) #empty the main queue: q = Queue() q.put(None) self.main_queue = q for proto in (self.client_protocol, self.server_protocol): if proto and proto != skip_proto: proto.flush_then_close(["disconnect", reason])
def __init__(self, description="wrapper"): self.process = None self.protocol = None self.command = None self.description = description self.send_queue = Queue() self.signal_callbacks = {} self.large_packets = [] #hook a default packet handlers: self.connect(Protocol.CONNECTION_LOST, self.connection_lost) self.connect(Protocol.GIBBERISH, self.gibberish)
def stop(self, force=False): if self.exit: return if force: if self.items.qsize()>0: log.warn("Worker stop: %s items in the queue will not be run!", self.items.qsize()) self.items.put(None) self.items = Queue() self.exit = True else: if self.items.qsize()>0: log.info("waiting for %s items in work queue to complete", self.items.qsize()) debug("Worker_Thread.stop(%s) %s items in work queue", force, self.items) self.items.put(None)
def __init__(self, input_filename="-", output_filename="-", wrapped_object=None, method_whitelist=None): self.name = "" self._input = None self._output = None self.input_filename = input_filename self.output_filename = output_filename self.method_whitelist = method_whitelist self.large_packets = [] #the gobject instance which is wrapped: self.wrapped_object = wrapped_object self.send_queue = Queue() self.protocol = None register_os_signals(self.handle_signal) self.setup_mainloop()
def __init__(self, input_filename="-", output_filename="-", wrapped_object=None, method_whitelist=None): self.name = "" self.input_filename = input_filename self.output_filename = output_filename self.method_whitelist = method_whitelist self.large_packets = [] #the gobject instance which is wrapped: self.wrapped_object = wrapped_object self.send_queue = Queue() self.protocol = None if HANDLE_SIGINT: #this breaks gobject3! signal.signal(signal.SIGINT, self.handle_signal) signal.signal(signal.SIGTERM, self.handle_signal) self.setup_mainloop()
def __init__(self, description="wrapper"): self.process = None self.protocol = None self.command = None self.description = description self.send_queue = Queue() self.signal_callbacks = {} self.large_packets = [] #hook a default packet handlers: self.connect(Protocol.CONNECTION_LOST, self.connection_lost) self.connect(Protocol.GIBBERISH, self.gibberish) glib = import_glib() self.idle_add = glib.idle_add self.timeout_add = glib.timeout_add self.source_remove = glib.source_remove
def stop(self, force=False): if self.exit: return items = tuple(x for x in tuple(self.items.queue) if x is not None) log("Worker_Thread.stop(%s) %i items still in work queue: %s", force, len(items), items) if force: if items: log.warn("Worker stop: %s items in the queue will not be run!", len(items)) self.items.put(None) self.items = Queue() self.exit = True else: if items: log.info("waiting for %s items in work queue to complete", len(items)) self.items.put(None)
def terminate_queue_threads(self): log("terminate_queue_threads()") #the format thread will exit since closed is set too: self._source_has_more.set() #make the threads exit by adding the empty marker: exit_queue = Queue() for _ in range(10): #just 2 should be enough! exit_queue.put(None) try: owq = self._write_queue self._write_queue = exit_queue owq.put_nowait(None) except: pass try: orq = self._read_queue self._read_queue = exit_queue orq.put_nowait(None) except: pass
def __init__(self): Thread.__init__(self, name="Worker_Thread") self.items = Queue() self.exit = False self.setDaemon(True)
def __init__(self, *args): Connection.__init__(self, *args) self.queue = Queue()
def close(self): self.pending_read = Queue() SocketConnection.close(self)
def run(self): log("ProxyProcess.run() pid=%s, uid=%s, gid=%s", os.getpid(), getuid(), getgid()) setuidgid(self.uid, self.gid) if self.env_options: #TODO: whitelist env update? os.environ.update(self.env_options) self.video_init() log.info("new proxy instance started") log.info(" for client %s", self.client_conn) log.info(" and server %s", self.server_conn) signal.signal(signal.SIGTERM, self.signal_quit) signal.signal(signal.SIGINT, self.signal_quit) log("registered signal handler %s", self.signal_quit) start_thread(self.server_message_queue, "server message queue") if not self.create_control_socket(): #TODO: should send a message to the client return self.control_socket_thread = start_thread(self.control_socket_loop, "control") self.main_queue = Queue() #setup protocol wrappers: self.server_packets = Queue(PROXY_QUEUE_SIZE) self.client_packets = Queue(PROXY_QUEUE_SIZE) self.client_protocol = Protocol(self, self.client_conn, self.process_client_packet, self.get_client_packet) self.client_protocol.restore_state(self.client_state) self.server_protocol = Protocol(self, self.server_conn, self.process_server_packet, self.get_server_packet) #server connection tweaks: self.server_protocol.large_packets.append("input-devices") self.server_protocol.large_packets.append("draw") self.server_protocol.large_packets.append("window-icon") self.server_protocol.large_packets.append("keymap-changed") self.server_protocol.large_packets.append("server-settings") if self.caps.boolget("file-transfer"): self.client_protocol.large_packets.append("send-file") self.client_protocol.large_packets.append("send-file-chunk") self.server_protocol.large_packets.append("send-file") self.server_protocol.large_packets.append("send-file-chunk") self.server_protocol.set_compression_level(self.session_options.get("compression_level", 0)) self.server_protocol.enable_default_encoder() self.lost_windows = set() self.encode_queue = Queue() self.encode_thread = start_thread(self.encode_loop, "encode") log("starting network threads") self.server_protocol.start() self.client_protocol.start() self.send_hello() self.timeout_add(VIDEO_TIMEOUT*1000, self.timeout_video_encoders) try: self.run_queue() except KeyboardInterrupt as e: self.stop(str(e)) finally: log("ProxyProcess.run() ending %s", os.getpid())
def run(self): register_SIGUSR_signals(self.idle_add) log.info("started %s", self) log.info(" for client %s", self.client_conn) log.info(" and server %s", self.server_conn) client_protocol_class = get_client_protocol_class( self.client_conn.socktype) server_protocol_class = get_server_protocol_class( self.server_conn.socktype) self.client_protocol = client_protocol_class( self, self.client_conn, self.process_client_packet, self.get_client_packet) self.client_protocol.restore_state(self.client_state) self.server_protocol = server_protocol_class( self, self.server_conn, self.process_server_packet, self.get_server_packet) log("ProxyProcessProcess.run() pid=%s, uid=%s, gid=%s", os.getpid(), getuid(), getgid()) set_proc_title("Xpra Proxy Instance for %s" % self.server_conn) if POSIX and (getuid() != self.uid or getgid() != self.gid): #do we need a valid XDG_RUNTIME_DIR for the socket-dir? username = get_username_for_uid(self.uid) socket_dir = osexpand(self.socket_dir, username, self.uid, self.gid) if not os.path.exists(socket_dir): log( "the socket directory '%s' does not exist, checking for $XDG_RUNTIME_DIR path", socket_dir) for prefix in ("/run/user/", "/var/run/user/"): if socket_dir.startswith(prefix): from xpra.scripts.server import create_runtime_dir xrd = os.path.join(prefix, str(self.uid)) #ie: /run/user/99 log("creating XDG_RUNTIME_DIR=%s for uid=%i, gid=%i", xrd, self.uid, self.gid) create_runtime_dir(xrd, self.uid, self.gid) break #change uid or gid: setuidgid(self.uid, self.gid) if self.env_options: #TODO: whitelist env update? os.environ.update(self.env_options) signal.signal(signal.SIGTERM, self.signal_quit) signal.signal(signal.SIGINT, self.signal_quit) log("registered signal handler %s", self.signal_quit) start_thread(self.server_message_queue, "server message queue") if not self.create_control_socket(): self.stop(None, "cannot create the proxy control socket") return self.control_socket_thread = start_thread(self.control_socket_loop, "control", daemon=True) self.main_queue = Queue() ProxyInstance.run(self) try: QueueScheduler.run(self) except KeyboardInterrupt as e: self.stop(None, str(e)) finally: log("ProxyProcess.run() ending %s", os.getpid())
def __init__(self): self.main_queue = Queue() self.exit = False self.timer_id = AtomicInteger() self.timers = {} self.timer_lock = RLock()
def stop_main_queue(self): self.main_queue.put(None) #empty the main queue: q = Queue() q.put(None) self.main_queue = q
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)