def get_pulse_device(device_name_match=None, want_monitor_device=True, input_or_output=None, remote=None, xpra_device_name=None): """ choose the device to use """ try: from xpra.sound.pulseaudio.pulseaudio_util import has_pa, get_pa_device_options, get_default_sink, get_pulse_server, get_pulse_id if not has_pa(): log.warn("Warning: pulseaudio is not available!") return None except ImportError as e: log.warn("Warning: pulseaudio is not available!") log.warn(" %s", e) return None pa_server = get_pulse_server() if remote: log("start sound, remote pulseaudio server=%s, local pulseaudio server=%s", remote.pulseaudio_server, pa_server) #only worth comparing if we have a real server string #one that starts with {UUID}unix:/.. if pa_server and pa_server.startswith("{") and \ remote.pulseaudio_server and remote.pulseaudio_server==pa_server: log.error("Error: sound is disabled to prevent a sound loop") log.error(" identical Pulseaudio server '%s'", pa_server) return None pa_id = get_pulse_id() log("start sound, client id=%s, server id=%s", remote.pulseaudio_id, pa_id) if remote.pulseaudio_id and remote.pulseaudio_id==pa_id: log.error("Error: sound is disabled to prevent a sound loop") log.error(" identical Pulseaudio ID '%s'", pa_id) return None device_type_str = "" if input_or_output is not None: device_type_str = ["output", "input"][input_or_output] if want_monitor_device: device_type_str += " monitor" #def get_pa_device_options(monitors=False, input_or_output=None, ignored_devices=["bell-window-system"], log_errors=True) devices = get_pa_device_options(want_monitor_device, input_or_output) log("found %i pulseaudio %s device%s: %s", len(devices), device_type_str, engs(devices), devices) if len(devices)==0: log.error("Error: sound forwarding is disabled") log.error(" could not detect any Pulseaudio %s devices", device_type_str) return None #try to match one of the devices using the device name filters: if len(devices)>1: filters = [] matches = [] for match in (device_name_match, PULSEAUDIO_DEVICE_NAME, xpra_device_name): if not match: continue if match!=xpra_device_name: filters.append(match) match = match.lower() matches = dict((k,v) for k,v in devices.items() if k.lower().find(match)>=0 or v.lower().find(match)>=0) #log("matches(%s, %s)=%s", devices, match, matches) if len(matches)==1: log("found name match for '%s': %s", match, matches.items()[0]) break elif len(matches)>1: log.warn("Warning: Pulseaudio %s device name filter '%s'", device_type_str, match) log.warn(" matched %i devices", len(matches)) if filters or len(matches)>0: if len(matches)==0: log.warn("Warning: Pulseaudio %s device name filter%s:", device_type_str, engs(filters)) log.warn(" %s", csv("'%s'" % x for x in filters)) log.warn(" did not match any of the devices found:") for k,v in devices.items(): log.warn(" * '%s'", k) log.warn(" '%s'", v) return None devices = matches #still have too many devices to choose from? if len(devices)>1: if want_monitor_device: #use the monitor of the default sink if we find it: default_sink = get_default_sink() default_monitor = default_sink+".monitor" if default_monitor in devices: device_name = devices.get(default_monitor) log.info("using monitor of default sink: %s", device_name) return default_monitor global WARNED_MULTIPLE_DEVICES if not WARNED_MULTIPLE_DEVICES: WARNED_MULTIPLE_DEVICES = True if not PULSEAUDIO_DEVICE_NAME: #warned already dtype = "audio" if want_monitor_device: dtype = "output monitor" elif input_or_output is False: dtype = "audio input" elif input_or_output is True: dtype = "audio output" log.warn("Warning: found %i %s devices:", len(devices), dtype) for k,v in devices.items(): log.warn(" * %s", v) log.warn(" %s", k) if not PULSEAUDIO_DEVICE_NAME: #used already! log.warn(" to select a specific one,") log.warn(" use the environment variable XPRA_PULSEAUDIO_DEVICE_NAME") #default to first one: if USE_DEFAULT_DEVICE: log.info("using default pulseaudio device") return None #default to first one: device, device_name = devices.items()[0] log.info("using pulseaudio device:") log.info(" '%s'", device_name) return device
def get_pulse_device(device_name_match=None, want_monitor_device=True, input_or_output=None, remote=None, env_device_name=None): """ choose the device to use """ log("get_pulse_device%s", (device_name_match, want_monitor_device, input_or_output, remote, env_device_name)) try: from xpra.sound.pulseaudio.pulseaudio_util import ( has_pa, get_pa_device_options, get_default_sink, get_pactl_server, get_pulse_id, ) if not has_pa(): log.warn("Warning: pulseaudio is not available!") return None except ImportError as e: log.warn("Warning: pulseaudio is not available!") log.warn(" %s", e) return None pa_server = get_pactl_server() log("get_pactl_server()=%s", pa_server) if remote: log("start sound, remote pulseaudio server=%s, local pulseaudio server=%s", remote.pulseaudio_server, pa_server) #only worth comparing if we have a real server string #one that starts with {UUID}unix:/.. if pa_server and pa_server.startswith("{") and \ remote.pulseaudio_server and remote.pulseaudio_server==pa_server: log.error("Error: sound is disabled to prevent a sound loop") log.error(" identical Pulseaudio server '%s'", pa_server) return None pa_id = get_pulse_id() log("start sound, client id=%s, server id=%s", remote.pulseaudio_id, pa_id) if remote.pulseaudio_id and remote.pulseaudio_id==pa_id: log.error("Error: sound is disabled to prevent a sound loop") log.error(" identical Pulseaudio ID '%s'", pa_id) return None device_type_str = "" if input_or_output is not None: device_type_str = "input" if input_or_output else "output" if want_monitor_device: device_type_str += " monitor" #def get_pa_device_options(monitors=False, input_or_output=None, ignored_devices=["bell-window-system"]) devices = get_pa_device_options(want_monitor_device, input_or_output) log("found %i pulseaudio %s device%s: %s", len(devices), device_type_str, engs(devices), devices) ignore = () if input_or_output is True: ignore = IGNORED_INPUT_DEVICES elif input_or_output is False: ignore = IGNORED_OUTPUT_DEVICES else: ignore = IGNORED_INPUT_DEVICES+IGNORED_OUTPUT_DEVICES if ignore and devices: #filter out the ignore list: filtered = {} for k,v in devices.items(): kl = bytestostr(k).strip().lower() vl = bytestostr(v).strip().lower() if kl not in ignore and vl not in ignore: filtered[k] = v devices = filtered if not devices: log.error("Error: sound forwarding is disabled") log.error(" could not detect any Pulseaudio %s devices", device_type_str) return None env_device = None if env_device_name: env_device = os.environ.get(env_device_name) #try to match one of the devices using the device name filters: if len(devices)>1: filters = [] matches = [] for match in (device_name_match, env_device): if not match: continue if match!=env_device: filters.append(match) match = match.lower() log("trying to match '%s' in devices=%s", match, devices) matches = dict((k,v) for k,v in devices.items() if (bytestostr(k).strip().lower().find(match)>=0 or bytestostr(v).strip().lower().find(match)>=0)) #log("matches(%s, %s)=%s", devices, match, matches) if len(matches)==1: log("found name match for '%s': %s", match, tuple(matches.items())[0]) break elif len(matches)>1: log.warn("Warning: Pulseaudio %s device name filter '%s'", device_type_str, match) log.warn(" matched %i devices", len(matches)) if filters or matches: if not matches: log.warn("Warning: Pulseaudio %s device name filter%s:", device_type_str, engs(filters)) log.warn(" %s", csv("'%s'" % x for x in filters)) log.warn(" did not match any of the devices found:") for k,v in devices.items(): log.warn(" * '%s'", k) log.warn(" '%s'", v) return None devices = matches #still have too many devices to choose from? if len(devices)>1: if want_monitor_device: #use the monitor of the default sink if we find it: default_sink = get_default_sink() default_monitor = default_sink+".monitor" if default_monitor in devices: device_name = devices.get(default_monitor) log.info("using monitor of default sink: %s", device_name) return default_monitor global WARNED_MULTIPLE_DEVICES if not WARNED_MULTIPLE_DEVICES: WARNED_MULTIPLE_DEVICES = True dtype = "audio" if want_monitor_device: dtype = "output monitor" elif input_or_output is False: dtype = "audio output" elif input_or_output is True: dtype = "audio input" log.info("found %i %s devices:", len(devices), dtype) for k,v in devices.items(): log.info(" * %s", bytestostr(v)) log.info(" %s", bytestostr(k)) if not env_device: #used already! log.info(" to select a specific one,") log.info(" use the environment variable '%s'", env_device_name) #default to first one: if USE_DEFAULT_DEVICE: log.info("using default pulseaudio device") return None #default to first one: device, device_name = tuple(devices.items())[0] log.info("using pulseaudio device:") log.info(" '%s'", bytestostr(device_name)) return device
def get_pulse_defaults(device_name_match=None, want_monitor_device=True, input_or_output=None, remote=None, xpra_device_name=None): """ choose the device to use """ try: from xpra.sound.pulseaudio.pulseaudio_util import has_pa, get_pa_device_options, get_default_sink from xpra.sound.pulseaudio.pulseaudio_util import get_pulse_server, get_pulse_id, set_source_mute, set_sink_mute if not has_pa(): log.warn("Warning: pulseaudio is not available!") return None except ImportError as e: log.warn("Warning: pulseaudio is not available!") log.warn(" %s", e) return None pa_server = get_pulse_server() if remote: log( "start sound, remote pulseaudio server=%s, local pulseaudio server=%s", remote.pulseaudio_server, pa_server) #only worth comparing if we have a real server string #one that starts with {UUID}unix:/.. if pa_server and pa_server.startswith("{") and \ remote.pulseaudio_server and remote.pulseaudio_server==pa_server: log.error("Error: sound is disabled to prevent a sound loop") log.error(" identical Pulseaudio server '%s'", pa_server) return None pa_id = get_pulse_id() log("start sound, client id=%s, server id=%s", remote.pulseaudio_id, pa_id) if remote.pulseaudio_id and remote.pulseaudio_id == pa_id: log.error("Error: sound is disabled to prevent a sound loop") log.error(" identical Pulseaudio ID '%s'", pa_id) return None device_type_str = "" if input_or_output is not None: device_type_str = ["output", "input"][input_or_output] if want_monitor_device: device_type_str += " monitor" #def get_pa_device_options(monitors=False, input_or_output=None, ignored_devices=["bell-window-system"], log_errors=True) devices = get_pa_device_options(want_monitor_device, input_or_output) log("found %i pulseaudio %s device%s: %s", len(devices), device_type_str, engs(devices), devices) if len(devices) == 0: log.error("Error: sound forwarding is disabled") log.error(" could not detect any Pulseaudio %s devices", device_type_str) return None if len(devices) > 1: filters = [] matches = [] for match in (device_name_match, PULSEAUDIO_DEVICE_NAME, xpra_device_name): if not match: continue if match != xpra_device_name: filters.append(match) match = match.lower() matches = dict( (k, v) for k, v in devices.items() if k.lower().find(match) >= 0 or v.lower().find(match) >= 0) #log("matches(%s, %s)=%s", devices, match, matches) if len(matches) == 1: log("found name match for '%s': %s", match, matches.items()[0]) break elif len(matches) > 1: log.warn("Warning: Pulseaudio %s device name filter '%s'", device_type_str, match) log.warn(" matched %i devices", len(matches)) if filters or len(matches) > 0: if len(matches) == 0: log.warn("Warning: Pulseaudio %s device name filter%s:", device_type_str, engs(filters)) log.warn(" %s", csv("'%s'" % x for x in filters)) log.warn(" did not match the devices found:") for k, v in devices.items(): log.warn(" * '%s'", k) log.warn(" '%s'", v) return None devices = matches #default to first one: device, device_name = devices.items()[0] if len(devices) > 1: default_sink = get_default_sink() default_monitor = default_sink + ".monitor" global WARNED_MULTIPLE_DEVICES if not WARNED_MULTIPLE_DEVICES: WARNED_MULTIPLE_DEVICES = True if not PULSEAUDIO_DEVICE_NAME: #warned already log.warn("Warning: found %i audio devices:", len(devices)) for k, v in devices.items(): log.warn(" * %s", v) log.warn(" %s", k) if not PULSEAUDIO_DEVICE_NAME: #used already! log.warn(" to select a specific one,") log.warn( " use the environment variable XPRA_PULSEAUDIO_DEVICE_NAME" ) if default_monitor in devices: device = default_monitor device_name = devices.get(default_monitor) if not WARNED_MULTIPLE_DEVICES: log.warn("using monitor of default sink: %s", device_name) else: if not WARNED_MULTIPLE_DEVICES: log.warn("using the first device") log.info("using pulseaudio device:") log.info(" '%s'", device_name) #make sure it is not muted: if input_or_output is True or want_monitor_device: set_source_mute(device, mute=False) elif input_or_output is False: set_sink_mute(device, mute=False) return {"device": device}