[vlc-commits] PulseAudio output device (sink) run-time selection

Rémi Denis-Courmont git at videolan.org
Tue Apr 12 19:05:05 CEST 2011


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue Apr 12 20:01:02 2011 +0300| [7553aa0fbe893bac3df934f8d914acde52c47292] | committer: Rémi Denis-Courmont

PulseAudio output device (sink) run-time selection

Notes:

- The variable value represents the PulseAudio sink index.
  It is not a member of the AOUT_VAR_ enumeration.

- There is no configuration item. PulseAudio normally remembers the
  last sink VLC used. So I think there is no need value in writing
  code to duplicate that effort.

- I am not sure if we need more locking inside the variable callback.
  This needs to be clarified with PulseAudio guys.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=7553aa0fbe893bac3df934f8d914acde52c47292
---

 modules/audio_output/pulse.c |   63 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/modules/audio_output/pulse.c b/modules/audio_output/pulse.c
index bad3e1d..3041a5b 100644
--- a/modules/audio_output/pulse.c
+++ b/modules/audio_output/pulse.c
@@ -47,6 +47,12 @@ vlc_module_end ()
 
 /* TODO: single static mainloop */
 
+/* NOTE:
+ * Be careful what you do when the PulseAudio mainloop is held, which is to say
+ * within PulseAudio callbacks, or after pa_threaded_mainloop_lock().
+ * In particular, the VLC audio output object variables can be manipulated with
+ * the PulseAudio mainloop lock held, but not vice versa! */
+
 struct aout_sys_t
 {
     pa_stream *stream; /**< PulseAudio playback stream object */
@@ -90,6 +96,23 @@ static void error(aout_instance_t *aout, const char *msg, pa_context *context)
 }
 
 /* Sink */
+static void sink_list_cb(pa_context *c, const pa_sink_info *i, int eol,
+                         void *userdata)
+{
+    aout_instance_t *aout = userdata;
+    vlc_value_t val, text;
+
+    if (eol)
+        return;
+    (void) c;
+
+    msg_Dbg(aout, "listing sink %s (%"PRIu32"): %s", i->name, i->index,
+            i->description);
+    val.i_int = i->index;
+    text.psz_string = (char *)i->description;
+    var_Change(aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text);
+}
+
 static void sink_info_cb(pa_context *c, const pa_sink_info *i, int eol,
                          void *userdata)
 {
@@ -317,12 +340,36 @@ static int VolumeSet(aout_instance_t *aout, audio_volume_t vol, bool mute)
     return 0;
 }
 
+static int StreamMove(vlc_object_t *obj, const char *varname, vlc_value_t old,
+                      vlc_value_t val, void *userdata)
+{
+    aout_instance_t *aout = (aout_instance_t *)obj;
+    aout_sys_t *sys = aout->output.p_sys;
+    pa_stream *s = userdata;
+    pa_operation *op;
+    uint32_t idx = pa_stream_get_index(s);
+    uint32_t sink_idx = val.i_int;
+
+    op = pa_context_move_sink_input_by_index(sys->context, idx, sink_idx,
+                                             NULL, NULL);
+    if (unlikely(op == NULL)) {
+        error(aout, "cannot move sink", sys->context);
+        return VLC_EGENERIC;
+    }
+    pa_operation_unref(op);
+    msg_Dbg(aout, "moving to sink %"PRIu32, sink_idx);
+    (void) varname; (void) old;
+    return VLC_SUCCESS;
+}
+
+
 /*****************************************************************************
  * Open: open the audio device
  *****************************************************************************/
 static int Open(vlc_object_t *obj)
 {
     aout_instance_t *aout = (aout_instance_t *)obj;
+    pa_operation *op;
 
     /* Sample format specification */
     struct pa_sample_spec ss;
@@ -514,6 +561,16 @@ static int Open(vlc_object_t *obj)
             pba->maxlength, pba->tlength, pba->prebuf, pba->minreq);
 
     aout->output.i_nb_samples = pba->minreq / pa_frame_size(&ss);
+
+    var_Create(aout, "audio-device", VLC_VAR_INTEGER|VLC_VAR_HASCHOICE);
+    var_Change(aout, "audio-device", VLC_VAR_SETTEXT,
+               &(vlc_value_t){ .psz_string = (char *)_("Audio device") },
+               NULL);
+    var_AddCallback (aout, "audio-device", StreamMove, s);
+    op = pa_context_get_sink_info_list(ctx, sink_list_cb, aout);
+    /* We may need to wait for completion... once LibVLC supports this */
+    if (op != NULL)
+        pa_operation_unref(op);
     pa_threaded_mainloop_unlock(mainloop);
 
     aout->output.pf_play = Play;
@@ -537,6 +594,12 @@ static void Close (vlc_object_t *obj)
     pa_context *ctx = sys->context;
     pa_stream *s = sys->stream;
 
+    if (s != NULL) {
+        /* The callback takes mainloop lock, so it CANNOT be held here! */
+        var_DelCallback (aout, "audio-device", StreamMove, s);
+        var_Destroy (aout, "audio-device");
+    }
+
     pa_threaded_mainloop_lock(mainloop);
     if (s != NULL) {
         pa_operation *op;



More information about the vlc-commits mailing list