Hi all,

Finally had time to check the pulseaudio mixer in E17 and while it
work, I do have some concerns regarding things below:

 - talking bare metal PA protocol is cumbersome, DBus API is the way
to go according to developers;

 - sticking (id + 1) to address cards and channels, while the actual
string name could be used (cosmetic, but would help debug);

 - not using the generic properties like device.class (to filter) and
device.description (to provide human-readable name);

 - not providing source handling and thus no way to control microphone;

 - pulse code was mixed into e_mod*.c, something I'd like to avoid.
Yes, what I did before was a compile-time module, thus symbols had to
be defined in the correct module. But it's easy to change to a struct
with defined pointers... e_mixer_pulse_setup() and
e_mixer_default_setup() are cumbersome and will get ugly if we need to
add a 3rd system :-(

I've hacked a quick python-dbus test (attached) to show how it could
be done with DBus, it does cover all our cases and if done properly
will even create/remove elements on the fly given PA changes.

What I noticed is that some changes to the internal sys_* API must be changed:

  - create sys_common.c to implement e_mixer_system* functions calling
plugins (alsa, dummy, pulse)

  - replace detection of "capture" mode from channel and create 3
specific lists to be used by the app_mixer (dialog)
     * sources (capture channel)
     * sinks (output channel)
     * users (or applications?)

  - replace hard coded 2-volume (left, right) with a list of values
and given names. However seems that PA will handle a single volume
value, applying to all the same. No idea how useful will be to open a
5.1 video in VLC and have 6 sliders to show in E17.

With these in place is easier to add a simpler PA and keep the same
infra. I'd use DBus here, but there is no issue to use current bare
metal code... just more work (now and in the long term).

If people agree I can try to do these sys_* API changes soon and help
with the dbus api.

-- 
Gustavo Sverzut Barbieri
http://profusion.mobi embedded systems
--------------------------------------
MSN: barbi...@gmail.com
Skype: gsbarbieri
Mobile: +55 (19) 9225-2202
#!/usr/bin/env python

import dbus
import os
import sys


if "-h" in sys.argv or "--help" in sys.argv:
    print "Usage:"
    print "\t%s <dbus-device-path> <property> <value1> <valueN>" % sys.argv[0]
    print """
very raw way to change values -- not user friendly.

Caveats:
\t- must provide full dbus object path for an org.PulseAudio.Core1.Device
\t  compatible interface (sinks or sources)
\t- just Mute and Volume properties are supported
\t- volume must be set in absolute number and for every channel

Examples:
\tSet volume of a 2-channel source (microphone):
\t\tdbus-device-path: /org/pulseaudio/core1/source2
\t\tproperty: Volume
\t\tvalues: 65536 65536
\tMute an output (sink)
\t\tdbus-device-path: /org/pulseaudio/core1/sink0
\t\tproperty: Mute
\t\tvalues: 1
"""
    raise SystemExit()

try:
    conf_path = sys.argv[1]
    conf_prop = sys.argv[2]
    conf_values = sys.argv[3:]

    if conf_prop not in ("Mute", "Volume"):
        raise SystemExit("Unsupported property: %s" % conf_prop)

except IndexError:
    conf_path = conf_prop = conf_values = None

def 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), address


conn, address = connect()
core = conn.get_object(object_path="/org/pulseaudio/core1")

print "Successfully connected to %s (%s)" % (core.Get("org.PulseAudio.Core1", "Name", dbus_interface="org.freedesktop.DBus.Properties"), address)

if conf_path and conf_prop and conf_values:
    o = conn.get_object(object_path=conf_path)
    iface = "org.PulseAudio.Core1.Device"

    old_vals = o.Get(iface, conf_prop)
    if isinstance(old_vals, dbus.Array):
        vals = dbus.Array([y.__class__(int(x))
                           for x, y in zip(conf_values, old_vals)],
                          signature=old_vals.signature,
                          variant_level=old_vals.variant_level)
    else:
        vals = old_vals.__class__(int(conf_values[0]),
                                  variant_level=old_vals.variant_level)
    o.Set(iface, conf_prop, vals)


def print_props(o, iface, props):
    def prop(name):
        try:
            return o.Get(iface, name)
        except dbus.exceptions.DBusException:
            return None
    print "%s:" % (o.object_path,)
    for p in props:
        val = prop(p)
        if isinstance(val, dbus.Array):
            x = []
            for e in val:
                x.append(str(e))
            val = ", ".join(x)
        print "\t%s: %s" % (p, val)

    d = prop("PropertyList")
    if d:
        print "\tPROPERTIES:"
        lst = list(d.iteritems())
        lst.sort()
        for k, v in lst:
            print "\t\t%s: %s" % (k, "".join(chr(x) for x in v))

    print

def core_get_prop_obj_iterator(name):
    for path in core.Get("org.PulseAudio.Core1", name):
        o = conn.get_object(object_path=path)
        yield o

def print_dev(o):
    print_props(o, "org.PulseAudio.Core1.Device",
                ("Name", "Index", "Channels", "Volume", "BaseVolume",
                 "VolumeSteps", "Mute", "State", "Ports"))

print "SINKS:"
for o in core_get_prop_obj_iterator("Sinks"):
    print_dev(o)

print "SOURCES:"
for o in core_get_prop_obj_iterator("Sources"):
    print_dev(o)

print "CARDS:"
for o in core_get_prop_obj_iterator("Cards"):
    print_props(o, "org.PulseAudio.Core1.Card",
                ("Name", "Index", "Sinks"))#, "Sources", "Profiles"):

print "CLIENTS:"
for o in core_get_prop_obj_iterator("Clients"):
    print_props(o, "org.PulseAudio.Core1.Client",
                ("Index", "PlaybackStreams", "RecordStreams"))

print "SUMMARY:"
def get_prop(o, iface, name):
    try:
        return o.Get(iface, name)
    except dbus.exceptions.DBusException:
        return None

def get_gen_prop(o, iface, name):
    try:
        props = o.Get(iface, "PropertyList")
    except dbus.exceptions.DBusException:
        return None
    if not props:
        return None
    x = props.get(name)
    if x:
        return "".join(chr(v) for v in x[:-1])

for o in core_get_prop_obj_iterator("Sinks"):
    iface = "org.PulseAudio.Core1.Device"
    cls = get_gen_prop(o, iface, "device.class")
    if cls != "sound":
        continue
    print "sink: %s" % (get_prop(o, iface, "Name"))
    desc = get_gen_prop(o, iface, "device.description")
    if desc:
        print "\tdescription:", desc
    print "\tmute: %s, volumes:" % (get_prop(o, iface,"Mute"),),
    vols = get_prop(o, iface, "Volume")
    base_vol = get_prop(o, iface, "BaseVolume")
    for v in vols:
        print "%4.1f%%" % (100.0 * float(v) / base_vol),
    print


for o in core_get_prop_obj_iterator("Sources"):
    iface = "org.PulseAudio.Core1.Device"
    cls = get_gen_prop(o, iface, "device.class")
    if cls != "sound":
        continue
    print "source: %s" % (get_prop(o, iface, "Name"))
    desc = get_gen_prop(o, iface, "device.description")
    if desc:
        print "\tdescription:", desc
    print "\tmute: %s, volumes:" % (get_prop(o, iface,"Mute"),),
    vols = get_prop(o, iface, "Volume")
    base_vol = get_prop(o, iface, "BaseVolume")
    for v in vols:
        print "%4.1f%%" % (100.0 * float(v) / base_vol),
    print


def print_stream(o):
    iface = "org.PulseAudio.Core1.Stream"

    dev_path = get_prop(o, iface, "Device")
    print "\t\tid: %d, device: %s" % (get_prop(o, iface, "Index"), dev_path)
    print "\t\t\tchannels: %d, mute: %s, volume:" % \
        (len(get_prop(o, iface, "Channels")),
         get_prop(o, iface, "Mute")),

    base_vol = get_prop(conn.get_object(object_path=dev_path),
                        "org.PulseAudio.Core1.Device", "BaseVolume")
    vols = get_prop(o, iface, "Volume")
    for v in vols:
        print "%4.1f%%" % (100.0 * float(v) / base_vol),
    print

for o in core_get_prop_obj_iterator("Clients"):
    iface = "org.PulseAudio.Core1.Client"
    p_streams = get_prop(o, iface, "PlaybackStreams")
    r_streams = get_prop(o, iface, "RecordStreams")
    if not p_streams and not r_streams:
        continue
    appname = get_gen_prop(o, iface, "application.name")
    if not appname:
        appname = "Client %s" % (get_prop(o, iface, "Index"))
    print "client: %s" % (appname,)
    if p_streams:
        print "\tplayback:"
        for path in p_streams:
            stream = conn.get_object(object_path=path)
            print_stream(stream)
    if r_streams:
        print "\trecord:"
        for path in r_streams:
            stream = conn.get_object(object_path=path)
            print_stream(stream)
------------------------------------------------------------------------------
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security
threats, fraudulent activity, and more. Splunk takes this data and makes
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2dcopy2
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to