veromix/0000755000175100017500000000000011766302605011053 5ustar nikkibuveromix/common/0000755000175100017500000000000011766302605012343 5ustar nikkibuveromix/common/MediaPlayer.py0000644000175100017500000001722611766302605015121 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2011-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import signal, os, datetime, dbus #from veromixcommon.PulseProxyObjects import * ## class MediaPlayer(): Stopped, Playing, Paused, NA = list(range(4)) def __init__(self): self._state = MediaPlayer.NA self._position = 0 self._length = 0 self._artwork = None self._cover_string = "" self._last_playing_icon = None self._fetch_extended_info = False self.last_position_change = datetime.datetime.now() def init_connection(self): pass def disconnect(self): pass def state(self): return self._state def set_state(self, state): self._state = state def name(self): return None def play(self): pass def pause(self): pass def next_track(self): pass def prev_track(self): pass def seek(self, position): pass def length(self): return self._length def set_length(self, length): self._length = length def position(self): return self._position def set_position(self, position): self._position = position def artwork(self): return self._artwork def set_artwork(self, artwork): self._artwork = artwork def get_application_name(self): name = self.name() if str(name).find("org.mpris.MediaPlayer2.") == 0: return name[23:] if str(name).find("org.mpris.") == 0: return name[10:] return name def fetch_extended_info(self): return self._fetch_extended_info def set_fetch_extended_info(self, boolean): self._fetch_extended_info = boolean def is_nowplaying_player(self): return False def is_mpris2_player(self): return False def signal_data_updated(self): pass ## Abstract !! def url_path_of(self, string): pass def trigger_timer_callback(self, timeout, function): pass def create_pixmap(self, val): pass class Mpris2MediaPlayer(MediaPlayer): def __init__(self,name, dbus_proxy): MediaPlayer.__init__(self) self._name = name self._dbus_proxy = dbus_proxy self._seek_position = 0 self._timer_running = False def init_connection(self): self.connect_mpris2() def get_index(self): return self.name() def name(self): return self._name def play(self): self._dbus_proxy.nowplaying_play(self.name()) def pause(self): self._dbus_proxy.nowplaying_pause(self.name()) def next_track(self): self._dbus_proxy.nowplaying_next(self.name()) def prev_track(self): self._dbus_proxy.nowplaying_prev(self.name()) def seek(self, position): self.schedule_set_mpris2_position(position) def connect_mpris2(self): if self._dbus_proxy: self._dbus_proxy.connect_mpris2_player(self.on_mpris2_properties_changed, str(self.name()) ) self.poll_dbus_info() def set_fetch_extended_info(self, boolean): MediaPlayer.set_fetch_extended_info(self, boolean) if boolean: self.poll_dbus_info() def poll_dbus_info(self): if not self._dbus_proxy: return properties = {} try: # Once connected we get notified via dbus about changes - but initially we fetch them manually properties[dbus.String("PlaybackStatus")] =self._dbus_proxy.mpris2_get_playback_status(self.name()) properties[dbus.String("Metadata")] = self._dbus_proxy.mpris2_get_metadata(self.name()) self.on_mpris2_properties_changed(None, properties, None) self.fetch_position() except: pass def on_mpris2_properties_changed(self, interface, properties, signature): changed = False if type(properties) == type(dbus.String("")): return if dbus.String("PlaybackStatus") in list(properties.keys()): status = properties[dbus.String("PlaybackStatus")] old_state = self.state() if status == 'Playing': self.set_state(MediaPlayer.Playing) else: self.set_state(MediaPlayer.Paused) if old_state != self.state(): changed = True if dbus.String("Metadata") in list(properties.keys()): metadata = properties[dbus.String("Metadata")] if type(metadata) == type(dbus.String("")): return if type(metadata) == type(dbus.Struct([""])): #deadbeef fallback metadata = metadata[0] #self.mpris2_trackid = metadata[dbus.String("mpris:trackid")] if dbus.String("mpris:artUrl") in list(metadata.keys()): val = self.url_path_of(str(metadata[dbus.String("mpris:artUrl")])) if val != self._cover_string: changed = True if (os.path.isfile(val)): self.set_artwork(self.create_pixmap(val)) else: self.set_artwork(None) self._cover_string = val if dbus.String("mpris:length") in list(metadata.keys()): length = metadata[dbus.String("mpris:length")] / 1000000 if length != self.length(): changed = True self.set_length(length) if changed: self.signal_data_updated() def fetch_position(self): if self.fetch_extended_info(): changed = False pos = self._dbus_proxy.mpris2_get_position(self.name()) position = pos / 1000000 if position != self.position() and position <= self.length(): changed = True self.set_position(position) if changed: self.signal_data_updated() self.trigger_timer_callback(1500, self.fetch_position) def is_mpris2_player(self): return True # Don't flood players while dragging the slider. # Update the position at most every 500ms def schedule_set_mpris2_position(self, value=0): # FIXME now = datetime.datetime.now() time = (now - self.last_position_change ).microseconds if value > 0: # value is % of current track: Calculate position in seconds new_pos = (value * self.length()) / 100 self._seek_position = int((new_pos - self.position()) * 1000000) self.last_position_change = now else: # callback from timer self._timer_running = False if time > 500000: self._dbus_proxy.mpris2_set_position(self.name() , self._seek_position) #self.set_position(self._seek_position / 1000000) self.last_position_change = now else: if not self._timer_running: self._timer_running = True self.trigger_timer_callback(500, self.schedule_set_mpris2_position) veromix/common/__init__.py0000644000175100017500000000130611766302605014454 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . veromix/common/PulseProxyObjects.py0000644000175100017500000004466511766302605016400 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gettext i18n = gettext.gettext from .LADSPAEffects import * try: import html except: class html: @staticmethod def escape(arg): return arg try: import urllib.parse unquote = urllib.parse.unquote except: import urllib unquote = urllib.unquote ## FIXME bad name: how is one "channel" of a strereo stream called? class SinkChannel(): def __init__(self, name, volume): self.name = name self.volume = volume def get_name(self) : return self.name def get_volume(self): return self.volume def printDebug(self): print(" ") print(" " + self.name + "") print(" " + self.volume + "") print(" ") class AbstractSink(): # FIXME KDE DEFAULT_ICON = "audio-x-generic-symbolic" def __init__(self, pulseaudio, index, name, muted, volume, props): self.pulse_proxy = pulseaudio self.index = index self.name = name self.mute = muted self. volume = volume self.props = props self._update_nice_values(pulseaudio.veromix) def is_default(self): return False def get_index(self): return int(self.index) def get_name(self) : return self.name def toggle_mute(self): pass def step_volume_by(self, STEP, up): vol = self.get_volume() if up: vol = vol + STEP else: vol = vol - STEP if vol < 0: vol = 0 if vol > 100: # FIXME self.get_max_volume_value(): vol = 100 #self.get_max_volume_value() self.set_volume(self.volumeDiffFor(vol)) def set_volume(self, values): pass def get_volume(self): val =0 for t in list(self.volume.keys()): val += list(self.volume[t].values())[0] return int(val/ len(list(self.volume.keys()))) def getChannels(self): channels = [] for key in list(self.volume.keys()): t = self.volume[key] name = list(t.keys())[0] vol = list(t.values())[0] channels.append(SinkChannel(name,vol)) return channels def volumeDiffFor(self, value): vol = [] diff = self.get_volume() - value for key in list(self.volume.keys()): value = list(self.volume[key].values())[0] - diff if value < 0: value = 0 vol.append(value ) return vol def printDebug(self): print("") print(" " + self.index + "") print(" " + self.name + "") print(" " + self.mute + "") print(" ") for channel in self.getChannels(): channel.printDebug() print(" ") print(" ") for key in list(self.props.keys()): print(" <" + key + ">", self.props[key],"") print(" ") print("") def isMuted(self): # FIXME return self.is_muted() def is_muted(self): return self.mute == 1 def get_monitor_name(self): return "Veromix monitor" ## testing def is_sourceoutput(self): return False def is_sinkoutput(self): return False def is_source(self): return self.is_sinkoutput() def is_sinkinput(self): return False def is_sink(self): return False def is_media_player(self): return False def properties(self): return self.props def _update_nice_values(self, veromix=None): self._nice_text = "" self._nice_title = self.name self._nice_icon = self.DEFAULT_ICON def get_nice_text(self): return html.escape(self._nice_text) def get_nice_title(self): return html.escape(self._nice_title) def get_nice_icon(self): return self._nice_icon def get_nice_title_and_name(self): return "" + self.get_nice_title() + " " + self.get_nice_text() def is_default_sink(self): return False def get_output_index(self): return int(self.get_index()) def get_owner_module(self): if "owner_module" in self.props: return self.props["owner_module"] return None def has_monitor(self): if "has_monitor" in self.props: return (self.props["has_monitor"] == "True") return False class SinkInfo(AbstractSink): # FIXME KDE DEFAULT_ICON = "audio-card-symbolic" def __init__(self, pulseaudio, index, name, muted, volume, props, ports, active_port): AbstractSink.__init__(self, pulseaudio, index, name, muted, volume, props) self.ports=ports self.active_port=active_port def is_sink(self): return True def be_default_sink(self): self.pulse_proxy.set_default_sink(self.name) def is_default(self): if "isdefault" in self.props: return self.props["isdefault"] == "True" return False def set_volume(self, values): self.pulse_proxy.set_sink_volume(self.index, values) def toggle_mute(self): if self.isMuted(): self.pulse_proxy.set_sink_mute(self.index, False) else: self.pulse_proxy.set_sink_mute(self.index, True) def set_port(self, portstr): self.pulse_proxy.set_sink_port(self.index,portstr) def toggle_monitor(self): self.pulse_proxy.toggle_monitor_of_sink(self.index, self.get_monitor_name()) def kill(self): if self.is_ladspa_sink(): self.remove_ladspa_sink() def set_ladspa_sink(self,parameters): self.pulse_proxy.set_ladspa_sink(int(self.index), int(self.props["owner_module"]), str(parameters)) def remove_ladspa_sink(self): self.pulse_proxy.remove_ladspa_sink(int(self.props["owner_module"])) def remove_combined_sink(self): self.pulse_proxy.remove_combined_sink(int(self.props["owner_module"])) def is_default_sink(self): if "isdefault" in self.props: return self.props["isdefault"] == "True" return False def _update_nice_values(self, veromix=None): self._nice_text = "" self._nice_title = self.name self._nice_icon = self.DEFAULT_ICON text = "" try: self._nice_title = self.props["device_name"] except: pass def move_sink_input(self, target_sink): self.pulse_proxy.move_sink_input(int(target_sink), int(self.get_index())) def is_ladspa_sink(self): return "device.ladspa.module" in self.props.keys() def get_ladspa_master(self): return self.get_name() class SinkInputInfo(AbstractSink): def is_sinkinput(self): return True def set_volume(self, values): self.pulse_proxy.set_sink_input_volume(self.index, values) def toggle_mute(self): if self.isMuted(): self.pulse_proxy.set_sink_input_mute(self.index, False) else: self.pulse_proxy.set_sink_input_mute(self.index, True) def toggle_monitor(self): self.pulse_proxy.toggle_monitor_of_sinkinput(self.index, self.get_output_index(), self.get_monitor_name()) def kill(self): self.pulse_proxy.sink_input_kill(self.index) def _update_nice_values(self, veromix=None): text = self.name bold = self.props["app"] iconname = None if self.props["app_icon"] != "None": iconname = self.props["app_icon"] if veromix: if iconname == None and self.props["app"] != "None": iconname = veromix.query_application(self.props["app"], self.DEFAULT_ICON) if bold == "knotify": bold = i18n("Event Sounds") text = "" iconname = 'dialog-information' if bold == "npviewer.bin" or bold == "plugin-container": bold = i18n("Flash Player") text = "" iconname = 'flash' if bold == "chromium-browser": bold = i18n("Chromium Browser") text = "" if bold == "Skype": if text == "Event Sound": text = i18n("Event Sound") if text == "Output": text = i18n("Voice Output") if veromix: if text == "LADSPA Stream" or ("media.name" in self.props.keys() and self.props["media.name"] == "LADSPA Stream"): for sink in veromix.get_sink_widgets(): if sink.pa_sink_proxy().get_owner_module() == self.get_owner_module(): bold = sink.pa_sink_proxy().props["device.ladspa.name"] text = "" iconname = sink.pa_sink_proxy().props["device.icon_name"] # FIXME if bold in ["", "None", None]: bold = text text = "" if text in ["None", None]: text = "" if iconname in ["", "None", None]: iconname = self.DEFAULT_ICON # FIXME "mixer-pcm" self._nice_text = text self._nice_title = bold self._nice_icon = iconname def get_output_index(self): return int(self.props["sink"]) class SourceInfo(AbstractSink): DEFAULT_ICON = "audio-input-microphone-symbolic" def __init__(self, pulseaudio, index, name, muted, volume, props, ports, active_port): AbstractSink.__init__(self, pulseaudio, index, name, muted, volume, props) self.ports=ports self.active_port=active_port def is_sinkoutput(self): return True def set_volume(self, values): self.pulse_proxy.set_source_volume(self.index, values) def toggle_mute(self): if self.isMuted(): self.pulse_proxy.set_source_mute(self.index, False) else: self.pulse_proxy.set_source_mute(self.index, True) def set_port(self, portstr): self.pulse_proxy.set_source_port(self.index,portstr) def toggle_monitor(self): self.pulse_proxy.toggle_monitor_of_source(self.index, self.get_monitor_name()) def kill(self): pass def _update_nice_values(self, veromix=None): self._nice_text = "" self._nice_title = self.name self._nice_icon = self.DEFAULT_ICON if "description" in self.props.keys(): self._nice_title = self.props["description"] # self._nice_text = self.name class SourceOutputInfo(AbstractSink): def is_sourceoutput(self): return True def set_volume(self, values): pass def toggle_mute(self): pass def kill(self): pass def toggle_monitor(self, parent): pass def get_volume(self): return 0 def getChannels(self): return [] def _update_nice_values(self, veromix=None): self._nice_text = "" self._nice_title = self.name self._nice_icon = self.DEFAULT_ICON if "description" in self.props.keys(): self._nice_title = self.props["description"] self._nice_text = self.name if self.name.find("ALSA") == 0 and "application.process.binary" in self.props.keys(): self._nice_title = self.props[ "application.process.binary"] self._nice_text = self.props[ "application.name"] if "application.icon_name" in self.props.keys(): self._nice_icon = self.props["application.icon_name"] if veromix: if self._nice_icon == self.DEFAULT_ICON and "app" in self.props.keys(): self._nice_icon = veromix.query_application(self.props["app"], self.DEFAULT_ICON) if self._nice_icon is None and self._nice_title == "plugin-container": self._nice_icon = 'flash' class CardProfile: def __init__(self, name, properties): self.name = name self.properties = properties self.description = properties["description"] # FIXME other values def printDebug(self): print("") print(" ", self.name, "") print(" ") for key in list(self.properties.keys()): print(" <" + key + ">", self.properties[key],"") print(" ") print("") class CardInfo: def __init__(self, index, name, properties, active_profile_name, profiles_dict): self.index = index self.name = name self.properties = properties self.active_profile_name = active_profile_name self.profiles_dict = profiles_dict self.profiles = [] for key in list(self.profiles_dict.keys()): self.profiles.append(CardProfile(key, self.profiles_dict[key] )) def get_property(self,key): if self.properties == None: return "" if key in list(self.properties.keys()): return self.properties[key] return "" def get_description(self): return self.get_property("device.description") def get_profiles(self): return self.profiles def get_active_profile(self): for profile in self.card_profiles(): if self.active_profile_name == profile.name: return profile return None def get_active_profile_name(self): return self.active_profile_name def printDebug(self): print("") print(" ", self.index, "") print(" ", self.name, "") print(" ") for key in list(self.properties.keys()): print(" <" + key + ">", self.properties[key],"") print(" ") print("") class ModuleInfo: def __init__(self, index, name, argument, n_used, auto_unload): self.index = int(index) self.name = name self.argument = argument self.n_used = n_used self.auto_unload = auto_unload def get_index(self): return self.index def set_pa_sink_proxy(self, pa_sink_proxy): self.pa_sink_proxy = pa_sink_proxy self.ladspa_parse_module_info(self.argument, self.pa_sink_proxy) def get_ladspa_nice_title(self): text = "" try: if self.is_ladspa_preset(): text = str(self.get_ladspa_name()) + " - " + str(self.get_ladspa_preset_name()) else: text = str(self.get_ladspa_name()) except: pass return text def ladspa_parse_module_info(self, string, pa_sink_proxy): args = {} controls = string.split(" ") for entry in controls: s = entry.split("=") if len(s) == 2: args[s[0]]=s[1] args["name"] = "" if "device.ladspa.name" in pa_sink_proxy.props.keys(): args["name"] = pa_sink_proxy.props["device.ladspa.name"] args["preset_name"] = unquote(str(args["sink_name"])) self.ladspa_module_info = args def get_ladspa_effect_name(self): return self.get_ladspa_label() def get_ladspa_preset_name(self): return self.ladspa_module_info["preset_name"] def get_ladspa_name(self): return self.ladspa_module_info["name"] def get_ladspa_label(self): return self.ladspa_module_info["label"] def get_ladspa_control_string(self): return self.ladspa_module_info["control"] def get_ladspa_control(self): string = self.get_ladspa_control_string() controls = [] if str(string) != "": controls = string.split(",") return controls def get_lasapa_number_of_controls(self): return len(self.get_ladspa_control()) def get_ladspa_effect_settings(self): effect = None for preset in LADSPAEffects().effects(): if preset["label"] == self.get_ladspa_label(): effect = preset return effect def is_ladspa_preset(self): return self.get_ladspa_name() != self.get_ladspa_preset_name() def get_ladspa_scale(self, number): effect = self.get_ladspa_effect_settings() return effect["scale"][number] def get_ladspa_range(self, number): effect = self.get_ladspa_effect_settings() return effect["range"][number] def get_ladspa_scaled_range(self, number): scale = self.get_ladspa_scale(number) scaled = [0,0] scaled[0] = (self.get_ladspa_range(number)[0]) * scale scaled[1] = (self.get_ladspa_range(number)[1]) * scale return scaled def get_ladspa_effect_label(self, number): effect = self.get_ladspa_effect_settings() return effect["labels"][number] def get_ladspa_control_value(self, number): return float(self.get_ladspa_control()[number]) def get_ladspa_control_value_scaled(self, number): return int(self.get_ladspa_scale(number) * self.get_ladspa_control_value(number)) def set_ladspa_sink(self, values, pa_sink_proxy): control = "" effect = self.get_ladspa_effect_settings() i = 0 # multiply (visible) values with scale for val in values: scale = self.get_ladspa_scale(i) control = control + str(float(val)/float(scale)) + "," i = i + 1 self.ladspa_module_info["control"] = control[:-1] parameters = "sink_name=%(sink_name)s master=%(master)s plugin=%(plugin)s label=%(label)s control=%(control)s" % self.ladspa_module_info pa_sink_proxy.set_ladspa_sink(parameters) def get_ladspa_master(self): return self.ladspa_module_info["master"] def save_preset(self, name=None): if name != None: self.ladspa_module_info["preset_name"] = str(name) self.ladspa_module_info["sink_name"] = str(name) LADSPAPresetLoader().write_preset(self.ladspa_module_info) veromix/common/LADSPAEffects.py0000644000175100017500000004407211766302605015170 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2011-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os,re,math,shutil _presets = None try: import commands getstatusoutput = commands.getstatusoutput except: import subprocess getstatusoutput = subprocess.getstatusoutput class LADSPAPresetLoader: configdir = os.getenv('HOME') + "/.pulse" user_preset_directory = configdir + "/presets" def install_ladspa_presets_if_needed(self): veromix_path = os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.realpath(__file__), os.path.pardir)), os.path.pardir)) + "/data/presets" if os.path.exists(self.user_preset_directory): return print("Veromix copying default presets to: " + self.user_preset_directory) try: shutil.copytree(veromix_path, self.user_preset_directory) except: print("Veromix exception while copying presets: ") def get_user_preset_directory(self): return self.user_preset_directory def read_preset(self, filename): f = open(filename, "r") rawdata=f.read().split('\n') f.close preset = { #"plugins" = #"mbeq" "label" : str(rawdata[1]), # "name" : "Multiband EQ", "name" : str(rawdata[2]), #unused "preamp" : str(rawdata[3]), #"plugin": "mbeq_1197", "plugin" : str(rawdata[0]), "preset_name" : str(rawdata[4]), # unused currently "inputs" : "50,100,156,220,311,440,622,880,1250,1750,2500,3500,5000,10000,20000" } #"control": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0", num_ladspa_controls = int(rawdata[5]) control = "" for x in range(0, num_ladspa_controls): control = control + str(rawdata[6 + x]) + "," preset["control"] = control[:-1] effect = None for settings in LADSPAEffects().effects(): if (settings["label"] == preset["label"]): effect = settings if effect: preset["range"] = effect["range"] #"range" : [[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30],[-70, 30]], preset["scale"] = effect["scale"] #"scale" : [1,1,1, 1,1,1, 1,1,1, 1,1,1, 1,1,1], preset["labels"] = effect["labels"] #"labels" : ["50Hz","100Hz","156Hz","220Hz","311Hz","440Hz","622Hz","880Hz","1250Hz","1750Hz","2500Hz","3500Hz","5000Hz","10000Hz","20000Hz",] _range = [] for x in range(0, num_ladspa_controls): _range.append([-30,30]) preset["range"] = _range else: _range = [] for x in range(0, num_ladspa_controls): _range.append([0,100]) preset["range"] = _range scale = [] for x in range(0, num_ladspa_controls): scale.append(1) preset["scale"] = scale labels = [] for x in range(0, num_ladspa_controls): labels.append("raw_"+str(x)) preset["labels"] = labels return preset def presets(self, do_reload=False): global _presets if _presets == None or do_reload: self.read_presets() _presets = sorted(_presets, key=lambda k: k['preset_name']) return _presets def read_presets(self): global _presets _presets = [] for path in self.listdir_fullpath(self.user_preset_directory): _presets.append(self.read_preset(path)) def listdir_fullpath(self, directory): if os.path.exists(directory): dir_list = os.listdir(directory) return [os.path.join(directory, x) for x in os.listdir(directory) if x.endswith('.preset')] return [] def preset_exists(self, name): return os.path.exists(self.preset_full_path(name)) def preset_full_path(self,name): tmp = ''.join(c for c in name if c not in ['\\', '/']) return self.get_user_preset_directory() + "/" + tmp + ".preset" def write_preset(self, plugin_settings): if not os.path.exists(self.get_user_preset_directory()): os.path.mkdir(self.get_user_preset_directory()) f = open(self.preset_full_path(str(plugin_settings["preset_name"])), "w") rawdata = [] rawdata.append(str(plugin_settings["plugin"])) rawdata.append(str(plugin_settings["label"])) rawdata.append(str(plugin_settings["name"])) rawdata.append(str(2)) # preamp rawdata.append(str(plugin_settings["preset_name"])) controls = plugin_settings["control"].split(",") num_ladspa_controls = len(controls) rawdata.append(str(num_ladspa_controls)) for i in controls: rawdata.append(str(i)) effect = None for settings in LADSPAEffects().effects(): if (settings["label"] == plugin_settings["label"]): effect = settings for i in effect["labels"]: rawdata.append(str(i)) for i in rawdata: f.write(str(i)+'\n') f.close() found = False self.presets(True) _effects = None class LADSPAEffects: blacklist_file = os.getenv('HOME') + "/.pulse/veromix-ladspa-blacklist.conf" def effects(self, do_reload=False): global _effects if _effects == None or do_reload: blacklist = self.blacklist() _effects = [] for effect in self.all_effects(): if effect["preset_name"] not in blacklist: _effects.append(effect) return _effects def all_effects(self): _all_effects = fetch_plugins() _all_effects = sorted(_all_effects, key=lambda k: k['preset_name']) return _all_effects def blacklist(self): if not os.path.exists(self.blacklist_file): return [] f = open(self.blacklist_file, "r") rawdata = f.read().split('\n') f.close return rawdata def write_blacklist(self, blacklist): f = open(self.blacklist_file, "w") rawdata = [] for entry in blacklist: f.write(str(entry)+'\n') f.close() self.effects(True) def ladspa_sdk_available(self): status,output = getstatusoutput("listplugins") #status2, output = commands.getstatusoutput("analyseplugin") return status == 0 def fetch_plugins(): status,output = getstatusoutput("listplugins") if status != 0: print("Veromix LADSPA: command 'listplugins' returend an error - is it installed? Check if ladspa-sdk is installed.") return hardcoded_plugins() plugins = [] for line in output.split("\n"): if re.match (".*:$", line): name = line[0:-1] filename = os.path.basename(name) try: status,out = getstatusoutput("analyseplugin " + filename) if status != 0: print("Veromix LADSPA: command 'analyseplugin' returend an error:") print(out) else: lines = out.split("\n") "one file (for example amp.so can have multiple pluigin-definitions)" plugin = [] for line in lines: if len(line) == 0: if len(plugin) > 1: p = None #print plugin p = extract_plugin(filename, plugin) if p: plugins.append(p) plugin = [] else: plugin.append(line) except: print("Problem during plugin extraction") if len(plugins) == 0: return hardcoded_plugins() return plugins def extract_plugin(filename, lines): definition = { "label" : value_from_line(lines[1]), # FIXME "preset_name" : value_from_line(lines[0]) + " (" + filename[0:-3] + ")" , "plugin" : filename[0:-3], "name" : value_from_line(lines[0]) } has_input = False has_output = False port_hints = lines[10:] for port_hint in port_hints: # "50Hz gain (low shelving)" input, control, -70 to 30, default 0 match = re.match(r'^.*\"(.*)\" input, control, (-?[\d\.]*) to (-?[\d\.]*), default (-?[\d\.]*)(, logarithmic)?', port_hint) if match: if "labels" not in list(definition.keys()): definition["labels"] = [] definition["labels"].append(match.group(1)) #print match.group(1), match.group(2), match.group(3) if "range" not in list(definition.keys()): definition["range"] = [] lower = match.group(2) upper = match.group(3) if lower == "...": lower = "-1000" if upper == "...": upper = "1000" lower = float(lower) if '.' in lower else int(lower) upper = float(upper) if '.' in upper else int(upper) definition["range"].append([lower,upper]) if "control" not in list(definition.keys()): definition["control"] = "" definition["controlnumbers"] = [] definition["control"] = definition["control"] + "," + str(match.group(4)) definition["controlnumbers"].append(float(match.group(4)) if '.' in match.group(4) else int(match.group(4))) if "control_type" not in list(definition.keys()): definition["control_type"] = [] if match.group(5): definition["control_type"].append("log") else: definition["control_type"].append("dec") # "Input" input, audio match = re.match(r'.*" input, audio', port_hint) if match: has_input = True #"Output" output, audio match = re.match(r'.*" output, audio', port_hint) if match: has_output = True #"latency" output, control match = re.match(r'.*" output, control', port_hint) if match: pass # Currently this module only works with plugins that have one audio input port named "Input" and one output with name "Output". # http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Modules#module-ladspa-sink if has_input and has_output: # some cleanup if "control" in list(definition.keys()): definition["control"] = definition["control"][1:] definition["scale"] = [] index = 0 for assoc in definition["range"]: lower = assoc[0] upper = assoc[1] control_default = definition["controlnumbers"][index] index = index + 1 num = 1 if isinstance(lower, float): num = len(str(lower).split(".")[1]) if isinstance(upper, float): tmp = len(str(upper).split(".")[1]) if tmp > num: num = tmp if isinstance(control_default, float): tmp = len(str(control_default).split(".")[1]) if tmp > num: num = tmp if (upper - lower) < 11: definition["scale"].append(pow(10,num)) else: definition["scale"].append(1) else: definition["labels"] = [] definition["range"] = [] definition["control"] = "" definition["scale"] = [] return definition return None def value_from_line(line): match = re.search(r'"(.*)"', line) return match.group(0)[1:-1] def hardcoded_plugins(): return [ { "preset_name" : "Multiband EQ", "label" : "mbeq", "name" : "Multiband EQ", "plugin": "mbeq_1197", "control": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0", "range" : [[-70, 30],[-70, 30],[-70, 30], [-70, 30],[-70, 30],[-70, 30], [-70, 30],[-70, 30],[-70, 30], [-70, 30],[-70, 30],[-70, 30], [-70, 30],[-70, 30],[-70, 30]], "scale" : [1,1,1, 1,1,1, 1,1,1, 1,1,1, 1,1,1], "labels" : ["50Hz","100Hz","156Hz", "220Hz","311Hz","440Hz", "622Hz","880Hz","1250Hz", "1750Hz","2500Hz","3500Hz", "5000Hz","10000Hz","20000Hz",] }, { "preset_name" : "DJ Equalizer", "label" : "dj_eq_mono", "name" : "DJ Equalizer", "plugin": "dj_eq_1901", "control": "0,0,0", "range" : [[-70, 6],[-70, 6],[-70, 6]], "scale" : [1,1,1], "labels" : ["Lo gain","Mid gain","Hi gain"]}, { "preset_name" : "Flanger", "label" : "flanger", "name" : "Flanger", "plugin": "flanger_1191", "control": "6.325,2.5,0.33437,0", "range" : [[0.1, 25],[0, 10],[0, 100],[-1, 1]], "scale" : [100,10,10, 10], "labels" : ["Delay base","Max slowdown","LFO frequency", "Feedback"] }, { "preset_name" : "Pitch Scaler", "label" : "pitchScale", "name" : "Pitch Scaler", "plugin": "pitch_scale_1193", "control": "1", "range" : [[0.5, 2]], "scale" : [100], "labels" : ["Co-efficient"]}, { "preset_name" : "Multivoice Chorus", "label" : "multivoiceChorus", "name" : "Multivoice Chorus", "plugin": "multivoice_chorus_1201", "control": "1,10,0.5,1,9,0", "range" : [[1, 8], [10, 40], [0, 2], [0, 5], [2, 30], [-20, 0]], "scale" : [1,10,10,10, 10, 10 ], "labels" : ["Voices", "Delay base", "Voice separation", "Detune", "LFO frequency", "Output attenuation"] } ] ## GOOD #sink_name="sink_name=ladspa_output.dj_eq_1901.dj_eq."+str(self.ladspa_index) #plugin = "plugin=dj_eq_1901" #label = "label=dj_eq_mono" #control = "control=0,0,0" # fun! #sink_name="sink_name=ladspa_output.multivoice_chorus_1201.multivoiceChorus."+str(self.ladspa_index) #plugin = "plugin=multivoice_chorus_1201" #label = "label=multivoiceChorus" #control = "control=0,0,0,0,0,0" ## fun #sink_name="sink_name=ladspa_output.pitch_scale_1193.pitchScale."+str(self.ladspa_index) #plugin = "plugin=pitch_scale_1193" #label = "label=pitchScale" #control = "control=1.9" ##works but .. #sink_name="sink_name=ladspa_output.flanger_1191.flanger."+str(self.ladspa_index) #plugin = "plugin=flanger_1191" #label = "label=flanger" #control = "control=0,0,0,0" ## not working? #sink_name="sink_name=ladspa_output.df_flanger_1438.djFlanger."+str(self.ladspa_index) #plugin = "plugin=dj_flanger_1438" #label = "label=djFlanger" #control = "control=0,0,0,0" ## .. #sink_name="sink_name=ladspa_output.phasers_1217.autoPhaser."+str(self.ladspa_index) #plugin = "plugin=phasers_1217" #label = "label=autoPhaser" #control = "control=0,0,0,0,0" ## does not work #sink_name="sink_name=ladspa_output.dj_eq_1901.dj_eq."+str(self.ladspa_index) #plugin = "plugin=dj_eq_1901" #label = "label=dj_eq" #control = "control=0,0,0" ## no #sink_name="sink_name=ladspa_output.decay_1886.decay."+str(self.ladspa_index) #plugin = "plugin=decay_1886" #label = "label=decay" #control = "control=0" ## i dont hear it #sink_name="sink_name=ladspa_output.delay_1898.delay_n."+str(self.ladspa_index) #plugin = "plugin=delay_1898" #label = "label=delay_n" #control = "control=0,0" ## i dont hear it #sink_name="sink_name=ladspa_output.delay_1898.delay_l."+str(self.ladspa_index) #plugin = "plugin=delay_1898" #label = "label=delay_l" #control = "control=0,0" ## i dont hear it #sink_name="sink_name=ladspa_output.delay_1898.delay_c."+str(self.ladspa_index) #plugin = "plugin=delay_1898" #label = "label=delay_c" #control = "control=0,0" ## does not work (stereo) #sink_name="sink_name=ladspa_output.karaoke_1409.karaoke."+str(self.ladspa_index) #plugin = "plugin=karaoke_1409" #label = "label=karaoke" #control = "control=-50" ## not work (stereo) #sink_name="sink_name=ladspa_output.plate_1423.plate."+str(self.ladspa_index) #plugin = "plugin=plate_1423" #label = "label=plate" #control = "control=0,0,0" ## less fun #sink_name="sink_name=ladspa_output.pitch_scale_1194.pitchScaleHQ."+str(self.ladspa_index) #plugin = "plugin=pitch_scale_1194" #label = "label=pitchScaleHQ" #control = "control=1.9" if __name__ == '__main__': for x in fetch_plugins(): print(x["preset_name"]) print(" labels:" + str(x["labels"])) print(" control: " + str(x["control"])) print(" range: " + str(x["range"])) print(" scale: " + str(x["scale"])) veromix/common/Utils.py0000644000175100017500000001026111766302605014015 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys, os try: from xdg import BaseDirectory _XDG_SERVICE_DIR = BaseDirectory.xdg_data_home + "/dbus-1/services/" except: _XDG_SERVICE_DIR = os.path.expanduser("~/.local/share/dbus-1/services/") try: from xdg import BaseDirectory _XDG_CONFIG_DIR = BaseDirectory.xdg_config_home + "/veromix/" except: _XDG_CONFIG_DIR = os.path.expanduser("~/.config/veromix/") def createDbusServiceDescription(path, use_qt): if "usr/share/veromix" in os.path.realpath(__file__): return True print ("Outputting dbus-servie file") service_dir = os.path.join(_XDG_SERVICE_DIR) createDirectory(service_dir) # File to create fn = service_dir+"org.veromix.pulseaudio.qt.service" if not use_qt: fn = service_dir+"org.veromix.pulseaudio.glib.service" exec_dir = str(path) # File contents c = [] c.append("[D-BUS Service]\n") if use_qt: c.append("Name=org.veromix.pulseaudio.qt\n") else: c.append("Name=org.veromix.pulseaudio.glib\n") c.append("Exec="+exec_dir+"\n") # Write file try: f = open(fn,"w") f.writelines(c) f.close() except: print ("Problem writing to file: " + fn) print ("Unexpected error:", sys.exc_info()[0]) try: import subprocess subprocess.getstatusoutput("chmod u+x "+exec_dir) except: import commands commands.getstatusoutput("chmod u+x "+exec_dir) def createDirectory(d): if not os.path.isdir(d): try: os.makedirs(d) except: print ("Problem creating directory: "+d) print ("Unexpected error:", sys.exc_info()[0]) def pixmapFromSVG( name): from PyKDE4.plasma import Plasma from PyKDE4.kdeui import KIcon svg = Plasma.Svg() svg.setImagePath("icons/audio") if not svg.isValid(): return KIcon(name).pixmap(22,22) svg.setContainsMultipleImages(False) return svg.pixmap(name) ## FIXME : copied from VeromixUtils encodings = [ "ascii", "utf_8", "big5", "big5hkscs", "cp037", "cp424", "cp437", "cp500", "cp737", "cp775", "cp850", "cp852", "cp855", "cp856", "cp857", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866", "cp869", "cp874", "cp875", "cp932", "cp949", "cp950", "cp1006", "cp1026", "cp1140", "cp1250", "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256", "cp1257", "cp1258", "euc_jp", "euc_jis_2004", "euc_jisx0213", "euc_kr", "gb2312", "gbk", "gb18030", "hz", "iso2022_jp", "iso2022_jp_1", "iso2022_jp_2", "iso2022_jp_2004", "iso2022_jp_3", "iso2022_jp_ext", "iso2022_kr", "latin_1", "iso8859_2", "iso8859_3", "iso8859_4", "iso8859_5", "iso8859_6", "iso8859_7", "iso8859_8", "iso8859_9", "iso8859_10", "iso8859_13", "iso8859_14", "iso8859_15", "johab", "koi8_r", "koi8_u", "mac_cyrillic", "mac_greek", "mac_iceland", "mac_latin2", "mac_roman", "mac_turkish", "ptcp154", "shift_jis", "shift_jis_2004", "shift_jisx0213", "utf_32", "utf_32_be", "utf_32_le", "utf_16", "utf_16_be", "utf_16_le", "utf_7", "utf_8_sig" ] def in_unicode(string): '''make unicode''' if isinstance(string, unicode): return string for enc in encodings: try: utf8 = unicode(string, enc) return utf8 except: if enc == encodings[-1]: #raise UnicodingError("still don't recognise encoding after trying do guess.") return "problem with string decoding" return "problem with string decoding" veromix/plasma/0000755000175100017500000000000011766302605012330 5ustar nikkibuveromix/plasma/contents/0000755000175100017500000000000011766302605014165 5ustar nikkibuveromix/plasma/contents/ui/0000755000175100017500000000000011766302605014602 5ustar nikkibuveromix/plasma/contents/ui/about.ui0000644000175100017500000000340111766302605016251 0ustar nikkibu Form 0 0 400 320 400 320 Form Version Qt::Vertical 20 40 Homepage <a href="http://code.google.com/p/veromix-plasmoid/">http://code.google.com/p/veromix-plasmoid/</A> X.Y veromix/plasma/contents/ui/nowplaying.ui0000644000175100017500000000340311766302605017330 0ustar nikkibu Form 400 340 Form Use KDE nowplaying dataengine Use mpris2 Media player blacklist: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Running media players: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Show album art veromix/plasma/contents/ui/appearance.ui0000644000175100017500000001167511766302605017252 0ustar nikkibu Form 0 0 310 159 Form Popup Mode QComboBox::AdjustToContents Close when losing focus Close manually Background QComboBox::AdjustToContents No background Translucent background Standard background Notification Show toolip Layout Use tabs Always show sources Show context menu button Show unit values Autostart meters true Meters can be very CPU intensive! You can always enable meters by double clicking a channel. Qt::Vertical 20 40 Homepage <a href="http://code.google.com/p/veromix-plasmoid/">http://code.google.com/p/veromix-plasmoid/</A> Version X.Y veromix/plasma/contents/locale0000777000175100017500000000000011766302605020065 2../../data/localeustar nikkibuveromix/plasma/contents/icons0000777000175100017500000000000011766302605017615 2../../data/iconsustar nikkibuveromix/plasma/contents/code/0000755000175100017500000000000011766302605015077 5ustar nikkibuveromix/plasma/contents/code/SortedLayout.py0000644000175100017500000001644311766302605020117 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyQt4.QtGui import * from SinkInputUI import InputSinkUI from SinkInputUI import SinkUI from SinkMbeqUI import SinkMbeqUI class SortedLayout(QGraphicsLinearLayout): def __init__(self, orient, reverse): QGraphicsLinearLayout.__init__(self, orient) self.reverse= reverse self.channels = {} self.sink_pool = [] self.sink_input_pool = [] def get_new_sink_input(self, veromix): if len(self.sink_input_pool) == 0: return InputSinkUI(veromix) else: val = self.sink_input_pool[0] self.sink_input_pool.remove(val) val.show() return val def get_new_sink(self, veromix, sink): sink_type = None if "device.ladspa.module" in sink.properties().keys(): # and sink_type = sink.properties()["device.ladspa.module"] #"device.ladspa.module" return self._get_new_ladspa_sink(veromix, str(sink_type)) else: return self._get_new_sink(veromix) def _get_new_ladspa_sink(self, veromix, sink_type): pool = [] for sink in self.sink_pool: # FIXME if sink.get_ladspa_type() == "ladspa": pool.append(sink) if len(pool) == 0: return SinkMbeqUI(veromix) else: val = pool[0] self.sink_pool.remove(val) val.show() return val def _get_new_sink(self, veromix): if len(self.sink_pool) == 0: return SinkUI(veromix) else: val = self.sink_pool[0] self.sink_pool.remove(val) val.show() return val def getChannels(self): return self.channels def get_source_widgets(self): return self._get_source_widgets(self.channels.values()) def _get_source_widgets(self, objects): toreturn = [] for obj in objects : if obj.isSourceOutput(): toreturn.append(obj) return toreturn def get_sinkoutput_widgets(self): return self._get_sinkoutput_widgets(self.channels.values()) def _get_sinkoutput_widgets(self, objects): toreturn = [] for obj in objects : if obj.isSinkOutput(): toreturn.append(obj) return toreturn def get_sink_widgets(self): return self._get_sink_widgets(self.channels.values()) def _get_sink_widgets(self, objects): toreturn = [] for obj in objects : if obj.isSink(): toreturn.append(obj) return toreturn def get_sinkinput_widgets(self): return self._get_sinkinput_widgets(self.channels.values()) def _get_sinkinput_widgets(self, objects): toreturn = [] for obj in objects : if obj.isSinkInput(): toreturn.append(obj) return toreturn def get_mediaplayer_widgets(self): toreturn = [] for index in self.channels.keys() : if self.channels[index].isNowplaying(): toreturn.append(self.channels[index]) return self._get_mediaplayer_widgets(self.channels.values()) def _get_mediaplayer_widgets(self, objects): toreturn = [] for obj in objects : if obj.isNowplaying(): toreturn.append(obj) return toreturn def getChannel(self, key): if key in self.channels.keys(): return self.channels[key] return None def addChannel(self, key, widget): if(key not in self.channels.keys()): self.channels[key] = widget sorting = self.sort(self.channels.values()) index = sorting.index(widget) self.insertItem(index, widget ) def removeChannel(self, key): if(key in self.channels.keys()): self.channels[key].hide() self.removeItem(self.channels[key]) if self.channels[key].isSinkInput(): self.sink_input_pool.append(self.channels[key]) if self.channels[key].isSink(): self.sink_pool.append(self.channels[key]) #self.channels[key].deleteLater() del self.channels[key] def check_ItemOrdering(self): while(self.needs_ordering()): self.order_items() def sorted_channels(self): return self.sort(self.channels.values()) def order_items(self): sorting = self.sort(self.channels.values()) for i in range(0,len(sorting)): if self.itemAt(i).graphicsItem () != sorting[i]: item = self.itemAt(i).graphicsItem() index = sorting.index(item) self.insertItem(index , item ) return def needs_ordering(self): sorting = self.sort(self.channels.values()) for i in range(0,len(sorting)): if self.itemAt(i).graphicsItem () != sorting[i]: return True return False def order_index(self, widget): return self.sort(self.channels.values()).index(widget) def sort(self,objects): sources = self._sort_by_attribute(self._get_source_widgets(objects), '_name') sourceoutputs = self._sort_by_attribute(self._get_sinkoutput_widgets(objects), '_name') sinks = self._sort_by_attribute(self._get_sink_widgets(objects), '_name') sink_inputs = self._sort_by_attribute(self._get_sinkinput_widgets(objects), '_name') mediaplayers = self._sort_by_attribute(self._get_mediaplayer_widgets(objects), '_name') sorting = [] for s in sinks: if s.isDefaultSink(): sinks.remove(s) sinks.insert(0,s) for s in sourceoutputs: sorting.append(s) for so in sources: if int(s.index) == int(so.get_assotiated_source()): sorting.append(so) #sinks.reverse() for s in sinks: sorting.append(s) for i in sink_inputs: if int(s.index) == int(i.getOutputIndex()): sorting.append(i) for m in mediaplayers: assoc = m.get_assotiated_sink_input() if assoc != None and int(i.index) == assoc.index: sorting.append(m) for i in set(objects).difference(set(sorting)): sorting.append(i) return sorting def _sort_by_attribute(self, objects,sortAttrib): nlist = map(lambda object, sortAttrib=sortAttrib: (getattr(object, sortAttrib),object), objects) nlist.sort(reverse=self.reverse) return map(lambda (key, object): object, nlist) veromix/plasma/contents/code/veromixcommon0000777000175100017500000000000011766302605022054 2../../../common/ustar nikkibuveromix/plasma/contents/code/NowPlaying.py0000644000175100017500000000643511766302605017550 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2011-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from veromixcommon.MediaPlayer import * class NowPlayingController(QObject, MediaPlayer): data_updated = pyqtSignal() def __init__(self, veromix, source): QObject.__init__(self) MediaPlayer.__init__(self) self.veromix = veromix self.proxy = source def init_connection(self): self.connect_nowplaying() def disconnect(self): pass def connect_nowplaying(self): self.veromix.applet.nowplaying_player_dataUpdated.connect(self.on_nowplaying_data_updated) def on_nowplaying_data_updated(self, name, values): if name == self.name(): self.parse_values(values) def parse_values(self,data): state = self.state() changed = False if QString('State') in data: if data[QString('State')] == u'playing': self.set_state(MediaPlayer.Playing) else: self.set_state(MediaPlayer.Paused) if state != self.state(): changed = True if QString('Position') in data: v = data[QString('Position')] if v != self.position(): self.set_position(v) changed = True if QString('Length') in data: v = data[QString('Length')] if v != self.length(): changed = True self.set_length(v) if QString('Artwork') in data: val = data[QString('Artwork')] if self.artwork() != val: self.set_artwork(val) if val == None: self.last_playing_icon = KIcon(self.get_pauseIcon()) else: self.last_playing_icon = QIcon(QPixmap(self.artwork)) if changed: self.data_updated.emit() def name(self): return self.proxy.destination() def play(self): self.proxy.startOperationCall(self.proxy.operationDescription('play')) def pause(self): self.proxy.startOperationCall(self.proxy.operationDescription('pause')) def next_track(self): self.proxy.startOperationCall(self.proxy.operationDescription('next')) def prev_track(self): self.proxy.startOperationCall(self.proxy.operationDescription('previous')) def seek(self, position): pos = int (position * self.length()/100) op = self.proxy.operationDescription('seek') op.writeEntry("seconds",pos) self.proxy.startOperationCall(op) def is_nowplaying_player(self): return True veromix/plasma/contents/code/MuteButton.py0000644000175100017500000000762411766302605017570 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyKDE4.plasma import Plasma from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from veromixcommon.Utils import * class MuteButton(Plasma.IconWidget): def __init__(self , parent): Plasma.IconWidget.__init__(self) self.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed,True) ) self.BIGSIZE= 24 self.setPreferredSize(QSizeF(self.BIGSIZE,self.BIGSIZE)) self.setMaximumSize(QSizeF(self.BIGSIZE,self.BIGSIZE)) self.setParent(parent) self.play_Icon = "audio-volume-high" self.muted_Icon = "audio-volume-muted" def mouseMoveEvent(self,event): self.parent().startDrag(event) def setAbsSize(self, value): self.BIGSIZE = value self.setPreferredSize(QSizeF(self.BIGSIZE,self.BIGSIZE)) self.setMaximumSize(QSizeF(self.BIGSIZE,self.BIGSIZE)) def setMuted(self, boolean): if boolean : self.setSvg("icons/audio", self.muted_Icon) else: self.setSvg("icons/audio", self.play_Icon) # compatibility with kde 4.4 def setSvg(self, path, name): svg = Plasma.Svg() svg.setImagePath("icons/audio") if svg.isValid(): Plasma.IconWidget.setSvg(self,path, name) else: self.setIcon(KIcon(name)) class InputMuteButton(MuteButton): def __init__(self , parent) : MuteButton.__init__(self,parent) self.setParent(parent) self.big_name = "mixer-pcm" self.status_icon = KIcon(self.play_Icon) #self.status_icon.setSvg("icons/audio", self.play_Icon) def setMuted(self, boolean): if boolean : self.status_icon = self.muted_Icon else: self.status_icon = self.play_Icon self.setIcon(self._draw_icon()) def setBigIconName(self, name): if self.big_name != name: self.big_name = name self.setIcon(self._draw_icon()) def _draw_icon(self ): if self.status_icon == self.muted_Icon: size = self.BIGSIZE size2= 22 #pos = self.size().height() - size2 + int(size2/4) pos = 8 orig = KIcon(self.big_name).pixmap(size2, size2) #over = KIcon(self.status_icon).pixmap(size2,size2) over = pixmapFromSVG(self.status_icon) #over = KIcon(self.big_name).pixmap(size2,size2) #orig = self.status_icon.pixmap(28,28) pixmap = QPixmap(size, size) pixmap.fill(Qt.transparent) p = QPainter(pixmap) #p.fillRect(QRect(0,0,size,size),QColor(0,100,1,250)) p.drawPixmap(0,0,orig) p.end() copy = QPixmap(pixmap) paint_copy = QPainter(copy) paint_copy.fillRect(pixmap.rect(), QColor(1,1,1,10)) paint_copy.end() pixmap.setAlphaChannel(copy) paint = QPainter(pixmap) #over = KIconLoader.loadIcon(loader, "audio-volume-muted", KIconLoader.NoGroup, size2, KIconLoader.DefaultState, "", "", True) paint.drawPixmap( pos , pos, over) paint.end() return QIcon(pixmap) else: return KIcon(self.big_name) veromix/plasma/contents/code/MediaPlayerUI.py0000644000175100017500000003216211766302605020107 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2011-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import dbus, os, datetime from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from PyKDE4.plasma import Plasma from LabelSlider import LabelSlider from LabelSlider import Label from Channel import Channel from MuteButton import * from veromixcommon.MediaPlayer import * class MediaPlayerUI(Channel): def __init__(self,name, veromix, controller): self.controller = controller Channel.__init__(self, veromix) self.controller.data_updated.connect(self.controller_data_updated) self.index = -1 self._state= None self._position = 0 self._artwork = "" self.last_playing_icon = KIcon(self.get_pauseIcon()) self.layout.setContentsMargins(6,0,6,2) self.controller.init_connection() def initArrangement(self): self.svg_path = self.veromix.applet.package().filePath('images', 'buttons.svgz') self.createMiddle() self.createSlider() self.create_prev_panel() self.create_frame() self.create_panel() self.create_prev_button() self.create_play_pause_button() self.create_next_button() self.create_next_panel() self.createPositionLabel() self.createLengthLabel() self.create_expander() def composeArrangement(self): self.layout.addItem(self.frame) self.frame_layout.addItem(self.panel) self.prev_panel_layout.addStretch() self.prev_panel_layout.addItem(self.prev) self.next_panel_layout.addStretch() self.next_panel_layout.addItem(self.next) self.prev_panel.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.next_panel.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.play.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.middle_layout.addStretch() self.middle_layout.addItem(self.play) self.panel.setContentsMargins(0,0,0,0) self.panel_layout.setContentsMargins(6,0,10,6) self.panel_layout.addStretch() self.panel_layout.addItem(self.prev_panel) self.panel_layout.addItem(self.middle) self.panel_layout.addItem(self.next_panel) self.panel_layout.addStretch() def on_expander_clicked(self): self.middle_layout.removeItem(self.slider) if (self.extended_panel_shown): self.extended_panel_shown = False #self.frame_layout.removeItem(self.extended_panel) self.extended_panel.setParent(None) self.panel_layout.setContentsMargins(6,0,10,6) self.extended_panel = None self.slider= None self.expander.setSvg("widgets/arrows", "left-arrow") else: self.extended_panel_shown = True self.create_settings_widget() #self.frame_layout.addItem(self.extended_panel) self.panel_layout.setContentsMargins(6,0,10,20) self.extended_panel.setPos(0, int(self.frame.size().height() - 15)) #self.expander.setSvg("widgets/arrows", "up-arrow") self.expander.setSvg("widgets/arrows", "down-arrow") self.controller.set_fetch_extended_info(self.extended_panel_shown) self.veromix.check_geometries() def _resize_widgets(self): #self.expander.setPos(int(self.panel.size().width() - self.expander.size().width()) ,self.panel.size().height() - self.expander.size().height()) self.expander.setPos(int(self.panel.size().width() - self.expander.size().width()) ,0) if self.extended_panel: self.extended_panel.resize(QSizeF(int(self.frame.size().width()), -1)) #self.extended_panel.setPos(0, int(self.frame.size().height() - 12)) def create_settings_widget(self): self.createLengthLabel() self.createPositionLabel() self.createSlider() self.extended_panel = QGraphicsWidget(self.frame) self.extended_panel_layout = QGraphicsLinearLayout(Qt.Horizontal) self.extended_panel.setLayout(self.extended_panel_layout) self.extended_panel.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.position_label.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)) self.length_label.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)) self.extended_panel_layout.addItem(self.position_label) self.extended_panel_layout.addItem(self.slider) self.extended_panel_layout.addItem(self.length_label) def controller_data_updated(self): self.update_state() self.update_cover() if self.extended_panel_shown: self.update_position() self.update_slider() def on_update_configuration(self): self.set_middle_size() if self.veromix.is_albumart_enabled(): self.middle.setIcon(KIcon()) self._on_upate_expander_enabled() def update_with_info(self, info): pass ## update ui def update_state(self): state = self.controller.state() if self._state != state: self._state = state if state == MediaPlayer.Playing: #self.play.setSvg(self.svg_path, "pause-normal") self.play.setIcon(KIcon("media-playback-pause")) if self.veromix.is_albumart_enabled(): self.middle.setIcon(self.last_playing_icon) else: #self.play.setSvg(self.svg_path, "play-normal") self.play.setIcon(KIcon("media-playback-start")) if self.veromix.is_albumart_enabled(): self.middle.setIcon(KIcon(self.get_pauseIcon())) def update_cover(self): if not self.veromix.is_albumart_enabled(): self.middle.setIcon(KIcon()) return True # FIXME val = self.controller._cover_string if self._artwork != val: self._artwork = val if val == None: self.last_playing_icon = KIcon(self.get_pauseIcon()) else: self.last_playing_icon = QIcon(QPixmap(self.controller.artwork())) self.middle.setIcon(self.last_playing_icon) def update_position(self): v = self.controller.position() if v != self._position: self._position = v pos_str = ( '%d:%02d' % (v / 60, v % 60)) self.position_label.setBoldText(pos_str) v = self.controller.length() if v : pos_str = ( '%d:%02d' % (v / 60, v % 60)) self.length_label.setBoldText(pos_str) def update_slider(self): if self.slider and self.extended_panel_shown: if self.controller.state() == MediaPlayer.Stopped: self.slider.setValueFromPulse(0) else: if self.controller.length() > 0 : v = self.controller.position() * 100 / self.controller.length() # if self.slider.check_pulse_timestamp(): self.slider.setValueFromPulse(v) def on_slider_action_triggered(self, action): value = self.slider.nativeWidget().sliderPosition() if value > -1 and (action == 7 or action == 3): self.controller.seek(value) ## initialize ui def context_menu_create_mute(self): pass def on_contextmenu_clicked(self, action): pass def context_menu_create_unlock_channels(self): action_unlock = QAction(i18n("Show position"), self.popup_menu) self.popup_menu.addAction(action_unlock) action_unlock.setCheckable(True) action_unlock.setChecked(self.extended_panel_shown) action_unlock.triggered.connect(self.on_expander_clicked) def create_next_panel(self): self.next_panel = QGraphicsWidget() self.next_panel_layout = QGraphicsLinearLayout(Qt.Vertical) self.next_panel_layout.setContentsMargins(0,0,0,0) self.next_panel.setLayout(self.next_panel_layout) def createPositionLabel(self): self.position_label = Label() self.position_label.setContentsMargins(0,0,0,0) self.position_label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding, True)) self.position_label.setAlignment(Qt.AlignRight) def createLengthLabel(self): self.length_label = Label() self.length_label.setContentsMargins(0,0,0,0) self.length_label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding, True)) self.length_label.setAlignment(Qt.AlignLeft) def create_prev_panel(self): self.prev_panel = Plasma.IconWidget() self.prev_panel_layout = QGraphicsLinearLayout(Qt.Vertical) self.prev_panel_layout.setContentsMargins(0,0,0,0) self.prev_panel.setLayout(self.prev_panel_layout) self.prev_panel.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)) def createMiddle(self): self.middle = Plasma.IconWidget() self.middle_layout = QGraphicsLinearLayout(Qt.Vertical) self.middle_layout.setContentsMargins(0,0,0,0) self.middle.setLayout(self.middle_layout) self.set_middle_size() self.middle.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) if self.veromix.is_albumart_enabled(): self.middle.setIcon(KIcon(self.get_pauseIcon())) def set_middle_size(self): if self.veromix.is_albumart_enabled(): self.CONTROLSBAR_SIZE = 80 else: self.CONTROLSBAR_SIZE = 30 self.middle.setMinimumHeight(self.CONTROLSBAR_SIZE) self.middle.setPreferredHeight(self.CONTROLSBAR_SIZE) self.middle.setMaximumHeight(self.CONTROLSBAR_SIZE) def create_next_button(self): self.next = MuteButton(self) self.next.setAbsSize(20) #self.next.setSvg(self.svg_path , "next-normal") self.next.setIcon(KIcon("media-skip-forward")) self.connect(self.next, SIGNAL("clicked()"), self.on_next_cb ) def create_prev_button(self): self.prev = MuteButton(self) self.prev.setAbsSize(20) #self.prev.setSvg(self.svg_path, "prev-normal") self.prev.setIcon(KIcon("media-skip-backward")) self.connect(self.prev, SIGNAL("clicked()"), self.on_prev_cb ) def create_play_pause_button(self): self.play = MuteButton(self) self.play.setAbsSize(-1) #self.play.setSvg(self.svg_path, "stop-normal") self.play.setIcon(KIcon("media-playback-stop")) self.connect(self.play, SIGNAL("clicked()"), self.on_play_cb ) def createMute(self): pass # callbacks def on_mute_cb(self): pass def on_next_cb(self): self.controller.next_track() def on_prev_cb(self): self.controller.prev_track() def on_play_cb(self): if self.controller.state() == MediaPlayer.Playing: self.controller.pause() else: self.controller.play() # helpers def name(self): return self.controller_name() def controller_name(self): return self.controller.name() def get_pauseIcon(self): name = self.get_application_name() app = self.veromix.query_application(str(name)) if app == None: return name return app def get_application_name(self): return self.controller.get_application_name() def matches(self, sink): sink = self.get_assotiated_sink_input() if sink == None: return False return True def get_assotiated_sink_input(self): name = str(self.get_application_name()).lower() for sink in self.veromix.get_sinkinput_widgets(): if str(name).lower().find(sink.name()) >= 0: return sink for sink in self.veromix.get_sinkinput_widgets(): if str(sink.name()).lower().find(name) >= 0 : return sink return None ## overrides def isNowplaying(self): return True def isSinkOutput(self): return False def isSinkInput(self): return False def createSlider(self): Channel.createSlider(self) self.slider.setMaximum(100) self.slider.volumeChanged.disconnect(self.on_slider_cb) self.slider.nativeWidget ().actionTriggered.connect(self.on_slider_action_triggered) ## testing def is_nowplaying_player(self): return self.controller.is_mpris2_player() def is_mpris2_player(self): return self.controller.is_mpris2_player() veromix/plasma/contents/code/SinkUI.py0000644000175100017500000001071011766302605016612 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import datetime from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from PyKDE4.plasma import Plasma from PyKDE4.kdecore import i18n from Channel import Channel class SinkUI(Channel): muteInfo = pyqtSignal(bool) def __init__(self , parent): self.automatically_muted = False self.extended_panel = None Channel.__init__(self, parent) self.setContentsMargins(0,0,0,0) def context_menu_create_custom(self): self.context_menu_create_ports() self.context_menu_create_sounddevices() action_device = QAction(i18n("Default Sink"), self.popup_menu) self.popup_menu.addAction(action_device) action_device.setCheckable(True) if self.isDefaultSink(): action_device.setChecked(True) action_device.setEnabled(False) else: action_device.setChecked(False) action_device.setEnabled(True) action_device.triggered.connect(self.on_set_default_sink_triggered) def create_menu_kill_sink(self): Channel.create_menu_kill_sink(self) if self.pa_sink.props["driver"]=="module-combine-sink.c": action=QAction(i18n("Uncombine"), self.popup_menu) self.popup_menu.addAction(action) action.triggered.connect(self.stopcombining) self.context_menu_create_sounddevices_other() def context_menu_create_effects(self): if not self.veromix.is_ladspa_enabled(): return effects_menu = QMenu(i18n("Add Effect"), self.popup_menu) effects_menu.triggered.connect(self.on_add_ladspa_effect) self.popup_menu.addMenu(effects_menu) self.populate_presets_menu(effects_menu, None, False) self.populate_switch_effect_menu(effects_menu, None) def stopcombining(self, action): self.pa_sink.remove_combined_sink() def on_add_ladspa_effect(self, action): self.on_set_ladspa_effect(action.text(), self.get_pasink_name()) def on_set_default_sink_triggered(self, action): if action: self.pa_sink.be_default_sink() def updateIcon(self): if self.isMuted(): self.updateMutedInfo(True) self.mute.setMuted(True) else: self.updateMutedInfo(False) self.mute.setMuted(False) def updateMutedInfo(self, aBoolean): if self.isDefaultSink(): self.muteInfo.emit(aBoolean) def update_label(self): if self.slider: self.slider.setBoldText(self.pa_sink.get_nice_title()) self.set_name(self.pa_sink.get_nice_title()) ## Drag and Drop Support def startDrag(self,event): drag = QDrag(event.widget()) drag.setPixmap(self.mute.icon().pixmap(self.size().height(),self.size().height())) mimedata = QMimeData() liste = [] liste.append(QUrl( "veromix://sink_index:"+str(int(self.index)) )) mimedata.setUrls(liste) drag.setMimeData(mimedata) #drag.setHotSpot(event.pos() - self.rect().topLeft()) dropAction = drag.start(Qt.MoveAction) def dropEvent(self, dropEvent): uris = dropEvent.mimeData().urls() for uri in uris: if uri.scheme() == "veromix": if uri.host() == "sink_index" and uri.port() != self.index: self.pa.create_combined_sink(self.index, uri.port()) elif uri.host() == "sink_input_index": self.pa.move_sink_input(uri.port(), self.index) def dragEnterEvent(self, event): uris = event.mimeData().urls() for uri in uris: if uri.scheme() == "veromix": if uri.host() == "sink_index" and uri.port() == self.index: return event.ignore() event.accept() veromix/plasma/contents/code/VeroMix.py0000644000175100017500000004472111766302605017052 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import datetime, dbus from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.plasma import Plasma from PyKDE4.kdeui import KIcon from PyKDE4.kdecore import * from PulseAudioProxy import PulseAudio from SortedLayout import SortedLayout from LockableScrollWidget import LockableScrollWidget from SinkUI import SinkUI from SinkInputUI import InputSinkUI from SourceUI import SourceUI from SourceOutputUI import SourceOutputUI from MediaPlayerUI import MediaPlayerUI class VeroMix(QGraphicsWidget): sinkOutputChanged = pyqtSignal() def __init__(self,parent): QGraphicsWidget.__init__(self) self.applet = parent self.pa = None self.last_resize_running = datetime.datetime.now() self.last_resize_running_timer_running = False self.card_infos = {} self.ladspa_index = 1 self.setFocusPolicy(Qt.TabFocus) def init(self): self.setAcceptsHoverEvents (True) self.layout = QGraphicsLinearLayout(Qt.Vertical, self) self.layout.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)) self.scroller = LockableScrollWidget(self) self.scroller.setMinimumSize(120,90) self.layout.addItem(self.scroller) if self.applet.formFactor() != Plasma.Planar : self.scroller.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.source_panel = QGraphicsWidget() self.sink_panel = QGraphicsWidget() self.scrolled_panel_layout = QGraphicsLinearLayout(Qt.Vertical) self.scrolled_panel_widget = QGraphicsWidget() self.scrolled_panel_widget.setLayout(self.scrolled_panel_layout) self.scrolled_panel_layout.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.scrolled_panel_layout.setContentsMargins(0,0,0,6) self.showsTabs = not self.applet.useTabs() self.switchView(True) self.source_panel_layout = SortedLayout(Qt.Vertical, False) self.source_panel_layout.setSpacing(0) self.source_panel.setLayout(self.source_panel_layout) self.source_panel_layout.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) if self.showsTabs: self.source_panel_layout.addStretch() self.sink_panel_layout = SortedLayout(Qt.Vertical, False) self.sink_panel_layout.setSpacing(0) self.sink_panel.setLayout(self.sink_panel_layout) self.sink_panel_layout.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.layout.setContentsMargins(0,0,0,0) self.source_panel_layout.setContentsMargins(0,0,0,0) self.sink_panel_layout.setContentsMargins(0,0,0,0) #QTimer.singleShot(4000, self.start_pa) self.start_pa() self.connect_mediaplayers() def switchView(self, startup=False): if self.showsTabs: self.scrolled_panel_layout = QGraphicsLinearLayout(Qt.Vertical) scrolled_panel = QGraphicsWidget() scrolled_panel.setLayout(self.scrolled_panel_layout) self.scrolled_panel_layout.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.scrolled_panel_layout.addItem(self.source_panel) self.scrolled_panel_layout.addItem(self.sink_panel) else: scrolled_panel = Plasma.TabBar() scrolled_panel.addTab(i18n("Playback"), self.sink_panel) scrolled_panel.addTab(i18n("Record"), self.source_panel) self.source_panel.show() self.scrolled_panel = scrolled_panel self.showsTabs = not self.showsTabs self.scroller.setWidget(self.scrolled_panel) if not startup: self.check_geometries() def on_update_configuration(self): for source in self.source_panel_layout.getChannels().values(): source.on_update_configuration() for sink in self.sink_panel_layout.getChannels().values(): sink.on_update_configuration() self.pa.set_autostart_meters(bool(self.applet.is_meter_visible())) # connect to pulseaudio(dbus) callbacks def start_pa(self): try: self.pa = PulseAudio(self) self.pa.connect_veromix_service() except Exception, e: self.showMessage(KIcon("script-error"), i18n("There is a problem with the backgroud-service. \
    \
  • If you just upgraded try killing the process named: VeromixServiceMain.py and relaunch this plasmoid
  • \
  • If you don't know how to do that consider rebooting

\ See wiki for more details (right click and copy url).")) print "\nError connecting to veromix-service:\n" , e, "\n" return self.connect(self.pa, SIGNAL("on_sink_input_info(PyQt_PyObject)"), self.on_sink_input_info) self.connect(self.pa, SIGNAL("on_sink_info(PyQt_PyObject)"), self.on_sink_info) self.connect(self.pa, SIGNAL("on_source_output_info(PyQt_PyObject)"), self.on_source_output_info) self.connect(self.pa, SIGNAL("on_source_info(PyQt_PyObject)"), self.on_source_info) self.connect(self.pa, SIGNAL("on_sink_remove(int)"), self.on_remove_sink) self.connect(self.pa, SIGNAL("on_sink_input_remove(int)"), self.on_remove_sink_input) self.connect(self.pa, SIGNAL("on_source_remove(int)"), self.on_remove_source) self.connect(self.pa, SIGNAL("on_source_output_remove(int)"), self.on_remove_source_output) self.connect(self.pa, SIGNAL("on_volume_meter_sink(int, float)"), self.on_volume_meter_sink) self.connect(self.pa, SIGNAL("on_volume_meter_sink_input(int, float)"), self.on_volume_meter_sink_input) self.connect(self.pa, SIGNAL("on_volume_meter_source(int, float)"), self.on_volume_meter_source) self.connect(self.pa, SIGNAL("on_card_info(PyQt_PyObject)"), self.on_card_info) self.connect(self.pa, SIGNAL("on_card_remove(int)"), self.on_remove_card) self.connect(self.pa, SIGNAL("on_module_info(int,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.on_module_info) self.pa.requestInfo() def connect_mediaplayers(self): self.applet.nowplaying_player_added.connect(self.on_mediaplayer_added) self.applet.nowplaying_player_removed.connect(self.on_mediaplayer_removed) self.connect(self.pa, SIGNAL("mpris2_player_added(QString, PyQt_PyObject)"), self.on_mediaplayer_added) self.connect(self.pa, SIGNAL("mpris2_player_removed(QString, PyQt_PyObject)"), self.on_mediaplayer_removed) ## helpers UI def check_geometries(self): self.check_ItemOrdering() count = 0 for source in self.source_panel_layout.getChannels().values(): if source.isSourceOutput(): count += 1 self.setSourcesPanelVisible( self.applet.get_always_show_sources() or count > 0) # REstore #self.sink_panel.adjustSize() #self.source_panel.adjustSize() #self.scrolled_panel.adjustSize() if self.applet.formFactor() == Plasma.Planar: pass else: self.trigger_schedule_timer() #self.updateGeometry() def do_scheduled_resize(self): now = datetime.datetime.now() if (now - self.last_resize_running).seconds > 1: self.adjustSize() self.setMinimumHeight(self.scrolled_panel.preferredSize().height()) self.setMaximumHeight(self.scrolled_panel.preferredSize().height()) self.last_resize_running = datetime.datetime.now() else: self.trigger_schedule_timer() def trigger_schedule_timer(self): if self.last_resize_running_timer_running: return self.last_resize_running_timer_running = True QTimer.singleShot(1000, self.on_schedule_resize_timer_cb) def on_schedule_resize_timer_cb(self): self.last_resize_running_timer_running = False self.do_scheduled_resize() def check_ItemOrdering(self): self.source_panel_layout.check_ItemOrdering() self.sink_panel_layout.check_ItemOrdering() pass def setSourcesPanelVisible(self, aBoolean): if self.showsTabs: return #if self.applet.isPopupShowing(): if aBoolean : self.source_panel.show() self.scrolled_panel_layout.insertItem(0, self.source_panel) else: self.source_panel.hide() self.scrolled_panel_layout.removeItem(self.source_panel) ## callbacks source output def on_source_output_info(self, sink): key = "sourceoutput" + str(sink.index) if not self.update_channel(key ,sink, self.source_panel_layout): widget = SourceOutputUI( self) # FIXME sliders want to be visible when added, else we get a crash self.setSourcesPanelVisible(True) self.add_channel(key, widget , sink, self.source_panel_layout) def on_remove_source_output(self, index): # FIXME sliders want to be visible when added, else we get a crash self.setSourcesPanelVisible(True) self.remove_channel("sourceoutput" + str(index), self.source_panel_layout) ## callbacks source def on_source_info(self, sink): key = "source" + str(sink.index) if not self.update_channel(key ,sink, self.source_panel_layout): widget = SourceUI(self) # FIXME sliders want to be visible when added, else we get a crash self.setSourcesPanelVisible(True) self.add_channel(key, widget , sink, self.source_panel_layout) def on_remove_source(self, index): # FIXME sliders want to be visible when added, else we get a crash self.setSourcesPanelVisible(True) self.remove_channel("source" + str(index), self.source_panel_layout) ## callbacks sink def on_sink_info(self,sink): key = "sink" + str(sink.index) if not self.update_channel(key ,sink, self.sink_panel_layout): widget = self.sink_panel_layout.get_new_sink(self,sink) self.add_channel(key, widget, sink , self.sink_panel_layout) widget.muteInfo.connect(self.updateIcon) self.sinkOutputChanged.emit() #sink.printDebug() # FIXME def on_module_info(self, index, name, argument, n_used, auto_unload): key = "sink" + str(index) for widget in self.sink_panel_layout.getChannels().values(): if widget.pa_sink: module = widget.pa_sink.get_owner_module() if module: if module == str(index): widget.update_module_info(index, name, argument, n_used, auto_unload) def on_remove_sink(self, index): self.remove_channel("sink" + str(index), self.sink_panel_layout) self.sinkOutputChanged.emit() ## callbacks sink input def on_sink_input_info(self, sink): if sink.props["driver"]=="module-combine-sink.c": return key = "sinkinput" + str(sink.index) if not self.update_channel(key ,sink, self.sink_panel_layout): widget = self.sink_panel_layout.get_new_sink_input(self) self.add_channel(key, widget, sink , self.sink_panel_layout) def on_remove_sink_input(self, index): self.remove_channel("sinkinput" + str(index), self.sink_panel_layout) ## callbacks card info def on_card_info(self, info): self.card_infos[info.name] = info #info.printDebug() def on_remove_card(self, index): for key in self.card_infos.keys(): card = self.card_infos[key] if int(card.index) == int(index): del self.card_infos[key] ## Callbacks volume menters def on_volume_meter_sink(self, index, level): for sink in self.sink_panel_layout.getChannels().values(): sink.on_update_meter(index,int(level), len(self.sink_panel_layout.getChannels())) def on_volume_meter_sink_input(self, index, level): for sink in self.sink_panel_layout.getChannels().values(): sink.on_update_meter(index,int(level), len(self.sink_panel_layout.getChannels())) def on_volume_meter_source(self, index, level): sources = self.source_panel_layout.getChannels().values() for source in sources: source.on_update_meter(index,int(level), len(sources)) def resizeEvent(self, e): self.emit(SIGNAL("resized()")) ### panel-icon callbacks def on_toggle_mute(self): sink = self.getDefaultSink() if sink != None: sink.on_mute_cb() self.applet.showTooltip() def on_step_volume_up(self): self.on_step_volume(True) def on_step_volume_down(self): self.on_step_volume(False) def on_step_volume(self, up): sink = self.getDefaultSink() if sink != None: sink.on_step_volume(up) self.applet.showTooltip() ### mediaplayer callbacks def on_mediaplayer_added(self, name, controller): if self.applet.in_mediaplayer_blacklist(name) : return widget = MediaPlayerUI( name, self, controller) self.add_channel(name, widget, None, self.sink_panel_layout) def on_mediaplayer_removed(self, name): self.remove_channel(name,self.sink_panel_layout) ### panel icons def updateIcon(self, muted): self.applet.updateIcon() ### helpers accessing channels def add_channel(self, key, widget, sink, target_layout): if sink: widget.update_with_info(sink) target_layout.addChannel(key, widget) self.check_geometries() return widget def update_channel(self, key, sink, target_layout): if target_layout.getChannel(key): target_layout.getChannel(key).update_with_info(sink) self.check_ItemOrdering() return True else: return False def remove_channel(self, key, target_layout): target_layout.removeChannel(key) self.check_geometries() def get_source_widgets(self): return self.source_panel_layout.get_source_widgets() def get_sinkoutput_widgets(self): return self.source_panel_layout.get_sinkoutput_widgets() def get_sink_widgets(self): return self.sink_panel_layout.get_sink_widgets() def get_sinkinput_widgets(self): return self.sink_panel_layout.get_sinkinput_widgets() def get_mediaplayer_widgets(self): return self.sink_panel_layout.get_mediaplayer_widgets() def getDefaultSink(self): for sink in self.sink_panel_layout.getChannels().values(): if sink.isDefaultSink(): return sink if len(self.sink_panel_layout.get_sink_widgets()) > 0: return self.sink_panel_layout.get_sink_widgets()[0] if len(self.sink_panel_layout.getChannels().values()) > 0: return self.sink_panel_layout.getChannels().values()[0] def get_visible_channels(self): # FIXME sources self.source_panel return self.sink_panel_layout.sorted_channels() ## helpers def get_card_info_for(self, sink): card_identifier = dbus.String(u'alsa.long_card_name') #u'sysfs.path' info = self._get_card_info_for(sink, card_identifier) if info: return info card_identifier = dbus.String(u'device.string') info = self._get_card_info_for(sink, card_identifier) if info: return info card_identifier = dbus.String(u'sysfs.path') return self._get_card_info_for(sink, card_identifier) def _get_card_info_for(self, sink, card_identifier): if sink.pa_sink == None: #print "get_card_info_for: no pa_sink" return None if card_identifier not in sink.pa_sink.props.keys(): #print "get_card_info_for: key: ", card_identifier," not found in:", sink.pa_sink.props.keys() return None for info in self.card_infos.values(): if card_identifier in info.properties.keys(): if info.properties[dbus.String(card_identifier)] == sink.pa_sink.props[card_identifier]: #print "get_card_info_for found" return info return None def is_ladspa_enabled(self): return self.applet.is_ladspa_enabled() def is_albumart_enabled(self): return self.applet.is_albumart_enabled() def is_meter_visible(self): return self.applet.is_meter_visible() def is_expander_enabled(self): return self.applet.is_expander_enabled() def get_max_volume_value(self): return self.applet.get_max_volume_value() def get_auto_mute(self): return self.applet.get_auto_mute() def is_slider_unit_value_visible(self): return self.applet.is_slider_unit_value_visible() def getPulseAudio(self): return self.pa def query_application(self, needle, default_icon=None): return self.applet.query_application(needle) def showMessage(self, icon, message): self.applet.showMessage(icon, message, Plasma.ButtonOk) def doExit(self): for i in self.sink_panel_layout.getChannels().values(): # if a slider is not visible, plasmoidviewer crashes if the slider is not removed before exit... (dont ask me) i.removeSlider() for i in self.source_panel_layout.getChannels().values(): # if a slider is not visible, plasmoidviewer crashes if the slider is not removed before exit... (dont ask me) i.removeSlider() def showModalWidget(self, widget): self.applet.showModalWidget(widget) def destroyMessageOverlay(self): self.applet.destroyMessageOverlay() veromix/plasma/contents/code/LabelSlider.py0000644000175100017500000002107411766302605017637 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import datetime from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.plasma import Plasma from PyKDE4 import plasmascript from PyKDE4.kdeui import * from PyKDE4.kdecore import * from PyKDE4.kdecore import * from PyKDE4.plasma import * class Label(Plasma.Label): volumeChanged = pyqtSignal(int) def __init__(self, parent=None, show_unit_value = False, unit_symbol="%"): self.text = "" self.bold_text = "" self.unit_value = -1 self.unit_symbol = unit_symbol self.show_unit_value = show_unit_value Plasma.Label.__init__(self, parent) def setText(self, text): self.text = text self._set_text() def setBoldText(self,text): self.bold_text = text self._set_text() def _get_formated_unit_string(self): if self.show_unit_value and self.unit_value != -1: return str(self.unit_value).zfill(2) + self.unit_symbol + " " return "" def _set_text(self): Plasma.Label.setText(self, "" + self._get_formated_unit_string() + self.bold_text + " " + self.text) def update_unit_string(self,unit_value): self.unit_value = unit_value self._set_text() def setMinimum(self, value): pass def setMaximum(self, value): pass def update_with_info(self, info): pass def set_unit_value_visible(self, boolean): self.show_unit_value = boolean self._set_text() class LabelSlider(Plasma.Slider): volumeChanged = pyqtSignal(int) def __init__(self, parent=None, show_unit_value=False, unit_symbol="%"): self.DELAY= 1 self.text = "" self.bold_text = "" d = datetime.timedelta(seconds=2) self.pulse_timestamp = datetime.datetime.now() + d self.plasma_timestamp = datetime.datetime.now() + d Plasma.Slider.__init__(self) self.label = Label(self, show_unit_value, unit_symbol) self.label.setPos(0, -4) self.connect(self, SIGNAL("geometryChanged()"), self._resize_widgets) self.valueChanged.connect( self.on_slider_cb) def setMaximum(self, value, showticks=True): Plasma.Slider.setMaximum(self,value) if value > 100 and showticks: self.nativeWidget().setTickInterval(100) self.nativeWidget().setTickPosition(QSlider.TicksBelow) else: self.nativeWidget().setTickPosition(QSlider.NoTicks) def set_unit_value_visible(self, boolean): self.label.set_unit_value_visible(boolean) def _resize_widgets(self): w = self.size().width() self.label.setMinimumWidth(w) self.label.setMaximumWidth(w) # set abs position of label, respect fonts-size h = self.size().height() s = Plasma.Theme.defaultTheme().fontMetrics().height() + 2 v = int ((h/2) - s) self.label.setPos(0,v) def setText(self, text): self.label.setText(text) def setBoldText(self,text): self.label.setBoldText(text) def setValueFromPlasma(self, value): if self.check_pulse_timestamp(): self.update_plasma_timestamp() self.setValue(value) def setValue(self,value): Plasma.Slider.setValue(self,value) self.label.update_unit_string(value) def update_with_info(self, info): self.setValueFromPulse(info.get_volume()) def setValueFromPulse(self, value): if self.check_plasma_timestamp(): self.update_pulse_timestamp() self.setValue(value) def on_slider_cb(self, value): self.label.update_unit_string(value) if self.check_pulse_timestamp(): self.update_plasma_timestamp() self.volumeChanged.emit(value) def set_focus(self): self.scene().setFocusItem(self, Qt.TabFocusReason) # private def update_pulse_timestamp(self): self.pulse_timestamp = datetime.datetime.now() def update_plasma_timestamp(self): self.plasma_timestamp = datetime.datetime.now() ## testing def check_plasma_timestamp(self): now = datetime.datetime.now() return (now - self.plasma_timestamp).seconds > self.DELAY def check_pulse_timestamp(self): now = datetime.datetime.now() return (now - self.pulse_timestamp).seconds > self.DELAY class VerticalSlider(LabelSlider): volumeChanged = pyqtSignal(int) def __init__(self): LabelSlider.__init__(self) self.label.setRotation(-90) self._resize_widgets() def _resize_widgets(self): h = self.size().height() self.label.setPos(-6, h) w = self.size().height() self.label.setMinimumWidth(w) self.label.setMaximumWidth(w) class MeterSlider(QGraphicsWidget): volumeChanged = pyqtSignal(int) def __init__(self, show_unit_value = False, unit_symbol="%"): QGraphicsWidget.__init__(self) self.meter = None self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed,True)) self.slider = LabelSlider(show_unit_value, unit_symbol) self.slider.setParent(self) self.slider.volumeChanged.connect(self.on_volume_changed) self.layout = QGraphicsLinearLayout(Qt.Vertical) self.layout.setContentsMargins(2,2,2,0) self.setLayout(self.layout) self.layout.addItem(self.slider) self.connect(self, SIGNAL("geometryChanged()"), self._resize_widgets) def create_meter(self): self.meter = Plasma.Meter(self) self.meter.setMeterType(Plasma.Meter.BarMeterHorizontal) self.meter.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed, True)) self.meter.setZValue(0) if self.event_filter: self.meter.installEventFilter(self.event_filter) def on_volume_changed(self,val): self.volumeChanged.emit(val) def setOrientation(self, orient): self.slider.setOrientation(orient) def setMaximum(self, orient): self.slider.setMaximum(orient) def setMinimum(self, orient): self.slider.setMinimum(orient) def setText(self, text): self.slider.setText(text) def setBoldText(self,text): self.slider.setBoldText(text) def setValueFromPlasma(self, value): self.slider.setValueFromPlasma(value) def update_with_info(self, info): self.slider.update_with_info(info) def setValueFromPulse(self, value): self.slider.setValueFromPulse(value) def nativeWidget(self): return self.slider.nativeWidget() def set_unit_value_visible(self, boolean): self.slider.set_unit_value_visible(boolean) def _resize_widgets(self): if not self.meter: return meter_width = self.size().width() self.meter.setMinimumWidth(meter_width) self.meter.setMaximumWidth(meter_width) meter_height = Plasma.Theme.defaultTheme().fontMetrics().height() self.meter.setMinimumHeight(meter_height) self.meter.setMaximumHeight(meter_height) self.meter.setPos(0, int(self.size().height()/2)) self.slider.setZValue(800) self.slider.label.setZValue(100) def toggle_meter(self): self.set_meter_visible((self.meter == None)) def set_meter_value(self, value): if self.meter: self.meter.setValue(int(value)) def set_meter_visible(self, aboolean): if aboolean: self.create_meter() else: if self.meter: self.meter.setParent(None) del self.meter self.meter = None self._resize_widgets() def installEventFilter(self, filter): self.event_filter = filter self.slider.installEventFilter(filter) self.slider.label.installEventFilter(filter) if self.meter: self.meter.installEventFilter(filter) QGraphicsWidget.installEventFilter(self, filter) def set_focus(self): self.slider.set_focus() veromix/plasma/contents/code/SourceUI.py0000644000175100017500000000430611766302605017152 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from PyKDE4.plasma import Plasma import signal, os, datetime from LabelSlider import * from Channel import * from MuteButton import * from ClickableMeter import * class SourceUI( Channel ): def __init__(self , parent): Channel.__init__(self, parent) def createMute(self): self.mute = InputMuteButton(self) self.mute.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum,True) ) self.connect(self.mute, SIGNAL("clicked()"), self.on_mute_cb ) self.mute.setBigIconName("audio-input-microphone.png") def context_menu_create_custom(self): self.context_menu_create_ports() self.context_menu_create_sounddevices() def update_label(self): text = "" bold = self.pa_sink.get_nice_title() if self.slider: self.slider.setText(text ) self.slider.setBoldText(bold) self.set_name(bold) def on_update_meter(self, index, value, number_of_sinks): if self.index == index: self.slider.set_meter_value(int(value)) def updateIcon(self): if self.isMuted(): self.mute.setMuted(True) else: self.mute.setMuted(False) ## Drag and Drop Support def dropEvent(self, dropEvent): uris = dropEvent.mimeData().urls() for uri in uris: if uri.scheme() == "veromix": self.pa.move_source_output(uri.port(), self.index) veromix/plasma/contents/code/ClickableMeter.py0000644000175100017500000000175711766302605020331 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyKDE4.plasma import Plasma from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * class ClickableMeter(Plasma.Meter): def __init__(self): Plasma.Meter.__init__(self) def mousePressEvent (self, event): self.emit(SIGNAL("clicked()")) veromix/plasma/contents/code/LockableScrollWidget.py0000644000175100017500000000260011766302605021506 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.plasma import Plasma from PyKDE4 import plasmascript from PyKDE4.kdeui import * from PyKDE4.kdecore import * from PyKDE4.kdecore import * from PyKDE4.plasma import * import sys class LockableScrollWidget(Plasma.ScrollWidget): def __init__(self,parent): self.locked = True Plasma.ScrollWidget.__init__(self,parent) def sceneEventFilter(self, item, event): if self.locked: return False else: return Plasma.ScrollWidget.sceneEventFilter(self, item, event) def beLocked(self): self.locked = True def beUnLocked(self): self.locked = False veromix/plasma/contents/code/main.py0000644000175100017500000007656311766302605016416 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ### # Veromix - A Pulseaudio volume control # # Veromix has two components: # - a service that sends notifications over dbus and offers an interface # to perform actions (set volume, mute ...) # - the plasmoid that connects to the service # # The service is launchd by dbus. For this to work veromix installs a service # description-file in /usr/share/dbus-1/services/ called org.veromix.pulseaudio.service . # # Pulseaudio will (one day) provide their own dbus-interface: # http://pulseaudio.org/wiki/DBusInterface # # The python-interface to pulseaudio is a mix of these two projects (extended by myself): # https://launchpad.net/earcandy # https://fedorahosted.org/pulsecaster/ ###### 2009 - 2012 import commands,dbus from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4 import uic from PyKDE4 import plasmascript from PyKDE4.plasma import Plasma from PyKDE4.kdeui import KIcon from PyKDE4.kdeui import KActionCollection from PyKDE4.kdeui import KAction from PyKDE4.kdeui import KShortcut from PyKDE4.kdeui import KKeySequenceWidget from PyKDE4.kdeui import KPageDialog from PyKDE4.kdeui import KDialog from PyKDE4.kdecore import * from VeroMix import VeroMix from NowPlaying import NowPlayingController from veromixcommon.LADSPAEffects import LADSPAEffects from veromixcommon.LADSPAEffects import LADSPAPresetLoader from veromixcommon.Utils import * COMMENT=i18n("Veromix is a mixer for the Pulseaudio sound server. ") class VeroMixPlasmoid(plasmascript.Applet): VERSION="0.18.3" nowplaying_player_added = pyqtSignal(QString, QObject) nowplaying_player_removed = pyqtSignal(QString) nowplaying_player_dataUpdated = pyqtSignal(QString, dict) def __init__(self,parent,args=None): self.engine = None self.now_playing_engine = None self.louder_action_editor = None self.lower_action_editor = None self.mute_action_editor = None self.card_settings = None self.messageDialog = None self.messageOverlay = None self.config_ui = None plasmascript.Applet.__init__(self,parent) def init(self): plasmascript.Applet.init(self) KGlobal.locale().insertCatalog("veromix"); if "usr/share/kde4" not in os.path.realpath(__file__): out = commands.getstatusoutput("xdg-icon-resource install --size 128 " + unicode(self.package().path()) + "contents/icons/veromix-plasmoid-128.png veromix-plasmoid") if out[0] == 0: print "veromix icon installed" else: print "Error installing veromix icon:", out LADSPAPresetLoader().install_ladspa_presets_if_needed() if self.is_ladspa_enabled(): # force singleton initialisation LADSPAPresetLoader().presets() LADSPAEffects().effects() createDbusServiceDescription(self.package().path() + "/dbus-service/veromix-service-qt.py", True) KGlobal.locale().insertCatalog("veromix") self.setHasConfigurationInterface(True) self.setAspectRatioMode(Plasma.IgnoreAspectRatio) self.theme = Plasma.Svg(self) self.widget = VeroMix(self) self.widget.init() defaultSize = QVariant(QSize (0,0)) size = self.config().readEntry("size", defaultSize).toSize() if self.formFactor() == Plasma.Planar: self.widget.setMinimumSize(275,125) elif (size != defaultSize) : self.widget.setPreferredSize(size.width(), size.height()) else: self.widget.setPreferredSize(470 ,145) self.connect(self.widget, SIGNAL("resized()"), self.dialogResized) #try: self.setGraphicsWidget(self.widget) self.applet.setPassivePopup(True) ## FIXME: see fixPopupcion self.setPopupIcon(KIcon("audio-volume-high")) #self.setPopupIcon("audio-volume-muted") # dont know why but adding it a second time helps (otherwise it # wont popup when you add it directly to the panel) self.setGraphicsWidget(self.widget) self.connect(self.applet, SIGNAL("appletDestroyed(Plasma::Applet*)"), self.doExit) self.setBackgroundHints(Plasma.Applet.StandardBackground) self.applyConfig() #except AttributeError , e: #print e #updateMetadataDesktop(self) self.initTooltip() self.initShortcuts() QTimer.singleShot(1000, self.fixPopupIcon) def initShortcuts(self): self.actionCollection = KActionCollection(self) #self.actionCollection.setConfigGlobal(True) self.louder_action = self.actionCollection.addAction("VeromixVolumeUp") self.louder_action.setText( i18n("Veromix volume up")) self.louder_action.setGlobalShortcut(KShortcut()) self.louder_action.triggered.connect(self.widget.on_step_volume_up) self.lower_action = self.actionCollection.addAction("VeromixVolumeDown") self.lower_action.setText(i18n("Veromix volume down")) self.lower_action.setGlobalShortcut(KShortcut()) self.lower_action.triggered.connect(self.widget.on_step_volume_down) self.mute_action = self.actionCollection.addAction("VeromixVolumeMute") self.mute_action.setText(i18n("Veromix toggle mute")) self.mute_action.setGlobalShortcut(KShortcut()) self.mute_action.triggered.connect(self.widget.on_toggle_mute) def initTooltip(self): if (self.formFactor() != Plasma.Planar): self.tooltip = Plasma.ToolTipContent() self.tooltip.setImage(pixmapFromSVG("audio-volume-high")) self.tooltip.setMainText(i18n( "Main Volume")) #self.tooltip.setSubText("") Plasma.ToolTipManager.self().setContent(self.applet, self.tooltip) Plasma.ToolTipManager.self().registerWidget(self.applet) def updateIcon(self): icon_state = "audio-volume-muted" sink = self.widget.getDefaultSink() if sink == None: QTimer.singleShot(2000, self.fixPopupIcon) return vol = sink.get_volume() if sink.isMuted() : icon_state= "audio-volume-muted" else: if vol == 0: icon_state = "audio-volume-muted" elif vol < 30: icon_state= "audio-volume-low" elif vol < 70: icon_state= "audio-volume-medium" else: icon_state= "audio-volume-high" self.setPopupIcon(icon_state) if (self.formFactor() != Plasma.Planar): self.tooltip.setImage(pixmapFromSVG(icon_state)) ## FIXME this should better go to toolTipAboutToShow but is not working: # https://bugs.kde.org/show_bug.cgi?id=254764 self.tooltip.setMainText(sink.name()) self.tooltip.setSubText( str(vol) + "%") Plasma.ToolTipManager.self().setContent(self.applet, self.tooltip) def showTooltip(self): if self.get_show_toolip(): Plasma.ToolTipManager.self().show(self.applet) @pyqtSlot(name="toolTipAboutToShow") def toolTipAboutToShow(self): pass ## FIXME Looks like a bug in plasma: Only when sending a # KIcon instance PopUpApplet acts like a Poppupapplet... def fixPopupIcon(self): #sink = self.widget.getDefaultSink() #if sink: self.updateIcon() def doExit(self): # prevent crash in plasmoidviewer self.widget.doExit() self.widget.deleteLater() def dialogResized(self): if self.isPopupShowing(): self.config().writeEntry("size", QVariant(self.widget.size())) def query_application(self, query): #print "query: ", query if not query : return None needle = query.lower() if self.engine == None: self.engine = self.dataEngine("apps") for source in self.engine.sources(): key = unicode(source).replace(".desktop", "") if (0<= key.find(needle)) or (0 <= needle.find(key)) : #print "found: ",key, needle , source result = self.engine.query(source) if QString("iconName") in result: iconname = result[QString("iconName")].toString() return iconname return None def wheelEvent(self, event): if event.orientation() == Qt.Horizontal: self.widget.on_step_volume((event.delta() < 0)) else: self.widget.on_step_volume((event.delta() > 0)) def mousePressEvent(self, event): if event.button() == Qt.MidButton: self.widget.on_toggle_mute() def createConfigurationInterface(self, parent): self.pp = parent self.config_widget = QWidget(parent) self.connect(self.config_widget, SIGNAL('destroyed(QObject*)'), self.configWidgetDestroyed) self.config_ui = uic.loadUi(str(self.package().filePath('ui', 'appearance.ui')), self.config_widget) self.config_ui.showBackground.setCurrentIndex( self.config().readEntry("background","2").toInt() [0]) self.config_ui.showBackground.currentIndexChanged.connect(parent.settingsModified) if self.formFactor() != Plasma.Planar: self.config_ui.showBackground.setEnabled(False) self.config_ui.popupMode.setCurrentIndex( self.config().readEntry("popupMode",False).toInt() [0]) self.config_ui.popupMode.currentIndexChanged.connect(parent.settingsModified) if self.formFactor() == Plasma.Planar: self.config_ui.popupMode.setEnabled(False) self.config_ui.useTabs.setChecked(self.useTabs()) self.config_ui.useTabs.stateChanged.connect(parent.settingsModified) self.config_ui.show_tooltip.setChecked(self.get_show_toolip()) self.config_ui.show_tooltip.stateChanged.connect(parent.settingsModified) self.config_ui.always_show_sources.setChecked(self.get_always_show_sources()) self.config_ui.always_show_sources.stateChanged.connect(parent.settingsModified) self.config_ui.meter_visible.setChecked(self.is_meter_visible()) self.config_ui.meter_visible.stateChanged.connect(parent.settingsModified) self.config_ui.expander_enabled.setChecked(self.is_expander_enabled()) self.config_ui.expander_enabled.stateChanged.connect(parent.settingsModified) self.config_ui.unitvalues_visible.setChecked(self.is_slider_unit_value_visible()) self.config_ui.unitvalues_visible.stateChanged.connect(parent.settingsModified) self.config_ui.version.setText(VeroMixPlasmoid.VERSION) parent.addPage(self.config_widget, i18n("Appearance"), "veromix") self.mediaplayer_settings_widget = QWidget(parent) self.mediaplayer_settings_ui = uic.loadUi(str(self.package().filePath('ui', 'nowplaying.ui')), self.mediaplayer_settings_widget) self.mediaplayer_settings_ui.mediaplayerBlacklist.setPlainText(self.get_mediaplayer_blacklist_string()) self.mediaplayer_settings_ui.runningMediaplayers.setPlainText(self.get_running_mediaplayers()) self.mediaplayer_settings_ui.runningMediaplayers.setReadOnly(True) self.mediaplayer_settings_ui.use_nowplaying.setChecked(self.is_nowplaying_enabled()) self.mediaplayer_settings_ui.use_nowplaying.stateChanged.connect(self.update_mediaplayer_settings_ui) self.mediaplayer_settings_ui.use_nowplaying.stateChanged.connect(parent.settingsModified) self.mediaplayer_settings_ui.use_mpris2.setChecked(self.is_mpris2_enabled()) self.mediaplayer_settings_ui.use_mpris2.stateChanged.connect(self.update_mediaplayer_settings_ui) self.mediaplayer_settings_ui.use_mpris2.stateChanged.connect(parent.settingsModified) self.mediaplayer_settings_ui.show_albumart.setChecked(self.is_albumart_enabled()) self.mediaplayer_settings_ui.show_albumart.stateChanged.connect(parent.settingsModified) parent.addPage(self.mediaplayer_settings_widget, i18n("Media Player Controls"), "veromix") #self.about_widget = QWidget(parent) #self.about_ui = uic.loadUi(str(self.package().filePath('ui', 'about.ui')), self.about_widget) #self.about_ui.version.setText(VeroMixPlasmoid.VERSION) #parent.addPage(self.about_widget, "About", "help-about") self.add_audio_settings(parent) self.add_ladspa_settings(parent) self.add_global_shortcut_page(parent) # FIXME KDE 4.6 workaround self.connect(parent, SIGNAL("okClicked()"), self.configChanged) self.connect(parent, SIGNAL("applyClicked()"), self.configChanged) self.connect(parent, SIGNAL("cancelClicked()"), self.configDenied) return self.config_widget def add_audio_settings(self, dialog): self.audio_settings_page = QWidget() layout = QGridLayout() self.audio_settings_page.setLayout(layout) self.max_volume_spinbox = QSpinBox() self.max_volume_spinbox.setRange(1,255) self.max_volume_spinbox.setSingleStep(1) self.max_volume_spinbox.setValue(self.get_max_volume_value()) self.max_volume_spinbox.valueChanged.connect(dialog.settingsModified) layout.addWidget(QLabel(i18n("Max volume value")), 0,0) layout.addWidget(self.max_volume_spinbox, 0,1) self.automute_checkbox = QCheckBox() self.automute_checkbox.setChecked(self.get_auto_mute()) self.automute_checkbox.stateChanged.connect(dialog.settingsModified) layout.addWidget(QLabel(i18n("Mute if volume reaches zero")), 1,0) layout.addWidget(self.automute_checkbox, 1,1) layout.addItem(QSpacerItem(0,20, QSizePolicy.Minimum,QSizePolicy.Fixed), 2,0) layout.addWidget(QLabel(""+i18n("Sound Card Profiles")+""), 3,0) index=4 self.card_settings = {} for card in self.widget.card_infos.values(): combo = QComboBox() #self.automute_checkbox.setChecked(self.get_auto_mute()) #print card.properties layout.addWidget(QLabel(card.properties[dbus.String("device.description")]), index,0) layout.addWidget(combo, index,1) index = index + 1 self.card_settings[combo] = card profiles = card.get_profiles() active = card.get_active_profile_name() active_index = 0 for profile in profiles: combo.addItem(profile.description) if active == profile.name: active_index = profiles.index(profile) combo.setCurrentIndex(active_index) layout.addItem(QSpacerItem(0,0, QSizePolicy.Minimum,QSizePolicy.Expanding), index,0) dialog.addPage(self.audio_settings_page, i18n("Pulseaudio"), "preferences-desktop-sound") def add_ladspa_settings(self, dialog): self.ladspa_settings_page = QWidget() layout = QGridLayout() self.ladspa_settings_page.setLayout(layout) text = i18n("LADSPA is a standard for handling audio filters and effects. Every linux software archive offers a large number of effects - search for LADSPA to get more.\ Not every effect is supported by Pulseaudio and others simple don't make sense (or create only noise).

\ The following list shows all available effects on your system: Only checked effects will appear in the context-menu.") if not LADSPAEffects().ladspa_sdk_available(): text = text + i18n("

Warning: Cannot find the executables 'listplugins' and 'analyseplugin' which are required for dynamically detecting installed effects.
\ In OpenSUSE, Fedora and Arch Linux the package is named 'ladspa', in Debian/Ubuntu 'ladspa-sdk'.

") ladspa_intro = QLabel(text) ladspa_intro.setWordWrap(True) layout.addWidget(ladspa_intro, 0,0) self.ladspa_enabled_checkbox = QCheckBox() self.ladspa_enabled_checkbox.setText(i18n("Enable LADSPA effects.")) self.ladspa_enabled_checkbox.setChecked(self.is_ladspa_enabled()) self.ladspa_enabled_checkbox.stateChanged.connect(dialog.settingsModified) layout.addWidget(self.ladspa_enabled_checkbox, 1,0) self.effects_list_widget = QListWidget() layout.addWidget(self.effects_list_widget,2,0) self.effects_list_widget.itemClicked.connect(dialog.settingsModified) blacklisted = LADSPAEffects().blacklist() effects = LADSPAEffects().all_effects() for effect in effects: item = QListWidgetItem(effect["preset_name"]) item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) if effect["preset_name"] in blacklisted: item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Checked) self.effects_list_widget.addItem(item) layout.addItem(QSpacerItem(0,0, QSizePolicy.Minimum,QSizePolicy.Expanding), 3,0) dialog.addPage(self.ladspa_settings_page, i18n("Effects / Equalizer"), "preferences-desktop-sound") # anybody knows how to remove/extend the default shortcuts page? def add_global_shortcut_page(self,dialog): self.kb_settings_page = QWidget() layout = QGridLayout() self.kb_settings_page.setLayout(layout) self.louder_action_editor = KKeySequenceWidget() self.louder_action_editor.setKeySequence( self.louder_action.globalShortcut().primary()) layout.addWidget(QLabel(i18n("Veromix volume up")), 0,0) layout.addWidget(self.louder_action_editor, 0,1) self.lower_action_editor = KKeySequenceWidget() self.lower_action_editor.setKeySequence( self.lower_action.globalShortcut().primary()) layout.addWidget(QLabel(i18n("Veromix volume down")), 1, 0) layout.addWidget(self.lower_action_editor, 1, 1) self.mute_action_editor = KKeySequenceWidget() self.mute_action_editor.setKeySequence( self.mute_action.globalShortcut().primary()) layout.addWidget(QLabel(i18n("Veromix toggle mute")), 2, 0) layout.addWidget(self.mute_action_editor, 2, 1) layout.addItem(QSpacerItem(0,0, QSizePolicy.Minimum,QSizePolicy.Expanding), 3,0) dialog.addPage(self.kb_settings_page, i18n("Volume Keyboard Shortcuts"), "preferences-desktop-keyboard") def configDenied(self): self.apply_nowplaying(self.is_nowplaying_enabled()) self.apply_mpris2(self.is_mpris2_enabled()) def configChanged(self): if self.config_ui: self.config().writeEntry("background",str(self.config_ui.showBackground.currentIndex())) self.config().writeEntry("popupMode", str(self.config_ui.popupMode.currentIndex())) tabs = self.useTabs() self.config().writeEntry("useTabs", bool(self.config_ui.useTabs.isChecked())) self.config().writeEntry("show_tooltip", bool(self.config_ui.show_tooltip.isChecked())) self.config().writeEntry("always_show_sources", bool(self.config_ui.always_show_sources.isChecked())) self.config().writeEntry("meter_visible", bool(self.config_ui.meter_visible.isChecked())) self.config().writeEntry("expander_enabled", bool(self.config_ui.expander_enabled.isChecked())) self.config().writeEntry("unitvalues_visible", bool(self.config_ui.unitvalues_visible.isChecked())) self.config().writeEntry("use_nowplaying", str(self.mediaplayer_settings_ui.use_nowplaying.isChecked())) self.config().writeEntry("use_mpris2", str(self.mediaplayer_settings_ui.use_mpris2.isChecked())) self.config().writeEntry("show_albumart", str(self.mediaplayer_settings_ui.show_albumart.isChecked())) #self.config().writeEntry("mpris2List",str(self.mediaplayer_settings_ui.mpris2List.toPlainText()).strip()) self.config().writeEntry("nowplayingBlacklist",str(self.mediaplayer_settings_ui.mediaplayerBlacklist.toPlainText()).strip()) self.config().writeEntry("max_volume", str(self.max_volume_spinbox.value())) self.config().writeEntry("auto_mute", str(self.automute_checkbox.isChecked())) self.config().writeEntry("ladspa_enabled",str(self.ladspa_enabled_checkbox.isChecked())) self.ladspa_save_effects_blacklist() if tabs != self.useTabs(): self.widget.switchView() self.applyConfig() self.widget.on_update_configuration() def update_mediaplayer_settings_ui(self): enable = ( self.mediaplayer_settings_ui.use_nowplaying.isChecked() or self.mediaplayer_settings_ui.use_mpris2.isChecked()) self.mediaplayer_settings_ui.mediaplayerBlacklist.setEnabled(enable) self.mediaplayer_settings_ui.mediaplayerBlacklistLabel.setEnabled(enable) self.mediaplayer_settings_ui.runningMediaplayers.setEnabled(enable) self.mediaplayer_settings_ui.runningMediaplayersLabel.setEnabled(enable) self.mediaplayer_settings_ui.runningMediaplayers.setPlainText(self.get_running_mediaplayers()) self.mediaplayer_settings_ui.show_albumart.setEnabled(enable) def apply_nowplaying(self, enabled): self.disable_nowplaying() if enabled: self.init_nowplaying() def apply_mpris2(self, enabled): self.widget.pa.disable_mpris2() self.remove_mpris2_widgets() if enabled: self.widget.pa.enable_mpris2() self.init_running_mpris2() def applyConfig(self): self.apply_nowplaying(self.is_nowplaying_enabled()) self.apply_mpris2(self.is_mpris2_enabled()) if self.formFactor() == Plasma.Planar: bg = self.config().readEntry("background","2").toInt()[0] if bg == 0: self.setBackgroundHints(Plasma.Applet.NoBackground) elif bg == 1: self.setBackgroundHints(Plasma.Applet.TranslucentBackground) else: self.setBackgroundHints(Plasma.Applet.StandardBackground) mode = self.config().readEntry("popupMode",False).toInt()[0] if mode== 0: self.setPassivePopup(False) elif mode == 1: self.setPassivePopup(True) else: self.setPassivePopup(True) if self.louder_action_editor: sequence = self.louder_action_editor.keySequence() if sequence != self.louder_action.globalShortcut().primary(): self.louder_action.setGlobalShortcut(KShortcut(sequence), KAction.ActiveShortcut, KAction.NoAutoloading) if self.lower_action_editor: sequence = self.lower_action_editor.keySequence() if sequence != self.lower_action.globalShortcut().primary(): self.lower_action.setGlobalShortcut(KShortcut(sequence), KAction.ActiveShortcut, KAction.NoAutoloading) if self.mute_action_editor: sequence = self.mute_action_editor.keySequence() if sequence != self.mute_action.globalShortcut().primary(): self.mute_action.setGlobalShortcut(KShortcut(sequence), KAction.ActiveShortcut, KAction.NoAutoloading) if self.card_settings: for combo in self.card_settings.keys(): card = self.card_settings[combo] for profile in card.profiles: if combo.currentText() == profile.description: self.widget.pa.set_card_profile(card.index, profile.name) self.update() def configWidgetDestroyed(self): self.config_widget = None self.config_ui = None def useTabs(self): return self.config().readEntry("useTabs",False).toBool() def is_meter_visible(self): return self.config().readEntry("meter_visible",False).toBool() def get_auto_mute(self): return self.config().readEntry("auto_mute",False).toBool() def get_show_toolip(self): return self.config().readEntry("show_tooltip",True).toBool() def get_always_show_sources(self): return self.config().readEntry("always_show_sources",False).toBool() def get_max_volume_value(self): default = 100 return self.config().readEntry("max_volume",default).toInt()[0] def is_slider_unit_value_visible(self): return self.config().readEntry("unitvalues_visible",False).toBool() def is_ladspa_enabled(self): return self.config().readEntry("ladspa_enabled",True).toBool() def ladspa_save_effects_blacklist(self): blacklisted = [] for i in range(0,self.effects_list_widget.count()): item = self.effects_list_widget.item(i) if not item.checkState(): blacklisted.append(str(item.text())) LADSPAEffects().write_blacklist(blacklisted) ### now playing def is_nowplaying_enabled(self): return self.config().readEntry("use_nowplaying",False).toBool() def is_mpris2_enabled(self): return self.config().readEntry("use_mpris2",True).toBool() def is_albumart_enabled(self): return self.config().readEntry("show_albumart",True).toBool() def is_expander_enabled(self): return self.config().readEntry("expander_enabled",True).toBool() def disable_nowplaying(self): for player in self.widget.get_mediaplayer_widgets(): if player.is_nowplaying_player(): self.on_nowplaying_player_removed(player.controller_name()) self.now_playing_engine = None def remove_mpris2_widgets(self): for player in self.widget.get_mediaplayer_widgets(): if player.is_mpris2_player(): self.on_mpris2_removed(player.controller_name()) def init_nowplaying(self): self.now_playing_engine = self.dataEngine('nowplaying') self.connect(self.now_playing_engine, SIGNAL('sourceAdded(QString)'), self.on_nowplaying_player_added) self.connect(self.now_playing_engine, SIGNAL('sourceRemoved(QString)'), self.on_nowplaying_player_removed) self.connect_to_nowplaying_engine() def init_running_mpris2(self): for controller in self.widget.pa.get_mpris2_players(): v= controller.name() if self.in_mediaplayer_blacklist(v): return self.nowplaying_player_added.emit(controller.name(), controller) def connect_to_nowplaying_engine(self): # get sources and connect for source in self.now_playing_engine.sources(): self.on_nowplaying_player_added(source) def on_nowplaying_player_added(self, player): if player == "players": # FIXME 4.6 workaround return if self.in_mediaplayer_blacklist(player): return self.now_playing_engine.disconnectSource(player, self) self.now_playing_engine.connectSource(player, self, 2000) controller = self.now_playing_engine.serviceForSource(player) self.nowplaying_player_added.emit(player, NowPlayingController(self.widget,controller)) def in_mediaplayer_blacklist(self,player): for entry in self.get_mediaplayer_blacklist(): if str(player).find(entry) == 0: return True return False def on_nowplaying_player_removed(self, player): if self.now_playing_engine: self.now_playing_engine.disconnectSource(player, self) self.nowplaying_player_removed.emit(player) def on_mpris2_removed(self, player): self.nowplaying_player_removed.emit(player) def get_running_mediaplayers(self): val = "nowplaying:\n" engine = self.now_playing_engine if engine == None: engine = self.dataEngine('nowplaying') for source in engine.sources(): val += source + "\n" val += "\nmpris2:\n" for controller in self.widget.pa.get_mpris2_players(): val += controller.name() + "\n" return val def get_mediaplayer_blacklist(self): return self.get_mediaplayer_blacklist_string().split("\n") def get_mediaplayer_blacklist_string(self): default = "org.mpris.bangarang" return self.config().readEntry("nowplayingBlacklist",default).toString() @pyqtSignature('dataUpdated(const QString&, const Plasma::DataEngine::Data&)') def dataUpdated(self, sourceName, data): self.nowplaying_player_dataUpdated.emit(sourceName, data) ## Modal Widget def showModalWidget(self,mainWidget): #mainWidget.widgetClose.connect(self.destroyMessageOverlay) if self.messageOverlay: return if self.messageDialog: return corona = self.scene() mainWidget.adjustSize() hint = mainWidget.preferredSize() if (hint.height() > self.widget.size().height()) or (hint.width() > self.widget.size().width()): ## either a collapsed popup in h/v form factor or just too small, ## so show it in a dialog associated with ourselves #pass if (corona): corona.addOffscreenWidget(mainWidget) if (self.messageDialog): pass else: self.messageDialog = Plasma.Dialog() self.messageDialog.setGraphicsWidget(mainWidget) mainWidget.setParentItem(self.messageDialog.graphicsWidget ()) else: self.messageOverlay = self.createMessageOverlay() self.formatOverlay() self.messageOverlay.opacity = 0.8 mainWidget.setParentItem(self.messageOverlay) l = QGraphicsLinearLayout(self.messageOverlay) l.addItem(mainWidget) if self.messageDialog: pos = self.geometry().topLeft().toPoint() if (corona): pos = corona.popupPosition(self.applet, self.messageDialog.size()) self.messageDialog.move(pos) #self.locationToDirection(self.location()) self.messageDialog.animatedShow(Plasma.Direction(0)) self.hidePopup() else: self.messageOverlay.show() def createMessageOverlay(self): if self.messageOverlay == None: messageOverlay = QGraphicsWidget(self.widget) return messageOverlay def formatOverlay(self): self.messageOverlay.resize(self.widget.contentsRect().size()) self.messageOverlay.setPos(self.widget.contentsRect().topLeft()) zValue = 100 for child in self.widget.children(): if (child.zValue() > zValue): zValue = child.zValue() + 1 self.messageOverlay.setZValue(zValue) def destroyMessageOverlay(self): if self.messageDialog != None: #Plasma::locationToInverseDirection(q->location()) self.messageDialog.animatedHide(Plasma.Direction(0)) self.messageDialog.deleteLater() self.messageDialog.hide() self.messageDialog = None self.showPopup(0) if self.messageOverlay == None: return self.messageOverlay.hide() self.messageOverlay = None def CreateApplet(parent): # Veromix is dedicated to my girlfriend Vero. return VeroMixPlasmoid(parent) veromix/plasma/contents/code/Mpris2MediaPlayerQt.py0000644000175100017500000000256411766302605021256 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2011-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from veromixcommon.MediaPlayer import * class Mpris2MediaPlayerQt(QObject, Mpris2MediaPlayer): data_updated = pyqtSignal() def __init__(self, name, dbus_proxy): QObject.__init__(self) Mpris2MediaPlayer.__init__(self, name, dbus_proxy) def signal_data_updated(self): self.data_updated.emit() def url_path_of(self, string): return QUrl(string).path() def trigger_timer_callback(self, timeout, function): QTimer.singleShot(timeout, function) def create_pixmap(self, val): return QPixmap(val) veromix/plasma/contents/code/SourceOutputUI.py0000644000175100017500000000730411766302605020374 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from PyKDE4.plasma import Plasma import signal, os, datetime from LabelSlider import * from Channel import * from MuteButton import * from ClickableMeter import * class SourceOutputUI( Channel ): def __init__(self , parent): self.mouse_pressed = False Channel.__init__(self, parent) self.layout.setContentsMargins(6,2,6,2) def createMute(self): self.mute = InputMuteButton(self) self.mute.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum,True) ) self.connect(self.mute, SIGNAL("clicked()"), self.on_mute_cb ) self.mute.setBigIconName("audio-input-microphone.png") def createSlider(self): self.slider = Label() def context_menu_create_unlock_channels(self): pass def context_menu_create_mute(self): pass def context_menu_create_meter(self): pass def context_menu_create_custom(self): move_to = QMenu(i18n("Move To"), self.popup_menu) for widget in self.veromix.get_sinkoutput_widgets(): action = QAction(widget.name(), self.popup_menu) move_to.addAction(action) self.popup_menu.addMenu(move_to) def on_contextmenu_clicked(self, action): for widget in self.veromix.get_sinkoutput_widgets(): if widget.name() == action.text(): self.veromix.pa.move_source_output(self.index, widget.index) def update_label(self): text = self.pa_sink.get_nice_text() bold = self.pa_sink.get_nice_title() self.set_name(bold) if self.slider: self.slider.setText(text) self.slider.setBoldText(bold) iconname = self.pa_sink.get_nice_icon() if iconname == None and "app" in self.pa_sink.props.keys(): iconname = self.veromix.query_application(self.pa_sink.props["app"]) if iconname : self.mute.setBigIconName(iconname) self.updateIcon() def get_assotiated_source(self): try: return self.pa_sink.props["source"] except: return 0 def on_slider_cb(self, value): pass def on_update_meter(self, index, value, number_of_sinks): # FIXME pass #if self.getOutputIndex() == index: #self.slider.set_meter_value(int(value) ### Drag and Drop def mousePressEvent(self, event): self.mouse_pressed = True def mouseReleaseEvent(self, event): self.mouse_pressed = False def mouseMoveEvent(self,e): if self.mouse_pressed : self.startDrag(e) def startDrag(self,event): drag = QDrag(event.widget()) mimedata = QMimeData() liste = [] liste.append(QUrl( "veromix://source_output_index:"+str(int(self.index)) )) mimedata.setUrls(liste) drag.setMimeData(mimedata) #drag.setHotSpot(event.pos() - self.rect().topLeft()) dropAction = drag.start(Qt.MoveAction) veromix/plasma/contents/code/PulseAudioProxy.py0000644000175100017500000002755111766302605020577 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import signal import dbus.mainloop.qt from PyQt4.QtCore import * from veromixcommon.PulseProxyObjects import * from Mpris2MediaPlayerQt import Mpris2MediaPlayerQt class PulseAudio(QObject): def __init__(self, parent): QObject.__init__(self) self.REQUIRED_SERVICE_VERSION = 15 if not dbus.get_default_main_loop(): mainloop=dbus.mainloop.qt.DBusQtMainLoop(set_as_default=True) else: mainloop=dbus.mainloop.qt.DBusQtMainLoop(set_as_default=False) self.bus = dbus.SessionBus() self.veromix = parent def connect_veromix_service(self): if self.getMixer().veromix_service_version() != self.REQUIRED_SERVICE_VERSION: try: self.getMixer().veromix_service_quit() if self.getMixer().veromix_service_version() != self.REQUIRED_SERVICE_VERSION: raise NameError("Wrong server versions") except: raise NameError("Wrong server versions") self.bus.add_signal_receiver(self.on_sink_input_info, dbus_interface="org.veromix.notification", signal_name="sink_input_info") self.bus.add_signal_receiver(self.on_sink_info, dbus_interface="org.veromix.notification", signal_name="sink_info") self.bus.add_signal_receiver(self.on_source_output_info, dbus_interface="org.veromix.notification", signal_name="source_output_info") self.bus.add_signal_receiver(self.on_source_info, dbus_interface="org.veromix.notification", signal_name="source_info") self.bus.add_signal_receiver(self.on_sink_input_remove, dbus_interface="org.veromix.notification", signal_name="sink_input_remove") self.bus.add_signal_receiver(self.on_sink_remove, dbus_interface="org.veromix.notification", signal_name="sink_remove") self.bus.add_signal_receiver(self.on_source_remove, dbus_interface="org.veromix.notification", signal_name="source_remove") self.bus.add_signal_receiver(self.on_source_output_remove, dbus_interface="org.veromix.notification", signal_name="source_output_remove") self.bus.add_signal_receiver(self.on_volume_meter_sink_input, dbus_interface="org.veromix.notification", signal_name="volume_meter_sink_input") self.bus.add_signal_receiver(self.on_volume_meter_source, dbus_interface="org.veromix.notification", signal_name="volume_meter_source") self.bus.add_signal_receiver(self.on_volume_meter_sink, dbus_interface="org.veromix.notification", signal_name="volume_meter_sink") self.bus.add_signal_receiver(self.on_card_info, dbus_interface="org.veromix.notification", signal_name="card_info") self.bus.add_signal_receiver(self.on_card_remove, dbus_interface="org.veromix.notification", signal_name="card_remove") self.bus.add_signal_receiver(self.on_module_info, dbus_interface="org.veromix.notification", signal_name="module_info") def enable_mpris2(self): self.bus.add_signal_receiver(self.on_name_owner_changed, signal_name="NameOwnerChanged") def disable_mpris2(self): self.bus.remove_signal_receiver(self.on_name_owner_changed, signal_name="NameOwnerChanged") def on_name_owner_changed(self, val, val1=None, val2=None): if "org.mpris.MediaPlayer2" in val: if val in self.bus.list_names(): self.emit(SIGNAL("mpris2_player_added(QString, PyQt_PyObject)"), str(val), Mpris2MediaPlayerQt(QString(val), self)) else: self.emit(SIGNAL("mpris2_player_removed(QString, PyQt_PyObject)"), str(val), Mpris2MediaPlayerQt(QString(val), self)) def connect_mpris2_player(self, callback, name): self.bus.add_signal_receiver(callback, dbus_interface="org.freedesktop.DBus.Properties", signal_name="PropertiesChanged", bus_name=name) def disconnect_mpris2_player(self, callback, name): self.bus.remove_signal_receiver(callback, dbus_interface="org.freedesktop.DBus.Properties", signal_name="PropertiesChanged", bus_name=name) def get_mpris2_players(self): collection = [] for val in self.bus.list_names() : if "org.mpris.MediaPlayer2" in val: collection.append(Mpris2MediaPlayerQt(QString(val), self)) return collection def getMixer(self): pa_obj = self.bus.get_object("org.veromix.pulseaudio.qt","/org/veromix/pulseaudio") return dbus.Interface(pa_obj, 'org.veromix.pulseaudio') def get_mpris2_object(self, destination): return self.bus.get_object(destination, '/org/mpris/MediaPlayer2') def getNowPlaying(self, destination): pa_obj = self.get_mpris2_object(destination) return dbus.Interface(pa_obj, 'org.mpris.MediaPlayer2.Player') def getNowPlayingProperty(self, destination, name): pa_obj = self.get_mpris2_object(destination) props = dbus.Interface(pa_obj, 'org.freedesktop.DBus.Properties') return props.Get('org.mpris.MediaPlayer2.Player', name) def on_sink_input_info(self, index, name, muted, volume, props): sink =SinkInputInfo(self, index, name, muted, volume, props) self.emit(SIGNAL("on_sink_input_info(PyQt_PyObject)"), sink) def on_sink_info(self, index, name, muted, volume, props, ports, active_port): sink = SinkInfo(self, index, name, muted, volume, props, ports, active_port) self.emit(SIGNAL("on_sink_info(PyQt_PyObject)"), sink) def on_source_output_info(self, index, name, props): sink = SourceOutputInfo(self, index, name, True, {"left":0, "right":0}, props) self.emit(SIGNAL("on_source_output_info(PyQt_PyObject)"), sink) def on_source_info(self, index, name, muted, volume, props, ports, active_port): sink = SourceInfo(self, index, name, muted, volume, props, ports, active_port) self.emit(SIGNAL("on_source_info(PyQt_PyObject)"), sink) def on_sink_input_remove(self, index): self.emit(SIGNAL("on_sink_input_remove(int)"), index) def on_sink_remove(self, index): self.emit(SIGNAL("on_sink_remove(int)"), index) def on_source_remove(self, index): self.emit(SIGNAL("on_source_remove(int)"), index) def on_source_output_remove(self, index): self.emit(SIGNAL("on_source_output_remove(int)"), index) def on_volume_meter_sink_input(self, index, value): self.emit(SIGNAL("on_volume_meter_sink_input(int,float)"), index, value) def on_volume_meter_sink(self, index, value): self.emit(SIGNAL("on_volume_meter_sink(int,float)"), index, value) def on_volume_meter_source(self, index, value): self.emit(SIGNAL("on_volume_meter_source(int,float)"), index, value) def on_card_info(self, index, name, properties, active_profile_name, profiles_dict): info = CardInfo(index, name, properties, active_profile_name, profiles_dict) self.emit(SIGNAL("on_card_info(PyQt_PyObject)"), info) def on_card_remove(self, index): self.emit(SIGNAL("on_card_remove(int)"), index) # calls def set_card_profile(self, index, value): self.getMixer().set_card_profile(index, value) def set_sink_input_volume(self, index, vol): try: self.getMixer().sink_input_volume(index,vol) except Exception, e: print "dbus connection not ready: " def set_sink_input_mute(self, index, mute): self.getMixer().sink_input_mute(index,mute) def sink_input_kill(self, index): self.getMixer().sink_input_kill(index) def set_sink_volume(self, index, vol): self.getMixer().sink_volume(index,vol) def set_sink_mute(self, index, mute): self.getMixer().sink_mute(index,mute) def set_sink_port(self, index, portstr): self.getMixer().sink_port(index,portstr) def set_default_sink(self, index): self.getMixer().set_default_sink(index) def create_combined_sink(self, first_sink_index, second_sink_index): self.getMixer().create_combined_sink(int(first_sink_index), int(second_sink_index)) def set_source_volume(self, index, vol): self.getMixer().source_volume(index,vol) def set_source_mute(self, index, mute): self.getMixer().source_mute(index,mute) def set_source_port(self, index, portstr): self.getMixer().source_port(index,portstr) def set_default_source(self, index): self.getMixer().set_default_source(index) def move_sink_input(self, sink, output): self.getMixer().move_sink_input(sink, output) def move_source_output(self, sink, output): self.getMixer().move_source_output(sink, output) def toggle_monitor_of_sink(self, sink_index, named): self.getMixer().toggle_monitor_of_sink(sink_index, named) def toggle_monitor_of_sinkinput(self, sinkinput_index, sink_index, named): self.getMixer().toggle_monitor_of_sinkinput(sinkinput_index, sink_index, named) def toggle_monitor_of_source(self, source_index, named): self.getMixer().toggle_monitor_of_source(source_index, named) def set_ladspa_sink(self, sink_index, module_index, parameters): self.getMixer().set_ladspa_sink(sink_index, module_index, parameters) def remove_ladspa_sink(self, sink_index): self.getMixer().remove_ladspa_sink(sink_index) def remove_combined_sink(self, sink_index): self.getMixer().remove_combined_sink(sink_index) def on_module_info(self, index, name, argument, n_used, auto_unload): self.emit(SIGNAL("on_module_info(int,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),index, name, argument, n_used, auto_unload) # FIXME def nowplaying_next(self, destination): self.getNowPlaying(str(destination)).Next() def nowplaying_prev(self, destination): self.getNowPlaying(str(destination)).Previous() def nowplaying_pause(self, destination): self.getNowPlaying(str(destination)).Pause() def nowplaying_play(self, destination): self.getNowPlaying(str(destination)).Play() def mpris2_get_position(self, destination): return self.getNowPlayingProperty(str(destination), "Position") def mpris2_set_position(self, destination, position): self.getNowPlaying(str(destination)).Seek(long(position)) def mpris2_get_metadata(self, destination): return self.getNowPlayingProperty(str(destination), "Metadata") def mpris2_get_playback_status(self, destination): return self.getNowPlayingProperty(str(destination), "PlaybackStatus") def requestInfo(self): try: self.getMixer().requestInfo() except Exception, e: print "dbus connection not ready: ", e def set_autostart_meters(self, aboolean): self.getMixer().set_autostart_meters(aboolean) veromix/plasma/contents/code/Channel.py0000644000175100017500000004327111766302605017030 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import datetime, urllib from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from PyKDE4.plasma import Plasma from PyKDE4.kdecore import i18n from LabelSlider import MeterSlider from MuteButton import MuteButton from ClickableMeter import ClickableMeter from SinkChannelWidget import SinkChannelWidget from veromixcommon.LADSPAEffects import LADSPAEffects from veromixcommon.LADSPAEffects import LADSPAPresetLoader from veromixcommon.Utils import * class Channel(QGraphicsWidget): def __init__(self , parent): QGraphicsWidget.__init__(self) self.veromix = parent self.index = -1 self.pa = parent.getPulseAudio() self.set_name("") self.deleted = True self.pa_sink = None self.extended_panel_shown = False self.extended_panel= None self.show_meter = True self.expander = None self.popup_menu = None self.card_settings = None self.menus = None self.port_actions = None self.double_click_filter = ChannelEventFilter(self) self.installEventFilter(self.double_click_filter) self.init() self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed,True)) def init(self): self.layout = QGraphicsLinearLayout(Qt.Vertical) self.layout.setContentsMargins(2,2,2,0) self.setLayout(self.layout) self.initArrangement() self.composeArrangement() self.setAcceptDrops(True) self._on_upate_expander_enabled() def initArrangement(self): self.create_frame() self.create_panel() self.createMute() self.createMiddle() self.create_expander() def composeArrangement(self): self.layout.addItem(self.frame) self.frame_layout.addItem(self.panel) self.panel_layout.addItem(self.mute) self.panel_layout.addItem(self.middle) def create_frame(self): self.frame = Plasma.Frame() self.frame_layout = QGraphicsLinearLayout(Qt.Vertical) self.frame.setEnabledBorders (Plasma.FrameSvg.NoBorder) self.frame.setFrameShadow(Plasma.Frame.Plain) self.frame_layout.setContentsMargins(0,0,0,0) self.frame.setLayout(self.frame_layout) def create_panel(self): self.panel = QGraphicsWidget() self.panel_layout = QGraphicsLinearLayout(Qt.Horizontal) self.panel_layout.setContentsMargins(6,8,10,6) self.panel.setLayout(self.panel_layout) def createMute(self): self.mute = MuteButton(self) self.connect(self.mute, SIGNAL("clicked()"), self.on_mute_cb) def createMiddle(self): self.middle = QGraphicsWidget() self.middle_layout = QGraphicsLinearLayout(Qt.Vertical) #self.middle_layout.setContentsMargins(6,8,6,0) self.middle_layout.setContentsMargins(0,0,0,0) self.middle.setLayout(self.middle_layout) self.middle.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.createSlider() self.middle_layout.addItem(self.slider) def createSlider(self): self.slider = MeterSlider(None, self.veromix.is_slider_unit_value_visible()) self.slider.installEventFilter(self.double_click_filter) self.slider.set_meter_visible(self.veromix.is_meter_visible()) self.slider.setOrientation(Qt.Horizontal) self.slider.setMaximum(self.veromix.get_max_volume_value()) self.slider.setMinimum(0) self.slider.volumeChanged.connect( self.on_slider_cb) def create_expander(self): self.expander = Plasma.IconWidget(self.panel) self.expander.setZValue(10) self.connect(self, SIGNAL("geometryChanged()"), self._resize_widgets) self.expander.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)) self.expander.clicked.connect(self.on_expander_clicked) self.expander.setSvg("widgets/arrows", "left-arrow") def create_context_menu(self, event): self.popup_menu = QMenu() self.popup_menu.triggered.connect(self.on_contextmenu_clicked) self.context_menu_create_custom() self.context_menu_create_mute() self.context_menu_create_meter() self.context_menu_create_unlock_channels() self.context_menu_create_effects() self.create_menu_kill_sink() self.context_menu_create_settings() if event: self.popup_menu.exec_(event.screenPos()) else: self.popup_menu.exec_(QCursor.pos()) def context_menu_create_mute(self): action_mute = QAction(i18n("Muted"), self.popup_menu) self.popup_menu.addAction(action_mute) action_mute.setCheckable(True) action_mute.setChecked(self.isMuted()) action_mute.triggered.connect(self.on_mute_cb) def context_menu_create_meter(self): action_meter = QAction(i18n("Volume meter"), self.popup_menu) self.popup_menu.addAction(action_meter) action_meter.setCheckable(True) action_meter.setChecked(self.pa_sink.has_monitor()) action_meter.triggered.connect(self.on_meter_cb) def context_menu_create_unlock_channels(self): action_unlock = QAction(i18n("Unlock channels"), self.popup_menu) self.popup_menu.addAction(action_unlock) action_unlock.setCheckable(True) action_unlock.setChecked(self.extended_panel_shown) action_unlock.triggered.connect(self.toggle_channel_lock) def context_menu_create_ports(self): self.port_actions = {} if len(self.pa_sink.ports.keys()) > 1: ports_menu = QMenu(i18n("Ports"), self.popup_menu) ports = self.pa_sink.ports for port in ports.keys(): action = QAction(in_unicode(ports[port]), self.popup_menu) self.port_actions[action]=port if port == self.pa_sink.active_port: action.setCheckable(True) action.setChecked(True) else: action.setChecked(False) action.setCheckable(False) ports_menu.addAction(action) self.popup_menu.addMenu(ports_menu) def create_menu_kill_sink(self): pass def context_menu_create_sounddevices(self): self.card_settings = {} self.menus = [] for card in self.veromix.card_infos.values(): current = self.veromix.get_card_info_for(self) if current != None and current.get_description() == card.get_description(): card_menu = QMenu(i18n("Profile"), self.popup_menu) self.popup_menu.addMenu(card_menu) else: card_menu = QMenu(card.get_description(), self.popup_menu) self.menus.append(card_menu) active_profile_name = card.get_active_profile_name() self.profiles = card.get_profiles() for profile in self.profiles: action = QAction(in_unicode(profile.description), card_menu) self.card_settings[action] = card if profile.name == active_profile_name: action.setCheckable(True) action.setChecked(True) card_menu.addAction(action) def context_menu_create_sounddevices_other(self): if len(self.menus) > 0: self.popup_menu.addSeparator() for each in self.menus: self.popup_menu.addMenu(each) def context_menu_create_custom(self): pass def context_menu_create_effects(self): pass def context_menu_create_settings(self): self.popup_menu.addSeparator() action_settings = QAction(i18n("Veromix Settings"), self.popup_menu) self.popup_menu.addAction(action_settings) action_settings.triggered.connect(self.veromix.applet.showConfigurationInterface) def _resize_widgets(self): self.expander.setPos(int(self.panel.size().width() - self.expander.size().width()) ,0) def on_double_clicked(self): self.slider.toggle_meter() self.pa_sink.toggle_monitor() self.slider.set_meter_value(0) def on_step_volume(self, up): vol = self.pa_sink.get_volume() STEP = 5 if up: vol = vol + STEP else: vol = vol - STEP if vol < 0: vol = 0 if vol > self.veromix.get_max_volume_value(): vol = self.veromix.get_max_volume_value() self.setVolume(vol) def setVolume(self, value): vol = self.pa_sink.volumeDiffFor(value) if self.veromix.get_auto_mute(): for c in vol: if c <= 0: ## FIXME HACK for MurzNN this should be conditional self.pa.set_sink_mute(self.index, True) self.automatically_muted = True return if self.automatically_muted : self.automatically_muted = False self.pa.set_sink_mute(self.index, False) self.set_channel_volumes(vol) def get_volume(self): if self.pa_sink: return self.pa_sink.get_volume() return [0] def on_expander_clicked(self): self.contextMenuEvent(None) def toggle_channel_lock(self): self.middle_layout.removeItem(self.slider) self.slider = None if (self.extended_panel_shown): self.extended_panel_shown = False self.expander.setSvg("widgets/arrows", "left-arrow") self.createSlider() self.middle_layout.addItem(self.slider) else: self.extended_panel_shown = True self.expander.setSvg("widgets/arrows", "down-arrow") self.slider = SinkChannelWidget(self.veromix, self) self.slider.installEventFilter(self.double_click_filter) self.middle_layout.addItem(self.slider) self.middle_layout.setContentsMargins(0,0,0,0) self.middle.setContentsMargins(0,0,0,0) self.update_with_info(self.pa_sink) self.veromix.check_geometries() def on_update_configuration(self): self.slider.set_meter_visible(self.veromix.is_meter_visible()) self.slider.setMaximum(self.veromix.get_max_volume_value()) self.slider.set_unit_value_visible(self.veromix.is_slider_unit_value_visible()) self._on_upate_expander_enabled() def _on_upate_expander_enabled(self): if self.veromix.is_expander_enabled(): self.expander.show() else: self.expander.hide() def on_contextmenu_clicked(self, action): if action in self.card_settings.keys(): card = self.card_settings[action] for profile in card.get_profiles(): if action.text() == profile.description: self.veromix.pa.set_card_profile(card.index, profile.name) if action in self.port_actions.keys(): self.pa_sink.set_port(self.port_actions[action]) def contextMenuEvent(self,event): self.create_context_menu(event) def on_mute_cb(self): self.pa_sink.toggle_mute() def on_meter_cb(self): self.on_double_clicked() def sink_input_kill(self): self.pa_sink.kill() def set_channel_volumes(self, values): self.pa_sink.set_volume(values) def on_update_meter(self, index, value, number_of_sinks): if self.index == index: self.slider.set_meter_value(int(value)) def update_with_info(self,info): self.pa_sink = info self.index = info.index self.update_label() self.updateIcon() if self.slider: self.slider.update_with_info(info) if self.extended_panel: self.extended_panel.update_with_info(info) self.update() def update_label(self): if self.pa_sink: self.set_name(self.pa_sink.name) def getOutputIndex(self): return self.index def sinkIndexFor( self, index): return (index * 100000) + 100000 def updateIcon(self): pass def on_slider_cb(self, value): self.setVolume(value) def isDefaultSink(self): if self.pa_sink and "isdefault" in self.pa_sink.props: return self.pa_sink.props["isdefault"] == "True" return False def startDrag(self,event): pass def removeSlider(self): # if a slider is not visible, plasmoidviewer crashes if the slider is not removed.. (dont ask me) if self.slider: self.middle_layout.removeItem(self.slider) self.slider = None def isMuted(self): if self.pa_sink: return self.pa_sink.isMuted() return False def isSinkOutput(self): if self.pa_sink: return self.pa_sink.is_sinkoutput() return False def isSinkInput(self): if self.pa_sink: return self.pa_sink.is_sinkinput() return False def isSink(self): if self.pa_sink: return self.pa_sink.is_sink() return False def isNowplaying(self): return False def isSourceOutput(self): if self.pa_sink: return self.pa_sink.is_sourceoutput() return False def wheelEvent(self, event): if self.slider: self.slider.wheelEvent(event) def set_name(self, string): self._name = in_unicode(string) def name(self): return self._name def update_module_info(self, index, name, argument, n_used, auto_unload): pass def get_ladspa_type(self): return str(type(self)) def get_pasink_name(self): return self.pa_sink.name ## LADSPA helpers def populate_presets_menu(self, target_menu, checked_item, add_actions): effect_menu = QMenu(i18n("Presets"), target_menu) if add_actions: self.action_save_preset = QAction(i18n("Save"),effect_menu) effect_menu.addAction(self.action_save_preset) if not self.is_preset(): self.action_save_preset.setEnabled(False) self.action_save_as_preset = QAction(i18n("Save As..."),effect_menu) effect_menu.addAction(self.action_save_as_preset) effect_menu.addSeparator() for preset in LADSPAPresetLoader().presets(): action = QAction(preset["preset_name"],effect_menu) effect_menu.addAction(action) if checked_item == preset["preset_name"]: action.setCheckable(True) action.setChecked(True) action.setEnabled(False) target_menu.addMenu(effect_menu) def populate_switch_effect_menu(self, target_menu, checked_item): effect_menu = QMenu(i18n("Effect"), target_menu) for preset in LADSPAEffects().effects(): action = QAction(preset["preset_name"],effect_menu) effect_menu.addAction(action) if checked_item == preset["label"]: action.setCheckable(True) action.setChecked(True) action.setEnabled(False) target_menu.addMenu(effect_menu) def on_set_ladspa_effect(self, value, master): parameters = "" preset = None for p in LADSPAEffects().effects(): if p["preset_name"] == value: parameters = "sink_name=" + urllib.quote(p["name"]) preset = p for p in LADSPAPresetLoader().presets(): if p["preset_name"] == value: parameters = "sink_name=" + urllib.quote(p["preset_name"]) preset = p parameters = parameters + " master=" + master + " " parameters = parameters + " plugin=" + preset["plugin"] parameters = parameters + " label=" + preset["label"] parameters = parameters + " control=" + preset["control"] self.pa_sink.set_ladspa_sink(parameters) def next_focus(self, forward=True): channels = self.veromix.get_visible_channels() if len(channels) > 0: index = 0 if self in channels: index = channels.index(self) if forward: index = index + 1 if index >= len(channels): index = 0 else: index = index - 1 if index < 0: index = len(channels) - 1 channels[index].set_focus() def set_focus(self): self.slider.set_focus() def pa_sink_proxy(self): return self.pa_sink class ChannelEventFilter(QObject): def __init__(self, channel): QObject.__init__(self) self.channel = channel def eventFilter(self, obj, event): if event and event.type() == QEvent.GraphicsSceneMouseDoubleClick: self.channel.on_double_clicked() return True if event.type() == QEvent.KeyPress: if event.key() == Qt.Key_Backtab: self.channel.next_focus(False) return True elif event.key() == Qt.Key_Tab: self.channel.next_focus() return True return QObject.eventFilter(self, obj, event) veromix/plasma/contents/code/SinkMbeqUI.py0000644000175100017500000002566211766302605017433 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2011-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import signal, os, datetime, urllib from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from PyKDE4.plasma import Plasma from SinkUI import SinkUI from LabelSlider import * from veromixcommon.LADSPAEffects import * class SinkMbeqUI(SinkUI): muteInfo = pyqtSignal(bool) def __init__(self , parent): self.automatically_muted = False self.extended_panel = None self.sliders = {} self.number_of_siders = 0 self.ladspa_sink_update = datetime.datetime.now() self.ladspa_values = None self.ladspa_timer_running = False self.module_info = None self.timer = QTimer() self.timer.timeout.connect(self.on_timer) SinkUI.__init__(self, parent) self.setContentsMargins(0,0,0,0) def initArrangement(self): SinkUI.initArrangement(self) self.create_sliders() self.create_header() def update_label(self): text = "" try: if self.module_info == None: pass elif self.is_preset(): text = str(self.module_info["name"]) + " - " + str(self.module_info["preset_name"]) else: text = str(self.module_info["name"]) except Exception, e: print "SinkMbeqUI", e if self.slider: self.label.setBoldText(text) self.set_name(text) def create_sliders(self): self.sliders = {} self.equalizer_widget = QGraphicsWidget() self.equalizer_layout = QGraphicsLinearLayout(Qt.Horizontal) self.equalizer_layout.setContentsMargins(0,0,0,0) self.equalizer_widget.setLayout(self.equalizer_layout) self.equalizer_layout.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) if self.module_info == None: return for i in range(0,self.number_of_siders): self.sliders[i] = VerticalSlider() self.sliders[i].setOrientation(Qt.Vertical) self.sliders[i].nativeWidget().actionTriggered.connect(self.on_sliders_cb) self.equalizer_layout.addItem(self.sliders[i]) self.equalizer_layout.addStretch() def remove_equalizer_widget(self): self.middle_layout.removeItem(self.equalizer_widget) def add_equalizer_widget(self): self.middle_layout.addItem(self.equalizer_widget) def composeArrangement(self): self.middle_layout.addItem(self.header_widget) self.add_equalizer_widget() self.layout.addItem(self.frame) self.frame_layout.addItem(self.panel) self.panel_layout.addItem(self.mute) self.panel_layout.addItem(self.middle) self.show_meter = False def create_header(self): self.header_widget = QGraphicsWidget() self.header_layout = QGraphicsLinearLayout(Qt.Horizontal) #self.header_layout.setContentsMargins(6,8,6,0) self.header_layout.setContentsMargins(0,0,12,0) self.header_widget.setLayout(self.header_layout) self.header_widget.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.label = Label() self.label.setContentsMargins(0,0,0,0) self.label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)) self.header_layout.addItem(self.label) def _get_effect_settings(self): effect = None for preset in LADSPAEffects().effects(): if preset["label"] == self.module_info["label"]: effect = preset return effect def createMiddle(self): self.middle = QGraphicsWidget() self.middle_layout = QGraphicsLinearLayout(Qt.Vertical) #self.middle_layout.setContentsMargins(6,8,6,0) self.middle_layout.setContentsMargins(0,0,0,0) self.middle.setLayout(self.middle_layout) self.middle.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)) self.createSlider() def context_menu_create_custom(self): self.create_menu_switch_preset() self.create_menu_switch_effect() self.action_kill = QAction(i18n("Disconnect/kill"), self.popup_menu) self.popup_menu.addAction(self.action_kill) def create_menu_switch_preset(self): self.populate_presets_menu(self.popup_menu, urllib.unquote(str(self.module_info["sink_name"])), True) def create_menu_switch_effect(self): self.populate_switch_effect_menu(self.popup_menu, self.module_info["label"]) def on_contextmenu_clicked(self, action): if action == self.action_save_preset: LADSPAPresetLoader().write_preset(self.module_info) elif action == self.action_save_as_preset: self.veromix.showModalWidget(SaveAsDialog(self)) elif action == self.action_kill: self.pa_sink.remove_ladspa_sink() else: self.on_change_effect(action.text()) def is_preset(self): return self.module_info["name"] != self.module_info["preset_name"] def context_menu_create_unlock_channels(self): pass def context_menu_create_sounddevices_other(self): pass def update_module_info(self, index, name, argument, n_used, auto_unload): self.module_info = self.parse_module_info(argument) if str(self.module_info["control"]) == "": count = 0 controls = "" else: controls = self.module_info["control"].split(",") count = len(controls) if count != self.number_of_siders: self.number_of_siders = count self.remove_equalizer_widget() self.create_sliders() self.add_equalizer_widget() self.set_name(self.module_info["sink_name"]) self.update_label() for i in range(0,self.number_of_siders): effect = self._get_effect_settings() scale = effect["scale"][i] minmax = effect["range"][i] self.sliders[i].setMinimum(minmax[0] * scale) self.sliders[i].setMaximum(minmax[1] * scale, False) self.sliders[i].setText(effect["labels"][i]) #self.sliders[i].setBoldText(str(controls[i])) tooltip = Plasma.ToolTipContent() #tooltip.setImage(pixmapFromSVG("audio-volume-high")) tooltip.setMainText(effect["name"] + " - " + effect["labels"][i] ) tooltip.setSubText(controls[i]) Plasma.ToolTipManager.self().setContent(self.sliders[i], tooltip) Plasma.ToolTipManager.self().registerWidget(self.sliders[i]) value = float(controls[i]) * scale self.sliders[i].setValue(int(value)) def parse_module_info(self, string): args = {} controls = string.split(" ") for entry in controls: s = entry.split("=") if len(s) == 2: args[s[0]]=s[1] args["name"] = "" if "device.ladspa.name" in self.pa_sink.props.keys(): args["name"] = self.pa_sink.props["device.ladspa.name"] args["preset_name"] = urllib.unquote(str(args["sink_name"])) return args def on_sliders_cb(self, action): if action == 7 or action == 3: values = [] for i in range(0,self.number_of_siders): values.append(self.sliders[i].value()) self.sliders[i].update_plasma_timestamp() self._schedule_set_ladspa_sink(values) def on_timer(self): self.timer.stop() self._set_ladspa_sink(self.ladspa_values) def _schedule_set_ladspa_sink(self,values): if self.timer.isActive(): self.timer.stop() self.ladspa_values = values self.timer.start(1000) def _set_ladspa_sink(self, values): if self.module_info == None: return control = "" effect = self._get_effect_settings() i = 0 # multiply (visible) values with scale for val in values: scale = effect["scale"][i] control = control + str(float(val)/float(scale)) + "," i = i + 1 self.module_info["control"] = control[:-1] parameters = "sink_name=%(sink_name)s master=%(master)s plugin=%(plugin)s label=%(label)s control=%(control)s" % self.module_info self.pa_sink.set_ladspa_sink(parameters) def on_change_effect(self, value): self.on_set_ladspa_effect(value, self.module_info["master"]) def get_ladspa_type(self): # FIXME return "ladspa" def wheelEvent(self, event): pass def on_close_save_dialog(self): self.veromix.destroyMessageOverlay() def save_preset(self, name): self.module_info["preset_name"] = str(name) LADSPAPresetLoader().write_preset(self.module_info) self.on_change_effect(str(name)) self.on_close_save_dialog() def context_menu_create_effects(self): pass class SaveAsDialog(QGraphicsWidget): def __init__(self, sinkmbequi): QGraphicsWidget .__init__(self) self.sinkmbequi = sinkmbequi self.setAutoFillBackground(True) layout = QGraphicsLinearLayout(Qt.Vertical) self.setLayout(layout) input_widget = QGraphicsWidget() input_layout = QGraphicsLinearLayout(Qt.Horizontal) input_widget.setLayout(input_layout) label = Plasma.Label() label.setText(""+i18n("Name")+"") input_layout.addItem(label) self.text_field = Plasma.LineEdit() input_layout.addItem(self.text_field) layout.addItem(input_widget) button_widget = QGraphicsWidget() button_layout = QGraphicsLinearLayout(Qt.Horizontal) button_widget.setLayout(button_layout) button_layout.addStretch() cancel_button = Plasma.PushButton() cancel_button.setText(i18n("Cancel")) cancel_button.clicked.connect(self.sinkmbequi.on_close_save_dialog) button_layout.addItem(cancel_button) save_button = Plasma.PushButton() save_button.setText(i18n("Save")) save_button.clicked.connect(self.on_save_clicked) button_layout.addItem(save_button) layout.addItem(button_widget) layout.addStretch() def on_save_clicked(self): if self.text_field.text() == "": return self.sinkmbequi.save_preset(self.text_field.text()) veromix/plasma/contents/code/Dummy-Testclient-dbus.py0000644000175100017500000000611611766302605021617 0ustar nikkibu#!/usr/bin/env python # -*- coding: utf-8 -*- # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import dbus import dbus.mainloop.qt from PyQt4.QtCore import * import signal ## ps -ef | grep test-dbus | grep -v grep | awk '{ print $2 }' | xargs -n 1 kill class PulseAudioDBus(QObject): #def __init__(self, sessionBus): #QObject.__init__(self) #self.call_manager_obj = sessionBus.get_object("org.veromix.pulseaudioservice","/org/veromix/pulseaudio") #self.call_manager = dbus.Interface(self.call_manager_obj, dbus_interface='org.veromix.notification' ) #self.connectToSignals() #def connectToSignals(self): #self.call_manager.connect_to_signal("sink_info", self.sink_info) ##self.call_manager.connect_to_signal("incomingCall", self.incomingCall) ##self.call_manager.connect_to_signal("callStateChanged", self.callStateChanged) def __init__(self): bus = dbus.SessionBus() pa_obj = bus.get_object("org.veromix.pulseaudioservice","/org/veromix/pulseaudio") interface = dbus.Interface(pa_obj,dbus_interface="org.veromix.notification") interface.connect_to_signal("sink_input_info", self.sink_input_info) interface.connect_to_signal("sink_info", self.sink_info) interface.connect_to_signal("sink_input_remove", self.sink_input_remove) interface.connect_to_signal("sink_remove", self.sink_remove) def sink_input_info(self, index, name, muted , volume , client_index,client_name, props): print "sink input signal: " , index, name, muted , volume , client_index,client_name, props print "" def sink_info(self, index, name, muted , volume , client_index,client_name, props): print "sink signal: " , index, name, muted , volume , client_index,client_name, props print "" def sink_input_remove(self, index): print "sink input remove signal: " , index def sink_remove(self, index): print "sink remove signal: " , index def pulse_set_sink_input_volume(self, index, vol): pass def pulse_sink_mute(self, index, mute): pass def pulse_set_sink_volume(self, index, vol): pass def pulse_sink_mute(self, index, mute): pass if __name__ == '__main__': print 'Entering loop' app=QCoreApplication(sys.argv) mainloop=dbus.mainloop.qt.DBusQtMainLoop(set_as_default=True) signal.signal(signal.SIGINT, signal.SIG_DFL) bus = dbus.SessionBus() obj = PulseAudioDBus() app.exec_() veromix/plasma/contents/code/SinkInputUI.py0000644000175100017500000001255011766302605017636 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from PyKDE4.plasma import Plasma import signal, os, datetime from LabelSlider import * from SinkUI import * from Channel import * from MuteButton import InputMuteButton class InputSinkUI(SinkUI): def __init__(self, parent): self.mouse_pressed = False SinkUI.__init__(self, parent) self.setAcceptDrops(False) self.setContentsMargins(0,0,0,0) self.layout.setContentsMargins(6,2,6,0) def createMute(self): self.mute = InputMuteButton(self) self.mute.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed,True)) self.connect(self.mute, SIGNAL("clicked()"), self.on_mute_cb) def context_menu_create_custom(self): self.create_menu_switch_sink() self.create_menu_ladspa_effects() def create_menu_kill_sink(self): self.action_kill = QAction(i18n("Disconnect/kill"), self.popup_menu) self.popup_menu.addAction(self.action_kill) self.action_kill.triggered.connect(self.on_contextmenu_clicked) def context_menu_create_settings(self): pass def create_menu_switch_sink(self): sink_menu = QMenu(i18n("Move To"), self.popup_menu) sinks = self.veromix.get_sink_widgets() for sink in sinks: action = QAction(sink.name(), self.popup_menu) sink_menu.addAction(action) self.popup_menu.addMenu(sink_menu) def create_menu_ladspa_effects(self): if not self.veromix.is_ladspa_enabled(): return def context_menu_create_effects(self): pass def on_contextmenu_clicked(self, action): if type(action) == bool: return if action.text() == self.action_kill.text(): self.sink_input_kill() return 0 # search ouputs for text, and move sink_input for sink in self.veromix.get_sink_widgets(): if action.text() == sink.name(): self.pa.move_sink_input(self.index, int(sink.index)) return 0 def getOutputIndex(self): return self.pa_sink.props["sink"] def update_label(self): text = self.pa_sink.name bold = self.pa_sink.props["app"] iconname = None if self.pa_sink.props["app_icon"] != "None": iconname = self.pa_sink.props["app_icon"] if iconname == None and self.pa_sink.props["app"] != "None": iconname = self.veromix.query_application(self.pa_sink.props["app"]) if bold == "knotify": bold = i18n("Event Sounds") text = "" iconname = 'dialog-information' if bold == "npviewer.bin" or bold == "plugin-container": bold = i18n("Flash Player") text = "" iconname = 'flash' if bold == "chromium-browser": bold = i18n("Chromium Browser") text = "" if bold == "Skype": if text == "Event Sound": text = i18n("Event Sound") if text == "Output": text = i18n("Voice Output") if text == "LADSPA Stream" or (self.pa_sink.props["media.name"] == "LADSPA Stream"): for sink in self.veromix.get_sink_widgets(): if sink.pa_sink.props["owner_module"] == self.pa_sink.props["owner_module"]: bold = sink.pa_sink.props["device.ladspa.name"] text = "" iconname = sink.pa_sink.props["device.icon_name"] # FIXME if bold in ["", "None", None]: bold = text text = "" if text in ["None", None]: text = "" if iconname in ["", "None", None]: iconname = "mixer-pcm" if iconname : self.mute.setBigIconName(iconname) self.updateIcon() if self.slider: self.set_name(bold) self.slider.setText(text) self.slider.setBoldText(bold) ### Drag and Drop def mousePressEvent(self, event): self.mouse_pressed = True def mouseReleaseEvent(self, event): self.mouse_pressed = False def mouseMoveEvent(self,e): if self.mouse_pressed : self.startDrag(e) def startDrag(self,event): drag = QDrag(event.widget()) drag.setPixmap(self.mute.icon().pixmap(self.size().height(),self.size().height())) mimedata = QMimeData() liste = [] liste.append(QUrl( "veromix://sink_input_index:" + str(int(self.index)))) mimedata.setUrls(liste) drag.setMimeData(mimedata) #drag.setHotSpot(event.pos() - self.rect().topLeft()) dropAction = drag.start(Qt.MoveAction) veromix/plasma/contents/code/SinkChannelWidget.py0000644000175100017500000001134711766302605021020 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2009-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from PyKDE4.plasma import Plasma from PyQt4.QtCore import * from PyQt4.QtGui import * from PyKDE4.kdeui import * from LabelSlider import LabelSlider class SinkChannelWidget(QGraphicsWidget): def __init__(self, veromix, sink): QGraphicsWidget.__init__(self) self.veromix = veromix self.sink = sink self.sliders = [] self.text = "" self.bold_text = "" self.init() def init(self): self.init_arrangement() self.create_channel_sliders() self.compose_arrangement() def compose_arrangement(self): self.setContentsMargins(0,0,0,0) self.layout.setContentsMargins(0,0,0,0) self.layout.addItem(self.label) self.layout.addItem(self.slider_widget) self.adjustSize() def init_arrangement(self): self.layout = QGraphicsLinearLayout(Qt.Vertical) self.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed, True)) self.layout.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed, True)) self.setLayout(self.layout) self.label = Plasma.Label() self.label.setPreferredHeight(self.sink.mute.size().height()) self.label.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed, True)) def create_channel_sliders(self): self.slider_layout = QGraphicsLinearLayout(Qt.Vertical) self.slider_layout.setContentsMargins(0,2,0,0) self.slider_widget = QGraphicsWidget() self.slider_widget.setLayout(self.slider_layout) self.slider_widget.setContentsMargins(0,0,0,0) def create_sliders(self): for channel in self.sink.pa_sink.getChannels(): slider = LabelSlider() slider.setOrientation(Qt.Horizontal) slider.setText(channel.get_name()) slider.setMaximum(self.veromix.get_max_volume_value()) slider.setValue(channel.get_volume()) slider.volumeChanged.connect(self.on_slider_cb) self.sliders.append(slider) self.slider_layout.addItem(slider) slider.installEventFilter(self.event_filter) def remove_sliders(self): for slider in self.sliders: self.slider_layout.removeItem(slider) del slider del self.sliders self.sliders = [] ## FIXME def setText(self, text): if text: self.text = text self.label.setText( ""+self.bold_text + " " + self.text) def setBoldText(self,text): if text: self.bold_text = text self.setText(self.text) def update_with_info(self, info): self.set_slider_values() def set_slider_values(self): channels = self.sink.pa_sink.getChannels() if len(channels) != len(self.sliders): self.remove_sliders() self.create_sliders() for i in range(0,len(channels)): name = channels[i].get_name() if name != "None": self.sliders[i].setBoldText("") self.sliders[i].setText(name) self.sliders[i].setValueFromPulse(channels[i].get_volume()) def on_slider_cb(self, value): vol = [] for slider in self.sliders: vol.append(slider.value()) slider.update_plasma_timestamp() self.sink.set_channel_volumes(vol) def setMaximum(self, value): for slider in self.sliders: slider.setMaximum(value) def wheelEvent(self, event): # dont touch the sliders, they will get the new values # via the pa-callback # else we get infinite loops self.sink.on_step_volume(event.delta() > 0) def installEventFilter(self, filter): if filter: self.event_filter = filter for slider in self.sliders: slider.installEventFilter(filter) self.label.installEventFilter(filter) self.slider_widget.installEventFilter(filter) QGraphicsWidget.installEventFilter(self,filter) def set_focus(self): # FIXME self.sliders[0].set_focus() veromix/plasma/contents/images/0000755000175100017500000000000011766302605015432 5ustar nikkibuveromix/plasma/contents/images/buttons.svgz0000644000175100017500000002533411766302605020052 0ustar nikkibu‹í}Y·£F–î»~EÞì—î%§Å<¸Ëuó „z¹ 1‰ýú‹Î”'g¦ËÕ«ªísì\;v"⋈½?bøÛÿÎå»!jÚ¬®~}þ ¼UAfUòë{gÇ Þ¿k;¿ ý²®¢_ßWõûÿû÷Õßþχï˜&ò»(|7f]úNªŠ6ð/Ñ»ÿL»îòËf3ŽãÏÙ“ðçºI6ÿõîÇ%e;$«wïÞ-­Ú_Âà×÷Oú—¾)ôÂ`•Ñ9ªºvþ nÞT>ª÷‡gCÔçs]µ)«ö?^)7aü¢}™~PI’ÜЂ>,Ú¹êüéçI—wüZR€Í÷QóÇ´~™Ê¥$~óeb_?})ýËòï%Á³àç¶î› Š—”ÑÏUÔmØûùø9ìÂW?ó\øŸ<÷“©üsÔ^ü j7Ïò‡ôcvéx¸M£,I»÷Yøëû%ÐÃÍóãyÁð3üõü›¯£ìÓTaÜßâ×÷§¾ëîõ¸üðíÓÔuß]úîÿESU?³¼û«Œ&{÷îâ' ¬ÊºùõýO§º £æ9 {øû$ª^ 3ëæÇG>F$ÍR˜u5~,Ù_ý\ÒgaôIÜSD}Ê£ ûZÌK¡ÜßñåiÀÏ8@LB_SkS?¬Ç_ßy«ëóòÛðÏ(Œá ùyt0ýúG~&@„¿ˆ[žŠ‘?8Äç‘Kö÷æû¡¯²ni"—é‹ä}ÓÜJŽ–¢|À'¥6­Ç{¡ýú¾kúèó”cV-™ùðŒPùâÕž4^@ ÂÈo¨,ùIè‹¢}н—ëlà¼ÄÝ_ìQýÝ»è|yU(F`Ž ï_E?#%Ž_ÕúR½¯ê Ç@É—¸ßHro¥K¼¤—â|OŸ‰—G?ÅÜóð"­üS}Z®K+ÉÚl&½ÿ=¯À/Ân¾w&Ó|xÿnó²yyä¾þ­7øÛæËVý £¸ýؼïwÈÕyYºˆËÒÔ–qäõs_‰Áå÷i*8üP7Y’-ý ŒC?!ï~y£K¥8L.×à—I‡Ëÿ»Ý[ò3@"±(¡ö3H€Ào'¸å¹àa ¾ò>‹Îô¨óõ{) Çâû</y/£‡«sÔù¡ßù‹ïY‚?á2tþb±üߟžñ· øÅ­›âù‘ïÞÝüÓÒ9ÿúþýß_Ä ƒ_–áëìwÏÎKßt'×Ëpµ<ü%âåû+üÑÇŸm¢Çqð«¦Cœ³{¢Ýee)Ýò‚Õ{&Ÿ^ô)›WùøÛæ9—wÉÇÜÒ?½Â{Ý_Îu=)|_ú§¨üõ½z[jãé‰ÉÕ÷¤÷ !Ä'ø¿,¿ûa鋪/ë<š.uÓ}˜ÂKvï¿‚Š'ùE㥠šÚËt~ÝG,¶ÃOèÕýs? !¯„OÝï'²û ßBPô•¸íæ{Û~êó~ÿ;^ªå—j±%®>|ñ¡éËåÕ‡¨ªÃð¿Û®©‹èQùñú±ã_”ŸnË)ZrûËRUøZ˜×Yõ©tEÔ”Ùü‚<ËB›ÆŸ?yÆ]ZÇqu¿Ï²—×| ¦‹ß¥ŸÀ]Cþª©ö'~BÞ©÷–~¡Ç{äÝíËÒz(£e ¸ÿýb~†ÐK÷yYÝ-­/Šê¡t¾Ìì«Ü}×—¬¾Œ›äG0ã_ÁxÖ>Œ ?ŽQàAûkBôxÀý¿O³xGÌ£)ù¯ÂÙCsÁZ öØX@â±±`Ÿµ•çö¶Xä÷€ú ó»€ !ù%P«ûUþLÿt@úZÓAðï´²¯6Çé³û‡ýÝ®BÀ/°àX‚t Ð#:Ŀٕ~ ëÿ^]éCV¡_Œë¿Ã6xmS|HëÅCþå{ìÓ*xÁð+`1Á—´½[jw{}¹,ý.úOû ø¯¤G~ >~I›(^LôÅòúåÑ*¼TÉßr ù)ÛÓ†5ŠÔÔò§ÛNÊ9ÉrÅÞo©‘¡¼% ÔpïZÔ{oJ •H1•ÙƒZ9Ú|y[-W§f¤(#èCzµS”€µO"Ï¡¦ÁÙ¡B8„ÕsÙû°ž{ºTÏä|D‡~Kß_„mÇ¢W{!£Ács:¥—/ù›Î 2O±’çæLb6Ýȃ_J’Ùeñ¡VF£/T’;dº¬nÚÜ@iž­¨ÛI`µ[;êiWKŽì‘Éæ&nðÍ ºñP›^Û˜!›L¸õ~K\xê*S¼iÛ:êÌ× Æ¬Ê¬ø‹zmàœÈA0âÈj€mp…·Á:õ¡Š£ º’ ;áI¼AlX -D DиWŽC©Fy«#ƒÓ¤}»âÒB(Ø|³Ïµu(ùhÚtJ¤“Î(^‹çÛKpÊ+äb~‹pÉ)}J¹¤<Ã!'^ˉzBNuj:+ã*›8Öf«\nnRÈ6 eÃ[§zLÕÑœlã6“"kfKv2€wÓ¦¤oc‡i¨I!‡2K†8ó‰m‘¯¼RV`©þCa´I퉂•ý¨•à‘%>Iöû ˜ÌÁƒȶ=p»v|vô Ë ¥ù†u¹!Y™ŽÀ¹Ö^‘²¹A­L™š—ÄŠ²—®ŠNÕñÔâñírZ$ å{65^Rˆ1Y‡Ìßíú­–µ+IF2ƒ…¢Æ1%[V<ÊÂ$ ß›.!Ó´8^Ypà*”I&¨kžQfj˜{IÎZ`ÈcŠÒì•sš[à’p¦r¼ì(+1•s¥¹g Ô ÏÐj*ê\಼/¼80Nf ª ¥Ñl!XÜæ ´f¼ Âv‡ÊÝ­zF©±¼ÀÌ@%ÜQ5Ñ|0=A2Au½¿xr9‹G…èZÈÒ›©‹TEoçÖ–×Ù¶o’èËÍmmÚ|e KsØÔëòBÉNÊ-Í…úœ€°ŠäNÕ¡õšß©µ½”$SЙǣ)ëjêÈ û½'=ȦE“Öw«fÀ„› îµ%·pN½Œv|Å!IDæ ¢v$½Òµ"x}ËÐûÑW9“ŽNqdœ1ˆ°½Æ+zðH{Ýfõ6¸y6iª¨&/ƒ=C1Ìžó)^éžÛ´JãëKÛk* A[Ì%)¸¾ÉM¡Å+Œ¢*jhcÎ6 >„.Õ11֛Ѥ/Óh-ï*­®fÕšƒ’jRg­“ì !u8:d©®ÃöÜj[«Lœ|E‘óWm»´†«–õÅšÊ7¦KüfïŸeB;273 Ë·=¤ÛQ€“ž*Ž Ø]¤ãV'ÊÊ%³X›±j‚U2hY(›,ª*MEGÉÔ¯ýnª“0 *ê”Jp’B%5…â8P´£§ž¢ÒµTØ­öWlËÊô¡£¶WÅ:ª9ÄÒi‚†Ä Js ıL8Ø‚©(â-Eöî9ï¸Ìh±ºêÀòc ê”ÌÙj•Ñ®IªÈŽMœíeÇœ¢’íì =‡’›mC±‡€ ÙŽ¤2H׌=,ЗžDr'8( L:eN˜P‰ÀQ[ù§b}U{1f†¢†ÏŠé!¥Ê‚’º¡p¬oîÖ%ɘ ÎÞiŠ d‚Ã..cv‡6»xBw›ÝZ¹ÓÁܸZ¶”k 9I’_]ý Éüoå‘=XC =˜C÷ðÑZ‘Gƒè1æë3ÓÔøÔÚ}2¾åÓáÀoÚ_ºn¯HŽ7àÍx3Þ €7àÍøÿ§ñÚEÆ~ˆÌ@?¾Qäaô^‚‡ÁÃÇîñ¿3™ñ=ëÁïÛè‡Í‡¾e>|Î#ýï·õÅ~ÀtÀ×î!ªæ,¥­paöÜCfž.Ùõ´Õ("BÐWacÍòçÊ®cÌû=¦_.²×¥¼’(¨Àee–õf2/Ŷkg4pØÄ˽“"ˆ±{Ðv+3Áb|'@·=Nv•ã Ä©U¹¦$2S5mw¬5ß[!ø5ß9ÌÚ`WήdeÌâŒT«,\{„G i挂¤g‰qlȱ2<Ú) iv¹³aÒ°o°J“#IÕ®œ ˆî”ëK•“´5z̹Ùƒëš4"ʘ¥ú2ÎS7mKŒlZNÁk‰¥C#³ÎÁ¦¶ÃÒá’ê†‰í±½Uõª°¿ÝÝF 9Z“"– ¿GÌ Þ)É8:ÏëÚÙ°g£%$$<¾ \(0¦t…S[œ–¼-b'ã|›*¢7)ýd³b ^\B­e‹ï¹S­Qm²ò °gz¶­Nʆw-:µTØQEàq«œ¡k™ÁäA"³yê×|äÂÖ¡F,u6 +ìÆ\4¸ R#Ÿ—²ÀŠâpEà]ÓØA²ã‚ Â’«¡«lšó\R!níOü’X‰bTU¡ÅHË·t—ë°Ts€Ã|¿Œ½"x7D4 ‰&š?]Dè¶"ZO#|ñPðÛ,¯6Ô®Œ"ÙíTLµ·' L!ë õž†‰éq› ÐLkJÙºvÑ„Ñh`ÂŽ–4ÈŽ·•EéIu†d1¢ŽSÂO‚°RÌ·öfñ“}$X¬âÓA„ñ~Ý+•N¦5m¬—ª: Q8˜èÒ§CpF _-µ†¦ ž«E7ñÝ0×4WDt=f4×',„䩜βø¹_ÓâEh›X.xnù[@rÝl"úd¥Ûã­bÏ„ÄèöYÙÖZçíH)¹ˆœ`ÇÓUˆÍ‚IGÔ*N MÂ7`{A=Óö, Ç è°¡È‹•VˆäKÃ.UGý*kz2$kÉõ´´è3O³»¾îŠ+¹ÆABKš¡…M¹-GdÏî¼ê µêœ[±”fÞM#å*ÙbWɼƒ““æPy‡õ7B„´Ü1A §"b-=öyGuÔM˜X rܤ­öÕ¼¡ŒØ‡ÿ°ÅƒÅÿJÛhVGh{äU첀Ρɠ'Ü«¨šìv£A("mUïAw½Ùm&Ék7;è°2ÿ²mÊ¹Š›ž‡Gû¦4Ãv—Í`¬vâ¼KRþjr„dqÑE ©Ñã¦ñI€ãÛ½/Ì6o¹GÎö05"ÖÊÚSgÞX«|d…½p2vù?a /YrCIX‹6àÄjÅ•8RGbBð!¦Ó;L7Ú€¤bÚï„|–«<`Ô†äq‰ëÐlJ¸Ô=Ç2ÈÌðVkÜ6wÎÒ.Ýex±<¥ººj+–IŽ‹Auå}Æ•+ 4<8°ÙêËŽ’.¨ª2ýôµ“O”¸gCðÕ¸c“K‰9/M—JzÖn†³e\¨ÓT©%®b+µ¥»Ñfå eÍM¥¬nŸ²ÝËEq–Ém©Qø]±µûæÒîÝ“v”Ç]1©ë‰¿ì×§ºÏÇqÅã¾gw"ïQŒáa <À œ·^ˆfÇ"ã÷ ,¥Œ4M6¸­`HâN‹§×ÒKTóh¦ó4³Õnj@¦Ë…YØ(ȹÔuDVp¸ÉšTdgPÔ6²ÔƇ-êiˆ±i­%œ"mOº ¹Ñ¶&WHb÷dä—3C;˜Ùuk‹²„jQ›®Ám»3KíÉ̺ʘȴ«6] ÛS‹]™ñªuÉæz>­´âÙ]š¥w¾A°‘ÐÉj5^£×äe[ˆ¾ã>Uê¦ Ìn³±U}cò.¼cDyËWÆžO†TKç¨UVM*õÞ-öWkÞÖ%Ñr-¦Uk©L›šê*¨ ή¹`ÞÎÖ7µ œ¯v¹íâ˜sc¥¡·ã†;Ñ+ÃvÅ’·Zøx<#–P»“ÜðVaqu†ºqK¸¦\y×õz''³'9]Îmµ¨Ý™4}Qo‚Öuu³…Û®OÜ:HÝt1Vx_À-Ö®ÑUØÒÛµdñ¸]“}Ó7iB½\úë›Çê#2yâ78y5¥»B€Å¾HIÉÈt‚¼¶B… 7×'üf©Ô†€dñZ=œbDŒrØ÷ÞɃ‰g;{ÃRPÆ“¤?ì ßø¸ùhøÃ?AÄÝÒ'^BäÁ€_ÂE~{§½Ã G  4ùsx×üsþ™ßŸôKóãÜ’WNÕ7ýŒW_3¿åe¿MR¾ª9ÿò×ùÚù欼9+oÎÊ›³ò欼9+oÎÊ›³òæ¬üû9+ßö5@|t@ûx@ƒá_‚T<~“1Çó¥Þ;…“$ÂÕf™2‡"Qü”š …8`«ÚèÅàZ¾Åö½•Íp>ò;Š’a!‘˜n®N™”8uDöÁžšéY¹µ$·Âv·¢hÁìÖè­Uw‰³“È£ràido§ÂX£¼Xá›pЋ„”­Æ“q ?œ]æ,Ÿ˜íz¯™ B±««'Ù¥lš¡Ú«{áYŠgµ½yÔ}ébvÕ™TÑÈX׿”ÝQ÷vQ\ËvÒ™F s^¥ì89׊|;l¹SvD‰míÜDû':8eÏ}„S¡KŽ ©-P”¸ÛÅ>6Œ:@Ì€dPSÑ$‚ $kGY©­½–XÕy%DJprv#)EʼäÊãf$ä™4/4]ÕšÚç¹uÈöÂÑßi…]NÜfŸv0JâÑ(Øaµð^’=´Jü‚‰\;Pg/y‚¥«½>Dù¨GVÙSÂYm0 iL”K—ã6mPA W0wª%Ÿ9Òl~ÅŸ“©ñ…}æ£bîƒýÅÕ‹Î1A1é½ëöjË‚â×ܱ¾T§'0`6¼ØTQ3X§ÐœÎYbÙúhµº\`ü¼޶çÌS¤ "¨“¸­!…¢dl'cœ”ÏÉ·+…¾ËxcÑ CÞ%ïˆÄ)5”p’ÊV¨TtÓ;¸³ö݉…´Ñð%7ì{ñP² GµÒƒ­™DÌnĤ t‘·¬ùùýêsÁÚà7^rh³c\»©ët1ŸˆCVðÔì¤ ª÷ƒåqxïïbÉbôƒÙÁ·ä]Q8bîlhºÒ%Y€ÄŽ³Û ×Ñ«<ÀHí&DËm=7íúÚ„k¸•—êdÀ¹< *!t8ûЋ©Õ>àn„Ê Ú‘›ÀZôT³4”A^jóÔ[ÄL;¼à¸c‹:É Û…“Å£j0ÆZðf—gp`\º :s÷òÙCŒJ:§`f}ϵtI8¶d¨¬¥“釔x3P EŽñ(UÉÖÐHtm§(’f Î:½·ô<^½ öV¾#Øî5i‚îdX Þ_žò×öå&¨¥7akÛ¼µen’Øfõ1&ÉÝþ‘c³Ü‹jÎUR¬NíMÙÛndS–ÖêiŸœµ¼!ctH|7c·t»Ip,ÁÚð¦¢kwPl˜ö¾LØ6ï]¥K³©øàWL7!ˆt£òb̹ý¤ŸÎÄ>@™_Z*I[nVÎHÀ4HÝ*(WtpÃzt:P‡uœó‚lPÞIÖV;ce·KíÉ©šÙef^!µ‰TÓ½p?Š“Üh\µ½¤n|,™„±i‚Ô­‡Æp ‘Ý‚%uo²:¾»tÉ œáÝ xÃ( “ê‹WòœCDÐdšk;åäû<‘ Ù·áœÈ}ÓÀöÍÉÙpœ³ÙàñdmñèÒûÈ+v‚ø´A×ùd±”®+ˆÜf›¹È‘žÓp-ŸêKGM ·ƒq` JvC,Ùå:³V 9%N¨µre&¾­« yMá U˜û›ŒÈ.ç÷ƒ!òaº¢›æèmHâ$‰8LŽk°Ûµ ž7-{>sÕÍ|ÔêŸýñ¿iþ¢Ð§fú5Öľ|‰Oddƒøwíß/¯ûŸhâ:@„~A™½ÿÂZþ±éÿÈtO(£ßš.€éo&÷›Éýfr¿™Üo&÷›Éýfr¿™Ü?jrÿ‹¾Fÿ“¿o2ÿ[}€ý'³ÆU4u?ΓßdqèÏÆ·ñ§ËûË›ØzþæÚc x™¤ùª8'3ZÏ`šêÍaÖi6 êl4ÇX†k#ì"Ý_ųd…oÝ‹\­föÜš`Üek”Ï [)3‡Ž €¦©¸Øè0‚ò°‡ÈIŽâÈOˆ: œŠ§Ó é½l}oĬÎëdBWëÔŠcÊE„ÛDËx±Ûð“(„C. T"Þpñ b [¢Ùö†SbEI;Ï-’¢…¨yœlñLü•·,im`¢¹ØÐ›Î9xÏ2‘¤Ø—®ø<ͤðcª¬OÝJÀÜpÃÑ"eÔ-%ƒIžs*§ÎÖMt‡S œé8t×[í Uç+srÊÃbV Ó¦lÊ[1E¦ar`%\²«C䵸ŒÇ=ä„´tE{$@ÂIŒìÜñøÌK¢ 03ë8Ä•ºRDçJä)HäÃArVPùêVÌš4Eg¢ÕÐôù˜ì’Œím5Ê™šòÀzë,š§³xÓ-SXj:óÙ®÷%†Ï¸™§U«“V"›+6 æÏ£[]MctÓ:n8Cˆp kl´ª=Óʘ?kö^üt¤CÙLgj§tŽÙe+s>à;YS`«àÖY㔆P/€ÍíÝùxBø9½å”ÆóÀžo©]iþöšs)ÃÃÛ"Gˆ´j@*¢²P’5Z·…ÚYzÑU]Œ!›3g†Ò™ÝåÍd¹05«‘v´ŽYz G<<‡3¯ºãªÉ<3H-“SegàQì3¦àš•lÌfÕÜNÂè«/>œEÓžt<Ç?SôVévæ]Ð+¬Ä êhÁ™âwžä:µ#I/jq¢V©2!¼Å¨4"áI4’º#\žØCf2/î/žu–qŒ¥4wÕç#™³dò£Ø2UêðºQ.šë3+rœúTïèqqTS¯]új‘£-‘s̽Ƙr[FÚÀ‰|Cík±£`Ý8&·<“GMšç*ƒex%æ&QW3ÝÍÞIœŒ¥€Ðf@»´9èšs¶‚²<_ü±Å£Ü¶@odõåÅ–½&A]‚óY‹áèÌæeÊ™³¢åÑõoߘ Éã~qÕl³&L5H`Ûv´ÂpN¬iO­g+Ó°“2ܸ•D€kËöÊ“’„<²šJ–:<‡ë`»–”Y äð†ÑL̼b7£=?[~a÷,u6=p@ÍvZ“D<áWšƒB† ru»ÍÆ! ‡Oƒ‚ÈX´%ÊN¢#šiQgäAh×1Ù!B‰–Žlϳ Á5—Û* „¦‹À‘bê"k×îmU¶„eËè!(íA•ǵ<¨b •ÈM¥Íóæò–U—ÃŒy 3\Y]÷š_Îñ~tªL‘ ÆêgiϺ«u~ ºCŒ\'tÒð¤µR`ÁÅö=$O­m¾Þ)2yVPðOÄ>Ü®}#+Ç "•ÆÕíÐG§ F¹Ä«œ±Ø.·Ó sZ/¿†p$…ÂYqöÈí”Çã¡ ×bD®³!^6äfk‰]ºëðiîÈ„'™éÖJ¿2“ÜìÑà +¤;u·e¬Ì©z‚[ÔÅ’=®@Hq¦©?VA…À”"}•wçYF‚ãØöÖÄf“xXGD¤*w OebÂäRÒ@´ÆŠ¢½ÒwoˆEû£Zp9älövÒœKñ²/çK¤¶¿QŒã Ó9LW͸<_‡f‰ n8êÙŒ›ÔAd3½ÁIŒ/lØ}¬à—K ƒ@·gÄõ¡¬0€W²”!]²[¯Á­z":Ãmµœ_‰ÚM¸×2Tø[¿ÝQxîèVÆUÍ(9-™HU,CÕ'{±µ¦\CßrËȬ¶àE¶:¯ )êúx¬•<úœx*÷A¢òë6 ‡ÀxÓô¡AUJÇ~Cu6‡ ¹¥eiúÐ&SФ"æ‰3om"ò¶×WÍÚ2*òëÅÔ­’xX<Ý}º)*ê²cWdªÄF¦ç.Ñ+‘sÍ•S³ô<œo‹»:¢NS[Ü"À1Y¡ÄÑÓ’ì…œç›0ðú"‰bP+‘qŒàŠ\/Š×½`»AñPå§T†bIllàDëhÊX¶«Ä`24ÖCZ›&nL#ÅpÝ£mqì¹=Ân‘jäú° ÁcÐA6žEt“  q¼ÝÐBp¥È“ÐÃA[ã6`©™:<ãLþœ—‘pA˜“7#E©yðQLØS=ÅÁÏf7jH©_£QœmhÏžhâo¨ÀÕiMiÖv»9N ž*(rbÕš¤²\}7[~w_ÈÍ6ßK›[+Ѝ»ª_»ZÜ×p—ÉADa<߇ÂÖ­¼!­må6°v˜Š¯’Ó–vÝ‘Î7’½ÜÎàU–¼~PÀp^h•'ú²d?\“³E÷&®¯@ˆ¬â-°ÍFàÁ­–sŸâÚÎ[o™k»õ§¢ØS5ÔÄZX38rN‘‚.9‡å<ØÒR²Ò)\)P¯±K|«æ¶°`—J[«»H2‰;sÈî!?ÎoèDo6S^-¥Æx„Ÿ˜YžNˆ³ 0ÃE@:‚»òÄÚV×r®ÚP]ܨyFm³+¹ñ²qcQAáŸ$"•½’­N\Ô%3£çÙÁE:Þj^úfÜ&!¶ØJÃOÙaˆ° Gù*7^ëBì«”õ˜=#LÐÐ×=  Aê ÔFGbwqÖGp(ûê<,{XáNãk–Š XpõÐ%6v¸“p*ÒæJ\­µbwÚj0Ðq‡N>zÆ*ƒ©@Më&“î± ìºbSQ‹UZ¥¥¿÷TÏ]%s.Ä„n±ðb[;í“4G8¥Rô½WÌkO˜Sw×ZzšÅÛ[ÍLͰ>#ý´‡âV76+d ÿè7wÏc»†ë¤Q.Né‰y¼(rJû{=IБèÊáz;m$ižæHÀ%ªf 4êöv´`(0\{•ãç÷!“ëzbƒam©e¶A>ï¥KÏåñ–f°7ï5"N¶ëã†Ùñn\òÞO¶Cš`(¨‰†Dp³JvÇö.nÁfµmÑDs×e7fZ$ûˆîaHíΛ àãnL@5…<š¿ ²2£G°Ùk€ÚyX·UnÂ!–.üvDxgÅAć‡3on±AůÖfmØÍ5•茊‰³ÜÚ» øv]Þ¾®—…ð•9qÿôÒÄ7¶)œm ý„c÷y•ÐOäÞHäOòx¿ÈïSmÉ£ù¨aO䳯"yÐÀˆ—ðYó9¼kþo´ôµm¤`ô‡øýΉÿÈwNûïœ8ô×ùÎùF½‘Do$ÑIôF½‘Do$ÑIôF½‘Do$ÑIôF½‘Do$ÑïL<3÷ òñÔ ü‘ÄyŠzØb‘=iáOZ ò¬…¿h-²G-ûxñ¢þrñ-Âçßê|W„Ï·Ï®»ë5Ñð£ûàA¿=±}þõ=‰}:ço\ÍWóÆÕ¼q5o\ÍWóÆÕ¼q5o\ÍWóÆÕ¼q5o\ÍWóÆÕüi¸š?8¡‡üú ‘6ðËè??€?ÿõ#g¤!_YšõO$g€Oÿþ¹g±‚ØO <1OË¿‚Š\dijl‰}d´ÈgÍûÕ“&ô¬ùû¨ ½h¯¯>¦y•xµ±à·˜¢>™ üí¥_¿QÅ_Çú6/èkzãšÞ¸¦7®ékzãšÞ¸¦7®ékzãšÞ¸¦7®ékzãšþÊ\Ó}ŽÉ'{È^¼¨L÷tÐ㎘?p8„½Z'öÝš¾Fþž-MálKÓýA ÿèFM_+ÔÏ÷ãÿcç$@ùÝBýKœ“ðíÀßBùŸqgݯ¶=ô;Íô«íù~J ñþó>á÷ ûr¡ßßÓíOïïHáäï÷ÿê=ð¾ nò÷'ëŸ?¸ÿàÉdúýñÏ î—ÕìßÞ¥üÞ±de«ôÿ%ñ§IíøÓœv~œÿ(8Q~ÔX xÔx”ß5ȧÙö$ô>k>‡³ã¿…ìÏ·{üÃÈþŠÿ—AöË´ýo„%¿y,ùìÏ^>9 OQè@Ÿ´îZ8ñ¤õuןÝ{uñ¢þ1ð?¼ˆâ¨)½ráoÂüóeæß?¤áOó8YüÍ.üèȳߋ<{¹0þ᧨‡ñ'­ûÅ£ð¤õõ õ<™"^]¼¨L÷  ÿSX†ÿy û0¾Ïþ‡Í𿲗ùØŸÿÈQ“þ}kåkû÷¹˜ü—]ÐKÃz™¤?5¿§¨‡iMðó\&ø™{žüdÞ›ûÇðYõ% ðsåsxÿAû+;™vø¡þvGþócg>š¡oŸi>Ú­ŸhÝVŸ—u>éOk@_žvù‚€—ðYñ9ü½»}ýëÕÇîú¶Åò¹aþG‘þ—÷8€-$Ó2ås~¥ ÿýí‡Ç¾ü¹A=5 }lqò3 }ÔX zÔx”ß5'_A^ÂgÍçðwûœÔFÁþJ>çCð·M;,Áÿ­g[î»veromix/plasma/metadata.desktop0000644000175100017500000000141011766302605015477 0ustar nikkibu[Desktop Entry] Encoding=UTF-8 Name=Veromix Name[sr]=Ð’ÐµÑ€Ð¾Ð¼Ð¸ÐºÑ Comment=Veromix is a mixer for the Pulseaudio sound server. Comment[sr]=МикÑетаз за звучни Ñервер ПулÑаудио. Comment[sr@latin]=Mikseta za zvuÄni server Pulseaudio. Type=Service ServiceTypes=Plasma/Applet,Plasma/PopupApplet Icon=veromix-plasmoid X-Plasma-API=python X-Plasma-MainScript=code/main.py X-KDE-PluginInfo-Author=Nik Lutz X-KDE-PluginInfo-Email=nik.lutz@gmail.com X-KDE-PluginInfo-Name=veromix-plasmoid X-KDE-PluginInfo-Version=0.18.3 X-KDE-PluginInfo-Website=http://code.google.com/p/veromix-plasmoid/ X-KDE-PluginInfo-Category=Multimedia X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true X-Plasma-NotificationArea=true veromix/plasma/dbus-service0000777000175100017500000000000011766302605017374 2../dbus-serviceustar nikkibuveromix/gtk/0000755000175100017500000000000011766302605011640 5ustar nikkibuveromix/gtk/Mpris2MediaPlayerGtk.py0000644000175100017500000000403711766302605016155 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from gi.repository import Gtk, Gdk, GObject from veromixcommon.MediaPlayer import * from veromixcommon.PulseProxyObjects import AbstractSink class Mpris2MediaPlayerGtk(GObject.GObject, Mpris2MediaPlayer, AbstractSink): __gsignals__ = { 'data_updated': (GObject.SIGNAL_RUN_FIRST, None, (),), } def __init__(self, name, dbus_proxy): GObject.GObject.__init__(self) Mpris2MediaPlayer.__init__(self, name, dbus_proxy) self.init_connection() self._nice_title = name def signal_data_updated(self): self.emit("data_updated") def url_path_of(self, string): # FIXME return string[7:] def trigger_timer_callback(self, timeout, function): QTimer.singleShot(timeout, function) def create_pixmap(self, val): img = Gtk.Image() img.set_from_file(val) return img def is_media_player(self): return True def get_assotiated_sink_input(self, sink_inputs): name = str(self.get_application_name()).lower() for channel in sink_inputs: if str(name).lower().find(channel.pa_sink_proxy().get_nice_title()) >= 0: return channel for channel in sink_inputs: if str(channel.pa_sink_proxy().get_nice_title()).lower().find(name) >= 0: return channel return None veromix/gtk/veromixcommon0000777000175100017500000000000011766302605016110 2../commonustar nikkibuveromix/gtk/GPulseAudioProxy.py0000644000175100017500000003164611766302605015447 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import signal import dbus.mainloop.glib #from PyQt4.QtCore import * from gi.repository import GObject from veromixcommon.PulseProxyObjects import * from Mpris2MediaPlayerGtk import Mpris2MediaPlayerGtk def SIGNAL(name): return name class PulseAudio(GObject.GObject): __gsignals__ = { 'on_sink_info': (GObject.SIGNAL_RUN_FIRST, None, (object,)), 'on_sink_remove': (GObject.SIGNAL_RUN_FIRST, None, (int,)), 'on_sink_input_info': (GObject.SIGNAL_RUN_FIRST, None, (object,)), 'on_sink_input_remove': (GObject.SIGNAL_RUN_FIRST, None, (int,)), 'on_source_info': (GObject.SIGNAL_RUN_FIRST, None, (object,)), 'on_source_remove': (GObject.SIGNAL_RUN_FIRST, None, (int,)), 'on_source_output_info': (GObject.SIGNAL_RUN_FIRST, None, (object,)), 'on_source_output_remove': (GObject.SIGNAL_RUN_FIRST, None, (int,)), 'on_card_info': (GObject.SIGNAL_RUN_FIRST, None, (object,)), 'on_card_remove': (GObject.SIGNAL_RUN_FIRST, None, (int,)), 'on_module_info': (GObject.SIGNAL_RUN_FIRST, None, (object,)), 'on_volume_meter_sink_input': (GObject.SIGNAL_RUN_FIRST, None, (int, float,)), 'on_volume_meter_source': (GObject.SIGNAL_RUN_FIRST, None, (int, float,)), 'on_volume_meter_sink': (GObject.SIGNAL_RUN_FIRST, None, (int, float,)), 'mpris2_player_added': (GObject.SIGNAL_RUN_FIRST, None, (str, object,)), 'mpris2_player_removed': (GObject.SIGNAL_RUN_FIRST, None, (str, object,)), } def __init__(self, parent, dbus=None): GObject.GObject.__init__(self) self.REQUIRED_SERVICE_VERSION = 15 if dbus == None: if not dbus.get_default_main_loop(): mainloop=dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) else: mainloop=dbus.mainloop.glib.DBusGMainLoop(set_as_default=False) self.bus = dbus.SessionBus() else: self.bus = dbus self.veromix = parent def connect_veromix_service(self): if self.getMixer().veromix_service_version() != self.REQUIRED_SERVICE_VERSION: try: self.getMixer().veromix_service_quit() if self.getMixer().veromix_service_version() != self.REQUIRED_SERVICE_VERSION: raise NameError("Wrong server versions") except: raise NameError("Wrong server versions") self.bus.add_signal_receiver(self.on_sink_input_info, dbus_interface="org.veromix.notification", signal_name="sink_input_info") self.bus.add_signal_receiver(self.on_sink_info, dbus_interface="org.veromix.notification", signal_name="sink_info") self.bus.add_signal_receiver(self.on_source_output_info, dbus_interface="org.veromix.notification", signal_name="source_output_info") self.bus.add_signal_receiver(self.on_source_info, dbus_interface="org.veromix.notification", signal_name="source_info") self.bus.add_signal_receiver(self.on_sink_input_remove, dbus_interface="org.veromix.notification", signal_name="sink_input_remove") self.bus.add_signal_receiver(self.on_sink_remove, dbus_interface="org.veromix.notification", signal_name="sink_remove") self.bus.add_signal_receiver(self.on_source_remove, dbus_interface="org.veromix.notification", signal_name="source_remove") self.bus.add_signal_receiver(self.on_source_output_remove, dbus_interface="org.veromix.notification", signal_name="source_output_remove") self.bus.add_signal_receiver(self.on_volume_meter_sink_input, dbus_interface="org.veromix.notification", signal_name="volume_meter_sink_input") self.bus.add_signal_receiver(self.on_volume_meter_source, dbus_interface="org.veromix.notification", signal_name="volume_meter_source") self.bus.add_signal_receiver(self.on_volume_meter_sink, dbus_interface="org.veromix.notification", signal_name="volume_meter_sink") self.bus.add_signal_receiver(self.on_card_info, dbus_interface="org.veromix.notification", signal_name="card_info") self.bus.add_signal_receiver(self.on_card_remove, dbus_interface="org.veromix.notification", signal_name="card_remove") self.bus.add_signal_receiver(self.on_module_info, dbus_interface="org.veromix.notification", signal_name="module_info") def enable_mpris2(self): self.bus.add_signal_receiver(self.on_name_owner_changed, signal_name="NameOwnerChanged") def disable_mpris2(self): self.bus.remove_signal_receiver(self.on_name_owner_changed, signal_name="NameOwnerChanged") def on_name_owner_changed(self, val, val1=None, val2=None): if "org.mpris.MediaPlayer2" in val: if val in self.bus.list_names(): self.emit("mpris2_player_added", str(val), Mpris2MediaPlayerGtk(str(val), self)) else: self.emit("mpris2_player_removed", str(val), Mpris2MediaPlayerGtk(str(val), self)) def connect_mpris2_player(self, callback, name): self.bus.add_signal_receiver(callback, dbus_interface="org.freedesktop.DBus.Properties", signal_name="PropertiesChanged", bus_name=name) def disconnect_mpris2_player(self, callback, name): self.bus.remove_signal_receiver(callback, dbus_interface="org.freedesktop.DBus.Properties", signal_name="PropertiesChanged", bus_name=name) def get_mpris2_players(self): collection = [] for val in self.bus.list_names() : if "org.mpris.MediaPlayer2" in val: collection.append(Mpris2MediaPlayerGtk(str(val), self)) return collection def getMixer(self): pa_obj = self.bus.get_object("org.veromix.pulseaudio.glib","/org/veromix/pulseaudio") return dbus.Interface(pa_obj, 'org.veromix.pulseaudio') def get_mpris2_object(self, destination): return self.bus.get_object(destination, '/org/mpris/MediaPlayer2') def getNowPlaying(self, destination): pa_obj = self.get_mpris2_object(destination) return dbus.Interface(pa_obj, 'org.mpris.MediaPlayer2.Player') def getNowPlayingProperty(self, destination, name): pa_obj = self.get_mpris2_object(destination) props = dbus.Interface(pa_obj, 'org.freedesktop.DBus.Properties') return props.Get('org.mpris.MediaPlayer2.Player', name) def on_sink_input_info(self, index, name, muted, volume, props): sink = SinkInputInfo(self, index, name, muted, volume, props) self.emit("on_sink_input_info", sink) def on_sink_info(self, index, name, muted, volume, props, ports, active_port): sink = SinkInfo(self, index, name, muted, volume, props, ports, active_port) self.emit("on_sink_info", sink) def on_source_output_info(self, index, name, props): sink = SourceOutputInfo(self, index, name, True, {"left":0, "right":0}, props) self.emit("on_source_output_info", sink) def on_source_info(self, index, name, muted, volume, props, ports, active_port): sink = SourceInfo(self, index, name, muted, volume, props, ports, active_port) self.emit("on_source_info", sink) def on_sink_input_remove(self, index): self.emit("on_sink_input_remove", index) def on_sink_remove(self, index): self.emit("on_sink_remove", index) def on_source_remove(self, index): self.emit("on_source_remove", index) def on_source_output_remove(self, index): self.emit("on_source_output_remove", index) def on_volume_meter_sink_input(self, index, value): self.emit("on_volume_meter_sink_input", index, value) def on_volume_meter_sink(self, index, value): self.emit("on_volume_meter_sink", index, value) def on_volume_meter_source(self, index, value): self.emit("on_volume_meter_source", index, value) def on_card_info(self, index, name, properties, active_profile_name, profiles_dict): info = CardInfo(index, name, properties, active_profile_name, profiles_dict) self.emit("on_card_info", info) def on_card_remove(self, index): self.emit("on_card_remove", index) # calls def set_card_profile(self, index, value): self.getMixer().set_card_profile(index, value) def set_sink_input_volume(self, index, vol): try: self.getMixer().sink_input_volume(index,vol) except(Exception, e): print ("dbus connection not ready: ") def set_sink_input_mute(self, index, mute): self.getMixer().sink_input_mute(index,mute) def sink_input_kill(self, index): self.getMixer().sink_input_kill(index) def set_sink_volume(self, index, vol): self.getMixer().sink_volume(index,vol) def set_sink_mute(self, index, mute): self.getMixer().sink_mute(index,mute) def set_sink_port(self, index, portstr): self.getMixer().sink_port(index,portstr) def set_default_sink(self, index): self.getMixer().set_default_sink(index) def create_combined_sink(self, first_sink_index, second_sink_index): self.getMixer().create_combined_sink(int(first_sink_index), int(second_sink_index)) def set_source_volume(self, index, vol): self.getMixer().source_volume(index,vol) def set_source_mute(self, index, mute): self.getMixer().source_mute(index,mute) def set_source_port(self, index, portstr): self.getMixer().source_port(index,portstr) def set_default_source(self, index): self.getMixer().set_default_source(index) def move_sink_input(self, sink, output): self.getMixer().move_sink_input(sink, output) def move_source_output(self, sink, output): self.getMixer().move_source_output(sink, output) def toggle_monitor_of_sink(self, sink_index, named): self.getMixer().toggle_monitor_of_sink(sink_index, named) def toggle_monitor_of_sinkinput(self, sinkinput_index, sink_index, named): self.getMixer().toggle_monitor_of_sinkinput(sinkinput_index, sink_index, named) def toggle_monitor_of_source(self, source_index, named): self.getMixer().toggle_monitor_of_source(source_index, named) def set_ladspa_sink(self, sink_index, module_index, parameters): self.getMixer().set_ladspa_sink(sink_index, module_index, parameters) def remove_ladspa_sink(self, sink_index): self.getMixer().remove_ladspa_sink(sink_index) def remove_combined_sink(self, sink_index): self.getMixer().remove_combined_sink(sink_index) def on_module_info(self, index, name, argument, n_used, auto_unload): info = ModuleInfo(index, name, argument, n_used, auto_unload) self.emit("on_module_info",info) # FIXME def nowplaying_next(self, destination): self.getNowPlaying(str(destination)).Next() def nowplaying_prev(self, destination): self.getNowPlaying(str(destination)).Previous() def nowplaying_pause(self, destination): self.getNowPlaying(str(destination)).Pause() def nowplaying_play(self, destination): self.getNowPlaying(str(destination)).Play() def mpris2_get_position(self, destination): return self.getNowPlayingProperty(str(destination), "Position") def mpris2_set_position(self, destination, position): self.getNowPlaying(str(destination)).Seek(long(position)) def mpris2_get_metadata(self, destination): return self.getNowPlayingProperty(str(destination), "Metadata") def mpris2_get_playback_status(self, destination): return self.getNowPlayingProperty(str(destination), "PlaybackStatus") def requestInfo(self): try: self.getMixer().requestInfo() except(Exception, e): print ("dbus connection not ready: ", e) def set_autostart_meters(self, aboolean): self.getMixer().set_autostart_meters(aboolean) veromix/gtk/MuteButton.py0000644000175100017500000000500711766302605014322 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from gi.repository import Gtk, Gdk from gi.repository.GdkPixbuf import Pixbuf class MuteButton(Gtk.Fixed): ICON_HEIGHT = 36 def __init__(self): Gtk.Fixed.__init__(self) self._image_name = None self.image = Gtk.Image() self.muted_image = Gtk.Image() self.muted_image.set_from_icon_name("gtk-close", Gtk.IconSize.MENU) self.mute = Gtk.ToggleButton() self.mute.set_can_focus(False) self.mute.set_relief(Gtk.ReliefStyle.NONE) self.mute.set_image_position(1) self.mute.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [], Gdk.DragAction.COPY) self.mute.drag_source_add_text_targets() self.set_size_request(self.ICON_HEIGHT,self.ICON_HEIGHT) self.mute.set_size_request(self.ICON_HEIGHT,self.ICON_HEIGHT) self.put(self.mute, 0, 0) def set_active(self, aboolean): if aboolean: pos = self.ICON_HEIGHT - Gtk.icon_size_lookup(Gtk.IconSize.MENU)[1] if self.muted_image not in self.get_children(): self.put(self.muted_image, pos, pos) self.muted_image.show() else: if self.muted_image in self.get_children(): self.muted_image.hide() self.mute.set_active(aboolean) def set_image_name(self, name): if self._image_name != name: self.image.set_from_icon_name(name, Gtk.IconSize.BUTTON) self.mute.set_image(self.image) def connect_clicked(self, function): # 'clicked' would have the right behaviour for drag and drop but # it is also triggered when the state changes (via context-menu or external event) self.mute.connect("button-release-event", function) def connect_drag(self, function): self.mute.connect("drag-data-get", function) veromix/gtk/Veromix.py0000644000175100017500000001121411766302605013642 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from gi.repository import Gtk, Gdk from GPulseAudioProxy import PulseAudio from ContextMenu import ContextMenu from SortedChannelBox import SortedChannelBox from Configuration import config class Veromix(Gtk.VBox): def __init__(self, window, dbus): Gtk.VBox.__init__(self, window) self.window = window self.pa = PulseAudio(self, dbus) self.create_sinks() self.launch_pa() self.init_mpris2() def launch_pa(self): self.pa.connect_veromix_service() # FIXME: singleton initialization ContextMenu.get_instance(self) self.pa.connect("on_sink_info", self.sink_box.on_sink_info) self.pa.connect("on_sink_remove", self.sink_box.on_sink_remove) self.pa.connect("on_sink_input_info", self.sink_box.on_sink_input_info) self.pa.connect("on_sink_input_remove", self.sink_box.on_sink_remove) self.pa.connect("on_source_info", self.source_box.on_source_info) self.pa.connect("on_source_remove", self.source_box.on_sink_remove) self.pa.connect("on_source_output_info", self.source_box.on_source_output_info) self.pa.connect("on_source_output_remove", self.source_box.on_sink_remove) self.pa.connect("on_module_info", self.sink_box.on_module_info) self.pa.connect("on_volume_meter_sink", self.sink_box.on_volume_meter_sink) self.pa.connect("on_volume_meter_sink_input", self.sink_box.on_volume_meter_sink_input) self.pa.connect("on_volume_meter_source", self.source_box.on_volume_meter_source) self.pa.connect("mpris2_player_added", self.sink_box.on_media_player_added) self.pa.connect("mpris2_player_removed", self.sink_box.on_media_player_removed) self.pa.requestInfo() def init_mpris2(self): if not config().get_media_player_enabled(): return self self.pa.enable_mpris2() for controller in self.pa.get_mpris2_players(): v = controller.get_name() # if self.in_mediaplayer_blacklist(v): # return self.sink_box.on_media_player_added(None, controller.get_name(), controller) def create_sinks(self): self.veromix_sinks = Gtk.VBox() self.source_box = SortedChannelBox() self.veromix_sinks.pack_start(self.source_box, False, True, 0) self.source_box.connect("veromix-resize", self._do_resize) self.sink_box = SortedChannelBox() self.veromix_sinks.pack_start(self.sink_box, False, True, 0) self.sink_box.connect("veromix-resize", self._do_resize) spacer = Gtk.HBox() self.veromix_sinks.pack_start(spacer,True,True,0) self.scroll = Gtk.ScrolledWindow(hadjustment=None, vadjustment=None) self.scroll.set_policy(1, 1) self.scroll.add_with_viewport(self.veromix_sinks) self.scroll.set_border_width(5) # self.expander = Gtk.Expander(label="Outputs") # self.expander.set_expanded(True) # self.expander.add(self.scroll) # self.pack_start(self.expander, True, True, 0) self.pack_start(self.scroll, True, True, 0) def get_default_sink(self): return self.sink_box.get_default_sink() def get_sink_widgets(self): return self.sink_box.get_sinks() def pa_proxy(self): return self.pa def query_application(self, app_info, default_icon=None): # FIXME return default_icon def _do_resize(self, event): previous_policy = self.scroll.get_policy() # Disable scrolling: self.scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER) # See what changed: desired = self.scroll.size_request() toplevel = self.scroll.get_toplevel() new_size = toplevel.size_request() # Reenable scrolling: self.scroll.set_policy(*previous_policy) default_size = self.window.get_default_size() self.window.resize(max(new_size.width, default_size[0]), max(new_size.height, default_size[1])) veromix/gtk/SortedChannelBox.py0000644000175100017500000001651111766302605015420 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from gi.repository import Gtk, GObject from Channel import SinkChannel from Channel import SinkInputChannel from Channel import SourceChannel from Channel import SourceOutputChannel from Channel import LadspaChannel from Channel import MediaPlayerChannel class SortedChannelBox(Gtk.VBox): CHANNEL_PADDING = 2 __gsignals__ = { 'veromix-resize': (GObject.SIGNAL_RUN_FIRST, None, (),), } def __init__(self): Gtk.VBox.__init__(self) self.set_border_width(4) self.channels = {} def on_sink_remove(self, data, index): if int(index) in self.channels.keys(): self.remove(self.channels[index]) del self.channels[index] self.order_items() self.check_resize() def on_sink_info(self, widget, data): channel = None if data.get_index() not in self.channels.keys(): if "device.ladspa.module" in data.properties().keys(): channel = LadspaChannel() else: channel = SinkChannel() self._add_channel_widget(channel,data) def on_sink_input_info(self, widget, data): channel = None if data.get_index() not in self.channels.keys(): channel = SinkInputChannel() self._add_channel_widget(channel, data) def on_source_info(self, widget, data): channel = None if data.get_index() not in self.channels.keys(): channel = SourceChannel() self._add_channel_widget(channel,data) def on_source_output_info(self, widget, data): channel = None if data.get_index() not in self.channels.keys(): channel = SourceOutputChannel() self._add_channel_widget(channel,data) def on_module_info(self, widget, data): for widget in self.channels.values(): if widget.pa_sink_proxy(): module = widget.pa_sink_proxy().get_owner_module() if module: if module == str(data.get_index()): widget.on_pa_module_data_updated(data) self.emit('veromix-resize') def on_volume_meter_sink(self, widget, index, value): for sink in self.get_sinks(): if sink.pa_sink_proxy().get_index() == index: sink.slider.on_volume_meter_data(value) def on_volume_meter_sink_input(self, widget, index, value): for sink in self.get_sink_inputs(): if sink.pa_sink_proxy().get_index() == index: sink.slider.on_volume_meter_data(value) def on_volume_meter_source(self, widget, index, value): # FIXME for sink in self.channels.values(): if sink.pa_sink_proxy().get_index() == index: sink.slider.on_volume_meter_data(value) def on_media_player_added(self, widget, string, obj): channel = MediaPlayerChannel(string,obj) self._add_channel_widget(channel,obj) def on_media_player_removed(self, widget, string, obj): if string in self.channels.keys(): self.remove(self.channels[string]) del self.channels[string] self.order_items() self.check_resize() def _add_channel_widget(self, channel, data): if data.get_index() not in self.channels.keys(): self.channels[data.get_index()] = channel self.pack_start(channel, True, True, self.CHANNEL_PADDING) self.show_all() self.channels[data.get_index()].on_pa_data_updated(data) self.order_items() ## def order_items(self): while(self.needs_ordering()): self._order_items() self.emit('veromix-resize') def needs_ordering(self): sorting = self._sort() if len(sorting) != len(self.get_children()): return False for i in range(0,len(sorting)): if self.get_children()[i] != sorting[i]: return True return False def get_sources(self): return list(filter(lambda channel: channel.pa_sink_proxy().is_source(), self.channels.values())) def get_sinks(self): return list(filter(lambda channel: channel.pa_sink_proxy().is_sink(), self.channels.values())) def get_default_sink(self): if len(self.channels.values()) == 0: return None collection = list(filter(lambda channel: channel.pa_sink_proxy().is_default(), self.channels.values())) if len(collection) == 0: return list(self.channels.values())[0] return collection[0] def get_sink_inputs(self): return list(filter(lambda channel: channel.pa_sink_proxy().is_sinkinput(), self.channels.values())) def get_media_players(self): return list(filter(lambda channel: channel.pa_sink_proxy().is_media_player(), self.channels.values())) def _order_items(self): sorting = self._sort() for i in range(0,len(sorting)): if self.get_children()[i] != sorting[i]: self.reorder_child(self.get_children()[i], sorting.index(self.get_children()[i])) return def _sort(self): sources = [] #self._sort_by_attribute(self._get_source_widgets(objects), '_name') sourceoutputs = [] # self._sort_by_attribute(self._get_sinkoutput_widgets(objects), '_name') sinks = self._sort_by_attribute(self.get_sinks()) sink_inputs = self._sort_by_attribute(self.get_sink_inputs()) mediaplayers = self._sort_by_attribute(self.get_media_players()) # self._sort_by_attribute(self._get_mediaplayer_widgets(objects), '_name') sorting = [] for s in sinks: if s.pa_sink_proxy().is_default_sink(): sinks.remove(s) sinks.insert(0,s) for s in sourceoutputs: sorting.append(s) for so in sources: if int(s.index) == int(so.get_assotiated_source()): sorting.append(so) #sinks.reverse() for s in sinks: sorting.append(s) for i in sink_inputs: if s.pa_sink_proxy().get_index() == i.pa_sink_proxy().get_output_index(): sorting.append(i) # FIXME for m in mediaplayers: assoc = m.pa_sink_proxy().get_assotiated_sink_input(sink_inputs) if assoc != None and int(i.pa_sink_proxy().get_index()) == assoc.pa_sink_proxy().get_index(): sorting.append(m) # FIXME #for i in set(objects).difference(set(sorting)): #sorting.append(i) return sorting def _sort_by_attribute(self, objects): return sorted(objects, key = lambda x: x.pa_sink_proxy()._nice_title) veromix/gtk/main.py0000755000175100017500000000660111766302605013144 0ustar nikkibu#!/usr/bin/python3 # -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ## # python3-gi python3-dbus ## import os, gettext, dbus, dbus.service from gi.repository import Gtk, Gdk from gettext import gettext as i18n from Veromix import Veromix from Indicator import Indicator from Configuration import config from veromixcommon.Utils import createDbusServiceDescription from veromixcommon.LADSPAEffects import LADSPAPresetLoader DBUS_INTERFACE = "org.veromix.gtkfrontend" VEROMIX_BASEDIR = os.path.abspath(os.path.join(os.path.realpath(__file__), os.path.pardir)) VEROMIX_BASEDIR = os.path.abspath(os.path.join(VEROMIX_BASEDIR, os.path.pardir)) VEROMIX_SERVICE = "/dbus-service/veromix-service-glib.py" class VeromixWindow(dbus.service.Object): def __init__(self, bus): dbus.service.Object.__init__ (self, bus, "/", DBUS_INTERFACE) self.window = Gtk.Window(title=i18n("Veromix"),type =Gtk.WindowType.TOPLEVEL) self.window.set_icon_name("veromix") self.window.connect('delete-event', self.on_delete_event) self.window.set_default_size(430, 180) veromix = Veromix(self.window, bus) self.window.add(veromix) self.create_indicator(veromix) self.window.show_all() @dbus.service.method (DBUS_INTERFACE, in_signature='', out_signature='') def show_window(self): self.window.present() def on_delete_event(self, widget, event): if config().get_window_exit_on_close(): Gtk.main_quit() self.window.hide() return True def create_indicator(self, veromix): self.tray_icon = Indicator(veromix) def init_locales(): name = "veromix" directory = VEROMIX_BASEDIR + "/data/locale" if "usr/share/veromix" in VEROMIX_BASEDIR: directory = "/usr/share/locale" gettext.bindtextdomain(name, directory) gettext.textdomain(name) if __name__ == '__main__': # Veromix is dedicated to my girlfriend Véronique init_locales() Gdk.set_program_class("veromix") if not dbus.get_default_main_loop(): mainloop=dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) else: mainloop=dbus.mainloop.glib.DBusGMainLoop(set_as_default=False) bus = dbus.SessionBus() request = bus.request_name (DBUS_INTERFACE, dbus.bus.NAME_FLAG_DO_NOT_QUEUE) if request == dbus.bus.REQUEST_NAME_REPLY_EXISTS: obj = bus.get_object (DBUS_INTERFACE, "/") app = dbus.Interface (obj, DBUS_INTERFACE) app.show_window() Gdk.notify_startup_complete() else: createDbusServiceDescription(VEROMIX_BASEDIR + VEROMIX_SERVICE, False) LADSPAPresetLoader().install_ladspa_presets_if_needed() win = VeromixWindow(bus) win.show_window() Gtk.main() config().save() veromix/gtk/Configuration.py0000644000175100017500000000444011766302605015023 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os, configparser from veromixcommon.Utils import _XDG_CONFIG_DIR, createDirectory __config_instance = None def config(): global __config_instance if __config_instance == None: __config_instance = VeromixConfiguration() return __config_instance class VeromixConfiguration: _FILENAME = _XDG_CONFIG_DIR + "/veromix.conf" def __init__(self): self.section = 'UI' self._load() def _load(self): self._config = configparser.ConfigParser() self._config[self.section] = {} if os.path.exists(self._FILENAME): self._config.read(self._FILENAME) if len(self._config.sections()) == 0: self._config[self.section] = {} def save(self): createDirectory(_XDG_CONFIG_DIR) with open(self._FILENAME, 'w') as configfile: self._config.write(configfile) def _get(self, key, default): if key not in self._config[self.section]: self._config[self.section][key] = str(default) if type(default) == bool: return self._config[self.section].getboolean(key) if type(default) == int: return self._config[self.section].getint(key) return self._config[self.section][key] def get_window_exit_on_close(self): return self._get('exit_on_close', True) def get_indicator_type(self): self._config[self.section]['#indicator_type'] = 'None|GtkStatusIcon|AppIndicator' return self._get('indicator_type', 'AppIndicator') def get_media_player_enabled(self): return self._get('media_player_enable', True) veromix/gtk/Channel.py0000644000175100017500000002145311766302605013567 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import re from gi.repository import Gtk, Gdk from gi.repository.GdkPixbuf import Pixbuf from SliderWidget import SliderWidget from LadspaWidget import LadspaWidget from ContextMenu import ContextMenu from MuteButton import MuteButton from veromixcommon.MediaPlayer import MediaPlayer DRAG_ACTION = Gdk.DragAction.COPY (TARGET_ENTRY_TEXT, TARGET_ENTRY_PIXBUF) = range(2) class Channel(Gtk.Alignment): ICON_HEIGHT = 36 def __init__(self): Gtk.Alignment.__init__(self) #self.set_homogeneous(False) self._init() self.set_size_request(self.ICON_HEIGHT, self.ICON_HEIGHT) def _init(self): self.frame = Gtk.Frame() self.hbox = Gtk.HBox() self._create() self._pack_contents() self._pack_frame() def _pack_contents(self): self.mute_box.pack_start(self.mute, False, True, 2) self.mute_box.pack_start(Gtk.HBox(), True, True, 0) self.menu_box.pack_start(self.menu_button, False, True, 2) self.menu_box.pack_start(Gtk.HBox(), True, True, 0) self.hbox.pack_start(self.mute_box, False, True, 2) self.hbox.pack_start(self.slider,True,True,5) self.hbox.pack_start(self.menu_box,False,False, 2) def _pack_frame(self): self.frame.add(self.hbox) self.add(self.frame) self.connect("button-press-event", self.on_button_press_event) def _create(self): self._create_mute() self._create_slider() self._create_menu_button() def _create_menu_button(self): self.menu_box=Gtk.VBox() self.menu_button = Gtk.ToggleButton() self.menu_button.set_relief(Gtk.ReliefStyle.NONE) self.menu_button.set_can_focus(False) self.menu_button.add(Gtk.Arrow(Gtk.ArrowType.DOWN, Gtk.ShadowType.NONE)) self.menu_button.connect("released", self.show_popupmenu) self.menu_button.set_size_request(-1, self.ICON_HEIGHT) def on_menu_button_released(self, widget): self.menu_button.set_active(False) def _create_mute(self): self.mute_box = Gtk.VBox() self.mute = MuteButton() self.mute.connect_clicked(self.on_mute_clicked) def _create_slider(self): self.slider = SliderWidget() def show_popupmenu(self, widget, button=0, time=0): self.menu = Gtk.Menu() self.menu.connect("selection-done", self.on_menu_button_released) instance = ContextMenu.get_instance() instance.populate_menu(self.pa_sink_proxy(), self.menu, self.slider) self.menu.show_all() self.menu.popup(None, None, None, None, 0, 0) return False def on_button_press_event(self, widget, event): if (event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3): self.show_popupmenu(event.button, event.time) return True # event has been handled def on_mute_clicked(self, button, event): # catch drag and drop: if (Gdk.EventType.BUTTON_RELEASE and (event.x != 0.0 and event.y != 0.0)): self.pa_sink_proxy().toggle_mute() return True return False def pa_sink_proxy(self): return self._pa_sink def on_pa_data_updated(self, data): self._pa_sink = data self.slider.set_volume(data) self.mute.set_active(data.isMuted()) self.mute.set_image_name(data.get_nice_icon()) def step_volume(self, up): self.slider.step_volume(up) def toggle_mute(self): self.pa_sink_proxy().toggle_mute() def on_pa_module_data_updated(self, data): pass class SinkChannel(Channel): def _init(self): Channel._init(self) self.drag_dest_set(Gtk.DestDefaults.ALL, [], DRAG_ACTION) self.drag_dest_add_text_targets() self.connect("drag-data-received", self.on_drag_data_received) def on_drag_data_received(self, widget, drag_context, x, y, data, info, time): if info == TARGET_ENTRY_TEXT: match = re.match("veromix://sink_input_index:(\d*)", data.get_text()) if match: self.pa_sink_proxy().move_sink_input(match.group(1)) class SinkInputChannel(Channel): def _init(self): Channel._init(self) self.set_padding(0, 0, self.ICON_HEIGHT / 2, 0) self.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [], DRAG_ACTION) self.drag_source_add_text_targets() self.connect("drag-data-get", self.on_drag_data_get) self.mute.connect_drag(self.on_drag_data_get) def on_drag_data_get(self, widget, drag_context, data, info, time): data.set_text("veromix://sink_input_index:"+str(self.pa_sink_proxy().get_index()), -1) class SourceChannel(Channel): def _init(self): Channel._init(self) class SourceOutputChannel(Channel): def _init(self): Channel._init(self) self.set_padding(0, 0, self.ICON_HEIGHT / 2, 0) class LadspaChannel(SinkChannel): def _create_slider(self): self.slider = LadspaWidget() def on_pa_module_data_updated(self, data): self.slider.on_pa_module_data_updated(data, self.pa_sink_proxy()) class MediaPlayerChannel(Channel): def __init__(self,name, controller): Channel.__init__(self) self._pa_sink = controller self.controller = controller self.controller.connect("data_updated", self.controller_data_updated) self.controller_data_updated(None) self.set_padding(0, 0, self.ICON_HEIGHT / 2, 0) def controller_data_updated(self, widget): if self.controller.state() == MediaPlayer.Playing: self.play.set_from_icon_name("player_stop", Gtk.IconSize.BUTTON) else: self.play.set_from_icon_name("player_play", Gtk.IconSize.BUTTON) p = self.controller.artwork() if p: q = p.get_pixbuf().scale_simple(self.ICON_HEIGHT * 2, self.ICON_HEIGHT * 2, 0) self.cover.set_from_pixbuf(q) else: self.cover.set_from_icon_name(self.controller.get_application_name(), Gtk.IconSize.DND) def on_pa_data_updated(self, data): pass def _pack_contents(self): prev_box = Gtk.VBox() prev_box.pack_start(Gtk.HBox(), True,True, 0) prev_box.pack_start(self.prev, False,False, 0) next_box = Gtk.VBox() next_box.pack_start(Gtk.HBox(), True,True, 0) next_box.pack_start(self.next, False,False, 0) self.hbox.pack_start(Gtk.HBox(), True, True, 0) self.hbox.pack_start(prev_box, False,False, 0) self.hbox.pack_start(self.event_box, False,False, 0) self.hbox.pack_start(next_box, False,False, 0) self.hbox.pack_start(Gtk.HBox(), True, True, 0) def _create(self): self.cover = Gtk.Image() self.cover.set_size_request(self.ICON_HEIGHT * 2, self.ICON_HEIGHT * 2) self.play = Gtk.Image() self.play.set_size_request(self.ICON_HEIGHT, self.ICON_HEIGHT) self.play.set_from_icon_name("player_stop", Gtk.IconSize.BUTTON) self.prev = self._create_button("player_rew", self.on_prev_clicked) self.next = self._create_button("player_fwd", self.on_next_clicked) self.fixed = Gtk.Fixed() self.fixed.add(self.cover) self.fixed.put(self.play, int(self.ICON_HEIGHT/2), self.ICON_HEIGHT) self.event_box = Gtk.EventBox() self.event_box.add(self.fixed) self.event_box.show_all() self.event_box.connect("button_press_event", self.on_play_clicked) def _create_button(self, image_name, callback): button = Gtk.Button() button.set_relief(Gtk.ReliefStyle.NONE) button.set_can_focus(False) img = Gtk.Image() img.set_from_icon_name(image_name, Gtk.IconSize.BUTTON) button.set_image(img) button.set_size_request(self.ICON_HEIGHT,self.ICON_HEIGHT) button.connect("clicked", callback) return button def on_play_clicked(self, widget, data): if self.controller.state() == MediaPlayer.Playing: self.controller.pause() else: self.controller.play() def on_prev_clicked(self, widget): self.controller.prev_track() def on_next_clicked(self, widget): self.controller.next_track() veromix/gtk/SliderWidget.py0000644000175100017500000002256611766302605014613 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import re, urllib.parse from gi.repository import Gtk, Gdk from veromixcommon.LADSPAEffects import * DRAG_ACTION = Gdk.DragAction.COPY (TARGET_ENTRY_TEXT, TARGET_ENTRY_PIXBUF) = range(2) class AbstractLabelSlider: # FIXME SLIDER_HEIGHT = 36 def __init__(self): self.MAX_VOLUME = 100 self.STEP_SIZE = -5 self.slider_hidden = False self._create_label() self._create_slider() self._signal_handler = None def connect_value_changed(self, target): self._signal_handler = self.slider.connect("change-value", target) def disconnect_value_changed(self): if self._signal_handler: self.slider.disconnect(self._signal_handler) def _create_slider(self): self.slider = Gtk.HScale() self.slider.set_can_focus(False) #self.slider.set_slider_size_fixed(True) self.slider.set_draw_value(False) self.slider.set_value_pos(1) self.slider.set_range(0, self.MAX_VOLUME) self.slider.set_value(0) self.slider.set_increments(0, self.STEP_SIZE) self.slider.set_restrict_to_fill_level(False) self.slider.set_size_request(-1, self.SLIDER_HEIGHT) def _create_label(self): self.label = Gtk.Label() self.layout = self.label.get_layout() self.label.set_markup("Initialgg") self.label.set_alignment(xalign=0, yalign=0) self.label.set_size_request(-1, self.SLIDER_HEIGHT) #def show_slider_value(self): #self.slider.set_draw_value(True) #self.slider.set_value_pos(1) def set_volume(self, volume): self.slider.set_value(volume) def set_range(self, amin, amax): self.slider.set_range(amin, amax) def get_volume(self): return self.slider.get_value() def set_markup(self, markup): self.label.set_markup(markup) def hide_slider(self): if not self.slider_hidden: self.slider.unmap() self.slider_hidden = True def set_meter(self, value): self.slider.set_fill_level(value) def set_show_fill_level(self, value): if self.slider.get_show_fill_level() != value: self.slider.set_show_fill_level(value) self.slider.set_fill_level(0) class LabelSlider(Gtk.Fixed, AbstractLabelSlider): def __init__(self): Gtk.Fixed.__init__(self) AbstractLabelSlider.__init__(self) self.init_layout() self.connect('size-allocate', self.on_resize) def init_layout(self): self.put(self.label,0,3) self.put(self.slider, 0, 0) def on_resize(self, widget, event): if event: # set position of slider event.y = event.y + self.label.get_layout().get_pixel_size()[1] * 0.4 self.slider.size_allocate(event) class VerticalLabelSlider(Gtk.HBox, AbstractLabelSlider): def __init__(self): Gtk.HBox.__init__(self) AbstractLabelSlider.__init__(self) self.init_layout() def init_layout(self): align = Gtk.Alignment() align.set_padding(20, 5, 0, 0) align.add(self.label) self.pack_start(align, False, False, 0) self.pack_start(self.slider, False, False, 0) def _create_label(self): LabelSlider._create_label(self) self.label.set_angle(90) def _create_slider(self): self.slider = Gtk.VScale() self.slider.set_can_focus(False) self.slider.set_draw_value(False) self.slider.set_value_pos(1) self.slider.set_range(0, self.MAX_VOLUME) self.slider.set_value(0) self.slider.set_increments(0, -1 * self.STEP_SIZE) self.slider.set_inverted(True) class SliderWidget(Gtk.VBox): def __init__(self): Gtk.VBox.__init__(self) self.set_border_width(0) self._pa_sink_proxy = None self.sliders = [] self.label = None self.EXPAND_CHANNELS = False def add_sliders(self, sink): if self.EXPAND_CHANNELS: self.create_sliders(sink) else: self.create_slider(sink) self.show_all() def remove_sliders(self, sink): for slider in self.sliders: slider.disconnect_value_changed() self.remove(slider) del slider self.sliders = [] def create_label(self, sink): self.label_box = Gtk.EventBox() self.label = Gtk.Label() self.label_box.add(self.label) self.label.set_alignment(xalign=0, yalign=1) def create_slider(self, sink): if self.label: self.remove(self.label_box) del self.label self.label = None slider = self._create_slider(sink.get_nice_title_and_name()) slider.connect_value_changed(self.on_slider_value_changed) def create_sliders(self, sink): self.create_label(sink) self.pack_start(self.label_box, False, False, 0) for channel in sink.getChannels(): slider = self._create_slider("" + channel.get_name() + "") slider.connect_value_changed(self.on_sliders_value_changed) def _create_slider(self, title): slider = LabelSlider() slider.set_markup(title) self.sliders.append(slider) self.pack_start(slider, False, False, 0) size = slider.label.get_layout().get_pixel_size() slider.set_size_request(-1, size[1] * 2) return slider def pa_sink_proxy(self): return self._pa_sink_proxy def on_volume_meter_data(self, value): if len(self.sliders) > 0: self.sliders[0].set_meter(value) def set_volume(self, pa_sink_proxy): self._pa_sink_proxy = pa_sink_proxy nr_channels = len(pa_sink_proxy.getChannels()) if self.EXPAND_CHANNELS and nr_channels > 1: self.set_slider_values(pa_sink_proxy) self.label.set_markup(pa_sink_proxy.get_nice_title_and_name()) self.sliders[0].set_show_fill_level(pa_sink_proxy.has_monitor()) else: if len(self.sliders) != 1: self.remove_sliders(pa_sink_proxy) self.add_sliders(pa_sink_proxy) if len(self.sliders) > 0: if nr_channels > 0: self.sliders[0].set_volume(pa_sink_proxy.get_volume()) self.sliders[0].set_show_fill_level(pa_sink_proxy.has_monitor()) if nr_channels == 0: self.sliders[0].hide_slider() self.sliders[0].set_markup(pa_sink_proxy.get_nice_title_and_name()) def set_slider_values(self, sink): channels = sink.getChannels() if len(channels) != len(self.sliders): self.remove_sliders(sink) self.add_sliders(sink) for i in range(0,len(channels)): self.sliders[i].set_markup(channels[i].get_name()) #sink.get_nice_title_and_name()) self.sliders[i].set_volume(channels[i].get_volume()) def is_expanded(self): return self.EXPAND_CHANNELS def expand(self, boolean): self.EXPAND_CHANNELS = boolean self.set_volume(self._pa_sink_proxy) def step_volume(self, up): # self.pa_sink_proxy().step_volume_by(self.STEP_SIZE, up) ## FIXME self.pa_sink_proxy().step_volume_by(5, up) def on_slider_value_changed(self, slider, scrolltype, value): vol = self.pa_sink_proxy().volumeDiffFor(value) self.pa_sink_proxy().set_volume(vol) return True def on_sliders_value_changed(self, slider, scrolltype, value): vol = [] for slider in self.sliders: vol.append(slider.get_volume()) self.pa_sink_proxy().set_volume(vol) return False def on_pa_module_data_updated(self, data): pass def get_selected_preset(self): return None def get_selected_effect(self): return None def is_ladspa(self): return False def get_ladspa_master(self): return self.pa_sink_proxy().get_ladspa_master() def set_ladspa_effect(self, value, master): parameters = "" preset = None for p in LADSPAEffects().effects(): if p["preset_name"] == value: parameters = "sink_name=" + urllib.parse.quote(p["name"]) preset = p for p in LADSPAPresetLoader().presets(): if p["preset_name"] == value: parameters = "sink_name=" + urllib.parse.quote(p["preset_name"]) preset = p parameters = parameters + " master=" + master + " " parameters = parameters + " plugin=" + preset["plugin"] parameters = parameters + " label=" + preset["label"] parameters = parameters + " control=" + preset["control"] self.pa_sink_proxy().set_ladspa_sink(parameters) veromix/gtk/ContextMenu.py0000644000175100017500000003302611766302605014467 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gettext, dbus from gettext import gettext as i18n from gi.repository import Gtk from gi.repository import GObject from veromixcommon.LADSPAEffects import LADSPAPresetLoader from veromixcommon.LADSPAEffects import LADSPAEffects _instance = None class ContextMenu: def get_instance(pa_proxy=None): global _instance if _instance == None: _instance = ContextMenuFactory(pa_proxy) return _instance class ContextMenuFactory(GObject.GObject): def __init__(self, veromix): GObject.GObject.__init__(self) self.card_infos = {} self.card_settings = {} self.port_actions = {} self.menus = [] self.profiles = [] self.veromix = veromix self._pa_proxy = veromix.pa_proxy() self._pa_proxy.connect("on_card_info", self.on_card_info) self._pa_proxy.connect("on_card_remove", self.on_remove_card) def populate_menu(self, pa_sink_proxy, menu, slider): if pa_sink_proxy.is_sinkinput(): self.create_menu_sinks(pa_sink_proxy, menu) if slider.is_ladspa(): self.context_menu_create_presets(slider, menu) self.context_menu_create_effects(slider, menu) if pa_sink_proxy.is_sink(): self.context_menu_create_ports(pa_sink_proxy, menu) self.context_menu_create_sounddevices(pa_sink_proxy, menu) self.context_menu_create_defaultsink(pa_sink_proxy, menu) self.context_menu_create_mute(pa_sink_proxy, menu) if not slider.is_ladspa() and not pa_sink_proxy.is_sourceoutput(): self.context_menu_create_expand(slider, menu) self.context_menu_create_volume_meter(pa_sink_proxy, menu) if pa_sink_proxy.is_sinkinput() or slider.is_ladspa(): self.context_menu_create_kill(pa_sink_proxy, menu) if pa_sink_proxy.is_sink() and not slider.is_ladspa(): self.context_menu_create_presets_and_effects(slider, menu) self.context_menu_create_sounddevices_other(menu) # ---- helper methods def on_card_info(self, widget, info): self.card_infos[info.name] = info def on_remove_card(self, widget, index): for key in self.card_infos.keys(): card = self.card_infos[key] if int(card.index) == int(index): del self.card_infos[key] def on_defaultsink_clicked(self, widget, sink): sink.be_default_sink() def on_mute_clicked(self, widget, sink): sink.toggle_mute() def on_volume_meter_clicked(self, widget, proxy): proxy.toggle_monitor() def on_kill_clicked(self, widget, sink): sink.kill() def on_expand_clicked(self, widget, slider_widget): slider_widget.expand(widget.get_active()) def on_card_profile_clicked(self, widget, sink): if widget in self.card_settings.keys(): card = self.card_settings[widget] for profile in card.get_profiles(): if widget.get_label() == profile.description: self._pa_proxy.set_card_profile(card.index, profile.name) def on_moveto_sink_clicked(self, widget, sinkinput): self.sink_actions[widget].move_sink_input(sinkinput.get_index()) def on_card_port_clicked(self, widget, sink): sink.set_port(self.port_actions[widget]) def context_menu_create_defaultsink(self, sink, popup_menu): item = Gtk.CheckMenuItem() item.set_active(sink.is_default()) item.set_label(i18n("Default device")) item.connect("activate", self.on_defaultsink_clicked, sink) popup_menu.append(item) def context_menu_create_kill(self, sink, popup_menu): item = Gtk.MenuItem() item.set_label(i18n("Disconnect/kill")) item.connect("activate", self.on_kill_clicked, sink) popup_menu.append(item) def context_menu_create_mute(self, sink, popup_menu): item = Gtk.CheckMenuItem() item.set_active(sink.isMuted()) #item.set_draw_as_radio(True) item.set_label(i18n("Mute")) item.connect("activate", self.on_mute_clicked, sink) popup_menu.append(item) def context_menu_create_volume_meter(self, sink, popup_menu): item = Gtk.CheckMenuItem() item.set_active(sink.has_monitor()) #item.set_draw_as_radio(True) item.set_label(i18n("Volume meter")) item.connect("activate", self.on_volume_meter_clicked, sink) popup_menu.append(item) def context_menu_create_expand(self, slider_widget, popup_menu): item = Gtk.CheckMenuItem() #item.set_draw_as_radio(True) item.set_label(i18n("Unlock Channels")) item.set_active(slider_widget.is_expanded()) item.connect("activate", self.on_expand_clicked, slider_widget) popup_menu.append(item) def create_menu_sinks(self, proxy, popup_menu): moveto_menu = Gtk.Menu() moveto_menu_item = Gtk.MenuItem(i18n("Move To")) moveto_menu_item.set_submenu(moveto_menu) self.sink_actions = {} sinks = self.veromix.get_sink_widgets() for sink in sinks: action = Gtk.CheckMenuItem() action.set_draw_as_radio(True) action.set_label(sink.pa_sink_proxy().get_nice_title()) self.sink_actions[action] = sink.pa_sink_proxy() if proxy.get_output_index() == sink.pa_sink_proxy().get_index(): action.set_active(True) moveto_menu.append(action) action.connect("activate", self.on_moveto_sink_clicked, proxy) popup_menu.append(moveto_menu_item) def context_menu_create_ports(self, sink, popup_menu): self.port_actions = {} if len(sink.ports.keys()) > 1: ports_menu = Gtk.Menu() ports_menu_item = Gtk.MenuItem(i18n("Ports")) ports_menu_item.set_submenu(ports_menu) ports = sink.ports for port in ports.keys(): action = Gtk.CheckMenuItem() action.set_draw_as_radio(True) action.set_label(ports[port]) self.port_actions[action]=port if port == sink.active_port: action.set_active(True) ports_menu.append(action) action.connect("activate", self.on_card_port_clicked, sink) popup_menu.append(ports_menu_item) def context_menu_create_sounddevices(self, sink, popup_menu): self.card_settings = {} self.menus = [] for card in self.card_infos.values(): current = self.get_card_info_for(sink) card_menu = None if current != None and current.get_description() == card.get_description(): card_menu = Gtk.Menu() card_menu_item = Gtk.MenuItem() card_menu_item.set_label(i18n("Profile")) card_menu_item.set_submenu(card_menu) popup_menu.append(card_menu_item) else: card_menu = Gtk.Menu() card_menu_item = Gtk.MenuItem() card_menu_item.set_label(card.get_description()) card_menu_item.set_submenu(card_menu) self.menus.append(card_menu_item) active_profile_name = card.get_active_profile_name() self.profiles = card.get_profiles() for profile in self.profiles: action = Gtk.CheckMenuItem() action.set_draw_as_radio(True) action.set_label(profile.description) self.card_settings[action] = card if profile.name == active_profile_name: action.set_active(True) action.connect("activate", self.on_card_profile_clicked, sink) card_menu.append(action) def context_menu_create_sounddevices_other(self, popup_menu): if len(self.menus) > 0: s = Gtk.SeparatorMenuItem() popup_menu.append(s) for each in self.menus: popup_menu.append(each) def get_card_info_for(self, sink): card_identifier = dbus.String('alsa.long_card_name') #u'sysfs.path' info = self._get_card_info_for(sink, card_identifier) if info: return info card_identifier = dbus.String('device.string') info = self._get_card_info_for(sink, card_identifier) if info: return info card_identifier = dbus.String('sysfs.path') return self._get_card_info_for(sink, card_identifier) def _get_card_info_for(self, sink, card_identifier): if sink == None: return None if card_identifier not in sink.props.keys(): return None for info in self.card_infos.values(): if card_identifier in info.properties.keys(): if info.properties[dbus.String(card_identifier)] == sink.props[card_identifier]: return info return None def context_menu_create_presets_and_effects(self, sink, popup_menu): effects_menu = Gtk.Menu() effects_menu_item = Gtk.MenuItem() effects_menu_item.set_label(i18n("Add Effect")) effects_menu_item.set_submenu(effects_menu) popup_menu.append(effects_menu_item) self.context_menu_create_presets(sink, effects_menu) self.context_menu_create_effects(sink, effects_menu) def context_menu_create_presets(self, slider, popup_menu): presets_menu = Gtk.Menu() presets_menu_item = Gtk.MenuItem() presets_menu_item.set_label(i18n("Preset")) presets_menu_item.set_submenu(presets_menu) popup_menu.append(presets_menu_item) if slider.is_ladspa(): if slider.module_proxy.is_ladspa_preset(): save = Gtk.MenuItem() save.set_label(i18n("Save")) presets_menu.append(save) save.connect("activate", self.on_save_preset_clicked) saveas = Gtk.MenuItem() saveas.set_label(i18n("Save As...")) presets_menu.append(saveas) saveas.connect("activate", self.on_save_as_preset_clicked) separator = Gtk.SeparatorMenuItem() presets_menu.append(separator) self.presets_slider = slider for preset in LADSPAPresetLoader().presets(): action = Gtk.CheckMenuItem() action.set_draw_as_radio(True) action.set_label(preset["preset_name"]) presets_menu.append(action) if slider.get_selected_preset() == preset["preset_name"]: action.set_active(True) action.connect("activate", self.on_preset_clicked, preset) def context_menu_create_effects(self, slider, popup_menu): effects_menu = Gtk.Menu() effects_menu_item = Gtk.MenuItem() effects_menu_item.set_label(i18n("Effect")) effects_menu_item.set_submenu(effects_menu) popup_menu.append(effects_menu_item) self.effect_slider = slider for preset in LADSPAEffects().effects(): action = Gtk.CheckMenuItem() action.set_draw_as_radio(True) action.set_label(preset["preset_name"]) effects_menu.append(action) if slider.get_selected_effect() == preset["label"]: action.set_active(True) action.connect("activate", self.on_effect_clicked, preset) def on_preset_clicked(self, widget, preset): self.presets_slider.set_ladspa_effect(preset["preset_name"], self.presets_slider.get_ladspa_master()) def on_effect_clicked(self, widget, preset): self.effect_slider.set_ladspa_effect(preset["preset_name"], self.effect_slider.get_ladspa_master()) def on_save_preset_clicked(self, widget): self.effect_slider.save_preset(None) def on_save_as_preset_clicked(self, widget): dialog = SavePresetsDialog(self.veromix.window) response = dialog.run() text = dialog.get_text() if response == Gtk.ResponseType.OK: self.effect_slider.save_preset(text) dialog.destroy() class SavePresetsDialog(Gtk.MessageDialog): def __init__(self, parent): Gtk.MessageDialog.__init__(self, 0, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK_CANCEL, i18n("Save Preset")) self.set_markup('Please enter a name for the preset:') self.entry = Gtk.Entry() self.entry.connect("activate", self.save_and_close, self, Gtk.ResponseType.OK) hbox = Gtk.HBox() hbox.pack_start(Gtk.Label("Name:"), False, 5, 5) hbox.pack_end(self.entry, True, 5, 5) self.format_secondary_markup("It will be save in ~/.pulse/presets") self.vbox.pack_end(hbox, True, True, 0) self.show_all() def get_text(self): return self.entry.get_text() def save_and_close(self, entry, dialog, response): self.response(response) veromix/gtk/Indicator.py0000644000175100017500000001574011766302605014135 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from gi.repository import Gtk, Gdk from Configuration import config class Indicator: def __init__(self, veromix): self.window = veromix.window self.veromix = veromix self.menu = Gtk.Menu() self.indicator = None if config().get_indicator_type() != 'None': self.install_menu() self.install_quicklist() self.connect_events() def connect_events(self): self.veromix.pa_proxy().connect("on_sink_info", self.on_sink_info, self.veromix) def install_menu(self): self.APPIND_SUPPORT = True try: from gi.repository import AppIndicator3 except: self.APPIND_SUPPORT = False if self.APPIND_SUPPORT and config().get_indicator_type() == 'AppIndicator': self.indicator = AppIndicator3.Indicator.new("Veromix", "audio-volume-medium", AppIndicator3.IndicatorCategory.APPLICATION_STATUS) self.indicator.set_status (AppIndicator3.IndicatorStatus.ACTIVE) self.indicator.set_menu(self.menu) self.indicator.connect("scroll-event", self.on_scroll_wheel) # self.indicator.connect("menu-show", self.toggle_window) toggle = Gtk.MenuItem() toggle.set_label("Toggle Window") toggle.connect("activate", self.toggle_window) mute = Gtk.MenuItem() mute.set_label("Mute") mute.connect("activate", self.on_middle_click) self.menu.append(mute) self.indicator.set_secondary_activate_target(mute) self.menu.append(toggle) self.APPIND_SUPPORT = True elif config().get_indicator_type() == 'GtkStatusIcon': self.status_icon = Gtk.StatusIcon() self.status_icon.set_from_icon_name("audio-volume-medium") self.status_icon.connect('popup-menu', self.on_right_click_statusicon) self.status_icon.connect("activate", self.toggle_window) self.status_icon.connect('scroll_event', self.on_scroll_wheel) self.status_icon.connect("button_press_event", self.on_status_icon_clicked) self.APPIND_SUPPORT = False quit = Gtk.MenuItem() quit.set_label("Quit") quit.connect("activate", Gtk.main_quit) self.menu.append(quit) self.menu.show_all() def on_status_icon_clicked(self, widget, event): if event.button == 2: # if event.type == Gdk.EventType._2BUTTON_PRESS: self.on_middle_click(event) return True return False def on_middle_click(self, event, arg=None, data=None): self.veromix.get_default_sink().toggle_mute() def on_scroll_wheel(self, widget, event, value = None): if self.APPIND_SUPPORT: self.veromix.get_default_sink().step_volume((value == 0)) self.window.present() else: if event.direction == Gdk.ScrollDirection.DOWN or event.direction == Gdk.ScrollDirection.LEFT: self.veromix.get_default_sink().step_volume(False) if event.direction == Gdk.ScrollDirection.UP or event.direction == Gdk.ScrollDirection.RIGHT: self.veromix.get_default_sink().step_volume(True) def toggle_window(self, widget): if not self.window.is_active(): self.window.present() else: self.window.hide() def get_tray_menu(self): return self.menu def on_right_click_statusicon(self, icon, button, time): self.get_tray_menu() def pos(menu, aicon): return (Gtk.StatusIcon.position_menu(menu, aicon)) self.menu.popup(None, None, pos, icon, button, time) def on_sink_info(self, index, info, sink_box): channel = sink_box.get_default_sink() if config().get_indicator_type() != 'None': if channel == None: return volume = channel.pa_sink_proxy().get_volume() if channel.pa_sink_proxy().is_muted(): self.set_icon("audio-volume-muted") elif volume > 75: self.set_icon("audio-volume-high") elif volume > 30: self.set_icon("audio-volume-medium") elif volume > -5: self.set_icon("audio-volume-low") if self.DBUSMENU_SUPPORT: if channel.pa_sink_proxy().is_muted(): self.dbusmenu_mute.property_set_int(self.dbusmenu_checked[0], self.dbusmenu_checked[1]) else: self.dbusmenu_mute.property_set_int(self.dbusmenu_unchecked[0], self.dbusmenu_unchecked[1]) def set_icon(self, iconname): if self.APPIND_SUPPORT: self.indicator.set_icon(iconname) else: self.status_icon.set_from_icon_name(iconname) def install_quicklist(self): self.DBUSMENU_SUPPORT = True try: from gi.repository import Unity, Dbusmenu self.dbusmenu_checked = (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED) self.dbusmenu_unchecked = (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, Dbusmenu.MENUITEM_TOGGLE_STATE_UNCHECKED) except: self.DBUSMENU_SUPPORT = False return self.launcher = Unity.LauncherEntry.get_for_desktop_id("veromix.desktop") self.quicklist = Dbusmenu.Menuitem.new() self.dbusmenu_mute = Dbusmenu.Menuitem.new() self.dbusmenu_mute.property_set(Dbusmenu.MENUITEM_PROP_LABEL, "Mute") self.dbusmenu_mute.property_set(Dbusmenu.MENUITEM_PROP_TOGGLE_TYPE, Dbusmenu.MENUITEM_TOGGLE_CHECK) self.dbusmenu_mute.property_set_int(Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, Dbusmenu.MENUITEM_TOGGLE_STATE_UNCHECKED) self.dbusmenu_mute.property_set_bool(Dbusmenu.MENUITEM_PROP_VISIBLE, True) self.dbusmenu_mute.connect (Dbusmenu.MENUITEM_SIGNAL_ITEM_ACTIVATED, self.on_middle_click, None) self.quicklist.child_append(self.dbusmenu_mute) if not config().get_window_exit_on_close(): quit = Dbusmenu.Menuitem.new() quit.property_set (Dbusmenu.MENUITEM_PROP_LABEL, "Shutdown Veromix") quit.property_set_bool(Dbusmenu.MENUITEM_PROP_VISIBLE, True) quit.connect(Dbusmenu.MENUITEM_SIGNAL_ITEM_ACTIVATED, Gtk.main_quit, None) self.quicklist.child_append(quit) self.launcher.set_property("quicklist", self.quicklist) veromix/gtk/LadspaWidget.py0000644000175100017500000000777211766302605014577 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import datetime, urllib.parse from gi.repository import Gtk, GObject from SliderWidget import SliderWidget from SliderWidget import VerticalLabelSlider from veromixcommon.LADSPAEffects import * class LadspaWidget(SliderWidget): def __init__(self): self.number_of_siders = 0 self.ladspa_sink_update = datetime.datetime.now() self.ladspa_values = None self.ladspa_timer_running = False self.module_info = None self.timer = None SliderWidget.__init__(self) self.init_layout() def init_layout(self): self.slider_box = Gtk.HBox(0) self.create_label(None) self.pack_start(self.label_box, False, False, 3) self.pack_start(self.slider_box, False, False, 0) self.EXPAND_CHANNELS = True def on_pa_data_updated(self, data): pass def _create_slider(self, title): slider = VerticalLabelSlider() slider.set_markup(title) self.sliders.append(slider) self.slider_box.pack_start(slider, False, False, 0) return slider def create_sliders(self, sink): self.sliders = [] for i in range(0, self.number_of_siders): slider = self._create_slider("") slider.connect_value_changed(self.on_sliders_value_changed) def on_sliders_value_changed(self, widget, value, data): values = [] for i in range(0,self.number_of_siders): values.append(self.sliders[i].get_volume()) self._schedule_set_ladspa_sink(values) def set_volume(self, pa_sink_proxy): self._pa_sink_proxy = pa_sink_proxy def on_pa_module_data_updated(self, data, pa_sink_proxy): self.module_proxy = data self.module_proxy.set_pa_sink_proxy(pa_sink_proxy) count = self.module_proxy.get_lasapa_number_of_controls() if count != self.number_of_siders: self.number_of_siders = count self.remove_sliders(pa_sink_proxy) self.create_sliders(pa_sink_proxy) if self.label: self.label.set_markup("" + self.module_proxy.get_ladspa_nice_title() + "") for i in range(0, self.number_of_siders): minmax = self.module_proxy.get_ladspa_scaled_range(i) self.sliders[i].set_range(minmax[0], minmax[1]) self.sliders[i].set_markup("" + self.module_proxy.get_ladspa_effect_label(i) + "") self.sliders[i].set_volume(self.module_proxy.get_ladspa_control_value_scaled(i)) self.show_all() def _schedule_set_ladspa_sink(self,values): if self.timer != None: GObject.source_remove(self.timer) self.ladspa_values = values self.timer = GObject.timeout_add(1000, self._set_ladspa_sink) def _set_ladspa_sink(self): self.timer = None self.module_proxy.set_ladspa_sink(self.ladspa_values, self.pa_sink_proxy()) def save_preset(self, name): self.module_proxy.save_preset(name) self.on_sliders_value_changed(None, None, None) def get_selected_preset(self): return self.module_proxy.get_ladspa_preset_name() def get_selected_effect(self): return self.module_proxy.get_ladspa_effect_name() def is_ladspa(self): return True def get_ladspa_master(self): return self.module_proxy.get_ladspa_master() veromix/COPYING0000644000175100017500000010451311766302605012112 0ustar nikkibu GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . veromix/data/0000755000175100017500000000000011766302605011764 5ustar nikkibuveromix/data/locale/0000755000175100017500000000000011766302605013223 5ustar nikkibuveromix/data/locale/sr/0000755000175100017500000000000011766302605013647 5ustar nikkibuveromix/data/locale/sr/LC_MESSAGES/0000755000175100017500000000000011766302605015434 5ustar nikkibuveromix/data/locale/sr/LC_MESSAGES/veromix.po0000644000175100017500000002726111766302605017475 0ustar nikkibu# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Slobodan Terzić , 2012. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-12 02:22+0200\n" "PO-Revision-Date: 2012-02-05 17:14+0100\n" "Last-Translator: Slobodan Terzić \n" "Language-Team: Serbian \n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Lokalize 1.4\n" #: rc.py:3 rc.py:18 rc.py:81 msgid "Form" msgstr "Облик" #: rc.py:6 rc.py:75 msgid "Version" msgstr "Верзија" #: rc.py:9 rc.py:69 msgid "Homepage" msgstr "Домаћа Ñтраница" #: rc.py:12 rc.py:72 msgid "" "http://code.google." "com/p/veromix-plasmoid/" msgstr "" "http://code.google." "com/p/veromix-plasmoid/" #: rc.py:15 rc.py:78 msgid "X.Y" msgstr "X.Y" #: rc.py:21 msgid "Popup Mode" msgstr "Режим иÑкакања" #: rc.py:24 msgid "Close when losing focus" msgstr "затварај при губитку фокуÑа" #: rc.py:27 msgid "Close manually" msgstr "ручно затварање" #: rc.py:30 msgid "Background" msgstr "Позадина" #: rc.py:33 msgid "No background" msgstr "без позадине" #: rc.py:36 msgid "Translucent background" msgstr "провидна позадина" #: rc.py:39 msgid "Standard background" msgstr "уобичајена позадина" #: rc.py:42 msgid "Notification " msgstr "Обавештење" #: rc.py:45 msgid "Show toolip" msgstr "Прикажи Ñавете" #: rc.py:48 msgid "Layout" msgstr "РаÑпоред" #: rc.py:51 msgid "Use tabs" msgstr "Језичци" #: rc.py:54 msgid "Always show sources" msgstr "Увек прикажи изворе" #: rc.py:57 msgid "Show context menu button" msgstr "Дугме контекÑтног менија" #: rc.py:60 msgid "Show unit values" msgstr "" #: rc.py:63 msgid "Autostart meters" msgstr "" #: rc.py:66 msgid "" "Meters can be very CPU intensive! You can always enable meters by double " "clicking a channel." msgstr "" #: rc.py:84 msgid "Use KDE nowplaying dataengine" msgstr "КДЕ-ов датамотор тренутне Ñвирке" #: rc.py:87 msgid "Use mpris2" msgstr "МПРИС2" #: rc.py:90 msgid "Media player blacklist:" msgstr "Забрањени плејери:" #: rc.py:93 msgid "Running media players:" msgstr "Покренути плејери:" #: rc.py:96 msgid "Show album art" msgstr "Омоти албума" #: plasma/contents/code/Channel.py:140 msgid "Muted" msgstr "Утишано" #: plasma/contents/code/Channel.py:147 gtk/ContextMenu.py:134 #, fuzzy msgid "Volume meter" msgstr "Прикажи мерач" #: plasma/contents/code/Channel.py:154 msgid "Unlock channels" msgstr "Откључај канале" #: plasma/contents/code/Channel.py:163 gtk/ContextMenu.py:167 msgid "Ports" msgstr "Портови" #: plasma/contents/code/Channel.py:187 gtk/ContextMenu.py:190 msgid "Profile" msgstr "Профил" #: plasma/contents/code/Channel.py:216 msgid "Veromix Settings" msgstr "ПоÑтавке ВеромикÑа" #: plasma/contents/code/Channel.py:413 msgid "Presets" msgstr "" #: plasma/contents/code/Channel.py:415 plasma/contents/code/SinkMbeqUI.py:294 #: gtk/ContextMenu.py:260 msgid "Save" msgstr "" #: plasma/contents/code/Channel.py:420 gtk/ContextMenu.py:265 msgid "Save As..." msgstr "" #: plasma/contents/code/Channel.py:434 gtk/ContextMenu.py:284 msgid "Effect" msgstr "Ефекти" #: plasma/contents/code/MediaPlayerUI.py:206 msgid "Show position" msgstr "Прикажи позицију" #: plasma/contents/code/SinkInputUI.py:48 #: plasma/contents/code/SinkMbeqUI.py:131 gtk/ContextMenu.py:118 msgid "Disconnect/kill" msgstr "Откачи Ñе/убиј" #: plasma/contents/code/SinkInputUI.py:56 #: plasma/contents/code/SourceOutputUI.py:53 gtk/ContextMenu.py:148 msgid "Move To" msgstr "ПремеÑти на" #: plasma/contents/code/SinkInputUI.py:95 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:305 msgid "Event Sounds" msgstr "Звуци догађаја" #: plasma/contents/code/SinkInputUI.py:99 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:309 msgid "Flash Player" msgstr "Флеш плејер" #: plasma/contents/code/SinkInputUI.py:103 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:313 msgid "Chromium Browser" msgstr "Хромијум" #: plasma/contents/code/SinkInputUI.py:107 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:317 msgid "Event Sound" msgstr "Звуци догађаја" #: plasma/contents/code/SinkInputUI.py:109 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:319 msgid "Voice Output" msgstr "Излаз за глаÑ" #: plasma/contents/code/SinkMbeqUI.py:279 msgid "Name" msgstr "" #: plasma/contents/code/SinkMbeqUI.py:290 msgid "Cancel" msgstr "" #: plasma/contents/code/SinkUI.py:39 msgid "Default Sink" msgstr "Подразумевани одвод" #: plasma/contents/code/SinkUI.py:53 msgid "Uncombine" msgstr "" #: plasma/contents/code/SinkUI.py:61 gtk/ContextMenu.py:244 #, fuzzy msgid "Add Effect" msgstr "Ефекти" #: plasma/contents/code/VeroMix.py:101 msgid "Playback" msgstr "Пуштање" #: plasma/contents/code/VeroMix.py:102 msgid "Record" msgstr "Снимање" #: plasma/contents/code/VeroMix.py:125 #, fuzzy msgid "" "There is a problem with the backgroud-" "service. " "
  • If you just " "upgraded try killing the process named: VeromixServiceMain.py and relaunch " "this plasmoid
  • " "
  • If you don't know how to do that consider rebooting

See wiki for more " "details (right click and copy url)." msgstr "" "ПоÑтоји проблем Ñа позадинÑким ÑервиÑом. " "
  • уколико " "Ñте вршили надоградњу, пробајте да убијете процеÑ: VeromixServiceMain.py " "and и поново покренете овај плазмоид.
  • ако не знате " "како, најбоље поново покрените ÑиÑтем.

Погледајте вики за више детаља. (right click and copy url)." #: plasma/contents/code/main.py:59 msgid "Veromix is a mixer for the Pulseaudio sound server. " msgstr "Ð’ÐµÑ€Ð¾Ð¼Ð¸ÐºÑ Ñ˜Ðµ микÑета за звучни Ñервер ПулÑаудио. " #: plasma/contents/code/main.py:142 plasma/contents/code/main.py:409 msgid "Veromix volume up" msgstr "Појачај" #: plasma/contents/code/main.py:147 plasma/contents/code/main.py:414 msgid "Veromix volume down" msgstr "Утишај" #: plasma/contents/code/main.py:152 msgid "Veromix toggle mute" msgstr "ИÑкључи звук" #: plasma/contents/code/main.py:160 msgid "Main Volume" msgstr "Главна јачина звука" #: plasma/contents/code/main.py:278 msgid "Appearance" msgstr "Изглед" #: plasma/contents/code/main.py:298 msgid "Media Player Controls" msgstr "Управљање медијÑким плејерима" #: plasma/contents/code/main.py:324 msgid "Max volume value" msgstr "МакÑимална вредноÑÑ‚ јачине звука" #: plasma/contents/code/main.py:330 msgid "Mute if volume reaches zero" msgstr "ИÑкључи звук ако је јачина на нули" #: plasma/contents/code/main.py:334 msgid "Sound Card Profiles" msgstr "Профили звучне карте" #: plasma/contents/code/main.py:356 msgid "Pulseaudio" msgstr "ПулÑаудио" #: plasma/contents/code/main.py:363 msgid "" "LADSPA is a standard for handling audio filters and effects. Every linux " "software archive offers a large number of effects - search for LADSPA to get " "more. Not every effect is supported by Pulseaudio and others " "simple don't make sense (or create only noise).

The " "following list shows all available effects on your system: Only checked " "effects will appear in the context-menu." msgstr "" #: plasma/contents/code/main.py:368 msgid "" "

Warning: Cannot find the executables 'listplugins' and " "'analyseplugin' which are required for dynamically detecting installed " "effects.
In OpenSUSE, Fedora and Arch Linux the package " "is named 'ladspa', in Debian/Ubuntu 'ladspa-sdk'.

" msgstr "" #: plasma/contents/code/main.py:377 msgid "Enable LADSPA effects." msgstr "" #: plasma/contents/code/main.py:398 msgid "Effects / Equalizer" msgstr "" #: plasma/contents/code/main.py:419 msgid "Veromix toggle mute" msgstr "Прекидач звука" #: plasma/contents/code/main.py:423 msgid "Volume Keyboard Shortcuts" msgstr "Пречице" #: gtk/ContextMenu.py:112 #, fuzzy msgid "Default device" msgstr "Подразумевани одвод" #: gtk/ContextMenu.py:126 #, fuzzy msgid "Mute" msgstr "Утишано" #: gtk/ContextMenu.py:141 #, fuzzy msgid "Unlock Channels" msgstr "Откључај канале" #: gtk/ContextMenu.py:253 msgid "Preset" msgstr "" #: gtk/ContextMenu.py:321 msgid "Save Preset" msgstr "" #: gtk/main.py:42 #, fuzzy msgid "Veromix" msgstr "ПоÑтавке ВеромикÑа" #~ msgid "Please remove and re-add myself" #~ msgstr "Молим да ме уклоните па поново додате" #~ msgid "" #~ "Configuration updated
Because of a known bug in " #~ "KDE 4.4 initialization of Veromix failed.

A " #~ "workaround is now installed.

Please remove " #~ "this applet and add Veromix again to your desktop/panel " #~ "(alternatively you can restart plasma-desktop).

" #~ "Sorry for the inconvenience.

See wiki for more details (right " #~ "click and copy url). " #~ msgstr "" #~ "ПоÑтавке Ñу ажуриране
Због познате бубе у КДЕ-у " #~ "4.4 покретање ВеромикÑа није уÑпело..

ИÑправка је Ñада " #~ "инÑталирана.

Молимо да уклоните овај аплет и поново " #~ "поÑтавите Ð’ÐµÑ€Ð¾Ð¼Ð¸ÐºÑ Ð½Ð° површ/панел (алтернативно, можете поново " #~ "покренути ÑеÑију).

Извините на непријатноÑти.

Погледајте вики за више детаља." #~ " (деÑни клик и копирајте урл). " #~ msgid "Add equalizer" #~ msgstr "Додај еквилајзер" veromix/data/locale/tr/0000755000175100017500000000000011766302605013650 5ustar nikkibuveromix/data/locale/tr/LC_MESSAGES/0000755000175100017500000000000011766302605015435 5ustar nikkibuveromix/data/locale/tr/LC_MESSAGES/veromix.po0000644000175100017500000002515311766302605017474 0ustar nikkibu# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Anıl Özbek , 2010. msgid "" msgstr "" "Project-Id-Version: veromix-0.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-12 02:22+0200\n" "PO-Revision-Date: 2010-12-16 03:41+0200\n" "Last-Translator: Anıl Özbek \n" "Language-Team: Turkish \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Turkish\n" "X-Generator: Lokalize 1.1\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #: rc.py:3 rc.py:18 rc.py:81 msgid "Form" msgstr "Form" #: rc.py:6 rc.py:75 msgid "Version" msgstr "Sürüm" #: rc.py:9 rc.py:69 msgid "Homepage" msgstr "Anasayfa" #: rc.py:12 rc.py:72 msgid "" "http://code.google." "com/p/veromix-plasmoid/" msgstr "" "http://code.google." "com/p/veromix-plasmoid/" #: rc.py:15 rc.py:78 msgid "X.Y" msgstr "X.Y" #: rc.py:21 msgid "Popup Mode" msgstr "Açılır Pencere KipiÄŸpenPopu" #: rc.py:24 #, fuzzy msgid "Close when losing focus" msgstr "Odak kaybettiÄŸinde otomatik kapatolduÄŸu" #: rc.py:27 msgid "Close manually" msgstr "Elle kapat" #: rc.py:30 msgid "Background" msgstr "Arkaplan" #: rc.py:33 msgid "No background" msgstr "Arkaplan yok" #: rc.py:36 msgid "Translucent background" msgstr "Yarı saydam arkaplanf" #: rc.py:39 msgid "Standard background" msgstr "Standart arkaplan" #: rc.py:42 msgid "Notification " msgstr "" #: rc.py:45 msgid "Show toolip" msgstr "" #: rc.py:48 msgid "Layout" msgstr "YerleÅŸim" #: rc.py:51 msgid "Use tabs" msgstr "" #: rc.py:54 msgid "Always show sources" msgstr "" #: rc.py:57 msgid "Show context menu button" msgstr "" #: rc.py:60 msgid "Show unit values" msgstr "" #: rc.py:63 msgid "Autostart meters" msgstr "" #: rc.py:66 msgid "" "Meters can be very CPU intensive! You can always enable meters by double " "clicking a channel." msgstr "" #: rc.py:84 msgid "Use KDE nowplaying dataengine" msgstr "" #: rc.py:87 msgid "Use mpris2" msgstr "" #: rc.py:90 #, fuzzy msgid "Media player blacklist:" msgstr "Medya oynatıcı karalistesi" #: rc.py:93 #, fuzzy msgid "Running media players:" msgstr "Åžu an çalışan medya oynatıcılarlayÖ" #: rc.py:96 msgid "Show album art" msgstr "" #: plasma/contents/code/Channel.py:140 msgid "Muted" msgstr "" #: plasma/contents/code/Channel.py:147 gtk/ContextMenu.py:134 msgid "Volume meter" msgstr "" #: plasma/contents/code/Channel.py:154 msgid "Unlock channels" msgstr "" #: plasma/contents/code/Channel.py:163 gtk/ContextMenu.py:167 msgid "Ports" msgstr "" #: plasma/contents/code/Channel.py:187 gtk/ContextMenu.py:190 msgid "Profile" msgstr "" #: plasma/contents/code/Channel.py:216 msgid "Veromix Settings" msgstr "" #: plasma/contents/code/Channel.py:413 msgid "Presets" msgstr "" #: plasma/contents/code/Channel.py:415 plasma/contents/code/SinkMbeqUI.py:294 #: gtk/ContextMenu.py:260 msgid "Save" msgstr "" #: plasma/contents/code/Channel.py:420 gtk/ContextMenu.py:265 msgid "Save As..." msgstr "" #: plasma/contents/code/Channel.py:434 gtk/ContextMenu.py:284 msgid "Effect" msgstr "" #: plasma/contents/code/MediaPlayerUI.py:206 msgid "Show position" msgstr "" #: plasma/contents/code/SinkInputUI.py:48 #: plasma/contents/code/SinkMbeqUI.py:131 gtk/ContextMenu.py:118 msgid "Disconnect/kill" msgstr "" #: plasma/contents/code/SinkInputUI.py:56 #: plasma/contents/code/SourceOutputUI.py:53 gtk/ContextMenu.py:148 msgid "Move To" msgstr "" #: plasma/contents/code/SinkInputUI.py:95 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:305 msgid "Event Sounds" msgstr "" #: plasma/contents/code/SinkInputUI.py:99 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:309 msgid "Flash Player" msgstr "" #: plasma/contents/code/SinkInputUI.py:103 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:313 msgid "Chromium Browser" msgstr "" #: plasma/contents/code/SinkInputUI.py:107 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:317 msgid "Event Sound" msgstr "" #: plasma/contents/code/SinkInputUI.py:109 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:319 msgid "Voice Output" msgstr "" #: plasma/contents/code/SinkMbeqUI.py:279 msgid "Name" msgstr "" #: plasma/contents/code/SinkMbeqUI.py:290 msgid "Cancel" msgstr "" #: plasma/contents/code/SinkUI.py:39 msgid "Default Sink" msgstr "" #: plasma/contents/code/SinkUI.py:53 msgid "Uncombine" msgstr "" #: plasma/contents/code/SinkUI.py:61 gtk/ContextMenu.py:244 msgid "Add Effect" msgstr "" #: plasma/contents/code/VeroMix.py:101 msgid "Playback" msgstr "Oynatma" #: plasma/contents/code/VeroMix.py:102 msgid "Record" msgstr "Kaydetme" #: plasma/contents/code/VeroMix.py:125 #, fuzzy msgid "" "There is a problem with the backgroud-" "service. " "
  • If you just " "upgraded try killing the process named: VeromixServiceMain.py and relaunch " "this plasmoid
  • " "
  • If you don't know how to do that consider rebooting

See wiki for more " "details (right click and copy url)." msgstr "" "Arkaplan servisinde bir problem " "var. " "
  • EÄŸer yeni " "güncelleme yaptıysanız VeromixServiceMain.py isimli süreci öldürmeyi deneyin " "ve programcığı yeniden çalıştırın.
  • EÄŸer bu " "yeniden baÅŸlatmayı nasıI yapacağınızı bilmiyorsanız

detaylar için vikiye bakınız (sağ tıklayın ve bağlantıyı kopyalayın)." #: plasma/contents/code/main.py:59 msgid "Veromix is a mixer for the Pulseaudio sound server. " msgstr "Veromix, PulseAudio ses sunucusu için bir karıştırıcıdır. " #: plasma/contents/code/main.py:142 plasma/contents/code/main.py:409 msgid "Veromix volume up" msgstr "Veromix ses yükselt" #: plasma/contents/code/main.py:147 plasma/contents/code/main.py:414 msgid "Veromix volume down" msgstr "Veromix ses kıs" #: plasma/contents/code/main.py:152 #, fuzzy msgid "Veromix toggle mute" msgstr "Veromix sessiz" #: plasma/contents/code/main.py:160 msgid "Main Volume" msgstr "Ana Ses" #: plasma/contents/code/main.py:278 msgid "Appearance" msgstr "Görünüm" #: plasma/contents/code/main.py:298 msgid "Media Player Controls" msgstr "Medya Oynatıcı Kontrolleri" #: plasma/contents/code/main.py:324 #, fuzzy msgid "Max volume value" msgstr "Veromix ses yükselt" #: plasma/contents/code/main.py:330 msgid "Mute if volume reaches zero" msgstr "" #: plasma/contents/code/main.py:334 msgid "Sound Card Profiles" msgstr "" #: plasma/contents/code/main.py:356 msgid "Pulseaudio" msgstr "" #: plasma/contents/code/main.py:363 msgid "" "LADSPA is a standard for handling audio filters and effects. Every linux " "software archive offers a large number of effects - search for LADSPA to get " "more. Not every effect is supported by Pulseaudio and others " "simple don't make sense (or create only noise).

The " "following list shows all available effects on your system: Only checked " "effects will appear in the context-menu." msgstr "" #: plasma/contents/code/main.py:368 msgid "" "

Warning: Cannot find the executables 'listplugins' and " "'analyseplugin' which are required for dynamically detecting installed " "effects.
In OpenSUSE, Fedora and Arch Linux the package " "is named 'ladspa', in Debian/Ubuntu 'ladspa-sdk'.

" msgstr "" #: plasma/contents/code/main.py:377 msgid "Enable LADSPA effects." msgstr "" #: plasma/contents/code/main.py:398 msgid "Effects / Equalizer" msgstr "" #: plasma/contents/code/main.py:419 msgid "Veromix toggle mute" msgstr "Veromix sessiz" #: plasma/contents/code/main.py:423 msgid "Volume Keyboard Shortcuts" msgstr "" #: gtk/ContextMenu.py:112 msgid "Default device" msgstr "" #: gtk/ContextMenu.py:126 msgid "Mute" msgstr "" #: gtk/ContextMenu.py:141 msgid "Unlock Channels" msgstr "" #: gtk/ContextMenu.py:253 msgid "Preset" msgstr "" #: gtk/ContextMenu.py:321 msgid "Save Preset" msgstr "" #: gtk/main.py:42 msgid "Veromix" msgstr "" #~ msgid "Please remove and re-add myself" #~ msgstr "Lütfen beni kaldır ve tekrar ekle," #~ msgid "" #~ "Configuration updated
Because of a known bug in " #~ "KDE 4.4 initialization of Veromix failed.

A " #~ "workaround is now installed.

Please remove " #~ "this applet and add Veromix again to your desktop/panel " #~ "(alternatively you can restart plasma-desktop).

" #~ "Sorry for the inconvenience.

See wiki for more details (right " #~ "click and copy url). " #~ msgstr "" #~ "Yapılandırma güncellendi
KDE 4.4'teki bilinen bir " #~ "hatadan dolayı Veromix'in ilklendirilmesi başarısızlığa uğradı.

Geçici bir çözüm yüklendi.

Lütfen bu " #~ "programcığı kaldırın ve Veromix'i tekrar masaüstünüze veya " #~ "panelinize ekleyin (alternatif olarak plasma-desktop'u yeniden " #~ "başlatabilirsiniz).

Rahatsızlık için üzgünüz.

Daha fazla bilgi için " #~ "vikiye bakabilirsiniz (saÄŸ tıklayın " #~ "ve baÄŸlantıyı kopyalayın). " #~ msgid "Enable media player controls" #~ msgstr "Medya oynatıcı kontrollerini aktifleÅŸtir" #~ msgid "mpris2 Mediaplayers" #~ msgstr "mpris2 Medya oynatıcıları" #~ msgid "Use tabs (requires plasma restart)" #~ msgstr "Sekme kullan (plasma'nın yeniden baÅŸlatılması gerekir)leri" veromix/data/locale/de/0000755000175100017500000000000011766302605013613 5ustar nikkibuveromix/data/locale/de/LC_MESSAGES/0000755000175100017500000000000011766302605015400 5ustar nikkibuveromix/data/locale/de/LC_MESSAGES/veromix.po0000644000175100017500000002614311766302605017437 0ustar nikkibu# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Kai Uwe b , 2011. msgid "" msgstr "" "Project-Id-Version: veromix-0.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-12 02:22+0200\n" "PO-Revision-Date: 2012-06-10 02:15+0100\n" "Last-Translator: Nik Lutz \n" "Language-Team: German \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: German\n" "X-Generator: Lokalize 1.2\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" # #: rc.py:3 rc.py:18 rc.py:81 msgid "Form" msgstr "Von" #: rc.py:6 rc.py:75 msgid "Version" msgstr "Version" #: rc.py:9 rc.py:69 msgid "Homepage" msgstr "Homepage" #: rc.py:12 rc.py:72 msgid "" "http://code.google." "com/p/veromix-plasmoid/" msgstr "" "http://code.google." "com/p/veromix-plasmoid/" #: rc.py:15 rc.py:78 msgid "X.Y" msgstr "X.Y" #: rc.py:21 msgid "Popup Mode" msgstr "Popup-Verhalten" #: rc.py:24 msgid "Close when losing focus" msgstr "Automatisch schließen" #: rc.py:27 msgid "Close manually" msgstr "Klicken zum Schließen" #: rc.py:30 msgid "Background" msgstr "Hintergrund" #: rc.py:33 msgid "No background" msgstr "Kein Hintergrund" #: rc.py:36 msgid "Translucent background" msgstr "Durchsichtiger Hintergrund" #: rc.py:39 msgid "Standard background" msgstr "Standard-Hintergrund" #: rc.py:42 msgid "Notification " msgstr "Systembenachrichtigungen" #: rc.py:45 msgid "Show toolip" msgstr "Popup zeigen" #: rc.py:48 msgid "Layout" msgstr "Layout" #: rc.py:51 msgid "Use tabs" msgstr "Registerkarten verwenden" #: rc.py:54 msgid "Always show sources" msgstr "Eingabegeräte immer anzeigen" #: rc.py:57 msgid "Show context menu button" msgstr "Knopf für Kontextmenü anzeigen" #: rc.py:60 msgid "Show unit values" msgstr "Aktuelle Werte neben Regler anzeigen" #: rc.py:63 msgid "Autostart meters" msgstr "" #: rc.py:66 msgid "" "Meters can be very CPU intensive! You can always enable meters by double " "clicking a channel." msgstr "" #: rc.py:84 msgid "Use KDE nowplaying dataengine" msgstr "KDE-Wiedergabe-Engine verwenden" #: rc.py:87 msgid "Use mpris2" msgstr "MPris2 verwenden" #: rc.py:90 msgid "Media player blacklist:" msgstr "Die folgenden Medienspieler ignorieren:" #: rc.py:93 msgid "Running media players:" msgstr "Aktuell laufende Medienwiedergabeprogramme:" #: rc.py:96 msgid "Show album art" msgstr "Cover anzeigen" #: plasma/contents/code/Channel.py:140 msgid "Muted" msgstr "Stummgeschaltet" #: plasma/contents/code/Channel.py:147 gtk/ContextMenu.py:134 msgid "Volume meter" msgstr "Lautstärkepegel" #: plasma/contents/code/Channel.py:154 msgid "Unlock channels" msgstr "Kanäle anzeigen" #: plasma/contents/code/Channel.py:163 gtk/ContextMenu.py:167 msgid "Ports" msgstr "Anschlüsse" #: plasma/contents/code/Channel.py:187 gtk/ContextMenu.py:190 msgid "Profile" msgstr "Profil" #: plasma/contents/code/Channel.py:216 msgid "Veromix Settings" msgstr "Veromix Einstellungen" #: plasma/contents/code/Channel.py:413 msgid "Presets" msgstr "Presets" #: plasma/contents/code/Channel.py:415 plasma/contents/code/SinkMbeqUI.py:294 #: gtk/ContextMenu.py:260 msgid "Save" msgstr "Speichern" #: plasma/contents/code/Channel.py:420 gtk/ContextMenu.py:265 msgid "Save As..." msgstr "Speichern unter..." #: plasma/contents/code/Channel.py:434 gtk/ContextMenu.py:284 msgid "Effect" msgstr "Effekt" #: plasma/contents/code/MediaPlayerUI.py:206 msgid "Show position" msgstr "Position anzeigen" #: plasma/contents/code/SinkInputUI.py:48 #: plasma/contents/code/SinkMbeqUI.py:131 gtk/ContextMenu.py:118 msgid "Disconnect/kill" msgstr "Trennen" #: plasma/contents/code/SinkInputUI.py:56 #: plasma/contents/code/SourceOutputUI.py:53 gtk/ContextMenu.py:148 msgid "Move To" msgstr "Verschieben" #: plasma/contents/code/SinkInputUI.py:95 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:305 msgid "Event Sounds" msgstr "Ereignistöne" #: plasma/contents/code/SinkInputUI.py:99 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:309 msgid "Flash Player" msgstr "Flash Player" #: plasma/contents/code/SinkInputUI.py:103 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:313 msgid "Chromium Browser" msgstr "Chromium Browser" #: plasma/contents/code/SinkInputUI.py:107 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:317 msgid "Event Sound" msgstr "Ereigniston" #: plasma/contents/code/SinkInputUI.py:109 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:319 msgid "Voice Output" msgstr "Sprachausgabe" #: plasma/contents/code/SinkMbeqUI.py:279 msgid "Name" msgstr "Name" #: plasma/contents/code/SinkMbeqUI.py:290 msgid "Cancel" msgstr "Abbrechen" #: plasma/contents/code/SinkUI.py:39 msgid "Default Sink" msgstr "Standardgerät" #: plasma/contents/code/SinkUI.py:53 msgid "Uncombine" msgstr "auflösen" #: plasma/contents/code/SinkUI.py:61 gtk/ContextMenu.py:244 msgid "Add Effect" msgstr "Effekt hinzufügen" #: plasma/contents/code/VeroMix.py:101 msgid "Playback" msgstr "Wiedergabe" #: plasma/contents/code/VeroMix.py:102 msgid "Record" msgstr "Aufnahme" #: plasma/contents/code/VeroMix.py:125 msgid "" "There is a problem with the backgroud-" "service. " "
  • If you just " "upgraded try killing the process named: VeromixServiceMain.py and relaunch " "this plasmoid
  • " "
  • If you don't know how to do that consider rebooting

See wiki for more " "details (right click and copy url)." msgstr "" "Es besteht ein Problem mit der Verbindung zum Pulseaudio server.
  • " "Falls Sie das Plasmoid gerade aktualisiert haben, versuchen Sie den Prozess " "mit dem Namen \"VeromixServiceMain.py\" zu beenden
  • Alternativ können " "Sie Ihren Computer auch neu starten

Mehr Informationen finden sie im Wiki (rechts click und \"Adresse kopieren\")." #: plasma/contents/code/main.py:59 msgid "Veromix is a mixer for the Pulseaudio sound server. " msgstr "Veromix ist ein Lautstärkeregler für den Pulseaudio-Soundserver." #: plasma/contents/code/main.py:142 plasma/contents/code/main.py:409 msgid "Veromix volume up" msgstr "Veromix-Lautstärke erhöhen" #: plasma/contents/code/main.py:147 plasma/contents/code/main.py:414 msgid "Veromix volume down" msgstr "Veromix-Lautstärke verringern" #: plasma/contents/code/main.py:152 msgid "Veromix toggle mute" msgstr "Veromix-Stummschaltung ein/aus" #: plasma/contents/code/main.py:160 msgid "Main Volume" msgstr "Hauptregler" #: plasma/contents/code/main.py:278 msgid "Appearance" msgstr "Erscheinungsbild" #: plasma/contents/code/main.py:298 msgid "Media Player Controls" msgstr "Medienwiedergabesteuerung" #: plasma/contents/code/main.py:324 msgid "Max volume value" msgstr "Maximal-Lautstärke" #: plasma/contents/code/main.py:330 msgid "Mute if volume reaches zero" msgstr "Stummschalten wenn Lautstärke Null erreicht" #: plasma/contents/code/main.py:334 msgid "Sound Card Profiles" msgstr "Soundkarten-Profile" #: plasma/contents/code/main.py:356 msgid "Pulseaudio" msgstr "Pulseaudio" #: plasma/contents/code/main.py:363 msgid "" "LADSPA is a standard for handling audio filters and effects. Every linux " "software archive offers a large number of effects - search for LADSPA to get " "more. Not every effect is supported by Pulseaudio and others " "simple don't make sense (or create only noise).

The " "following list shows all available effects on your system: Only checked " "effects will appear in the context-menu." msgstr "" #: plasma/contents/code/main.py:368 msgid "" "

Warning: Cannot find the executables 'listplugins' and " "'analyseplugin' which are required for dynamically detecting installed " "effects.
In OpenSUSE, Fedora and Arch Linux the package " "is named 'ladspa', in Debian/Ubuntu 'ladspa-sdk'.

" msgstr "" #: plasma/contents/code/main.py:377 msgid "Enable LADSPA effects." msgstr "LADSPA Effekte einschalten" #: plasma/contents/code/main.py:398 msgid "Effects / Equalizer" msgstr "Effekte / Equalizer" #: plasma/contents/code/main.py:419 msgid "Veromix toggle mute" msgstr "Veromix-Stummschaltung ein/aus" #: plasma/contents/code/main.py:423 msgid "Volume Keyboard Shortcuts" msgstr "Lautstärke-Tastenkürzel" #: gtk/ContextMenu.py:112 msgid "Default device" msgstr "Standardgerät" #: gtk/ContextMenu.py:126 msgid "Mute" msgstr "Stummschalten" #: gtk/ContextMenu.py:141 msgid "Unlock Channels" msgstr "Kanäle" #: gtk/ContextMenu.py:253 msgid "Preset" msgstr "Preset" #: gtk/ContextMenu.py:321 msgid "Save Preset" msgstr "Preset speichern" #: gtk/main.py:42 #, fuzzy msgid "Veromix" msgstr "Veromix Einstellungen" #~ msgid "Kill" #~ msgstr "Trennen" #~ msgid "Please remove and re-add myself" #~ msgstr "" #~ "Bitte entfernen Sie dieses Plasmoid und fügen Sie es erneut zu " #~ "Ihrem Desktop hinzu. Alternativ können Sie Ihren Computer auch neu " #~ "starten. " #~ msgid "" #~ "Configuration updated
Because of a known bug in " #~ "KDE 4.4 initialization of Veromix failed.

A " #~ "workaround is now installed.

Please remove " #~ "this applet and add Veromix again to your desktop/panel " #~ "(alternatively you can restart plasma-desktop).

" #~ "Sorry for the inconvenience.

See wiki for more details (right " #~ "click and copy url). " #~ msgstr "" #~ "Konfiguration aktualisiert
Aufgrund eines bekannten Fehlers in " #~ "KDE 4.4 konnte Veromix nicht geladen werden.

Die Konfiguration " #~ "wurde aktualisiert, sodass dieser Fehler beim nächsten Start nicht mehr " #~ "auftreten sollte.

Bitte entfernen Sie dieses Plasmoid und " #~ "fügen Sie es erneut zu Ihrem Desktop hinzu. Alternativ können Sie Ihren " #~ "Computer auch neu starten.

Mehr " #~ "Informationen finden sie im Wiki " #~ "(Recktsklick → „Adresse kopieren“)." #~ msgid "Output" #~ msgstr "Ausgabe" #~ msgid "Enable media player controls" #~ msgstr "Medienwiedergabesteuerung anzeigen" #~ msgid "mpris2 Mediaplayers" #~ msgstr "mpris2 Medien-Player " #~ msgid "Use tabs (requires plasma restart)" #~ msgstr "Tabs anzeigen (plasma muss neu gestartet werden)" veromix/data/locale/lt/0000755000175100017500000000000011766302605013642 5ustar nikkibuveromix/data/locale/lt/LC_MESSAGES/0000755000175100017500000000000011766302605015427 5ustar nikkibuveromix/data/locale/lt/LC_MESSAGES/veromix.po0000644000175100017500000002122711766302605017464 0ustar nikkibu# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Donatas G. , 2011. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-12 02:22+0200\n" "PO-Revision-Date: 2011-04-18 12:27+0300\n" "Last-Translator: Donatas G. \n" "Language-Team: Lithuanian \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n%10==1 && n%100!=11 ? 1 : n" "%10>=2 && (n%100<10 || n%100>=20) ? 2 : 3);\n" "X-Generator: Lokalize 1.2\n" #: rc.py:3 rc.py:18 rc.py:81 msgid "Form" msgstr "IÅ¡" #: rc.py:6 rc.py:75 msgid "Version" msgstr "Versija" #: rc.py:9 rc.py:69 msgid "Homepage" msgstr "Namų puslapis" #: rc.py:12 rc.py:72 msgid "" "http://code.google." "com/p/veromix-plasmoid/" msgstr "" #: rc.py:15 rc.py:78 msgid "X.Y" msgstr "X.Y" #: rc.py:21 msgid "Popup Mode" msgstr "IššokanÄio lango veiksena" #: rc.py:24 #, fuzzy msgid "Close when losing focus" msgstr "Užverti praradus fokusÄ…" #: rc.py:27 msgid "Close manually" msgstr "Užverti rankiniu bÅ«du" #: rc.py:30 msgid "Background" msgstr "Fonas" #: rc.py:33 msgid "No background" msgstr "Be fono" #: rc.py:36 msgid "Translucent background" msgstr "Permatomas fonas" #: rc.py:39 msgid "Standard background" msgstr "Numatytasis fonas" #: rc.py:42 msgid "Notification " msgstr "PerspÄ—jimas " #: rc.py:45 msgid "Show toolip" msgstr "Rodyti mygtuko paaiÅ¡kinimÄ…" #: rc.py:48 msgid "Layout" msgstr "IÅ¡dÄ—stymas" #: rc.py:51 msgid "Use tabs" msgstr "Naudoti korteles" #: rc.py:54 msgid "Always show sources" msgstr "Visuomet rodyti Å¡altinius" #: rc.py:57 msgid "Show context menu button" msgstr "" #: rc.py:60 msgid "Show unit values" msgstr "" #: rc.py:63 msgid "Autostart meters" msgstr "" #: rc.py:66 msgid "" "Meters can be very CPU intensive! You can always enable meters by double " "clicking a channel." msgstr "" #: rc.py:84 #, fuzzy msgid "Use KDE nowplaying dataengine" msgstr "Naudoti KDE „dabar groja“ duomenų variklį" #: rc.py:87 msgid "Use mpris2" msgstr "Naudoti mpris2" #: rc.py:90 #, fuzzy msgid "Media player blacklist:" msgstr "Leistuvo valdymo juodasis sÄ…raÅ¡as" #: rc.py:93 #, fuzzy msgid "Running media players:" msgstr "Veikiantys leistuvai" #: rc.py:96 msgid "Show album art" msgstr "" #: plasma/contents/code/Channel.py:140 msgid "Muted" msgstr "" #: plasma/contents/code/Channel.py:147 gtk/ContextMenu.py:134 #, fuzzy msgid "Volume meter" msgstr "Rodyti metrÄ…" #: plasma/contents/code/Channel.py:154 msgid "Unlock channels" msgstr "" #: plasma/contents/code/Channel.py:163 gtk/ContextMenu.py:167 msgid "Ports" msgstr "" #: plasma/contents/code/Channel.py:187 gtk/ContextMenu.py:190 msgid "Profile" msgstr "" #: plasma/contents/code/Channel.py:216 msgid "Veromix Settings" msgstr "" #: plasma/contents/code/Channel.py:413 msgid "Presets" msgstr "" #: plasma/contents/code/Channel.py:415 plasma/contents/code/SinkMbeqUI.py:294 #: gtk/ContextMenu.py:260 msgid "Save" msgstr "" #: plasma/contents/code/Channel.py:420 gtk/ContextMenu.py:265 msgid "Save As..." msgstr "" #: plasma/contents/code/Channel.py:434 gtk/ContextMenu.py:284 msgid "Effect" msgstr "" #: plasma/contents/code/MediaPlayerUI.py:206 msgid "Show position" msgstr "" #: plasma/contents/code/SinkInputUI.py:48 #: plasma/contents/code/SinkMbeqUI.py:131 gtk/ContextMenu.py:118 msgid "Disconnect/kill" msgstr "Atjungti/nužudyti" #: plasma/contents/code/SinkInputUI.py:56 #: plasma/contents/code/SourceOutputUI.py:53 gtk/ContextMenu.py:148 msgid "Move To" msgstr "" #: plasma/contents/code/SinkInputUI.py:95 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:305 msgid "Event Sounds" msgstr "" #: plasma/contents/code/SinkInputUI.py:99 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:309 msgid "Flash Player" msgstr "" #: plasma/contents/code/SinkInputUI.py:103 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:313 msgid "Chromium Browser" msgstr "" #: plasma/contents/code/SinkInputUI.py:107 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:317 msgid "Event Sound" msgstr "" #: plasma/contents/code/SinkInputUI.py:109 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:319 #, fuzzy msgid "Voice Output" msgstr "IÅ¡vestis" #: plasma/contents/code/SinkMbeqUI.py:279 msgid "Name" msgstr "" #: plasma/contents/code/SinkMbeqUI.py:290 msgid "Cancel" msgstr "" #: plasma/contents/code/SinkUI.py:39 msgid "Default Sink" msgstr "Numatytoji audio iÅ¡vestis" #: plasma/contents/code/SinkUI.py:53 msgid "Uncombine" msgstr "" #: plasma/contents/code/SinkUI.py:61 gtk/ContextMenu.py:244 msgid "Add Effect" msgstr "" #: plasma/contents/code/VeroMix.py:101 msgid "Playback" msgstr "Grojimas" #: plasma/contents/code/VeroMix.py:102 msgid "Record" msgstr "Ä®raÅ¡ymas" #: plasma/contents/code/VeroMix.py:125 msgid "" "There is a problem with the backgroud-" "service. " "
  • If you just " "upgraded try killing the process named: VeromixServiceMain.py and relaunch " "this plasmoid
  • " "
  • If you don't know how to do that consider rebooting

See wiki for more " "details (right click and copy url)." msgstr "" #: plasma/contents/code/main.py:59 msgid "Veromix is a mixer for the Pulseaudio sound server. " msgstr "Veromix yra Pulseaudio serverio maiÅ¡iklis. " #: plasma/contents/code/main.py:142 plasma/contents/code/main.py:409 msgid "Veromix volume up" msgstr "Veromix - padidinti garsÄ…" #: plasma/contents/code/main.py:147 plasma/contents/code/main.py:414 msgid "Veromix volume down" msgstr "Veromix - sumažinti garsÄ…" #: plasma/contents/code/main.py:152 #, fuzzy msgid "Veromix toggle mute" msgstr "Veromix - sukeisti iÅ¡/į begarsį" # Ðе уверен что Ñто такое #: plasma/contents/code/main.py:160 msgid "Main Volume" msgstr "Pagrindinis garso reguliuoklis" #: plasma/contents/code/main.py:278 msgid "Appearance" msgstr "IÅ¡vaizda" #: plasma/contents/code/main.py:298 msgid "Media Player Controls" msgstr "Leistuvo valdymas" #: plasma/contents/code/main.py:324 msgid "Max volume value" msgstr "Maksimalus garsas" #: plasma/contents/code/main.py:330 msgid "Mute if volume reaches zero" msgstr "Užtildyti garsÄ… valdikliui pasiekus nulį" #: plasma/contents/code/main.py:334 msgid "Sound Card Profiles" msgstr "Garso plokÅ¡tÄ—s profiliai" #: plasma/contents/code/main.py:356 msgid "Pulseaudio" msgstr "Pulseaudio" #: plasma/contents/code/main.py:363 msgid "" "LADSPA is a standard for handling audio filters and effects. Every linux " "software archive offers a large number of effects - search for LADSPA to get " "more. Not every effect is supported by Pulseaudio and others " "simple don't make sense (or create only noise).

The " "following list shows all available effects on your system: Only checked " "effects will appear in the context-menu." msgstr "" #: plasma/contents/code/main.py:368 msgid "" "

Warning: Cannot find the executables 'listplugins' and " "'analyseplugin' which are required for dynamically detecting installed " "effects.
In OpenSUSE, Fedora and Arch Linux the package " "is named 'ladspa', in Debian/Ubuntu 'ladspa-sdk'.

" msgstr "" #: plasma/contents/code/main.py:377 msgid "Enable LADSPA effects." msgstr "" #: plasma/contents/code/main.py:398 msgid "Effects / Equalizer" msgstr "" #: plasma/contents/code/main.py:419 msgid "Veromix toggle mute" msgstr "Veromix - sukeisti iš/į begarsį" #: plasma/contents/code/main.py:423 #, fuzzy msgid "Volume Keyboard Shortcuts" msgstr "Globalieji spartieji klavišai" #: gtk/ContextMenu.py:112 #, fuzzy msgid "Default device" msgstr "Numatytoji audio išvestis" #: gtk/ContextMenu.py:126 msgid "Mute" msgstr "" #: gtk/ContextMenu.py:141 msgid "Unlock Channels" msgstr "" #: gtk/ContextMenu.py:253 msgid "Preset" msgstr "" #: gtk/ContextMenu.py:321 msgid "Save Preset" msgstr "" #: gtk/main.py:42 msgid "Veromix" msgstr "" #~ msgid "Please remove and re-add myself" #~ msgstr "Prašome pašalinti ir iš naujo pridėti plazmoidą" #~ msgid "Output" #~ msgstr "Išvestis" #, fuzzy #~ msgid "Enable media player controls" #~ msgstr "Įgalinti leistuvo valdymą" #, fuzzy #~ msgid "System Notifications" #~ msgstr "Perspėjimas " veromix/data/locale/it/0000755000175100017500000000000011766302605013637 5ustar nikkibuveromix/data/locale/it/LC_MESSAGES/0000755000175100017500000000000011766302605015424 5ustar nikkibuveromix/data/locale/it/LC_MESSAGES/veromix.po0000644000175100017500000002730611766302605017465 0ustar nikkibu# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Gianluca Boiano , 2011, 2012. msgid "" msgstr "" "Project-Id-Version: veromix-0.9\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-12 02:22+0200\n" "PO-Revision-Date: 2012-05-07 11:59+0200\n" "Last-Translator: Gianluca Boiano \n" "Language-Team: Italian \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: German\n" "X-Generator: Lokalize 1.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: rc.py:3 rc.py:18 rc.py:81 msgid "Form" msgstr "Form" #: rc.py:6 rc.py:75 msgid "Version" msgstr "Versione" #: rc.py:9 rc.py:69 msgid "Homepage" msgstr "Sito ufficiale" #: rc.py:12 rc.py:72 msgid "" "http://code.google." "com/p/veromix-plasmoid/" msgstr "" "http://code.google." "com/p/veromix-plasmoid/" #: rc.py:15 rc.py:78 msgid "X.Y" msgstr "X.Y" #: rc.py:21 msgid "Popup Mode" msgstr "Comportamento Finestra a comparsa" #: rc.py:24 msgid "Close when losing focus" msgstr "Chiudi in assenza di focus" #: rc.py:27 msgid "Close manually" msgstr "Da chiudere manualmente" #: rc.py:30 msgid "Background" msgstr "Sfondo" #: rc.py:33 msgid "No background" msgstr "Senza sfondo" #: rc.py:36 msgid "Translucent background" msgstr "Sfondo trasparente" #: rc.py:39 msgid "Standard background" msgstr "Sfondo predefinito" #: rc.py:42 msgid "Notification " msgstr "Notifiche" #: rc.py:45 msgid "Show toolip" msgstr "Mostra suggerimenti" #: rc.py:48 msgid "Layout" msgstr "Dettagli interfaccia" #: rc.py:51 msgid "Use tabs" msgstr "Usa schede" #: rc.py:54 msgid "Always show sources" msgstr "Mostra sempre sorgenti " #: rc.py:57 msgid "Show context menu button" msgstr "Mostra pulsante per menu contestuale" #: rc.py:60 msgid "Show unit values" msgstr "Mostra percentuale volume" #: rc.py:63 msgid "Autostart meters" msgstr "Autoavvia VuMeter" #: rc.py:66 msgid "" "Meters can be very CPU intensive! You can always enable meters by double " "clicking a channel." msgstr "" "I VuMeter possono gravare sulle performance della CPU! Puoi sempre " "abilitarli cliccando due volte su di un canale." #: rc.py:84 msgid "Use KDE nowplaying dataengine" msgstr "Usa nowplaying nativo di KDE" #: rc.py:87 msgid "Use mpris2" msgstr "Usa mpris2" #: rc.py:90 msgid "Media player blacklist:" msgstr "Media player da ignorare:" #: rc.py:93 msgid "Running media players:" msgstr "Media player in esecuzione:" #: rc.py:96 msgid "Show album art" msgstr "Mostra copertine" #: plasma/contents/code/Channel.py:140 msgid "Muted" msgstr "Muto" #: plasma/contents/code/Channel.py:147 gtk/ContextMenu.py:134 #, fuzzy msgid "Volume meter" msgstr "Mostra VuMeter" #: plasma/contents/code/Channel.py:154 msgid "Unlock channels" msgstr "Dividi canali" #: plasma/contents/code/Channel.py:163 gtk/ContextMenu.py:167 msgid "Ports" msgstr "Porte" #: plasma/contents/code/Channel.py:187 gtk/ContextMenu.py:190 msgid "Profile" msgstr "Profilo" #: plasma/contents/code/Channel.py:216 msgid "Veromix Settings" msgstr "Impostazioni di Veromix" #: plasma/contents/code/Channel.py:413 msgid "Presets" msgstr "Programmi" #: plasma/contents/code/Channel.py:415 plasma/contents/code/SinkMbeqUI.py:294 #: gtk/ContextMenu.py:260 msgid "Save" msgstr "Salva" #: plasma/contents/code/Channel.py:420 gtk/ContextMenu.py:265 msgid "Save As..." msgstr "Salva con nome" #: plasma/contents/code/Channel.py:434 gtk/ContextMenu.py:284 msgid "Effect" msgstr "Effetto" #: plasma/contents/code/MediaPlayerUI.py:206 msgid "Show position" msgstr "Mostra posizione" #: plasma/contents/code/SinkInputUI.py:48 #: plasma/contents/code/SinkMbeqUI.py:131 gtk/ContextMenu.py:118 msgid "Disconnect/kill" msgstr "Disconnetti/termina" #: plasma/contents/code/SinkInputUI.py:56 #: plasma/contents/code/SourceOutputUI.py:53 gtk/ContextMenu.py:148 msgid "Move To" msgstr "Sposta in" #: plasma/contents/code/SinkInputUI.py:95 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:305 msgid "Event Sounds" msgstr "Suoni Notifica" #: plasma/contents/code/SinkInputUI.py:99 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:309 msgid "Flash Player" msgstr "Flash Player" #: plasma/contents/code/SinkInputUI.py:103 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:313 msgid "Chromium Browser" msgstr "Chromium Browser" #: plasma/contents/code/SinkInputUI.py:107 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:317 msgid "Event Sound" msgstr "Suono Notifica" #: plasma/contents/code/SinkInputUI.py:109 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:319 msgid "Voice Output" msgstr "Uscita" #: plasma/contents/code/SinkMbeqUI.py:279 msgid "Name" msgstr "Nome" #: plasma/contents/code/SinkMbeqUI.py:290 msgid "Cancel" msgstr "Cancella" #: plasma/contents/code/SinkUI.py:39 msgid "Default Sink" msgstr "Audio Interno" #: plasma/contents/code/SinkUI.py:53 msgid "Uncombine" msgstr "Separa" #: plasma/contents/code/SinkUI.py:61 gtk/ContextMenu.py:244 msgid "Add Effect" msgstr "Aggiungi Effetto" #: plasma/contents/code/VeroMix.py:101 msgid "Playback" msgstr "Riproduzione" #: plasma/contents/code/VeroMix.py:102 msgid "Record" msgstr "Registrazione" #: plasma/contents/code/VeroMix.py:125 msgid "" "There is a problem with the backgroud-" "service. " "
  • If you just " "upgraded try killing the process named: VeromixServiceMain.py and relaunch " "this plasmoid
  • " "
  • If you don't know how to do that consider rebooting

See wiki for more " "details (right click and copy url)." msgstr "" "Si è verificato un problema col demone Pulseaudio.
  • Se hai già " "aggiornato il plasmoide prova a terminare il processo VeromixServiceMain.py " "e riavvia Veromix
  • In alternativa riavvia il sistema

" "Consulta il wiki per maggiori informazioni (tasto destro e \"Copia indirizzo di collegamento\")." #: plasma/contents/code/main.py:59 msgid "Veromix is a mixer for the Pulseaudio sound server. " msgstr "Veromix è un mixer per il server sonoro Pulseaudio." #: plasma/contents/code/main.py:142 plasma/contents/code/main.py:409 msgid "Veromix volume up" msgstr "Aumenta volume" #: plasma/contents/code/main.py:147 plasma/contents/code/main.py:414 msgid "Veromix volume down" msgstr "Diminuisci volume" #: plasma/contents/code/main.py:152 msgid "Veromix toggle mute" msgstr "Muto per Veromix" #: plasma/contents/code/main.py:160 msgid "Main Volume" msgstr "Volume Principale" #: plasma/contents/code/main.py:278 msgid "Appearance" msgstr "Aspetto" #: plasma/contents/code/main.py:298 msgid "Media Player Controls" msgstr "Controlli Multimediali" #: plasma/contents/code/main.py:324 msgid "Max volume value" msgstr "Valore massimo per volume" #: plasma/contents/code/main.py:330 msgid "Mute if volume reaches zero" msgstr "Abilita muto se il volume è 0" #: plasma/contents/code/main.py:334 msgid "Sound Card Profiles" msgstr "Profili Scheda Audio" #: plasma/contents/code/main.py:356 msgid "Pulseaudio" msgstr "Pulseaudio" #: plasma/contents/code/main.py:363 msgid "" "LADSPA is a standard for handling audio filters and effects. Every linux " "software archive offers a large number of effects - search for LADSPA to get " "more. Not every effect is supported by Pulseaudio and others " "simple don't make sense (or create only noise).

The " "following list shows all available effects on your system: Only checked " "effects will appear in the context-menu." msgstr "" "LADSPA è uno standard per gestire filtri ed effetti audio. Ogni " "distribuzione linux offre, nei suoi repository, un gran numero di effetti - " "cerca LADSPA per usarne altri. Non tutti gli effetti sono supportati da " "Pulseaudio, altri invece non si integrano o generano solo rumore.

La seguente lista mostra tutti gli effetti disponibili sul tuo sistema. " "Solo quelli selezionati appariranno nel menu contestuale. " #: plasma/contents/code/main.py:368 msgid "" "

Warning: Cannot find the executables 'listplugins' and " "'analyseplugin' which are required for dynamically detecting installed " "effects.
In OpenSUSE, Fedora and Arch Linux the package " "is named 'ladspa', in Debian/Ubuntu 'ladspa-sdk'.

" msgstr "" "

Attenzione: Impossibile trovare 'listplugins' e " "'analyseplugin', eseguibili richiesti per ottenere dinamicamente gli effetti " "installati.
In OpenSUSE, Fedora e Arch Linux il pacchetto " "da installare è chiamato 'ladspa', in Debian/Ubuntu 'ladspa-sdk'.

" #: plasma/contents/code/main.py:377 msgid "Enable LADSPA effects." msgstr "Attiva effetti LADSPA." #: plasma/contents/code/main.py:398 msgid "Effects / Equalizer" msgstr "Effetti / Equalizzatore" #: plasma/contents/code/main.py:419 msgid "Veromix toggle mute" msgstr "Muto" #: plasma/contents/code/main.py:423 msgid "Volume Keyboard Shortcuts" msgstr "Tasti rapidi per Volume" #: gtk/ContextMenu.py:112 #, fuzzy msgid "Default device" msgstr "Audio Interno" #: gtk/ContextMenu.py:126 #, fuzzy msgid "Mute" msgstr "Muto" #: gtk/ContextMenu.py:141 #, fuzzy msgid "Unlock Channels" msgstr "Dividi canali" #: gtk/ContextMenu.py:253 #, fuzzy msgid "Preset" msgstr "Programmi" #: gtk/ContextMenu.py:321 #, fuzzy msgid "Save Preset" msgstr "Programmi" #: gtk/main.py:42 #, fuzzy msgid "Veromix" msgstr "Impostazioni di Veromix" #~ msgid "Please remove and re-add myself" #~ msgstr "Per favore rimuovi il plasmoide Veromix e riaggiungilo" #~ msgid "" #~ "Configuration updated
Because of a known bug in " #~ "KDE 4.4 initialization of Veromix failed.

A " #~ "workaround is now installed.

Please remove " #~ "this applet and add Veromix again to your desktop/panel " #~ "(alternatively you can restart plasma-desktop).

" #~ "Sorry for the inconvenience.

See wiki for more details (right " #~ "click and copy url). " #~ msgstr "" #~ "Impostazioni aggiornate
A causa di un bug in KDE 4.4 Veromix " #~ "ha riscontrato un problema di avvio.

Il problema sarà aggirato a " #~ "breve.

Si pregadi rimuovere questo plasmoidee di " #~ "riaggiunderlo al desktop/pannello. In alternativa riavvia plasma-" #~ "desktop.

Troverai maggiori dettagli " #~ "sul wiki (tasto destro e \"Copia " #~ "indirizzo del collegamento\")." #~ msgid "Add equalizer" #~ msgstr "Aggiungi equalizzatore" #~ msgid "Output" #~ msgstr "Uscita" #~ msgid "Enable media player controls" #~ msgstr "Mostra controlli lettore multimediale" #~ msgid "System Notifications" #~ msgstr "Notifiche di sistema" #~ msgid "mpris2 Mediaplayers" #~ msgstr "Interfaccia multimediale MPRIS2" #~ msgid "Use tabs (requires plasma restart)" #~ msgstr "Tabs anzeigen (plasma muss neu gestartet werden)" veromix/data/locale/sr@latin/0000755000175100017500000000000011766302605014777 5ustar nikkibuveromix/data/locale/sr@latin/LC_MESSAGES/0000755000175100017500000000000011766302605016564 5ustar nikkibuveromix/data/locale/sr@latin/LC_MESSAGES/veromix.po0000644000175100017500000002500611766302605020620 0ustar nikkibu# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Slobodan Terzić , 2012. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-12 02:22+0200\n" "PO-Revision-Date: 2012-02-05 17:22+0100\n" "Last-Translator: Slobodan Terzić \n" "Language-Team: Serbian \n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Lokalize 1.4\n" #: rc.py:3 rc.py:18 rc.py:81 msgid "Form" msgstr "Oblik" #: rc.py:6 rc.py:75 msgid "Version" msgstr "Verzija" #: rc.py:9 rc.py:69 msgid "Homepage" msgstr "Domaća stranica" #: rc.py:12 rc.py:72 msgid "" "http://code.google." "com/p/veromix-plasmoid/" msgstr "" "http://code.google." "com/p/veromix-plasmoid/" #: rc.py:15 rc.py:78 msgid "X.Y" msgstr "X.Y" #: rc.py:21 msgid "Popup Mode" msgstr "Režim iskakanja" #: rc.py:24 msgid "Close when losing focus" msgstr "zatvaraj pri gubitku fokusa" #: rc.py:27 msgid "Close manually" msgstr "ruÄno zatvaranje" #: rc.py:30 msgid "Background" msgstr "Pozadina" #: rc.py:33 msgid "No background" msgstr "bez pozadine" #: rc.py:36 msgid "Translucent background" msgstr "providna pozadina" #: rc.py:39 msgid "Standard background" msgstr "uobiÄajena pozadina" #: rc.py:42 msgid "Notification " msgstr "ObaveÅ¡tenje" #: rc.py:45 msgid "Show toolip" msgstr "Prikaži savete" #: rc.py:48 msgid "Layout" msgstr "Raspored" #: rc.py:51 msgid "Use tabs" msgstr "JeziÄci" #: rc.py:54 msgid "Always show sources" msgstr "Uvek prikaži izvore" #: rc.py:57 msgid "Show context menu button" msgstr "Dugme kontekstnog menija" #: rc.py:60 msgid "Show unit values" msgstr "" #: rc.py:63 msgid "Autostart meters" msgstr "" #: rc.py:66 msgid "" "Meters can be very CPU intensive! You can always enable meters by double " "clicking a channel." msgstr "" #: rc.py:84 msgid "Use KDE nowplaying dataengine" msgstr "KDE-ov datamotor trenutne svirke" #: rc.py:87 msgid "Use mpris2" msgstr "MPRIS2" #: rc.py:90 msgid "Media player blacklist:" msgstr "Zabranjeni plejeri:" #: rc.py:93 msgid "Running media players:" msgstr "Pokrenuti plejeri:" #: rc.py:96 msgid "Show album art" msgstr "Omoti albuma" #: plasma/contents/code/Channel.py:140 msgid "Muted" msgstr "UtiÅ¡ano" #: plasma/contents/code/Channel.py:147 gtk/ContextMenu.py:134 #, fuzzy msgid "Volume meter" msgstr "Prikaži meraÄ" #: plasma/contents/code/Channel.py:154 msgid "Unlock channels" msgstr "OtkljuÄaj kanale" #: plasma/contents/code/Channel.py:163 gtk/ContextMenu.py:167 msgid "Ports" msgstr "Portovi" #: plasma/contents/code/Channel.py:187 gtk/ContextMenu.py:190 msgid "Profile" msgstr "Profil" #: plasma/contents/code/Channel.py:216 msgid "Veromix Settings" msgstr "Postavke Veromixa" #: plasma/contents/code/Channel.py:413 msgid "Presets" msgstr "" #: plasma/contents/code/Channel.py:415 plasma/contents/code/SinkMbeqUI.py:294 #: gtk/ContextMenu.py:260 msgid "Save" msgstr "" #: plasma/contents/code/Channel.py:420 gtk/ContextMenu.py:265 msgid "Save As..." msgstr "" #: plasma/contents/code/Channel.py:434 gtk/ContextMenu.py:284 msgid "Effect" msgstr "Efekti" #: plasma/contents/code/MediaPlayerUI.py:206 msgid "Show position" msgstr "Prikaži poziciju" #: plasma/contents/code/SinkInputUI.py:48 #: plasma/contents/code/SinkMbeqUI.py:131 gtk/ContextMenu.py:118 msgid "Disconnect/kill" msgstr "OtkaÄi se/ubij" #: plasma/contents/code/SinkInputUI.py:56 #: plasma/contents/code/SourceOutputUI.py:53 gtk/ContextMenu.py:148 msgid "Move To" msgstr "Premesti na" #: plasma/contents/code/SinkInputUI.py:95 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:305 msgid "Event Sounds" msgstr "Zvuci dogaÄ‘aja" #: plasma/contents/code/SinkInputUI.py:99 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:309 msgid "Flash Player" msgstr "Flash plejer" #: plasma/contents/code/SinkInputUI.py:103 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:313 msgid "Chromium Browser" msgstr "Chromium" #: plasma/contents/code/SinkInputUI.py:107 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:317 msgid "Event Sound" msgstr "Zvuci dogaÄ‘aja" #: plasma/contents/code/SinkInputUI.py:109 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:319 msgid "Voice Output" msgstr "Izlaz za glas" #: plasma/contents/code/SinkMbeqUI.py:279 msgid "Name" msgstr "" #: plasma/contents/code/SinkMbeqUI.py:290 msgid "Cancel" msgstr "" #: plasma/contents/code/SinkUI.py:39 msgid "Default Sink" msgstr "Podrazumevani odvod" #: plasma/contents/code/SinkUI.py:53 msgid "Uncombine" msgstr "" #: plasma/contents/code/SinkUI.py:61 gtk/ContextMenu.py:244 #, fuzzy msgid "Add Effect" msgstr "Efekti" #: plasma/contents/code/VeroMix.py:101 msgid "Playback" msgstr "PuÅ¡tanje" #: plasma/contents/code/VeroMix.py:102 msgid "Record" msgstr "Snimanje" #: plasma/contents/code/VeroMix.py:125 #, fuzzy msgid "" "There is a problem with the backgroud-" "service. " "
  • If you just " "upgraded try killing the process named: VeromixServiceMain.py and relaunch " "this plasmoid
  • " "
  • If you don't know how to do that consider rebooting

See wiki for more " "details (right click and copy url)." msgstr "" "Postoji problem sa pozadinskim servisom. " "
  • ukoliko " "ste vrÅ¡ili nadogradnju, probajte da ubijete proces: VeromixServiceMain.py " "and i ponovo pokrenete ovaj plazmoid.
  • ako ne znate " "kako, najbolje ponovo pokrenite sistem.

Pogledajte viki za viÅ¡e detalja. (right click and copy url)." #: plasma/contents/code/main.py:59 msgid "Veromix is a mixer for the Pulseaudio sound server. " msgstr "Veromix je mikseta za zvuÄni server Pulsaudio. " #: plasma/contents/code/main.py:142 plasma/contents/code/main.py:409 msgid "Veromix volume up" msgstr "PojaÄaj" #: plasma/contents/code/main.py:147 plasma/contents/code/main.py:414 msgid "Veromix volume down" msgstr "UtiÅ¡aj" #: plasma/contents/code/main.py:152 msgid "Veromix toggle mute" msgstr "IskljuÄi zvuk" #: plasma/contents/code/main.py:160 msgid "Main Volume" msgstr "Glavna jaÄina zvuka" #: plasma/contents/code/main.py:278 msgid "Appearance" msgstr "Izgled" #: plasma/contents/code/main.py:298 msgid "Media Player Controls" msgstr "Upravljanje medijskim plejerima" #: plasma/contents/code/main.py:324 msgid "Max volume value" msgstr "Maksimalna vrednost jaÄine zvuka" #: plasma/contents/code/main.py:330 msgid "Mute if volume reaches zero" msgstr "IskljuÄi zvuk ako je jaÄina na nuli" #: plasma/contents/code/main.py:334 msgid "Sound Card Profiles" msgstr "Profili zvuÄne karte" #: plasma/contents/code/main.py:356 msgid "Pulseaudio" msgstr "Pulseaudio" #: plasma/contents/code/main.py:363 msgid "" "LADSPA is a standard for handling audio filters and effects. Every linux " "software archive offers a large number of effects - search for LADSPA to get " "more. Not every effect is supported by Pulseaudio and others " "simple don't make sense (or create only noise).

The " "following list shows all available effects on your system: Only checked " "effects will appear in the context-menu." msgstr "" #: plasma/contents/code/main.py:368 msgid "" "

Warning: Cannot find the executables 'listplugins' and " "'analyseplugin' which are required for dynamically detecting installed " "effects.
In OpenSUSE, Fedora and Arch Linux the package " "is named 'ladspa', in Debian/Ubuntu 'ladspa-sdk'.

" msgstr "" #: plasma/contents/code/main.py:377 msgid "Enable LADSPA effects." msgstr "" #: plasma/contents/code/main.py:398 msgid "Effects / Equalizer" msgstr "" #: plasma/contents/code/main.py:419 msgid "Veromix toggle mute" msgstr "PrekidaÄ zvuka" #: plasma/contents/code/main.py:423 msgid "Volume Keyboard Shortcuts" msgstr "PreÄice" #: gtk/ContextMenu.py:112 #, fuzzy msgid "Default device" msgstr "Podrazumevani odvod" #: gtk/ContextMenu.py:126 #, fuzzy msgid "Mute" msgstr "UtiÅ¡ano" #: gtk/ContextMenu.py:141 #, fuzzy msgid "Unlock Channels" msgstr "OtkljuÄaj kanale" #: gtk/ContextMenu.py:253 msgid "Preset" msgstr "" #: gtk/ContextMenu.py:321 msgid "Save Preset" msgstr "" #: gtk/main.py:42 #, fuzzy msgid "Veromix" msgstr "Postavke Veromixa" #~ msgid "Please remove and re-add myself" #~ msgstr "Molim da me uklonite pa ponovo dodate" #~ msgid "" #~ "Configuration updated
Because of a known bug in " #~ "KDE 4.4 initialization of Veromix failed.

A " #~ "workaround is now installed.

Please remove " #~ "this applet and add Veromix again to your desktop/panel " #~ "(alternatively you can restart plasma-desktop).

" #~ "Sorry for the inconvenience.

See wiki for more details (right " #~ "click and copy url). " #~ msgstr "" #~ "Postavke su ažurirane
Zbog poznate bube u KDE-u " #~ "4.4 pokretanje Veromixa nije uspelo..

Ispravka je sada " #~ "instalirana.

Molimo da uklonite ovaj aplet i ponovo " #~ "postavite Veromix na površ/panel (alternativno, možete ponovo " #~ "pokrenuti sesiju).

Izvinite na neprijatnosti.

Pogledajte viki za viÅ¡e detalja." #~ " (desni klik i kopirajte url). " #~ msgid "Add equalizer" #~ msgstr "Dodaj ekvilajzer" veromix/data/locale/ru/0000755000175100017500000000000011766302605013651 5ustar nikkibuveromix/data/locale/ru/LC_MESSAGES/0000755000175100017500000000000011766302605015436 5ustar nikkibuveromix/data/locale/ru/LC_MESSAGES/veromix.po0000644000175100017500000003453611766302605017502 0ustar nikkibu# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # prodoomman, 2010. # proDOOMman , 2010, 2011. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-06-12 02:22+0200\n" "PO-Revision-Date: 2012-05-25 13:06+0300\n" "Last-Translator: Roman Timushev \n" "Language-Team: Russian \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 1.2\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #: rc.py:3 rc.py:18 rc.py:81 msgid "Form" msgstr "" #: rc.py:6 rc.py:75 msgid "Version" msgstr "ВерÑиÑ" #: rc.py:9 rc.py:69 msgid "Homepage" msgstr "ДомашнÑÑ Ñтраница" #: rc.py:12 rc.py:72 msgid "" "http://code.google." "com/p/veromix-plasmoid/" msgstr "" "http://code.google." "com/p/veromix-plasmoid/" #: rc.py:15 rc.py:78 msgid "X.Y" msgstr "X.Y" #: rc.py:21 msgid "Popup Mode" msgstr "Окно микшера" #: rc.py:24 msgid "Close when losing focus" msgstr "Закрывать при потере фокуÑа" #: rc.py:27 msgid "Close manually" msgstr "Закрывать вручную" #: rc.py:30 msgid "Background" msgstr "Фон" #: rc.py:33 msgid "No background" msgstr "Без фона" #: rc.py:36 msgid "Translucent background" msgstr "Полупрозрачный фон" #: rc.py:39 msgid "Standard background" msgstr "Стандартный фон" #: rc.py:42 msgid "Notification " msgstr "УведомлениÑ" #: rc.py:45 msgid "Show toolip" msgstr "Показывать подÑказки" #: rc.py:48 msgid "Layout" msgstr "Размещение" #: rc.py:51 msgid "Use tabs" msgstr "ИÑпользовать вкладки" #: rc.py:54 msgid "Always show sources" msgstr "Ð’Ñегда показывать иÑточники" #: rc.py:57 msgid "Show context menu button" msgstr "Показывать кнопку вызова контекÑтного меню" #: rc.py:60 msgid "Show unit values" msgstr "Показывать чиÑленные значениÑ" #: rc.py:63 msgid "Autostart meters" msgstr "ÐвтоматичеÑки запуÑкать измерители" #: rc.py:66 msgid "" "Meters can be very CPU intensive! You can always enable meters by double " "clicking a channel." msgstr "" "Измерители могут Ñильно нагружать процеÑÑор! Ð’Ñ‹ вÑегда можете включить " "измеритель двойным щелчком по каналу." #: rc.py:84 msgid "Use KDE nowplaying dataengine" msgstr "ИÑпользовать иÑточник данных KDE" #: rc.py:87 msgid "Use mpris2" msgstr "ИÑпользовать mpris2" #: rc.py:90 msgid "Media player blacklist:" msgstr "Черный ÑпиÑок проигрывателей:" #: rc.py:93 msgid "Running media players:" msgstr "Запущенные проигрыватели:" #: rc.py:96 msgid "Show album art" msgstr "Показывать обложку альбома" #: plasma/contents/code/Channel.py:140 msgid "Muted" msgstr "Выключен" #: plasma/contents/code/Channel.py:147 gtk/ContextMenu.py:134 #, fuzzy msgid "Volume meter" msgstr "Отображать метки громкоÑти" #: plasma/contents/code/Channel.py:154 msgid "Unlock channels" msgstr "Разблокировать каналы" #: plasma/contents/code/Channel.py:163 gtk/ContextMenu.py:167 msgid "Ports" msgstr "Разъёмы" #: plasma/contents/code/Channel.py:187 gtk/ContextMenu.py:190 msgid "Profile" msgstr "Профиль" #: plasma/contents/code/Channel.py:216 msgid "Veromix Settings" msgstr "ÐаÑтроить Veromix" #: plasma/contents/code/Channel.py:413 msgid "Presets" msgstr "ПредуÑтановки" #: plasma/contents/code/Channel.py:415 plasma/contents/code/SinkMbeqUI.py:294 #: gtk/ContextMenu.py:260 msgid "Save" msgstr "Сохранить" #: plasma/contents/code/Channel.py:420 gtk/ContextMenu.py:265 msgid "Save As..." msgstr "Сохранить как..." #: plasma/contents/code/Channel.py:434 gtk/ContextMenu.py:284 msgid "Effect" msgstr "Эффект" #: plasma/contents/code/MediaPlayerUI.py:206 msgid "Show position" msgstr "Показывать позицию воÑпроизведениÑ" #: plasma/contents/code/SinkInputUI.py:48 #: plasma/contents/code/SinkMbeqUI.py:131 gtk/ContextMenu.py:118 msgid "Disconnect/kill" msgstr "Отключить/завершить" #: plasma/contents/code/SinkInputUI.py:56 #: plasma/contents/code/SourceOutputUI.py:53 gtk/ContextMenu.py:148 msgid "Move To" msgstr "ПеремеÑтить в" #: plasma/contents/code/SinkInputUI.py:95 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:305 msgid "Event Sounds" msgstr "Звуки уведомлений" #: plasma/contents/code/SinkInputUI.py:99 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:309 msgid "Flash Player" msgstr "Flash Player" #: plasma/contents/code/SinkInputUI.py:103 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:313 msgid "Chromium Browser" msgstr "Браузер Chromium" #: plasma/contents/code/SinkInputUI.py:107 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:317 msgid "Event Sound" msgstr "Звуки уведомлений" #: plasma/contents/code/SinkInputUI.py:109 #: plasma/contents/code/veromixcommon/PulseProxyObjects.py:319 msgid "Voice Output" msgstr "ГолоÑ" #: plasma/contents/code/SinkMbeqUI.py:279 msgid "Name" msgstr "" #: plasma/contents/code/SinkMbeqUI.py:290 msgid "Cancel" msgstr "" #: plasma/contents/code/SinkUI.py:39 msgid "Default Sink" msgstr "Ðудиовыход по умолчанию" #: plasma/contents/code/SinkUI.py:53 msgid "Uncombine" msgstr "Разъеденить" #: plasma/contents/code/SinkUI.py:61 gtk/ContextMenu.py:244 msgid "Add Effect" msgstr "Добавить Ñффект" #: plasma/contents/code/VeroMix.py:101 msgid "Playback" msgstr "ВоÑпроизведение" #: plasma/contents/code/VeroMix.py:102 msgid "Record" msgstr "ЗапиÑÑŒ" #: plasma/contents/code/VeroMix.py:125 msgid "" "There is a problem with the backgroud-" "service. " "
  • If you just " "upgraded try killing the process named: VeromixServiceMain.py and relaunch " "this plasmoid
  • " "
  • If you don't know how to do that consider rebooting

See wiki for more " "details (right click and copy url)." msgstr "" "Обнаружена проблема Ñ Ñ„Ð¾Ð½Ð¾Ð²Ñ‹Ð¼ " "процеÑÑом. " "
  • ЕÑли вы " "только что обновилиÑÑŒ, попробуйте завершить процеÑÑ Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ " "VeromixServiceMain.py и перезапуÑтить Ñтот плазмоид
  • ЕÑли вы не " "знаете как Ñто Ñделать, проÑто перезаргузитеÑÑŒ

Детали в вики " "(Ñкопируйте Ð°Ð´Ñ€ÐµÑ Ð¸Ð· контекÑтного меню)." #: plasma/contents/code/main.py:59 msgid "Veromix is a mixer for the Pulseaudio sound server. " msgstr "Veromix — Ñто микшер Ð´Ð»Ñ Ð·Ð²ÑƒÐºÐ¾Ð²Ð¾Ð³Ð¾ Ñервера Pulseaudio." #: plasma/contents/code/main.py:142 plasma/contents/code/main.py:409 msgid "Veromix volume up" msgstr "Veromix — увеличить громкоÑть" #: plasma/contents/code/main.py:147 plasma/contents/code/main.py:414 msgid "Veromix volume down" msgstr "Veromix — уменьшить громкоÑть" #: plasma/contents/code/main.py:152 msgid "Veromix toggle mute" msgstr "Veromix — включить или выключить звук" # Ðе уверен что Ñто такое #: plasma/contents/code/main.py:160 msgid "Main Volume" msgstr "ОÑновной канал" #: plasma/contents/code/main.py:278 msgid "Appearance" msgstr "Внешний вид" #: plasma/contents/code/main.py:298 msgid "Media Player Controls" msgstr "Управление проигрывателÑми" #: plasma/contents/code/main.py:324 msgid "Max volume value" msgstr "МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð³Ñ€Ð¾Ð¼ÐºÐ¾Ñть" #: plasma/contents/code/main.py:330 msgid "Mute if volume reaches zero" msgstr "Выключать звук при уменьшении громкоÑти до нулÑ" #: plasma/contents/code/main.py:334 msgid "Sound Card Profiles" msgstr "Профили звуковых карт" #: plasma/contents/code/main.py:356 msgid "Pulseaudio" msgstr "Pulseaudio" #: plasma/contents/code/main.py:363 msgid "" "LADSPA is a standard for handling audio filters and effects. Every linux " "software archive offers a large number of effects - search for LADSPA to get " "more. Not every effect is supported by Pulseaudio and others " "simple don't make sense (or create only noise).

The " "following list shows all available effects on your system: Only checked " "effects will appear in the context-menu." msgstr "" "LADSPA ÑвлÑетÑÑ Ñтандартом Ð´Ð»Ñ Ð°ÑƒÐ´Ð¸Ð¾-фильтров и Ñффектов. Ð’ любом " "репозитории пакетов Ð´Ð»Ñ Linux вы Ñможете найти множеÑтво Ñффектов по " "ключевому Ñлову LADSPA. Ðе вÑе Ñффекты поддерживаютÑÑ PulseAudio, а " "некоторые проÑто не имеют ÑмыÑла (или производÑÑ‚ иÑключительно шум).

Ð’ ÑпиÑке ниже предÑтавленны вÑе Ñфекты уÑтановленные в вашей ÑиÑтеме. " "Только отмеченные Ñффекты будут доÑтупны в контекÑтном меню." #: plasma/contents/code/main.py:368 msgid "" "

Warning: Cannot find the executables 'listplugins' and " "'analyseplugin' which are required for dynamically detecting installed " "effects.
In OpenSUSE, Fedora and Arch Linux the package " "is named 'ladspa', in Debian/Ubuntu 'ladspa-sdk'.

" msgstr "" "

Предупреждение: Ðе найдены иÑполнÑемые файлы 'listplugins' " "и 'analyseplugin', которые необходимы Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка уÑтановленных Ñффектов.
Ð’ OpenSUSE, Fedora и Arch Linux пакет называетÑÑ 'ladspa', Ð’ " "Debian/Ubuntu — 'ladspa-sdk'.

" #: plasma/contents/code/main.py:377 msgid "Enable LADSPA effects." msgstr "ИÑпользовать Ñффекты LADSPA" #: plasma/contents/code/main.py:398 msgid "Effects / Equalizer" msgstr "Эффекты / Эквалайзер" #: plasma/contents/code/main.py:419 msgid "Veromix toggle mute" msgstr "Veromix — включить или выключить звук" #: plasma/contents/code/main.py:423 msgid "Volume Keyboard Shortcuts" msgstr "Глобальные комбинации клавиш" #: gtk/ContextMenu.py:112 #, fuzzy msgid "Default device" msgstr "Ðудиовыход по умолчанию" #: gtk/ContextMenu.py:126 #, fuzzy msgid "Mute" msgstr "Выключен" #: gtk/ContextMenu.py:141 #, fuzzy msgid "Unlock Channels" msgstr "Разблокировать каналы" #: gtk/ContextMenu.py:253 #, fuzzy msgid "Preset" msgstr "ПредуÑтановки" #: gtk/ContextMenu.py:321 #, fuzzy msgid "Save Preset" msgstr "ПредуÑтановки" #: gtk/main.py:42 #, fuzzy msgid "Veromix" msgstr "ÐаÑтроить Veromix" # myself = Ð¼ÐµÐ½Ñ Ð¸Ð»Ð¸ ÑебÑ? # Где вообще будет юзатьÑÑ Ñтот текÑÑ‚? #~ msgid "Please remove and re-add myself" #~ msgstr "ПожалуйÑта, удалите и заново добавьте менÑ" #~ msgid "" #~ "Configuration updated
Because of a known bug in " #~ "KDE 4.4 initialization of Veromix failed.

A " #~ "workaround is now installed.

Please remove " #~ "this applet and add Veromix again to your desktop/panel " #~ "(alternatively you can restart plasma-desktop).

" #~ "Sorry for the inconvenience.

See wiki for more details (right " #~ "click and copy url). " #~ msgstr "" #~ "ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð°
Из-за извеÑтной ошибки KDE " #~ "4.4 Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Veromix не удалаÑÑŒ.

Будет " #~ "иÑпользован коÑтыль.

ПожалуйÑта, удалите " #~ "Ñтот плазмоид и добавьте его Ñнова на вашу панель или рабочий Ñтол " #~ "(также можно перезапуÑтить plasma-desktop).

" #~ "Извините за неудобÑтво.

Детали в вики (Ñкопируйте Ð°Ð´Ñ€ÐµÑ " #~ "из контекÑтного меню). " #~ msgid "Output" #~ msgstr "Вывод" #~ msgid "Enable media player controls" #~ msgstr "Включить управление проигрывателÑми" #~ msgid "mpris2 Mediaplayers" #~ msgstr "Mpris2 проигрыватели" #~ msgid "Use tabs (requires plasma restart)" #~ msgstr "ИÑпользовать табы (нужен перезапуÑк plasma)" veromix/data/presets/0000755000175100017500000000000011766302605013451 5ustar nikkibuveromix/data/presets/Rock.preset0000644000175100017500000000026211766302605015573 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Rock 15 5.3 2.6 2.6 -8.5 -10.5 -11.2 -16.0 -14.7 -6.6 -5.7 -3.0 3.0 6.7 7.3 7.3 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Club.preset0000644000175100017500000000025211766302605015561 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Club 15 -0.2 -0.2 -0.2 -0.2 3.5 3.5 3.5 3.5 3.5 3.5 3.5 2.5 2.5 0.0 0.0 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Soft Rock.preset0000644000175100017500000000026111766302605016466 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Soft Rock 15 2.7 2.7 2.7 1.5 1.5 1.4 0.0 -3.6 -8.0 -7.2 -9.8 -8.9 -6.6 1.4 5.8 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Full Bass.preset0000644000175100017500000000027011766302605016447 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Full Bass 15 -16.0 -16.0 6.5 6.5 6.0 5.5 4.5 1.0 1.0 1.0 -8.0 -10.0 -16.0 -16.0 -20.4 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Ska.preset0000644000175100017500000000025311766302605015413 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Ska 15 -4.5 -8.1 -8.9 -8.5 -8.0 -6.0 0.0 1.5 2.5 2.7 3.2 3.3 5.8 6.4 6.4 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Pop.preset0000644000175100017500000000025211766302605015432 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Pop 15 -3.4 1.7 2.0 3.0 5.0 5.6 6.5 5.2 3.2 1.5 0.0 -2.5 -4.8 -4.8 -3.2 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Techno.preset0000644000175100017500000000025711766302605016121 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Techno 15 5.0 4.0 3.9 3.3 0.0 -4.5 -10.0 -8.9 -8.1 -5.5 -1.5 3.0 6.0 6.1 5.8 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Flat.preset0000644000175100017500000000021211766302605015556 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2.0 Flat 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Full Bass & Treble.preset0000644000175100017500000000027411766302605017757 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Full Bass & Treble 15 4.8 4.8 3.5 2.5 0.0 -7.0 -14.0 -10.0 -10.0 -8.0 1.0 1.0 5.2 7.7 9.5 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Headphones.preset0000644000175100017500000000026111766302605016752 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Headphones 15 3.0 3.0 7.3 7.0 3.0 -1.0 -6.6 -6.3 -4.5 -4.0 1.1 1.2 5.8 7.9 8.8 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Laptop.preset0000644000175100017500000000023311766302605016132 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Laptop 15 -1 -1 -1 -1 -5 -10 -18 -15 -10 -5 -5 -5 -5 0 0 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Classical.preset0000644000175100017500000000027511766302605016577 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Classical 15 -0.2 -0.2 -0.2 -0.2 -0.2 -0.2 -0.2 -0.2 -0.2 -0.2 -0.2 -0.2 -21.0 -21.0 -27.0 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Large Hall.preset0000644000175100017500000000026111766302605016567 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Large Hall 15 7.0 7.0 7.0 3.5 3.0 3.0 3.0 1.5 0.0 -2.0 -3.5 -6.0 -9.0 -1.0 0.0 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Full Treble.preset0000644000175100017500000000027411766302605017000 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Full Treble 15 4.8 -18.6 -18.6 -18.6 -18.6 -10.0 -8.0 -6.5 1.5 1.5 1.5 8.5 10.6 10.6 10.6 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Reggae.preset0000644000175100017500000000025411766302605016070 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Reggae 15 0.0 0.0 0.0 0.0 0.0 -4.5 -10.0 -6.0 0.5 1.0 2.0 4.0 4.0 0.0 0.0 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Party.preset0000644000175100017500000000024711766302605015777 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Party 15 4.8 4.8 4.8 3.1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.5 4.8 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Dance.preset0000644000175100017500000000026111766302605015706 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Dance 15 6.1 4.3 4.3 1.7 1.7 1.7 -0.1 -0.1 -0.1 0.8 -10.7 -14.2 -15.1 -7.2 0.0 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Live.preset0000644000175100017500000000025011766302605015571 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Live 15 -9.0 -5.5 0.0 1.5 2.1 3.4 3.4 3.4 3.4 3.4 3.4 3.4 2.8 1.6 1.8 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/presets/Soft.preset0000644000175100017500000000025011766302605015605 0ustar nikkibumbeq_1197 mbeq Multiband EQ 2 Soft 15 3.2 2.8 0.8 0.9 0.0 -2.4 -4.8 1.5 0.0 1.1 3.0 3.0 5.8 7.8 7.8 50 100 156 220 311 440 622 880 1250 1750 2500 3500 5000 10000 20000 veromix/data/dbus-1/0000755000175100017500000000000011766302605013057 5ustar nikkibuveromix/data/dbus-1/services/0000755000175100017500000000000011766302605014702 5ustar nikkibuveromix/data/dbus-1/services/org.veromix.pulseaudio.qt.service0000644000175100017500000000015211766302605023335 0ustar nikkibu[D-BUS Service] Name=org.veromix.pulseaudio.qt Exec=/usr/share/veromix/dbus-service/veromix-service-qt.py veromix/data/dbus-1/services/org.veromix.pulseaudio.glib.service0000644000175100017500000000015611766302605023632 0ustar nikkibu[D-BUS Service] Name=org.veromix.pulseaudio.glib Exec=/usr/share/veromix/dbus-service/veromix-service-glib.py veromix/data/applications/0000755000175100017500000000000011766302605014452 5ustar nikkibuveromix/data/applications/veromix.desktop0000644000175100017500000000027311766302605017540 0ustar nikkibu [Desktop Entry] Type=Application Exec=veromix Hidden=false NoDisplay=false X-GNOME-Autostart-enabled=true Name=Veromix Comment=Mixer for the PulseAudio sound server (GTK+) Icon=veromix veromix/data/icons/0000755000175100017500000000000011766302605013077 5ustar nikkibuveromix/data/icons/veromix-narrow.png0000644000175100017500000000163211766302605016606 0ustar nikkibu‰PNG  IHDR€€Ã>aËsRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÙ 6 ­¹ÕìIDATxÚíÛ¿kaÀñç.!1à¯Å¡ ‚".¥†æ®ÅBÁ u]…®:ní"(ê¿ Á¹µn*•6w)†€ˆ NJËQJškï³§¹\/¹äû™2¼÷äÍû<÷Þû¾IDô‡ÁÄgrròR6›=×íuÇÇÇûµZíâɲ¬UyqLUD*ŽãÌ·_Si255u' Ã^㘦YÞÞÞþ”dßMÒ×»0 ÏRœndIßéïØ¦Ñhô½ŸÀ)˜•¹¹¹ŽíÆÆÆd}}½¯}å0â"ÍÓÓÓ7ƒ X‘I†0Vk–eE¹®–Édæ·¶¶¾'2Að‚äÖD;'‰=<Æ|àDÊI¤G€ïûK¹\L0î""rADnÄçGÄDÖ}ß_J¬êõúžˆ<"ïÿY–u_DÖbµà8ÎG¶)×l6¥Ùlž¨çCÈqq'}å`ÄQñø&"­c´ÚqÅ·1)•J Ãx¬ª]ÿÀ0Œ}Uýàºî# €GÀ‰‹Å+Ùlö¥ªv}c†ŠÈ—ÃÃÃåF£áj¤z˜ÉdÞ‹È=È\Çwóù| "¯Ø¤qú2ŒÛ1İÙŽvÿGz'44'¹\N;¶óO}"Òë¿i>«êBš³ŸÏçnnnî&º h¿án??¸eYAwëºÎ¨NC³ ôaËsRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÙ ;4æc/IDATxÚíÝ¿K:Àñ×™ „bÖPê ’C M"*­5¹47æÖRs“äÚÐÞ"ýâ(P‹s¿ŒM‹BÐïðù~—ïò©÷]çû¼çcÖ7ö~?õλë4F£ÑHàY>¦€@ €@ €@ €kù™{4 ÙÛÛ“^¯÷ãç†B!)‹²ººÊ'€[•J%¥ÅéõzR*•ظU»Ý–V«eiŒV«%ív›ÜèùùY«qÀaªý¿5€@à8Àø$“É¿>æîîŽ&Q:–\.÷×ÇE£Q©V«l@ ¸n ßïËp8ôü$~||Ø6ÎÛÛÛÏÞÁ>ŸƒAgFrpp •J…·ö÷÷•ž·±±!‡‡‡b†3›€z½Îâk¤R©H½^wnàââ‚Y׌êš(ðøøÈŒkFuM”è÷û̸fT×D)€ÙÙYf\3ªk¢ÀÒÒ3®Õ5Q “ÉH `Ö5$“É8w ‹I±X”óósf_þ\ÊuyyiyœT*% ?~ÞúúºÄb1çøïŦR)Vÿ߯`vÏç%N;úÚ9àq@ð2®ú¥};G›à^ÓÓÓZC›ŸŸ×jpX<Ó4-aš¦Äãqp«B¡ ~¿Ú·j¿ß/…Ba,¯ÛàÇ£íÓív•®Ì ƒ‡ | €àן  òòòòóÃh4ªôïT ‰÷÷wÙÞÞ–ûû{¥ç¯­­ÉÑÑ‘§#põ& \.+/¾ˆH­V“››öÜêúúÚòWWWàVvÜZõõõ•ܪÓéh1Œ 19€güßwþ­ªÓéÈíí-+?i„ÃáoݳÛí›ö†Ã¡<==õÅÛq—ÒÏÏOyxxpõ"F£Qñù|Î0eggGšÍ¦ëßFC677]ý7,//ËÉɉRJÙÔjµ‰XüIÑl6¥V«9·`ÇY8ØKuM”ÇïÛáwÖD)€¯¯/f\3ªk¢ÀÜÜ3®Õ5Q `ee…׌êš(Íf% 1ëš…B’Íf;‰DäøøXªÕêX/Ê8==•Á``i Ó4•'O†aH.—“H$â\""‰DB‰ÄXÿø³³3Ë,..Êîî®g?=8àq@𲉹"¨ÛíJ¹\þÖã0ˆèñkÜl@ GLMM±‚^`ffF‹1`L¬ÞœQäÏõtàRvüh•Ó?ÒD6ÚÚÚ²tj:ŸÏK2™ôtÜ(’@€@ €@ €@p©ù-×°U>êIEND®B`‚veromix/data/icons/veromix.png0000644000175100017500000000225711766302605015304 0ustar nikkibu‰PNG  IHDR€€Ã>aËsRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÙ ;4æc/IDATxÚíÝ¿K:Àñ×™ „bÖPê ’C M"*­5¹47æÖRs“äÚÐÞ"ýâ(P‹s¿ŒM‹BÐïðù~—ïò©÷]çû¼çcÖ7ö~?õλë4F£ÑHàY>¦€@ €@ €@ €kù™{4 ÙÛÛ“^¯÷ãç†B!)‹²ººÊ'€[•J%¥ÅéõzR*•ظU»Ý–V«eiŒV«%ív›ÜèùùY«qÀaªý¿5€@à8Àø$“É¿>æîîŽ&Q:–\.÷×ÇE£Q©V«l@ ¸n ßïËp8ôü$~||Ø6ÎÛÛÛÏÞÁ>ŸƒAgFrpp •J…·ö÷÷•ž·±±!‡‡‡b†3›€z½Îâk¤R©H½^wnàââ‚Y׌êš(ðøøÈŒkFuM”è÷û̸fT×D)€ÙÙYf\3ªk¢ÀÒÒ3®Õ5Q “ÉH `Ö5$“É8w ‹I±X”óósf_þ\ÊuyyiyœT*% ?~ÞúúºÄb1çøïŦR)Vÿ߯`vÏç%N;úÚ9àq@ð2®ú¥};G›à^ÓÓÓZC›ŸŸ×jpX<Ó4-aš¦Äãqp«B¡ ~¿Ú·j¿ß/…Ba,¯ÛàÇ£íÓív•®Ì ƒ‡ | €àן  òòòòóÃh4ªôïT ‰÷÷wÙÞÞ–ûû{¥ç¯­­ÉÑÑ‘§#põ& \.+/¾ˆH­V“››öÜêúúÚòWWWàVvÜZõõõ•ܪÓéh1Œ 19€güßwþ­ªÓéÈíí-+?i„ÃáoݳÛí›ö†Ã¡<==õÅÛq—ÒÏÏOyxxpõ"F£Qñù|Î0eggGšÍ¦ëßFC677]ý7,//ËÉɉRJÙÔjµ‰XüIÑl6¥V«9·`ÇY8ØKuM”ÇïÛáwÖD)€¯¯/f\3ªk¢ÀÜÜ3®Õ5Q `ee…׌êš(Íf% 1ëš…B’Íf;‰DäøøXªÕêX/Ê8==•Á``i Ó4•'O†aH.—“H$â\""‰DB‰ÄXÿø³³3Ë,..Êîî®g?=8àq@𲉹"¨ÛíJ¹\þÖã0ˆèñkÜl@ GLMM±‚^`ffF‹1`L¬ÞœQäÏõtàRvüh•Ó?ÒD6ÚÚÚ²tj:ŸÏK2™ôtÜ(’@€@ €@ €@p©ù-×°U>êIEND®B`‚veromix/data/icons/veromix.svg0000644000175100017500000000676411766302605015326 0ustar nikkibu image/svg+xml veromix/Makefile0000644000175100017500000000565111766302605012522 0ustar nikkibu# Makefile SHELL := sh -e VERSION := $$(awk -F= '/X-KDE-PluginInfo-Version/ { print $$2 }' plasma/metadata.desktop) DATE := $$(date +"%Y-%m-%d") _VEROMIX_SHARED := $(DESTDIR)/usr/share/veromix all: build build: sh Messages.sh install: install-plasmoid install-gtk install-service: mkdir -p $(_VEROMIX_SHARED) cp -a dbus-service common $(_VEROMIX_SHARED) mkdir -p $(_VEROMIX_SHARED)/data cp -a data/icons data/presets $(_VEROMIX_SHARED)/data mkdir -p $(DESTDIR)/usr/share/dbus-1/services cp -a data/dbus-1/services/* $(DESTDIR)/usr/share/dbus-1/services mkdir -p $(DESTDIR)/usr/share/icons ln -s ../veromix/data/icons/veromix.png $(DESTDIR)/usr/share/icons/veromix.png mkdir -p $(DESTDIR)/usr/share/locale cp -a data/locale/* $(DESTDIR)/usr/share/locale -find $(DESTDIR)/usr/share/locale -name "*.po" | xargs rm -f install-plasmoid: install-service mkdir -p $(DESTDIR)/usr/share/kde4/apps/plasma/plasmoids/veromix-plasmoid cp -a plasma/contents plasma/metadata.desktop $(DESTDIR)/usr/share/kde4/apps/plasma/plasmoids/veromix-plasmoid mkdir -p $(DESTDIR)/usr/share/kde4/services ln -s ../apps/plasma/plasmoids/veromix-plasmoid/metadata.desktop $(DESTDIR)/usr/share/kde4/services/plasma-widget-veromix.desktop ln -sf ../../../../../../../veromix/common $(DESTDIR)/usr/share/kde4/apps/plasma/plasmoids/veromix-plasmoid/contents/code/veromixcommon ln -sf ../../../../../../veromix/data/icons $(DESTDIR)/usr/share/kde4/apps/plasma/plasmoids/veromix-plasmoid/contents/icons ln -sf ../../../../../../locale $(DESTDIR)/usr/share/kde4/apps/plasma/plasmoids/veromix-plasmoid/contents/locale ln -sf ../../../../../veromix/dbus-service $(DESTDIR)/usr/share/kde4/apps/plasma/plasmoids/veromix-plasmoid/dbus-service install-gtk: install-service mkdir -p $(_VEROMIX_SHARED) cp -a gtk $(_VEROMIX_SHARED) mkdir -p $(DESTDIR)/usr/share/applications cp -a data/applications/veromix.desktop $(DESTDIR)/usr/share/applications plasma-pkg: clean build cd plasma && zip -r ../../tmp-veroimx.plasmoid . cd .. mv ../tmp-veroimx.plasmoid ../$(DATE)_$(VERSION)_veromix.plasmoid local-gtk: clean build echo "#!/bin/sh\ngtk/main.py" > veromix.sh chmod a+x veromix.sh echo "REQUIREMENTS:\n- python3-dbus\n- python3-gi\n- pulseaudio\n- python-xdg (Optional)\n- ladspa-sdk, swh-plugins (Optional)\n\n" > README echo "Configuration:\nSome basic configuration options can be found in ~/.config/veromix/veromix.conf" >> README tar cfzv ../$(DATE)_$(VERSION)_veromix-gtk.tar.gz --exclude=.git --exclude=debian --exclude="Makefile" --exclude="Messages.sh" --exclude="plasma" --exclude="contrib" ../$(shell basename $(CURDIR)) rm veromix.sh README clean: -find . -name '*~' | xargs rm -f -find . -name '*.pyc' | xargs rm -f -find . -name '__pycache__' | xargs rm -rf -find data/locale -name "*.mo" | xargs rm -f distclean: clean dist: clean tar cfzv ../veromix_$(VERSION).orig.tar.gz --exclude=.git --exclude=debian --exclude="contrib" ../$(shell basename $(CURDIR)) veromix/Messages.sh0000755000175100017500000000207311766302605013163 0ustar nikkibu#! /usr/bin/env bash ## # copied from now-rocking plasmoid ## NAME="veromix" XGETTEXT="xgettext -ki18n" EXTRACTRC="extractrc" if [ "x$1" != "x" ]; then if [ ! -d "data/locale/$1" ]; then mkdir -p "data/locale/$1/LC_MESSAGES" fi fi $EXTRACTRC plasma/contents/ui/*.ui plasma/contents/config/*.xml > ./rc.py $XGETTEXT rc.py plasma/contents/code/*.py plasma/contents/code/veromixcommon/*.py gtk/*.py -o "$NAME.pot" sed -e 's/charset=CHARSET/charset=UTF-8/g' -i "$NAME.pot" for d in data/locale/*; do if [ -d "$d" ]; then if [ -f "$d/LC_MESSAGES/$NAME.po" ]; then echo "Merging $NAME.pot -> $d/LC_MESSAGES/$NAME.po ..." msgmerge -U "$d/LC_MESSAGES/$NAME.po" "$NAME.pot" else echo "Copying $NAME.pot -> $d/LC_MESSAGES/$NAME.po ..." cp "$NAME.pot" "$d/LC_MESSAGES/$NAME.po" fi fi done for d in data/locale/*; do echo "Making $d/LC_MESSAGES/$NAME.mo ..." msgfmt "$d/LC_MESSAGES/$NAME.po" -o "$d/LC_MESSAGES/$NAME.mo" done find . -name '*~' | xargs rm -f rm -f rc.py rm -f $NAME.pot veromix/Changelog0000644000175100017500000001651711766302605012677 0ustar nikkibu0.18.3 - 14.6.2012 - fix encoding problem in PulseSource (Fix Debian bug #677445). 0.18.2 - 14.6.2012 - fix encoding problem in PulseSource (Issue 101). 0.18.1 - 12.6.2012 - fix icon install - fix path of veromix-service-qt.py 0.18.0 - 11.6.2012 - python3 compatibility. - New sourcecode structure, new makefile. - Big refactoring to share code with the gtk frontend. - Update russian, italian and german translations. - Enable volume meter via context menu. - Do not name monitor-sinks created by veromix (always ascii->utf8 problems). - Renamed VeromixServiceMain.py to veromix-service-qt.py 0.17.0 - 25.4.2012 - LADSPA preset support (load, save) - file format compatible with python-equalizer. - Dynamically detect installed LADSPA effects. - Remove "Add Effect" Button. Choose effects and presets (to be added) via context-menu. - Initial support for keyboard navigation (Tab and Shift-T between streams, change volume with arrwos). 0.16.2 - 4.4.2012 - Invert/fix the behaviour of horizontal scrolling over the icon in the systemtray/panel. - Fix: Plasmoid icon changes its size and position when plasmoid settings is changed. - Disable background chooser in settings dialog for popup applets. - Disable popup-mode checkbox in settings dialog for planar applets. 0.16.1 - 17.2.2012 - fix add effects button not clickable 0.16.0 - 13.2.2012 - Replace analog meter with vertical meter below slider. - Adding an option to autostart meters. - Combine sinks by dragging on sink on another. - Catch expections when veromix service does not startup. - Ticks below sliders instead of above and below, when max volume >100. - New option to show values (precentage) of each slider. - New serbian translations. - Added minimum size, fixing issue 28 . - Changed default background from transparent to standard. - Changed meters to hidden by default. - Fix: Icon of sink-input sometimes shows the icon of another application. 0.15.1 - 5.2.2012 - Make sure we got unicode strings for ports before displaying them. - Fix bad looking label in unlocked view. - switch from svn to git. 0.15.0 - 30.1.2012 - Support for changing ports of sinks by Jonathan Challinger. Fixes Issue 85: Cannot switch microphone inputs. - Update italian translation. 0.14.1 - 28.1.2012 - Fix: Record streams no longer showing up in veromix. - Rearranging context menu items. - Updating translation files. 0.14.0 - 28.1.2012 - Adding right click context menu. - The button on the right opens the context menu. - Moving all channel related settings to the context menu (dropping in channel checkbox and/or comboboxes). - Adding a configuration option to hide the context menu button. - Adding a fallback for the brooken mpris support in deadbeef. 0.13.2 - 13.1.2012 - fix: Dropdownbox of audiooutput lies not on top of the sliders (Issue 37). - enable "apply" button when the user changes settings in the settings dialog. - add an option to disable album art (fixes issue 75). 0.13.1 - 14.9.2012 - fix sorting of sources - fix sink-output selection in combobox - fix label of tooltip - improve label position for bigger fonts 0.13.0 - 26.7.2011 - adding support for ladspa effects (equalizer an others) - changed sorting of sinks (alphabetically) - fix regression: Default sink not detected (no monochrom icons) - fix sink inputs having the wrong stream or application name - fix expander button below meter - setting better titles for some known applications (patch by Kai Uwe Broulik) 0.12.1 - 25.6.2011 - fix zerodevision in media player controls - updating italian translations - installed a workaround to fallback on python2 where python3 is default. 0.12.0 - 13.6.2011 - better settings-ui for mediaplayer controls - adding position, length and seek to mediaplayer controls - workaround title for "knotify" and "npviewer.bin" (patch by Bajk...@googlemail.com) - new configuration option: "Show tooltip/notifications" 0.11.2 - 28.3.2011 - fix switching bluetooth profiles - improve layout of settings widgets (patch by proDOOM...@gmail.com) - improve packaging 0.11.1 - 21.3.2011 - added italian translations 0.11.0 - 19.3.2011 - sound card profiles support (aka quick switching between hdmi and regular) - show slider ticks if max volume is > 100% - tabbed view: Fixed not correctly removed meters - new russian translations 0.10.1 - 14.3.2011 - fix issue 39: Settings in veromix are always default - workaround nowplaying DataEngine returns invalid (and not existing) player named "players" 0.10 - 12.3.2011 - expander button - new config options - show/hide meter - ability to turn the master volume above 100% (like gnome applet) - mute if volume reaches zero - configure global shortcuts - only connect peak-meters if requested by the user (click on meter) - saves CPU cycles 0.9.1 - 20.12.2010 - new UI - per channel volume control (mono, stereo, dolby 5.1 ... ) - better mpris2 support (don't poll - listen for notifications) - UI components are no longer deleted, they are stored and reused - improved resizing behaviour 0.9.0 - 03.12.2010 - nowplaying integration - localization - more configuration options 0.8.7 - 26.11.2010 - bugfix - merged configuration dialogs - improved error-messages with link to the wiki 0.8.6 - 23.11.2010 - global keyboard shortcuts 0.8.5 - 19.11.2010 - monochrome icons (kde 4.5) - configuration interface (more to come there) - autohide - panel icon shows 4 states: mute low medium high - tooltip over panel icon - better scrolling behaviour 0.8.4 - 25.10.2010 - fix regression (SinkInputs not appearing) 0.8.3 - 25.10.2010 - fix SinkInputs without session-id (mpd) - fix set volume of Sinks/SinkInputs with more than 2 channels 0.8.2 - 22.10.2010 - Panel icon: mute default sink with mouse middle button - Panel icon: increase/decrease volume of default sink with mouse wheel 0.8.1 - packaging fixes 0.8 - 2.10.2010 - control input devices (recording) - sources are only shown if at least one application is recording - set default output device - kill streams - information dialog with hardware information - don't show scrollbars when poping up from the panel - implemented a workaround for kde 4.4 compatibility - cleanup plasmoid-package Release Notes: - clicking on the meter-indicator expands the channel and offers advanced settings (kill, set as default): I' am looking for a better solution 0.7.6 - 21.08.2010 - bugfix: remove output device correctly 0.7.5 - 18.08.2010 - create directory ~/.local/share/dbus-1/services/ if it does not exist - mute-button shows application icon when muted 0.7.4 - 03.08.2010 - changed ServiceTypes=Plasma/Applet;Plasma/PopupApplet - use less space 0.7.3 - 03.08.2010 - support multiple plasmoid instances - resize sliders after a remove 0.7.2 - 27.07.2010 - dbus-initialization improved (somtimes crashed plasma-desktop). Working on support for multiple plasmoids.. 0.7.1 - 27.07.2010 - make the dbus-service executable 0.7 - 27.07.2010 - fixed crash (a dbus-service is started to gather info from pulseaudio) - improved icon-lookup - store size of popup 0.6 - 05.06.2010 - Ordering of sources and targets: Sources are always above their correct target/ouput - Switch audio-target on the fly: Drag a source to the new target - Mute is now an IconWidget (was a PushButton) - looks differently 0.5 - 30.3.2010 - themed label-color (dark themes) - better utf8 handling 0.4 - 23.3.2010 - place it in your systemtray 0.3 - 23.03.2010 - PopupApplet -> place it in your panel 0.2 - 7.12.2009 - Initial Release veromix/dbus-service/0000755000175100017500000000000011766302605013446 5ustar nikkibuveromix/dbus-service/veromix-service-glib.py0000755000175100017500000000277011766302605020073 0ustar nikkibu#!/usr/bin/python3 # -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import signal import sys import dbus import dbus.service import dbus.mainloop.glib from gi.repository import GObject from pulseaudio.PulseAudio import * from VeromixDbus import * from VeromixEvent import * from Pa2dBus import * if __name__ == '__main__': GObject.threads_init() signal.signal(signal.SIGINT, signal.SIG_DFL) mainloop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) conn = dbus.SessionBus() name = dbus.service.BusName("org.veromix.pulseaudio.glib", conn) dbus.set_default_main_loop(mainloop) pulse = PulseAudio() bus = VeromixDbus(pulse,conn) i = Pa2dBus(bus, pulse) event_processor = VeromixEvent(i) pulse.set_receiver(event_processor) pulse.start_pulsing() print ("starting main loop") GObject.MainLoop().run() veromix/dbus-service/Pa2dBus.py0000644000175100017500000001457211766302605015271 0ustar nikkibu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import signal import datetime import dbus import dbus.service #from PyQt4.QtCore import QObject #from PyQt4.QtCore import SIGNAL #from PyQt4 import QtCore from VeromixUtils import * ### # Pass info/signals from PA to DBUS ### class Pa2dBus(): def __init__(self, veromixdbus, pulseaudio): self.dbus = veromixdbus self.pulse = pulseaudio self.LIMIT_SEND_METER_ENABLED = False self.METER_SEND_MSECS = 100000 #micro self.last_volume_meter_send = datetime.datetime.now() self.last_source_meter_send = datetime.datetime.now() # self.connect(self.pulse, SIGNAL("sink_info(PyQt_PyObject)"), self.on_sink_info) # self.connect(self.pulse, SIGNAL("sink_remove(int)"), self.on_remove_sink) # self.connect(self.pulse, SIGNAL("sink_input_info(PyQt_PyObject)"), self.on_sink_input_info) # self.connect(self.pulse, SIGNAL("sink_input_remove(int)"), self.on_remove_sink_input) # self.connect(self.pulse, SIGNAL("source_info(PyQt_PyObject)"), self.on_source_info) # self.connect(self.pulse, SIGNAL("source_remove(int)"), self.on_remove_source) # self.connect(self.pulse, SIGNAL("source_output_info(PyQt_PyObject)"), self.on_source_output_info) # self.connect(self.pulse, SIGNAL("source_output_remove(int)"), self.on_remove_source_output) # self.connect(self.pulse, SIGNAL("volume_meter_sink_input(int, float )"), self.on_volume_meter_sink_input) # self.connect(self.pulse, SIGNAL("volume_meter_sink(int, float )"), self.on_volume_meter_sink) # self.connect(self.pulse, SIGNAL("volume_meter_source(int, float )"), self.on_volume_meter_source) # self.connect(self.pulse, SIGNAL("card_info(PyQt_PyObject)"), self.on_card_info) # self.connect(self.pulse, SIGNAL("card_remove(int)"), self.on_remove_card) # self.connect(self.pulse, SIGNAL("module_info(int, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)"), self.on_module_info) def on_source_info(self, sink): index = int(sink.index) name = in_unicode(sink.name) muted = (sink.mute == 1) volume = sink.volume.getVolumes() active_port = sink.active_port ports = sink.ports props = sink.propDict() if "device.class" in props.keys() and props["device.class"] == "monitor": return self.dbus.source_info(index, name, muted, volume, props, ports, active_port) def on_source_output_info(self, sink): index = int(sink.index) name = in_unicode(sink.name) if sink.resample_method != "peaks": self.dbus.source_output_info(index, name, sink.propDict()) def on_sink_input_info(self, sink): index = int(sink.index) name = in_unicode(sink.name) muted = (sink.mute == 1) volume = sink.volume.getVolumes() self.dbus.sink_input_info(index, name, muted, volume, sink.propDict()) def on_sink_info(self, sink): index = int(sink.index) name = in_unicode(sink.name) muted = (sink.mute == 1) volume = sink.volume.getVolumes() self.dbus.sink_info(index, name, muted, volume, sink.propDict(), sink.ports, sink.active_port) def on_card_info(self, card_info): self.dbus.card_info(card_info.index, card_info.name, card_info.properties(), card_info.active_profile_name(), card_info.profiles_dict()) def on_remove_card(self, index): self.dbus.card_remove(index) def on_remove_sink(self, index): self.dbus.sink_remove(index) def on_remove_sink_input(self, index): self.dbus.sink_input_remove(index) def on_remove_source(self, index): self.dbus.source_remove(int(index)) def on_remove_source_output(self, index): self.dbus.source_output_remove(int(index)) def on_volume_meter_sink_input(self, index, level): if level == level: if self.LIMIT_SEND_METER_ENABLED: now = datetime.datetime.now() # FIXME limit dbus spam but this solution could always prevent the same source from transmitting if (now - self.last_volume_meter_send).microseconds > self.METER_SEND_MSECS : self.last_volume_meter_send = now self.dbus.volume_meter_sink_input(int(index),level) else: self.dbus.volume_meter_sink_input(int(index),level) def on_volume_meter_sink(self, index, level): if level == level: if self.LIMIT_SEND_METER_ENABLED: now = datetime.datetime.now() # FIXME limit dbus spam but this solution could always prevent the same source from transmitting if (now - self.last_volume_meter_send).microseconds > self.METER_SEND_MSECS : self.last_volume_meter_send = now self.dbus.volume_meter_sink(int(index),level) else: self.dbus.volume_meter_sink(int(index),level) def on_volume_meter_source(self, index, level): if level == level: if self.LIMIT_SEND_METER_ENABLED: now = datetime.datetime.now() # FIXME limit dbus spam but this solution could always prevent the same source from transmitting if (now - self.last_source_meter_send).microseconds > self.METER_SEND_MSECS : self.last_source_meter_send = now self.dbus.volume_meter_source(int(index),level) else: self.dbus.volume_meter_source(int(index),level) def on_module_info(self, index, name, argument, n_used, auto_unload): self.dbus.module_info(index, in_unicode(name), in_unicode(argument), in_unicode(n_used), in_unicode(auto_unload)) veromix/dbus-service/VeromixEvent.py0000644000175100017500000000437311766302605016462 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . class VeromixEvent(): def __init__(self, target): self.target = target def sink_input_info(self, sink): self.target.on_sink_input_info(sink) def sink_input_remove(self, int_index): self.target.on_remove_sink_input(int_index) def volume_meter_sink_input(self, int_index, float_value): self.target.on_volume_meter_sink_input(int_index, float_value) def sink_info(self, sink): self.target.on_sink_info(sink) def sink_remove(self, int_index): self.target.on_remove_sink(int_index) def volume_meter_sink(self, int_index, float_value): self.target.on_volume_meter_sink(int_index, float_value) def source_output_info(self, source): self.target.on_source_output_info(source) def source_output_remove(self, int_index): self.target.on_remove_source_output(int_index) def source_info(self, source): self.target.on_source_info(source) def source_remove(self, int_index): self.target.on_remove_source(int_index) def volume_meter_source(self, int_index, float_value): self.target.on_volume_meter_source(int_index, float_value) def card_info(self, card): self.target.on_card_info(card) def card_remove(self, card_index): self.target.on_remove_card(card_index) def client_remove(self, int_index): # FIXME pass def module_info(self, int_index, name, argument, n_used_string, autounload_string): self.target.on_module_info(int_index, name, argument, n_used_string, autounload_string) veromix/dbus-service/VeromixDbus.py0000644000175100017500000002151611766302605016274 0ustar nikkibu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import signal import sys import dbus import dbus.service #from PulseAudio import * from pulseaudio.PulseVolume import * ### # The DBUS interface we offer ### class VeromixDbus(dbus.service.Object): #interface = "org.veromix.pulseaudioservice" def __init__(self, pulseaudio, conn , object_path='/org/veromix/pulseaudio'): dbus.service.Object.__init__(self, conn, object_path) self.pulse = pulseaudio self.VERSION = 15 @dbus.service.signal(dbus_interface="org.veromix.notification", signature='') def veromix_startup(self): pass ## ----------------------------- source ----------------------------------------- @dbus.service.signal(dbus_interface="org.veromix.notification", signature='isba{ia{si}}a{ss}a{ss}s') def source_info(self, index, name , mute, volume , dictProperties, ports, active_port): pass @dbus.service.signal(dbus_interface="org.veromix.notification", signature='d') def source_remove(self, index ): pass @dbus.service.signal(dbus_interface="org.veromix.notification", signature='id') def volume_meter_source(self, index,value ): pass @dbus.service.method("org.veromix.pulseaudio", in_signature='s', out_signature='') def set_default_source(self, index): self.pulse.pulse_set_default_source(index) ## ----------------------------- source output----------------------------------------- @dbus.service.signal(dbus_interface="org.veromix.notification", signature='isa{ss}') def source_output_info(self, index, name , dictProperties): pass @dbus.service.signal(dbus_interface="org.veromix.notification", signature='i') def source_output_remove(self, index ): pass @dbus.service.method("org.veromix.pulseaudio", in_signature='ib', out_signature='') def source_mute(self, index, mute): self.pulse.pulse_source_mute(int(index), int(mute)) @dbus.service.method("org.veromix.pulseaudio", in_signature='is', out_signature='') def source_port(self, index, portstr): self.pulse.pulse_set_source_port(int(index), portstr) @dbus.service.method("org.veromix.pulseaudio", in_signature='iai', out_signature='') def source_volume(self, index, vol): self.pulse.pulse_set_source_volume(index, PulseVolume(vol)) @dbus.service.method("org.veromix.pulseaudio", in_signature='ii', out_signature='') def move_source_output(self, index, output): self.pulse.pulse_move_source_output( index, output) @dbus.service.method("org.veromix.pulseaudio", in_signature='is', out_signature='') def toggle_monitor_of_source(self, source_index, named ): self.pulse.pulse_toggle_monitor_of_source( source_index, named) ## -----------------------------sink ----------------------------------------- @dbus.service.signal(dbus_interface="org.veromix.notification", signature='isba{ia{si}}a{ss}a{ss}s') def sink_info(self, index, name , mute, volume , dictProperties, ports, active_port): pass @dbus.service.signal(dbus_interface="org.veromix.notification", signature='i') def sink_remove(self, index ): pass @dbus.service.method("org.veromix.pulseaudio", in_signature='ib', out_signature='') def sink_mute(self, index, mute): self.pulse.pulse_sink_mute(int(index), int(mute)) @dbus.service.method("org.veromix.pulseaudio", in_signature='is', out_signature='') def sink_port(self, index, portstr): self.pulse.pulse_set_sink_port(int(index), portstr) @dbus.service.method("org.veromix.pulseaudio", in_signature='iai', out_signature='') def sink_volume(self, index, vol): self.pulse.pulse_set_sink_volume(int(index), PulseVolume(vol)) @dbus.service.signal(dbus_interface="org.veromix.notification", signature='id') def volume_meter_sink(self, index,value ): pass @dbus.service.method("org.veromix.pulseaudio", in_signature='is', out_signature='') def toggle_monitor_of_sink(self, sink_index,named ): self.pulse.pulse_toggle_monitor_of_sink( sink_index, named) @dbus.service.method("org.veromix.pulseaudio", in_signature='s', out_signature='') def set_default_sink(self, index): self.pulse.pulse_set_default_sink(index) @dbus.service.method("org.veromix.pulseaudio", in_signature='ii', out_signature='') def create_combined_sink(self, fist_sink_index, second_sink_index): self.pulse.create_combined_sink(fist_sink_index, second_sink_index) ## -----------------------------sink input----------------------------------------- @dbus.service.signal(dbus_interface="org.veromix.notification", signature='isba{ia{si}}a{ss}') def sink_input_info(self, index, name , mute, volume , dictProperties): pass @dbus.service.signal(dbus_interface="org.veromix.notification", signature='i') def sink_input_remove(self, index ): pass @dbus.service.method("org.veromix.pulseaudio", in_signature='i', out_signature='') def sink_input_kill(self, index): self.pulse.pulse_sink_input_kill(int(index)) @dbus.service.method("org.veromix.pulseaudio", in_signature='ib', out_signature='') def sink_input_mute(self, index, mute): self.pulse.pulse_sink_input_mute(int(index), int(mute)) @dbus.service.method("org.veromix.pulseaudio", in_signature='iai', out_signature='') def sink_input_volume(self, index, vol): v = PulseVolume(vol) self.pulse.pulse_set_sink_input_volume( index , v) @dbus.service.method("org.veromix.pulseaudio", in_signature='ii', out_signature='') def move_sink_input(self, index, output): self.pulse.pulse_move_sink_input( index, output) @dbus.service.signal(dbus_interface="org.veromix.notification", signature='id') def volume_meter_sink_input(self, index,value ): pass @dbus.service.method("org.veromix.pulseaudio", in_signature='iis', out_signature='') def toggle_monitor_of_sinkinput(self, sink_input_index, sink_index, named ): self.pulse.pulse_toggle_monitor_of_sinkinput( sink_input_index, sink_index, named) ## ----------------------------- card info ----------------------------------------- @dbus.service.signal(dbus_interface="org.veromix.notification", signature='isa{ss}sa{sa{ss}}') def card_info(self, index, name , properties, active_profile_name , profiles): pass @dbus.service.signal(dbus_interface="org.veromix.notification", signature='i') def card_remove(self, index ): pass @dbus.service.method("org.veromix.pulseaudio", in_signature='is', out_signature='') def set_card_profile(self, index, value): self.pulse.pulse_set_card_profile(index, value) ## ----------------------------- Modules ----------------------------------------- @dbus.service.signal(dbus_interface="org.veromix.notification", signature='issss') def module_info(self, index, name, argument, n_used, auto_unload): pass @dbus.service.method("org.veromix.pulseaudio", in_signature='iis', out_signature='') def set_ladspa_sink(self, sink_index, module_index, parameters): self.pulse.set_ladspa_sink(sink_index, module_index, parameters) @dbus.service.method("org.veromix.pulseaudio", in_signature='i', out_signature='') def remove_ladspa_sink(self, sink_index): self.pulse.remove_ladspa_sink(sink_index) @dbus.service.method("org.veromix.pulseaudio", in_signature='i', out_signature='') def remove_combined_sink(self, sink_index): self.pulse.remove_combined_sink(sink_index) ## ----------------------------- generic ----------------------------------------- @dbus.service.method("org.veromix.pulseaudio", in_signature='', out_signature='') def requestInfo(self): self.pulse.requestInfo() @dbus.service.method("org.veromix.pulseaudio", in_signature='', out_signature='i') def veromix_service_version(self): return self.VERSION @dbus.service.method("org.veromix.pulseaudio", in_signature='b', out_signature='') def set_autostart_meters(self, aboolean): self.pulse.set_autostart_meters(aboolean) @dbus.service.method("org.veromix.pulseaudio", in_signature='', out_signature='') def veromix_service_quit(self): sys.exit(0) veromix/dbus-service/veromix-service-qt.py0000755000175100017500000000277511766302605017607 0ustar nikkibu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import signal import sys import dbus import dbus.service import dbus.mainloop.qt from PyQt4.QtCore import QCoreApplication from PyQt4 import QtCore from pulseaudio.PulseAudio import * from VeromixDbus import * from VeromixEvent import * from Pa2dBus import * if __name__ == '__main__': app=QtCore.QCoreApplication(sys.argv) signal.signal(signal.SIGINT, signal.SIG_DFL) mainloop = dbus.mainloop.qt.DBusQtMainLoop(set_as_default=True) conn = dbus.SessionBus() name = dbus.service.BusName("org.veromix.pulseaudio.qt", conn) dbus.set_default_main_loop(mainloop) pulse = PulseAudio() bus = VeromixDbus(pulse,conn) i = Pa2dBus(bus, pulse) event_processor = VeromixEvent(i) pulse.set_receiver(event_processor) pulse.start_pulsing() app.exec_() veromix/dbus-service/pulseaudio/0000755000175100017500000000000011766302605015620 5ustar nikkibuveromix/dbus-service/pulseaudio/__init__.py0000644000175100017500000000000011766302605017717 0ustar nikkibuveromix/dbus-service/pulseaudio/PulseCard.py0000644000175100017500000000551211766302605020057 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2011-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from .lib_pulseaudio import * from VeromixUtils import * class CardProfile: def __init__(self, card_info): self.name = in_unicode(card_info.name) self.description = in_unicode(card_info.description) self.n_sinks = int(card_info.n_sinks) self.n_sources = int(card_info.n_sources) self.priority = int(card_info.priority) #print "got profile", self.name, self.description, self.n_sinks, self.n_sources, self.priority def as_dict(self): info = {} info["name"] = in_unicode(self.name) info["description"] = in_unicode(self.description) info["n_sinks"] = in_unicode(self.n_sinks) info["n_sources"] = in_unicode(self.n_sources) info["priority"] = in_unicode(self.priority) return info class CardInfo: def __init__(self, pa_card_info): self.index = int(pa_card_info.index) self.name = in_unicode(pa_card_info.name) self.owner_module = in_unicode(pa_card_info.owner_module) self.driver = in_unicode(pa_card_info.driver) self.n_profiles = int(pa_card_info.n_profiles) self.active_profile = CardProfile(pa_card_info.active_profile[0]) self.proplist_string = in_unicode(pa_proplist_to_string(pa_card_info.proplist)) self.proplist = proplist_to_dict(self.proplist_string) #print self.proplist #self.proplist = pa_card_info.proplist #print "got card", self.index, self.name, self.active_profile self.profiles = [] for index in range(0, self.n_profiles): profile = pa_card_info.profiles[index] if profile: self.profiles.append(CardProfile(profile)) def properties(self): # FIXME info = {} #info["owner_module"] = self.owner_module for key in list(self.proplist.keys()): info[key] = self.proplist[key] return info def active_profile_name(self): return in_unicode(self.active_profile.name) def profiles_dict(self): info = {} for profile in self.profiles: info[profile.name] = profile.as_dict() return info veromix/dbus-service/pulseaudio/PulseAudio.py0000644000175100017500000007521511766302605020256 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys import os import ctypes import random import time from .lib_pulseaudio import * from .PulseSink import PulseSinkInputInfo, PulseSinkInfo from .PulseSource import PulseSourceOutputInfo, PulseSourceInfo from .PulseClient import PulseClientCtypes from .PulseCard import CardInfo from VeromixUtils import in_unicode PA_VOLUME_CONVERSION_FACTOR = 655.36 # A null method that can be given to pulse methods def null_cb(a=None, b=None, c=None, d=None): #print "NULL CB" return class PulseAudio(): def __init__(self): self.initialize_variables() def set_receiver(self, event_receiver): self.receiver = event_receiver def initialize_variables(self): self._context = None self.sinks = {} self.sink_inputs = {} self.sources = {} self.loaded_modules = {} self.monitor_sinks = {} self.monitor_sink_inputs = {} self.monitor_sources = {} self.sink_inputs_to_restore = [] self.module_stream_restore_argument = "" self.default_source_name = "" self.default_sink_name = "" self._null_cb = None self.pa_mainloop_api = None self.pa_mainloop = None self._context_notify_cb = None self._pa_context_subscribe_cb = None self._pa_context_index_cb = None self._pa_stream_request_cb = None self._pa_stream_notify_cb = None self._pa_sink_info_cb = None self._pa_sink_input_info_list_cb = None self._pa_card_info_cb = None self._pa_source_info_cb = None self._pa_source_output_info_cb = None self._pa_client_info_list_cb = None self._pa_module_info_cb = None self.IS_READY = False self._autostart_meters = False self._meter_rate = 10 def start_pulsing(self): self.pa_mainloop = pa_threaded_mainloop_new() pa_threaded_mainloop_start(self.pa_mainloop) pa_threaded_mainloop_lock (self.pa_mainloop) self.pa_mainloop_api = pa_threaded_mainloop_get_api(self.pa_mainloop) veromix = "VeroMix" self._context = pa_context_new(self.pa_mainloop_api, as_p_char(veromix)) self._context_notify_cb = pa_context_notify_cb_t(self.context_notify_cb) pa_context_set_state_callback(self._context, self._context_notify_cb, None) pa_context_connect(self._context, None, 0, None) ## pa_threaded_mainloop_unlock (self.pa_mainloop) def pa_exit(self): #try: ##pa_context_exit_daemon(self._context, self._context_notify_cb, 0) pa_threaded_mainloop_lock (self.pa_mainloop) #pa_context_set_state_callback(self._context, None, None) #pa_context_disconnect(self._context) pa_context_unref(self._context) pa_threaded_mainloop_unlock (self.pa_mainloop) #pa_threaded_mainloop_stop(self.pa_mainloop) pa_threaded_mainloop_free(self.pa_mainloop) #pa_threaded_mainloop_wait(self.pa_mainloop) self.initialize_variables() def set_autostart_meters(self, aboolean): self._autostart_meters = aboolean if aboolean: for source in list(self.sources.values()): self.pa_create_monitor_stream_for_source(source) for sink in list(self.sinks.values()): self.pa_create_monitor_stream_for_sink(sink.index, sink.name) for sinkinput in list(self.sink_inputs.values()): self.pa_create_monitor_stream_for_sink_input(sinkinput.index, sinkinput.sink) else: for source in list(self.sources.values()): self.pa_disconnect_monitor_of_source(source.index) for sink in list(self.sinks.values()): self.pa_disconnect_monitor_of_sink(sink.index) for sinkinput in list(self.sink_inputs.values()): self.pa_disconnect_monitor_of_sinkinput(sinkinput.index) ############# def pulse_toggle_monitor_of_sinkinput(self, sinkinput_index, sink_index, name): if float(sinkinput_index) in list(self.monitor_sink_inputs.keys()): self.pa_disconnect_monitor_of_sinkinput(sinkinput_index) else: self.pa_create_monitor_stream_for_sink_input(sinkinput_index, sink_index) def pa_disconnect_monitor_of_sinkinput(self, sinkinput_index): if float(sinkinput_index) in list(self.monitor_sink_inputs.keys()): pa_stream_disconnect(self.monitor_sink_inputs[float(sinkinput_index)]) del self.monitor_sink_inputs[float(sinkinput_index)] sink = self.sink_inputs[int(sinkinput_index)] sink.set_has_monitor(False) self.receiver.sink_input_info(sink) def pa_create_monitor_stream_for_sink_input(self, index, sink_index, force = False): if not index in list(self.monitor_sink_inputs.keys()) or force : sink = self.sinks[float(sink_index)] ss = pa_sample_spec() ss.channels = 1 ss.format = PA_SAMPLE_FLOAT32LE ss.rate = self._meter_rate #ss.rate = sink.sample_spec.rate pa_stream = pa_stream_new(self._context, as_p_char("Veromix sinkinput peak detect"), ss, None) pa_stream_set_monitor_stream(pa_stream, index) pa_stream_set_read_callback(pa_stream, self._pa_stream_request_cb, index) #pa_stream_set_suspended_callback(pa_stream, self._pa_stream_notify_cb, None) # FIXME We often get the wrong monitor_source here. pa_stream_connect_record(pa_stream, as_p_char(sink.monitor_source), None, PA_STREAM_PEAK_DETECT) self.monitor_sink_inputs[float(index)] = pa_stream sinkinput = self.sink_inputs[int(index)] sinkinput.set_has_monitor(True) self.receiver.sink_input_info(sinkinput) ########### def pulse_toggle_monitor_of_sink(self, sink_index, name): if float(sink_index) in list(self.monitor_sinks.keys()): self.pa_disconnect_monitor_of_sink(sink_index) else: self.pa_create_monitor_stream_for_sink(sink_index, name) def pa_disconnect_monitor_of_sink(self, sink_index): if float(sink_index) in list(self.monitor_sinks.keys()): pa_stream_disconnect(self.monitor_sinks[float(sink_index)]) del self.monitor_sinks[float(sink_index)] sink = self.sinks[float(sink_index)] sink.set_has_monitor(False) self.receiver.sink_info(sink) def pa_create_monitor_stream_for_sink(self, index, name, force = False): if not index in list(self.monitor_sinks.keys()) or force : if float(index) not in list(self.sinks.keys()): return sink = self.sinks[float(index)] samplespec = pa_sample_spec() samplespec.channels = 1 samplespec.format = PA_SAMPLE_FLOAT32LE samplespec.rate = self._meter_rate #samplespec.rate = sink.sample_spec.rate pa_stream = pa_stream_new(self._context, as_p_char("Veromix sink peak detect"), samplespec, None) pa_stream_set_read_callback(pa_stream, self._pa_sink_stream_request_cb, index+1) #pa_stream_set_suspended_callback(pa_stream, self._pa_stream_notify_cb, None) pa_stream_connect_record(pa_stream, as_p_char(sink.monitor_source), None, PA_STREAM_PEAK_DETECT) self.monitor_sinks[float(index)] = pa_stream sink.set_has_monitor(True) self.receiver.sink_info(sink) ########### def pulse_toggle_monitor_of_source(self, source_index, name): if float(source_index) in list(self.monitor_sources.keys()): self.pa_disconnect_monitor_of_source(source_index) else: self.pa_create_monitor_for_source(source_index, self.sources[float(source_index)], name) def pa_disconnect_monitor_of_source(self, source_index): if float(source_index) in list(self.monitor_sources.keys()): pa_stream_disconnect(self.monitor_sources[float(source_index)]) del self.monitor_sources[float(source_index)] def pa_create_monitor_stream_for_source(self, source): self.pa_create_monitor_for_source(source.index, source, source.name) def pa_create_monitor_for_source(self, index, source, name, force = False): if not index in self.monitor_sources or force : # Create new stream samplespec = pa_sample_spec() samplespec.channels = 1 samplespec.format = PA_SAMPLE_FLOAT32LE samplespec.rate = self._meter_rate pa_stream = pa_stream_new(self._context, as_p_char("Veromix source peak detect"), samplespec, None) pa_stream_set_read_callback(pa_stream, self._pa_source_stream_request_cb, index) pa_stream_set_suspended_callback(pa_stream, self._pa_stream_notify_cb, None) device = pa_xstrdup(as_p_char(in_unicode(source.name))) pa_stream_connect_record(pa_stream, device, None, PA_STREAM_PEAK_DETECT) self.monitor_sources[float(index)] = pa_stream source.set_has_monitor(True) self.receiver.source_info(source) ############# callbacks def pa_context_index_cb(self, context, index, user_data): # Do nothing.... return def pa_context_success_cb(self, context, c_int, user_data): return # pulseaudio connection status def context_notify_cb(self, context, userdata): try: ctc = pa_context_get_state(context) if ctc == PA_CONTEXT_READY: print("Pulseaudio connection ready...") self._null_cb = pa_context_success_cb_t(null_cb) self._pa_context_success_cb = pa_context_success_cb_t(self.pa_context_success_cb) self._pa_stream_request_cb = pa_stream_request_cb_t(self.pa_stream_request_cb) self._pa_source_stream_request_cb = pa_stream_request_cb_t(self.pa_source_stream_request_cb) self._pa_sink_stream_request_cb = pa_stream_request_cb_t(self.pa_sink_stream_request_cb) self._pa_stream_notify_cb = pa_stream_notify_cb_t(self.pa_stream_request_cb) self._pa_sink_info_cb = pa_sink_info_cb_t(self.pa_sink_info_cb) self._pa_context_subscribe_cb = pa_context_subscribe_cb_t(self.pa_context_subscribe_cb) self._pa_source_info_cb = pa_source_info_cb_t(self.pa_source_info_cb) self._pa_source_output_info_cb = pa_source_output_info_cb_t(self.pa_source_output_info_cb) self._pa_card_info_cb = pa_card_info_cb_t(self.pa_card_info_cb) self._pa_server_info_cb = pa_server_info_cb_t(self.pa_server_info_cb) self._pa_sink_input_info_list_cb = pa_sink_input_info_cb_t(self.pa_sink_input_info_cb) self._pa_client_info_list_cb = pa_client_info_cb_t(self.pa_client_info_cb) self._pa_module_info_cb = pa_module_info_cb_t(self.pa_module_info_cb) self._pa_context_index_cb = pa_context_index_cb_t(self.pa_context_index_cb) self.requestInfo() pa_context_set_subscribe_callback(self._context, self._pa_context_subscribe_cb, None); o = pa_context_subscribe(self._context, (pa_subscription_mask_t) (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE| PA_SUBSCRIPTION_MASK_SINK_INPUT| PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| PA_SUBSCRIPTION_MASK_CLIENT| PA_SUBSCRIPTION_MASK_SERVER| PA_SUBSCRIPTION_MASK_CARD | PA_SUBSCRIPTION_MASK_MODULE), self._null_cb, None) self.IS_READY = True #pa_operation_unref(o) if ctc == PA_CONTEXT_FAILED : self.__print("Connection failed") pa_threaded_mainloop_signal(self.pa_mainloop, 0) if ctc == PA_CONTEXT_TERMINATED: self.__print("Connection terminated") #pa_threaded_mainloop_signal(self.pa_mainloop, 0) print("leaving veromix..............") except Exception as text: self.__print("ERROR context_notify_cb %s" % text) def requestInfo(self): if not self.IS_READY : # this method is also called when a new client starts up that starts this service.. return o = pa_context_get_client_info_list(self._context, self._pa_client_info_list_cb, None) pa_operation_unref(o) o = pa_context_get_server_info(self._context, self._pa_server_info_cb, None) pa_operation_unref(o) o = pa_context_get_sink_info_list(self._context, self._pa_sink_info_cb, None) pa_operation_unref(o) o = pa_context_get_sink_input_info_list(self._context, self._pa_sink_input_info_list_cb, True) pa_operation_unref(o) o = pa_context_get_source_info_list(self._context, self._pa_source_info_cb, True) pa_operation_unref(o) o = pa_context_get_source_output_info_list(self._context, self._pa_source_output_info_cb, None) pa_operation_unref(o) o = pa_context_get_card_info_list(self._context, self._pa_card_info_cb, None) pa_operation_unref(o) o = pa_context_get_module_info_list(self._context, self._pa_module_info_cb, None) pa_operation_unref(o) def pa_context_subscribe_cb(self, context, event_type, index, user_data): try: et = event_type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK if et == PA_SUBSCRIPTION_EVENT_SERVER: o = pa_context_get_server_info(self._context, self._pa_server_info_cb, None) pa_operation_unref(o) o = pa_context_get_source_info_list(self._context, self._pa_source_info_cb, None) pa_operation_unref(o) o = pa_context_get_sink_info_list(self._context, self._pa_sink_info_cb, None) pa_operation_unref(o) if et == PA_SUBSCRIPTION_EVENT_CARD: if event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK == PA_SUBSCRIPTION_EVENT_REMOVE: self.receiver.card_remove(int(index)) else: o = pa_context_get_card_info_list(self._context, self._pa_card_info_cb, None) pa_operation_unref(o) if et == PA_SUBSCRIPTION_EVENT_CLIENT: if event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK == PA_SUBSCRIPTION_EVENT_REMOVE: self.receiver.client_remove(int(index)) else: o = pa_context_get_client_info(self._context, index, self._pa_client_info_list_cb, None) pa_operation_unref(o) if et == PA_SUBSCRIPTION_EVENT_SINK_INPUT: if event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK == PA_SUBSCRIPTION_EVENT_REMOVE: self.receiver.sink_input_remove(int(index)) if float(index) in list(self.monitor_sink_inputs.keys()): del self.monitor_sink_inputs[float(index)] if int(index) in list(self.sink_inputs.keys()): del self.sink_inputs[int(index)] else: o = pa_context_get_sink_input_info(self._context, int(index), self._pa_sink_input_info_list_cb, True) pa_operation_unref(o) if et == PA_SUBSCRIPTION_EVENT_SINK: if event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK == PA_SUBSCRIPTION_EVENT_REMOVE: self.receiver.sink_remove(int(index)) if float(index) in list(self.monitor_sinks.keys()): del self.monitor_sinks[float(index)] if float(index) in list(self.sinks.keys()): del self.sinks[float(index)] else: ## TODO: check other event-types o = pa_context_get_sink_info_list(self._context, self._pa_sink_info_cb, None) #o = pa_context_get_sink_info_list(self._context, self._pa_source_info_cb, None) pa_operation_unref(o) if et == PA_SUBSCRIPTION_EVENT_SOURCE: if event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK == PA_SUBSCRIPTION_EVENT_REMOVE: self.receiver.source_remove(int(index)) if float(index) in list(self.monitor_sources.keys()): del self.monitor_sources[float(index)] else: #o = pa_context_get_source_info_by_index(self._context, int(index), self._pa_source_info_cb, None) o = pa_context_get_source_info_list(self._context, self._pa_source_info_cb, None) pa_operation_unref(o) if et == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: if event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK == PA_SUBSCRIPTION_EVENT_REMOVE: self.receiver.source_output_remove(int(index)) else: o = pa_context_get_source_output_info_list(self._context, self._pa_source_output_info_cb, None) #o = pa_context_get_source_info_by_index(self._context,int(index), self._pa_source_output_info_cb, None) pa_operation_unref(o) if et == PA_SUBSCRIPTION_EVENT_MODULE: if event_type & PA_SUBSCRIPTION_EVENT_TYPE_MASK == PA_SUBSCRIPTION_EVENT_REMOVE: if int(index) in list(self.loaded_modules.keys()): del self.loaded_modules[int(index)] else: o = pa_context_get_module_info(self._context, int(index), self._pa_module_info_cb, None) pa_operation_unref(o) #o = pa_context_get_module_info_list(self._context, self._pa_module_info_cb, False) #pa_operation_unref(o) except Exception as text: self.__print("pa :: ERROR pa_context_subscribe_cb %s" % text) def pa_server_info_cb(self, context, struct, user_data): self.default_source_name = struct[0].default_source_name self.default_sink_name = struct[0].default_sink_name #self.requestInfo() def pa_sink_input_info_cb(self, context, struct, index, user_data): if struct : sink = PulseSinkInputInfo(struct[0]) #print ( pa_proplist_to_string(struct.contents.proplist)) sink.set_has_monitor(float(sink.index) in list(self.monitor_sink_inputs.keys())) self.sink_inputs[int(sink.index)] = sink self.receiver.sink_input_info(sink) if self._autostart_meters: self.pa_create_monitor_stream_for_sink_input(sink.index, sink.sink) def pa_sink_info_cb(self, context, struct, index, data): if struct: sink = PulseSinkInfo(struct[0]) sink.set_has_monitor((float(sink.index) in list(self.monitor_sinks.keys()))) sink.updateDefaultSink(self.default_sink_name) self.sinks[float(sink.index)] = sink self.receiver.sink_info(sink) if self._autostart_meters: self.pa_create_monitor_stream_for_sink(sink.index, sink.name) def pa_client_info_cb(self, context, struct, c_int, user_data): return def pa_source_output_info_cb(self, context, struct, cindex, user_data): if struct: source = PulseSourceOutputInfo(struct[0]) self.receiver.source_output_info(source) def pa_source_info_cb(self, context, struct, eol, user_data): if struct: source = PulseSourceInfo(struct[0]) source.set_has_monitor((float(source.index) in list(self.monitor_sources.keys()))) source.updateDefaultSource(self.default_source_name) self.sources[ float(struct.contents.index) ] = source self.receiver.source_info(source) if self._autostart_meters: self.pa_create_monitor_stream_for_source(source) def pa_card_info_cb(self, context, struct, cindex, user_data): if struct: info = CardInfo(struct[0]) self.receiver.card_info(info) #print ( pa_proplist_to_string(struct.contents.proplist)) def pa_stream_request_cb(self, stream, length, index): # This isnt quite right... maybe not a float.. ? #null_ptr = ctypes.c_void_p() data = POINTER(c_float)() pa_stream_peek(stream, data, ctypes.c_ulong(length)) v = data[int(length / 4) - 1] * 100 if (v < 0): v = 0 if (v > 100): v = 99 pa_stream_drop(stream) if index: self.receiver.volume_meter_sink_input(int(index), float(v)) #print "volume_meter_sink_input(int, float)",index, v def pa_source_stream_request_cb(self, stream, length, index): # This isnt quite right... maybe not a float.. ? #null_ptr = ctypes.c_void_p() data = POINTER(c_float)() pa_stream_peek(stream, data, ctypes.c_ulong(length)) v = data[int(length / 4) - 1] * 100 if (v < 0): v = 0 if (v > 100): v = 99 pa_stream_drop(stream) if index: self.receiver.volume_meter_source(int(index), float(v)) def pa_sink_stream_request_cb(self, stream, length, index_incr): index = index_incr - 1 data = POINTER(c_float)() pa_stream_peek(stream, data, ctypes.c_ulong(length)) v = data[int(length / 4) - 1] * 100 if (v < 0): v = 0 if (v > 100): v=99 pa_stream_drop(stream) #print "volume_meter_sink(int, float)", v self.receiver.volume_meter_sink(int(index), float(v)) def pa_module_info_cb(self, context, pa_module_info, index, user_data): # print ("pa_module_info", pa_module_info, index) if pa_module_info: self.loaded_modules[int(pa_module_info.contents.index)] = in_unicode(pa_module_info.contents.name) if in_unicode(pa_module_info.contents.name) == "module-ladspa-sink": self.receiver.module_info(int(pa_module_info.contents.index), in_unicode(pa_module_info.contents.name), in_unicode(pa_module_info.contents.argument), in_unicode(pa_module_info.contents.n_used), in_unicode(pa_module_info.contents.auto_unload)) # Restore ladspa-effects moved = [] for values in self.sink_inputs_to_restore: sink_input = values[0] parameters = values[1] if str(pa_module_info.contents.argument) == parameters: for sink in list(self.sinks.values()): if sink.owner_module == int(pa_module_info.contents.index): self.pulse_move_sink_input(sink_input.index, int(sink.index)) moved.append(values) for m in moved: self.sink_inputs_to_restore.remove(values) return ################### misc #def pa_ext_stream_restore_delete( self, stream): ## Only execute this if module restore is loaded #if "module-stream-restore" in self.loaded_modules: #pa_ext_stream_restore_delete(self._context, stream, self._pa_context_success_cb, None) ####### unused def load_module_stream_restore(self): print("Reloading module-stream-restore ") pa_context_load_module(self._context, "module-stream-restore", self.module_stream_restore_argument, self._pa_context_index_cb, None) # Move a playing stream to a differnt output sink def move_sink(self, sink_index, output_name): self.__print("move_sink") pa_context_move_sink_input_by_name(self._context, sink_index, as_p_char(output_name), self._pa_context_success_cb, None) ################## card profile def pulse_set_card_profile(self, index, value): # operation = pa_context_set_card_profile_by_name(self._context,as_p_char(index),as_p_char(value), self._null_cb,None) operation = pa_context_set_card_profile_by_index(self._context,int(index),as_p_char(value), self._null_cb,None) pa_operation_unref(operation) return ################## volume def pulse_mute_stream(self, index): self.pulse_sink_input_mute(index, 1) return def pulse_unmute_stream(self, index): self.pulse_sink_input_mute(index, 0) return def pulse_mute_sink(self, index): self.pulse_sink_mute(index, 1) return def pulse_unmute_sink(self, index): self.pulse_sink_mute(index, 0) return def pulse_sink_input_kill(self, index): operation = pa_context_kill_sink_input(self._context,index, self._null_cb,None) pa_operation_unref(operation) return def pulse_sink_input_mute(self, index, mute): operation = pa_context_set_sink_input_mute(self._context,index,mute, self._null_cb,None) pa_operation_unref(operation) return def pulse_sink_mute(self, index, mute): "Mute sink by index" operation = pa_context_set_sink_mute_by_index(self._context, index,c_int(mute),self._null_cb,None) pa_operation_unref(operation) return def pulse_set_sink_port(self,index,portstr): "Switch ports by index and port string" operation = pa_context_set_sink_port_by_index(self._context,index, as_p_char(portstr),self._null_cb,None) pa_operation_unref(operation) return def pulse_set_default_sink(self, index): operation = pa_context_set_default_sink(self._context, as_p_char(str(index)),self._null_cb,None) pa_operation_unref(operation) return def pulse_source_mute(self, index, mute): "Mute sink by index" operation = pa_context_set_source_mute_by_index(self._context, index,mute,self._null_cb,None) pa_operation_unref(operation) return def pulse_set_source_port(self,index,portstr): "Switch ports by index and port string" operation = pa_context_set_source_port_by_index(self._context,index,portstr,self._null_cb,None) pa_operation_unref(operation) return def pulse_set_default_source(self, index): operation = pa_context_set_default_source(self._context, as_p_char(index),self._null_cb,None) pa_operation_unref(operation) return def pulse_set_sink_volume(self, index, vol): operation = pa_context_set_sink_volume_by_index(self._context,index,vol.toCtypes(), self._null_cb,None) pa_operation_unref(operation) return def pulse_set_source_volume(self, index, vol): operation = pa_context_set_source_volume_by_index(self._context, index, vol.toCtypes(), self._null_cb,None) pa_operation_unref(operation) return def pulse_set_sink_input_volume(self, index, vol): operation = pa_context_set_sink_input_volume(self._context,index,vol.toCtypes(),self._null_cb,None) pa_operation_unref(operation) return def pulse_move_sink_input(self, index, target): operation = pa_context_move_sink_input_by_index(self._context,index, target, self._null_cb, None) pa_operation_unref(operation) self.pa_create_monitor_stream_for_sink_input(index, target, True) return def pulse_move_source_output(self, index, target): operation = pa_context_move_source_output_by_index(self._context,index, target, self._null_cb, None) pa_operation_unref(operation) #self.pa_create_monitor_stream_for_source(int(index), self.sink_inputs[float(target)], "", True) return def set_ladspa_sink(self, sink_index, module_index, parameters): try: if sink_index > -1 and int(module_index) in list(self.loaded_modules.keys()): # collect connected sink_inputs for sinkinput in list(self.sink_inputs.values()): if float(sinkinput.sink) in list(self.sinks.keys()): if self.sinks[float(sinkinput.sink)].owner_module == module_index: self.sink_inputs_to_restore.append([sinkinput, parameters]) self.remove_ladspa_sink(module_index) o = pa_context_load_module(self._context, as_p_char("module-ladspa-sink"),as_p_char(parameters), self._pa_context_index_cb, None) pa_operation_unref(o) except Exception as e : print(e) def remove_ladspa_sink(self, index): for key in list(self.loaded_modules.keys()): if self.loaded_modules[key] == "module-ladspa-sink" and int(key) == index: o = pa_context_unload_module(self._context, int(key), self._null_cb, None) pa_operation_unref(o) def create_combined_sink(self, first_sink_index, second_sink_index): parameters="slaves=" + str(first_sink_index) + "," + str(second_sink_index) o = pa_context_load_module(self._context, "module-combine-sink",parameters, self._pa_context_index_cb, None) pa_operation_unref(o) def remove_combined_sink(self, index): for key in list(self.loaded_modules.keys()): if self.loaded_modules[key] == "module-combine-sink" and int(key) == index: o = pa_context_unload_module(self._context, int(key), self._null_cb, None) pa_operation_unref(o) def __print(self, text): print(text) return #if __name__ == '__main__': #c = PulseAudio() # Unload & reload stream-restore module with restore_device option disabled (to ensure that previously cached per-client sinks are not used) #for key in self.loaded_modules.keys(): #if self.loaded_modules[key] == "module-stream-restore": #o = pa_context_unload_module(self._context, int(key), self._null_cb, None) #pa_operation_unref(o) #o = pa_context_load_module(self._context, "module-stream-restore", "restore_device=false", self._pa_context_index_cb, None) #pa_operation_unref(o) #print "sink_index", sink_index, self.sinks.keys() veromix/dbus-service/pulseaudio/PulseClient.py0000644000175100017500000000360611766302605020426 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # Copyright (C) 2009 Harry Karvonen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from .lib_pulseaudio import * # This class contains all basic client features class PulseClient: def __init__(self, name, index = 0): self.index = index self.name = name return ### def printDebug(self): print("self.index:", self.index) print("self.name:", self.name) return ### def __str__(self): return "Client-ID: " + str(self.index) + ", Name: \"" + self.name + "\"" ################################################################################ # This class is used with Ctypes class PulseClientCtypes(PulseClient): def __init__(self, pa_client): PulseClient.__init__(self, pa_client.name, pa_client.index) self.owner_module = pa_client.owner_module self.driver = pa_client.driver #self.proplist = pa_sink_input_info.proplist return ### def printDebug(self): print("PulseClientCtypes") PulseClient.printDebug(self) print("self.owner_module:", self.owner_module) print("self.driver:", self.driver) #print "self.proplist:", self.proplist return veromix/dbus-service/pulseaudio/lib.py0000644000175100017500000000677111766302605016753 0ustar nikkibu# Copyright (c) 2006-2008 Alex Holkner # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # * Neither the name of pyglet nor the names of its # contributors may be used to endorse or promote products # derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import os import re import sys import ctypes import ctypes.util _debug_lib = False _debug_trace = False class LibraryLoader(object): def load_library(self, *names, **kwargs): '''Find and load a library. More than one name can be specified, they will be tried in order. Platform-specific library names (given as kwargs) are tried first. Raises ImportError if library is not found. ''' if 'framework' in kwargs and self.platform == 'darwin': return self.load_framework(kwargs['framework']) platform_names = kwargs.get(self.platform, []) if type(platform_names) in (str, str): platform_names = [platform_names] elif type(platform_names) is tuple: platform_names = list(platform_names) if self.platform == 'linux2': platform_names.extend(['lib%s.so' % n for n in names]) platform_names.extend(names) for name in platform_names: try: lib = ctypes.cdll.LoadLibrary(name) #if _debug_lib: print("Loaded library :", name) #if _debug_trace: # lib = _TraceLibrary(lib) return lib except OSError: path = self.find_library(name) if path: try: lib = ctypes.cdll.LoadLibrary(path) if _debug_lib: print(path) if _debug_trace: lib = _TraceLibrary(lib) return lib except OSError: pass raise ImportError('Library "%s" not found.' % names[0]) find_library = lambda self, name: ctypes.util.find_library(name) platform = sys.platform if platform == 'cygwin': platform = 'win32' def load_framework(self, path): raise RuntimeError("Can't load framework on this platform.") veromix/dbus-service/pulseaudio/lib_pulseaudio.py0000644000175100017500000023100311766302605021171 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2008 Jason Taylor # Copyright (C) 2011-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ## Helpers: # python /usr/share/pyshared/ctypeslib/h2xml.py /usr/include/pulse/introspect.h -o /tmp/test.xml # python /usr/share/pyshared/ctypeslib/xml2py.py test.xml -k f -l /usr/lib/libpulse.so -o lib.py import ctypes from ctypes import * from .lib import * import sys use_old = True if sys.version_info >= (3, 0): use_old = False def as_p_char(aString): if use_old: return str(aString) return c_char_p(bytes(aString, 'utf8')) _lib = LibraryLoader().load_library('pulse') _int_types = (c_int16, c_int32) if hasattr(ctypes, 'c_int64'): # Some builds of ctypes apparently do not have c_int64 # defined; it's a pretty good bet that these builds do not # have 64-bit pointers. _int_types += (ctypes.c_int64,) for t in _int_types: if sizeof(t) == sizeof(c_size_t): c_ptrdiff_t = t class c_void(Structure): # c_void_p is a buggy return type, converting to int, so # POINTER(None) == c_void_p is actually written as # POINTER(c_void), so it can be treated as a real pointer. _fields_ = [('dummy', c_int)] class struct_pa_mainloop_api(Structure): __slots__ = [ ] struct_pa_mainloop_api._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_mainloop_api(Structure): __slots__ = [ ] struct_pa_mainloop_api._fields_ = [ ('_opaque_struct', c_int) ] pa_mainloop_api = struct_pa_mainloop_api # /usr/include/pulse/mainloop-api.h:51 enum_pa_io_event_flags = c_int PA_IO_EVENT_NULL = 0 PA_IO_EVENT_INPUT = 1 PA_IO_EVENT_OUTPUT = 2 PA_IO_EVENT_HANGUP = 4 PA_IO_EVENT_ERROR = 8 pa_io_event_flags_t = enum_pa_io_event_flags # /usr/include/pulse/mainloop-api.h:60 class struct_pa_io_event(Structure): __slots__ = [ ] struct_pa_io_event._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_io_event(Structure): __slots__ = [ ] struct_pa_io_event._fields_ = [ ('_opaque_struct', c_int) ] pa_io_event = struct_pa_io_event # /usr/include/pulse/mainloop-api.h:63 pa_io_event_cb_t = CFUNCTYPE(None, POINTER(pa_mainloop_api), POINTER(pa_io_event), c_int, pa_io_event_flags_t, POINTER(None)) # /usr/include/pulse/mainloop-api.h:65 pa_io_event_destroy_cb_t = CFUNCTYPE(None, POINTER(pa_mainloop_api), POINTER(pa_io_event), POINTER(None)) # /usr/include/pulse/mainloop-api.h:67 class struct_pa_time_event(Structure): __slots__ = [ ] struct_pa_time_event._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_time_event(Structure): __slots__ = [ ] struct_pa_time_event._fields_ = [ ('_opaque_struct', c_int) ] pa_time_event = struct_pa_time_event # /usr/include/pulse/mainloop-api.h:70 class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] pa_time_event_cb_t = CFUNCTYPE(None, POINTER(pa_mainloop_api), POINTER(pa_time_event), POINTER(struct_timeval), POINTER(None)) # /usr/include/pulse/mainloop-api.h:72 pa_time_event_destroy_cb_t = CFUNCTYPE(None, POINTER(pa_mainloop_api), POINTER(pa_time_event), POINTER(None)) # /usr/include/pulse/mainloop-api.h:74 class struct_pa_defer_event(Structure): __slots__ = [ ] struct_pa_defer_event._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_defer_event(Structure): __slots__ = [ ] struct_pa_defer_event._fields_ = [ ('_opaque_struct', c_int) ] pa_defer_event = struct_pa_defer_event # /usr/include/pulse/mainloop-api.h:77 pa_defer_event_cb_t = CFUNCTYPE(None, POINTER(pa_mainloop_api), POINTER(pa_defer_event), POINTER(None)) # /usr/include/pulse/mainloop-api.h:79 pa_defer_event_destroy_cb_t = CFUNCTYPE(None, POINTER(pa_mainloop_api), POINTER(pa_defer_event), POINTER(None)) # /usr/include/pulse/mainloop-api.h:81 # /usr/include/pulse/mainloop-api.h:120 pa_mainloop_api_once = _lib.pa_mainloop_api_once pa_mainloop_api_once.restype = None pa_mainloop_api_once.argtypes = [POINTER(pa_mainloop_api), CFUNCTYPE(None, POINTER(pa_mainloop_api), POINTER(None)), POINTER(None)] PA_CHANNELS_MAX = 32 # /usr/include/pulse/sample.h:117 PA_RATE_MAX = 192000 # /usr/include/pulse/sample.h:120 enum_pa_sample_format = c_int PA_SAMPLE_U8 = 0 PA_SAMPLE_ALAW = 1 PA_SAMPLE_ULAW = 2 PA_SAMPLE_S16LE = 3 PA_SAMPLE_S16BE = 4 PA_SAMPLE_FLOAT32LE = 5 PA_SAMPLE_FLOAT32BE = 6 PA_SAMPLE_S32LE = 7 PA_SAMPLE_S32BE = 8 PA_SAMPLE_MAX = 9 PA_SAMPLE_INVALID = -1 pa_sample_format_t = enum_pa_sample_format # /usr/include/pulse/sample.h:135 class struct_pa_sample_spec(Structure): __slots__ = [ 'format', 'rate', 'channels', ] struct_pa_sample_spec._fields_ = [ ('format', pa_sample_format_t), ('rate', c_uint32), ('channels', c_uint8), ] pa_sample_spec = struct_pa_sample_spec # /usr/include/pulse/sample.h:173 pa_usec_t = c_uint64 # /usr/include/pulse/sample.h:176 # /usr/include/pulse/sample.h:179 pa_bytes_per_second = _lib.pa_bytes_per_second pa_bytes_per_second.restype = c_size_t pa_bytes_per_second.argtypes = [POINTER(pa_sample_spec)] # /usr/include/pulse/sample.h:182 pa_frame_size = _lib.pa_frame_size pa_frame_size.restype = c_size_t pa_frame_size.argtypes = [POINTER(pa_sample_spec)] # /usr/include/pulse/sample.h:185 pa_sample_size = _lib.pa_sample_size pa_sample_size.restype = c_size_t pa_sample_size.argtypes = [POINTER(pa_sample_spec)] # /usr/include/pulse/sample.h:188 pa_bytes_to_usec = _lib.pa_bytes_to_usec pa_bytes_to_usec.restype = pa_usec_t pa_bytes_to_usec.argtypes = [c_uint64, POINTER(pa_sample_spec)] # /usr/include/pulse/sample.h:191 pa_usec_to_bytes = _lib.pa_usec_to_bytes pa_usec_to_bytes.restype = c_size_t pa_usec_to_bytes.argtypes = [pa_usec_t, POINTER(pa_sample_spec)] # /usr/include/pulse/sample.h:194 pa_sample_spec_valid = _lib.pa_sample_spec_valid pa_sample_spec_valid.restype = c_int pa_sample_spec_valid.argtypes = [POINTER(pa_sample_spec)] # /usr/include/pulse/sample.h:197 pa_sample_spec_equal = _lib.pa_sample_spec_equal pa_sample_spec_equal.restype = c_int pa_sample_spec_equal.argtypes = [POINTER(pa_sample_spec), POINTER(pa_sample_spec)] # /usr/include/pulse/sample.h:200 pa_sample_format_to_string = _lib.pa_sample_format_to_string pa_sample_format_to_string.restype = c_char_p pa_sample_format_to_string.argtypes = [pa_sample_format_t] # /usr/include/pulse/sample.h:203 pa_parse_sample_format = _lib.pa_parse_sample_format pa_parse_sample_format.restype = pa_sample_format_t pa_parse_sample_format.argtypes = [c_char_p] PA_SAMPLE_SPEC_SNPRINT_MAX = 32 # /usr/include/pulse/sample.h:206 # /usr/include/pulse/sample.h:209 pa_sample_spec_snprint = _lib.pa_sample_spec_snprint pa_sample_spec_snprint.restype = c_char_p pa_sample_spec_snprint.argtypes = [c_char_p, c_size_t, POINTER(pa_sample_spec)] # /usr/include/pulse/sample.h:212 pa_bytes_snprint = _lib.pa_bytes_snprint pa_bytes_snprint.restype = c_char_p pa_bytes_snprint.argtypes = [c_char_p, c_size_t, c_uint] enum_pa_context_state = c_int PA_CONTEXT_UNCONNECTED = 0 PA_CONTEXT_CONNECTING = 1 PA_CONTEXT_AUTHORIZING = 2 PA_CONTEXT_SETTING_NAME = 3 PA_CONTEXT_READY = 4 PA_CONTEXT_FAILED = 5 PA_CONTEXT_TERMINATED = 6 pa_context_state_t = enum_pa_context_state # /usr/include/pulse/def.h:49 enum_pa_stream_state = c_int PA_STREAM_UNCONNECTED = 0 PA_STREAM_CREATING = 1 PA_STREAM_READY = 2 PA_STREAM_FAILED = 3 PA_STREAM_TERMINATED = 4 pa_stream_state_t = enum_pa_stream_state # /usr/include/pulse/def.h:58 enum_pa_operation_state = c_int PA_OPERATION_RUNNING = 0 PA_OPERATION_DONE = 1 PA_OPERATION_CANCELED = 2 pa_operation_state_t = enum_pa_operation_state # /usr/include/pulse/def.h:65 enum_pa_context_flags = c_int PA_CONTEXT_NOAUTOSPAWN = 1 pa_context_flags_t = enum_pa_context_flags # /usr/include/pulse/def.h:73 enum_pa_stream_direction = c_int PA_STREAM_NODIRECTION = 0 PA_STREAM_PLAYBACK = 1 PA_STREAM_RECORD = 2 PA_STREAM_UPLOAD = 3 pa_stream_direction_t = enum_pa_stream_direction # /usr/include/pulse/def.h:81 enum_pa_stream_flags = c_int PA_STREAM_START_CORKED = 1 PA_STREAM_INTERPOLATE_TIMING = 2 PA_STREAM_NOT_MONOTONOUS = 4 PA_STREAM_AUTO_TIMING_UPDATE = 8 PA_STREAM_NO_REMAP_CHANNELS = 16 PA_STREAM_NO_REMIX_CHANNELS = 32 PA_STREAM_FIX_FORMAT = 64 PA_STREAM_FIX_RATE = 128 PA_STREAM_FIX_CHANNELS = 256 PA_STREAM_DONT_MOVE = 512 PA_STREAM_VARIABLE_RATE = 1024 pa_stream_flags_t = enum_pa_stream_flags # /usr/include/pulse/def.h:212 class struct_pa_buffer_attr(Structure): __slots__ = [ 'maxlength', 'tlength', 'prebuf', 'minreq', 'fragsize', ] struct_pa_buffer_attr._fields_ = [ ('maxlength', c_uint32), ('tlength', c_uint32), ('prebuf', c_uint32), ('minreq', c_uint32), ('fragsize', c_uint32), ] pa_buffer_attr = struct_pa_buffer_attr # /usr/include/pulse/def.h:221 enum_pa_subscription_mask = c_int PA_SUBSCRIPTION_MASK_NULL = 0 PA_SUBSCRIPTION_MASK_SINK = 1 PA_SUBSCRIPTION_MASK_SOURCE = 2 PA_SUBSCRIPTION_MASK_SINK_INPUT = 4 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8 PA_SUBSCRIPTION_MASK_MODULE = 16 PA_SUBSCRIPTION_MASK_CLIENT = 32 PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64 PA_SUBSCRIPTION_MASK_SERVER = 128 PA_SUBSCRIPTION_MASK_AUTOLOAD = 256 PA_SUBSCRIPTION_MASK_CARD = 512 PA_SUBSCRIPTION_MASK_ALL = 511 pa_subscription_mask_t = enum_pa_subscription_mask # /usr/include/pulse/def.h:261 enum_pa_subscription_event_type = c_int PA_SUBSCRIPTION_EVENT_SINK = 0 PA_SUBSCRIPTION_EVENT_SOURCE = 1 PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2 PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3 PA_SUBSCRIPTION_EVENT_MODULE = 4 PA_SUBSCRIPTION_EVENT_CLIENT = 5 PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6 PA_SUBSCRIPTION_EVENT_SERVER = 7 PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8 PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15 PA_SUBSCRIPTION_EVENT_NEW = 0 PA_SUBSCRIPTION_EVENT_CHANGE = 16 PA_SUBSCRIPTION_EVENT_REMOVE = 32 PA_SUBSCRIPTION_EVENT_TYPE_MASK = 48 PA_SUBSCRIPTION_EVENT_CARD = 9 pa_subscription_event_type_t = enum_pa_subscription_event_type # /usr/include/pulse/def.h:280 class struct_pa_timing_info(Structure): __slots__ = [ 'timestamp', 'synchronized_clocks', 'sink_usec', 'source_usec', 'transport_usec', 'playing', 'write_index_corrupt', 'write_index', 'read_index_corrupt', 'read_index', ] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] struct_pa_timing_info._fields_ = [ ('timestamp', struct_timeval), ('synchronized_clocks', c_int), ('sink_usec', pa_usec_t), ('source_usec', pa_usec_t), ('transport_usec', pa_usec_t), ('playing', c_int), ('write_index_corrupt', c_int), ('write_index', c_int64), ('read_index_corrupt', c_int), ('read_index', c_int64), ] pa_timing_info = struct_pa_timing_info # /usr/include/pulse/def.h:347 class struct_pa_spawn_api(Structure): __slots__ = [ 'prefork', 'postfork', 'atfork', ] struct_pa_spawn_api._fields_ = [ ('prefork', POINTER(CFUNCTYPE(None))), ('postfork', POINTER(CFUNCTYPE(None))), ('atfork', POINTER(CFUNCTYPE(None))), ] pa_spawn_api = struct_pa_spawn_api # /usr/include/pulse/def.h:366 enum_pa_seek_mode = c_int PA_SEEK_RELATIVE = 0 PA_SEEK_ABSOLUTE = 1 PA_SEEK_RELATIVE_ON_READ = 2 PA_SEEK_RELATIVE_END = 3 pa_seek_mode_t = enum_pa_seek_mode # /usr/include/pulse/def.h:374 enum_pa_sink_flags = c_int PA_SINK_HW_VOLUME_CTRL = 1 PA_SINK_LATENCY = 2 PA_SINK_HARDWARE = 4 PA_SINK_NETWORK = 8 pa_sink_flags_t = enum_pa_sink_flags # /usr/include/pulse/def.h:382 enum_pa_source_flags = c_int PA_SOURCE_HW_VOLUME_CTRL = 1 PA_SOURCE_LATENCY = 2 PA_SOURCE_HARDWARE = 4 PA_SOURCE_NETWORK = 8 pa_source_flags_t = enum_pa_source_flags # /usr/include/pulse/def.h:390 pa_free_cb_t = CFUNCTYPE(None, POINTER(None)) # /usr/include/pulse/def.h:393 class struct_pa_operation(Structure): __slots__ = [ ] struct_pa_operation._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_operation(Structure): __slots__ = [ ] struct_pa_operation._fields_ = [ ('_opaque_struct', c_int) ] pa_operation = struct_pa_operation # /usr/include/pulse/operation.h:36 # /usr/include/pulse/operation.h:39 pa_operation_ref = _lib.pa_operation_ref pa_operation_ref.restype = POINTER(pa_operation) pa_operation_ref.argtypes = [POINTER(pa_operation)] # /usr/include/pulse/operation.h:42 pa_operation_unref = _lib.pa_operation_unref pa_operation_unref.restype = None pa_operation_unref.argtypes = [POINTER(pa_operation)] # /usr/include/pulse/operation.h:45 pa_operation_cancel = _lib.pa_operation_cancel pa_operation_cancel.restype = None pa_operation_cancel.argtypes = [POINTER(pa_operation)] # /usr/include/pulse/operation.h:48 pa_operation_get_state = _lib.pa_operation_get_state pa_operation_get_state.restype = pa_operation_state_t pa_operation_get_state.argtypes = [POINTER(pa_operation)] class struct_pa_context(Structure): __slots__ = [ ] struct_pa_context._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_context(Structure): __slots__ = [ ] struct_pa_context._fields_ = [ ('_opaque_struct', c_int) ] pa_context = struct_pa_context # /usr/include/pulse/context.h:160 pa_context_notify_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(None)) # /usr/include/pulse/context.h:163 pa_context_success_cb_t = CFUNCTYPE(None, POINTER(pa_context), c_int, POINTER(None)) # /usr/include/pulse/context.h:166 # /usr/include/pulse/context.h:170 pa_context_new = _lib.pa_context_new pa_context_new.restype = POINTER(pa_context) pa_context_new.argtypes = [POINTER(pa_mainloop_api), c_char_p] # /usr/include/pulse/context.h:173 pa_context_unref = _lib.pa_context_unref pa_context_unref.restype = None pa_context_unref.argtypes = [POINTER(pa_context)] # /usr/include/pulse/context.h:176 pa_context_ref = _lib.pa_context_ref pa_context_ref.restype = POINTER(pa_context) pa_context_ref.argtypes = [POINTER(pa_context)] # /usr/include/pulse/context.h:179 pa_context_set_state_callback = _lib.pa_context_set_state_callback pa_context_set_state_callback.restype = None pa_context_set_state_callback.argtypes = [POINTER(pa_context), pa_context_notify_cb_t, POINTER(None)] # /usr/include/pulse/context.h:182 pa_context_errno = _lib.pa_context_errno pa_context_errno.restype = c_int pa_context_errno.argtypes = [POINTER(pa_context)] # /usr/include/pulse/context.h:185 pa_context_is_pending = _lib.pa_context_is_pending pa_context_is_pending.restype = c_int pa_context_is_pending.argtypes = [POINTER(pa_context)] # /usr/include/pulse/context.h:188 pa_context_get_state = _lib.pa_context_get_state pa_context_get_state.restype = pa_context_state_t pa_context_get_state.argtypes = [POINTER(pa_context)] # /usr/include/pulse/context.h:197 pa_context_connect = _lib.pa_context_connect pa_context_connect.restype = c_int pa_context_connect.argtypes = [POINTER(pa_context), c_char_p, pa_context_flags_t, POINTER(pa_spawn_api)] # /usr/include/pulse/context.h:200 pa_context_disconnect = _lib.pa_context_disconnect pa_context_disconnect.restype = None pa_context_disconnect.argtypes = [POINTER(pa_context)] # /usr/include/pulse/context.h:203 pa_context_drain = _lib.pa_context_drain pa_context_drain.restype = POINTER(pa_operation) pa_context_drain.argtypes = [POINTER(pa_context), pa_context_notify_cb_t, POINTER(None)] # /usr/include/pulse/context.h:208 pa_context_exit_daemon = _lib.pa_context_exit_daemon pa_context_exit_daemon.restype = POINTER(pa_operation) pa_context_exit_daemon.argtypes = [POINTER(pa_context), pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/context.h:211 pa_context_set_default_sink = _lib.pa_context_set_default_sink pa_context_set_default_sink.restype = POINTER(pa_operation) pa_context_set_default_sink.argtypes = [POINTER(pa_context), c_char_p, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/context.h:214 pa_context_set_default_source = _lib.pa_context_set_default_source pa_context_set_default_source.restype = POINTER(pa_operation) pa_context_set_default_source.argtypes = [POINTER(pa_context), c_char_p, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/context.h:217 pa_context_is_local = _lib.pa_context_is_local pa_context_is_local.restype = c_int pa_context_is_local.argtypes = [POINTER(pa_context)] # /usr/include/pulse/context.h:220 pa_context_set_name = _lib.pa_context_set_name pa_context_set_name.restype = POINTER(pa_operation) pa_context_set_name.argtypes = [POINTER(pa_context), c_char_p, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/context.h:223 pa_context_get_server = _lib.pa_context_get_server pa_context_get_server.restype = c_char_p pa_context_get_server.argtypes = [POINTER(pa_context)] # /usr/include/pulse/context.h:226 pa_context_get_protocol_version = _lib.pa_context_get_protocol_version pa_context_get_protocol_version.restype = c_uint32 pa_context_get_protocol_version.argtypes = [POINTER(pa_context)] # /usr/include/pulse/context.h:229 pa_context_get_server_protocol_version = _lib.pa_context_get_server_protocol_version pa_context_get_server_protocol_version.restype = c_uint32 pa_context_get_server_protocol_version.argtypes = [POINTER(pa_context)] enum_pa_channel_position = c_int PA_CHANNEL_POSITION_INVALID = -1 PA_CHANNEL_POSITION_MONO = 0 PA_CHANNEL_POSITION_LEFT = 1 PA_CHANNEL_POSITION_RIGHT = 2 PA_CHANNEL_POSITION_CENTER = 3 PA_CHANNEL_POSITION_FRONT_LEFT = 0 PA_CHANNEL_POSITION_FRONT_RIGHT = 0 PA_CHANNEL_POSITION_FRONT_CENTER = 0 PA_CHANNEL_POSITION_REAR_CENTER = 1 PA_CHANNEL_POSITION_REAR_LEFT = 2 PA_CHANNEL_POSITION_REAR_RIGHT = 3 PA_CHANNEL_POSITION_LFE = 4 PA_CHANNEL_POSITION_SUBWOOFER = 0 PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER = 1 PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER = 2 PA_CHANNEL_POSITION_SIDE_LEFT = 3 PA_CHANNEL_POSITION_SIDE_RIGHT = 4 PA_CHANNEL_POSITION_AUX0 = 5 PA_CHANNEL_POSITION_AUX1 = 6 PA_CHANNEL_POSITION_AUX2 = 7 PA_CHANNEL_POSITION_AUX3 = 8 PA_CHANNEL_POSITION_AUX4 = 9 PA_CHANNEL_POSITION_AUX5 = 10 PA_CHANNEL_POSITION_AUX6 = 11 PA_CHANNEL_POSITION_AUX7 = 12 PA_CHANNEL_POSITION_AUX8 = 13 PA_CHANNEL_POSITION_AUX9 = 14 PA_CHANNEL_POSITION_AUX10 = 15 PA_CHANNEL_POSITION_AUX11 = 16 PA_CHANNEL_POSITION_AUX12 = 17 PA_CHANNEL_POSITION_AUX13 = 18 PA_CHANNEL_POSITION_AUX14 = 19 PA_CHANNEL_POSITION_AUX15 = 20 PA_CHANNEL_POSITION_AUX16 = 21 PA_CHANNEL_POSITION_AUX17 = 22 PA_CHANNEL_POSITION_AUX18 = 23 PA_CHANNEL_POSITION_AUX19 = 24 PA_CHANNEL_POSITION_AUX20 = 25 PA_CHANNEL_POSITION_AUX21 = 26 PA_CHANNEL_POSITION_AUX22 = 27 PA_CHANNEL_POSITION_AUX23 = 28 PA_CHANNEL_POSITION_AUX24 = 29 PA_CHANNEL_POSITION_AUX25 = 30 PA_CHANNEL_POSITION_AUX26 = 31 PA_CHANNEL_POSITION_AUX27 = 32 PA_CHANNEL_POSITION_AUX28 = 33 PA_CHANNEL_POSITION_AUX29 = 34 PA_CHANNEL_POSITION_AUX30 = 35 PA_CHANNEL_POSITION_AUX31 = 36 PA_CHANNEL_POSITION_TOP_CENTER = 37 PA_CHANNEL_POSITION_TOP_FRONT_LEFT = 38 PA_CHANNEL_POSITION_TOP_FRONT_RIGHT = 39 PA_CHANNEL_POSITION_TOP_FRONT_CENTER = 40 PA_CHANNEL_POSITION_TOP_REAR_LEFT = 41 PA_CHANNEL_POSITION_TOP_REAR_RIGHT = 42 PA_CHANNEL_POSITION_TOP_REAR_CENTER = 43 PA_CHANNEL_POSITION_MAX = 44 pa_channel_position_t = enum_pa_channel_position # /usr/include/pulse/channelmap.h:140 enum_pa_channel_map_def = c_int PA_CHANNEL_MAP_AIFF = 0 PA_CHANNEL_MAP_ALSA = 1 PA_CHANNEL_MAP_AUX = 2 PA_CHANNEL_MAP_WAVEEX = 3 PA_CHANNEL_MAP_OSS = 4 PA_CHANNEL_MAP_DEFAULT = 0 pa_channel_map_def_t = enum_pa_channel_map_def # /usr/include/pulse/channelmap.h:151 class struct_pa_channel_map(Structure): __slots__ = [ 'channels', 'map', ] struct_pa_channel_map._fields_ = [ ('channels', c_uint8), ('map', pa_channel_position_t * 32), ] pa_channel_map = struct_pa_channel_map # /usr/include/pulse/channelmap.h:159 # /usr/include/pulse/channelmap.h:162 pa_channel_map_init = _lib.pa_channel_map_init pa_channel_map_init.restype = POINTER(pa_channel_map) pa_channel_map_init.argtypes = [POINTER(pa_channel_map)] # /usr/include/pulse/channelmap.h:165 pa_channel_map_init_mono = _lib.pa_channel_map_init_mono pa_channel_map_init_mono.restype = POINTER(pa_channel_map) pa_channel_map_init_mono.argtypes = [POINTER(pa_channel_map)] # /usr/include/pulse/channelmap.h:168 pa_channel_map_init_stereo = _lib.pa_channel_map_init_stereo pa_channel_map_init_stereo.restype = POINTER(pa_channel_map) pa_channel_map_init_stereo.argtypes = [POINTER(pa_channel_map)] # /usr/include/pulse/channelmap.h:172 pa_channel_map_init_auto = _lib.pa_channel_map_init_auto pa_channel_map_init_auto.restype = POINTER(pa_channel_map) pa_channel_map_init_auto.argtypes = [POINTER(pa_channel_map), c_uint, pa_channel_map_def_t] # /usr/include/pulse/channelmap.h:175 pa_channel_position_to_string = _lib.pa_channel_position_to_string pa_channel_position_to_string.restype = c_char_p pa_channel_position_to_string.argtypes = [pa_channel_position_t] # /usr/include/pulse/channelmap.h:178 pa_channel_position_to_pretty_string = _lib.pa_channel_position_to_pretty_string pa_channel_position_to_pretty_string.restype = c_char_p pa_channel_position_to_pretty_string.argtypes = [pa_channel_position_t] PA_CHANNEL_MAP_SNPRINT_MAX = 336 # /usr/include/pulse/channelmap.h:181 # /usr/include/pulse/channelmap.h:184 pa_channel_map_snprint = _lib.pa_channel_map_snprint pa_channel_map_snprint.restype = c_char_p pa_channel_map_snprint.argtypes = [c_char_p, c_size_t, POINTER(pa_channel_map)] # /usr/include/pulse/channelmap.h:187 pa_channel_map_parse = _lib.pa_channel_map_parse pa_channel_map_parse.restype = POINTER(pa_channel_map) pa_channel_map_parse.argtypes = [POINTER(pa_channel_map), c_char_p] # /usr/include/pulse/channelmap.h:190 pa_channel_map_equal = _lib.pa_channel_map_equal pa_channel_map_equal.restype = c_int pa_channel_map_equal.argtypes = [POINTER(pa_channel_map), POINTER(pa_channel_map)] # /usr/include/pulse/channelmap.h:193 pa_channel_map_valid = _lib.pa_channel_map_valid pa_channel_map_valid.restype = c_int pa_channel_map_valid.argtypes = [POINTER(pa_channel_map)] pa_volume_t = c_uint32 # /usr/include/pulse/volume.h:101 PA_VOLUME_NORM = 65536 # /usr/include/pulse/volume.h:104 PA_VOLUME_MUTED = 0 # /usr/include/pulse/volume.h:107 class struct_pa_cvolume(Structure): __slots__ = [ 'channels', 'values', ] struct_pa_cvolume._fields_ = [ ('channels', c_uint8), ('values', pa_volume_t * 32), ] pa_cvolume = struct_pa_cvolume # /usr/include/pulse/volume.h:113 # /usr/include/pulse/volume.h:116 pa_cvolume_equal = _lib.pa_cvolume_equal pa_cvolume_equal.restype = c_int pa_cvolume_equal.argtypes = [POINTER(pa_cvolume), POINTER(pa_cvolume)] # /usr/include/pulse/volume.h:125 pa_cvolume_set = _lib.pa_cvolume_set pa_cvolume_set.restype = POINTER(pa_cvolume) pa_cvolume_set.argtypes = [POINTER(pa_cvolume), c_uint, pa_volume_t] PA_CVOLUME_SNPRINT_MAX = 64 # /usr/include/pulse/volume.h:128 # /usr/include/pulse/volume.h:131 pa_cvolume_snprint = _lib.pa_cvolume_snprint pa_cvolume_snprint.restype = c_char_p pa_cvolume_snprint.argtypes = [c_char_p, c_size_t, POINTER(pa_cvolume)] # /usr/include/pulse/volume.h:134 pa_cvolume_avg = _lib.pa_cvolume_avg pa_cvolume_avg.restype = pa_volume_t pa_cvolume_avg.argtypes = [POINTER(pa_cvolume)] # /usr/include/pulse/volume.h:137 pa_cvolume_valid = _lib.pa_cvolume_valid pa_cvolume_valid.restype = c_int pa_cvolume_valid.argtypes = [POINTER(pa_cvolume)] # /usr/include/pulse/volume.h:140 pa_cvolume_channels_equal_to = _lib.pa_cvolume_channels_equal_to pa_cvolume_channels_equal_to.restype = c_int pa_cvolume_channels_equal_to.argtypes = [POINTER(pa_cvolume), pa_volume_t] # /usr/include/pulse/volume.h:149 pa_sw_volume_multiply = _lib.pa_sw_volume_multiply pa_sw_volume_multiply.restype = pa_volume_t pa_sw_volume_multiply.argtypes = [pa_volume_t, pa_volume_t] # /usr/include/pulse/volume.h:152 pa_sw_cvolume_multiply = _lib.pa_sw_cvolume_multiply pa_sw_cvolume_multiply.restype = POINTER(pa_cvolume) pa_sw_cvolume_multiply.argtypes = [POINTER(pa_cvolume), POINTER(pa_cvolume), POINTER(pa_cvolume)] # /usr/include/pulse/volume.h:155 pa_sw_volume_from_dB = _lib.pa_sw_volume_from_dB pa_sw_volume_from_dB.restype = pa_volume_t pa_sw_volume_from_dB.argtypes = [c_double] # /usr/include/pulse/volume.h:158 pa_sw_volume_to_dB = _lib.pa_sw_volume_to_dB pa_sw_volume_to_dB.restype = c_double pa_sw_volume_to_dB.argtypes = [pa_volume_t] # /usr/include/pulse/volume.h:161 pa_sw_volume_from_linear = _lib.pa_sw_volume_from_linear pa_sw_volume_from_linear.restype = pa_volume_t pa_sw_volume_from_linear.argtypes = [c_double] # /usr/include/pulse/volume.h:164 pa_sw_volume_to_linear = _lib.pa_sw_volume_to_linear pa_sw_volume_to_linear.restype = c_double pa_sw_volume_to_linear.argtypes = [pa_volume_t] PA_DECIBEL_MININFTY = -200 # /usr/include/pulse/volume.h:170 class struct_pa_stream(Structure): __slots__ = [ ] struct_pa_stream._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_stream(Structure): __slots__ = [ ] struct_pa_stream._fields_ = [ ('_opaque_struct', c_int) ] pa_stream = struct_pa_stream # /usr/include/pulse/stream.h:268 pa_stream_success_cb_t = CFUNCTYPE(None, POINTER(pa_stream), c_int, POINTER(None)) # /usr/include/pulse/stream.h:271 pa_stream_request_cb_t = CFUNCTYPE(None, POINTER(pa_stream), c_size_t, POINTER(None)) # /usr/include/pulse/stream.h:274 pa_stream_notify_cb_t = CFUNCTYPE(None, POINTER(pa_stream), POINTER(None)) # /usr/include/pulse/stream.h:277 # /usr/include/pulse/stream.h:280 pa_stream_new = _lib.pa_stream_new pa_stream_new.restype = POINTER(pa_stream) pa_stream_new.argtypes = [POINTER(pa_context), c_char_p, POINTER(pa_sample_spec), POINTER(pa_channel_map)] # /usr/include/pulse/stream.h:287 pa_stream_unref = _lib.pa_stream_unref pa_stream_unref.restype = None pa_stream_unref.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:290 pa_stream_ref = _lib.pa_stream_ref pa_stream_ref.restype = POINTER(pa_stream) pa_stream_ref.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:293 pa_stream_get_state = _lib.pa_stream_get_state pa_stream_get_state.restype = pa_stream_state_t pa_stream_get_state.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:296 pa_stream_get_context = _lib.pa_stream_get_context pa_stream_get_context.restype = POINTER(pa_context) pa_stream_get_context.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:302 pa_stream_get_index = _lib.pa_stream_get_index pa_stream_get_index.restype = c_uint32 pa_stream_get_index.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:312 pa_stream_get_device_index = _lib.pa_stream_get_device_index pa_stream_get_device_index.restype = c_uint32 pa_stream_get_device_index.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:322 pa_stream_get_device_name = _lib.pa_stream_get_device_name pa_stream_get_device_name.restype = c_char_p pa_stream_get_device_name.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:328 pa_stream_is_suspended = _lib.pa_stream_is_suspended pa_stream_is_suspended.restype = c_int pa_stream_is_suspended.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:331 pa_stream_connect_playback = _lib.pa_stream_connect_playback pa_stream_connect_playback.restype = c_int pa_stream_connect_playback.argtypes = [POINTER(pa_stream), c_char_p, POINTER(pa_buffer_attr), pa_stream_flags_t, POINTER(pa_cvolume), POINTER(pa_stream)] # /usr/include/pulse/stream.h:340 pa_stream_connect_record = _lib.pa_stream_connect_record pa_stream_connect_record.restype = c_int pa_stream_connect_record.argtypes = [POINTER(pa_stream), c_char_p, POINTER(pa_buffer_attr), pa_stream_flags_t] # /usr/include/pulse/stream.h:347 pa_stream_disconnect = _lib.pa_stream_disconnect pa_stream_disconnect.restype = c_int pa_stream_disconnect.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:356 pa_stream_write = _lib.pa_stream_write pa_stream_write.restype = c_int pa_stream_write.argtypes = [POINTER(pa_stream), POINTER(None), c_size_t, pa_free_cb_t, c_int64, pa_seek_mode_t] # /usr/include/pulse/stream.h:369 pa_stream_peek = _lib.pa_stream_peek pa_stream_peek.restype = c_int #pa_stream_peek.argtypes = [POINTER(pa_stream), POINTER(POINTER(None)), POINTER(c_size_t)] pa_stream_peek.argtypes = [POINTER(pa_stream), POINTER(POINTER(c_float)), POINTER(c_size_t)] # /usr/include/pulse/stream.h:376 pa_stream_drop = _lib.pa_stream_drop pa_stream_drop.restype = c_int pa_stream_drop.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:379 pa_stream_writable_size = _lib.pa_stream_writable_size pa_stream_writable_size.restype = c_size_t pa_stream_writable_size.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:382 pa_stream_readable_size = _lib.pa_stream_readable_size pa_stream_readable_size.restype = c_size_t pa_stream_readable_size.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:385 pa_stream_drain = _lib.pa_stream_drain pa_stream_drain.restype = POINTER(pa_operation) pa_stream_drain.argtypes = [POINTER(pa_stream), pa_stream_success_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:391 pa_stream_update_timing_info = _lib.pa_stream_update_timing_info pa_stream_update_timing_info.restype = POINTER(pa_operation) pa_stream_update_timing_info.argtypes = [POINTER(pa_stream), pa_stream_success_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:394 pa_stream_set_state_callback = _lib.pa_stream_set_state_callback pa_stream_set_state_callback.restype = None pa_stream_set_state_callback.argtypes = [POINTER(pa_stream), pa_stream_notify_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:398 pa_stream_set_write_callback = _lib.pa_stream_set_write_callback pa_stream_set_write_callback.restype = None pa_stream_set_write_callback.argtypes = [POINTER(pa_stream), pa_stream_request_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:402 pa_stream_set_read_callback = _lib.pa_stream_set_read_callback pa_stream_set_read_callback.restype = None pa_stream_set_read_callback.argtypes = [POINTER(pa_stream), pa_stream_request_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:405 pa_stream_set_overflow_callback = _lib.pa_stream_set_overflow_callback pa_stream_set_overflow_callback.restype = None pa_stream_set_overflow_callback.argtypes = [POINTER(pa_stream), pa_stream_notify_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:408 pa_stream_set_underflow_callback = _lib.pa_stream_set_underflow_callback pa_stream_set_underflow_callback.restype = None pa_stream_set_underflow_callback.argtypes = [POINTER(pa_stream), pa_stream_notify_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:413 pa_stream_set_latency_update_callback = _lib.pa_stream_set_latency_update_callback pa_stream_set_latency_update_callback.restype = None pa_stream_set_latency_update_callback.argtypes = [POINTER(pa_stream), pa_stream_notify_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:420 pa_stream_set_moved_callback = _lib.pa_stream_set_moved_callback pa_stream_set_moved_callback.restype = None pa_stream_set_moved_callback.argtypes = [POINTER(pa_stream), pa_stream_notify_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:430 pa_stream_set_suspended_callback = _lib.pa_stream_set_suspended_callback pa_stream_set_suspended_callback.restype = None pa_stream_set_suspended_callback.argtypes = [POINTER(pa_stream), pa_stream_notify_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:433 pa_stream_cork = _lib.pa_stream_cork pa_stream_cork.restype = POINTER(pa_operation) pa_stream_cork.argtypes = [POINTER(pa_stream), c_int, pa_stream_success_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:438 pa_stream_flush = _lib.pa_stream_flush pa_stream_flush.restype = POINTER(pa_operation) pa_stream_flush.argtypes = [POINTER(pa_stream), pa_stream_success_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:442 pa_stream_prebuf = _lib.pa_stream_prebuf pa_stream_prebuf.restype = POINTER(pa_operation) pa_stream_prebuf.argtypes = [POINTER(pa_stream), pa_stream_success_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:447 pa_stream_trigger = _lib.pa_stream_trigger pa_stream_trigger.restype = POINTER(pa_operation) pa_stream_trigger.argtypes = [POINTER(pa_stream), pa_stream_success_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:450 pa_stream_set_name = _lib.pa_stream_set_name pa_stream_set_name.restype = POINTER(pa_operation) pa_stream_set_name.argtypes = [POINTER(pa_stream), c_char_p, pa_stream_success_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:467 pa_stream_get_time = _lib.pa_stream_get_time pa_stream_get_time.restype = c_int pa_stream_get_time.argtypes = [POINTER(pa_stream), POINTER(pa_usec_t)] # /usr/include/pulse/stream.h:473 pa_stream_get_latency = _lib.pa_stream_get_latency pa_stream_get_latency.restype = c_int pa_stream_get_latency.argtypes = [POINTER(pa_stream), POINTER(pa_usec_t), POINTER(c_int)] # /usr/include/pulse/stream.h:485 pa_stream_get_timing_info = _lib.pa_stream_get_timing_info pa_stream_get_timing_info.restype = POINTER(pa_timing_info) pa_stream_get_timing_info.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:488 pa_stream_get_sample_spec = _lib.pa_stream_get_sample_spec pa_stream_get_sample_spec.restype = POINTER(pa_sample_spec) pa_stream_get_sample_spec.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:491 pa_stream_get_channel_map = _lib.pa_stream_get_channel_map pa_stream_get_channel_map.restype = POINTER(pa_channel_map) pa_stream_get_channel_map.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:496 pa_stream_get_buffer_attr = _lib.pa_stream_get_buffer_attr pa_stream_get_buffer_attr.restype = POINTER(pa_buffer_attr) pa_stream_get_buffer_attr.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/stream.h:504 pa_stream_set_buffer_attr = _lib.pa_stream_set_buffer_attr pa_stream_set_buffer_attr.restype = POINTER(pa_operation) pa_stream_set_buffer_attr.argtypes = [POINTER(pa_stream), POINTER(pa_buffer_attr), pa_stream_success_cb_t, POINTER(None)] # /usr/include/pulse/stream.h:511 pa_stream_update_sample_rate = _lib.pa_stream_update_sample_rate pa_stream_update_sample_rate.restype = POINTER(pa_operation) pa_stream_update_sample_rate.argtypes = [POINTER(pa_stream), c_uint32, pa_stream_success_cb_t, POINTER(None)] class pa_sink_port_info(Structure): __slots__ = [ 'name', 'description', 'priority', 'available' ] class struct_pa_sink_info(Structure): __slots__ = [ 'name', 'index', 'description', 'sample_spec', 'channel_map', 'owner_module', 'volume', 'mute', 'monitor_source', 'monitor_source_name', 'latency', 'driver', 'flags', 'proplist', 'configured_latency', 'base_volume', 'state', 'n_volume_steps', 'card', 'n_ports', 'ports', 'active_port', 'n_formats', 'formats' ] struct_pa_sink_info._fields_ = [ ('name', c_char_p), ('index', c_uint32), ('description', c_char_p), ('sample_spec', pa_sample_spec), ('channel_map', pa_channel_map), ('owner_module', c_uint32), ('volume', pa_cvolume), ('mute', c_int), ('monitor_source', c_uint32), ('monitor_source_name', c_char_p), ('latency', pa_usec_t), ('driver', c_char_p), ('flags', pa_sink_flags_t), ('proplist', POINTER(c_int)), ('configured_latency', pa_usec_t), ('base_volume', pa_volume_t), ('state', c_int), ('n_volume_steps', c_uint32), ('card', c_uint32), ('n_ports', c_uint32), ('ports', POINTER(POINTER(pa_sink_port_info))), ('active_port', POINTER(pa_sink_port_info)) ] pa_sink_info = struct_pa_sink_info # /usr/include/pulse/introspect.h:224 pa_sink_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_sink_info), c_int, POINTER(None)) # /usr/include/pulse/introspect.h:227 # /usr/include/pulse/introspect.h:230 pa_context_get_sink_info_by_name = _lib.pa_context_get_sink_info_by_name pa_context_get_sink_info_by_name.restype = POINTER(pa_operation) pa_context_get_sink_info_by_name.argtypes = [POINTER(pa_context), c_char_p, pa_sink_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:233 pa_context_get_sink_info_by_index = _lib.pa_context_get_sink_info_by_index pa_context_get_sink_info_by_index.restype = POINTER(pa_operation) pa_context_get_sink_info_by_index.argtypes = [POINTER(pa_context), c_uint32, pa_sink_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:236 pa_context_get_sink_info_list = _lib.pa_context_get_sink_info_list pa_context_get_sink_info_list.restype = POINTER(pa_operation) pa_context_get_sink_info_list.argtypes = [POINTER(pa_context), pa_sink_info_cb_t, POINTER(None)] class pa_source_port_info(Structure): __slots__ = [ 'name', 'description', 'priority', 'available' ] class struct_pa_source_info(Structure): __slots__ = [ 'name', 'index', 'description', 'sample_spec', 'channel_map', 'owner_module', 'volume', 'mute', 'monitor_of_sink', 'monitor_of_sink_name', 'latency', 'driver', 'flags', "proplist", 'configured_latency', 'base_volume', 'state', 'n_ports', 'ports', 'active_port', ] struct_pa_source_info._fields_ = [ ('name', c_char_p), ('index', c_uint32), ('description', c_char_p), ('sample_spec', pa_sample_spec), ('channel_map', pa_channel_map), ('owner_module', c_uint32), ('volume', pa_cvolume), ('mute', c_int), ('monitor_of_sink', c_uint32), ('monitor_of_sink_name', c_char_p), ('latency', pa_usec_t), ('driver', c_char_p), ('flags', pa_source_flags_t), ('proplist', POINTER(c_int)), ('configured_latency', pa_usec_t), ('base_volume', pa_volume_t), ('state', c_int), ('n_volume_steps', c_uint32), ('card', c_uint32), ('n_ports', c_uint32), ('ports', POINTER(POINTER(pa_source_port_info))), ('active_port', POINTER(pa_source_port_info)), ] # values for enumeration 'pa_hashport_available' PA_PORT_AVAILABLE_UNKNOWN = 0 PA_PORT_AVAILABLE_NO = 1 PA_PORT_AVAILABLE_YES = 2 pa_port_available = c_int # enum pa_port_available_t = pa_port_available pa_sink_port_info._fields_ = [ ('name', c_char_p), ('description', c_char_p), ('priority', c_uint32), ('available', pa_port_available_t), ] pa_source_port_info._fields_ = [ ('name', c_char_p), ('description', c_char_p), ('priority', c_uint32), ('available', pa_port_available_t), ] pa_source_info = struct_pa_source_info # /usr/include/pulse/introspect.h:253 pa_source_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_source_info), c_int, POINTER(None)) # /usr/include/pulse/introspect.h:256 # /usr/include/pulse/introspect.h:259 pa_context_get_source_info_by_name = _lib.pa_context_get_source_info_by_name pa_context_get_source_info_by_name.restype = POINTER(pa_operation) pa_context_get_source_info_by_name.argtypes = [POINTER(pa_context), c_char_p, pa_source_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:262 pa_context_get_source_info_by_index = _lib.pa_context_get_source_info_by_index pa_context_get_source_info_by_index.restype = POINTER(pa_operation) pa_context_get_source_info_by_index.argtypes = [POINTER(pa_context), c_uint32, pa_source_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:265 pa_context_get_source_info_list = _lib.pa_context_get_source_info_list pa_context_get_source_info_list.restype = POINTER(pa_operation) pa_context_get_source_info_list.argtypes = [POINTER(pa_context), pa_source_info_cb_t, POINTER(None)] pa_context_set_source_port_by_name = _lib.pa_context_set_source_port_by_name pa_context_set_source_port_by_name.restype = POINTER(pa_operation) pa_context_set_source_port_by_name.argtypes = [POINTER(pa_context), c_char_p, c_char_p, pa_context_success_cb_t, c_void_p] pa_context_set_source_port_by_index = _lib.pa_context_set_source_port_by_index pa_context_set_source_port_by_index.restype = POINTER(pa_operation) pa_context_set_source_port_by_index.argtypes = [POINTER(pa_context), c_uint32, c_char_p, pa_context_success_cb_t, c_void_p] pa_context_set_sink_port_by_index = _lib.pa_context_set_sink_port_by_index pa_context_set_sink_port_by_index.restype = POINTER(pa_operation) pa_context_set_sink_port_by_index.argtypes = [POINTER(pa_context), c_uint32, c_char_p, pa_context_success_cb_t, c_void_p] pa_context_set_sink_port_by_name = _lib.pa_context_set_sink_port_by_name pa_context_set_sink_port_by_name.restype = POINTER(pa_operation) pa_context_set_sink_port_by_name.argtypes = [POINTER(pa_context), c_char_p, c_char_p, pa_context_success_cb_t, c_void_p] class struct_pa_server_info(Structure): __slots__ = [ 'user_name', 'host_name', 'server_version', 'server_name', 'sample_spec', 'default_sink_name', 'default_source_name', 'cookie', ] struct_pa_server_info._fields_ = [ ('user_name', c_char_p), ('host_name', c_char_p), ('server_version', c_char_p), ('server_name', c_char_p), ('sample_spec', pa_sample_spec), ('default_sink_name', c_char_p), ('default_source_name', c_char_p), ('cookie', c_uint32), ] pa_server_info = struct_pa_server_info # /usr/include/pulse/introspect.h:277 pa_server_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_server_info), POINTER(None)) # /usr/include/pulse/introspect.h:280 # /usr/include/pulse/introspect.h:283 pa_context_get_server_info = _lib.pa_context_get_server_info pa_context_get_server_info.restype = POINTER(pa_operation) pa_context_get_server_info.argtypes = [POINTER(pa_context), pa_server_info_cb_t, POINTER(None)] class struct_pa_module_info(Structure): __slots__ = [ 'index', 'name', 'argument', 'n_used', 'auto_unload', 'proplist', ] struct_pa_module_info._fields_ = [ ('index', c_uint32), ('name', c_char_p), ('argument', c_char_p), ('n_used', c_uint32), ('auto_unload', c_int), ('proplist', POINTER(c_int)), ] pa_module_info = struct_pa_module_info # /usr/include/pulse/introspect.h:292 pa_module_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_module_info), c_int, POINTER(None)) # /usr/include/pulse/introspect.h:295 # /usr/include/pulse/introspect.h:298 pa_context_get_module_info = _lib.pa_context_get_module_info pa_context_get_module_info.restype = POINTER(pa_operation) pa_context_get_module_info.argtypes = [POINTER(pa_context), c_uint32, pa_module_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:301 pa_context_get_module_info_list = _lib.pa_context_get_module_info_list pa_context_get_module_info_list.restype = POINTER(pa_operation) pa_context_get_module_info_list.argtypes = [POINTER(pa_context), pa_module_info_cb_t, POINTER(None)] class struct_pa_client_info(Structure): __slots__ = [ 'index', 'name', 'owner_module', 'driver', 'proplist' ] struct_pa_client_info._fields_ = [ ('index', c_uint32), ('name', c_char_p), ('owner_module', c_uint32), ('driver', c_char_p), ("proplist", POINTER(c_int)) ] pa_client_info = struct_pa_client_info # /usr/include/pulse/introspect.h:309 pa_client_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_client_info), c_int, POINTER(None)) # /usr/include/pulse/introspect.h:312 # /usr/include/pulse/introspect.h:315 pa_context_get_client_info = _lib.pa_context_get_client_info pa_context_get_client_info.restype = POINTER(pa_operation) pa_context_get_client_info.argtypes = [POINTER(pa_context), c_uint32, pa_client_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:318 pa_context_get_client_info_list = _lib.pa_context_get_client_info_list pa_context_get_client_info_list.restype = POINTER(pa_operation) pa_context_get_client_info_list.argtypes = [POINTER(pa_context), pa_client_info_cb_t, POINTER(None)] class struct_pa_sink_input_info(Structure): __slots__ = [ 'index', 'name', 'owner_module', 'client', 'sink', 'sample_spec', 'channel_map', 'volume', 'buffer_usec', 'sink_usec', 'resample_method', 'driver', 'mute', 'proplist', 'monitor_index', ] struct_pa_sink_input_info._fields_ = [ ('index', c_uint32), ('name', c_char_p), ('owner_module', c_uint32), ('client', c_uint32), ('sink', c_uint32), ('sample_spec', pa_sample_spec), ('channel_map', pa_channel_map), ('volume', pa_cvolume), ('buffer_usec', pa_usec_t), ('sink_usec', pa_usec_t), ('resample_method', c_char_p), ('driver', c_char_p), ('mute', c_int), ("proplist", POINTER(c_int)), ('monitor_index', c_int), ] pa_sink_input_info = struct_pa_sink_input_info # /usr/include/pulse/introspect.h:335 pa_sink_input_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_sink_input_info), c_int, POINTER(None)) # /usr/include/pulse/introspect.h:338 # /usr/include/pulse/introspect.h:341 pa_context_get_sink_input_info = _lib.pa_context_get_sink_input_info pa_context_get_sink_input_info.restype = POINTER(pa_operation) pa_context_get_sink_input_info.argtypes = [POINTER(pa_context), c_uint32, pa_sink_input_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:344 pa_context_get_sink_input_info_list = _lib.pa_context_get_sink_input_info_list pa_context_get_sink_input_info_list.restype = POINTER(pa_operation) pa_context_get_sink_input_info_list.argtypes = [POINTER(pa_context), pa_sink_input_info_cb_t, POINTER(None)] class struct_pa_source_output_info(Structure): __slots__ = [ 'index', 'name', 'owner_module', 'client', 'source', 'sample_spec', 'channel_map', 'buffer_usec', 'source_usec', 'resample_method', 'driver', "proplist", ] struct_pa_source_output_info._fields_ = [ ('index', c_uint32), ('name', c_char_p), ('owner_module', c_uint32), ('client', c_uint32), ('source', c_uint32), ('sample_spec', pa_sample_spec), ('channel_map', pa_channel_map), ('buffer_usec', pa_usec_t), ('source_usec', pa_usec_t), ('resample_method', c_char_p), ('driver', c_char_p), ("proplist", POINTER(c_int)), ] pa_source_output_info = struct_pa_source_output_info # /usr/include/pulse/introspect.h:359 pa_source_output_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_source_output_info), c_int, POINTER(None)) # /usr/include/pulse/introspect.h:362 # /usr/include/pulse/introspect.h:365 pa_context_get_source_output_info = _lib.pa_context_get_source_output_info pa_context_get_source_output_info.restype = POINTER(pa_operation) pa_context_get_source_output_info.argtypes = [POINTER(pa_context), c_uint32, pa_source_output_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:368 pa_context_get_source_output_info_list = _lib.pa_context_get_source_output_info_list pa_context_get_source_output_info_list.restype = POINTER(pa_operation) pa_context_get_source_output_info_list.argtypes = [POINTER(pa_context), pa_source_output_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:371 pa_context_set_sink_volume_by_index = _lib.pa_context_set_sink_volume_by_index pa_context_set_sink_volume_by_index.restype = POINTER(pa_operation) pa_context_set_sink_volume_by_index.argtypes = [POINTER(pa_context), c_uint32, POINTER(pa_cvolume), pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:374 pa_context_set_sink_volume_by_name = _lib.pa_context_set_sink_volume_by_name pa_context_set_sink_volume_by_name.restype = POINTER(pa_operation) pa_context_set_sink_volume_by_name.argtypes = [POINTER(pa_context), c_char_p, POINTER(pa_cvolume), pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:377 pa_context_set_sink_mute_by_index = _lib.pa_context_set_sink_mute_by_index pa_context_set_sink_mute_by_index.restype = POINTER(pa_operation) pa_context_set_sink_mute_by_index.argtypes = [POINTER(pa_context), c_uint32, c_int, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:380 pa_context_set_sink_mute_by_name = _lib.pa_context_set_sink_mute_by_name pa_context_set_sink_mute_by_name.restype = POINTER(pa_operation) pa_context_set_sink_mute_by_name.argtypes = [POINTER(pa_context), c_char_p, c_int, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:383 pa_context_set_sink_input_volume = _lib.pa_context_set_sink_input_volume pa_context_set_sink_input_volume.restype = POINTER(pa_operation) pa_context_set_sink_input_volume.argtypes = [POINTER(pa_context), c_uint32, POINTER(pa_cvolume), pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:386 pa_context_set_sink_input_mute = _lib.pa_context_set_sink_input_mute pa_context_set_sink_input_mute.restype = POINTER(pa_operation) pa_context_set_sink_input_mute.argtypes = [POINTER(pa_context), c_uint32, c_int, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:389 pa_context_set_source_volume_by_index = _lib.pa_context_set_source_volume_by_index pa_context_set_source_volume_by_index.restype = POINTER(pa_operation) pa_context_set_source_volume_by_index.argtypes = [POINTER(pa_context), c_uint32, POINTER(pa_cvolume), pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:392 pa_context_set_source_volume_by_name = _lib.pa_context_set_source_volume_by_name pa_context_set_source_volume_by_name.restype = POINTER(pa_operation) pa_context_set_source_volume_by_name.argtypes = [POINTER(pa_context), c_char_p, POINTER(pa_cvolume), pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:395 pa_context_set_source_mute_by_index = _lib.pa_context_set_source_mute_by_index pa_context_set_source_mute_by_index.restype = POINTER(pa_operation) pa_context_set_source_mute_by_index.argtypes = [POINTER(pa_context), c_uint32, c_int, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:398 pa_context_set_source_mute_by_name = _lib.pa_context_set_source_mute_by_name pa_context_set_source_mute_by_name.restype = POINTER(pa_operation) pa_context_set_source_mute_by_name.argtypes = [POINTER(pa_context), c_char_p, c_int, pa_context_success_cb_t, POINTER(None)] class struct_pa_stat_info(Structure): __slots__ = [ 'memblock_total', 'memblock_total_size', 'memblock_allocated', 'memblock_allocated_size', 'scache_size', ] struct_pa_stat_info._fields_ = [ ('memblock_total', c_uint32), ('memblock_total_size', c_uint32), ('memblock_allocated', c_uint32), ('memblock_allocated_size', c_uint32), ('scache_size', c_uint32), ] pa_stat_info = struct_pa_stat_info # /usr/include/pulse/introspect.h:407 pa_stat_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_stat_info), POINTER(None)) # /usr/include/pulse/introspect.h:410 # /usr/include/pulse/introspect.h:413 pa_context_stat = _lib.pa_context_stat pa_context_stat.restype = POINTER(pa_operation) pa_context_stat.argtypes = [POINTER(pa_context), pa_stat_info_cb_t, POINTER(None)] class struct_pa_sample_info(Structure): __slots__ = [ 'index', 'name', 'volume', 'sample_spec', 'channel_map', 'duration', 'bytes', 'lazy', 'filename', ] struct_pa_sample_info._fields_ = [ ('index', c_uint32), ('name', c_char_p), ('volume', pa_cvolume), ('sample_spec', pa_sample_spec), ('channel_map', pa_channel_map), ('duration', pa_usec_t), ('bytes', c_uint32), ('lazy', c_int), ('filename', c_char_p), ] pa_sample_info = struct_pa_sample_info # /usr/include/pulse/introspect.h:426 pa_sample_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_sample_info), c_int, POINTER(None)) # /usr/include/pulse/introspect.h:429 # /usr/include/pulse/introspect.h:432 pa_context_get_sample_info_by_name = _lib.pa_context_get_sample_info_by_name pa_context_get_sample_info_by_name.restype = POINTER(pa_operation) pa_context_get_sample_info_by_name.argtypes = [POINTER(pa_context), c_char_p, pa_sample_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:435 pa_context_get_sample_info_by_index = _lib.pa_context_get_sample_info_by_index pa_context_get_sample_info_by_index.restype = POINTER(pa_operation) pa_context_get_sample_info_by_index.argtypes = [POINTER(pa_context), c_uint32, pa_sample_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:438 pa_context_get_sample_info_list = _lib.pa_context_get_sample_info_list pa_context_get_sample_info_list.restype = POINTER(pa_operation) pa_context_get_sample_info_list.argtypes = [POINTER(pa_context), pa_sample_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:441 pa_context_kill_client = _lib.pa_context_kill_client pa_context_kill_client.restype = POINTER(pa_operation) pa_context_kill_client.argtypes = [POINTER(pa_context), c_uint32, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:444 pa_context_kill_sink_input = _lib.pa_context_kill_sink_input pa_context_kill_sink_input.restype = POINTER(pa_operation) pa_context_kill_sink_input.argtypes = [POINTER(pa_context), c_uint32, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:447 pa_context_kill_source_output = _lib.pa_context_kill_source_output pa_context_kill_source_output.restype = POINTER(pa_operation) pa_context_kill_source_output.argtypes = [POINTER(pa_context), c_uint32, pa_context_success_cb_t, POINTER(None)] pa_context_index_cb_t = CFUNCTYPE(None, POINTER(pa_context), c_uint32, POINTER(None)) # /usr/include/pulse/introspect.h:450 # /usr/include/pulse/introspect.h:453 pa_context_load_module = _lib.pa_context_load_module pa_context_load_module.restype = POINTER(pa_operation) pa_context_load_module.argtypes = [POINTER(pa_context), c_char_p, c_char_p, pa_context_index_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:456 pa_context_unload_module = _lib.pa_context_unload_module pa_context_unload_module.restype = POINTER(pa_operation) pa_context_unload_module.argtypes = [POINTER(pa_context), c_uint32, pa_context_success_cb_t, POINTER(None)] enum_pa_autoload_type = c_int PA_AUTOLOAD_SINK = 0 PA_AUTOLOAD_SOURCE = 1 pa_autoload_type_t = enum_pa_autoload_type # /usr/include/pulse/introspect.h:462 class struct_pa_autoload_info(Structure): __slots__ = [ 'index', 'name', 'type', 'module', 'argument', ] struct_pa_autoload_info._fields_ = [ ('index', c_uint32), ('name', c_char_p), ('type', pa_autoload_type_t), ('module', c_char_p), ('argument', c_char_p), ] pa_autoload_info = struct_pa_autoload_info # /usr/include/pulse/introspect.h:471 pa_autoload_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_autoload_info), c_int, POINTER(None)) # /usr/include/pulse/introspect.h:474 # /usr/include/pulse/introspect.h:477 pa_context_get_autoload_info_by_name = _lib.pa_context_get_autoload_info_by_name pa_context_get_autoload_info_by_name.restype = POINTER(pa_operation) pa_context_get_autoload_info_by_name.argtypes = [POINTER(pa_context), c_char_p, pa_autoload_type_t, pa_autoload_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:480 pa_context_get_autoload_info_by_index = _lib.pa_context_get_autoload_info_by_index pa_context_get_autoload_info_by_index.restype = POINTER(pa_operation) pa_context_get_autoload_info_by_index.argtypes = [POINTER(pa_context), c_uint32, pa_autoload_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:483 pa_context_get_autoload_info_list = _lib.pa_context_get_autoload_info_list pa_context_get_autoload_info_list.restype = POINTER(pa_operation) pa_context_get_autoload_info_list.argtypes = [POINTER(pa_context), pa_autoload_info_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:486 pa_context_add_autoload = _lib.pa_context_add_autoload pa_context_add_autoload.restype = POINTER(pa_operation) pa_context_add_autoload.argtypes = [POINTER(pa_context), c_char_p, pa_autoload_type_t, c_char_p, c_char_p, pa_context_index_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:489 pa_context_remove_autoload_by_name = _lib.pa_context_remove_autoload_by_name pa_context_remove_autoload_by_name.restype = POINTER(pa_operation) pa_context_remove_autoload_by_name.argtypes = [POINTER(pa_context), c_char_p, pa_autoload_type_t, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:492 pa_context_remove_autoload_by_index = _lib.pa_context_remove_autoload_by_index pa_context_remove_autoload_by_index.restype = POINTER(pa_operation) pa_context_remove_autoload_by_index.argtypes = [POINTER(pa_context), c_uint32, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:495 pa_context_move_sink_input_by_name = _lib.pa_context_move_sink_input_by_name pa_context_move_sink_input_by_name.restype = POINTER(pa_operation) pa_context_move_sink_input_by_name.argtypes = [POINTER(pa_context), c_uint32, c_char_p, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:498 pa_context_move_sink_input_by_index = _lib.pa_context_move_sink_input_by_index pa_context_move_sink_input_by_index.restype = POINTER(pa_operation) pa_context_move_sink_input_by_index.argtypes = [POINTER(pa_context), c_uint32, c_uint32, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:501 pa_context_move_source_output_by_name = _lib.pa_context_move_source_output_by_name pa_context_move_source_output_by_name.restype = POINTER(pa_operation) pa_context_move_source_output_by_name.argtypes = [POINTER(pa_context), c_uint32, c_char_p, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:504 pa_context_move_source_output_by_index = _lib.pa_context_move_source_output_by_index pa_context_move_source_output_by_index.restype = POINTER(pa_operation) pa_context_move_source_output_by_index.argtypes = [POINTER(pa_context), c_uint32, c_uint32, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:507 pa_context_suspend_sink_by_name = _lib.pa_context_suspend_sink_by_name pa_context_suspend_sink_by_name.restype = POINTER(pa_operation) pa_context_suspend_sink_by_name.argtypes = [POINTER(pa_context), c_char_p, c_int, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:510 pa_context_suspend_sink_by_index = _lib.pa_context_suspend_sink_by_index pa_context_suspend_sink_by_index.restype = POINTER(pa_operation) pa_context_suspend_sink_by_index.argtypes = [POINTER(pa_context), c_uint32, c_int, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:513 pa_context_suspend_source_by_name = _lib.pa_context_suspend_source_by_name pa_context_suspend_source_by_name.restype = POINTER(pa_operation) pa_context_suspend_source_by_name.argtypes = [POINTER(pa_context), c_char_p, c_int, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/introspect.h:516 pa_context_suspend_source_by_index = _lib.pa_context_suspend_source_by_index pa_context_suspend_source_by_index.restype = POINTER(pa_operation) pa_context_suspend_source_by_index.argtypes = [POINTER(pa_context), c_uint32, c_int, pa_context_success_cb_t, POINTER(None)] pa_context_subscribe_cb_t = CFUNCTYPE(None, POINTER(pa_context), pa_subscription_event_type_t, c_uint32, POINTER(None)) # /usr/include/pulse/subscribe.h:54 # /usr/include/pulse/subscribe.h:57 pa_context_subscribe = _lib.pa_context_subscribe pa_context_subscribe.restype = POINTER(pa_operation) pa_context_subscribe.argtypes = [POINTER(pa_context), pa_subscription_mask_t, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/subscribe.h:60 pa_context_set_subscribe_callback = _lib.pa_context_set_subscribe_callback pa_context_set_subscribe_callback.restype = None pa_context_set_subscribe_callback.argtypes = [POINTER(pa_context), pa_context_subscribe_cb_t, POINTER(None)] # /usr/include/pulse/scache.h:83 pa_stream_connect_upload = _lib.pa_stream_connect_upload pa_stream_connect_upload.restype = c_int pa_stream_connect_upload.argtypes = [POINTER(pa_stream), c_size_t] # /usr/include/pulse/scache.h:87 pa_stream_finish_upload = _lib.pa_stream_finish_upload pa_stream_finish_upload.restype = c_int pa_stream_finish_upload.argtypes = [POINTER(pa_stream)] # /usr/include/pulse/scache.h:90 pa_context_play_sample = _lib.pa_context_play_sample pa_context_play_sample.restype = POINTER(pa_operation) pa_context_play_sample.argtypes = [POINTER(pa_context), c_char_p, c_char_p, pa_volume_t, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/scache.h:99 pa_context_remove_sample = _lib.pa_context_remove_sample pa_context_remove_sample.restype = POINTER(pa_operation) pa_context_remove_sample.argtypes = [POINTER(pa_context), c_char_p, pa_context_success_cb_t, POINTER(None)] # /usr/include/pulse/version.h:43 pa_get_library_version = _lib.pa_get_library_version pa_get_library_version.restype = c_char_p pa_get_library_version.argtypes = [] PA_API_VERSION = 11 # /usr/include/pulse/version.h:48 PA_PROTOCOL_VERSION = 12 # /usr/include/pulse/version.h:52 # /usr/include/pulse/error.h:37 pa_strerror = _lib.pa_strerror pa_strerror.restype = c_char_p pa_strerror.argtypes = [c_int] # /usr/include/pulse/xmalloc.h:40 pa_xmalloc = _lib.pa_xmalloc pa_xmalloc.restype = POINTER(c_void) pa_xmalloc.argtypes = [c_size_t] # /usr/include/pulse/xmalloc.h:43 pa_xmalloc0 = _lib.pa_xmalloc0 pa_xmalloc0.restype = POINTER(c_void) pa_xmalloc0.argtypes = [c_size_t] # /usr/include/pulse/xmalloc.h:46 pa_xrealloc = _lib.pa_xrealloc pa_xrealloc.restype = POINTER(c_void) pa_xrealloc.argtypes = [POINTER(None), c_size_t] # /usr/include/pulse/xmalloc.h:49 pa_xfree = _lib.pa_xfree pa_xfree.restype = None pa_xfree.argtypes = [POINTER(None)] # /usr/include/pulse/xmalloc.h:52 pa_xstrdup = _lib.pa_xstrdup pa_xstrdup.restype = c_char_p pa_xstrdup.argtypes = [c_char_p] # /usr/include/pulse/xmalloc.h:55 pa_xstrndup = _lib.pa_xstrndup pa_xstrndup.restype = c_char_p pa_xstrndup.argtypes = [c_char_p, c_size_t] # /usr/include/pulse/xmalloc.h:58 pa_xmemdup = _lib.pa_xmemdup pa_xmemdup.restype = POINTER(c_void) pa_xmemdup.argtypes = [POINTER(None), c_size_t] # /usr/include/pulse/utf8.h:37 pa_utf8_valid = _lib.pa_utf8_valid pa_utf8_valid.restype = c_char_p pa_utf8_valid.argtypes = [c_char_p] # /usr/include/pulse/utf8.h:40 pa_utf8_filter = _lib.pa_utf8_filter pa_utf8_filter.restype = c_char_p pa_utf8_filter.argtypes = [c_char_p] # /usr/include/pulse/utf8.h:43 pa_utf8_to_locale = _lib.pa_utf8_to_locale pa_utf8_to_locale.restype = c_char_p pa_utf8_to_locale.argtypes = [c_char_p] # /usr/include/pulse/utf8.h:46 pa_locale_to_utf8 = _lib.pa_locale_to_utf8 pa_locale_to_utf8.restype = c_char_p pa_locale_to_utf8.argtypes = [c_char_p] class struct_pa_threaded_mainloop(Structure): __slots__ = [ ] struct_pa_threaded_mainloop._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_threaded_mainloop(Structure): __slots__ = [ ] struct_pa_threaded_mainloop._fields_ = [ ('_opaque_struct', c_int) ] pa_threaded_mainloop = struct_pa_threaded_mainloop # /usr/include/pulse/thread-mainloop.h:242 # /usr/include/pulse/thread-mainloop.h:247 pa_threaded_mainloop_new = _lib.pa_threaded_mainloop_new pa_threaded_mainloop_new.restype = POINTER(pa_threaded_mainloop) pa_threaded_mainloop_new.argtypes = [] # /usr/include/pulse/thread-mainloop.h:252 pa_threaded_mainloop_free = _lib.pa_threaded_mainloop_free pa_threaded_mainloop_free.restype = None pa_threaded_mainloop_free.argtypes = [POINTER(pa_threaded_mainloop)] # /usr/include/pulse/thread-mainloop.h:255 pa_threaded_mainloop_start = _lib.pa_threaded_mainloop_start pa_threaded_mainloop_start.restype = c_int pa_threaded_mainloop_start.argtypes = [POINTER(pa_threaded_mainloop)] # /usr/include/pulse/thread-mainloop.h:259 pa_threaded_mainloop_stop = _lib.pa_threaded_mainloop_stop pa_threaded_mainloop_stop.restype = None pa_threaded_mainloop_stop.argtypes = [POINTER(pa_threaded_mainloop)] # /usr/include/pulse/thread-mainloop.h:267 pa_threaded_mainloop_lock = _lib.pa_threaded_mainloop_lock pa_threaded_mainloop_lock.restype = None pa_threaded_mainloop_lock.argtypes = [POINTER(pa_threaded_mainloop)] # /usr/include/pulse/thread-mainloop.h:270 pa_threaded_mainloop_unlock = _lib.pa_threaded_mainloop_unlock pa_threaded_mainloop_unlock.restype = None pa_threaded_mainloop_unlock.argtypes = [POINTER(pa_threaded_mainloop)] # /usr/include/pulse/thread-mainloop.h:279 pa_threaded_mainloop_wait = _lib.pa_threaded_mainloop_wait pa_threaded_mainloop_wait.restype = None pa_threaded_mainloop_wait.argtypes = [POINTER(pa_threaded_mainloop)] # /usr/include/pulse/thread-mainloop.h:286 pa_threaded_mainloop_signal = _lib.pa_threaded_mainloop_signal pa_threaded_mainloop_signal.restype = None pa_threaded_mainloop_signal.argtypes = [POINTER(pa_threaded_mainloop), c_int] # /usr/include/pulse/thread-mainloop.h:292 pa_threaded_mainloop_accept = _lib.pa_threaded_mainloop_accept pa_threaded_mainloop_accept.restype = None pa_threaded_mainloop_accept.argtypes = [POINTER(pa_threaded_mainloop)] # /usr/include/pulse/thread-mainloop.h:295 pa_threaded_mainloop_get_retval = _lib.pa_threaded_mainloop_get_retval pa_threaded_mainloop_get_retval.restype = c_int pa_threaded_mainloop_get_retval.argtypes = [POINTER(pa_threaded_mainloop)] # /usr/include/pulse/thread-mainloop.h:298 pa_threaded_mainloop_get_api = _lib.pa_threaded_mainloop_get_api pa_threaded_mainloop_get_api.restype = POINTER(pa_mainloop_api) pa_threaded_mainloop_get_api.argtypes = [POINTER(pa_threaded_mainloop)] # /usr/include/pulse/thread-mainloop.h:301 pa_threaded_mainloop_in_thread = _lib.pa_threaded_mainloop_in_thread pa_threaded_mainloop_in_thread.restype = c_int pa_threaded_mainloop_in_thread.argtypes = [POINTER(pa_threaded_mainloop)] class struct_pa_mainloop(Structure): __slots__ = [ ] struct_pa_mainloop._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_mainloop(Structure): __slots__ = [ ] struct_pa_mainloop._fields_ = [ ('_opaque_struct', c_int) ] pa_mainloop = struct_pa_mainloop # /usr/include/pulse/mainloop.h:79 # /usr/include/pulse/mainloop.h:82 pa_mainloop_new = _lib.pa_mainloop_new pa_mainloop_new.restype = POINTER(pa_mainloop) pa_mainloop_new.argtypes = [] # /usr/include/pulse/mainloop.h:85 pa_mainloop_free = _lib.pa_mainloop_free pa_mainloop_free.restype = None pa_mainloop_free.argtypes = [POINTER(pa_mainloop)] # /usr/include/pulse/mainloop.h:90 pa_mainloop_prepare = _lib.pa_mainloop_prepare pa_mainloop_prepare.restype = c_int pa_mainloop_prepare.argtypes = [POINTER(pa_mainloop), c_int] # /usr/include/pulse/mainloop.h:93 pa_mainloop_poll = _lib.pa_mainloop_poll pa_mainloop_poll.restype = c_int pa_mainloop_poll.argtypes = [POINTER(pa_mainloop)] # /usr/include/pulse/mainloop.h:97 pa_mainloop_dispatch = _lib.pa_mainloop_dispatch pa_mainloop_dispatch.restype = c_int pa_mainloop_dispatch.argtypes = [POINTER(pa_mainloop)] # /usr/include/pulse/mainloop.h:100 pa_mainloop_get_retval = _lib.pa_mainloop_get_retval pa_mainloop_get_retval.restype = c_int pa_mainloop_get_retval.argtypes = [POINTER(pa_mainloop)] # /usr/include/pulse/mainloop.h:108 pa_mainloop_iterate = _lib.pa_mainloop_iterate pa_mainloop_iterate.restype = c_int pa_mainloop_iterate.argtypes = [POINTER(pa_mainloop), c_int, POINTER(c_int)] # /usr/include/pulse/mainloop.h:111 pa_mainloop_run = _lib.pa_mainloop_run pa_mainloop_run.restype = c_int pa_mainloop_run.argtypes = [POINTER(pa_mainloop), POINTER(c_int)] # /usr/include/pulse/mainloop.h:114 pa_mainloop_get_api = _lib.pa_mainloop_get_api pa_mainloop_get_api.restype = POINTER(pa_mainloop_api) pa_mainloop_get_api.argtypes = [POINTER(pa_mainloop)] # /usr/include/pulse/mainloop.h:117 pa_mainloop_quit = _lib.pa_mainloop_quit pa_mainloop_quit.restype = None pa_mainloop_quit.argtypes = [POINTER(pa_mainloop), c_int] # /usr/include/pulse/mainloop.h:120 pa_mainloop_wakeup = _lib.pa_mainloop_wakeup pa_mainloop_wakeup.restype = None pa_mainloop_wakeup.argtypes = [POINTER(pa_mainloop)] class struct_pollfd(Structure): __slots__ = [ ] struct_pollfd._fields_ = [ ('_opaque_struct', c_int) ] class struct_pollfd(Structure): __slots__ = [ ] struct_pollfd._fields_ = [ ('_opaque_struct', c_int) ] pa_poll_func = CFUNCTYPE(c_int, POINTER(struct_pollfd), c_ulong, c_int, POINTER(None)) # /usr/include/pulse/mainloop.h:123 # /usr/include/pulse/mainloop.h:126 pa_mainloop_set_poll_func = _lib.pa_mainloop_set_poll_func pa_mainloop_set_poll_func.restype = None pa_mainloop_set_poll_func.argtypes = [POINTER(pa_mainloop), pa_poll_func, POINTER(None)] # /usr/include/pulse/mainloop-signal.h:43 pa_signal_init = _lib.pa_signal_init pa_signal_init.restype = c_int pa_signal_init.argtypes = [POINTER(pa_mainloop_api)] # /usr/include/pulse/mainloop-signal.h:46 pa_signal_done = _lib.pa_signal_done pa_signal_done.restype = None pa_signal_done.argtypes = [] class struct_pa_signal_event(Structure): __slots__ = [ ] struct_pa_signal_event._fields_ = [ ('_opaque_struct', c_int) ] class struct_pa_signal_event(Structure): __slots__ = [ ] struct_pa_signal_event._fields_ = [ ('_opaque_struct', c_int) ] pa_signal_event = struct_pa_signal_event # /usr/include/pulse/mainloop-signal.h:49 # /usr/include/pulse/mainloop-signal.h:52 pa_signal_new = _lib.pa_signal_new pa_signal_new.restype = POINTER(pa_signal_event) pa_signal_new.argtypes = [c_int, CFUNCTYPE(None, POINTER(pa_mainloop_api), POINTER(pa_signal_event), c_int, POINTER(None)), POINTER(None)] # /usr/include/pulse/mainloop-signal.h:55 pa_signal_free = _lib.pa_signal_free pa_signal_free.restype = None pa_signal_free.argtypes = [POINTER(pa_signal_event)] # /usr/include/pulse/mainloop-signal.h:58 pa_signal_set_destroy = _lib.pa_signal_set_destroy pa_signal_set_destroy.restype = None pa_signal_set_destroy.argtypes = [POINTER(pa_signal_event), CFUNCTYPE(None, POINTER(pa_mainloop_api), POINTER(pa_signal_event), POINTER(None))] # /usr/include/pulse/util.h:38 pa_get_user_name = _lib.pa_get_user_name pa_get_user_name.restype = c_char_p pa_get_user_name.argtypes = [c_char_p, c_size_t] # /usr/include/pulse/util.h:41 pa_get_host_name = _lib.pa_get_host_name pa_get_host_name.restype = c_char_p pa_get_host_name.argtypes = [c_char_p, c_size_t] # /usr/include/pulse/util.h:44 pa_get_fqdn = _lib.pa_get_fqdn pa_get_fqdn.restype = c_char_p pa_get_fqdn.argtypes = [c_char_p, c_size_t] # /usr/include/pulse/util.h:47 pa_get_home_dir = _lib.pa_get_home_dir pa_get_home_dir.restype = c_char_p pa_get_home_dir.argtypes = [c_char_p, c_size_t] # /usr/include/pulse/util.h:51 pa_get_binary_name = _lib.pa_get_binary_name pa_get_binary_name.restype = c_char_p pa_get_binary_name.argtypes = [c_char_p, c_size_t] # /usr/include/pulse/util.h:55 pa_path_get_filename = _lib.pa_path_get_filename pa_path_get_filename.restype = c_char_p pa_path_get_filename.argtypes = [c_char_p] # /usr/include/pulse/util.h:58 pa_msleep = _lib.pa_msleep pa_msleep.restype = c_int pa_msleep.argtypes = [c_ulong] PA_MSEC_PER_SEC = 1000 # /usr/include/pulse/timeval.h:36 PA_USEC_PER_SEC = 1000000 # /usr/include/pulse/timeval.h:37 PA_NSEC_PER_SEC = 1000000000 # /usr/include/pulse/timeval.h:38 PA_USEC_PER_MSEC = 1000 # /usr/include/pulse/timeval.h:39 class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] # /usr/include/pulse/timeval.h:44 pa_gettimeofday = _lib.pa_gettimeofday pa_gettimeofday.restype = POINTER(struct_timeval) pa_gettimeofday.argtypes = [POINTER(struct_timeval)] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] # /usr/include/pulse/timeval.h:48 pa_timeval_diff = _lib.pa_timeval_diff pa_timeval_diff.restype = pa_usec_t pa_timeval_diff.argtypes = [POINTER(struct_timeval), POINTER(struct_timeval)] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] # /usr/include/pulse/timeval.h:51 pa_timeval_cmp = _lib.pa_timeval_cmp pa_timeval_cmp.restype = c_int pa_timeval_cmp.argtypes = [POINTER(struct_timeval), POINTER(struct_timeval)] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] # /usr/include/pulse/timeval.h:54 pa_timeval_age = _lib.pa_timeval_age pa_timeval_age.restype = pa_usec_t pa_timeval_age.argtypes = [POINTER(struct_timeval)] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] # /usr/include/pulse/timeval.h:57 pa_timeval_add = _lib.pa_timeval_add pa_timeval_add.restype = POINTER(struct_timeval) pa_timeval_add.argtypes = [POINTER(struct_timeval), pa_usec_t] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] # /usr/include/pulse/timeval.h:60 pa_timeval_store = _lib.pa_timeval_store pa_timeval_store.restype = POINTER(struct_timeval) pa_timeval_store.argtypes = [POINTER(struct_timeval), pa_usec_t] class struct_timeval(Structure): __slots__ = [ ] struct_timeval._fields_ = [ ('_opaque_struct', c_int) ] # /usr/include/pulse/timeval.h:63 pa_timeval_load = _lib.pa_timeval_load pa_timeval_load.restype = pa_usec_t pa_timeval_load.argtypes = [POINTER(struct_timeval)] # MANUALLY ADDED PA_STREAM_PEAK_DETECT = 2048 PA_STREAM_ADJUST_LATENCY = 8192 # Set monitor steam pa_stream_set_monitor_stream = _lib.pa_stream_set_monitor_stream pa_stream_set_monitor_stream.restype = c_int pa_context_play_sample.argtypes = [POINTER(pa_stream), c_int] pa_proplist_gets = _lib.pa_proplist_gets pa_proplist_gets.restype = c_char_p pa_proplist_gets.argtypes = [POINTER(c_int), c_char_p] # Get entire proplist as a string pa_proplist_to_string = _lib.pa_proplist_to_string pa_proplist_to_string.restype = c_char_p pa_proplist_to_string.argtypes = [ POINTER(c_int) ] pa_ext_stream_restore_delete = _lib.pa_ext_stream_restore_delete pa_ext_stream_restore_delete.restype = pa_operation pa_ext_stream_restore_delete.argtypes = [POINTER(pa_context), c_char_p, pa_context_success_cb_t, POINTER(None)] # CARD INFO STUFF class pa_card_profile_info(Structure): pass pa_card_profile_info._fields_ = [ ('name', c_char_p), ('description', c_char_p), ('n_sinks', c_uint32), ('n_sources', c_uint32), ('priority', c_uint32), ] class pa_card_info(Structure): pass pa_card_info._fields_ = [ ('index', c_uint32), ('name', c_char_p), ('owner_module', c_uint32), ('driver', c_char_p), ('n_profiles', c_uint32), ('profiles', POINTER(pa_card_profile_info)), ('active_profile', POINTER(pa_card_profile_info)), ('proplist', POINTER(c_int)), ] pa_card_info_cb_t = CFUNCTYPE(None, POINTER(pa_context), POINTER(pa_card_info), c_int, c_void_p) pa_context_get_card_info_by_index = _lib.pa_context_get_card_info_by_index pa_context_get_card_info_by_index.restype = POINTER(pa_operation) pa_context_get_card_info_by_index.argtypes = [POINTER(pa_context), c_uint32, pa_card_info_cb_t, c_void_p] pa_context_get_card_info_by_name = _lib.pa_context_get_card_info_by_name pa_context_get_card_info_by_name.restype = POINTER(pa_operation) pa_context_get_card_info_by_name.argtypes = [POINTER(pa_context), c_char_p, pa_card_info_cb_t, c_void_p] pa_context_get_card_info_list = _lib.pa_context_get_card_info_list pa_context_get_card_info_list.restype = POINTER(pa_operation) pa_context_get_card_info_list.argtypes = [POINTER(pa_context), pa_card_info_cb_t, c_void_p] # CARD PROFILE pa_context_set_card_profile_by_index = _lib.pa_context_set_card_profile_by_index pa_context_set_card_profile_by_index.restype = POINTER(pa_operation) pa_context_set_card_profile_by_index.argtypes = [POINTER(pa_context), c_uint32, c_char_p, pa_context_success_cb_t, c_void_p] pa_context_set_card_profile_by_name = _lib.pa_context_set_card_profile_by_name pa_context_set_card_profile_by_name.restype = POINTER(pa_operation) pa_context_set_card_profile_by_name.argtypes = [POINTER(pa_context), c_char_p, c_char_p, pa_context_success_cb_t, c_void_p] # Proplist update class pa_proplist(Structure): pass pa_proplist_from_string = _lib.pa_proplist_from_string pa_proplist_from_string.restype = POINTER(pa_proplist) pa_proplist_from_string.argtypes = [c_char_p] # values for enumeration 'pa_update_mode' PA_UPDATE_SET = 0 PA_UPDATE_MERGE = 1 PA_UPDATE_REPLACE = 2 pa_update_mode = c_int # enum pa_update_mode_t = pa_update_mode pa_proplist_update = _lib.pa_proplist_update pa_proplist_update.restype = None pa_proplist_update.argtypes = [POINTER(pa_proplist), pa_update_mode_t, POINTER(pa_proplist)] veromix/dbus-service/pulseaudio/PulseSink.py0000644000175100017500000002626111766302605020116 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # Copyright (C) 2009 Harry Karvonen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from .lib_pulseaudio import * from .PulseClient import PulseClient from .PulseVolume import PulseVolumeCtypes from VeromixUtils import * # This class contains all commons features from PulseSinkInputInfo and # PulseSinkInfo def todict(obj): data = {} for key, value in obj.__dict__.items(): try: data[key] = todict(str(value)) except AttributeError: data[key] = value return data class PulseSink: def __init__(self, index, name, mute, volume, client): self.index = int(index) self.name = in_unicode(name) self.mute = mute self.volume = volume self.client = client self.isDefaultSink = False self.default_sink_name = "" self.monitor_enabled = False return # PROTOTYPE def unmuteStream(self): raise Exception("ABSTRACT METHOD CALLED") return # PROTOTYPE def muteStream(self): raise Exception("ABSTRACT METHOD CALLED") return # PROTOTYPE def setVolume(self): raise Exception("ABSTRACT METHOD CALLED") return def asDict(self): return todict(self) def propDict(self): return {"pulsesink":"pulsesink"} def updateDefaultSink(self, string): self.isDefaultSink = (self.name == in_unicode(string)) self.default_sink_name = in_unicode(string) def set_has_monitor(self, aboolean): self.monitor_enabled = aboolean def has_monitor(self): return self.monitor_enabled def printDebug(self): print("self.index:", self.index) print("self.name:", in_unicode(self.name)) print("self.mute:", self.mute) print("self.volume:", self.volume) print("self.client:", self.client) return ################################################################################ class PulseSinkInfo(PulseSink): def __init__(self, pa_sink_info): PulseSink.__init__(self, pa_sink_info.index, pa_sink_info.name, pa_sink_info.mute, PulseVolumeCtypes(pa_sink_info.volume, pa_sink_info.channel_map), PulseClient("Selected Sink")) self.description = in_unicode(pa_sink_info.description) self.sample_spec = in_unicode(pa_sink_info.sample_spec) self.channel_map = in_unicode(pa_sink_info.channel_map) self.owner_module = int(pa_sink_info.owner_module) self.monitor_source = in_unicode(pa_sink_info.monitor_source) self.monitor_source_name = in_unicode(pa_sink_info.monitor_source_name) self.latency = int(pa_sink_info.latency) self.driver = in_unicode(pa_sink_info.driver) self.flags = in_unicode(pa_sink_info.flags) self.proplist = pa_sink_info.proplist self.active_port = "" self.ports = {} for x in range(pa_sink_info.n_ports): self.ports[in_unicode(pa_sink_info.ports[x].contents.name)] = in_unicode(pa_sink_info.ports[x].contents.description) if(pa_sink_info.active_port): self.active_port = in_unicode(pa_sink_info.active_port.contents.name) #self.configured_latency = pa_sink_info.configured_latency self.device_name = in_unicode(pa_proplist_gets(pa_sink_info.proplist, as_p_char("device.description"))) self.proplist_string = in_unicode( pa_proplist_to_string(pa_sink_info.proplist)) self.proplist_dict = proplist_to_dict(self.proplist_string ) return def propDict(self): dict = { "description": self.description , # self.sample_spec #self.channel_map "owner_module": str(self.owner_module), "monitor_source" : str(self.monitor_source), "monitor_source_name" : self.monitor_source_name, "latency" : str(self.latency), "driver" : str(self.driver) , "flags" : str(self.flags) , "device_name" : self.device_name, "isdefault" : str(self.isDefaultSink), "default_sink_name" : str(self.default_sink_name), "has_monitor" : str(self.has_monitor()) } dict.update(self.proplist_dict) return dict def asDict(self): obj = todict(self) for key in ["sample_spec", "channel_map" ,"proplist"]: if key in list(obj.keys()): del obj[key] return assertEncoding(obj) #return obj ### # # Define PROTOTYPE functions def unmuteStream(self, pulseInterface): pulseInterface.pulse_unmute_sink(self.index) self.mute = 0 return ### def muteStream(self, pulseInterface): pulseInterface.pulse_mute_sink(self.index) self.mute = 1 return ### def setVolume(self, pulseInterface, volume): pulseInterface.pulse_set_sink_volume(self.index, volume) self.volume = volume return ### def asDict(self): return self.propDict() def printDebug(self): print("PulseSinkInfo") PulseSink.printDebug(self) print("self.description", self.description) print("self.sample_spec", self.sample_spec) print("self.channel_map", self.channel_map) print("self.owner_module", self.owner_module) print("self.monitor_source", self.monitor_source) print("self.monitor_source_name", self.monitor_source_name) print("self.latency", self.latency) print("self.driver", self.driver) print("self.flags", self.flags) print("self.proplist", self.proplist) #print "self.configured_latency", self.configured_latency return ### def __str__(self): return "ID: " + str(self.index) + ", Name: \"" + \ self.name + "\"" ################################################################################ class PulseSinkInputInfo(PulseSink): def __init__(self, pa_sink_input_info): PulseSink.__init__(self, pa_sink_input_info.index, pa_sink_input_info.name, pa_sink_input_info.mute, PulseVolumeCtypes(pa_sink_input_info.volume, pa_sink_input_info.channel_map), PulseClient("Unknown client")) self.owner_module = in_unicode(pa_sink_input_info.owner_module) self.client_id = int(pa_sink_input_info.client) self.sink = int(pa_sink_input_info.sink) self.sample_spec = in_unicode(pa_sink_input_info.sample_spec) self.channel_map = in_unicode(pa_sink_input_info.channel_map) self.monitor_index = int(pa_sink_input_info.monitor_index) self.buffer_usec = int(pa_sink_input_info.buffer_usec) self.sink_usec = int(pa_sink_input_info.sink_usec) self.resample_method = in_unicode(pa_sink_input_info.resample_method) self.driver = in_unicode(pa_sink_input_info.driver) self.proplist = pa_sink_input_info.proplist self.proplist_string = in_unicode( pa_proplist_to_string(pa_sink_input_info.proplist)) self.proplist_dict = proplist_to_dict(self.proplist_string ) self.app = in_unicode(pa_proplist_gets(pa_sink_input_info.proplist, as_p_char("application.name"))) self.app_icon = in_unicode(pa_proplist_gets(pa_sink_input_info.proplist, as_p_char("application.icon_name"))) if self.app and self.app.find("ALSA") == 0: self.app = in_unicode(pa_proplist_gets(pa_sink_input_info.proplist, as_p_char("application.process.binary"))) return def propDict(self): adict = { "index" : str(self.index), "name" : in_unicode(self.name), "owner_module" : str(self.owner_module), "client_id" : str(self.client_id ) , "sink" : str(self.sink), "sample_spec" : str(self.sample_spec), "channel_map" : str(self.channel_map), #"volume" "buffer_usec" : str(self.buffer_usec), "sink_usec" : str(self.sink_usec), "resample_method" : str(self.resample_method), "driver" : str(self.driver), #"mute" #"monitor_index" : str(self.monitor_index), "app" : str(self.app), "app_icon" : str(self.app_icon), "isdefault" : str(self.isDefaultSink), "has_monitor" : str(self.has_monitor()) #"proplist" : str(self.proplist_string) } adict.update(self.proplist_dict) for key in ["sample_spec", "channel_map" ,"application.process.session_id"]: if key in list(adict.keys()): del adict[key] #print adict return assertEncoding(adict) #return adict ### def setClient(self, c): self.client = c ### # # Define PROTOTYPE functions def unmuteStream(self, pulseInterface): pulseInterface.pulse_unmute_stream(self.index) self.mute = 0 return ### def muteStream(self, pulseInterface): pulseInterface.pulse_mute_stream(self.index) self.mute = 1 return ### def setVolume(self, pulseInterface, volume): pulseInterface.pulse_set_sink_input_volume(self.index, volume) self.volume = volume return ### def printDebug(self): print("PulseSinkInputInfo") PulseSink.printDebug(self) print("self.owner_module:", self.owner_module) print("self.client_id:", self.client_id) print("self.sink:", self.sink) print("self.sample_spec:", self.sample_spec) print("self.channel_map:", self.channel_map) print("self.buffer_usec:", self.buffer_usec) print("self.sink_usec:", self.sink_usec) print("self.resample_method:", self.resample_method) print("self.driver:", self.driver) ### def __str__(self): if self.client: return "ID: " + str(self.index) + ", Name: \"" + \ str(self.name) + "\", mute: " + str(self.mute) + ", " + str(self.client) return "ID: " + str(self.index) + ", Name: \"" + \ str(self.name) + "\", mute: " + str(self.mute) veromix/dbus-service/pulseaudio/PulseVolume.py0000644000175100017500000000711311766302605020454 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # Copyright (C) 2009 Harry Karvonen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from .lib_pulseaudio import * import math from VeromixUtils import * # This contains all basic volume features class PulseVolume: def __init__(self, vol, channels): self.channels = channels if vol > 100 or vol < 0: print("WARNING: Volume is invalid!") vol = 0 self.values = [vol] * self.channels return def __init__(self, values): self.channels = len(values) self.values = values return ############################## # # Type conversions # #def fromCtypes(self, pa_cvolume): # self.channels = pa_cvolume.channels # self.values = map(lambda x: (math.ceil(float(x) * 100 / PA_VOLUME_NORM)), # pa_cvolume.values[0:self.channels]) # return self def toCtypes(self): ct = struct_pa_cvolume() ct.channels = self.channels for x in range(0, self.channels): ct.values[x] = int((self.values[x] * PA_VOLUME_NORM) / 100) return ct def toCtypes2(self, num): ct = struct_pa_cvolume() ct.channels = num for x in range(0, num): ct.values[x] = (self.values[x] * PA_VOLUME_NORM) / 100 return ct ### def printDebug(self): print("PulseVolume") print("self.channels:", self.channels) print("self.values:", self.values) #print "self.proplist:", self.proplist ### def incVolume(self, vol): "Increment volume level (mono only)" vol += sum(self.values) / len(self.values) vol = int(vol) if vol > 100: vol = 100 elif vol < 0: vol = 0 self.setVolume(vol) return ### def setVolume(self, vol, balance = None): if not balance: self.values = [vol] * self.channels else: self.values[balance] = vol return ### def getVolume(self): "Return mono volume" return int(sum(self.values) / len(self.values)) ### def __str__(self): return "Channels: " + str(self.channels) + \ ", values: \"" + str([str(x) + "%" for x in self.values]) + "\"" ################################################################################ class PulseVolumeCtypes(PulseVolume): def __init__(self, pa_cvolume, pa_channel_map): self.channels = pa_cvolume.channels self.channel_map = pa_channel_map self.values = [(math.ceil(float(x) * 100 / PA_VOLUME_NORM)) for x in pa_cvolume.values[0:self.channels]] return def getVolumes(self): vol = {} for i in range(0, self.channels): key = pa_channel_position_to_pretty_string(self.channel_map.map[i]) entry = {} entry[in_unicode(key)] = self.values[i] vol[i] = entry return vol veromix/dbus-service/pulseaudio/PulseSource.py0000644000175100017500000002152211766302605020445 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # Copyright (C) 2009 Harry Karvonen # Copyright (C) 2009 Paul W. Frields # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from .lib_pulseaudio import * from .PulseClient import PulseClient from .PulseClient import PulseClientCtypes from .PulseVolume import PulseVolumeCtypes from .PulseVolume import PulseVolume from VeromixUtils import * # This class contains all commons features from PulseSourceInputInfo and # PulseSourceInfo class PulseSource: def __init__(self, index, name, client): self.index = int(index) self.name = in_unicode(name) self.client = client self.isDefaultSource = False self.monitor_enabled = False return # PROTOTYPE def unmuteStream(self): raise Exception("ABSTRACT METHOD CALLED") return # PROTOTYPE def muteStream(self): raise Exception("ABSTRACT METHOD CALLED") return # PROTOTYPE def setVolume(self): raise Exception("ABSTRACT METHOD CALLED") return def printDebug(self): print("self.name:", self.name) print("self.index:", self.index) print("self.client:", self.client) return def set_has_monitor(self, aboolean): self.monitor_enabled = aboolean def has_monitor(self): return self.monitor_enabled def propDict(self): return { "name:": self.name, "index:": self.index , "client:": self.client, "has_monitor" : str(self.has_monitor())} ################################################################################ class PulseSourceInfo(PulseSource): def __init__(self, pa_source_info): PulseSource.__init__(self, pa_source_info.index, pa_source_info.name, PulseClient("PulseSourceInfo")) self.mute = pa_source_info.mute self.volume = PulseVolumeCtypes(pa_source_info.volume,pa_source_info.channel_map ) self.description = in_unicode(pa_source_info.description) self.sample_spec = in_unicode(pa_source_info.sample_spec) self.channel_map = in_unicode(pa_source_info.channel_map) self.owner_module = in_unicode(pa_source_info.owner_module) self.monitor_of_sink = in_unicode(pa_source_info.monitor_of_sink) self.monitor_of_sink_name = in_unicode(pa_source_info.monitor_of_sink_name) self.latency = in_unicode(pa_source_info.latency) self.driver = in_unicode(pa_source_info.driver) self.flags = in_unicode(pa_source_info.flags) self.proplist = pa_source_info.proplist self.n_ports = int(pa_source_info.n_ports) self.ports = {} self.active_port = "" for x in range(self.n_ports): self.ports[in_unicode(pa_source_info.ports[x].contents.name)] = in_unicode(pa_source_info.ports[x].contents.description) if pa_source_info.active_port: self.active_port = in_unicode(pa_source_info.active_port.contents.name) #self.configured_latency = pa_source_info.configured_latency self.proplist_string = in_unicode(pa_proplist_to_string(pa_source_info.proplist)) self.proplist_dict = proplist_to_dict(self.proplist_string ) return def propDict(self): aDict = { "description": self.description, "sample_spec": self.sample_spec , "channel_map": self.channel_map, "owner_module":self.owner_module , "monitor_of_sink":self.monitor_of_sink , "monitor_of_sink_name":self.monitor_of_sink_name , "latency":self.latency , "driver":self.driver , "flags":self.flags, "isdefault" : str(self.isDefaultSource), "has_monitor" : str(self.has_monitor())} aDict.update(self.proplist_dict) return assertEncoding(aDict) ### # # Define PROTOTYPE functions def unmuteStream(self, pulseInterface): pulseInterface.pulse_unmute_source(self.index) self.mute = 0 return ### def muteStream(self, pulseInterface): pulseInterface.pulse_mute_source(self.index) self.mute = 1 return ### def setVolume(self, pulseInterface, volume): pulseInterface.pulse_set_source_volume(self.index, volume) self.volume = volume return ### def printDebug(self): print("PulseSourceInfo") PulseSource.printDebug(self) print("self.mute:", self.mute) print("self.volume:", self.volume) print("self.description", self.description) print("self.sample_spec", self.sample_spec) print("self.channel_map", self.channel_map) print("self.owner_module", self.owner_module) print("self.monitor_of_sink", self.monitor_of_sink) print("self.monitor_of_sink_name", self.monitor_of_sink_name) print("self.latency", self.latency) print("self.driver", self.driver) print("self.flags", self.flags) #print "self.proplist", self.proplist print("self.configured_latency", self.configured_latency) return ### def __str__(self): return "ID: " + str(self.index) + ", Name: \"" + \ self.name + "\"" def updateDefaultSource(self, string): self.isDefaultSource = (self.name == string) ################################################################################ class PulseSourceOutputInfo(PulseSource): def __init__(self, pa_source_output_info): PulseSource.__init__(self, pa_source_output_info.index, pa_source_output_info.name, PulseClient("PulseSourceOutputInfo")) self.owner_module = pa_source_output_info.owner_module self.client_id = pa_source_output_info.client self.source = in_unicode(pa_source_output_info.source) self.sample_spec = pa_source_output_info.sample_spec self.channel_map = pa_source_output_info.channel_map self.buffer_usec = pa_source_output_info.buffer_usec self.source_usec = None #pa_source_output_info.source_usec self.resample_method = in_unicode(pa_source_output_info.resample_method) self.driver = pa_source_output_info.driver self.proplist = pa_source_output_info.proplist self.proplist_string = in_unicode(pa_proplist_to_string(pa_source_output_info.proplist)) self.proplist_dict = proplist_to_dict(self.proplist_string ) return def propDict(self): aDict = self.proplist_dict aDict.update({ "owner_module": self.owner_module, "client_id": self.client_id, "source": self.source , "sample_spec": self.sample_spec, "channel_map":self.channel_map , "buffer_usec":self.buffer_usec , "source_usec":self.source_usec , "driver":self.driver , "resample_method":self.resample_method, "isdefault" : str(self.isDefaultSource), "has_monitor" : str(self.has_monitor())}) return assertEncoding(aDict) ### def setClient(self, c): self.client = c ### def printDebug(self): print("PulseSourceOutputInfo") PulseSource.printDebug(self) print("self.owner_module:", self.owner_module) print("self.client_id:", self.client_id) print("self.source:", self.source) print("self.sample_spec:", self.sample_spec) print("self.channel_map:", self.channel_map) print("self.buffer_usec:", self.buffer_usec) print("self.source_usec:", self.source_usec) print("self.resample_method:", self.resample_method) print("self.driver:", self.driver) ### def __str__(self): if self.client: return "ID: " + str(self.index) + ", Name: \"" + \ self.name + "\", " + str(self.client) return "ID: " + str(self.index) + ", Name: \"" + \ self.name + "\", " veromix/dbus-service/pulseaudio/PulseStream.py0000644000175100017500000000357211766302605020445 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # Copyright (C) 2009 Harry Karvonen # Copyright (C) 2009 Paul W. Frields # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from .lib_pulseaudio import * from ctypes import * from .PulseClient import PulseClient from .PulseVolume import PulseVolumeCtypes class PulseStream: def __init__(self, context, name, sample_spec, channel_map): self.context = context self.name = name self.sample_spec = sample_spec self.channel_map = channel_map self.data = None self.size = None return def connect_record(self, source): #pa_stream_connect_record(pa_stream, str(monitor_index), attr, 10752) retval = pa_stream_connect_record(self, source.name, None, # buffer_attr 0) # flags if retval != 0: raise Exception("Couldn't do connect_record()") def peek(self, pulseInterface): pa_stream_peek(self, data, size) def disconnect(self): retval = pa_stream_disconnect(self) if retval != 0: raise Exception("Couldn't do disconnect()") veromix/dbus-service/VeromixUtils.py0000644000175100017500000000652711766302605016504 0ustar nikkibu# -*- coding: utf-8 -*- # Copyright (C) 2010-2012 Nik Lutz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys use_old = True if sys.version_info >= (3, 0): use_old = False class UnicodingError(Exception): pass # these encodings should be in most likely order to save time encodings = [ "ascii", "utf_8", "big5", "big5hkscs", "cp037", "cp424", "cp437", "cp500", "cp737", "cp775", "cp850", "cp852", "cp855", "cp856", "cp857", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866", "cp869", "cp874", "cp875", "cp932", "cp949", "cp950", "cp1006", "cp1026", "cp1140", "cp1250", "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256", "cp1257", "cp1258", "euc_jp", "euc_jis_2004", "euc_jisx0213", "euc_kr", "gb2312", "gbk", "gb18030", "hz", "iso2022_jp", "iso2022_jp_1", "iso2022_jp_2", "iso2022_jp_2004", "iso2022_jp_3", "iso2022_jp_ext", "iso2022_kr", "latin_1", "iso8859_2", "iso8859_3", "iso8859_4", "iso8859_5", "iso8859_6", "iso8859_7", "iso8859_8", "iso8859_9", "iso8859_10", "iso8859_13", "iso8859_14", "iso8859_15", "johab", "koi8_r", "koi8_u", "mac_cyrillic", "mac_greek", "mac_iceland", "mac_latin2", "mac_roman", "mac_turkish", "ptcp154", "shift_jis", "shift_jis_2004", "shift_jisx0213", "utf_32", "utf_32_be", "utf_32_le", "utf_16", "utf_16_be", "utf_16_le", "utf_7", "utf_8_sig" ] def in_unicode(string): if use_old: return _in_unicode(string) if isinstance(string, bytes): return string.decode("utf-8") return str(string) def _in_unicode(string): # FIXME - fix the sender! if string == None: return "None" if isinstance(string, int): return str(string) if isinstance(string, float): return str(string) if isinstance(string, long): return str(string) if isinstance(string, tuple): if len(string) > 1: return in_unicode(string[0]) return "" if isinstance(string, unicode): return string for enc in encodings: try: utf8 = unicode(string, enc) return utf8 except: if enc == encodings[-1]: #raise UnicodingError("still don't recognise encoding after trying do guess.") # print type(string) return "problem with string decoding" return "problem with string decoding" def proplist_to_dict(string): dict = {} lines = string.split("\n") for line in lines: arr = line.split(" = ") if len(arr) == 2: dict[arr[0]] = in_unicode(arr[1].strip('"')) return dict def assertEncoding(aDict): for key in aDict.keys(): try: aDict[key]= in_unicode(aDict[key]) except: aDict[key] = "error with string encoding #1" return aDict