sidorares/dbus-native

Setting a property of type 'au' (pulseaudio volume) produces marshall.js exceptions

Closed this issue · 4 comments

I'm trying to set the "Volume" property of a pulseaudio device via node-dbus. I can't seem to figure out how to do so. I know setting a property that isn't an array works but haven't had to set a property of type 'au' before now.

DBUS_PROPERTIES_INTERFACE = 'org.freedesktop.DBus.Properties';

// Parameters used to lookup the bus name of the pulseaudio dbus server
DBUS_PULSE_INTERFACE = 'org.PulseAudio.ServerLookup1';
DBUS_PULSE_DESTINATION = 'org.PulseAudio1';
DBUS_PULSE_PATH = '/org/pulseaudio/server_lookup1';

// Parameters used to itneract with the pulseaudio dbus service
DBUS_CORE_INTERFACE = 'org.PulseAudio.Core1.Device';
DBUS_CORE_DESTINATION = "org.PulseAudio.Core1.Device"
DBUS_CORE_PATH = '/org/pulseaudio/core1/sink0';

var dbus = require('dbus-native');

var bus = dbus.sessionBus();

var pulseInterface;
var deviceInterface;

bus.getService(DBUS_PULSE_DESTINATION).getInterface(DBUS_PULSE_PATH,
    DBUS_PROPERTIES_INTERFACE, function(err, iface) 
{
    console.log("completion");

    if (err) 
    {
        console.log("bus.getInterface ", err);
    }
    else
    {
        // retrieve the pulseaudio dbus server path
        pulseInterface = iface;

        pulseInterface.Get(DBUS_PULSE_INTERFACE, "Address", function(err, result)
        {
            console.log("err is " + err);
            console.log("result is " + result);
            console.log(result[1]);

            // strip 'unix:path=' from the start of the string
            console.log(typeof(result[1][0]))
            unixSocketPath = result[1][0].replace("unix:path=", "");
            console.log("socket path " + unixSocketPath)

            // connect to the pulseaudio server
            var pulseServerClient = dbus.createClient({
                socket: unixSocketPath,
                direct: true
            });

            // retrieve the volume
            pulseServerClient.getService(DBUS_CORE_DESTINATION).getInterface(DBUS_CORE_PATH,
            DBUS_PROPERTIES_INTERFACE, function(err, iface) {
                if(err)
                {
                    console.log("err from client service is " + err);
                }

                deviceInterface = iface;
                deviceInterface.Get(DBUS_CORE_INTERFACE, "Volume", function(err, result) {
                    if(err)
                    {
                        console.log("err is " + err);
                    }

                    console.log("result is " + result);

                    // set the volume
                    var volumes = [];
                    volumes[0] = 5535;
                    volumes[1] = 5535;
                    console.log(volumes);

                    var vol = { v1 : 5665, v2 : 5566};
                    console.log(vol);

                    deviceInterface.Set(DBUS_CORE_INTERFACE, "Volume", ['au', volumes], function(err, result) {
                        if(err)
                        {
                            console.log("set error " + err);
                        }

                        console.log("set completed");
                    });
                });
            });
        });
    }
});

Produces:

node patest.js 
completion
err is null
result is [object Object],unix:path=/run/user/1000/pulse/dbus-socket
[ 'unix:path=/run/user/1000/pulse/dbus-socket' ]
string
socket path /run/user/1000/pulse/dbus-socket
result is [object Object],6,5
[ 5535, 5535 ]
{ v1: 5665, v2: 5566 }

/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/lib/marshall.js:28
    throw new Error("Invalid struct data");
          ^
Error: Invalid struct data
    at writeStruct (/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/lib/marshall.js:28:11)
    at write (/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/lib/marshall.js:87:9)
    at writeStruct (/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/lib/marshall.js:31:5)
    at module.exports (/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/lib/marshall.js:16:13)
    at Object.marshallMessage [as marshall] (/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/lib/message.js:84:16)
    at EventEmitter.self.message (/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/index.js:118:28)
    at bus.invoke (/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/lib/bus.js:28:24)
    at Object.Set (/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/lib/introspect.js:112:13)
    at Object.<anonymous> (/home/cmorgan/projects/test/panodetest/patest.js:77:37)
    at EventEmitter.<anonymous> (/home/cmorgan/projects/test/panodetest/node_modules/dbus-native/lib/bus.js:113:26)

volumes needs to be like [ [5535, 5335] ].
Imagine that instead of 'au' you have 'sau' parameter type - that'll be serialized as [ 'foo', [1, 2, 3]].

Doh. This did fix things for me. I hope this ticket will help to answer the question for the next person who asks it as I did search around and couldn't find any examples of this particular type of usage.

Thank you again for your help and a cool library.

Yeah, serialisation can become tricky very fast. This needs to be improved somehow (in addition to documentation)

also, I'd like to add properties support to code generator ( see bin/dbus2js ) so api would be like

  var bus = connect-to-bus-somehow
  var PulseAudioDevice = require('./pulse')['org.PulseAudio.Core1.Device'];  // generated module
  var d = new PulseAudioDevice(bus, 'org.PulseAudio.Core1.Device', '/org/pulseaudio/core1/sink0');
  d.Address = "123" // would call org.freedesktop.DBus.Properties.Set internally. Not implemented yet
  // maybe use Promises to return value from props
  var p = d.Address;
  // can do yield with tj/co
  // or use promise directly
  p.then( function(addr) {
     console.log(addr);
  });