tags:

views:

84

answers:

3

I'm writing some C# bindings for the C library controlling the pulseaudio sound server, and I'm unsure how to idiomatically bind some potentially transient objects exposed: particularly sinks.

pulseaudio has the concept of an audio sink - the hardware a given audio stream is getting played to. This would naturally map to a Sink class, with some obvious properties - volume and such. The problem is hotplug - audio hardware can come and go during runtime, and so such Sink objects can end up as zombies referring to non-existent hardware, and all operations performed on them will fail. Worse, the C library doesn't offer unique handles to sinks, so a sequence of hotplug events could change the hardware a given Sink instance actually controls without the code noticing.

Both of these problems smell. I want to provide some Sink abstraction, but I'm not sure how to avoid these problems.

How have others in a similar situation handled this sort of problem?

EDIT: in the C library it appears you just hope no hotplug events happen between querying the sinks and trying to change their properties. Sinks are identified in the API by an index, but this isn't stable. Each sink also has an identifier string which is, I think, unique, at least for each run.

There is an API to get callbacks on various interesting events, such as hotplug, so it would be possible to hook up each Sink to that and at least get notified of when it goes away.

A: 

Couldn't you just listen to the HotPlug event, and then bubble it up to the application using your library? The normal C# pattern is to implement INotifyPropertyChanged for your Sink class.

vanja.
A: 

If PulseAudio doesn't notify you of hardware events, then dealing with this situation is fundamentally untenable. You need to write some patches to PA's C library to handle this gracefully, though I'm quite surprised that PA doesn't expose any way whatsoever to deal with hotplug devices.

Paul Betts
I've added some extra info to the original post. PA does provide various callbacks, including hotplug events. That at least makes it possible to deal with the second problem (at the cost of a little overhead), but still leaves me with a zombie Sink.Consumers of the library will just end up with a Sink object for which all operations fail, which seems ugly.
RAOF
+1  A: 

I think you should try to communicate this behaviour of the C library to the user of your C# library.

I'm not familiar with pulseaudio, but basing on the information on unique identifiers you gave, a possible design for a Sink class could look like this:

/// <summary>
/// Represents a sink. May refer to different hardware.
/// </summary>
public class Sink
{
    public static IEnumerable<string> GetCurrentIdentifiers() { ... }

    public static Sink GetSinkForIdentifier(string identifier) { ... }

    private Sink() { ... }
}


Interesting read: The Law of Leaky Abstractions

So my recommendation would be not to try to create a (leaky) abstraction but simply to expose the concepts of pulseaudio.

dtb
I think I'll actually end up doing both; try an even higher abstraction for the sinks, but also expose the underlying PulseAudio concepts to catch the drips.
RAOF