module-alsa-card: Support external device in case of using sink2/source2 33/267533/16 accepted/tizen/unified/20220603.141256 submit/tizen/20220602.051141
authorJaechul Lee <jcsing.lee@samsung.com>
Mon, 6 Dec 2021 07:00:03 +0000 (16:00 +0900)
committerJaechul Lee <jcsing.lee@samsung.com>
Mon, 30 May 2022 08:14:30 +0000 (17:14 +0900)
pa_alsa_sink/source_new and pa_alsa_sink/source_free functions were
replaced with pa_dl_* for supporting tizenaudio-sink2/source2 when a
external sound card was inserted.

Additionally, use_tizen_hal property that can turn on/off this
functionality was added just in case.

[Version] 15.0-9
[Issue Type] New Feature

Change-Id: I11fdf2340befa6ab182eb0291ba218859c5e2a09
Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
meson.build
packaging/pulseaudio.spec
src/modules/alsa/module-alsa-card.c
src/modules/meson.build
src/modules/module-udev-detect.c

index 3a41501..63afbcc 100644 (file)
@@ -1049,6 +1049,7 @@ summary = [
   '  empty-pop:                   @0@'.format(get_option('empty-pop')),
   '  volume-ramp:                 @0@'.format(get_option('volume-ramp')),
   '  individual-volume-ratio:     @0@'.format(get_option('individual-volume-ratio')),
+  '  aec:                         @0@'.format(get_option('aec')),
   '  prelink (for TV):            @0@'.format(get_option('prelink')),
   '  lwipc (for TV):              @0@'.format(get_option('lwipc')),
 ]
index 23f0eef..206d66d 100644 (file)
@@ -4,7 +4,7 @@
 Name:             pulseaudio
 Summary:          Improved Linux sound server
 Version:          15.0
-Release:          8
+Release:          9
 Group:            Multimedia/Audio
 License:          LGPL-2.1
 URL:              http://pulseaudio.org
index 2609e6d..b148725 100755 (executable)
 #include <modules/udev-util.h>
 #endif
 
+#ifdef __TIZEN__
+#include <dlfcn.h>
+#endif
+
 #include "alsa-util.h"
 #include "alsa-ucm.h"
 #include "alsa-sink.h"
@@ -70,6 +74,9 @@ PA_MODULE_USAGE(
         "use_ucm=<load use case manager> "
         "avoid_resampling=<use stream original sample rate if possible?> "
         "control=<name of mixer control> "
+#ifdef __TIZEN__
+        "use_tizen_hal=<use tizen hal through tizenaudio-sink2/source2>"
+#endif
 );
 
 static const char* const valid_modargs[] = {
@@ -99,6 +106,9 @@ static const char* const valid_modargs[] = {
     "use_ucm",
     "avoid_resampling",
     "control",
+#ifdef __TIZEN__
+    "use_tizen_hal",
+#endif
     NULL
 };
 
@@ -113,6 +123,27 @@ static const char* const valid_modargs[] = {
 */
 #define PROFILE_PRIO_BONUS 0x8000
 
+#ifdef __TIZEN__
+#define DEFINE_TYPE(rtype, name, ...) \
+    typedef rtype (* name)(__VA_ARGS__)
+#define DEFINE_TYPE_WITH_PARAM(rtype, name) \
+    DEFINE_TYPE(rtype, name, \
+                    pa_module *, pa_modargs *, \
+                    const char *, pa_card *, char **, \
+                    pa_sample_spec *, pa_channel_map *)
+
+#define PA_TIZEN_HAL_FILEPATH "libtizenaudio-util.so"
+#define PA_TIZEN_HAL_SINK2_NEW "pa_tizenaudio_sink2_new"
+#define PA_TIZEN_HAL_SOURCE2_NEW "pa_tizenaudio_source2_new"
+#define PA_TIZEN_HAL_SINK2_FREE "pa_tizenaudio_sink2_free"
+#define PA_TIZEN_HAL_SOURCE2_FREE "pa_tizenaudio_source2_free"
+
+DEFINE_TYPE_WITH_PARAM(pa_sink *, dl_sink_new_t);
+DEFINE_TYPE_WITH_PARAM(pa_source *, dl_source_new_t);
+DEFINE_TYPE(void, dl_sink_free_t, pa_sink *);
+DEFINE_TYPE(void, dl_source_free_t, pa_source *);
+#endif
+
 struct userdata {
     pa_core *core;
     pa_module *module;
@@ -133,12 +164,147 @@ struct userdata {
     bool use_ucm;
     pa_alsa_ucm_config ucm;
 
+#ifdef __TIZEN__
+    bool use_tizen_hal;
+#endif
 };
 
 struct profile_data {
     pa_alsa_profile *profile;
 };
 
+#ifdef __TIZEN__
+static void *pa_dl_get_tizenaudio_function(const char *func) {
+    void *ret = NULL, *h = NULL;
+    char *path = NULL;
+
+    path = pa_sprintf_malloc("%s/%s", PA_DLSEARCHPATH, PA_TIZEN_HAL_FILEPATH);
+    if (!path) {
+        pa_log_error("Failed to alloc path");
+        return NULL;
+    }
+
+    h = dlopen(path, RTLD_LAZY);
+    if (!h) {
+        pa_log_error("Failed to get dl handle (%s)", path);
+        goto out;
+    }
+
+    ret = dlsym(h, func);
+    if (!ret) {
+        pa_log_error("Failed to get symbol (%s)", func);
+        goto out;
+    }
+
+out:
+    if (h)
+        dlclose(h);
+    if (path)
+        pa_xfree(path);
+
+    return ret;
+}
+
+static pa_sink *pa_dl_alsa_sink_new(pa_module *m, pa_modargs *ma, const char *driver, pa_card *card, pa_alsa_mapping *mapping) {
+    pa_sink *s;
+    dl_sink_new_t dl_sink_new;
+    struct userdata *u = (struct userdata *)m->userdata;
+
+    if (!u->use_tizen_hal)
+        goto exit;
+
+    if (!(dl_sink_new = pa_dl_get_tizenaudio_function(PA_TIZEN_HAL_SINK2_NEW))) {
+        pa_log_error("Failed to get sink_new function. Uses alsa-sink");
+        goto exit;
+    }
+
+    pa_log_info("Try to load sink. mapping name(%s), description(%s)", mapping->name, mapping->description);
+
+    s = dl_sink_new(m, ma, driver, card, mapping->device_strings,
+                    &mapping->sample_spec, &mapping->channel_map);
+    if (!s) {
+        pa_log_error("Failed to create sink. Uses alsa-sink");
+        goto exit;
+    }
+
+    return s;
+
+exit:
+    return pa_alsa_sink_new(m, ma, driver, card, mapping);
+}
+
+static pa_source *pa_dl_alsa_source_new(pa_module *m, pa_modargs *ma, const char *driver, pa_card *card, pa_alsa_mapping *mapping) {
+    pa_source *s;
+    dl_source_new_t dl_source_new;
+    struct userdata *u = (struct userdata *)m->userdata;
+
+    if (!u->use_tizen_hal)
+        goto exit;
+
+    if (!(dl_source_new = pa_dl_get_tizenaudio_function(PA_TIZEN_HAL_SOURCE2_NEW))) {
+        pa_log_error("Failed to get source_new function. Uses alsa-source");
+        goto exit;
+    }
+
+    pa_log_info("Try to load sink. mapping name(%s), description(%s)", mapping->name, mapping->description);
+
+    s = dl_source_new(m, ma, driver, card, mapping->device_strings,
+                        &mapping->sample_spec, &mapping->channel_map);
+
+    if (!s) {
+        pa_log_error("Failed to create source. Uses alsa-source");
+        goto exit;
+    }
+
+    return s;
+
+exit:
+    return pa_alsa_source_new(m, ma, driver, card, mapping);
+}
+
+static void pa_dl_alsa_sink_free(pa_sink *s) {
+    pa_module *m;
+    struct userdata *u;
+    dl_sink_free_t dl_sink_free;
+
+    pa_assert(s);
+    pa_assert(s->module);
+    pa_assert(s->module->userdata);
+
+    m = s->module;
+    u = m->userdata;
+
+    if (u->use_tizen_hal) {
+        dl_sink_free = pa_dl_get_tizenaudio_function(PA_TIZEN_HAL_SINK2_FREE);
+        dl_sink_free(s);
+        return;
+    }
+
+    pa_alsa_sink_free(s);
+}
+
+static void pa_dl_alsa_source_free(pa_source *s) {
+    pa_module *m;
+    struct userdata *u;
+    dl_source_free_t dl_source_free;
+
+    pa_assert(s);
+    pa_assert(s->module);
+    pa_assert(s->module->userdata);
+
+    m = s->module;
+    u = m->userdata;
+
+    if (u->use_tizen_hal) {
+        dl_source_free = pa_dl_get_tizenaudio_function(PA_TIZEN_HAL_SOURCE2_FREE);
+        dl_source_free(s);
+        return;
+    }
+
+    pa_alsa_source_free(s);
+}
+#endif
+
 static void add_profiles(struct userdata *u, pa_hashmap *h, pa_hashmap *ports) {
     pa_alsa_profile *ap;
     void *state;
@@ -228,7 +394,11 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
                 continue;
 
             sink_inputs = pa_sink_move_all_start(am->sink, sink_inputs);
+#ifdef __TIZEN__
+            pa_dl_alsa_sink_free(am->sink);
+#else
             pa_alsa_sink_free(am->sink);
+#endif
             am->sink = NULL;
         }
 
@@ -243,7 +413,11 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
                 continue;
 
             source_outputs = pa_source_move_all_start(am->source, source_outputs);
+#ifdef __TIZEN__
+            pa_dl_alsa_source_free(am->source);
+#else
             pa_alsa_source_free(am->source);
+#endif
             am->source = NULL;
         }
 
@@ -260,7 +434,11 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
         PA_IDXSET_FOREACH(am, nd->profile->output_mappings, idx) {
 
             if (!am->sink)
+#ifdef __TIZEN__
+                am->sink = pa_dl_alsa_sink_new(c->module, u->modargs, __FILE__, c, am);
+#else
                 am->sink = pa_alsa_sink_new(c->module, u->modargs, __FILE__, c, am);
+#endif
 
             if (sink_inputs && am->sink) {
                 pa_sink_move_all_finish(am->sink, sink_inputs, false);
@@ -272,7 +450,11 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
         PA_IDXSET_FOREACH(am, nd->profile->input_mappings, idx) {
 
             if (!am->source)
+#ifdef __TIZEN__
+                am->source = pa_dl_alsa_source_new(c->module, u->modargs, __FILE__, c, am);
+#else
                 am->source = pa_alsa_source_new(c->module, u->modargs, __FILE__, c, am);
+#endif
 
             if (source_outputs && am->source) {
                 pa_source_move_all_finish(am->source, source_outputs, false);
@@ -310,11 +492,19 @@ static void init_profile(struct userdata *u) {
 
     if (d->profile && d->profile->output_mappings)
         PA_IDXSET_FOREACH(am, d->profile->output_mappings, idx)
+#ifdef __TIZEN__
+            am->sink = pa_dl_alsa_sink_new(u->module, u->modargs, __FILE__, u->card, am);
+#else
             am->sink = pa_alsa_sink_new(u->module, u->modargs, __FILE__, u->card, am);
+#endif
 
     if (d->profile && d->profile->input_mappings)
         PA_IDXSET_FOREACH(am, d->profile->input_mappings, idx)
+#ifdef __TIZEN__
+            am->source = pa_dl_alsa_source_new(u->module, u->modargs, __FILE__, u->card, am);
+#else
             am->source = pa_alsa_source_new(u->module, u->modargs, __FILE__, u->card, am);
+#endif
 }
 
 static pa_available_t calc_port_state(pa_device_port *p, struct userdata *u) {
@@ -942,6 +1132,13 @@ int pa__init(pa_module *m) {
         goto fail;
     }
 
+#ifdef __TIZEN__
+    if (pa_modargs_get_value_boolean(u->modargs, "use_tizen_hal", &u->use_tizen_hal) < 0) {
+        pa_log("Failed to parse use_tizen_hal= argument.");
+        goto fail;
+    }
+#endif
+
     /* Force ALSA to reread its configuration. This matters if our device
      * was hot-plugged after ALSA has already read its configuration - see
      * https://bugs.freedesktop.org/show_bug.cgi?id=54029
@@ -1187,10 +1384,18 @@ void pa__done(pa_module*m) {
         pa_hashmap_free(u->jacks);
 
     if (u->card && u->card->sinks)
+#ifdef __TIZEN__
+        pa_idxset_remove_all(u->card->sinks, (pa_free_cb_t) pa_dl_alsa_sink_free);
+#else
         pa_idxset_remove_all(u->card->sinks, (pa_free_cb_t) pa_alsa_sink_free);
+#endif
 
     if (u->card && u->card->sources)
+#ifdef __TIZEN__
+        pa_idxset_remove_all(u->card->sources, (pa_free_cb_t) pa_dl_alsa_source_free);
+#else
         pa_idxset_remove_all(u->card->sources, (pa_free_cb_t) pa_alsa_source_free);
+#endif
 
     if (u->card)
         pa_card_free(u->card);
index b213f70..0dd040c 100644 (file)
@@ -105,7 +105,7 @@ endif
 if alsa_dep.found()
   subdir('alsa')
   all_modules += [
-    [ 'module-alsa-card', 'alsa/module-alsa-card.c', [], [], [alsa_dep, libm_dep], libalsa_util ],
+    [ 'module-alsa-card', 'alsa/module-alsa-card.c', [], [], [alsa_dep, libm_dep, dl_dep], libalsa_util ],
     [ 'module-alsa-sink', 'alsa/module-alsa-sink.c', [], [], [alsa_dep, libm_dep], libalsa_util ],
     [ 'module-alsa-source', 'alsa/module-alsa-source.c', [], [], [alsa_dep, libm_dep], libalsa_util ],
   ]
index cc52cb5..a2885ce 100644 (file)
@@ -47,7 +47,11 @@ PA_MODULE_USAGE(
         "ignore_dB=<ignore dB information from the device?> "
         "deferred_volume=<syncronize sw and hw volume changes in IO-thread?> "
         "use_ucm=<use ALSA UCM for card configuration?> "
-        "avoid_resampling=<use stream original sample rate if possible?>");
+        "avoid_resampling=<use stream original sample rate if possible?>"
+#ifdef __TIZEN__
+        "use_tizen_hal=<use tizen hal through tizenaudio-sink2/source2>"
+#endif
+        );
 
 struct device {
     char *path;
@@ -79,6 +83,9 @@ struct userdata {
 
     int inotify_fd;
     pa_io_event *inotify_io;
+#ifdef __TIZEN__
+    bool use_tizen_hal;
+#endif
 };
 
 static const char* const valid_modargs[] = {
@@ -89,6 +96,9 @@ static const char* const valid_modargs[] = {
     "deferred_volume",
     "use_ucm",
     "avoid_resampling",
+#ifdef __TIZEN__
+    "use_tizen_hal",
+#endif
     NULL
 };
 
@@ -408,6 +418,9 @@ static void card_changed(struct userdata *u, struct udev_device *dev) {
                      "device_id=\"%s\" "
                      "name=\"%s\" "
                      "card_name=\"%s\" "
+#ifdef __TIZEN__
+                     "use_tizen_hal=%s "
+#endif
                      "namereg_fail=false "
                      "tsched=%s "
                      "fixed_latency_range=%s "
@@ -419,6 +432,9 @@ static void card_changed(struct userdata *u, struct udev_device *dev) {
                      path_get_card_id(path),
                      n,
                      d->card_name,
+#ifdef __TIZEN__
+                     pa_yes_no(u->use_tizen_hal),
+#endif
                      pa_yes_no(u->use_tsched),
                      pa_yes_no(u->fixed_latency_range),
                      pa_yes_no(u->ignore_dB),
@@ -767,6 +783,13 @@ int pa__init(pa_module *m) {
     }
     u->avoid_resampling = avoid_resampling;
 
+#ifdef __TIZEN__
+    if (pa_modargs_get_value_boolean(ma, "use_tizen_hal", &u->use_tizen_hal) < 0) {
+        pa_log("Failed to parse use_tizen_hal= argument.");
+        goto fail;
+    }
+#endif
+
     if (!(u->udev = udev_new())) {
         pa_log("Failed to initialize udev library.");
         goto fail;