]> code.delx.au - pulseaudio/blobdiff - src/modules/alsa/alsa-sink.c
move flat volume logic into the core. while doing so add n_volume_steps field to...
[pulseaudio] / src / modules / alsa / alsa-sink.c
index 955691532dc4a68abf75abf616f1317d153ea05e..3503c4a3a8a20615f3cc37ad943eab5ba8aab683 100644 (file)
@@ -251,7 +251,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
 
         if (PA_UNLIKELY(n <= u->hwbuf_unused_frames)) {
 
-            if (polled)
+            if (polled && pa_log_ratelimit())
                 pa_log("ALSA woke us up to write new data to the device, but there was actually nothing to write! "
                        "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers. "
                        "We were woken up with POLLOUT set -- however a subsequent snd_pcm_avail_update() returned 0.");
@@ -374,7 +374,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
 
         if (PA_UNLIKELY(n <= u->hwbuf_unused_frames)) {
 
-            if (polled)
+            if (polled && pa_log_ratelimit())
                 pa_log("ALSA woke us up to write new data to the device, but there was actually nothing to write! "
                        "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers. "
                        "We were woken up with POLLOUT set -- however a subsequent snd_pcm_avail_update() returned 0.");
@@ -715,6 +715,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
 
                 case PA_SINK_UNLINKED:
                 case PA_SINK_INIT:
+                case PA_SINK_INVALID_STATE:
                     ;
             }
 
@@ -756,7 +757,7 @@ static long to_alsa_volume(struct userdata *u, pa_volume_t vol) {
     return PA_CLAMP_UNLIKELY(alsa_vol, u->hw_volume_min, u->hw_volume_max);
 }
 
-static int sink_get_volume_cb(pa_sink *s) {
+static void sink_get_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err;
     unsigned i;
@@ -819,27 +820,24 @@ static int sink_get_volume_cb(pa_sink *s) {
 
     if (!pa_cvolume_equal(&u->hardware_volume, &r)) {
 
-        u->hardware_volume = s->volume = r;
+        s->virtual_volume = u->hardware_volume = r;
 
         if (u->hw_dB_supported) {
             pa_cvolume reset;
 
             /* Hmm, so the hardware volume changed, let's reset our software volume */
-
             pa_cvolume_reset(&reset, s->sample_spec.channels);
             pa_sink_set_soft_volume(s, &reset);
         }
     }
 
-    return 0;
+    return;
 
 fail:
     pa_log_error("Unable to read volume: %s", snd_strerror(err));
-
-    return -1;
 }
 
-static int sink_set_volume_cb(pa_sink *s) {
+static void sink_set_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err;
     unsigned i;
@@ -856,7 +854,7 @@ static int sink_set_volume_cb(pa_sink *s) {
             long alsa_vol;
             pa_volume_t vol;
 
-            vol = s->volume.values[i];
+            vol = s->virtual_volume.values[i];
 
             if (u->hw_dB_supported) {
 
@@ -870,6 +868,10 @@ static int sink_set_volume_cb(pa_sink *s) {
                 if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, u->mixer_map[i], &alsa_vol)) < 0)
                     goto fail;
 
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+                VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
+#endif
+
                 r.values[i] = pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0);
 
             } else {
@@ -889,7 +891,7 @@ static int sink_set_volume_cb(pa_sink *s) {
         pa_volume_t vol;
         long alsa_vol;
 
-        vol = pa_cvolume_max(&s->volume);
+        vol = pa_cvolume_max(&s->virtual_volume);
 
         if (u->hw_dB_supported) {
             alsa_vol = (long) (pa_sw_volume_to_dB(vol) * 100);
@@ -902,7 +904,11 @@ static int sink_set_volume_cb(pa_sink *s) {
             if ((err = snd_mixer_selem_get_playback_dB(u->mixer_elem, SND_MIXER_SCHN_MONO, &alsa_vol)) < 0)
                 goto fail;
 
-            pa_cvolume_set(&r, s->volume.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+            VALGRIND_MAKE_MEM_DEFINED(&alsa_vol, sizeof(alsa_vol));
+#endif
+
+            pa_cvolume_set(&r, s->sample_spec.channels, pa_sw_volume_from_dB((double) (alsa_vol - u->hw_dB_max) / 100.0));
 
         } else {
             alsa_vol = to_alsa_volume(u, vol);
@@ -923,11 +929,9 @@ static int sink_set_volume_cb(pa_sink *s) {
         char t[PA_CVOLUME_SNPRINT_MAX];
 
         /* Match exactly what the user requested by software */
+        pa_sw_cvolume_divide(&s->soft_volume, &s->virtual_volume, &r);
 
-        pa_sw_cvolume_divide(&r, &s->volume, &r);
-        pa_sink_set_soft_volume(s, &r);
-
-        pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->volume));
+        pa_log_debug("Requested volume: %s", pa_cvolume_snprint(t, sizeof(t), &s->virtual_volume));
         pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint(t, sizeof(t), &u->hardware_volume));
         pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint(t, sizeof(t), &r));
 
@@ -936,17 +940,15 @@ static int sink_set_volume_cb(pa_sink *s) {
         /* We can't match exactly what the user requested, hence let's
          * at least tell the user about it */
 
-        s->volume = r;
+        s->virtual_volume = r;
 
-    return 0;
+    return;
 
 fail:
     pa_log_error("Unable to set volume: %s", snd_strerror(err));
-
-    return -1;
 }
 
-static int sink_get_mute_cb(pa_sink *s) {
+static void sink_get_mute_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err, sw;
 
@@ -955,15 +957,13 @@ static int sink_get_mute_cb(pa_sink *s) {
 
     if ((err = snd_mixer_selem_get_playback_switch(u->mixer_elem, 0, &sw)) < 0) {
         pa_log_error("Unable to get switch: %s", snd_strerror(err));
-        return -1;
+        return;
     }
 
     s->muted = !sw;
-
-    return 0;
 }
 
-static int sink_set_mute_cb(pa_sink *s) {
+static void sink_set_mute_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err;
 
@@ -972,10 +972,8 @@ static int sink_set_mute_cb(pa_sink *s) {
 
     if ((err = snd_mixer_selem_set_playback_switch_all(u->mixer_elem, !s->muted)) < 0) {
         pa_log_error("Unable to set switch: %s", snd_strerror(err));
-        return -1;
+        return;
     }
-
-    return 0;
 }
 
 static void sink_update_requested_latency_cb(pa_sink *s) {
@@ -1185,7 +1183,7 @@ static void thread_func(void *userdata) {
                 u->since_start = 0;
             }
 
-            if (revents && u->use_tsched)
+            if (revents && u->use_tsched && pa_log_ratelimit())
                 pa_log_debug("Wakeup from ALSA!%s%s", (revents & POLLIN) ? " INPUT" : "", (revents & POLLOUT) ? " OUTPUT" : "");
         } else
             revents = 0;
@@ -1201,10 +1199,36 @@ finish:
     pa_log_debug("Thread shutting down");
 }
 
-pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const pa_alsa_profile_info *profile) {
+static void set_sink_name(pa_sink_new_data *data, pa_modargs *ma, const char *device_id, const char *device_name) {
+    const char *n;
+    char *t;
+
+    pa_assert(data);
+    pa_assert(ma);
+    pa_assert(device_name);
+
+    if ((n = pa_modargs_get_value(ma, "sink_name", NULL))) {
+        pa_sink_new_data_set_name(data, n);
+        data->namereg_fail = TRUE;
+        return;
+    }
+
+    if ((n = pa_modargs_get_value(ma, "name", NULL)))
+        data->namereg_fail = TRUE;
+    else {
+        n = device_id ? device_id : device_name;
+        data->namereg_fail = FALSE;
+    }
+
+    t = pa_sprintf_malloc("alsa_output.%s", n);
+    pa_sink_new_data_set_name(data, t);
+    pa_xfree(t);
+}
+
+pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_card *card, const pa_alsa_profile_info *profile) {
 
     struct userdata *u = NULL;
-    const char *dev_id;
+    const char *dev_id = NULL;
     pa_sample_spec ss;
     pa_channel_map map;
     uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark;
@@ -1212,9 +1236,6 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const pa_alsa_profile_in
     size_t frame_size;
     snd_pcm_info_t *pcm_info = NULL;
     int err;
-    const char *name;
-    char *name_buf = NULL;
-    pa_bool_t namereg_fail;
     pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d;
     pa_usec_t usec;
     pa_sink_new_data data;
@@ -1222,6 +1243,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const pa_alsa_profile_in
     snd_pcm_info_alloca(&pcm_info);
 
     pa_assert(m);
+    pa_assert(ma);
 
     ss = m->core->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) {
@@ -1287,6 +1309,11 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const pa_alsa_profile_in
 
     if (profile) {
 
+        if (!(dev_id = pa_modargs_get_value(ma, "device_id", NULL))) {
+            pa_log("device_id= not set");
+            goto fail;
+        }
+
         if (!(u->pcm_handle = pa_alsa_open_by_device_id_profile(
                       dev_id,
                       &u->device_name,
@@ -1366,11 +1393,11 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const pa_alsa_profile_in
 
             if (snd_pcm_info(u->pcm_handle, info) >= 0) {
                 char *md;
-                int card;
+                int card_idx;
 
-                if ((card = snd_pcm_info_get_card(info)) >= 0) {
+                if ((card_idx = snd_pcm_info_get_card(info)) >= 0) {
 
-                    md = pa_sprintf_malloc("hw:%i", card);
+                    md = pa_sprintf_malloc("hw:%i", card_idx);
 
                     if (strcmp(u->device_name, md))
                         if (pa_alsa_prepare_mixer(u->mixer_handle, md) >= 0)
@@ -1390,25 +1417,15 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const pa_alsa_profile_in
         }
     }
 
-    if ((name = pa_modargs_get_value(ma, "sink_name", NULL)))
-        namereg_fail = TRUE;
-    else if ((name = pa_modargs_get_value(ma, "name", NULL))) {
-        name = name_buf = pa_sprintf_malloc("alsa_output.%s", name);
-        namereg_fail = TRUE;
-    } else {
-        name = name_buf = pa_sprintf_malloc("alsa_output.%s", u->device_name);
-        namereg_fail = FALSE;
-    }
-
     pa_sink_new_data_init(&data);
-    data.driver = __FILE__;
+    data.driver = driver;
     data.module = m;
-    pa_sink_new_data_set_name(&data, name);
-    data.namereg_fail = namereg_fail;
+    data.card = card;
+    set_sink_name(&data, ma, dev_id, u->device_name);
     pa_sink_new_data_set_sample_spec(&data, &ss);
     pa_sink_new_data_set_channel_map(&data, &map);
 
-    pa_alsa_init_proplist_pcm(data.proplist, pcm_info);
+    pa_alsa_init_proplist_pcm(m->core, data.proplist, pcm_info);
     pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
     pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
     pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
@@ -1421,7 +1438,6 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const pa_alsa_profile_in
 
     u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
     pa_sink_new_data_done(&data);
-    pa_xfree(name_buf);
 
     if (!u->sink) {
         pa_log("Failed to create sink object");
@@ -1525,6 +1541,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const pa_alsa_profile_in
                 u->sink->flags |= PA_SINK_HW_VOLUME_CTRL | (u->hw_dB_supported ? PA_SINK_DECIBEL_VOLUME : 0);
                 pa_log_info("Using hardware volume control. Hardware dB scale %s.", u->hw_dB_supported ? "supported" : "not supported");
 
+                if (!u->hw_dB_supported)
+                    u->sink->n_volume_steps = u->hw_volume_max - u->hw_volume_min + 1;
             } else
                 pa_log_info("Using software volume control.");
         }