mk-fg / python-pulse-control

Python high-level interface and ctypes-based bindings for PulseAudio (libpulse)
https://pypi.org/project/pulsectl/
MIT License
171 stars 36 forks source link

Methods for proplist editing #21

Closed thegrumble closed 6 years ago

thegrumble commented 6 years ago

It would be handy to have wrappers around the methods that modify proplists (like pacmd does).

In particular, my use case for this is modifying the descriptions and names (device.description and similar) of sink inputs and source outputs.

mk-fg commented 6 years ago

Hi.

Yeah, shouldn't be hard to add, at least code-wise, will look at it a bit later today.

Not sure if it'd be more obvious to make proplist dict into something magical (that updates proplist in pulse when changed), make o.proplist a descriptor (i.e. property() thing) or just add o.proplist_update(key, value) method alongside it.

Last one seem to be most explicit and straightforward (no magic!) and shouldn't confuse people with extra custom types, but maybe you have a better idea?

mk-fg commented 6 years ago

Oh, right, proplists are updated in similar way to how Pulse.stream_restore_write() currently does it, with options to set/replace whole proplist or merge, which'd probably be useful to preserve, so definitely needs separate o.proplist_update(mode='merge', **props) or such.

mk-fg commented 6 years ago

Just looked more into it, and bad news - it doesn't seem to be supported for arbitrary streams. It's not in the introspection API, and stuff like "pa_stream_new_with_proplist" and "pa_stream_proplist_update" (client command) are only for streams that this pulse client creates, not arbitrary ones from other clients.

Looking at command_update_proplist() in native protocol, which gets run for PA_COMMANDUPDATE*_PROPLIST, it only picks streams from client's c->output_streams or c->record_streams, i.e. cannot affect other streams running on the pulse server.

Of course, module-cli code you've linked gets around that by running stuff in server context, which is what pacmd is for, with its separate protocol and access checks - kinda like "sudo" of pulseaudio.

So won't be able to add such commands, as libpulse does not have them.

You can however work around this limitation by using pulsectl.connect_to_cli() and writing "update-\<something>-proplist" lines through that to module-cli, which allows this stuff. Don't think it'd make sense to add special methods for that, as it's an entirely different interface, as mentioned, and should probably be simple enough to use as it is.

mk-fg commented 6 years ago

In particular, my use case for this is modifying the descriptions and names (device.description and similar) of sink inputs and source outputs.

One more thing that I've remembered that might be useful to you here.

If you're doing that to distinguish or annotate streams that are created by apps under your control, libpulse allows for adding extra stuff to proplists it creates via env vars.

E.g. one trick I use to have pulse store volume for mpv (linux media player) "music" streams separately from other streams of that app (e.g. videos), is to run it as: env PULSE_PROP_media.role=music mpv ... (module-stream-restore then picks up that "media.role" prop and stores volume level under it, instead of default generic "app-name:mpv" entry)

You should be able to add any extra props you want that way. Not sure if it'd allow you to override props though - maybe only add new ones - but might be a better option than setting them separately on the server for streams via module-cli, if you don't really have to override stuff.