davemds pushed a commit to branch master. http://git.enlightenment.org/enlightenment/modules/edgar.git/commit/?id=ac8f0d942c1336cc8b948ed97057fcd9debe3bb7
commit ac8f0d942c1336cc8b948ed97057fcd9debe3bb7 Author: Dave Andreoli <d...@gurumeditation.it> Date: Sat May 2 12:10:39 2020 +0200 Audio: Better support for stereo channels Also start to factorize Players and Channels, in preparation for the upcoming MPD support --- gadgets/audio/__init__.py | 99 +++++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 34 deletions(-) diff --git a/gadgets/audio/__init__.py b/gadgets/audio/__init__.py index 8019029..216e936 100644 --- a/gadgets/audio/__init__.py +++ b/gadgets/audio/__init__.py @@ -1,7 +1,6 @@ # This python file use the following encoding: utf-8 import os -import sys import dbus from urllib.parse import unquote as url_unquote @@ -24,14 +23,48 @@ __gadget_vapi__ = 2 __gadget_opts__ = {'popup_on_desktop': True} -# def DBG(msg): -# print("AUDIO: %s" % msg) -# sys.stdout.flush() +def DBG(*args): + import sys + print("AUDIO:", *args) + sys.stdout.flush() _instance = None +class PlayerBase(object): + """ Define the interface that players must implement """ + name = 'Player name' + label = 'Player label' + metadata = {} # metadata dict as per mpris2 specs + playback_status = 'Stopped' # or 'Playing' or 'Paused' + + def play(self): + raise NotImplemented + + def prev(self): + raise NotImplemented + + def next(self): + raise NotImplemented + + def rais(self): + raise NotImplemented + + +class ChannelBase(object): + """ Define the interface that volume channels must implement """ + name = 'Channel name' + volumes = [0.0, 0.0] # left/right channels, range: 0.0 - 1.0 + muted = True + + def volume_set(self, vols): + raise NotImplemented + + def mute_toggle(self): + raise NotImplemented + + class Gadget(e.Gadget): def __init__(self): @@ -67,20 +100,21 @@ class Gadget(e.Gadget): def speaker_update(self, speaker): if self.pulse and len(self.pulse.channels) > 0: ch = self.pulse.channels[0] - left = right = ch.volume / 655 + left, right = ch.volumes[0] * 100, ch.volumes[1] * 100 speaker.message_send(0, (ch.muted, left, right)) def speaker_wheel_cb(self, obj, sig, source): if self.pulse.channels: ch = self.pulse.channels[0] - vol = ch.volume + vol = (ch.volumes[0] + ch.volumes[1]) / 2 if sig == 'mouse,wheel,0,1': - new_vol = vol - 3000 + new_vol = vol - 0.03 elif sig == 'mouse,wheel,0,-1': - new_vol = vol + 3000 + new_vol = vol + 0.03 else: return - ch.volume_set(min(max(0, new_vol), 65500)) + new_vol = min(max(0.0, new_vol), 1.0) + ch.volume_set([new_vol, new_vol]) def popup_created(self, elm_parent): # DBG("POPUP CREATED") @@ -100,11 +134,11 @@ class Gadget(e.Gadget): main_box.data['players_box'] = players_box main_box.data['volumes_box'] = volumes_box - # add all the available players to the popup edje box + # add all the available mpris players to the popup edje box for player in self.mpris.players: self.popup_player_add(main_box, player) - # add all the channel sliders + # add all the pulse channels sliders if self.pulse.conn is not None: for ch in self.pulse.channels: self.popup_volume_add(main_box, ch) @@ -162,7 +196,7 @@ class Gadget(e.Gadget): self.player_objs[player].append(o) def player_changed(self, player): - # the mpris player has changed, update all the relative edje objects + # the player has changed, update all the relative edje objects for o in self.player_objs.get(player, []): self.player_update(o, player) @@ -213,11 +247,11 @@ class Gadget(e.Gadget): pass def popup_volume_add(self, popup, channel): - sl = elm.Slider(popup, text=channel.name, min_max=(0, 65500), + sl = elm.Slider(popup, text=channel.name, min_max=(0.0, 1.0), span_size=150, indicator_show=False, size_hint_expand=EXPAND_HORIZ, size_hint_fill=FILL_HORIZ) - sl.value = channel.volume + sl.value = (channel.volumes[0] + channel.volumes[1]) / 2 sl.disabled = True if channel.muted else False sl.callback_changed_add(self.popup_slider_changed_cb, channel) sl.callback_slider_drag_start_add(self.popup_slider_drag_start_cb) @@ -236,7 +270,7 @@ class Gadget(e.Gadget): @staticmethod def popup_slider_changed_cb(slider, channel): - channel.volume_set(slider.value) + channel.volume_set([slider.value, slider.value]) @staticmethod def popup_slider_click_cb(slider, event, channel): @@ -256,7 +290,7 @@ class Gadget(e.Gadget): if channel in self.channel_objs: for sl in self.channel_objs[channel]: if 'dragging' not in sl.data: - sl.value = channel.volume + sl.value = (channel.volumes[0] + channel.volumes[1]) / 2 # update all the speakers for speaker in self._instances: self.speaker_update(speaker) @@ -318,7 +352,7 @@ class Mpris2_Client(object): break -class Mpris2_Player(object): +class Mpris2_Player(PlayerBase): MAIN_IFACE = 'org.mpris.MediaPlayer2' PLAYER_IFACE = 'org.mpris.MediaPlayer2.Player' @@ -362,21 +396,22 @@ class Mpris2_Player(object): self.proxy.Raise(dbus_interface=self.MAIN_IFACE) -class AudioChannel(object): - def __init__(self, obj, iface, name, volume, muted): +class PulseAudioChannel(ChannelBase): + def __init__(self, obj, iface, name, volumes, muted): self.obj = obj self.iface = iface self.name = name - self.volume = int(volume[0]) + self.volumes = [float(volumes[0]) / 65536, float(volumes[1]) / 65536] self.muted = muted # This do not work, only connection on the main pulse obj work... # so for the moment dispatch the callback from there # obj.connect_to_signal('VolumeUpdated', self.volume_changed_signal_cb) - def volume_set(self, value): - self.volume = value - self.obj.Set(self.iface, 'Volume', [dbus.UInt32(value)], + def volume_set(self, vols): # values 0.0 - 1.0 + self.volumes = vols + values = [dbus.UInt32(vols[0] * 65536), dbus.UInt32(vols[1] * 65536)] + self.obj.Set(self.iface, 'Volume', values, dbus_interface=dbus.PROPERTIES_IFACE) def mute_toggle(self): @@ -385,17 +420,13 @@ class AudioChannel(object): dbus_interface=dbus.PROPERTIES_IFACE) def volume_changed_signal_cb(self, volume): - self.volume = int(volume[0]) + self.volumes = [volume[0] / 65536, volume[1] / 65536] _instance.volume_changed(self) def mute_changed_signal_cb(self, muted): self.muted = muted _instance.mute_changed(self) - def __str__(self): - return '[%s]: "%s" volume: %s' % \ - (self.iface.split('.')[-1], self.name, self.volume[:]) - class PulseAudio_Client(object): PULSE_OBJ = '/org/pulseaudio/core1' @@ -541,8 +572,8 @@ class PulseAudio_Client(object): def stream_add(self, obj_path): try: obj = self.conn.get_object(self.STREAM_IFACE, obj_path) - volume = obj.Get(self.STREAM_IFACE, 'Volume', - dbus_interface=dbus.PROPERTIES_IFACE) + volumes = obj.Get(self.STREAM_IFACE, 'Volume', + dbus_interface=dbus.PROPERTIES_IFACE) mute = obj.Get(self.STREAM_IFACE, 'Mute', dbus_interface=dbus.PROPERTIES_IFACE) props = obj.Get(self.STREAM_IFACE, 'PropertyList', @@ -555,7 +586,7 @@ class PulseAudio_Client(object): except: name = 'Unknown app' - ch = AudioChannel(obj, self.STREAM_IFACE, name, volume, mute) + ch = PulseAudioChannel(obj, self.STREAM_IFACE, name, volumes, mute) self.channels.append(ch) _instance.channel_added(ch) return ch @@ -563,8 +594,8 @@ class PulseAudio_Client(object): def sink_add(self, obj_path): try: obj = self.conn.get_object(self.DEVICE_IFACE, obj_path) - volume = obj.Get(self.DEVICE_IFACE, 'Volume', - dbus_interface=dbus.PROPERTIES_IFACE) + volumes = obj.Get(self.DEVICE_IFACE, 'Volume', + dbus_interface=dbus.PROPERTIES_IFACE) mute = obj.Get(self.DEVICE_IFACE, 'Mute', dbus_interface=dbus.PROPERTIES_IFACE) props = obj.Get(self.DEVICE_IFACE, 'PropertyList', @@ -580,7 +611,7 @@ class PulseAudio_Client(object): except: name = 'Unknown device' - ch = AudioChannel(obj, self.DEVICE_IFACE, name, volume, mute) + ch = PulseAudioChannel(obj, self.DEVICE_IFACE, name, volumes, mute) self.channels.append(ch) _instance.channel_added(ch) return ch --