summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2020-05-15 21:15:25 +0200
committerWim Taymans <wtaymans@redhat.com>2020-07-03 17:33:07 +0200
commit819549beba71ae61ae67e48f3b5ecc55fa2a5ccb (patch)
treee24db3b607aee16919f31e5996e436ada63eab63
parent0eb2edabd24a505606dd9c920c72db14342df00e (diff)
moe wip
-rw-r--r--config.h.meson3
-rw-r--r--meson.build3
-rw-r--r--spa/plugins/pulse/alsa-mixer.c36
-rw-r--r--spa/plugins/pulse/compat.h12
-rw-r--r--spa/plugins/pulse/volume.h168
5 files changed, 198 insertions, 24 deletions
diff --git a/config.h.meson b/config.h.meson
index ad0b79d0..3c6cf4bb 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -453,3 +453,6 @@
#mesondefine PIPEWIRE_VERSION_MAJOR
#mesondefine PIPEWIRE_VERSION_MINOR
#mesondefine PIPEWIRE_VERSION_MICRO
+
+#mesondefine PA_ALSA_PATHS_DIR
+#mesondefine PA_ALSA_PROFILE_SETS_DIR
diff --git a/meson.build b/meson.build
index 088e43e6..777dcbd8 100644
--- a/meson.build
+++ b/meson.build
@@ -52,6 +52,7 @@ else
endif
spa_plugindir = join_paths(pipewire_libdir, spa_name)
+alsadatadir = join_paths(pipewire_datadir, 'pulseaudio', 'alsa-mixer')
pipewire_headers_dir = join_paths(pipewire_name, 'pipewire')
@@ -179,6 +180,8 @@ cdata.set('VERSION', '"@0@"'.format(pipewire_version))
cdata.set('PLUGINDIR', '"@0@"'.format(spa_plugindir))
# FIXME: --with-memory-alignment],[8,N,malloc,pagesize (default is 32)]) option
cdata.set('MEMORY_ALIGNMENT_MALLOC', 1)
+cdata.set_quoted('PA_ALSA_PATHS_DIR', join_paths(alsadatadir, 'paths'))
+cdata.set_quoted('PA_ALSA_PROFILE_SETS_DIR', join_paths(alsadatadir, 'profile-sets'))
check_headers = [['dlfcn.h','HAVE_DLFCN_H'],
diff --git a/spa/plugins/pulse/alsa-mixer.c b/spa/plugins/pulse/alsa-mixer.c
index ebfcdebd..8ba1813d 100644
--- a/spa/plugins/pulse/alsa-mixer.c
+++ b/spa/plugins/pulse/alsa-mixer.c
@@ -4468,29 +4468,31 @@ static int profile_verify(pa_alsa_profile *p) {
PA_ELEMENTSOF(well_known_descriptions)));
if (!p->description) {
- pa_strbuf *sb;
uint32_t idx;
pa_alsa_mapping *m;
+ char *ptr;
+ size_t size;
+ FILE *f;
+ int count = 0;
- sb = pa_strbuf_new();
+ f = open_memstream(&ptr, &size);
if (p->output_mappings)
PA_IDXSET_FOREACH(m, p->output_mappings, idx) {
- if (!pa_strbuf_isempty(sb))
- pa_strbuf_puts(sb, " + ");
-
- pa_strbuf_printf(sb, _("%s Output"), m->description);
+ if (count++ > 0)
+ fprintf(f, " + ");
+ fprintf(f, _("%s Output"), m->description);
}
if (p->input_mappings)
PA_IDXSET_FOREACH(m, p->input_mappings, idx) {
- if (!pa_strbuf_isempty(sb))
- pa_strbuf_puts(sb, " + ");
-
- pa_strbuf_printf(sb, _("%s Input"), m->description);
+ if (count++ > 0)
+ fprintf(f, " + ");
+ fprintf(f, _("%s Input"), m->description);
}
- p->description = pa_strbuf_to_string_free(sb);
+ fclose(f);
+ p->description = ptr;
}
return 0;
@@ -4542,17 +4544,21 @@ void pa_alsa_decibel_fix_dump(pa_alsa_decibel_fix *db_fix) {
pa_assert(db_fix);
if (db_fix->db_values) {
- pa_strbuf *buf;
unsigned long i, nsteps;
+ FILE *f;
+ char *ptr;
+ size_t size;
+
+ f = open_memstream(&ptr, &size);
pa_assert(db_fix->min_step <= db_fix->max_step);
nsteps = db_fix->max_step - db_fix->min_step + 1;
- buf = pa_strbuf_new();
for (i = 0; i < nsteps; ++i)
- pa_strbuf_printf(buf, "[%li]:%0.2f ", i + db_fix->min_step, db_fix->db_values[i] / 100.0);
+ fprintf(f, "[%li]:%0.2f ", i + db_fix->min_step, db_fix->db_values[i] / 100.0);
- db_values = pa_strbuf_to_string_free(buf);
+ fclose(f);
+ db_values = ptr;
}
pa_log_debug("Decibel fix %s, min_step=%li, max_step=%li, db_values=%s",
diff --git a/spa/plugins/pulse/compat.h b/spa/plugins/pulse/compat.h
index 61e20a7a..35be524e 100644
--- a/spa/plugins/pulse/compat.h
+++ b/spa/plugins/pulse/compat.h
@@ -45,9 +45,7 @@ typedef void (*pa_free_cb_t)(void *p);
#include "dynarray.h"
#include "idxset.h"
#include "proplist.h"
-#include "channelmap.h"
-typedef struct pa_idxset pa_idxset;
typedef struct pa_card pa_card;
typedef struct pa_card_profile pa_card_profile;
@@ -69,13 +67,6 @@ typedef enum pa_available {
PA_AVAILABLE_YES = 2,
} pa_available_t;
-typedef uint32_t pa_volume_t;
-
-typedef struct pa_cvolume {
- uint32_t channels; /**< Number of channels */
- pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */
-} pa_cvolume;
-
typedef enum pa_sample_format {
PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */
@@ -295,6 +286,9 @@ static inline const char *pa_strna(const char *x) {
#define _(...) (__VA_ARGS__)
#define N_(...) (__VA_ARGS__)
+#include "channelmap.h"
+#include "volume.h"
+
#ifdef __cplusplus
}
#endif
diff --git a/spa/plugins/pulse/volume.h b/spa/plugins/pulse/volume.h
new file mode 100644
index 00000000..fb8661c3
--- /dev/null
+++ b/spa/plugins/pulse/volume.h
@@ -0,0 +1,168 @@
+/* PipeWire
+ *
+ * Copyright © 2020 Wim Taymans
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PA_VOLUME_H
+#define PA_VOLUME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+
+typedef uint32_t pa_volume_t;
+
+#define PA_VOLUME_MUTED ((pa_volume_t) 0U)
+#define PA_VOLUME_NORM ((pa_volume_t) 0x10000U)
+#define PA_VOLUME_MAX ((pa_volume_t) UINT32_MAX/2)
+
+#ifdef INFINITY
+#define PA_DECIBEL_MININFTY ((double) -INFINITY)
+#else
+#define PA_DECIBEL_MININFTY ((double) -200.0)
+#endif
+
+#define PA_CLAMP_VOLUME(v) (PA_CLAMP_UNLIKELY((v), PA_VOLUME_MUTED, PA_VOLUME_MAX))
+
+typedef struct pa_cvolume {
+ uint32_t channels; /**< Number of channels */
+ pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */
+} pa_cvolume;
+
+static inline double pa_volume_linear_to_dB(double v)
+{
+ return 20.0 * log10(v);
+}
+
+static inline double pa_sw_volume_to_linear(pa_volume_t v)
+{
+ double f;
+ if (v <= PA_VOLUME_MUTED)
+ return 0.0;
+ if (v == PA_VOLUME_NORM)
+ return 1.0;
+ f = ((double) v / PA_VOLUME_NORM);
+ return f*f*f;
+}
+
+static inline double pa_sw_volume_to_dB(pa_volume_t v)
+{
+ if (v <= PA_VOLUME_MUTED)
+ return PA_DECIBEL_MININFTY;
+ return pa_volume_linear_to_dB(pa_sw_volume_to_linear(v));
+}
+
+static inline double pa_volume_dB_to_linear(double v)
+{
+ return pow(10.0, v / 20.0);
+}
+
+static inline pa_volume_t pa_sw_volume_from_linear(double v)
+{
+ if (v <= 0.0)
+ return PA_VOLUME_MUTED;
+ return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM));
+}
+
+static inline pa_volume_t pa_sw_volume_from_dB(double dB)
+{
+ if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY)
+ return PA_VOLUME_MUTED;
+ return pa_sw_volume_from_linear(pa_volume_dB_to_linear(dB));
+}
+
+static inline pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v)
+{
+ uint32_t i;
+ a->channels = (uint8_t) channels;
+ for (i = 0; i < a->channels; i++)
+ a->values[i] = PA_CLAMP_VOLUME(v);
+ return a;
+}
+
+static inline pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b)
+{
+ uint64_t result;
+ result = ((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) /
+ (uint64_t) PA_VOLUME_NORM;
+ if (result > (uint64_t)PA_VOLUME_MAX)
+ pa_log_warn("pa_sw_volume_multiply: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings.");
+ return (pa_volume_t) PA_CLAMP_VOLUME(result);
+}
+
+static inline pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest,
+ const pa_cvolume *a, const pa_cvolume *b)
+{
+ unsigned i;
+ dest->channels = PA_MIN(a->channels, b->channels);
+ for (i = 0; i < dest->channels; i++)
+ dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]);
+ return dest;
+}
+
+static inline pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b)
+{
+ uint64_t result;
+ if (b <= PA_VOLUME_MUTED)
+ return 0;
+ result = ((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b;
+ if (result > (uint64_t)PA_VOLUME_MAX)
+ pa_log_warn("pa_sw_volume_divide: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings.");
+ return (pa_volume_t) PA_CLAMP_VOLUME(result);
+}
+
+static inline pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest,
+ const pa_cvolume *a, const pa_cvolume *b)
+{
+ unsigned i;
+ dest->channels = PA_MIN(a->channels, b->channels);
+ for (i = 0; i < dest->channels; i++)
+ dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]);
+ return dest;
+}
+
+#define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM)
+#define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED)
+
+static inline int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v,
+ const pa_channel_map *cm)
+{
+ return v->channels == cm->channels;
+}
+
+static inline pa_volume_t pa_cvolume_max(const pa_cvolume *a)
+{
+ pa_volume_t m = PA_VOLUME_MUTED;
+ unsigned c;
+ for (c = 0; c < a->channels; c++)
+ if (a->values[c] > m)
+ m = a->values[c];
+ return m;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PA_VOLUME_H */