Modificare il volume generale mediante le funzioni esterne del API di PulseAudio
Il sistema PulseAudio consente anche di modificare in tempo reale il volume generale dell'audio.
E' necessario in questo caso avere installata nel proprio sistema e richiamare in Gambas la libreria condivisa: "libpulse.so.0.24.3 ".
Poiché bisogna utilizzare la modalità asincrona con l'uso di funzioni esterne per il richiamo di funzioni di callback, prevista dalle risorse di PulseAudio, sarà necessario prevedere la creazione e l'uso di un'apposita libreria dinamica condivisa esterna, scritta in C.
Ricordare che si dovrà inserire nell'oggetto InputBox la stringa identificativa (ad esempio: alsa_output.pci-0000_01_00.1.hdmi-stereo) del sink dell'uscita audio, corrispondente alla corrente scheda audio attiva, e che potrà essere individuata lanciando in Terminale la seguente riga di comando:
~ $ pactl list sinks
o anche:
~ $ pacmd list-sinks | grep -e 'name:' -e 'index:'
La stringa identificativa sarà presente nella linea: "Nome: ".
Mostriamo un esempio pratico in ambiente grafico:
Private context As Pointer Private vol As Pointer Private dispositivo As String Private Const MASSIMO_VOLUME As Integer = 65536 Library "libpulse:0.24.3" ' pa_threaded_mainloop *pa_threaded_mainloop_new(void) ' Allocate a new threaded main loop object. Private Extern pa_threaded_mainloop_new() As Pointer ' pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) ' Return the main loop abstraction layer vtable for this main loop. Private Extern pa_threaded_mainloop_get_api(m As Pointer) As Pointer ' pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) ' Instantiate a new connection context with an abstract mainloop API and an application name. Private Extern pa_context_new(mainloop As Pointer, name As String) As Pointer ' int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) ' Connect the context to the specified server. Private Extern pa_context_connect(c As Pointer, server As String, flags As Integer, api As Pointer) As Integer ' int pa_threaded_mainloop_start(pa_threaded_mainloop *m) ' Start the event loop thread. Private Extern pa_threaded_mainloop_start(m As Pointer) As Integer ' pa_cvolume* pa_cvolume_init(pa_cvolume *a) ' Initialize the specified volume and return a pointer to it. Private Extern pa_cvolume_init(a As Pointer) ' pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) ' Set the volume of the specified number of channels to the volume v. Private Extern pa_cvolume_set(a As Pointer, channels As Byte, v As Long) As Pointer Library "/tmp/libadhoc" ' void State_Callback(pa_context *c) ' Chiama la libreria .so appositamente creata per usare la funzione esterna 'pa_context_set_state_callback( )' Private Extern State_Callback(c As Pointer) ' void Imposta_Volume(pa_context *c, char *device, struct pa_cvolume *v) ' Chiama la libreria .so appositamente creata per usare la funzione esterna 'pa_context_set_sink_volume_by_name( )' Private Extern Imposta_Volume(c As Pointer, device As String, v As Pointer) Public Sub Form_Open() Dim ml, mlgapi As Pointer Dim sink, exemplum As String ' Crea l'apposita libreria dinamica condivisa esterna per la corretta gestione delle funzioni esterne di "callback": CreaSo() Object.Lock(SpinBox1) With SpinBox1 .MaxValue = MASSIMO_VOLUME .MinValue = 656 .Value = MASSIMO_VOLUME \ 2 Valore_TextBox(.Value) End With ' Crea un mainloop API e una connessione al server audio predefinito: ml = pa_threaded_mainloop_new() mlgapi = pa_threaded_mainloop_get_api(ml) context = pa_context_new(mlgapi, "Controllo volume") ' Effettua la connessione al server di PulseAudio: pa_context_connect(context, Null, 0, 0) State_Callback(context) pa_threaded_mainloop_start(ml) vol = Alloc(256) pa_cvolume_init(vol) Object.Unlock(SpinBox1) sink = Lista_Sink() exemplum = Replace(Split(sink, ">")[0], "\tname: <", Null) dispositivo = InputBox("Immettere il sorgente output audio:", Null, exemplum) End Public Sub SpinBox1_Change() Dim vlm As Long Dim canali As Integer = 2 vlm = CLong(SpinBox1.Value) Valore_TextBox(vlm) pa_cvolume_set(vol, canali, vlm) Imposta_Volume(context, dispositivo, vol) End Private Procedure Valore_TextBox(v As Long) TextBox1.Text = Format((v * 100) / MASSIMO_VOLUME, "###.00") End Public Sub Form_Close() Free(vol) End Private Function Lista_Sink() As String Dim lista As String Shell "pacmd list-sinks | grep -e 'alsa.card_name' -e 'name:'" To lista Print "Lista sorgenti audio disponibili:\n\n"; lista Return lista End Private Procedure CreaSo() ' Scrive in C e crea l'apposita libreria .so esterna per la gestione delle funzioni esterne di "callback": File.Save("/tmp/libadhoc.c", "#include <pulse/pulseaudio.h>\n" & "#include <stdio.h>" "\n\n" & "void context_state_cb(pa_context *c, void *userdata) {" & "\n\n}" & "\n\n" & "void State_Callback(pa_context *context) {" & "\n\n" & " pa_context_set_state_callback(context, context_state_cb, NULL);" & "\n\n}" & "\n\n" & "void volume_cb(pa_context *c, int risultato, void *userdata) {" & "\n\n" & " if (risultato)\n" & " printf(\"\\rVolume impostato \");\n" & " else\n" & " printf(\"\\rVolume non impostato\");" & "\n\n}" & "\n\n" & "void Imposta_Volume(pa_context *c, char *device, struct pa_cvolume *v) {" & "\n\n" & " pa_context_set_sink_volume_by_name(c, device, v, volume_cb, NULL); " & "\n\n}") Shell "gcc -o /tmp/libadhoc.so /tmp/libadhoc.c -lpulse -shared -fPIC" Wait End