+static void mixer_volume_init(struct userdata *u) {
+ pa_assert(u);
+
+ if (!u->mixer_path->has_volume) {
+ pa_source_set_write_volume_callback(u->source, NULL);
+ pa_source_set_get_volume_callback(u->source, NULL);
+ pa_source_set_set_volume_callback(u->source, NULL);
+
+ pa_log_info("Driver does not support hardware volume control, falling back to software volume control.");
+ } else {
+ pa_source_set_get_volume_callback(u->source, source_get_volume_cb);
+ pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
+
+ if (u->mixer_path->has_dB && u->deferred_volume) {
+ pa_source_set_write_volume_callback(u->source, source_write_volume_cb);
+ pa_log_info("Successfully enabled deferred volume.");
+ } else
+ pa_source_set_write_volume_callback(u->source, NULL);
+
+ if (u->mixer_path->has_dB) {
+ pa_source_enable_decibel_volume(u->source, TRUE);
+ pa_log_info("Hardware volume ranges from %0.2f dB to %0.2f dB.", u->mixer_path->min_dB, u->mixer_path->max_dB);
+
+ u->source->base_volume = pa_sw_volume_from_dB(-u->mixer_path->max_dB);
+ u->source->n_volume_steps = PA_VOLUME_NORM+1;
+
+ pa_log_info("Fixing base volume to %0.2f dB", pa_sw_volume_to_dB(u->source->base_volume));
+ } else {
+ pa_source_enable_decibel_volume(u->source, FALSE);
+ pa_log_info("Hardware volume ranges from %li to %li.", u->mixer_path->min_volume, u->mixer_path->max_volume);
+
+ u->source->base_volume = PA_VOLUME_NORM;
+ u->source->n_volume_steps = u->mixer_path->max_volume - u->mixer_path->min_volume + 1;
+ }
+
+ pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->mixer_path->has_dB ? "supported" : "not supported");
+ }
+
+ if (!u->mixer_path->has_mute) {
+ pa_source_set_get_mute_callback(u->source, NULL);
+ pa_source_set_set_mute_callback(u->source, NULL);
+ pa_log_info("Driver does not support hardware mute control, falling back to software mute control.");
+ } else {
+ pa_source_set_get_mute_callback(u->source, source_get_mute_cb);
+ pa_source_set_set_mute_callback(u->source, source_set_mute_cb);
+ pa_log_info("Using hardware mute control.");
+ }
+}
+
+static int source_set_port_ucm_cb(pa_source *s, pa_device_port *p) {
+ struct userdata *u = s->userdata;
+
+ pa_assert(u);
+ pa_assert(p);
+ pa_assert(u->ucm_context);
+
+ return pa_alsa_ucm_set_port(u->ucm_context, p, FALSE);
+}
+