- /* Callled when the volume is queried. Called from main loop
- * context. If this is NULL a PA_SINK_MESSAGE_GET_VOLUME message
- * will be sent to the IO thread instead. If refresh_volume is
- * FALSE neither this function is called nor a message is sent. */
- void (*get_volume)(pa_sink *s); /* may be NULL */
-
- /* Called when the volume shall be changed. Called from main loop
- * context. If this is NULL a PA_SINK_MESSAGE_SET_VOLUME message
- * will be sent to the IO thread instead. */
- void (*set_volume)(pa_sink *s); /* dito */
-
- /* Called when the mute setting is queried. Called from main loop
- * context. If this is NULL a PA_SINK_MESSAGE_GET_MUTE message
- * will be sent to the IO thread instead. If refresh_mute is
- * FALSE neither this function is called nor a message is sent.*/
- void (*get_mute)(pa_sink *s); /* dito */
-
- /* Called when the mute setting shall be changed. Called from main
- * loop context. If this is NULL a PA_SINK_MESSAGE_SET_MUTE
- * message will be sent to the IO thread instead. */
- void (*set_mute)(pa_sink *s); /* dito */
+ /* Sink drivers that support hardware volume may set this
+ * callback. This is called when the current volume needs to be
+ * re-read from the hardware.
+ *
+ * There are two ways for drivers to implement hardware volume
+ * query: either set this callback or handle
+ * PA_SINK_MESSAGE_GET_VOLUME. The callback implementation or the
+ * message handler must update s->real_volume and s->soft_volume
+ * (using pa_sink_set_soft_volume()) to match the current hardware
+ * volume.
+ *
+ * If PA_SINK_DEFERRED_VOLUME is not set, then this is called from the
+ * main thread before sending PA_SINK_MESSAGE_GET_VOLUME, so in
+ * this case the driver can choose whether to read the volume from
+ * the hardware in the main thread or in the IO thread.
+ *
+ * If PA_SINK_DEFERRED_VOLUME is set, then this is called from the IO
+ * thread within the default handler for
+ * PA_SINK_MESSAGE_GET_VOLUME (the main thread is waiting while
+ * the message is being processed), so there's no choice of where
+ * to do the volume reading - it has to be done in the IO thread
+ * always.
+ *
+ * You must use the function pa_sink_set_get_volume_callback() to
+ * set this callback. */
+ pa_sink_cb_t get_volume; /* may be NULL */
+
+ /* Sink drivers that support hardware volume must set this
+ * callback. This is called when the hardware volume needs to be
+ * updated.
+ *
+ * If PA_SINK_DEFERRED_VOLUME is not set, then this is called from the
+ * main thread. The callback implementation must set the hardware
+ * volume according to s->real_volume. If the driver can't set the
+ * hardware volume to the exact requested value, it has to update
+ * s->real_volume and/or s->soft_volume so that they together
+ * match the actual hardware volume that was set.
+ *
+ * If PA_SINK_DEFERRED_VOLUME is set, then this is called from the IO
+ * thread. The callback implementation must not actually set the
+ * hardware volume yet, but it must check how close to the
+ * requested volume the hardware volume can be set, and update
+ * s->real_volume and/or s->soft_volume so that they together
+ * match the actual hardware volume that will be set later in the
+ * write_volume callback.
+ *
+ * You must use the function pa_sink_set_set_volume_callback() to
+ * set this callback. */
+ pa_sink_cb_t set_volume; /* may be NULL */
+
+ /* Sink drivers that set PA_SINK_DEFERRED_VOLUME must provide this
+ * callback. This callback is not used with sinks that do not set
+ * PA_SINK_DEFERRED_VOLUME. This is called from the IO thread when a
+ * pending hardware volume change has to be written to the
+ * hardware. The requested volume is passed to the callback
+ * implementation in s->thread_info.current_hw_volume.
+ *
+ * The call is done inside pa_sink_volume_change_apply(), which is
+ * not called automatically - it is the driver's responsibility to
+ * schedule that function to be called at the right times in the
+ * IO thread.
+ *
+ * You must use the function pa_sink_set_write_volume_callback() to
+ * set this callback. */
+ pa_sink_cb_t write_volume; /* may be NULL */
+
+ /* If the sink mute can change "spontaneously" (i.e. initiated by the sink
+ * implementation, not by someone else calling pa_sink_set_mute()), then
+ * the sink implementation can notify about changed mute either by calling
+ * pa_sink_mute_changed() or by calling pa_sink_get_mute() with
+ * force_refresh=true. If the implementation chooses the latter approach,
+ * it should implement the get_mute callback. Otherwise get_mute can be
+ * NULL.
+ *
+ * This is called when pa_sink_get_mute() is called with
+ * force_refresh=true. This is called from the IO thread if the
+ * PA_SINK_DEFERRED_VOLUME flag is set, otherwise this is called from the
+ * main thread. On success, the implementation is expected to return 0 and
+ * set the mute parameter that is passed as a reference. On failure, the
+ * implementation is expected to return -1.
+ *
+ * You must use the function pa_sink_set_get_mute_callback() to
+ * set this callback. */
+ pa_sink_get_mute_cb_t get_mute;
+
+ /* Called when the mute setting shall be changed. A PA_SINK_MESSAGE_SET_MUTE
+ * message will also be sent. Called from IO thread if PA_SINK_DEFERRED_VOLUME
+ * flag is set otherwise from main loop context.
+ *
+ * You must use the function pa_sink_set_set_mute_callback() to
+ * set this callback. */
+ pa_sink_cb_t set_mute; /* may be NULL */