summaryrefslogtreecommitdiffstats
path: root/bin/pulse-dbus-receive.py
blob: 62a967a8740f1a4297d061b0da35bcf2a7b69296 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env python2
# -*- coding: utf-8 -*-

import os, sys
import dbus
import gobject
import subprocess
from dbus.mainloop.glib import DBusGMainLoop
import sys
from functools import partial
import time

home = os.path.expanduser('~')
safe = {
    'sink': None,
    'muted': False,
    'volume': 0,
    'baseVolume': 0,
}
BAR_WIDTH = 50

def output_volume(vol):
    print('^cs()')
    bar = min(vol * BAR_WIDTH / 100, BAR_WIDTH)
    print('^fg(#999)^r(%dx6)^fg(#444)^r(%dx6)^fg()' % (bar, BAR_WIDTH - bar))
    sys.stdout.flush()

def output_mute(mute):
    if mute:
        print('^tw()^fg(#FF0000)^i(%s/.dzen2/icons/vol-mute.xbm)' % home)
    else:
        print('^tw()^fg()^i(%s/.dzen2/icons/vol-hi.xbm)' % home)
    sys.stdout.flush()

def dbus_connect():
    if 'PULSE_DBUS_SERVER' in os.environ:
        address = os.environ['PULSE_DBUS_SERVER']
    else:
        bus = dbus.SessionBus()
        server_lookup = bus.get_object("org.PulseAudio1", "/org/pulseaudio/server_lookup1")
        address = server_lookup.Get("org.PulseAudio.ServerLookup1", "Address", dbus_interface="org.freedesktop.DBus.Properties")
    return dbus.connection.Connection(address)

def update_volume(volumes, force=False):
    volume = (max(volumes) * 100)/safe['baseVolume']
    if safe['volume'] != volume or force:
        safe['volume'] = volume
        output_volume(safe['volume'])

def update_muted(muted, force=False):
    if safe['muted'] != muted or force:
        safe['muted'] = muted
        output_mute(muted)

def signal_cb(*args, **kwargs):
    msg = kwargs['msg']
    bus = kwargs['bus']

    if msg.get_interface() == 'org.PulseAudio.Core1.Device':
        if safe['sink'] is not None and msg.get_path() != safe['sink']:
	    return
        if msg.get_member() == 'VolumeUpdated':
            update_volume(args[0])
	elif msg.get_member() == 'MuteUpdated':
            update_muted(args[0])
    elif msg.get_interface()  == 'org.PulseAudio.Core1':
	if msg.get_member() == 'FallbackSinkUpdated':
	    init(bus, args[0])
    else:
        print msg

def init(bus, sink=None):
    if sink is not None:
	safe['sink'] = sink
    elif len(sys.argv) > 1:
        safe['sink'] = sys.argv[1]

    core = bus.get_object(object_path="/org/pulseaudio/core1")
    safe['sink'] = core.Get('org.PulseAudio.Core1', 'FallbackSink')

    sink = bus.get_object('org.PulseAudio.Core1.Device', safe['sink'])
    safe['baseVolume'] = sink.Get('org.PulseAudio.Core1.Device', 'BaseVolume')

    update_muted(sink.Get('org.PulseAudio.Core1.Device', 'Mute'), True)
    update_volume(sink.Get('org.PulseAudio.Core1.Device', 'Volume'), True)

def setup(loop, conn=None):
    bus = None
    while True:
        try:
            if conn is not None:
                time.sleep(2)
            bus = dbus_connect()
            break
        except:
            if conn is None:
                break

    if bus is None:
        print "Could not connect to dbus!"
        sys.exit(1)

    bus.call_on_disconnection(partial(setup, loop))
    init(bus)

    bus.add_signal_receiver(partial(signal_cb, bus=bus), message_keyword='msg')
    core = bus.get_object(object_path="/org/pulseaudio/core1")
    core.ListenForSignal('org.PulseAudio.Core1.Device.VolumeUpdated', dbus.Array(signature='o'))
    core.ListenForSignal('org.PulseAudio.Core1.Device.MuteUpdated', dbus.Array(signature='o'))

    if len(sys.argv) <= 1:
	core.ListenForSignal('org.PulseAudio.Core1.FallbackSinkUpdated', dbus.Array(signature='o'))

    loop.run()

if __name__ == '__main__':
    DBusGMainLoop(set_as_default=True)
    loop = gobject.MainLoop()
    setup(loop)