Modificare il volume generale mediante le funzioni esterne del API di PulseAudio

Da Gambas-it.org - Wikipedia.

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


Riferimenti