Skip to content

Instantly share code, notes, and snippets.

@xpaulnim
Last active November 21, 2020 16:52
Show Gist options
  • Save xpaulnim/4248a67eeb6263ffda71841905b3cc06 to your computer and use it in GitHub Desktop.
Save xpaulnim/4248a67eeb6263ffda71841905b3cc06 to your computer and use it in GitHub Desktop.
Using the Introspection Event API for PulseAudio asyncronus API in vala.
// sudo apt install libpulse-dev
// valac -X -lm --pkg libpulse --pkg posix --pkg gtk+-3.0 --pkg libpulse-mainloop-glib pulseaudio_devices.vala
public class AudioDevice : GLib.Object {
private PulseAudio.GLibMainLoop loop;
private PulseAudio.Context context;
private PulseAudio.Context.Flags cflags;
public AudioDevice () {
GLib.Object();
}
public void start () {
this.loop = new PulseAudio.GLibMainLoop();
this.context = new PulseAudio.Context(loop.get_api(), "pulseaudio_devices", null);
this.context.set_state_callback(this.context_state_callback);
if (this.context.connect(null, this.cflags, null) < 0) {
print("pa_context_connect() failed: %s\n", PulseAudio.strerror(context.errno()));
}
}
public void context_state_callback(PulseAudio.Context context) {
PulseAudio.Context.State state = context.get_state();
switch(state) {
case PulseAudio.Context.State.UNCONNECTED:
print ("State is UNCONNECTED\n");
break;
case PulseAudio.Context.State.CONNECTING:
print ("State is CONNECTING\n");
break;
case PulseAudio.Context.State.AUTHORIZING:
print ("State is AUTHORIZING\n");
break;
case PulseAudio.Context.State.SETTING_NAME:
print ("State is SETTING_NAME\n");
break;
case PulseAudio.Context.State.FAILED:
print ("State is FAILED\n");
break;
case PulseAudio.Context.State.TERMINATED:
print ("State is TERMINATED\n");
break;
case PulseAudio.Context.State.READY:
print ("State is READY\n");
context.set_subscribe_callback(subscribe_callback);
context.subscribe(
PulseAudio.Context.SubscriptionMask.SERVER |
PulseAudio.Context.SubscriptionMask.SINK |
PulseAudio.Context.SubscriptionMask.SOURCE |
PulseAudio.Context.SubscriptionMask.SINK_INPUT |
PulseAudio.Context.SubscriptionMask.SOURCE_OUTPUT |
PulseAudio.Context.SubscriptionMask.CARD
);
context.get_server_info(server_info_callback);
// context.get_card_info_info(card_info_callback);
break;
default:
print("unknown state\n");
break;
}
}
public void subscribe_callback(PulseAudio.Context context,
PulseAudio.Context.SubscriptionEventType subsciption_event,
uint32 index) {
var source_type = subsciption_event & PulseAudio.Context.SubscriptionEventType.FACILITY_MASK;
var event_type = subsciption_event & PulseAudio.Context.SubscriptionEventType.TYPE_MASK;
switch(source_type) {
case PulseAudio.Context.SubscriptionEventType.SINK:
case PulseAudio.Context.SubscriptionEventType.SINK_INPUT:
switch(event_type) {
case PulseAudio.Context.SubscriptionEventType.NEW:
context.get_sink_info_by_index(index, sink_info_callback);
break;
case PulseAudio.Context.SubscriptionEventType.CHANGE:
context.get_sink_info_by_index(index, sink_info_callback);
break;
case PulseAudio.Context.SubscriptionEventType.REMOVE:
print("subscribe_callback:SINK:REMOVE %zu\n", index);
break;
default:
print("event_type not recognised %zu\n", index);
break;
}
break;
case PulseAudio.Context.SubscriptionEventType.SERVER:
context.get_server_info(server_info_callback);
break;
case PulseAudio.Context.SubscriptionEventType.CARD:
switch(event_type) {
case PulseAudio.Context.SubscriptionEventType.NEW:
context.get_card_info_by_index(index, card_info_callback);
break;
case PulseAudio.Context.SubscriptionEventType.CHANGE:
context.get_card_info_by_index(index, card_info_callback);
break;
case PulseAudio.Context.SubscriptionEventType.REMOVE:
print("subscribe_callback:CARD:REMOVE %zu\n", index);
break;
default:
print("event_type not recognised %zu : %d\n", index, event_type);
break;
}
break;
case PulseAudio.Context.SubscriptionEventType.SOURCE:
case PulseAudio.Context.SubscriptionEventType.SOURCE_OUTPUT:
switch(event_type){
case PulseAudio.Context.SubscriptionEventType.NEW:
context.get_source_info_by_index(index, source_info_callback);
break;
case PulseAudio.Context.SubscriptionEventType.CHANGE:
context.get_source_info_by_index(index, source_info_callback);
break;
case PulseAudio.Context.SubscriptionEventType.REMOVE:
print("subscribe_callback: CARD:REMOVE %zu\n", index);
break;
default:
print("event_type not recognised %zu : %d\n", index, event_type);
break;
}
break;
default:
print("source_type not recognised %zu\n", index);
break;
}
}
private void sink_info_callback(PulseAudio.Context context,
PulseAudio.SinkInfo? sink_info,
int eol) {
if(sink_info == null) {
return;
}
print("sink_info update\n");
print("sink_info: \n\tindex:%zu \n\tname: %s \n\tdesc: %s\n\n",
sink_info.index, sink_info.name,
sink_info.description);
}
private void server_info_callback(PulseAudio.Context context, PulseAudio.ServerInfo? server_info) {
if(server_info == null) {
return;
}
print("server info update\n");
print("server_info: \n\tdefault_sink: %s \n\tdefault_source: %s\n\n",
server_info.default_sink_name,
server_info.default_source_name);
}
private void card_info_callback(PulseAudio.Context context,
PulseAudio.CardInfo? card_info,
int eol) {
if (card_info == null) {
return;
}
print("card info update\n");
print ("\tcard: %u %s (%s)\n",
card_info.index, card_info.proplist.gets (PulseAudio.Proplist.PROP_DEVICE_DESCRIPTION), card_info.name);
print ("\t\tactive profile: %s\n", card_info.active_profile.name);
print ("\t\tcard form factor: %s\n", card_info.proplist.gets (PulseAudio.Proplist.PROP_DEVICE_FORM_FACTOR));
print ("\t\tcard icon name: %s\n", card_info.proplist.gets (PulseAudio.Proplist.PROP_MEDIA_ICON_NAME));
}
public void source_info_callback(PulseAudio.Context context,
PulseAudio.SourceInfo? source_info,
int eof) {
if (source_info == null) {
return;
}
// completely ignore monitors, they're not real sources
if (source_info.monitor_of_sink != PulseAudio.INVALID_INDEX) {
return;
}
print ("source info update\n");
print ("\tsource: %s (%s)\n", source_info.description, source_info.name);
print ("\t\tcard: %u\n", source_info.card);
}
}
int main (string[] args) {
Gtk.init(ref args);
AudioDevice audioDevice = new AudioDevice();
audioDevice.start();
Gtk.main ();
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment