Last active
November 21, 2020 16:52
-
-
Save xpaulnim/4248a67eeb6263ffda71841905b3cc06 to your computer and use it in GitHub Desktop.
Using the Introspection Event API for PulseAudio asyncronus API in vala.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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