metadata['xesam:title']) if metadata['xesam:title'] else '' if not artist and not song: print('') else: if len(song) > trunclen: song = song[0:trunclen] song += '...' if ('(' in song) and (')' not in song): song += ')' if font: artist = label_with_font.format(font=font, label=artist) song = label_with_font.format(font=font, label=song) with pulsectl.Pulse('event-printer') as pulse: for inp in pulse.sink_input_list(): if inp.proplist['application.name'] == 'Spotify': vol = inp.volume vol.value_flat = 0.0 if not artist and ( song == 'Advertisement' or song == 'Spotify') else 1.0 pulse.volume_set(inp, vol) print(output.format(artist=artist, song=song, play_pause=play_pause)) except Exception as e: if isinstance(e, dbus.exceptions.DBusException): print('') else: print(e)
def player4(tauon): pctl = tauon.pctl gui = tauon.gui prefs = tauon.prefs print("Start PHAzOR backend...") # Get output device names if len(prefs.phazor_devices) < 2: try: import pulsectl pulse = pulsectl.Pulse('Tauon Music Box') sink_list = pulse.sink_list() for sink in sink_list: prefs.phazor_devices[sink.description] = sink.name pulse.close() except: print("Warning: Missing dependency Pulsectl") state = 0 player_timer = Timer() loaded_track = None fade_time = 400 aud = ctypes.cdll.LoadLibrary(pctl.install_directory + "/lib/libphazor.so") aud.init() aud.set_volume(int(pctl.player_volume)) def calc_rg(track): if prefs.replay_gain == 0 and prefs.replay_preamp == 0: pctl.active_replaygain = 0 return 0 g = 0 p = 1 if track is not None: tg = track.misc.get("replaygain_track_gain") tp = track.misc.get("replaygain_track_peak") ag = track.misc.get("replaygain_album_gain") ap = track.misc.get("replaygain_album_peak") if prefs.replay_gain > 0: if (prefs.replay_gain == 1 and tg is not None) or (prefs.replay_gain == 2 and ag is None and tg is not None): g = tg if tp is not None: p = tp elif ag is not None: g = ag if ap is not None: p = ap # print("Replay gain") # print("GAIN: " + str(g)) # print("PEAK: " + str(p)) # print("FINAL: " + str(min(10 ** ((g + prefs.replay_preamp) / 20), 1 / p))) pctl.active_replaygain = g return min(10 ** ((g + prefs.replay_preamp) / 20), 1 / p) audio_cache = tauon.cache_directory + "/network-audio1" class DownloadObject: def __init__(self, track): self.timestamp = time.time() self.status = "prep" self.tauon_id = track.index self.filepath = audio_cache if not os.path.exists(self.filepath): os.makedirs(self.filepath) self.filepath += "/" + str(self.tauon_id) + ".mp3" if os.path.exists(self.filepath): os.remove(self.filepath) self.network_url = "" self.params = "" self.part = None self.cancel = False self.downloaded_duration = -1 def download(self): print("Start download") try: self.part = requests.get(self.network_url, stream=True, params=self.params) if self.part.status_code == 404: gui.show_message("Server: File not found", mode="error") self.status = "error" return elif self.part.status_code != 200: gui.show_message("Server Error", mode="error") self.status = "error" return except: gui.show_message("Could not connect to server", mode="error") self.status = "error" return bitrate = 0 a = 0 z = 0 with open(self.filepath, 'wb') as f: for chunk in self.part.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks a += 1 if a == 300: # kilobyes~ self.status = "ready" if self.cancel is True: self.part.close() self.status = "failed" print("Abort download") return f.write(chunk) z += 1 if z == 60: z = 0 if bitrate == 0: audio = auto.File(self.filepath) bitrate = audio.bitrate if bitrate > 0: gui.update += 1 self.downloaded_duration = a * 1024 / (bitrate / 8) / 1000 #pctl.download_time = a * 1024 / (bitrate / 8) / 1000 #pctl.download_time = -1 self.status = "done" print("Download done") class DownloadManager: def __init__(self): self.items = {} if os.path.exists(audio_cache): shutil.rmtree(audio_cache) def get_filepath(self, track): return self.items[track.index].filepath def _prune(self): items = list(self.items.values()) items.sort(key=lambda x: x.timestamp) for item in items: if item.status in ("ready", "prep"): item.cancel = True elif item.status in ("failed", "error"): print("prune failed item") if os.path.exists(item.filepath): os.remove(item.filepath) del self.items[item.tauon_id] items = list(self.items.values()) items.sort(key=lambda x: x.timestamp) items = items[:-25] for item in items: print("prune old item") if os.path.exists(item.filepath): os.remove(item.filepath) del self.items[item.tauon_id] def request(self, track, t=0, whole=False): if track.index in self.items: item = self.items[track.index] if item.status == "ready": if whole: return "wait" if t == 0: return "go" elif item.downloaded_duration > t + 20: return "go" elif t: return "wait" if item.status == "done": item.timestamp = time.time() print("Use cached audio") return "go" if item.status == "prep": return "wait" if item.status == "error": del self.items[track.index] return "error" if item.status == "failed": del self.items[track.index] if t: print(item.status) return "wait" self._prune() item = DownloadObject(track) try: item.network_url, item.params = pctl.get_url(target_object) except: return "error" self.items[track.index] = item shoot_dl = threading.Thread(target=item.download) shoot_dl.daemon = True shoot_dl.start() return "wait" dm = DownloadManager() class URLDownloader: def __init__(self): self.active_url = "" self.part = None self.dl_ready = False self.dl_running = False self.save_temp = "" self.alt = "b" def download_part(self, url, target, params, item): self.dl_running = True try: self.part = requests.get(url, stream=True, params=params) if self.part.status_code == 404: gui.show_message("Server: File not found", mode="error") self.dl_ready = "failure" return elif self.part.status_code != 200: gui.show_message("Server Error", mode="error") self.dl_ready = "failure" return except: gui.show_message("Could not connect to server", mode="error") self.dl_ready = "failure" return bitrate = 0 a = 0 z = 0 if os.path.isfile(target): os.remove(target) with open(target, 'wb') as f: for chunk in self.part.iter_content(chunk_size=1024): if chunk: # filter out keep-alive new chunks a += 1 if a == 300: # kilobyes~ self.dl_ready = True if url != self.active_url: self.part.close() print("Abort download") break f.write(chunk) z += 1 if z == 60: z = 0 if bitrate == 0: audio = auto.File(target) bitrate = audio.bitrate if bitrate > 0: gui.update += 1 pctl.download_time = a * 1024 / (bitrate / 8) / 1000 pctl.download_time = -1 self.dl_ready = True self.dl_running = False dl = URLDownloader() def set_config(): aud.config_set_dev_buffer(prefs.device_buffer) if prefs.phazor_device_selected != "Default": if prefs.phazor_device_selected in prefs.phazor_devices.values(): aud.config_set_dev_name(prefs.phazor_device_selected.encode()) else: print("Warning: Selected audio output is now missing. Defaulting to default.") aud.config_set_dev_name(None) else: aud.config_set_dev_name(None) set_config() while True: time.sleep(0.016) # Level meter if state == 1 and gui.vis == 1: amp = aud.get_level_peak_l() l = (amp / 32767) * 12 amp = aud.get_level_peak_r() r = (amp / 32767) * 12 tauon.level_train.append((0, l, r)) gui.level_update = True # Command processing if pctl.playerCommandReady: command = pctl.playerCommand subcommand = pctl.playerSubCommand pctl.playerSubCommand = "" pctl.playerCommandReady = False if command == "reload": set_config() if command == "url": pctl.download_time = 0 w = 0 while len(tauon.stream_proxy.chunks) < 200: time.sleep(0.1) w += 1 if w > 100: print("Taking too long!") tauon.stream_proxy.stop() pctl.playerCommand = 'stop' pctl.playerCommandReady = True break else: aud.start(pctl.url.encode(), 0, 0, ctypes.c_float(calc_rg(None))) state = 3 player_timer.hit() if command == "open": if state == 2: aud.set_volume(int(pctl.player_volume)) pctl.download_time = 0 target_object = pctl.target_object target_path = target_object.fullpath if (tauon.spot_ctl.playing or tauon.spot_ctl.coasting) and not target_object.file_ext == "SPTY": tauon.spot_ctl.control("stop") if target_object.is_network: dl.dl_running = False if target_object.file_ext == "SPTY": tauon.level_train.clear() if state > 0: aud.stop() state = 0 try: tauon.spot_ctl.play_target(target_object.url_key) except: print("Failed to start Spotify track") pctl.playerCommand = "stop" pctl.playerCommandReady = True continue target_path = None while True: s = dm.request(target_object) if s == "go": target_path = dm.get_filepath(target_object) break elif s == "wait": if pctl.playerCommandReady and pctl.playerCommand == "open": break #print("wait") time.sleep(0.01) else: print("Abort for error") break if target_path is None: continue # # url = "" # params = None # # try: # url, params = pctl.get_url(target_object) # except: # gui.show_message("Failed to query url", "Bad login? Server offline?", mode='info') # pctl.stop() # return # # if url is None: # print(gui.show_message("Failed to query url", "Bad login? Server offline?", mode='info')) # pctl.stop() # return # # dl.save_temp = prefs.cache_directory + "/" + dl.alt + "-temp.mp3" # # if dl.alt == 'a': # dl.alt = 'b' # else: # dl.alt = 'a' # # dl.active_url = url # dl.dl_ready = False # # shoot_dl = threading.Thread(target=dl.download_part, args=([url, dl.save_temp, params, target_object])) # shoot_dl.daemon = True # shoot_dl.start() # # while not dl.dl_ready: # time.sleep(0.02) # target_path = dl.save_temp # # if dl.dl_ready == "failure": # state = 0 # aud.stop() # continue # if not target_object.is_network and target_object.file_ext not in ("MP3", "FLAC", "OGG", "OPUS"): # state = 0 # aud.stop() # continue if not os.path.isfile(target_path): target_object.found = False if not target_object.is_network: pctl.playing_state = 0 pctl.jump_time = 0 pctl.advance(inplace=True, play=True) continue elif not target_object.found: pctl.reset_missing_flags() length = 0 remain = 0 position = 0 if state == 1 and not pctl.start_time_target and not pctl.jump_time and \ loaded_track: length = aud.get_length_ms() / 1000 position = aud.get_position_ms() / 1000 remain = length - position # print("length: " + str(length)) # print("position: " + str(position)) # print("We are %s from end" % str(remain)) if loaded_track.is_network: length = loaded_track.length remain = length - position fade = 0 if state == 1 and length and position and not pctl.start_time_target and not pctl.jump_time and \ loaded_track and 0 < remain < 5.5 and not loaded_track.is_cue and subcommand != "now": print("Transition gapless mode") aud.next(target_path.encode(), int(pctl.start_time_target + pctl.jump_time) * 1000, ctypes.c_float(calc_rg(target_object))) pctl.playing_time = pctl.jump_time if remain > 0: time.sleep(0.01) remain -= 0.01 if pctl.playerCommandReady and pctl.playerCommand == "open": break loaded_track = target_object else: if state == 1 and prefs.use_jump_crossfade: fade = 1 aud.start(target_path.encode(), int(pctl.start_time_target + pctl.jump_time) * 1000, fade, ctypes.c_float(calc_rg(target_object))) loaded_track = target_object pctl.playing_time = pctl.jump_time if pctl.jump_time: while aud.get_result() == 0: time.sleep(0.01) aud.set_position_ms(int(pctl.jump_time * 1000)) # Restart track is failed to load (for some network tracks) (broken with gapless loading) while True: r = aud.get_result() if r == 1: break if r == 2: if loaded_track.is_network: gui.buffering = True while dm.request(loaded_track, whole=True) == "wait": time.sleep(0.05) if pctl.playerCommandReady: break print("Retry start file") aud.start(target_path.encode(), int(pctl.start_time_target + pctl.jump_time) * 1000, fade, ctypes.c_float(calc_rg(target_object))) gui.buffering = False player_timer.set() break else: aud.stop() gui.show_message("Error loading track", mode="warning") time.sleep(0.05) state = 1 player_timer.set() pctl.jump_time = 0 if loaded_track.length == 0 or loaded_track.file_ext.lower() in tauon.mod_formats: i = 0 t = 0 while t == 0: time.sleep(0.3) t = aud.get_length_ms() / 1000 i += 1 if i > 9: break loaded_track.length = t if loaded_track.length != 0: pctl.playing_length = loaded_track.length gui.pl_update += 1 if command == "seek": if tauon.spot_ctl.coasting or tauon.spot_ctl.playing: tauon.spot_ctl.control("seek", int(pctl.new_time * 1000)) pctl.playing_time = pctl.new_time elif state > 0: if loaded_track.is_network: # and loaded_track.fullpath.endswith(".ogg"): was_playing = False if state == 1: was_playing = True aud.pause() abort = False while True: s = dm.request(loaded_track, t=pctl.new_time) if s == "go": break if pctl.playerCommandReady: abort = True break if s == "wait": gui.buffering = True print("Can't seek yet") time.sleep(0.1) continue abort = True break gui.buffering = False if abort: continue # The vorbis decoder doesn't like appended files aud.start(dm.get_filepath(loaded_track).encode(), int(pctl.new_time + pctl.start_time_target) * 1000, 0, ctypes.c_float(calc_rg(loaded_track))) while aud.get_result() == 0: time.sleep(0.01) aud.set_position_ms(int(pctl.new_time * 1000)) else: aud.seek(int((pctl.new_time + pctl.start_time_target) * 1000), prefs.pa_fast_seek) pctl.playing_time = pctl.new_time pctl.decode_time = pctl.playing_time if command == "volume": if tauon.spot_ctl.coasting or tauon.spot_ctl.playing: tauon.spot_ctl.control("volume", int(pctl.player_volume)) else: aud.ramp_volume(int(pctl.player_volume), 750) if command == "runstop": length = aud.get_length_ms() / 1000 position = aud.get_position_ms() / 1000 remain = length - position # print("length: " + str(length)) # print("position: " + str(position)) # print("We are %s from end" % str(remain)) time.sleep(3) command = "stop" if command == "stop": if prefs.use_pause_fade and state != 3: if pctl.player_volume > 5: speed = fade_time / (int(pctl.player_volume) / 100) else: speed = fade_time / (5 / 100) aud.ramp_volume(0, int(speed)) time.sleep((fade_time + 100) / 1000) state = 0 pctl.playing_time = 0 aud.stop() time.sleep(0.1) aud.set_volume(int(pctl.player_volume)) if subcommand == "return": pctl.playerSubCommand = "stopped" #pctl.playerCommandReady = True if command == "pauseon": if prefs.use_pause_fade: if pctl.player_volume > 5: speed = fade_time / (int(pctl.player_volume) / 100) else: speed = fade_time / (5 / 100) aud.ramp_volume(0, int(speed)) time.sleep((fade_time + 100) / 1000) aud.pause() state = 2 if command == "pauseoff": if prefs.use_pause_fade: if pctl.player_volume > 5: speed = fade_time / (int(pctl.player_volume) / 100) else: speed = fade_time / (5 / 100) aud.ramp_volume(int(pctl.player_volume), int(speed)) aud.resume() player_timer.set() state = 1 if command == "unload": if prefs.use_pause_fade: if pctl.player_volume > 5: speed = fade_time / (int(pctl.player_volume) / 100) else: speed = fade_time / (5 / 100) aud.ramp_volume(0, int(speed)) time.sleep((fade_time + 100) / 1000) aud.stop() aud.shutdown() if os.path.exists(audio_cache): shutil.rmtree(audio_cache) pctl.playerCommand = "done" pctl.playerCommandReady = True break else: pctl.spot_test_progress() if state == 3: pctl.radio_progress() add_time = player_timer.hit() pctl.playing_time += add_time pctl.decode_time = pctl.playing_time buffering = aud.is_buffering() if gui.buffering != buffering: gui.buffering = buffering gui.update += 1 if state == 1: if loaded_track.is_network and pctl.playing_time < 7: if aud.get_result() == 2: print("STALL, RETRY") time.sleep(0.5) pctl.playerCommandReady = True pctl.playerCommand = "open" add_time = player_timer.hit() if add_time > 2: add_time = 2 if add_time < 0: add_time = 0 pctl.playing_time += add_time t = aud.get_position_ms() / 1000 pctl.total_playtime += add_time if t: pctl.decode_time = t - loaded_track.start_time else: pctl.decode_time = pctl.playing_time #print((pctl.playing_time, pctl.decode_time)) if pctl.playing_time < 3 and pctl.a_time < 3: pctl.a_time = pctl.playing_time else: pctl.a_time += add_time tauon.lfm_scrobbler.update(add_time) if len(pctl.track_queue) > 0 and 2 > add_time > 0: tauon.star_store.add(pctl.track_queue[pctl.queue_step], add_time) if pctl.playing_time > 1: pctl.test_progress()
def kiwi_main(kiwi): pass parser = argparse.ArgumentParser( description=kiwi.module_desc, epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) subparsers = parser.add_subparsers(dest="action") parser.add_argument("-q", "--quiet", help="do not display any output", action="store_true") # system volume control volume_subparser = subparsers.add_parser("volume") volume_subparser.add_argument("-I", "--intervals", type=int, metavar="AMOUNT", help="intervals of the entire volume range") volume_subparser.add_argument("-s", "--sink", type=int, metavar="INDEX", help="target sink index", default=0) volume_subparser.add_argument( "--range-symbol", type=str, metavar="SYMBOL", help="symbol that represents a unit of range", default="─") volume_subparser.add_argument( "--value-symbol", type=str, metavar="SYMBOL", help="symbol that represents the current value of range", default="|") volume_control_group = volume_subparser.add_mutually_exclusive_group() volume_control_group.add_argument("-t", "--toggle-mute", action="store_true", help="toggle sound mute") volume_control_group.add_argument("-m", "--mute", action="store_true", help="mute sound") volume_control_group.add_argument("-u", "--unmute", action="store_true", help="unmute sound") volume_control_group.add_argument( "-i", "--increment", type=int, metavar="PERCENTAGE", help="increment volume by specified percentage", choices=range(1, 100)) volume_control_group.add_argument( "-d", "--decrement", type=int, metavar="PERCENTAGE", help="decrement volume by specified percentage", choices=range(1, 100)) # system information info_subparser = subparsers.add_parser("info") info_subparser.add_argument("-j", "--jsonpath", type=str, metavar="PATH", help="fetch specific fields from result") info_subparsers = info_subparser.add_subparsers(dest="info_action") # system information for item in [ "wan", "lan", "ram", "swap", "cpu", "net", "temp", "fans", "battery" ]: info_subparsers.add_parser(item) args = parser.parse_args() # write stdout to devnull if quiet stdout = sys.stdout devnull = open(os.devnull, 'w') if args.quiet: sys.stdout = devnull try: # system volume control if args.action == "volume": import pulsectl # must provide a range to print it out if not args.quiet: if not args.intervals: parser.error("must provide interval range if not using -q") else: args.intervals = 0 # pulseaudio client with pulsectl.Pulse('client') as pulse: # get target sink target_sink = pulse.sink_list()[args.sink] # base off of the left channel volume current_volume = target_sink.volume.values[0] # if volume should be altered if args.increment or args.decrement or args.toggle_mute or args.mute or args.unmute: # if volume should be incremented if args.increment or args.decrement: # decide on a value increment_value = args.increment if args.increment else -args.decrement # keep target volume in range target_volume = current_volume + (increment_value / 100.0) if target_volume > 1 or target_volume < 0: target_volume = abs(target_volume) - ( abs(target_volume) % 1) # mute/unmute else: # action related functions def mute(current_volume): with open(VOLUME_CACHE_FILENAME, 'w') as VOLUME_CACHE: VOLUME_CACHE.write(str(current_volume)) return 0 def unmute(): if os.path.isfile(VOLUME_CACHE_FILENAME): with open(VOLUME_CACHE_FILENAME, 'r') as VOLUME_CACHE: return float(VOLUME_CACHE.read()) return 1.0 def toggle(): if current_volume == 0: return unmute() else: return mute(current_volume) # act based on parameter if args.toggle_mute: target_volume = toggle() elif args.mute: target_volume = mute(current_volume) else: target_volume = unmute() # set result volume pulse.volume_set_all_chans(target_sink, target_volume) # update current volume value current_volume = target_volume # print volume state volume_range = args.range_symbol * args.intervals value_index = max( 0, math.floor(args.intervals * current_volume) - 1) print(volume_range[:value_index] + args.value_symbol + volume_range[value_index + 1:]) # networking information elif args.action == "info": import psutil import jsonpath # get appropriate info info_json = { "wan": lambda: loads(kiwi.request(Request('GET', '/info/wan')).text), "lan": lambda: psutil.net_if_addrs(), "ram": lambda: psutil.virtual_memory()._asdict(), "swap": lambda: psutil.swap_memory()._asdict(), "cpu": lambda: { 'system-wide': psutil.cpu_percent(interval=1), 'per-cpu': psutil.cpu_percent(percpu=True), 'stats': psutil.cpu_stats()._asdict(), 'freq': psutil.cpu_freq()._asdict() }, "net": lambda: psutil.net_io_counters()._asdict(), "temp": lambda: psutil.sensors_temperatures(), "fans": lambda: psutil.sensors_fans(), "battery": lambda: psutil.sensors_battery()._asdict(), }.get(args.info_action, lambda: None)() info_json = info_json if info_json else {} # print query if specified, otherwise print everything if args.jsonpath: result = jsonpath.jsonpath(loads(dumps(info_json)), args.jsonpath) # format result if result: if len(result) == 1: result = result[0] else: result = "" print(result, end="") else: print(dumps(info_json, indent=4), end="") finally: sys.stdout = stdout
from PyQt4 import Qt, QtCore, QtGui, uic import os, netifaces as ni, psutil, time, alsaaudio, pulsectl from subprocess import call from xml.dom import minidom path=os.path.dirname(os.path.abspath( __file__ )) form_class = uic.loadUiType(path+"/gui.ui")[0] pulse = pulsectl.Pulse('pyCAR') class tableModel(QtGui.QStandardItemModel): def __init__(self,datain,parent=None,*args): QtGui.QStandardItemModel.__init__(self,parent,*args) self.header = None self.modules = None def headerData(self,section,orientation,role=QtCore.Qt.DisplayRole): if orientation==QtCore.Qt.Vertical: if role==QtCore.Qt.DecorationRole: mPath = path.rsplit('/', 1) module = self.modules[section] return QtGui.QPixmap(mPath[0]+"/"+module.attributes["name"].value+"/button.png") if role==QtCore.Qt.DisplayRole: return "" if role==QtCore.Qt.DisplayRole and orientation==QtCore.Qt.Horizontal: return self.header[section] return QtGui.QStandardItemModel.headerData(self,section,orientation,role) def itemChanged(self, item): print(item) print("Item {!r} checkState: {}".format(item.text(), item.checkState()))
def init_pulse(): return pulsectl.Pulse('rofi_sinks')
class Ui_MainWindow(object): #txrxOffset = 10057500000 # Difference between rx & tx txrxOffsetFixed = 10057500000 # Difference between rx & tx txrxOffset = txrxOffsetFixed #txrxOffset = 10057500080 # Difference between rx & tx #txrxOffset = 10057500030 # Difference between rx & tx #txrxOffset = 10057500050 # Difference between rx & tx #txrxOffset = 10057499700 # Difference between rx & tx #txrxOffset = 10057499950 # Difference between rx & tx #txrxOffset = 10057499930 # Difference between rx & tx #txrxOffset = 10057499900 # Difference between rx & tx #txrxOffset = 10057499990 # Difference between rx & tx #txrxOffset = 10057500950 # Difference between rx & tx # RTL +650 Hz #txrxOffset = 10057500250 # Difference between rx & tx # RTL +650 Hz #txrxOffset = 10057500700 # Difference between rx & tx # RTL +650 Hz rxHost = "localhost" # expecting rx to be 10498 rxPort = 7356 txHost = "localhost" # expecting 432. txPort = 4568 soundcardName = 'HyperX Virtual Surround Sound Analogue Stereo' # Get sound card name from list with output from below script #pulseDev = 1 # Audio sink in pulse to mute, list devs with: # import pulsectl # pulse = pulsectl.Pulse('my-client-name') # for x in pulse.sink_list() : # print x pulse = pulsectl.Pulse('my-client-name') pulseDev = 0 rxFreq = 0 txFreq = 0 syncRxReq = 0 syncRxFreq = 0 syncTxReq = 0 syncTxFreq = 0 offsetHz = 0 pttSet = 0 # 0 = no change, 1 = request ptt on, 2 = request ptt off for x in pulse.sink_list(): if re.search(soundcardName, str(x)): break pulseDev = pulseDev + 1 def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(759, 284) MainWindow.setFixedSize(MainWindow.size()) self.centralWidget = QWidget(MainWindow) self.centralWidget.setObjectName("centralWidget") self.offsetLbl1 = QLabel(self.centralWidget) self.offsetLbl1.setGeometry(QRect(30, 170, 101, 31)) font = QFont() font.setPointSize(17) self.offsetLbl1.setFont(font) self.offsetLbl1.setObjectName("offsetLbl1") self.txLabel = QLabel(self.centralWidget) self.txLabel.setGeometry(QRect(480, 0, 231, 31)) font = QFont() font.setPointSize(17) self.txLabel.setFont(font) self.txLabel.setObjectName("txLabel") self.rxLabel = QLabel(self.centralWidget) self.rxLabel.setGeometry(QRect(60, 0, 231, 31)) font = QFont() font.setPointSize(17) self.rxLabel.setFont(font) self.rxLabel.setObjectName("rxLabel") self.offsetLbl2 = QLabel(self.centralWidget) self.offsetLbl2.setGeometry(QRect(140, 170, 51, 31)) font = QFont() font.setPointSize(17) self.offsetLbl2.setFont(font) self.offsetLbl2.setLayoutDirection(Qt.LeftToRight) self.offsetLbl2.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.offsetLbl2.setObjectName("offsetLbl2") self.syncRxButton = QPushButton(self.centralWidget) self.syncRxButton.setGeometry(QRect(340, 120, 85, 27)) self.syncRxButton.setObjectName("syncRxButton") self.syncRxButton.clicked.connect(self.syncRx) # Added self.muteButton = QPushButton(self.centralWidget) self.muteButton.setGeometry(QRect(330, 170, 101, 71)) font = QFont() font.setPointSize(13) self.muteButton.setFont(font) self.muteButton.setCheckable(True) self.muteButton.setObjectName("muteButton") self.muteButton.clicked.connect(self.setMute) # Added self.offsetSlider = QSlider(self.centralWidget) self.offsetSlider.setGeometry(QRect(10, 210, 311, 18)) self.offsetSlider.setMinimum(-500) self.offsetSlider.setMaximum(500) self.offsetSlider.setSingleStep(10) self.offsetSlider.setOrientation(Qt.Horizontal) self.offsetSlider.setTickPosition(QSlider.TicksBelow) self.offsetSlider.setTickInterval(100) self.offsetSlider.setObjectName("offsetSlider") self.offsetSlider.valueChanged.connect(self.offsetChange) # Added self.lcdTx = QLCDNumber(self.centralWidget) self.lcdTx.setGeometry(QRect(440, 40, 311, 121)) self.lcdTx.setDigitCount(8) self.lcdTx.setObjectName("lcdTx") self.lcdRx = QLCDNumber(self.centralWidget) self.lcdRx.setGeometry(QRect(10, 40, 311, 121)) self.lcdRx.setDigitCount(8) self.lcdRx.setObjectName("lcdRx") self.syncTxButton = QPushButton(self.centralWidget) self.syncTxButton.setGeometry(QRect(340, 40, 85, 27)) self.syncTxButton.setObjectName("syncTxButton") self.syncTxButton.clicked.connect(self.syncTx) # Added self.linkButton = QPushButton(self.centralWidget) self.linkButton.setGeometry(QRect(340, 80, 85, 27)) self.linkButton.setCheckable(True) # Added self.linkButton.setObjectName("linkButton") self.linkButton.clicked.connect(self.linkTx) # Added self.pttButton = QPushButton(self.centralWidget) self.pttButton.setGeometry(QRect(440, 170, 301, 71)) font = QFont() font.setPointSize(27) self.pttButton.setFont(font) self.pttButton.setCheckable(True) self.pttButton.setObjectName("pttButton") self.pttButton.clicked.connect(self.setPtt) # Added self.offsetLbl3 = QLabel(self.centralWidget) self.offsetLbl3.setGeometry(QRect(200, 170, 71, 31)) font = QFont() font.setPointSize(17) self.offsetLbl3.setFont(font) self.offsetLbl3.setObjectName("offsetLbl3") MainWindow.setCentralWidget(self.centralWidget) self.mainToolBar = QToolBar(MainWindow) self.mainToolBar.setObjectName("mainToolBar") MainWindow.addToolBar(Qt.TopToolBarArea, self.mainToolBar) self.statusBar = QStatusBar(MainWindow) self.statusBar.setObjectName("statusBar") MainWindow.setStatusBar(self.statusBar) self.retranslateUi(MainWindow) QMetaObject.connectSlotsByName(MainWindow) self.threadpool = QThreadPool() rxWorker = Worker(self.connRx) self.threadpool.start(rxWorker) txWorker = Worker(self.connTx) self.threadpool.start(txWorker) def retranslateUi(self, MainWindow): _translate = QCoreApplication.translate MainWindow.setWindowTitle( _translate("MainWindow", "QO-100 Hamlib Helper")) self.offsetLbl1.setText(_translate("MainWindow", "TX Offset")) self.txLabel.setText(_translate("MainWindow", " Transmit 2400.")) self.rxLabel.setText(_translate("MainWindow", " Receive 10498.")) self.offsetLbl2.setText(_translate("MainWindow", "0")) self.syncRxButton.setText(_translate("MainWindow", "<< SYNC ")) self.muteButton.setText(_translate("MainWindow", "Mute On TX")) self.syncTxButton.setText(_translate("MainWindow", " SYNC >>")) self.linkButton.setText(_translate("MainWindow", "<< LINK >>")) self.pttButton.setText(_translate("MainWindow", "PTT")) self.offsetLbl3.setText(_translate("MainWindow", "Hz")) def setMute(self): # Added if self.pttButton.isChecked(): if self.muteButton.isChecked(): self.pulse.mute(self.pulse.sink_list()[self.pulseDev], True) else: self.pulse.mute(self.pulse.sink_list()[self.pulseDev], False) def setPtt( self ): # Added, need to allow easier configuration and setting by name if self.pttButton.isChecked(): self.pttButton.setStyleSheet( "background-color: red; border-radius: 1px;") if (self.muteButton.isChecked()): self.pulse.mute(self.pulse.sink_list()[self.pulseDev], True) self.pttSet = 1 # request ptt on else: self.pttButton.setStyleSheet("background-color: light grey") if (self.muteButton.isChecked()): self.pulse.mute(self.pulse.sink_list()[self.pulseDev], False) self.pttSet = 2 # request ptt off, 0 = no change #print ("Mute: %d" % self.isMuted) def offsetChange(self): self.offsetHz = int(round(self.offsetSlider.value(), -1)) self.offsetLbl2.setText(str(self.offsetHz)) def syncTx(self): #print ("sync Tx Txold: %d Rxnow: %d" % (int(self.txFreq), int(self.rxFreq))) shortF = self.txFreq[3:] # strip leading three, 432 here self.lcdTx.display(shortF[:3] + "." + shortF[3:]) # display xxx.xxx self.txFreq = str((int(self.rxFreq) - self.txrxOffset)) self.syncTxFreq = str((int(self.rxFreq) - self.txrxOffset)) self.syncTxReq = 1 def syncRx(self): shortF = self.rxFreq[5:] # strip leading three, 10368 here self.lcdRx.display(shortF[:3] + "." + shortF[3:]) # display xxx.xxx self.rxFreq = str((int(self.txFreq) + self.txrxOffset)) self.syncRxFreq = str((int(self.txFreq) + self.txrxOffset)) self.syncRxReq = 1 def linkTx(self): if self.linkButton.isChecked(): #print ("linking") self.syncTxButton.setEnabled(False) self.syncRxButton.setEnabled(False) self.linkButton.setStyleSheet( "background-color: red; border-radius: 1px;") else: #print ("unlinking") self.syncTxButton.setEnabled(True) self.syncRxButton.setEnabled(True) self.linkButton.setStyleSheet("background-color: light grey;") def connRx(self): try: connSock = socket(AF_INET, SOCK_STREAM) connSock.connect((self.rxHost, self.rxPort)) while 1: time.sleep(0.1) if (self.syncRxReq): #connSock.send('F %s' % self.rxFreq) sendString = ('F %s' % self.syncRxFreq) connSock.send(sendString.encode()) #connSock.send('F %s'.encode() % self.syncRxFreq) self.syncRxReq = 0 else: connSock.send('f\n'.encode()) output = connSock.recv(100).decode() if not (re.match(r'^[0-9]+$', str(output))): # change to not that or RPRT0 #print ("Unexpected non frequency response from hamlib: " + str(output)) # not strictly true F does this continue self.rxFreq = str(output) #print ('RX Frequency offset: %d read: %d real: %d' % (self.offsetHz, int(self.rxFreq), (int(self.rxFreq) + self.offsetHz))) #print ('TXRX Offset:%d With Adjust: %d' % (self.txrxOffset, int(self.txrxOffset - self.offsetHz)) ) shortF = self.rxFreq[5:] # strip leading three, 10368 here self.lcdRx.display(shortF[:3] + "." + shortF[3:]) # display xxx.xxx #print shortF[:3] + "." + shortF[3:] #self.lcdRx.display(self.rxFreq) ConnSock.close() except: print('Could not connect to Rx.') os._exit(1) def connTx( self ): # ****** make sure turns PTT off when program exits? ******** try: connSock = socket(AF_INET, SOCK_STREAM) connSock.connect((self.txHost, self.txPort)) while 1: time.sleep(0.1) if ((self.txrxOffsetFixed - self.offsetHz) != self.txrxOffset): # Adjust TX offset if changed in GUI self.txrxOffset = self.txrxOffsetFixed - self.offsetHz if (self.syncTxReq): #print ("TX Sync requested %s" % self.syncTxFreq) sendString = ('F %s\n' % self.syncTxFreq) connSock.send(sendString.encode()) self.syncTxReq = 0 elif (self.pttSet == 1): #print ("PTT ON REQUESTED") connSock.send("T 1\n".encode()) os.system( "(/usr/bin/mosquitto_pub -h 192.168.0.201 -t '/radio/amp/set2' -m 'ON')" ) self.pttSet = 0 elif (self.pttSet == 2): #print ("PTT OFF REQUESTED") connSock.send('T 0\n'.encode()) os.system( "(/usr/bin/mosquitto_pub -h 192.168.0.201 -t '/radio/amp/set2' -m 'OFF')" ) self.pttSet = 0 elif (self.linkButton.isChecked()): newTx = int(self.rxFreq) - self.txrxOffset if (int(self.txFreq) != newTx): #print ("Not equal, sync %d to %d" %(int(self.txFreq), newTx)) sendString = ('F %s\n' % newTx) connSock.send(sendString.encode()) self.txFreq = str(newTx) else: connSock.send('f\n'.encode()) else: connSock.send('f\n'.encode()) output = connSock.recv(100).decode() if not (re.match(r'^[0-9]+$', str(output))): #print ("Unexpected non frequency response from hamlib: " + str(output)) continue self.txFreq = str(output) #print ('TX Frequency offset: %d read: %d real: %d' % (self.offsetHz, int(self.txFreq), (int(self.txFreq) + self.offsetHz))) shortF = self.txFreq[3:] # strip leading three, 432 here self.lcdTx.display(shortF[:3] + "." + shortF[3:]) # display xxx.xxx #print shortF[:3] + "." + shortF[3:] #self.lcdTx.display(self.txFreq) ConnSock.close() except: print('Could not connect to Tx.') os._exit(1)
import pulsectl # streams that should be regarded as a game game = [ "Overwatch.exe;Audio Stream", "wine64-preloader;Simple DirectMedia Layer", "FactoryGame-Win64-Shipping.exe;Audio Stream", "FactoryGame-Win64-Shipping.exe;audio stream #1", "Borderlands2;Simple DirectMedia Layer", "Overwatch.exe;audio stream #1", "We Were Here.exe;audio stream #1", "FMOD Ex App;Mixer Stream", # "ZOOM VoiceEngine;playStream", <-- uncomment when zoom fixes their shitty app ] with pulsectl.Pulse("sink handler") as pulse: # get indices of sinks: sinks = pulse.sink_list() game_sink = next(filter(lambda s: "Game" in s.description, sinks)) chat_sink = next(filter(lambda s: "Chat" in s.description, sinks)) monitor_sink = next(filter(lambda s: "HDMI" in s.description, sinks)) for sink in pulse.sink_input_list(): props = sink.proplist app_name = props["application.name"] description = props["media.name"] id_str = app_name + ";" + description if os.environ["PA_OUTPUT"] == "monitor": pulse.sink_input_move(sink.index, monitor_sink.index) continue
import time import pulsectl pulse = pulsectl.Pulse('app-volume-ctl2') while True: for a in pulse.sink_input_list(): print(a.proplist) print("===") time.sleep(1)
def __init__(self): super().__init__() self.pulse = pulsectl.Pulse() self.sink_name = self.pulse.server_info().default_sink_name
import pulsectl with pulsectl.Pulse('volume-increaser') as pulse: for sink in pulse.sink_list(): # Volume is usually in 0-1.0 range, with >1.0 being soft-boosted pulse.volume_change_all_chans(sink, 0.1)
import pulsectl pulse = pulsectl.Pulse() for source in pulse.source_list(): print(f"Source {source.index} mute state is: {source.mute}") pulse.mute(source) for source in pulse.source_list(): print(f"Source {source.index} mute state is: {source.mute}")
import json import subprocess import pulsectl import gi gi.require_version('Gtk', '3.0') gi.require_version('AppIndicator3', '0.1') gi.require_version('Notify', '0.7') from gi.repository import Gtk as gtk from gi.repository import AppIndicator3 as appindicator from gi.repository import Notify as notify APPINDICATOR_ID = 'soundprofileswitcher' pulse = pulsectl.Pulse('soundprofileswitcher') def main(): indicator = appindicator.Indicator.new(APPINDICATOR_ID, "", appindicator.IndicatorCategory.SYSTEM_SERVICES) indicator.set_status(appindicator.IndicatorStatus.ACTIVE) indicator.set_menu(build_menu()) notify.init(APPINDICATOR_ID) gtk.main() def build_menu(): menu = gtk.Menu() for card in pulse.card_list(): menu.append(gtk.SeparatorMenuItem()) radio_group = None
def OnKeyPress(self, keyId): print("key press: {}".format(keyId)) focus = self.GetFocus() parent = focus.GetParent() if keyId == Key.FOCUS_RIGHT.value: focus = self.GetFocusTiled() if focus.IsFloating( ) else focus.GetNext() #focus = focus.GetAdjacent(chamfer.adjacent.RIGHT); focus.Focus() elif keyId == Key.FOCUS_LEFT.value: focus = self.GetFocusTiled() if focus.IsFloating( ) else focus.GetPrev() #focus = focus.GetAdjacent(chamfer.adjacent.LEFT); focus.Focus() elif keyId == Key.FOCUS_DOWN.value: focus = focus.GetNext() #focus = focus.GetAdjacent(chamfer.adjacent.DOWN); focus.Focus() elif keyId == Key.FOCUS_UP.value: focus = focus.GetPrev() #focus = focus.GetAdjacent(chamfer.adjacent.UP); focus.Focus() elif keyId == Key.MOVE_RIGHT.value: focus.MoveNext() elif keyId == Key.MOVE_LEFT.value: focus.MovePrev() elif keyId == Key.FOCUS_PARENT.value: if parent is None: return parent.Focus() elif keyId == Key.FOCUS_CHILD.value: focus = focus.GetFocus() if focus is None: return focus.Focus() elif keyId == Key.FOCUS_MRU.value: try: self.shiftFocus.shaderFlags &= ~ShaderFlag.FOCUS_NEXT.value except AttributeError: pass try: self.shiftFocus = self.shiftFocus.GetTiledFocus() except AttributeError: self.shiftFocus = focus.GetTiledFocus() if self.shiftFocus is None: return self.shiftFocus.shaderFlags |= ShaderFlag.FOCUS_NEXT.value self.GrabKeyboard(True) elif keyId == Key.FOCUS_FLOAT.value: try: self.shiftFocus.shaderFlags &= ~ShaderFlag.FOCUS_NEXT.value except AttributeError: pass try: self.shiftFocus = self.shiftFocus.GetFloatFocus() except AttributeError: self.shiftFocus = focus.GetFloatFocus() if self.shiftFocus is None: return self.shiftFocus.shaderFlags |= ShaderFlag.FOCUS_NEXT.value self.GrabKeyboard(True) elif keyId == Key.FOCUS_FLOAT_PREV.value: #TODO, get previous from the focus history pass elif keyId == Key.FOCUS_PARENT_RIGHT.value: if parent is None: return parent1 = parent.GetNext() focus = parent1.GetFocus() if focus is None: return focus.Focus() elif keyId == Key.FOCUS_PARENT_LEFT.value: if parent is None: return parent1 = parent.GetPrev() focus = parent1.GetFocus() if focus is None: return focus.Focus() elif keyId == Key.YANK_CONTAINER.value: print("yanking container...") self.yank = {focus} elif keyId == Key.YANK_APPEND_CONTAINER.value: print("yanking container (append)...") try: self.yank.add(focus) except AttributeError: self.yank = {focus} elif keyId == Key.PASTE_CONTAINER.value: print("pasting container...") try: if focus in self.yank: print( "cannot paste on selection (one of the yanked containers)." ) self.yank.remove(focus) peers = list(self.yank) focus1 = focus.GetFocus() peers[0].Move(focus) #warning! need to know wether yank is still alive if focus1 is None: focus = focus.GetParent() for peer in peers[1:]: peer.Move(focus) except (AttributeError, IndexError): print("no containers to paste.") elif keyId == Key.LIFT_CONTAINER.value: sibling = focus.GetNext() peer = sibling.GetNext() if peer is not focus: sibling = peer.Place(sibling) peer = sibling.GetNext() while peer is not focus: peer1 = peer.GetNext() peer.Move(sibling) peer = peer1 elif keyId == Key.LAYOUT.value: if parent is None: return layout = { chamfer.layout.VSPLIT: chamfer.layout.HSPLIT, chamfer.layout.HSPLIT: chamfer.layout.VSPLIT }[parent.layout] parent.ShiftLayout(layout) elif keyId == Key.SPLIT_V.value: #TODO: add render flags property, bitwise OR them print("split armed.") focus.splitArmed = not focus.splitArmed elif keyId == Key.FULLSCREEN.value: print("setting fullscreen") focus.SetFullscreen(not focus.fullscreen) elif keyId == Key.CONTRACT_ROOT_RESET.value: root = self.GetRoot() root.canvasOffset = (0.0, 0.0) root.canvasExtent = (0.0, 0.0) root.ShiftLayout(root.layout) elif keyId == Key.CONTRACT_ROOT_LEFT.value: root = self.GetRoot() root.canvasOffset = (root.canvasOffset[0] + 0.1, root.canvasOffset[1]) root.canvasExtent = (root.canvasExtent[0] + 0.1, root.canvasExtent[1]) #root.canvasOffset; root.ShiftLayout(root.layout) elif keyId == Key.CONTRACT_ROOT_RIGHT.value: root = self.GetRoot() root.canvasExtent = (root.canvasExtent[0] + 0.1, root.canvasExtent[1]) root.ShiftLayout(root.layout) elif keyId == Key.EXPAND_ROOT_LEFT.value: root = self.GetRoot() root.canvasOffset = (root.canvasOffset[0] - 0.1, root.canvasOffset[1]) root.canvasExtent = (root.canvasExtent[0] - 0.1, root.canvasExtent[1]) root.ShiftLayout(root.layout) elif keyId == Key.EXPAND_ROOT_RIGHT.value: root = self.GetRoot() root.canvasExtent = (root.canvasExtent[0] - 0.1, root.canvasExtent[1]) root.ShiftLayout(root.layout) elif keyId == Key.CONTRACT_RESET.value: focus.canvasOffset = (0.0, 0.0) focus.canvasExtent = (0.0, 0.0) focus.ShiftLayout(focus.layout) elif keyId == Key.CONTRACT_HORIZONTAL.value: focus.canvasOffset = (focus.canvasOffset[0] + 0.05, focus.canvasOffset[1]) focus.canvasExtent = (focus.canvasExtent[0] + 0.10, focus.canvasExtent[1]) focus.ShiftLayout(focus.layout) elif keyId == Key.CONTRACT_VERTICAL.value: focus.canvasOffset = (focus.canvasOffset[0], focus.canvasOffset[1] + 0.05) focus.canvasExtent = (focus.canvasExtent[0], focus.canvasExtent[1] + 0.10) focus.ShiftLayout(focus.layout) elif keyId == Key.EXPAND_HORIZONTAL.value: focus.canvasOffset = (focus.canvasOffset[0] - 0.05, focus.canvasOffset[1]) focus.canvasExtent = (focus.canvasExtent[0] - 0.10, focus.canvasExtent[1]) focus.ShiftLayout(focus.layout) elif keyId == Key.EXPAND_VERTICAL.value: focus.canvasOffset = (focus.canvasOffset[0], focus.canvasOffset[1] - 0.05) focus.canvasExtent = (focus.canvasExtent[0], focus.canvasExtent[1] - 0.10) focus.ShiftLayout(focus.layout) elif keyId == Key.KILL.value: focus.Kill() elif keyId == Key.LAUNCH_TERMINAL.value: psutil.Popen(["termite"], stdout=None, stderr=None) elif keyId == Key.LAUNCH_BROWSER.value: psutil.Popen(["firefox"], stdout=None, stderr=None) elif keyId == Key.LAUNCH_BROWSER_PRIVATE.value: psutil.Popen(["firefox", "--private-window"], stdout=None, stderr=None) elif keyId == Key.AUDIO_VOLUME_UP.value: if "pulsectl" in sys.modules: with pulsectl.Pulse('volume-increaser') as pulse: for sink in pulse.sink_list(): pulse.volume_change_all_chans(sink, 0.05) elif keyId == Key.AUDIO_VOLUME_DOWN.value: if "pulsectl" in sys.modules: with pulsectl.Pulse('volume-increaser') as pulse: for sink in pulse.sink_list(): pulse.volume_change_all_chans(sink, -0.05) elif keyId == Key.MONITOR_BRIGHTNESS_UP.value: psutil.Popen(["xbacklight", "-inc", "20"]) elif keyId == Key.MONITOR_BRIGHTNESS_DOWN.value: psutil.Popen(["xbacklight", "-dec", "20"])
weekdays = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"] def time(): today = datetime.datetime.today() now = datetime.datetime.now() time_string = weekdays[today.weekday()] + " {:%H:%M}".format(now) text = time_string t = (now.hour * 60 + now.minute) / 60 fade_value = -t * (t - 24) / 144 #Parabola bg_color = lerp_as_hsv(colors["yellow"], colors["red"], fade_value) return section(text, bg_color) pulse = pulsectl.Pulse("lemonbar", threading_lock=True) def volume(): sink = pulse.sink_list()[0] if sink.mute: text = "MUTE" fade_value = 0.0 else: vol = round(sink.volume.value_flat * 100) text = "VOL {}%".format(vol) fade_value = (vol / 100)**2 bg_color = lerp_as_hsv(colors["dark_blue"], colors["yellow"], fade_value) return section(text, bg_color)
def test_connect(self): with pulsectl.Pulse('t', server=self.sock_unix) as pulse: si = pulse.server_info() with pulsectl.Pulse('t', server=self.sock_tcp4) as pulse: si4 = pulse.server_info() self.assertEqual(vars(si), vars(si4)) with pulsectl.Pulse('t', server=self.sock_tcp6) as pulse: si6 = pulse.server_info() self.assertEqual(vars(si), vars(si6))
import pulsectl pulse = pulsectl.Pulse('pulsepy') preferred_output = [ "CalDigit Thunderbolt 3 Audio Analogue Stereo", "Built-in Audio Analogue Stereo" ] preferred_input = [ "RØDE VideoMic NTG Analogue Stereo", "CalDigit Thunderbolt 3 Audio Analogue Stereo", "Built-in Audio Analogue Stereo" ] outputs = {} inputs = {} for sink in pulse.sink_list(): outputs[sink.description] = sink for source in pulse.source_list(): inputs[source.description] = source for s in preferred_output: if s in outputs: pulse.sink_default_set(outputs[s]) print("Sink set to '" + s + "'") break for s in preferred_input: if s in inputs:
def test_server_info(self): with pulsectl.Pulse('t', server=self.sock_unix) as pulse: si, srcs, sinks = pulse.server_info(), pulse.source_list(), pulse.sink_list() self.assertEqual(len(srcs), 2) self.assertEqual(len(sinks), 2)
import sys from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QSystemTrayIcon, QMenu, QAction, QWidget, QWidgetAction, QSlider from PyQt5.QtCore import Qt from fbs_runtime.application_context.PyQt5 import ApplicationContext from shutil import copyfile import contextlib import os import pulsectl pulse = pulsectl.Pulse("t") class CadmusPulseInterface: @staticmethod def cli_command(command): if not isinstance(command, list): command = [command] with contextlib.closing(pulsectl.connect_to_cli()) as s: for c in command: s.write(c + "\n") @staticmethod def load_modules(mic_name, mic_rate, cadmus_lib_path): print(mic_name) print(mic_rate) print(cadmus_lib_path) pulse.module_load( "module-null-sink",
def test_get_sink_src(self): with pulsectl.Pulse('t', server=self.sock_unix) as pulse: src, sink = pulse.source_list()[0], pulse.sink_list()[0] self.assertEqual(sink.index, pulse.get_sink_by_name(sink.name).index) self.assertEqual(src.index, pulse.get_source_by_name(src.name).index)
def run_gui(): with pulsectl.Pulse("pulseaudio-loopback-tool") as pulseaudio: palt_gui = PaltGui(pulseaudio) palt_gui.run_gui()
def processCommand(self, command, x, url, number): msg = "Unknown command" longMsg = None if command == "power off": if self.can_poweroff(): self.ioloop.add_timeout(datetime.timedelta(seconds=3), self.cmd_poweroff) msg = "Powering off" else: msg = "Cannot power off" elif command == "sleep": if self.can_sleep(): self.ioloop.add_timeout(datetime.timedelta(seconds=3), self.cmd_sleep) msg = "Sleeping" else: msg = "Cannot sleep" elif command == "reboot": if self.can_reboot(): self.ioloop.add_timeout(datetime.timedelta(seconds=3), self.cmd_reboot) msg = "Rebooting" else: msg = "Cannot reboot" elif command == "lock": self.cmd_lock() msg = "Locking" elif command == "unlock": self.cmd_unlock() msg = "Unlocking" elif command == "open": if x: results = yield self.cmd_findApp(x.strip().lower()) if len(results) > 0: fn = results[0][7:] # remove file:// name = yield self.getAppName(fn) if name: msg = "Opening " + name longMsg = "Opening " + name + ": " + fn else: msg = "Opening" longMsg = "Opening " + fn self.ioloop.add_callback( lambda: self.cmd_openApp(fn, name)) else: msg = "No results found" else: msg = "Missing program to start" elif command == "close": msg = "Not implemented yet" elif command == "kill": msg = "Not implemented yet" elif command == "locate": if x: # Search might be slow try: results = yield tornado.gen.with_timeout( datetime.timedelta(seconds=3.5), self.cmd_locateDB(x)) except tornado.gen.TimeoutError: msg = "Timed out" else: self.locateResults = {} if results: msg = "Found " + str(len(results)) + " results" longMsg = "Results:\n" for i, r in enumerate(results): self.locateResults[i + 1] = url_unescape(r) longMsg += str(i + 1) + ") " + r + "\n" else: msg = "No results found" else: msg = "Missing search query" elif command == "fetch": if number: try: item = int(re.search(r'\d+', number).group()) except ValueError: msg = "Invalid item number: " + number except AttributeError: msg = "Invalid item number: " + number else: if item in self.locateResults: # Input filename, what we saved from the locate command inputFile = self.locateResults[item] # Output filename ext = os.path.splitext(inputFile)[-1] fn = datetime.datetime.now().strftime( "LinuxControl-Fetch-%Y-%m-%d-%Hh-%Mm-%Ss") + ext outputFile = os.path.join(os.environ["HOME"], "Dropbox", fn) msg = "Fetching item " + str(item) longMsg = "Fetching item "+str(item)+": copying"+ \ inputFile+" to "+outputFile self.ioloop.add_callback( lambda: self.cmd_fetchFile(inputFile, outputFile)) else: msg = "Item not found in last locate results" else: msg = "Please specify which item of your locate command to fetch." elif command == "set volume": if number: try: volume = int(re.search(r'\d+', number).group()) except ValueError: msg = "Invalid percentage: " + number except AttributeError: msg = "Invalid percentage: " + number else: with pulsectl.Pulse('setting-volume') as pulse: for sink in pulse.sink_list(): pulse.volume_set_all_chans(sink, volume / 100.0) msg = "Volume set" longMsg = "Volume set to " + str(volume) + "%" else: msg = "Please specify volume percentage" elif command == "stop": msg = "Not implemented yet" elif command == "take a picture": filename = os.path.join( os.environ["HOME"], "Dropbox", datetime.datetime.now().strftime( "LinuxControl-Picture-%Y-%m-%d-%Hh-%Mm-%Ss.png")) msg = "Taking picture, saving in Dropbox" longMsg = "Taking picture: " + filename self.ioloop.add_callback(lambda: self.cmd_image(filename)) elif command == "screenshot": filename = os.path.join( os.environ["HOME"], "Dropbox", datetime.datetime.now().strftime( "LinuxControl-Screenshot-%Y-%m-%d-%Hh-%Mm-%Ss.png")) msg = "Taking screenshot, saving in Dropbox" longMsg = "Taking screenshot: " + filename self.ioloop.add_callback(lambda: self.cmd_screenshot(filename)) elif command == "download": msg = "Not implemented yet" elif command == "start recording": msg = "Not implemented yet" elif command == "stop recording": msg = "Not implemented yet" return msg, longMsg
def mic_set(): print( '-------------------------------------------------------------------') print("[SETUP_MIC_SPEAKER] - THIẾT LẬP MICROPHONE VÀ MIC") try: os.system('sudo apt-get install -y -qq python3-pip >> /dev/null') except: pass if platform.machine() == 'x86': m = os.system( 'sudo apt-get install -y -qq libpulse0:i386 >> /dev/null') elif platform.machine() == 'armv7l': n = os.system('sudo apt-get install -y -qq libpulse0>> /dev/null') try: import pulsectl except: pass import pulsectl os.system('killall pulseaudio') os.system('sudo killall pulseaudio') os.system('pulseaudio --start') time.sleep(1) pulse = pulsectl.Pulse('my-client') blist = pulse.source_list() ee = len(blist) slist = pulse.sink_list() ss = len(slist) # print(blist) print('') print("ĐANG NHẬN DIỆN MICROPHONE...") print('') time.sleep(0.7) for i in range(0, ee): print('MIC ' + str(i) + ' :' + blist[i].name) if 'OmniVision' in blist[i].name: source = blist[i].name print( '------------------->>>MIC ARRAY SONY PS3<<<--------------------------' ) elif 'mono' in blist[i].name and 'input' in blist[ i].name and 'monitor' not in blist[i].name: source = blist[i].name print( '------------------------->>>MIC USB<<<-----------------------------' ) elif 'input' in blist[i].name and 'monitor' not in blist[i].name: source = blist[i].name print( '------------------------->>>MIC KHÁC<<<-----------------------------' ) else: source = blist[0].name time.sleep(0.7) # print ('KHÔNG RÕ LOẠI MIC BẠN ĐANG SỬ DỤNG HOẶC BẠN QUÊN CHƯA GẮN MIC') # iii = input('NHẬP TÊN MIC BẠN SỬ DỤNG (TỐT NHẤT LÀ BÔI ĐEN ĐOẠN TÊN BÊN TRÊN): ') # source = str(iii) print("--->>>XONG") print('') time.sleep(1) print("THIẾT LẬP MẶC ĐỊNH CỔNG RA 3.5 PI...") print('') # time.sleep(0.7) for j in range(0, ss): print('OUTPUT LIST: ' + str(j) + ' LÀ THIẾT BỊ ' + slist[j].description) if 'USB' in slist[j].description and 'output' in slist[j].name: sink = slist[j].index print('ĐẦU RA USB SOUND') elif 'Analog Stereo' in slist[j].description and 'output' in slist[ j].name and 'fallback' not in slist[j].name: sink = slist[j].index print('ĐẦU RA 3.5 PI') else: sink = slist[0].index print('CÁC ĐẦU RA KHÁC VUI LÒNG QUAN SÁT VÀ CÀI ĐẶT THỦ CÔNG') # sss = input('NHẬP SỐ THỨ TỰ OUTPUT LIST: ') # sink = int(sss) # time.sleep(0.7) # os.system('amixer cset numid=3 1') print("--->>>XONG") print('') time.sleep(1) if str(source) != '': os.system('pacmd set-default-source ' + str(source)) os.system('pactl set-source-volume 0 80%') if str(sink) != '': os.system('pacmd set-default-sink ' + str(sink)) os.system('pactl set-sink-volume 0 80%') print('') print('NẾU MIC KHÔNG HOẠT ĐỘNG HÃY DÙNG LỆNH DƯỚI ĐÂY. LƯU Ý ĐÚNG TÊN MIC') print('') print( 'pacmd set-default-source tên_mic, ví dụ: pacmd set-default-source ' + str(source)) print('') print( 'NẾU KHÔNG CÓ ÂM THANH PHÁT RA LOA. HÃY CÀI ĐẶT LẠI OUTPUT VỚI LỆNH: ') print( 'pacmd set-default-sink + số_thứ_tự_sinklist, ví dụ: pacmd set-default-sink ' + str(sink)) print('') # i=0 # while i<5: # try: # i+=1 # if 'OmniVision' in blist[i].name: # source_ps3 = blist[i].name # with open('/etc/pulse/default.pa','a+') as pulsewrite: # pulsewrite.writelines('set-default-source '+ str(source_ps3)) # print("Cài đặt mic PS3 làm mic mặc định") # break # elif 'mono' in blist[i].name: # source_mono = blist[i].name # with open('/etc/pulse/default.pa','a+') as pulsewrite: # pulsewrite.writelines('set-default-source '+ str(source_mono)) # print("Cài đặt mic USB làm mic mặc định") # break # except: # pass time.sleep(1) os.system('pacmd set-source-volume 1 120000') time.sleep(1) print('[SETUP] - KẾT THÚC SETUP BOT LBMINH') try: print('SỐ MODULE LỖI BƯỚC 1: ' + str(len(c))) print('SỐ MODULE LỖI BƯỚC 2: ' + str(len(d))) time.sleep(1) if len(c) == 0 and len(d) == 0: print('CHÚC MỪNG BẠN. CÀI ĐẶT THÀNH CÔNG') print( 'VUI LÒNG THIẾT LẬP CẤU HÌNH TRONG FILE CONFIG.YAML TRƯỚC KHI DÙNG' ) print(" ") print( "GÕ: 'python3 main.py' ĐỂ CHẠY THỦ CÔNG SAU KHI ĐÃ CẤU HÌNH XONG" ) print( "GÕ: 'sudo systemctl start bot.service' ĐỂ KHỞI ĐỘNG BOT SAU 4 PHÚT" ) else: print('VUI LÒNG CÀI LẠI CÁC MODULE LỖI') except: pass
import sys from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QSystemTrayIcon, QMenu, QAction from fbs_runtime.application_context.PyQt5 import ApplicationContext from shutil import copyfile import contextlib import os import pulsectl pulse = pulsectl.Pulse('t') class AudioMenuItem(QAction): def __init__(self, text, parent, disable_menu, mic_name, context): super().__init__(text, parent) self.mic_name = mic_name self.disable_menu = disable_menu self.context = context self.setStatusTip('Use the %s as an input for noise suppression' % text) self.triggered.connect( lambda: enable_noise_suppression(self, self.context)) def cli_command(command): with contextlib.closing(pulsectl.connect_to_cli()) as s: s.write(command) def load_modules(mic_name, context):