From 740ec5fd89f85b26072c3c2a0b4f3a125ee009ba Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Thu, 21 Apr 2022 17:15:38 +0900 Subject: [PATCH 01/16] tizenaudio-echo-cancel: Fix UNINIT.LOCAL_VAR This patch fixes the svace and convention issues * Fix svace issue * Relace echo with referece [Version] 15.0.12 [Issue Type] SVACE Change-Id: I8ebe7e724c090fc4ce8bfa120b0e596d95723a2d Signed-off-by: Jaechul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/echo-cancel/module-tizenaudio-echo-cancel.c | 33 ++++++++++++------------- src/echo-cancel/processor.c | 6 ++--- src/echo-cancel/processor.h | 2 +- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 9122970..6c31737 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.11 +Version: 15.0.12 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/echo-cancel/module-tizenaudio-echo-cancel.c b/src/echo-cancel/module-tizenaudio-echo-cancel.c index 8aa456c..d27a2cd 100644 --- a/src/echo-cancel/module-tizenaudio-echo-cancel.c +++ b/src/echo-cancel/module-tizenaudio-echo-cancel.c @@ -150,8 +150,8 @@ static pa_source_output *find_source_output_by_flags(pa_source *s) { } static pa_usec_t get_round_trip_latency(struct userdata *u) { - pa_usec_t sink_latency; - pa_usec_t source_latency; + pa_usec_t sink_latency = 0ULL; + pa_usec_t source_latency = 0ULL; pa_assert(u); pa_assert(u->sink); @@ -272,19 +272,6 @@ static int update_state_by_source(struct userdata *u, bool enable) { return 0; } -static void pa_source_push_echo(pa_source *s, pa_memchunk *chunk) { - pa_source_output *o = NULL; - - o = find_source_output_by_flags(s); - if (!o) { - pa_log_error("Can't find aec source-output"); - return; - } - - if (pa_processor_push_data(o->thread_info.processor, chunk) < 0) - pa_log_error("Failed to push reference data"); -} - static int post_process(pa_source_output *o, pa_memchunk *chunk, pa_memchunk *ochunk) { int ret = -1; @@ -336,8 +323,20 @@ static int process_msg( break; case PA_ECHO_CANCEL_MESSAGE_PUSH_ECHO: - if (u->enable_in_thread) - pa_source_push_echo(u->source, chunk); + if (u->enable_in_thread) { + pa_source_output *o = NULL; + + pa_assert(u->source); + + o = find_source_output_by_flags(u->source); + if (!o) { + pa_log_error("Can't find aec source-output"); + break; + } + + if (pa_processor_push_reference(o->thread_info.processor, chunk) < 0) + pa_log_error("Failed to push reference data"); + } break; case PA_ECHO_CANCEL_MESSAGE_SET_AEC_STATE: { diff --git a/src/echo-cancel/processor.c b/src/echo-cancel/processor.c index a97b99c..5b8916b 100644 --- a/src/echo-cancel/processor.c +++ b/src/echo-cancel/processor.c @@ -345,7 +345,7 @@ int pa_processor_process(pa_processor *processor, pa_memchunk *chunk, pa_memchun pa_assert(ochunk); if ((r = pa_memblockq_push(processor->output_memblockq, chunk)) < 0) { - pa_log_error("Failed to push chunk to echo memblockq"); + pa_log_error("Failed to push chunk to reference memblockq"); return r; } @@ -410,12 +410,12 @@ int pa_processor_push_data(pa_processor *processor, pa_memchunk *chunk) { } if ((r = pa_memblockq_push(processor->reference_memblockq, chunk)) < 0) - pa_log_error("Failed to push chunk to echo memblockq"); + pa_log_error("Failed to push chunk to reference memblockq"); if (processor->resampler) pa_memblock_unref(chunk->memblock); - pa_log_debug("Pushed echo data. bytes(%zu), msec(%" PRIu64 "ms), nblocks(%d) index(%" PRId64 ":%" PRId64 ")", + pa_log_debug("Pushed reference data. bytes(%zu), msec(%" PRIu64 "ms), nblocks(%d) index(%" PRId64 ":%" PRId64 ")", chunk->length, pa_bytes_to_usec(chunk->length, &processor->reference_memblockq_ss) / PA_USEC_PER_MSEC, pa_memblockq_get_nblocks(processor->reference_memblockq), diff --git a/src/echo-cancel/processor.h b/src/echo-cancel/processor.h index fa77e87..ea07143 100644 --- a/src/echo-cancel/processor.h +++ b/src/echo-cancel/processor.h @@ -55,7 +55,7 @@ int pa_processor_bind_reference(pa_processor *processor, pa_channel_map *reference_chmap); int pa_processor_setup_reference_memblockq_padding(pa_processor *processor, pa_usec_t latency); int pa_processor_process(pa_processor *processor, pa_memchunk *rec, pa_memchunk *out); -int pa_processor_push_data(pa_processor *processor, pa_memchunk *chunk); +int pa_processor_push_reference(pa_processor *processor, pa_memchunk *chunk); void pa_processor_flush(pa_processor *processor); int pa_processor_free(pa_processor *processor); pa_processor_method_t pa_processor_get_method(const char *requset_method, const char *default_method); -- 2.7.4 From fb4e3bb1fe76f82d3839d19d2a95b7d73042a642 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Thu, 14 Apr 2022 15:00:24 +0900 Subject: [PATCH 02/16] tizenaudio-sink/source: Fix crash when pulseaudio exit * Fix pulseaudio crash (pactl exit) * symbol mismatching(pa_processor_push_reference) * aarch64 build warning [Version] 15.0.13 [Issue Type] Bug Change-Id: I0d7f0d44a95cd9667746529ed1f03151ec92e64a Signed-off-by: Jaechul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/echo-cancel/processor.c | 2 +- src/module-sound-player.c | 2 +- src/module-tizenaudio-sink.c | 3 +++ src/module-tizenaudio-sink2.c | 3 +++ src/module-tizenaudio-source.c | 3 +++ src/module-tizenaudio-source2.c | 3 +++ 7 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 6c31737..d1d68f6 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.12 +Version: 15.0.13 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/echo-cancel/processor.c b/src/echo-cancel/processor.c index 5b8916b..0052ab8 100644 --- a/src/echo-cancel/processor.c +++ b/src/echo-cancel/processor.c @@ -397,7 +397,7 @@ int pa_processor_process(pa_processor *processor, pa_memchunk *chunk, pa_memchun return r; } -int pa_processor_push_data(pa_processor *processor, pa_memchunk *chunk) { +int pa_processor_push_reference(pa_processor *processor, pa_memchunk *chunk) { pa_memchunk ochunk; int r; diff --git a/src/module-sound-player.c b/src/module-sound-player.c index ce505a8..cf55d04 100644 --- a/src/module-sound-player.c +++ b/src/module-sound-player.c @@ -753,7 +753,7 @@ static void io_event_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io else pa_log_error("Invalid method!!!"); } else { - pa_log_warn("Fail to read, retry_count(%d), read sum(%d), err(%s)", retry_count, read_sum, pa_cstrerror(errno)); + pa_log_warn("Fail to read, retry_count(%d), read sum(%zu), err(%s)", retry_count, read_sum, pa_cstrerror(errno)); } } diff --git a/src/module-tizenaudio-sink.c b/src/module-tizenaudio-sink.c index 6c56de9..0ea7846 100644 --- a/src/module-tizenaudio-sink.c +++ b/src/module-tizenaudio-sink.c @@ -796,5 +796,8 @@ void pa__done(pa_module*m) { pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); } + if (u->hal_interface) + pa_hal_interface_unref(u->hal_interface); + pa_xfree(u); } diff --git a/src/module-tizenaudio-sink2.c b/src/module-tizenaudio-sink2.c index a81ac70..36675c3 100644 --- a/src/module-tizenaudio-sink2.c +++ b/src/module-tizenaudio-sink2.c @@ -654,5 +654,8 @@ void pa__done(pa_module*m) { pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); } + if (u->hal_interface) + pa_hal_interface_unref(u->hal_interface); + pa_xfree(u); } diff --git a/src/module-tizenaudio-source.c b/src/module-tizenaudio-source.c index 4beabf5..e3ed819 100644 --- a/src/module-tizenaudio-source.c +++ b/src/module-tizenaudio-source.c @@ -700,5 +700,8 @@ void pa__done(pa_module*m) { pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); } + if (u->hal_interface) + pa_hal_interface_unref(u->hal_interface); + pa_xfree(u); } diff --git a/src/module-tizenaudio-source2.c b/src/module-tizenaudio-source2.c index 5bd3a61..a47dbbe 100644 --- a/src/module-tizenaudio-source2.c +++ b/src/module-tizenaudio-source2.c @@ -619,5 +619,8 @@ void pa__done(pa_module*m) { pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); } + if (u->hal_interface) + pa_hal_interface_unref(u->hal_interface); + pa_xfree(u); } -- 2.7.4 From 4fc34cf8fb2339ba0936e6bd3dce38cbb16f2807 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Fri, 29 Apr 2022 10:42:16 +0900 Subject: [PATCH 03/16] tizenaudio-echo-cancel: Fix coverity defect (Dereference null return value) [Version] 15.0.14 [Issue Type] Coverity Change-Id: I69359a1fc8dfd988ab37cc24a9cc4f2f287396eb Signed-off-by: Jaechul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/echo-cancel/module-tizenaudio-echo-cancel.c | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index d1d68f6..21f6ccc 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.13 +Version: 15.0.14 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/echo-cancel/module-tizenaudio-echo-cancel.c b/src/echo-cancel/module-tizenaudio-echo-cancel.c index d27a2cd..f9e13c0 100644 --- a/src/echo-cancel/module-tizenaudio-echo-cancel.c +++ b/src/echo-cancel/module-tizenaudio-echo-cancel.c @@ -146,6 +146,9 @@ static pa_source_output *find_source_output_by_flags(pa_source *s) { break; } + if (!o) + pa_log_error("Failed to find AEC source-output"); + return o ? o : NULL; } @@ -234,10 +237,8 @@ static void set_echo_cancel_state(struct userdata *u, bool enable) { return; o = find_source_output_by_flags(u->source); - if (!o) { - pa_log_error("Failed to find EC source-output"); + if (!o) return; - } broadcast_echo_cancel_state(u, o, enable); u->enable = enable; @@ -302,6 +303,11 @@ static int process_msg( pa_usec_t latency; o = find_source_output_by_flags(u->source); + if (!o) { + u->triggered = false; + return 0; + } + o->post_process = post_process; latency = get_round_trip_latency(u); @@ -329,10 +335,8 @@ static int process_msg( pa_assert(u->source); o = find_source_output_by_flags(u->source); - if (!o) { - pa_log_error("Can't find aec source-output"); + if (!o) break; - } if (pa_processor_push_reference(o->thread_info.processor, chunk) < 0) pa_log_error("Failed to push reference data"); -- 2.7.4 From bcc7b8b7639a80d1c2541ed6ca0dcd1692095c3f Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Tue, 30 Nov 2021 11:19:34 +0900 Subject: [PATCH 04/16] Separate tizenaudio-sink2 and module-tizenaudio-sink2 pa_tizenaudio_source2_new/sink2_new were added in order to support usb device playback/capture. These function will be called in module-tizenaudio-sink2/source2 and module-alsa-card. [Version] 15.0.15 [Issue Type] Improvement Change-Id: Id1d2d852f4c8982ac4c622cd2d326589ca46ca69 Signed-off-by: Jaechul Lee --- Makefile.am | 14 +- packaging/pulseaudio-modules-tizen.spec | 3 +- src/module-tizenaudio-sink2.c | 585 +------------------------------ src/module-tizenaudio-source2.c | 550 +----------------------------- src/tizenaudio-sink2.c | 585 +++++++++++++++++++++++++++++++ src/tizenaudio-sink2.h | 38 +++ src/tizenaudio-source2.c | 587 ++++++++++++++++++++++++++++++++ src/tizenaudio-source2.h | 38 +++ 8 files changed, 1284 insertions(+), 1116 deletions(-) create mode 100644 src/tizenaudio-sink2.c create mode 100644 src/tizenaudio-sink2.h create mode 100644 src/tizenaudio-source2.c create mode 100644 src/tizenaudio-source2.h diff --git a/Makefile.am b/Makefile.am index e61e057..ed2843f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,6 +38,7 @@ pulsemodlibexec_LTLIBRARIES = \ libhal-interface.la \ libprocessor.la \ libcommunicator.la \ + libtizenaudio-util.la \ module-tizenaudio-sink.la \ module-tizenaudio-source.la \ module-tizenaudio-sink2.la \ @@ -78,14 +79,19 @@ module_tizenaudio_source_la_LDFLAGS = $(MODULE_LDFLAGS) module_tizenaudio_source_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la module_tizenaudio_source_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_source -module_tizenaudio_sink2_la_SOURCES = src/module-tizenaudio-sink2.c src/echo-cancel/echo-cancel-def.h +libtizenaudio_util_la_SOURCES = src/tizenaudio-sink2.c src/tizenaudio-sink2.h src/tizenaudio-source2.c src/tizenaudio-source2.h src/echo-cancel/echo-cancel-def.h +libtizenaudio_util_la_LDFLAGS = $(AM_LDFLAGS) $(PA_LDFLAGS) -avoid-version +libtizenaudio_util_la_LIBADD = $(AM_LIBADD) $(PA_LIBS) libhal-interface.la +libtizenaudio_util_la_CFLAGS = $(MODULE_CFLAGS) + +module_tizenaudio_sink2_la_SOURCES = src/module-tizenaudio-sink2.c module_tizenaudio_sink2_la_LDFLAGS = $(MODULE_LDFLAGS) -module_tizenaudio_sink2_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la +module_tizenaudio_sink2_la_LIBADD = $(MODULE_LIBADD) libtizenaudio-util.la module_tizenaudio_sink2_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_sink2 -module_tizenaudio_source2_la_SOURCES = src/module-tizenaudio-source2.c src/echo-cancel/echo-cancel-def.h +module_tizenaudio_source2_la_SOURCES = src/module-tizenaudio-source2.c module_tizenaudio_source2_la_LDFLAGS = $(MODULE_LDFLAGS) -module_tizenaudio_source2_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la +module_tizenaudio_source2_la_LIBADD = $(MODULE_LIBADD) libtizenaudio-util.la module_tizenaudio_source2_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_source2 libprocessor_la_SOURCES = \ diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 21f6ccc..0dccc40 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.14 +Version: 15.0.15 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ @@ -91,6 +91,7 @@ install -m 0644 %SOURCE1 %{buildroot}%{_tmpfilesdir}/pulseaudio.conf %{_libdir}/pulse-%{module_ver}/modules/module-tizenaudio-publish.so %{_libdir}/pulse-%{module_ver}/modules/module-tizenaudio-echo-cancel.so %{_libdir}/pulse-%{module_ver}/modules/libprocessor.so +%{_libdir}/pulse-%{module_ver}/modules/libtizenaudio-util.so %{_libdir}/pulse-%{module_ver}/modules/libhal-interface.so %{_libdir}/pulse-%{module_ver}/modules/libcommunicator.so %{_tmpfilesdir}/pulseaudio.conf diff --git a/src/module-tizenaudio-sink2.c b/src/module-tizenaudio-sink2.c index 36675c3..0861262 100644 --- a/src/module-tizenaudio-sink2.c +++ b/src/module-tizenaudio-sink2.c @@ -23,30 +23,9 @@ #include #endif -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include "hal-interface.h" -#include "echo-cancel/echo-cancel-def.h" +#include "tizenaudio-sink2.h" PA_MODULE_AUTHOR("Tizen"); PA_MODULE_DESCRIPTION("Tizen Audio Sink2"); @@ -63,41 +42,6 @@ PA_MODULE_USAGE( "fragments= " "fragment_size= "); -#define DEFAULT_SINK_NAME "tizenaudio-sink2" - -#define DEVICE_NAME_MAX 30 -#define DEFAULT_FRAGMENT_MSEC 20 -#define DEFAULT_FRAGMENTS 4 - -struct userdata { - pa_core *core; - pa_module *module; - pa_sink *sink; - - pa_thread *thread; - pa_thread_mq thread_mq; - pa_rtpoll *rtpoll; - pa_usec_t timestamp; - - void *pcm_handle; - uint32_t nfrags; - uint32_t frag_size; - - char* card; - char* device; - bool first; - bool echo_on; - - pa_rtpoll_item *rtpoll_item; - - uint64_t write_count; - pa_hal_interface *hal_interface; - - pa_msgobject *ec_object; - pa_asyncmsgq *ec_asyncmsgq; - pa_rtpoll_item *ec_poll_item; -}; - static const char* const valid_modargs[] = { "sink_name", "sink_properties", @@ -111,496 +55,19 @@ static const char* const valid_modargs[] = { NULL }; -static int build_pollfd(struct userdata *u) { - int32_t ret; - struct pollfd *pollfd; - int fd = -1; - - pa_assert(u); - pa_assert(u->pcm_handle); - pa_assert(u->rtpoll); - - if (u->rtpoll_item) - pa_rtpoll_item_free(u->rtpoll_item); - - u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); - pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); - ret = pa_hal_interface_pcm_get_fd(u->hal_interface, u->pcm_handle, &fd); - if (ret < 0 || fd < 0) { - pa_log_error("Failed to get fd(%d) of PCM device %d", fd, ret); - return -1; - } - pollfd->fd = fd; - pollfd->events = POLLOUT | POLLERR | POLLNVAL; - - return 0; -} - -/* Called from IO context */ -static int suspend(struct userdata *u) { - int32_t ret; - pa_assert(u); - pa_assert(u->pcm_handle); - - ret = pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); - if (ret) { - pa_log_error("Error closing PCM device %x", ret); - } - u->pcm_handle = NULL; - - if (u->rtpoll_item) { - pa_rtpoll_item_free(u->rtpoll_item); - u->rtpoll_item = NULL; - } - - pa_log_info("Device suspended..."); - - return 0; -} - -/* Called from IO context */ -static int unsuspend(struct userdata *u) { - pa_sample_spec sample_spec; - int32_t ret; - size_t frame_size; - - pa_assert(u); - pa_assert(!u->pcm_handle); - - pa_log_info("Trying resume..."); - - sample_spec = u->sink->sample_spec; - frame_size = pa_frame_size(&sample_spec); - if (frame_size == 0) { - pa_log_error("Unexpected frame size zero!"); - goto fail; - } - - ret = pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, - DIRECTION_OUT, - &sample_spec, - u->frag_size / frame_size, - u->nfrags, - (void **)&u->pcm_handle); - if (ret) { - pa_log_error("Error opening PCM device %x", ret); - goto fail; - } - - if (build_pollfd(u) < 0) - goto fail; - - u->write_count = 0; - u->first = true; - u->timestamp = pa_rtclock_now(); - - pa_log_info("Resumed successfully..."); - - return 0; - -fail: - if (u->pcm_handle) { - pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); - u->pcm_handle = NULL; - } - return -PA_ERR_IO; -} - -/* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { - struct userdata *u; - int r; - - pa_assert(s); - pa_assert_se(u = s->userdata); - - /* It may be that only the suspend cause is changing, in which case there's - * nothing to do. */ - if (new_state == s->thread_info.state) - return 0; - - switch (new_state) { - case PA_SINK_SUSPENDED: { - pa_assert(PA_SINK_IS_OPENED(s->thread_info.state)); - if ((r = suspend(u)) < 0) - return r; - break; - } - - case PA_SINK_IDLE: - case PA_SINK_RUNNING: { - if (s->thread_info.state == PA_SINK_INIT) { - if (build_pollfd(u) < 0) - return -PA_ERR_IO; - } - - if (s->thread_info.state == PA_SINK_SUSPENDED) { - if ((r = unsuspend(u)) < 0) - return r; - } - break; - } - - case PA_SINK_UNLINKED: - case PA_SINK_INIT: - case PA_SINK_INVALID_STATE: - break; - } - - return 0; -} - -static int sink_process_msg( - pa_msgobject *o, - int code, - void *data, - int64_t offset, - pa_memchunk *chunk) { - - struct userdata *u = PA_SINK(o)->userdata; - - switch (code) { - case PA_SINK_MESSAGE_SET_AEC_STATE: { - u->echo_on = !!data; - pa_log_info("EC state changed (%d)", u->echo_on); - return 0; - } - case PA_SINK_MESSAGE_GET_LATENCY: { - int64_t r = 0; - - if (u->pcm_handle) - r = u->timestamp + pa_bytes_to_usec(u->write_count, &u->sink->sample_spec) - pa_rtclock_now(); - - *((int64_t *) data) = r; - - return 0; - } - case PA_SINK_MESSAGE_REBUILD_RTPOLL: { - struct arguments { - pa_msgobject *o; - pa_asyncmsgq *q; - } *args; - - args = (struct arguments *)data; - - if (args) { - u->ec_object = args->o; - u->ec_asyncmsgq = args->q; - u->ec_poll_item = pa_rtpoll_item_new_asyncmsgq_write(u->rtpoll, PA_RTPOLL_EARLY, args->q); - } else { - pa_rtpoll_item_free(u->ec_poll_item); - u->ec_poll_item = NULL; - u->ec_object = NULL; - } - - return 0; - } - } - - return pa_sink_process_msg(o, code, data, offset, chunk); -} - -static void process_rewind(struct userdata *u) { -#if 1 - /* Rewind not supported */ - pa_sink_process_rewind(u->sink, 0); -#else - size_t rewind_nbytes, in_buffer; - pa_usec_t delay; - - pa_assert(u); - - rewind_nbytes = u->sink->thread_info.rewind_nbytes; - - if (!PA_SINK_IS_OPENED(u->sink->thread_info.state) || rewind_nbytes <= 0) - goto do_nothing; - - pa_log_debug("Requested to rewind %lu bytes.", (unsigned long)rewind_nbytes); - - if (u->timestamp <= now) - goto do_nothing; - - delay = u->timestamp - now; - in_buffer = pa_usec_to_bytes(delay, &u->sink->sample_spec); - - if (in_buffer <= 0) - goto do_nothing; - - if (rewind_nbytes > in_buffer) - rewind_nbytes = in_buffer; - - pa_sink_process_rewind(u->sink, rewind_nbytes); - u->timestamp -= pa_bytes_to_usec(rewind_nbytes, &u->sink->sample_spec); - - pa_log_debug("Rewound %lu bytes.", (unsigned long)rewind_nbytes); - return; - -do_nothing: - pa_sink_process_rewind(u->sink, 0); -#endif -} - -static int process_render(struct userdata *u) { - void *p; - size_t frame_size = pa_frame_size(&u->sink->sample_spec); - size_t frames_to_write = u->frag_size / frame_size; - uint32_t avail = 0; - pa_memchunk chunk; - - pa_assert(u); - - pa_hal_interface_pcm_available(u->hal_interface, u->pcm_handle, &avail); - - if (frames_to_write > avail) - return 0; - - pa_sink_render_full(u->sink, u->frag_size, &chunk); - p = pa_memblock_acquire(chunk.memblock); - - if (pa_hal_interface_pcm_write(u->hal_interface, u->pcm_handle, (const char*)p + chunk.index, (uint32_t)frames_to_write)) { - pa_log_error("failed to write pcm. p(%p), size(%zu)", p, frames_to_write); - return -1; - } - - pa_memblock_release(chunk.memblock); - - if (u->echo_on) { - pa_asyncmsgq_post(u->ec_asyncmsgq, u->ec_object, - PA_ECHO_CANCEL_MESSAGE_PUSH_ECHO, NULL, 0, &chunk, NULL); - } - - pa_memblock_unref(chunk.memblock); - - u->write_count += chunk.length; - - return 0; -} - -static void thread_func(void *userdata) { - struct userdata *u = userdata; - unsigned short revents = 0; - - pa_assert(u); - - pa_log_debug("Thread starting up"); - - if (u->core->realtime_scheduling) - pa_thread_make_realtime(u->core->realtime_priority); - - pa_thread_mq_install(&u->thread_mq); - - u->timestamp = pa_rtclock_now(); - - for (;;) { - int ret; - - if (PA_UNLIKELY(u->sink->thread_info.rewind_requested)) - process_rewind(u); - - if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) { - if (process_render(u)) - goto fail; - - if (u->first) { - pa_log_info("Starting playback."); - pa_hal_interface_pcm_start(u->hal_interface, u->pcm_handle); - u->first = false; - } - } - - /* Hmm, nothing to do. Let's sleep */ - if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) - goto fail; - - if (ret == 0) - goto finish; - - if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) { - struct pollfd *pollfd; - if (u->rtpoll_item) { - pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); - revents = pollfd->revents; - if (revents & ~POLLOUT) { - pa_log_debug("Poll error 0x%x occured, try recover.", revents); - pa_hal_interface_pcm_recover(u->hal_interface, u->pcm_handle, revents); - u->first = true; - revents = 0; - } - } - } - } - -fail: - pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); - pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); - -finish: - pa_log_debug("Thread shutting down"); -} - -static int parse_to_get_card(const char *modarg_device, char *card) { - const char *name_p; - char *card_p; - - if (!strchr(modarg_device, ',')) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - name_p = modarg_device; - card_p = card; - while (*name_p != ',') - *(card_p++) = *(name_p++); - *card_p = '\0'; - - return 0; -} - -static int parse_to_get_device(const char *modarg_device, char *device) { - const char *comma_p; - char *device_p; - - if (!(comma_p = strchr(modarg_device, ','))) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - comma_p++; - device_p = device; - while (*comma_p != '\0') - *(device_p++) = *(comma_p++); - *device_p = '\0'; - - return 0; -} - -int pa__init(pa_module*m) { - struct userdata *u = NULL; - pa_sample_spec ss; - pa_channel_map map; +int pa__init(pa_module *m) { pa_modargs *ma = NULL; - pa_sink_new_data data; - uint32_t alternate_sample_rate; - const char *modarg_device; - char card[DEVICE_NAME_MAX]; - char device[DEVICE_NAME_MAX]; - size_t frame_size, buffer_size, period_frames, buffer_frames; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log_error("Failed to parse module arguments."); + pa_log("Failed to parse module arguments"); goto fail; } - ss = m->core->default_sample_spec; - map = m->core->default_channel_map; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log_error("Invalid sample format specification or channel map"); + if (!(m->userdata = pa_tizenaudio_sink2_new(m, ma, __FILE__))) goto fail; - } - - alternate_sample_rate = m->core->alternate_sample_rate; - if (pa_modargs_get_alternate_sample_rate(ma, &alternate_sample_rate) < 0) { - pa_log_error("Failed to parse alternate sample rate"); - goto fail; - } - - m->userdata = u = pa_xnew0(struct userdata, 1); - u->core = m->core; - u->module = m; - u->first = true; - u->timestamp = 0ULL; - u->hal_interface = pa_hal_interface_get(u->core); - u->rtpoll = pa_rtpoll_new(); - pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); - - if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { - pa_log_error("device is invalid"); - goto fail; - } - - if (parse_to_get_card(modarg_device, card) || parse_to_get_device(modarg_device, device)) { - pa_log_error("failed to parse device module argument, %s", modarg_device); - goto fail; - } - - u->card = pa_xstrdup(card); - u->device = pa_xstrdup(device); - - u->frag_size = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGMENT_MSEC * PA_USEC_PER_MSEC, &ss); - u->nfrags = DEFAULT_FRAGMENTS; - if (pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size) < 0 || - pa_modargs_get_value_u32(ma, "fragments", &u->nfrags) < 0) { - pa_log_error("fragment_size or fragments are invalid."); - goto fail; - } - pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); - - pa_sink_new_data_init(&data); - data.driver = __FILE__; - data.module = m; - pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); - pa_sink_new_data_set_sample_spec(&data, &ss); - pa_sink_new_data_set_channel_map(&data, &map); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, _("Tizen audio sink")); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); - pa_proplist_sets(data.proplist, "tizen.card", u->card); - pa_proplist_sets(data.proplist, "tizen.device", u->device); - pa_proplist_sets(data.proplist, "tizen.version", "2"); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); - - frame_size = pa_frame_size(&ss); - buffer_size = u->frag_size * u->nfrags; - buffer_frames = buffer_size / frame_size; - period_frames = u->frag_size / frame_size; - pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); - pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); - - if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { - pa_log_error("Invalid properties."); - pa_sink_new_data_done(&data); - goto fail; - } - - u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY); - pa_sink_new_data_done(&data); - - if (!u->sink) { - pa_log_error("Failed to create sink object."); - goto fail; - } - - u->sink->parent.process_msg = sink_process_msg; - u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb; - u->sink->userdata = u; - - if (pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, - DIRECTION_OUT, - &u->sink->sample_spec, - u->frag_size / pa_frame_size(&u->sink->sample_spec), - u->nfrags, - (void **)&u->pcm_handle)) { - pa_log_error("Error opening PCM device"); - goto fail; - } - pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); - pa_sink_set_rtpoll(u->sink, u->rtpoll); - - pa_sink_set_max_request(u->sink, buffer_size); - pa_sink_set_max_rewind(u->sink, buffer_size); - - if (!(u->thread = pa_thread_new("tizenaudio-sink2", thread_func, u))) { - pa_log_error("Failed to create thread."); - goto fail; - } - pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(buffer_size, &ss)); - pa_sink_put(u->sink); pa_modargs_free(ma); return 0; @@ -610,52 +77,24 @@ fail: pa_modargs_free(ma); pa__done(m); + return -1; } int pa__get_n_used(pa_module *m) { - struct userdata *u; + pa_sink *s; pa_assert(m); - pa_assert_se((u = m->userdata)); + pa_assert_se((s = m->userdata)); - return pa_sink_linked_by(u->sink); + return pa_sink_linked_by(s); } -void pa__done(pa_module*m) { - struct userdata *u; +void pa__done(pa_module *m) { + pa_sink *s; pa_assert(m); - if (!(u = m->userdata)) - return; - - if (u->sink) - pa_sink_unlink(u->sink); - - if (u->thread) { - pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); - pa_thread_free(u->thread); - } - - pa_thread_mq_done(&u->thread_mq); - - if (u->sink) - pa_sink_unref(u->sink); - - pa_xfree(u->card); - pa_xfree(u->device); - - if (u->rtpoll) - pa_rtpoll_free(u->rtpoll); - - if (u->pcm_handle) { - pa_hal_interface_pcm_stop(u->hal_interface, u->pcm_handle); - pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); - } - - if (u->hal_interface) - pa_hal_interface_unref(u->hal_interface); - - pa_xfree(u); + if ((s = m->userdata)) + pa_tizenaudio_sink2_free(s); } diff --git a/src/module-tizenaudio-source2.c b/src/module-tizenaudio-source2.c index a47dbbe..1df595e 100644 --- a/src/module-tizenaudio-source2.c +++ b/src/module-tizenaudio-source2.c @@ -23,30 +23,9 @@ #include #endif -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include "hal-interface.h" -#include "echo-cancel/echo-cancel-def.h" +#include "tizenaudio-source2.h" PA_MODULE_AUTHOR("Tizen"); PA_MODULE_DESCRIPTION("Tizen Audio Source2"); @@ -63,43 +42,6 @@ PA_MODULE_USAGE( "fragments= " "fragment_size= "); -#define DEFAULT_SOURCE_NAME "tizenaudio-source2" - -#define DEVICE_NAME_MAX 30 -#define DEFAULT_FRAGMENT_MSEC 20 -#define DEFAULT_FRAGMENTS 4 - -struct userdata { - pa_core *core; - pa_module *module; - pa_source *source; - - pa_thread *thread; - pa_thread_mq thread_mq; - pa_rtpoll *rtpoll; - - void *pcm_handle; - uint32_t nfrags; - uint32_t frag_size; - - pa_usec_t timestamp; - - char* card; - char* device; - bool first; - bool echo_on; - - pa_rtpoll_item *rtpoll_item; - - uint64_t read_count; - pa_usec_t latency_time; - pa_hal_interface *hal_interface; - - pa_msgobject *ec_object; - pa_asyncmsgq *ec_asyncmsgq; - pa_rtpoll_item *ec_poll_item; -}; - static const char* const valid_modargs[] = { "source_name", "source_properties", @@ -113,459 +55,19 @@ static const char* const valid_modargs[] = { NULL }; -static int build_pollfd(struct userdata *u) { - int32_t ret; - struct pollfd *pollfd; - int fd = -1; - - pa_assert(u); - pa_assert(u->pcm_handle); - pa_assert(u->rtpoll); - - if (u->rtpoll_item) - pa_rtpoll_item_free(u->rtpoll_item); - - u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); - pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); - ret = pa_hal_interface_pcm_get_fd(u->hal_interface, u->pcm_handle, &fd); - if (ret < 0 || fd < 0) { - pa_log_error("Failed to get fd(%d) of PCM device %d", fd, ret); - return -1; - } - pollfd->fd = fd; - pollfd->events = POLLIN | POLLERR | POLLNVAL; - - return 0; -} - -/* Called from IO context */ -static int suspend(struct userdata *u) { - int32_t ret; - pa_assert(u); - pa_assert(u->pcm_handle); - - ret = pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); - if (ret) { - pa_log_error("Error closing PCM device %x", ret); - } - u->pcm_handle = NULL; - - if (u->rtpoll_item) { - pa_rtpoll_item_free(u->rtpoll_item); - u->rtpoll_item = NULL; - } - - pa_log_info("Device suspended..."); - - return 0; -} - -/* Called from IO context */ -static int unsuspend(struct userdata *u) { - pa_sample_spec sample_spec; - int32_t ret; - size_t frame_size; - - pa_assert(u); - pa_assert(!u->pcm_handle); - - pa_log_info("Trying resume..."); - - sample_spec = u->source->sample_spec; - frame_size = pa_frame_size(&sample_spec); - if (frame_size == 0) { - pa_log_error("Unexpected frame size zero!"); - goto fail; - } - - ret = pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, - DIRECTION_IN, - &sample_spec, - u->frag_size / frame_size, - u->nfrags, - (void **)&u->pcm_handle); - if (ret) { - pa_log_error("Error opening PCM device %x", ret); - goto fail; - } - - if (build_pollfd(u) < 0) - goto fail; - - u->read_count = 0; - u->first = true; - u->timestamp = pa_rtclock_now(); - - pa_log_info("Resumed successfully..."); - - return 0; - -fail: - if (u->pcm_handle) { - pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); - u->pcm_handle = NULL; - } - return -PA_ERR_IO; -} - -/* Called from the IO thread. */ -static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { - struct userdata *u; - int r; - - pa_assert(s); - pa_assert_se(u = s->userdata); - - /* It may be that only the suspend cause is changing, in which case there's - * nothing more to do. */ - if (new_state == s->thread_info.state) - return 0; - - switch (new_state) { - case PA_SOURCE_SUSPENDED: { - pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state)); - if ((r = suspend(u)) < 0) - return r; - break; - } - - case PA_SOURCE_IDLE: - case PA_SOURCE_RUNNING: { - if (s->thread_info.state == PA_SOURCE_INIT) { - if (build_pollfd(u) < 0) - return -PA_ERR_IO; - } - - if (s->thread_info.state == PA_SOURCE_SUSPENDED) { - if ((r = unsuspend(u)) < 0) - return r; - } - break; - } - - case PA_SOURCE_UNLINKED: - case PA_SOURCE_INIT: - case PA_SOURCE_INVALID_STATE: - break; - } - - return 0; -} - -static int source_process_msg( - pa_msgobject *o, - int code, - void *data, - int64_t offset, - pa_memchunk *chunk) { - - struct userdata *u = PA_SOURCE(o)->userdata; - - switch (code) { - case PA_SOURCE_MESSAGE_SET_AEC_STATE: { - u->echo_on = !!data; - pa_log_info("EC state changed (%d)", u->echo_on); - return 0; - } - case PA_SOURCE_MESSAGE_GET_LATENCY: { - uint64_t r = 0; - - if (u->pcm_handle) - r = pa_rtclock_now() - (u->timestamp + pa_bytes_to_usec(u->read_count, &u->source->sample_spec)); - - *((int64_t *) data) = r; - - return 0; - } - case PA_SOURCE_MESSAGE_REBUILD_RTPOLL: { - struct arguments { - pa_msgobject *o; - pa_asyncmsgq *q; - } *args; - - args = (struct arguments *)data; - - if (args) { - u->ec_object = args->o; - u->ec_asyncmsgq = args->q; - u->ec_poll_item = pa_rtpoll_item_new_asyncmsgq_write(u->rtpoll, PA_RTPOLL_EARLY, args->q); - } else { - pa_rtpoll_item_free(u->ec_poll_item); - u->ec_poll_item = NULL; - u->ec_object = NULL; - } - - return 0; - } - } - - return pa_source_process_msg(o, code, data, offset, chunk); -} - -static int process_render(struct userdata *u) { - void *p; - size_t frame_size = pa_frame_size(&u->source->sample_spec); - size_t frames_to_read = u->frag_size / frame_size; - uint32_t avail = 0; - pa_memchunk chunk; - - pa_assert(u); - - /* Fill the buffer up the latency size */ - - pa_hal_interface_pcm_available(u->hal_interface, u->pcm_handle, &avail); - if (frames_to_read > avail) { - pa_log_debug("not enough avail size. frames_to_read(%zu), avail(%d)", frames_to_read, avail); - return 0; - } - - chunk.length = u->frag_size; - chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length); - - p = pa_memblock_acquire(chunk.memblock); - if (pa_hal_interface_pcm_read(u->hal_interface, u->pcm_handle, p, (uint32_t)frames_to_read)) { - pa_log_error("failed to read pcm. p(%p), size(%zu)", p, frames_to_read); - return -1; - } - pa_memblock_release(chunk.memblock); - - chunk.index = 0; - chunk.length = (size_t)frames_to_read * frame_size; - - if (u->echo_on) { - pa_asyncmsgq_post(u->ec_asyncmsgq, u->ec_object, - PA_ECHO_CANCEL_MESSAGE_PUSH_DATA, NULL, 0, &chunk, NULL); - } else { - pa_source_post(u->source, &chunk); - } - - pa_memblock_unref(chunk.memblock); - - u->read_count += chunk.length; - - return 0; -} - -static void thread_func(void *userdata) { - struct userdata *u = userdata; - unsigned short revents = 0; - - pa_assert(u); - pa_log_debug("Thread starting up"); - - if (u->core->realtime_scheduling) - pa_thread_make_realtime(u->core->realtime_priority); - - pa_thread_mq_install(&u->thread_mq); - - u->timestamp = pa_rtclock_now(); - - for (;;) { - int ret; - - /* Render some data and drop it immediately */ - if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) { - if (process_render(u)) - goto fail; - - if (u->first) { - pa_log_info("Starting capture."); - pa_hal_interface_pcm_start(u->hal_interface, u->pcm_handle); - u->first = false; - } - } - - /* Hmm, nothing to do. Let's sleep */ - if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) - goto fail; - - if (ret == 0) - goto finish; - - if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) { - struct pollfd *pollfd; - if (u->rtpoll_item) { - pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); - revents = pollfd->revents; - if (revents & ~POLLIN) { - pa_log_debug("Poll error 0x%x occured, try recover.", revents); - pa_hal_interface_pcm_recover(u->hal_interface, u->pcm_handle, revents); - u->first = true; - revents = 0; - } - } - } - } - -fail: - pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); - pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); - -finish: - pa_log_debug("Thread shutting down"); -} - -static int parse_to_get_card(const char *modarg_device, char *card) { - const char *name_p; - char *card_p; - - if (!strchr(modarg_device, ',')) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - name_p = modarg_device; - card_p = card; - while (*name_p != ',') - *(card_p++) = *(name_p++); - *card_p = '\0'; - - return 0; -} - -static int parse_to_get_device(const char *modarg_device, char *device) { - const char *comma_p; - char *device_p; - - if (!(comma_p = strchr(modarg_device, ','))) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - comma_p++; - device_p = device; - while (*comma_p != '\0') - *(device_p++) = *(comma_p++); - *device_p = '\0'; - - return 0; -} - -int pa__init(pa_module*m) { - struct userdata *u = NULL; - pa_sample_spec ss; - pa_channel_map map; +int pa__init(pa_module *m) { pa_modargs *ma = NULL; - pa_source_new_data data; - uint32_t alternate_sample_rate; - const char *modarg_device; - char card[DEVICE_NAME_MAX]; - char device[DEVICE_NAME_MAX]; - size_t frame_size, buffer_size, period_frames, buffer_frames; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log_error("Failed to parse module arguments."); + pa_log("Failed to parse module arguments"); goto fail; } - ss = m->core->default_sample_spec; - map = m->core->default_channel_map; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log_error("Invalid sample format specification or channel map"); + if (!(m->userdata = pa_tizenaudio_source2_new(m, ma, __FILE__))) goto fail; - } - - alternate_sample_rate = m->core->alternate_sample_rate; - if (pa_modargs_get_alternate_sample_rate(ma, &alternate_sample_rate) < 0) { - pa_log_error("Failed to parse alternate sample rate"); - goto fail; - } - m->userdata = u = pa_xnew0(struct userdata, 1); - u->core = m->core; - u->module = m; - u->first = true; - u->hal_interface = pa_hal_interface_get(u->core); - u->rtpoll = pa_rtpoll_new(); - pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); - - if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { - pa_log_error("device is invalid"); - goto fail; - } - - if (parse_to_get_card(modarg_device, card) || parse_to_get_device(modarg_device, device)) { - pa_log_error("failed to parse device module argument, %s", modarg_device); - goto fail; - } - - u->card = pa_xstrdup(card); - u->device = pa_xstrdup(device); - - u->frag_size = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGMENT_MSEC * PA_USEC_PER_MSEC, &ss); - u->nfrags = DEFAULT_FRAGMENTS; - if (pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size) < 0 || - pa_modargs_get_value_u32(ma, "fragments", &u->nfrags) < 0) { - pa_log_error("fragment_size or fragments are invalid."); - goto fail; - } - pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); - - pa_source_new_data_init(&data); - data.driver = __FILE__; - data.module = m; - pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME)); - pa_source_new_data_set_sample_spec(&data, &ss); - pa_source_new_data_set_channel_map(&data, &map); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, _("Tizen audio source")); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); - pa_proplist_sets(data.proplist, "tizen.card", u->card); - pa_proplist_sets(data.proplist, "tizen.device", u->device); - pa_proplist_sets(data.proplist, "tizen.version", "2"); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); - - frame_size = pa_frame_size(&ss); - buffer_size = u->frag_size * u->nfrags; - buffer_frames = buffer_size / frame_size; - period_frames = u->frag_size / frame_size; - pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); - pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); - - if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { - pa_log_error("Invalid properties."); - pa_source_new_data_done(&data); - goto fail; - } - - u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY); - pa_source_new_data_done(&data); - - if (!u->source) { - pa_log_error("Failed to create source object."); - goto fail; - } - - u->source->parent.process_msg = source_process_msg; - u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb; - u->source->userdata = u; - - if (pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, - DIRECTION_IN, - &u->source->sample_spec, - u->frag_size / pa_frame_size(&u->source->sample_spec), - u->nfrags, - (void **)&u->pcm_handle)) { - pa_log_error("Error opening PCM device"); - goto fail; - } - - pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); - pa_source_set_rtpoll(u->source, u->rtpoll); - - u->timestamp = 0ULL; - - if (!(u->thread = pa_thread_new("tizenaudio-source2", thread_func, u))) { - pa_log_error("Failed to create thread."); - goto fail; - } - pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(buffer_size, &ss)); - pa_source_put(u->source); pa_modargs_free(ma); return 0; @@ -575,52 +77,24 @@ fail: pa_modargs_free(ma); pa__done(m); + return -1; } int pa__get_n_used(pa_module *m) { - struct userdata *u; + pa_source *s; pa_assert(m); - pa_assert_se((u = m->userdata)); + pa_assert_se((s = m->userdata)); - return pa_source_linked_by(u->source); + return pa_source_linked_by(s); } -void pa__done(pa_module*m) { - struct userdata *u; +void pa__done(pa_module *m) { + pa_source *s; pa_assert(m); - if (!(u = m->userdata)) - return; - - if (u->source) - pa_source_unlink(u->source); - - if (u->thread) { - pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); - pa_thread_free(u->thread); - } - - pa_thread_mq_done(&u->thread_mq); - - if (u->source) - pa_source_unref(u->source); - - pa_xfree(u->card); - pa_xfree(u->device); - - if (u->rtpoll) - pa_rtpoll_free(u->rtpoll); - - if (u->pcm_handle) { - pa_hal_interface_pcm_stop(u->hal_interface, u->pcm_handle); - pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); - } - - if (u->hal_interface) - pa_hal_interface_unref(u->hal_interface); - - pa_xfree(u); + if ((s = m->userdata)) + pa_tizenaudio_source2_free(s); } diff --git a/src/tizenaudio-sink2.c b/src/tizenaudio-sink2.c new file mode 100644 index 0000000..a7ffd93 --- /dev/null +++ b/src/tizenaudio-sink2.c @@ -0,0 +1,585 @@ +/*** + This file is part of PulseAudio. + + Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hal-interface.h" +#include "echo-cancel/echo-cancel-def.h" + +#define DEFAULT_SINK_NAME "tizenaudio-sink2" + +#define DEVICE_NAME_MAX 30 +#define DEFAULT_FRAGMENT_MSEC 20 +#define DEFAULT_FRAGMENTS 4 + +struct userdata { + pa_core *core; + pa_module *module; + pa_sink *sink; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + pa_usec_t timestamp; + + void *pcm_handle; + uint32_t nfrags; + uint32_t frag_size; + + char* card; + char* device; + bool first; + bool echo_on; + + pa_rtpoll_item *rtpoll_item; + + uint64_t write_count; + pa_hal_interface *hal_interface; + + pa_msgobject *ec_object; + pa_asyncmsgq *ec_asyncmsgq; + pa_rtpoll_item *ec_poll_item; +}; + +static void userdata_free(struct userdata *u); + +static int build_pollfd(struct userdata *u) { + int32_t ret; + struct pollfd *pollfd; + int fd = -1; + + pa_assert(u); + pa_assert(u->pcm_handle); + pa_assert(u->rtpoll); + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + ret = pa_hal_interface_pcm_get_fd(u->hal_interface, u->pcm_handle, &fd); + if (ret < 0 || fd < 0) { + pa_log_error("Failed to get fd(%d) of PCM device %d", fd, ret); + return -1; + } + pollfd->fd = fd; + pollfd->events = POLLOUT | POLLERR | POLLNVAL; + + return 0; +} + +/* Called from IO context */ +static int suspend(struct userdata *u) { + int32_t ret; + pa_assert(u); + pa_assert(u->pcm_handle); + + ret = pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); + if (ret) { + pa_log_error("Error closing PCM device %x", ret); + } + u->pcm_handle = NULL; + + if (u->rtpoll_item) { + pa_rtpoll_item_free(u->rtpoll_item); + u->rtpoll_item = NULL; + } + + pa_log_info("Device suspended..."); + + return 0; +} + +/* Called from IO context */ +static int unsuspend(struct userdata *u) { + pa_sample_spec sample_spec; + int32_t ret; + size_t frame_size; + + pa_assert(u); + pa_assert(!u->pcm_handle); + + pa_log_info("Trying resume..."); + + sample_spec = u->sink->sample_spec; + frame_size = pa_frame_size(&sample_spec); + if (frame_size == 0) { + pa_log_error("Unexpected frame size zero!"); + goto fail; + } + + ret = pa_hal_interface_pcm_open(u->hal_interface, + u->card, + u->device, + DIRECTION_OUT, + &sample_spec, + u->frag_size / frame_size, + u->nfrags, + (void **)&u->pcm_handle); + if (ret) { + pa_log_error("Error opening PCM device %x", ret); + goto fail; + } + + if (build_pollfd(u) < 0) + goto fail; + + u->write_count = 0; + u->first = true; + u->timestamp = pa_rtclock_now(); + + pa_log_info("Resumed successfully..."); + + return 0; + +fail: + if (u->pcm_handle) { + pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); + u->pcm_handle = NULL; + } + return -PA_ERR_IO; +} + +/* Called from the IO thread. */ +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { + struct userdata *u; + int r; + + pa_assert(s); + pa_assert_se(u = s->userdata); + + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + + switch (new_state) { + case PA_SINK_SUSPENDED: { + pa_assert(PA_SINK_IS_OPENED(s->thread_info.state)); + if ((r = suspend(u)) < 0) + return r; + break; + } + + case PA_SINK_IDLE: + case PA_SINK_RUNNING: { + if (s->thread_info.state == PA_SINK_INIT) { + if (build_pollfd(u) < 0) + return -PA_ERR_IO; + } + + if (s->thread_info.state == PA_SINK_SUSPENDED) { + if ((r = unsuspend(u)) < 0) + return r; + } + break; + } + + case PA_SINK_UNLINKED: + case PA_SINK_INIT: + case PA_SINK_INVALID_STATE: + break; + } + + return 0; +} + +static int sink_process_msg( + pa_msgobject *o, + int code, + void *data, + int64_t offset, + pa_memchunk *chunk) { + + struct userdata *u = PA_SINK(o)->userdata; + + switch (code) { + case PA_SINK_MESSAGE_SET_AEC_STATE: { + u->echo_on = !!data; + pa_log_info("EC state changed (%d)", u->echo_on); + return 0; + } + case PA_SINK_MESSAGE_GET_LATENCY: { + int64_t r = 0; + + if (u->pcm_handle) + r = u->timestamp + pa_bytes_to_usec(u->write_count, &u->sink->sample_spec) - pa_rtclock_now(); + + *((int64_t *) data) = r; + + return 0; + } + case PA_SINK_MESSAGE_REBUILD_RTPOLL: { + struct arguments { + pa_msgobject *o; + pa_asyncmsgq *q; + } *args; + + args = (struct arguments *)data; + + if (args) { + u->ec_object = args->o; + u->ec_asyncmsgq = args->q; + u->ec_poll_item = pa_rtpoll_item_new_asyncmsgq_write(u->rtpoll, PA_RTPOLL_EARLY, args->q); + } else { + pa_rtpoll_item_free(u->ec_poll_item); + u->ec_poll_item = NULL; + u->ec_object = NULL; + } + + return 0; + } + } + + return pa_sink_process_msg(o, code, data, offset, chunk); +} + +static void process_rewind(struct userdata *u) { + pa_sink_process_rewind(u->sink, 0); +} + +static int process_render(struct userdata *u) { + void *p; + size_t frame_size = pa_frame_size(&u->sink->sample_spec); + size_t frames_to_write = u->frag_size / frame_size; + uint32_t avail = 0; + pa_memchunk chunk; + + pa_assert(u); + + pa_hal_interface_pcm_available(u->hal_interface, u->pcm_handle, &avail); + if (frames_to_write > avail) + return 0; + + pa_sink_render_full(u->sink, u->frag_size, &chunk); + p = pa_memblock_acquire(chunk.memblock); + + if (pa_hal_interface_pcm_write(u->hal_interface, u->pcm_handle, (const char*)p + chunk.index, (uint32_t)frames_to_write)) { + pa_log_error("failed to write pcm. p(%p), size(%zu)", p, frames_to_write); + return -1; + } + + pa_memblock_release(chunk.memblock); + + if (u->echo_on) { + pa_asyncmsgq_post(u->ec_asyncmsgq, u->ec_object, + PA_ECHO_CANCEL_MESSAGE_PUSH_ECHO, NULL, 0, &chunk, NULL); + } + + pa_memblock_unref(chunk.memblock); + + u->write_count += chunk.length; + + return 0; +} + +static void thread_func(void *userdata) { + struct userdata *u = userdata; + unsigned short revents = 0; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + if (u->core->realtime_scheduling) + pa_thread_make_realtime(u->core->realtime_priority); + + pa_thread_mq_install(&u->thread_mq); + + u->timestamp = pa_rtclock_now(); + + for (;;) { + int ret; + + if (PA_UNLIKELY(u->sink->thread_info.rewind_requested)) + process_rewind(u); + + if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) { + if (process_render(u)) + goto fail; + + if (u->first) { + pa_log_info("Starting playback."); + pa_hal_interface_pcm_start(u->hal_interface, u->pcm_handle); + u->first = false; + } + } + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) { + struct pollfd *pollfd; + if (u->rtpoll_item) { + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + revents = pollfd->revents; + if (revents & ~POLLOUT) { + pa_log_debug("Poll error 0x%x occured, try recover.", revents); + pa_hal_interface_pcm_recover(u->hal_interface, u->pcm_handle, revents); + u->first = true; + revents = 0; + } + } + } + } + +fail: + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +static int parse_to_get_card(const char *modarg_device, char *card) { + const char *name_p; + char *card_p; + + if (!strchr(modarg_device, ',')) { + pa_log_error("Failed to parse device argument : no comma"); + return -1; + } + + name_p = modarg_device; + card_p = card; + while (*name_p != ',') + *(card_p++) = *(name_p++); + *card_p = '\0'; + + return 0; +} + +static int parse_to_get_device(const char *modarg_device, char *device) { + const char *comma_p; + char *device_p; + + if (!(comma_p = strchr(modarg_device, ','))) { + pa_log_error("Failed to parse device argument : no comma"); + return -1; + } + + comma_p++; + device_p = device; + while (*comma_p != '\0') + *(device_p++) = *(comma_p++); + *device_p = '\0'; + + return 0; +} + +pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *driver) { + struct userdata *u = NULL; + pa_sample_spec ss; + pa_channel_map map; + pa_sink_new_data data; + uint32_t alternate_sample_rate; + const char *modarg_device; + char card[DEVICE_NAME_MAX]; + char device[DEVICE_NAME_MAX]; + size_t frame_size, buffer_size, period_frames, buffer_frames; + + pa_assert(m); + pa_assert(ma); + + ss = m->core->default_sample_spec; + map = m->core->default_channel_map; + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { + pa_log_error("Invalid sample format specification or channel map"); + goto fail; + } + + alternate_sample_rate = m->core->alternate_sample_rate; + if (pa_modargs_get_alternate_sample_rate(ma, &alternate_sample_rate) < 0) { + pa_log_error("Failed to parse alternate sample rate"); + goto fail; + } + + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + u->first = true; + u->timestamp = 0ULL; + u->hal_interface = pa_hal_interface_get(u->core); + u->rtpoll = pa_rtpoll_new(); + pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); + + if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { + pa_log_error("device is invalid"); + goto fail; + } + + if (parse_to_get_card(modarg_device, card) || parse_to_get_device(modarg_device, device)) { + pa_log_error("failed to parse device module argument, %s", modarg_device); + goto fail; + } + + u->card = pa_xstrdup(card); + u->device = pa_xstrdup(device); + + u->frag_size = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGMENT_MSEC * PA_USEC_PER_MSEC, &ss); + u->nfrags = DEFAULT_FRAGMENTS; + if (pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size) < 0 || + pa_modargs_get_value_u32(ma, "fragments", &u->nfrags) < 0) { + pa_log_error("fragment_size or fragments are invalid."); + goto fail; + } + pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); + + pa_sink_new_data_init(&data); + data.driver = driver; + data.module = m; + pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); + pa_sink_new_data_set_sample_spec(&data, &ss); + pa_sink_new_data_set_channel_map(&data, &map); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, _("Tizen audio sink2")); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); + pa_proplist_sets(data.proplist, "tizen.card", u->card); + pa_proplist_sets(data.proplist, "tizen.device", u->device); + pa_proplist_sets(data.proplist, "tizen.version", "2"); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); + + frame_size = pa_frame_size(&ss); + buffer_size = (size_t)(u->frag_size * u->nfrags); + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); + + if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { + pa_log_error("Invalid properties."); + pa_sink_new_data_done(&data); + goto fail; + } + + u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY); + pa_sink_new_data_done(&data); + + if (!u->sink) { + pa_log_error("Failed to create sink object."); + goto fail; + } + + u->sink->parent.process_msg = sink_process_msg; + u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb; + u->sink->userdata = u; + + if (pa_hal_interface_pcm_open(u->hal_interface, + u->card, + u->device, + DIRECTION_OUT, + &u->sink->sample_spec, + u->frag_size / pa_frame_size(&u->sink->sample_spec), + u->nfrags, + (void **)&u->pcm_handle)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + + pa_sink_set_max_request(u->sink, buffer_size); + pa_sink_set_max_rewind(u->sink, buffer_size); + + if (!(u->thread = pa_thread_new("tizenaudio-sink2", thread_func, u))) { + pa_log_error("Failed to create thread."); + goto fail; + } + + pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(buffer_size, &ss)); + pa_sink_put(u->sink); + + return u->sink; + +fail: + userdata_free(u); + return NULL; +} + +static void userdata_free(struct userdata *u) { + pa_assert(u); + + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); + + pa_xfree(u->card); + pa_xfree(u->device); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->pcm_handle) { + pa_hal_interface_pcm_stop(u->hal_interface, u->pcm_handle); + pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); + } + + if (u->hal_interface) + pa_hal_interface_unref(u->hal_interface); + + pa_xfree(u); +} + +void pa_tizenaudio_sink2_free(pa_sink *s) { + struct userdata *u; + + pa_sink_assert_ref(s); + pa_assert_se((u = s->userdata)); + + userdata_free(u); +} diff --git a/src/tizenaudio-sink2.h b/src/tizenaudio-sink2.h new file mode 100644 index 0000000..dd9e9e2 --- /dev/null +++ b/src/tizenaudio-sink2.h @@ -0,0 +1,38 @@ +/*** + This file is part of PulseAudio. + + Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifndef footizenaudiosink2hfoo +#define footizenaudiosink2hfoo + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *driver); + +void pa_tizenaudio_sink2_free(pa_sink *s); + +#endif + diff --git a/src/tizenaudio-source2.c b/src/tizenaudio-source2.c new file mode 100644 index 0000000..8ddfa2f --- /dev/null +++ b/src/tizenaudio-source2.c @@ -0,0 +1,587 @@ +/*** + This file is part of PulseAudio. + + Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hal-interface.h" +#include "echo-cancel/echo-cancel-def.h" + +#define DEFAULT_SOURCE_NAME "tizenaudio-source2" + +#define DEVICE_NAME_MAX 30 +#define DEFAULT_FRAGMENT_MSEC 20 +#define DEFAULT_FRAGMENTS 4 + +struct userdata { + pa_core *core; + pa_module *module; + pa_source *source; + + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + + void *pcm_handle; + uint32_t nfrags; + uint32_t frag_size; + + pa_usec_t timestamp; + + char* card; + char* device; + bool first; + bool echo_on; + + pa_rtpoll_item *rtpoll_item; + + uint64_t read_count; + pa_usec_t latency_time; + pa_hal_interface *hal_interface; + + /* for echo-cancel */ + pa_msgobject *ec_object; + pa_asyncmsgq *ec_asyncmsgq; + pa_rtpoll_item *ec_poll_item; +}; + +static void userdata_free(struct userdata *u); + +static int build_pollfd(struct userdata *u) { + int32_t ret; + struct pollfd *pollfd; + int fd = -1; + + pa_assert(u); + pa_assert(u->pcm_handle); + pa_assert(u->rtpoll); + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + ret = pa_hal_interface_pcm_get_fd(u->hal_interface, u->pcm_handle, &fd); + if (ret < 0 || fd < 0) { + pa_log_error("Failed to get fd(%d) of PCM device %d", fd, ret); + return -1; + } + pollfd->fd = fd; + pollfd->events = POLLIN | POLLERR | POLLNVAL; + + return 0; +} + +/* Called from IO context */ +static int suspend(struct userdata *u) { + int32_t ret; + pa_assert(u); + pa_assert(u->pcm_handle); + + ret = pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); + if (ret) { + pa_log_error("Error closing PCM device %x", ret); + } + u->pcm_handle = NULL; + + if (u->rtpoll_item) { + pa_rtpoll_item_free(u->rtpoll_item); + u->rtpoll_item = NULL; + } + + pa_log_info("Device suspended..."); + + return 0; +} + +/* Called from IO context */ +static int unsuspend(struct userdata *u) { + pa_sample_spec sample_spec; + int32_t ret; + size_t frame_size; + + pa_assert(u); + pa_assert(!u->pcm_handle); + + pa_log_info("Trying resume..."); + + sample_spec = u->source->sample_spec; + frame_size = pa_frame_size(&sample_spec); + if (frame_size == 0) { + pa_log_error("Unexpected frame size zero!"); + goto fail; + } + + ret = pa_hal_interface_pcm_open(u->hal_interface, + u->card, + u->device, + DIRECTION_IN, + &sample_spec, + u->frag_size / frame_size, + u->nfrags, + (void **)&u->pcm_handle); + if (ret) { + pa_log_error("Error opening PCM device %x", ret); + goto fail; + } + + if (build_pollfd(u) < 0) + goto fail; + + u->read_count = 0; + u->first = true; + u->timestamp = pa_rtclock_now(); + + pa_log_info("Resumed successfully..."); + + return 0; + +fail: + if (u->pcm_handle) { + pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); + u->pcm_handle = NULL; + } + return -PA_ERR_IO; +} + +/* Called from the IO thread. */ +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { + struct userdata *u; + int r; + + pa_assert(s); + pa_assert_se(u = s->userdata); + + /* It may be that only the suspend cause is changing, in which case there's + * nothing more to do. */ + if (new_state == s->thread_info.state) + return 0; + + switch (new_state) { + case PA_SOURCE_SUSPENDED: { + pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state)); + if ((r = suspend(u)) < 0) + return r; + break; + } + + case PA_SOURCE_IDLE: + case PA_SOURCE_RUNNING: { + if (s->thread_info.state == PA_SOURCE_INIT) { + if (build_pollfd(u) < 0) + return -PA_ERR_IO; + } + + if (s->thread_info.state == PA_SOURCE_SUSPENDED) { + if ((r = unsuspend(u)) < 0) + return r; + } + break; + } + + case PA_SOURCE_UNLINKED: + case PA_SOURCE_INIT: + case PA_SOURCE_INVALID_STATE: + break; + } + + return 0; +} + +static int source_process_msg( + pa_msgobject *o, + int code, + void *data, + int64_t offset, + pa_memchunk *chunk) { + + struct userdata *u = PA_SOURCE(o)->userdata; + + switch (code) { + case PA_SOURCE_MESSAGE_SET_AEC_STATE: { + u->echo_on = !!data; + pa_log_info("EC state changed (%d)", u->echo_on); + return 0; + } + case PA_SOURCE_MESSAGE_GET_LATENCY: { + uint64_t r = 0; + + if (u->pcm_handle) + r = pa_rtclock_now() - (u->timestamp + pa_bytes_to_usec(u->read_count, &u->source->sample_spec)); + + *((int64_t *) data) = r; + + return 0; + } + case PA_SOURCE_MESSAGE_REBUILD_RTPOLL: { + struct arguments { + pa_msgobject *o; + pa_asyncmsgq *q; + } *args; + + args = (struct arguments *)data; + + if (args) { + u->ec_object = args->o; + u->ec_asyncmsgq = args->q; + u->ec_poll_item = pa_rtpoll_item_new_asyncmsgq_write(u->rtpoll, PA_RTPOLL_EARLY, args->q); + } else { + pa_rtpoll_item_free(u->ec_poll_item); + u->ec_poll_item = NULL; + u->ec_object = NULL; + } + + return 0; + } + } + + return pa_source_process_msg(o, code, data, offset, chunk); +} + +static int process_render(struct userdata *u) { + void *p; + size_t frame_size = pa_frame_size(&u->source->sample_spec); + size_t frames_to_read = u->frag_size / frame_size; + uint32_t avail = 0; + pa_memchunk chunk; + + pa_assert(u); + + /* Fill the buffer up the latency size */ + + pa_hal_interface_pcm_available(u->hal_interface, u->pcm_handle, &avail); + if (frames_to_read > avail) { + pa_log_debug("not enough avail size. frames_to_read(%zu), avail(%u)", frames_to_read, avail); + return 0; + } + + chunk.length = u->frag_size; + chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length); + + p = pa_memblock_acquire(chunk.memblock); + if (pa_hal_interface_pcm_read(u->hal_interface, u->pcm_handle, p, (uint32_t)frames_to_read)) { + pa_log_error("failed to read pcm. p(%p), size(%zu)", p, frames_to_read); + return -1; + } + pa_memblock_release(chunk.memblock); + + chunk.index = 0; + chunk.length = (size_t)frames_to_read * frame_size; + + if (u->echo_on) { + pa_asyncmsgq_post(u->ec_asyncmsgq, u->ec_object, + PA_ECHO_CANCEL_MESSAGE_PUSH_DATA, NULL, 0, &chunk, NULL); + } else { + pa_source_post(u->source, &chunk); + } + + pa_memblock_unref(chunk.memblock); + + u->read_count += chunk.length; + + return 0; +} + +static void thread_func(void *userdata) { + struct userdata *u = userdata; + unsigned short revents = 0; + + pa_assert(u); + pa_log_debug("Thread starting up"); + + if (u->core->realtime_scheduling) + pa_thread_make_realtime(u->core->realtime_priority); + + pa_thread_mq_install(&u->thread_mq); + + u->timestamp = pa_rtclock_now(); + + for (;;) { + int ret; + + /* Render some data and drop it immediately */ + if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) { + if (process_render(u)) + goto fail; + + if (u->first) { + pa_log_info("Starting capture."); + pa_hal_interface_pcm_start(u->hal_interface, u->pcm_handle); + u->first = false; + } + } + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) { + struct pollfd *pollfd; + if (u->rtpoll_item) { + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + revents = pollfd->revents; + if (revents & ~POLLIN) { + pa_log_debug("Poll error 0x%x occured, try recover.", revents); + pa_hal_interface_pcm_recover(u->hal_interface, u->pcm_handle, revents); + u->first = true; + revents = 0; + } + } + } + } + +fail: + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +static int parse_to_get_card(const char *modarg_device, char *card) { + const char *name_p; + char *card_p; + + if (!strchr(modarg_device, ',')) { + pa_log_error("Failed to parse device argument : no comma"); + return -1; + } + + name_p = modarg_device; + card_p = card; + while (*name_p != ',') + *(card_p++) = *(name_p++); + *card_p = '\0'; + + return 0; +} + +static int parse_to_get_device(const char *modarg_device, char *device) { + const char *comma_p; + char *device_p; + + if (!(comma_p = strchr(modarg_device, ','))) { + pa_log_error("Failed to parse device argument : no comma"); + return -1; + } + + comma_p++; + device_p = device; + while (*comma_p != '\0') + *(device_p++) = *(comma_p++); + *device_p = '\0'; + + return 0; +} + +pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *driver) { + struct userdata *u = NULL; + pa_sample_spec ss; + pa_channel_map map; + pa_source_new_data data; + uint32_t alternate_sample_rate; + const char *modarg_device; + char card[DEVICE_NAME_MAX]; + char device[DEVICE_NAME_MAX]; + size_t frame_size, buffer_size, period_frames, buffer_frames; + + pa_assert(m); + + ss = m->core->default_sample_spec; + map = m->core->default_channel_map; + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { + pa_log_error("Invalid sample format specification or channel map"); + goto fail; + } + + alternate_sample_rate = m->core->alternate_sample_rate; + if (pa_modargs_get_alternate_sample_rate(ma, &alternate_sample_rate) < 0) { + pa_log_error("Failed to parse alternate sample rate"); + goto fail; + } + + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + u->first = true; + u->hal_interface = pa_hal_interface_get(u->core); + u->rtpoll = pa_rtpoll_new(); + pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); + + if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { + pa_log_error("device is invalid"); + goto fail; + } + + if (parse_to_get_card(modarg_device, card) || parse_to_get_device(modarg_device, device)) { + pa_log_error("failed to parse device module argument, %s", modarg_device); + goto fail; + } + + u->card = pa_xstrdup(card); + u->device = pa_xstrdup(device); + + u->frag_size = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGMENT_MSEC * PA_USEC_PER_MSEC, &ss); + u->nfrags = DEFAULT_FRAGMENTS; + if (pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size) < 0 || + pa_modargs_get_value_u32(ma, "fragments", &u->nfrags) < 0) { + pa_log_error("fragment_size or fragments are invalid."); + goto fail; + } + pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); + + pa_source_new_data_init(&data); + data.driver = driver; + data.module = m; + pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME)); + pa_source_new_data_set_sample_spec(&data, &ss); + pa_source_new_data_set_channel_map(&data, &map); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, _("Tizen audio source2")); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); + pa_proplist_sets(data.proplist, "tizen.card", u->card); + pa_proplist_sets(data.proplist, "tizen.device", u->device); + pa_proplist_sets(data.proplist, "tizen.version", "2"); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); + + frame_size = pa_frame_size(&ss); + buffer_size = (size_t)(u->frag_size * u->nfrags); + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); + + if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { + pa_log_error("Invalid properties."); + pa_source_new_data_done(&data); + goto fail; + } + + u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY); + pa_source_new_data_done(&data); + + if (!u->source) { + pa_log_error("Failed to create source object."); + goto fail; + } + + u->source->parent.process_msg = source_process_msg; + u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb; + u->source->userdata = u; + + if (pa_hal_interface_pcm_open(u->hal_interface, + u->card, + u->device, + DIRECTION_IN, + &u->source->sample_spec, + u->frag_size / pa_frame_size(&u->source->sample_spec), + u->nfrags, + (void **)&u->pcm_handle)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); + + u->timestamp = 0ULL; + + if (!(u->thread = pa_thread_new("tizenaudio-source2", thread_func, u))) { + pa_log_error("Failed to create thread."); + goto fail; + } + + pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(buffer_size, &ss)); + pa_source_put(u->source); + + return u->source; + +fail: + userdata_free(u); + return NULL; +} + +static void userdata_free(struct userdata *u) { + pa_assert(u); + + if (u->source) + pa_source_unlink(u->source); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->source) + pa_source_unref(u->source); + + pa_xfree(u->card); + pa_xfree(u->device); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->pcm_handle) { + pa_hal_interface_pcm_stop(u->hal_interface, u->pcm_handle); + pa_hal_interface_pcm_close(u->hal_interface, u->pcm_handle); + } + + if (u->hal_interface) + pa_hal_interface_unref(u->hal_interface); + + pa_xfree(u); +} + +void pa_tizenaudio_source2_free(pa_source *s) { + struct userdata *u; + + pa_source_assert_ref(s); + pa_assert_se((u = s->userdata)); + + userdata_free(u); +} diff --git a/src/tizenaudio-source2.h b/src/tizenaudio-source2.h new file mode 100644 index 0000000..a8e67c0 --- /dev/null +++ b/src/tizenaudio-source2.h @@ -0,0 +1,38 @@ +/*** + This file is part of PulseAudio. + + Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifndef footizenaudiosource2hfoo +#define footizenaudiosource2hfoo + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +pa_sink *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *driver); + +void pa_tizenaudio_source2_free(pa_source *s); + +#endif + -- 2.7.4 From 1e46c80a9170dca47a380a8de5d70daeb5acb488 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Tue, 17 May 2022 15:41:12 +0900 Subject: [PATCH 05/16] Revert "aec-manager: Add audio AEC manager" This reverts commit f49985f02d8d1e49a4e2075f3b9f2d651c571770. [Version] 15.0.16 [Issue Type] Cleanup Change-Id: Ie7a9341ff90acd3aa26ed38d51ce140fffb02c0f --- Makefile.am | 9 -- configure.ac | 12 -- packaging/pulseaudio-modules-tizen.spec | 6 +- src/aec-manager.c | 273 -------------------------------- src/aec-manager.h | 38 ----- src/device-manager.c | 24 +-- src/module-tizenaudio-sink.c | 67 +------- src/module-tizenaudio-source.c | 67 +------- 8 files changed, 14 insertions(+), 482 deletions(-) delete mode 100644 src/aec-manager.c delete mode 100644 src/aec-manager.h diff --git a/Makefile.am b/Makefile.am index ed2843f..12098ed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,10 +27,6 @@ AM_LIBADD = $(PTHREAD_LIBS) $(INTLLIBS) AM_LDFLAGS = $(NODELETE_LDFLAGS) MODULE_CFLAGS = $(AM_CFLAGS) $(PACORE_CFLAGS) $(PA_CFLAGS) -D__TIZEN__ -if ENABLE_AEC -MODULE_CFLAGS += -DSUPPORT_AEC -endif - MODULE_LDFLAGS = $(AM_LDFLAGS) $(PACORE_LDFLAGS) $(PA_LDFLAGS) -module -disable-static -avoid-version MODULE_LIBADD = $(AM_LIBADD) $(PACORE_LIBS) $(PA_LIBS) @@ -139,11 +135,6 @@ module_tizenaudio_policy_la_SOURCES = \ src/device-manager-db.c src/device-manager-db-priv.h \ src/tizen-device.c src/tizen-device.h src/tizen-device-def.c src/tizen-device-def.h \ src/subscribe-observer.c src/subscribe-observer.h - -if ENABLE_AEC -module_tizenaudio_policy_la_SOURCES += src/aec-manager.c src/aec-manager.h -endif - module_tizenaudio_policy_la_LDFLAGS = $(MODULE_LDFLAGS) -L$(pulsemodlibexecdir) module_tizenaudio_policy_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS) $(INIPARSER_LIBS) $(LIBJSON_LIBS) libhal-interface.la libcommunicator.la module_tizenaudio_policy_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) $(VCONF_CFLAGS) $(INIPARSER_CFLAGS) $(LIBJSON_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_policy diff --git a/configure.ac b/configure.ac index 170b340..ad76385 100644 --- a/configure.ac +++ b/configure.ac @@ -397,18 +397,6 @@ AC_ARG_ENABLE(acm, AC_HELP_STRING([--enable-acm], [using acm]), AM_CONDITIONAL(ENABLE_ACM, test "x$ENABLE_ACM" = "xyes") dnl end -------------------------------------------------------------------- -dnl use aec ---------------------------------------------------------------- -AC_ARG_ENABLE(aec, AC_HELP_STRING([--enable-aec], [using aec]), -[ - case "${enableval}" in - yes) ENABLE_AEC=yes ;; - no) ENABLE_AEC=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-aec) ;; - esac - ],[USE_AEC=no]) -AM_CONDITIONAL(ENABLE_AEC, test "x$ENABLE_AEC" = "xyes") -dnl end -------------------------------------------------------------------- - dnl use webrtc ---------------------------------------------------------------- AC_ARG_ENABLE(webrtc, AC_HELP_STRING([--enable-webrtc], [using webrtc-audio-processing]), [ diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 0dccc40..16babe1 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.15 +Version: 15.0.16 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ @@ -54,9 +54,7 @@ export LD_AS_NEEDED=0 %reconfigure --prefix=%{_prefix} \ --disable-static \ --enable-acm \ -%if "%{tizen_profile_name}" != "tv" - --enable-aec -%else +%if "%{tizen_profile_name}" == "tv" --enable-vconf-helper %endif # --enable-haltc diff --git a/src/aec-manager.c b/src/aec-manager.c deleted file mode 100644 index c349f71..0000000 --- a/src/aec-manager.c +++ /dev/null @@ -1,273 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 2021 Jaechul Lee - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2.1 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "aec-manager.h" - -#define AEC_MANAGER_OBJECT_PATH "/org/pulseaudio/AecManager" -#define AEC_MANAGER_INTERFACE "org.pulseaudio.AecManager" - -#define AEC_MANAGER_METHOD_NAME_ON "On" -#define AEC_MANAGER_METHOD_NAME_OFF "Off" -#define AEC_MANAGER_METHOD_NAME_GET_SINK_PARAMS "GetSinkParam" -#define AEC_MANAGER_METHOD_NAME_GET_SOURCE_PARAMS "GetSourceParam" - -#define AEC_UNIX_SOCKET_PATH "/tmp/.aec.socket" - -static struct aec_manager { - pa_dbus_connection *dbus_conn; - pa_source *source; /* builtin-mic */ - pa_sink *sink; /* builtin-spk */ -} am; - -enum { - SINK_MESSAGE_SET_AEC_STATE = PA_SINK_MESSAGE_MAX, - SINK_MESSAGE_GET_AEC_PARAMS, -}; - -enum { - SOURCE_MESSAGE_SET_AEC_STATE = PA_SOURCE_MESSAGE_MAX, - SOURCE_MESSAGE_GET_AEC_PARAMS, -}; - -#define AEC_MANAGER_INTROSPECT_XML \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "" \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - "" - -enum method_handler_index { - METHOD_HANDLER_ON, - METHOD_HANDLER_OFF, - METHOD_HANDLER_GET_SINK_PARAMS, - METHOD_HANDLER_GET_SOURCE_PARAMS, - METHOD_HANDLER_MAX -}; - -static void handle_method_on(DBusConnection *conn, DBusMessage *msg, void *userdata); -static void handle_method_off(DBusConnection *conn, DBusMessage *msg, void *userdata); -static void handle_method_get_sink_params(DBusConnection *conn, DBusMessage *msg, void *userdata); -static void handle_method_get_source_params(DBusConnection *conn, DBusMessage *msg, void *userdata); - -static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = { - [METHOD_HANDLER_ON] = { - .method_name = AEC_MANAGER_METHOD_NAME_ON, - .receive_cb = handle_method_on }, - [METHOD_HANDLER_OFF] = { - .method_name = AEC_MANAGER_METHOD_NAME_OFF, - .receive_cb = handle_method_off }, - [METHOD_HANDLER_GET_SINK_PARAMS] = { - .method_name = AEC_MANAGER_METHOD_NAME_GET_SINK_PARAMS, - .receive_cb = handle_method_get_sink_params }, - [METHOD_HANDLER_GET_SOURCE_PARAMS] = { - .method_name = AEC_MANAGER_METHOD_NAME_GET_SOURCE_PARAMS, - .receive_cb = handle_method_get_source_params }, -}; - -static void send_get_param_reply(DBusConnection *conn, DBusMessage *msg, aec_params_t* param) { - DBusMessage *reply = NULL; - DBusMessageIter msg_iter; - - const char *ptr1 = param->card; - const char *ptr2 = param->device; - - reply = dbus_message_new_method_return(msg); - if (!reply) { - pa_log_error("Failed to alloc reply"); - return; - } - - dbus_message_iter_init_append(reply, &msg_iter); - dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->rate); - dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->channels); - dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->format); - dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->frag_size); - dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->nfrags); - dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &ptr1); - dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &ptr2); - if (!dbus_connection_send(conn, reply, NULL)) - pa_log_error("reply send error!"); - - dbus_message_unref(reply); -} - -static void handle_method_on(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_asyncmsgq_post(am.sink->asyncmsgq, PA_MSGOBJECT(am.sink), - SINK_MESSAGE_SET_AEC_STATE, (void *)TRUE, 0, NULL, NULL); - pa_asyncmsgq_post(am.source->asyncmsgq, PA_MSGOBJECT(am.source), - SOURCE_MESSAGE_SET_AEC_STATE, (void *)TRUE, 0, NULL, NULL); - - pa_dbus_send_empty_reply(conn, msg); -} - -static void handle_method_off(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_asyncmsgq_post(am.sink->asyncmsgq, PA_MSGOBJECT(am.sink), - SINK_MESSAGE_SET_AEC_STATE, (void *)FALSE, 0, NULL, NULL); - pa_asyncmsgq_post(am.source->asyncmsgq, PA_MSGOBJECT(am.source), - SOURCE_MESSAGE_SET_AEC_STATE, (void *)FALSE, 0, NULL, NULL); - - pa_dbus_send_empty_reply(conn, msg); -} - -static void handle_method_get_sink_params(DBusConnection *conn, DBusMessage *msg, void *userdata) { - aec_params_t param; - - pa_asyncmsgq_send(am.sink->asyncmsgq, PA_MSGOBJECT(am.sink), - SINK_MESSAGE_GET_AEC_PARAMS, ¶m, 0, NULL); - - send_get_param_reply(conn, msg, ¶m); -} - -static void handle_method_get_source_params(DBusConnection *conn, DBusMessage *msg, void *userdata) { - aec_params_t param; - - pa_asyncmsgq_send(am.source->asyncmsgq, PA_MSGOBJECT(am.source), - SOURCE_MESSAGE_GET_AEC_PARAMS, ¶m, 0, NULL); - - send_get_param_reply(conn, msg, ¶m); -} - -static DBusHandlerResult method_handler_for_vt(DBusConnection *conn, DBusMessage *m, void *userdata) { - const char *path, *interface, *member; - DBusMessage *r = NULL; - - pa_assert(conn); - pa_assert(m); - - path = dbus_message_get_path(m); - interface = dbus_message_get_interface(m); - member = dbus_message_get_member(m); - - pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member); - - if (!pa_safe_streq(path, AEC_MANAGER_OBJECT_PATH)) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) { - r = dbus_message_new_method_return(m); - if (r) { - const char *xml = AEC_MANAGER_INTROSPECT_XML; - if (dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID)) { - if (!dbus_connection_send(conn, r, NULL)) - pa_log_error("reply send error!"); - } else { - pa_log_error("args append error!"); - } - - dbus_message_unref(r); - } - } else { - int i; - for (i = 0; i < METHOD_HANDLER_MAX; i++) { - if (dbus_message_is_method_call(m, AEC_MANAGER_INTERFACE, - method_handlers[i].method_name)) - method_handlers[i].receive_cb(conn, m, NULL); - } - } - - return DBUS_HANDLER_RESULT_HANDLED; -} - -int aec_manager_init(pa_core *core, pa_source *source, pa_sink *sink) { - DBusError err; - pa_dbus_connection *conn = NULL; - static const DBusObjectPathVTable vtable = { - .message_function = method_handler_for_vt, - }; - - if (!source || !sink) { - pa_log_error("AEC init failed. source(%p)/sink(%p) is null.", source, sink); - return -1; - } - - dbus_error_init(&err); - if (!(conn = pa_dbus_bus_get(core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) { - if (conn) - pa_dbus_connection_unref(conn); - - dbus_error_free(&err); - pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message); - return -1; - } - - am.dbus_conn = conn; - if (!dbus_connection_register_object_path(pa_dbus_connection_get(conn), - AEC_MANAGER_OBJECT_PATH, &vtable, NULL)) { - pa_dbus_connection_unref(conn); - pa_log_error("Failed to register object path"); - return -1; - } - - am.source = source; - am.sink = sink; - - pa_log_info("AEC init success"); - - return 0; -} - -void aec_manager_deinit(void) { - if (am.dbus_conn) - pa_dbus_connection_unref(am.dbus_conn); - - pa_log_info("AEC deinit success"); -} diff --git a/src/aec-manager.h b/src/aec-manager.h deleted file mode 100644 index d30f788..0000000 --- a/src/aec-manager.h +++ /dev/null @@ -1,38 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 2021 Jaechul Lee - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2.1 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifndef footizenaecmanagerfoo -#define footizenaecmanagerfoo - -typedef struct aec_params { - int rate; - int channels; - int format; - int frag_size; - int nfrags; - char card[32]; - char device[32]; -} aec_params_t; - -int aec_manager_init(pa_core *core, pa_source *source, pa_sink *sink); -void aec_manager_deinit(); - -#endif diff --git a/src/device-manager.c b/src/device-manager.c index 51fdba9..b5d6e9c 100644 --- a/src/device-manager.c +++ b/src/device-manager.c @@ -49,10 +49,6 @@ #include "device-manager-dbus-priv.h" #include "device-manager-db-priv.h" -#ifdef SUPPORT_AEC -#include "aec-manager.h" -#endif - #define SHARED_DEVICE_MANAGER "tizen-device-manager" #define DEVICE_MAP_FILE PA_DEFAULT_CONFIG_DIR"/device-map.json" @@ -2973,8 +2969,6 @@ static pa_hook_result_t device_running_changed_hook_cb(pa_core *c, pa_tz_device_ pa_device_manager* pa_device_manager_get(pa_core *c) { pa_device_manager *dm; - pa_source *source; - pa_sink *sink; pa_assert(c); @@ -3031,17 +3025,12 @@ pa_device_manager* pa_device_manager_get(pa_core *c) { } /* Just for convenience when test*/ - sink = _device_manager_set_default_sink(dm, DEVICE_TYPE_SPEAKER, "normal"); - if (!sink) + if (!_device_manager_set_default_sink(dm, DEVICE_TYPE_SPEAKER, "normal")) { pa_log_warn("Set default sink with speaker(normal) failed"); - - source = _device_manager_set_default_source(dm, DEVICE_TYPE_MIC, "normal"); - if (!source) + } + if (!_device_manager_set_default_source(dm, DEVICE_TYPE_MIC, "normal")) { pa_log_warn("Set default source with mic(normal) failed"); - -#ifdef SUPPORT_AEC - aec_manager_init(dm->core, source, sink); -#endif + } pa_shared_set(c, SHARED_DEVICE_MANAGER, dm); @@ -3119,9 +3108,4 @@ void pa_device_manager_unref(pa_device_manager *dm) { pa_shared_remove(dm->core, SHARED_DEVICE_MANAGER); pa_xfree(dm); - -#ifdef SUPPORT_AEC - aec_manager_deinit(); -#endif - } diff --git a/src/module-tizenaudio-sink.c b/src/module-tizenaudio-sink.c index 0ea7846..bb86007 100644 --- a/src/module-tizenaudio-sink.c +++ b/src/module-tizenaudio-sink.c @@ -47,10 +47,6 @@ #include "hal-interface.h" -#ifdef SUPPORT_AEC -#include "aec-manager.h" -#endif - PA_MODULE_AUTHOR("Tizen"); PA_MODULE_DESCRIPTION("Tizen Audio Sink"); PA_MODULE_VERSION(PACKAGE_VERSION); @@ -79,13 +75,6 @@ PA_MODULE_USAGE( #define DEVICE_NAME_MAX 30 #define SMALL_AVAIL_LOG_PERIOD 20 -#ifdef SUPPORT_AEC -enum { - PA_SINK_MESSAGE_SET_AEC_STATE = PA_SINK_MESSAGE_MAX, - PA_SINK_MESSAGE_GET_AEC_PARAMS, -}; -#endif - struct userdata { pa_core *core; pa_module *module; @@ -113,11 +102,6 @@ struct userdata { uint64_t small_avail_count; uint64_t write_count; pa_hal_interface *hal_interface; - -#ifdef SUPPORT_AEC - bool aec_enable; - pa_sample_spec ss; -#endif }; static const char* const valid_modargs[] = { @@ -180,7 +164,7 @@ static int suspend(struct userdata *u) { u->rtpoll_item = NULL; } - pa_log_info("Device suspended..."); + pa_log_info("Device suspended...[%s,%s]", u->card, u->device); return 0; } @@ -191,9 +175,6 @@ static int unsuspend(struct userdata *u) { int32_t ret; size_t frame_size; - char *card = u->card; - char *device = u->device; - pa_assert(u); pa_assert(!u->pcm_handle); @@ -206,16 +187,9 @@ static int unsuspend(struct userdata *u) { goto fail; } -#ifdef SUPPORT_AEC - if (u->aec_enable) { - card = "Loopback"; - device = "0,0"; - } -#endif - ret = pa_hal_interface_pcm_open(u->hal_interface, - card, - device, + u->card, + u->device, DIRECTION_OUT, &sample_spec, u->frag_size / frame_size, @@ -232,7 +206,7 @@ static int unsuspend(struct userdata *u) { u->write_count = 0; u->first = true; - pa_log_info("Resumed successfully...device(%s:%s)", card, device); + pa_log_info("Resumed successfully..."); return 0; @@ -309,36 +283,6 @@ static int sink_process_msg( *((pa_usec_t*)data) = latency; return 0; } -#ifdef SUPPORT_AEC - case PA_SINK_MESSAGE_SET_AEC_STATE: { - pa_sink *s = PA_SINK(o); - bool enable = (bool)data; - - if (u->aec_enable == enable) - return 0; - - pa_log_info("AEC enable(%d)", enable); - - u->aec_enable = enable; - if (s->thread_info.state == PA_SINK_RUNNING) { - suspend(u); - unsuspend(u); - } - - return 0; - } - case PA_SINK_MESSAGE_GET_AEC_PARAMS: { - aec_params_t *params = (aec_params_t *)data; - params->rate = u->ss.rate; - params->channels = u->ss.channels; - params->format = u->ss.format; - params->frag_size = u->frag_size; - params->nfrags = u->nfrags; - snprintf(params->card, DEVICE_NAME_MAX, "%s", u->card); - snprintf(params->device, DEVICE_NAME_MAX, "%s", u->device); - return 0; - } -#endif } return pa_sink_process_msg(o, code, data, offset, chunk); @@ -641,9 +585,6 @@ int pa__init(pa_module*m) { u->first = true; u->hal_interface = pa_hal_interface_get(u->core); u->rtpoll = pa_rtpoll_new(); -#ifdef SUPPORT_AEC - u->ss = ss; -#endif pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { diff --git a/src/module-tizenaudio-source.c b/src/module-tizenaudio-source.c index e3ed819..746eb74 100644 --- a/src/module-tizenaudio-source.c +++ b/src/module-tizenaudio-source.c @@ -47,10 +47,6 @@ #include "hal-interface.h" -#ifdef SUPPORT_AEC -#include "aec-manager.h" -#endif - PA_MODULE_AUTHOR("Tizen"); PA_MODULE_DESCRIPTION("Tizen Audio Source"); PA_MODULE_VERSION(PACKAGE_VERSION); @@ -74,13 +70,6 @@ PA_MODULE_USAGE( #define DEVICE_NAME_MAX 30 -#ifdef SUPPORT_AEC -enum { - PA_SOURCE_MESSAGE_SET_AEC_STATE = PA_SOURCE_MESSAGE_MAX, - PA_SOURCE_MESSAGE_GET_AEC_PARAMS, -}; -#endif - struct userdata { pa_core *core; pa_module *module; @@ -106,11 +95,6 @@ struct userdata { uint64_t read_count; pa_usec_t latency_time; pa_hal_interface *hal_interface; - -#ifdef SUPPORT_AEC - bool aec_enable; - pa_sample_spec ss; -#endif }; static const char* const valid_modargs[] = { @@ -168,7 +152,7 @@ static int suspend(struct userdata *u) { u->rtpoll_item = NULL; } - pa_log_info("Device suspended..."); + pa_log_info("Device suspended...[%s,%s]", u->card, u->device); return 0; } @@ -179,9 +163,6 @@ static int unsuspend(struct userdata *u) { int32_t ret; size_t frame_size; - char *card = u->card; - char *device = u->device; - pa_assert(u); pa_assert(!u->pcm_handle); @@ -194,16 +175,9 @@ static int unsuspend(struct userdata *u) { goto fail; } -#ifdef SUPPORT_AEC - if (u->aec_enable) { - card = "Loopback"; - device = "1,1"; - } -#endif - ret = pa_hal_interface_pcm_open(u->hal_interface, - card, - device, + u->card, + u->device, DIRECTION_IN, &sample_spec, u->frag_size / frame_size, @@ -220,7 +194,7 @@ static int unsuspend(struct userdata *u) { u->read_count = 0; u->first = true; - pa_log_info("Resumed successfully...device(%s:%s)", card, device); + pa_log_info("Resumed successfully..."); return 0; @@ -291,36 +265,6 @@ static int source_process_msg( *((pa_usec_t*)data) = u->timestamp > now ? 0ULL : now - u->timestamp; return 0; } -#ifdef SUPPORT_AEC - case PA_SOURCE_MESSAGE_SET_AEC_STATE: { - pa_source *s = PA_SOURCE(o); - bool enable = (bool)data; - - if (u->aec_enable == enable) - return 0; - - pa_log_info("AEC enable(%d)", enable); - - u->aec_enable = enable; - if (s->thread_info.state == PA_SOURCE_RUNNING) { - suspend(u); - unsuspend(u); - } - - return 0; - } - case PA_SOURCE_MESSAGE_GET_AEC_PARAMS: { - aec_params_t *params = (aec_params_t *)data; - params->rate = u->ss.rate; - params->channels = u->ss.channels; - params->format = u->ss.format; - params->frag_size = u->frag_size; - params->nfrags = u->nfrags; - snprintf(params->card, DEVICE_NAME_MAX, "%s", u->card); - snprintf(params->device, DEVICE_NAME_MAX, "%s", u->device); - return 0; - } -#endif } return pa_source_process_msg(o, code, data, offset, chunk); @@ -555,9 +499,6 @@ int pa__init(pa_module*m) { u->first = true; u->hal_interface = pa_hal_interface_get(u->core); u->rtpoll = pa_rtpoll_new(); -#ifdef SUPPORT_AEC - u->ss = ss; -#endif pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { -- 2.7.4 From 9a497c1dcc1e95e276769e7f01a1117dcde3b80f Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Thu, 16 Jun 2022 23:48:35 +0900 Subject: [PATCH 06/16] device-manager: avoid registering the built-in device if not loaded properly Previously, it was shown that the built-in device exists even module is not loaded correctly. Now, this change fixed that mismatch. [Version] 15.0.17 [Issue Type] Bug Change-Id: I6c78231e62c75ac759964697ee2e079a80bb58c3 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/device-manager.c | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 16babe1..994fa15 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.16 +Version: 15.0.17 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/device-manager.c b/src/device-manager.c index b5d6e9c..4ba4450 100644 --- a/src/device-manager.c +++ b/src/device-manager.c @@ -2015,6 +2015,7 @@ static int _load_type_devices(device_type_info *type_info, bool is_playback, pa_ const char *device_string, *params; bool first_one = true; void *device; + bool loaded = false; pa_assert(dm); pa_assert(type_info); @@ -2035,6 +2036,7 @@ static int _load_type_devices(device_type_info *type_info, bool is_playback, pa_ } PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) { + pa_log_debug("k:role(%s), v:device_string(%s)", role, device_string); /* skip duplicate load */ if (is_playback && _core_get_sink(dm->core, device_string, NULL)) { pa_log_debug("Already loaded %s", device_string); @@ -2065,6 +2067,12 @@ static int _load_type_devices(device_type_info *type_info, bool is_playback, pa_ first_one = false; } pa_log_info("load device success %s %s %s", device_string, params, role); + loaded = true; + } + + if (!loaded) { + pa_log_error("Returning error due to no device loaded in success"); + return -1; } return 0; @@ -2204,7 +2212,7 @@ static int load_builtin_devices(pa_device_manager *dm) { type = type_info->type; - pa_log_info("type_info : %s", type); + pa_log_info("[%u] type_info : %s", type_idx, type); detected_type = _device_get_detected(dm, type, NULL); if (detected_type == DEVICE_DISCONNECTED) { pa_log_info("Not detected yet"); @@ -2219,23 +2227,25 @@ static int load_builtin_devices(pa_device_manager *dm) { _load_type_devices(type_info, true, dm); } handle_device_connected(dm, type, NULL, NULL, detected_type, type_info); - } else if (device_type_is_use_external_card(type) == false) { - dm_device_direction_t direction; - direction = device_type_get_static_direction(type); + } else if (!device_type_is_use_external_card(type)) { + dm_device_direction_t direction = device_type_get_static_direction(type); if (direction == DM_DEVICE_DIRECTION_NONE) { pa_log_warn("Wrong direction"); continue; } - if (direction & DM_DEVICE_DIRECTION_OUT) - _load_type_devices(type_info, true, dm); - if (direction & DM_DEVICE_DIRECTION_IN) - _load_type_devices(type_info, false, dm); - handle_device_connected(dm, type, NULL, NULL, detected_type, type_info); + + if ( _load_type_devices(type_info, (direction & DM_DEVICE_DIRECTION_OUT), dm) == 0) + handle_device_connected(dm, type, NULL, NULL, detected_type, type_info); + else + pa_log_warn("type %s failed....", type); + } else { pa_log_warn("Invalid case"); } } + pa_log_debug("Load Builtin Devices Done"); + return 0; } -- 2.7.4 From 1f8f4353d5463431b54d5ca119d60006df466fff Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Mon, 13 Jun 2022 21:37:50 +0900 Subject: [PATCH 07/16] device-manager: Add builtin tv-mic support [Version] 15.0.18 [Issue Type] Improvement Change-Id: If35aa1bffa27588629124e97bf7249688782d492 --- packaging/pulseaudio-modules-tizen.spec | 4 +- src/device-manager.c | 80 +++++++++++++++++++++++++-------- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 994fa15..6ec8a2b 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.17 +Version: 15.0.18 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ @@ -45,7 +45,7 @@ PulseAudio module-acm-sink for sending PCM data to ACM core. %build export CFLAGS="%{optflags} -fno-strict-aliasing -D__TIZEN__ -DSYSCONFDIR=\\\"%{_hal_sysconfdir}\\\" " %if "%{tizen_profile_name}" == "tv" - export CFLAGS+=" -DTIZEN_TV"; + export CFLAGS+=" -DTIZEN_TV -D__TIZEN_TV_BUILTIN_MIC__"; %else export CFLAGS+=" -D__TIZEN_INTERNAL_BT_SCO__" %endif diff --git a/src/device-manager.c b/src/device-manager.c index 4ba4450..acd3c38 100644 --- a/src/device-manager.c +++ b/src/device-manager.c @@ -99,6 +99,9 @@ typedef enum dm_device_class_type { DM_DEVICE_CLASS_BT, DM_DEVICE_CLASS_NULL, DM_DEVICE_CLASS_ACM, +#ifdef __TIZEN_TV_BUILTIN_MIC__ + DM_DEVICE_CLASS_TVMIC, +#endif DM_DEVICE_CLASS_MAX, } dm_device_class_t; @@ -235,7 +238,14 @@ static const device_module_t module_table[] = { .module_name = { NULL, "module-acm-sink" }, .device_string = "acm", .custom_device_get_func = NULL + }, +#ifdef __TIZEN_TV_BUILTIN_MIC__ + [DM_DEVICE_CLASS_TVMIC] = { + .module_name = { "module-tizentv-builtin-source", NULL }, + .device_string = "tvmic", + .custom_device_get_func = NULL } +#endif }; void simple_device_dump(pa_log_level_t level, const char *prefix, int id, const char *type, const char *name, int direction, int state) { @@ -322,6 +332,10 @@ static dm_device_class_t device_string_get_class(const char *device_string) { return DM_DEVICE_CLASS_TIZEN; else if (device_string == strstr(device_string, "acm")) return DM_DEVICE_CLASS_ACM; +#ifdef __TIZEN_TV_BUILTIN_MIC__ + else if (device_string == strstr(device_string, "tvmic")) + return DM_DEVICE_CLASS_TVMIC; +#endif return DM_DEVICE_CLASS_NONE; } @@ -461,6 +475,18 @@ static bool pulse_device_is_rtsp(pa_object *pdevice) { return pa_safe_streq(pa_proplist_gets(prop, PA_PROP_DEVICE_API), DEVICE_API_RTSP); } +#ifdef __TIZEN_TV_BUILTIN_MIC__ +static bool pulse_device_is_tvmic(pa_object *pdevice) { + if (!pdevice) + return false; + + if (pa_sink_isinstance(pdevice)) + return false; + + return pa_safe_streq(PA_SOURCE(pdevice)->module->name, module_table[DM_DEVICE_CLASS_TVMIC].module_name[0]); +} +#endif + #ifndef __TIZEN_INTERNAL_BT_SCO__ static bool pulse_device_is_btsco(pa_object *pdevice) { pa_proplist *prop = pulse_device_get_proplist(pdevice); @@ -529,6 +555,10 @@ static dm_device_class_t pulse_device_get_class(pa_object *pdevice) { return DM_DEVICE_CLASS_BT; else if (pulse_device_is_acm(pdevice)) return DM_DEVICE_CLASS_ACM; +#ifdef __TIZEN_TV_BUILTIN_MIC__ + else if (pulse_device_is_tvmic(pdevice)) + return DM_DEVICE_CLASS_TVMIC; +#endif return DM_DEVICE_CLASS_NONE; } @@ -805,28 +835,32 @@ static int build_params_to_load_module(const char *device_string, const char *pa pa_assert(params); pa_assert(target); - if ((device_class != DM_DEVICE_CLASS_ALSA) && - (device_class != DM_DEVICE_CLASS_TIZEN) && - (device_class != DM_DEVICE_CLASS_ACM)) - return -1; - - if (device_class == DM_DEVICE_CLASS_ACM) { + switch (device_class) { + case DM_DEVICE_CLASS_ACM: +#ifdef __TIZEN_TV_BUILTIN_MIC__ + /* fall-through */ + case DM_DEVICE_CLASS_TVMIC: +#endif snprintf(target, DEVICE_PARAM_STRING_MAX, "%s ", params); - return 0; - } + break; + + case DM_DEVICE_CLASS_ALSA: + /* fall-through */ + case DM_DEVICE_CLASS_TIZEN: + if (device_string_get_name(device_string, device_name) < 0) { + pa_log_error("Invalid device string '%s'", device_string); + return -1; + } + + snprintf(target, DEVICE_PARAM_STRING_MAX, "device=%s%s %s", + (device_class == DM_DEVICE_CLASS_ALSA) ? "hw:" : "", device_name, params); + break; - if (device_string_get_name(device_string, device_name) < 0) { - pa_log_error("Invalid device string '%s'", device_string); + default: + pa_log_error("unexpected device_class(%d)", device_class); return -1; } - if (device_class == DM_DEVICE_CLASS_ALSA) - snprintf(target, DEVICE_PARAM_STRING_MAX, "device=hw:%s ", device_name); - else if (device_class == DM_DEVICE_CLASS_TIZEN) - snprintf(target, DEVICE_PARAM_STRING_MAX, "device=%s ", device_name); - - strncat(target, params, DEVICE_PARAM_STRING_MAX - strlen(target)); - return 0; } @@ -1783,7 +1817,11 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pulse_device_set_use_internal_codec(PA_OBJECT(source), false); handle_bt_pulse_device(PA_OBJECT(source), true, dm); return PA_HOOK_OK; - } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) { + } else if (pulse_device_is_alsa(PA_OBJECT(source)) || +#ifdef __TIZEN_TV_BUILTIN_MIC__ + pulse_device_is_tvmic(PA_OBJECT(source)) || +#endif + pulse_device_is_tizenaudio(PA_OBJECT(source))) { pulse_device_set_use_internal_codec(PA_OBJECT(source), true); handle_internal_pulse_device(PA_OBJECT(source), true, dm); return PA_HOOK_OK; @@ -1831,7 +1869,11 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc pa_log_warn("tunnel but not remote....ignore this"); } return PA_HOOK_OK; - } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) { + } else if (pulse_device_is_alsa(PA_OBJECT(source)) || +#ifdef __TIZEN_TV_BUILTIN_MIC__ + pulse_device_is_tvmic(PA_OBJECT(source)) || +#endif + pulse_device_is_tizenaudio(PA_OBJECT(source))) { handle_internal_pulse_device(PA_OBJECT(source), false, dm); return PA_HOOK_OK; } else if (pulse_device_is_rtsp(PA_OBJECT(source))) { -- 2.7.4 From d072587ace032bdf2c0bd706365631967d4572dd Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Tue, 21 Jun 2022 17:05:56 +0900 Subject: [PATCH 08/16] Rename __TIZEN_INTERNAL_BT_SCO__ to __TIZEN_TV_EXTERNAL_BT_SCO__ The 'external bt sco' feature is only for tv binary. So, the preprocessor definition name is changed to have __TIZEN_TV_ prefix as well as to invert the meaning of the previous name. [Version] 15.0.19 [Issue Type] Rename Change-Id: Iff1847574b925d8fb72efc3687f1926d3e110b8e Signed-off-by: Sangchul Lee --- packaging/pulseaudio-modules-tizen.spec | 6 ++---- src/device-manager-dbus.c | 22 ++++++++++---------- src/device-manager.c | 18 ++++++++--------- src/module-tizenaudio-policy.c | 36 ++++++++++++++++----------------- src/tizen-device.c | 8 ++++---- src/tizen-device.h | 4 ++-- 6 files changed, 46 insertions(+), 48 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 6ec8a2b..5a5282f 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.18 +Version: 15.0.19 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ @@ -45,9 +45,7 @@ PulseAudio module-acm-sink for sending PCM data to ACM core. %build export CFLAGS="%{optflags} -fno-strict-aliasing -D__TIZEN__ -DSYSCONFDIR=\\\"%{_hal_sysconfdir}\\\" " %if "%{tizen_profile_name}" == "tv" - export CFLAGS+=" -DTIZEN_TV -D__TIZEN_TV_BUILTIN_MIC__"; -%else - export CFLAGS+=" -D__TIZEN_INTERNAL_BT_SCO__" +export CFLAGS+=" -DTIZEN_TV -D__TIZEN_TV_EXTERNAL_BT_SCO__ -D__TIZEN_TV_BUILTIN_MIC__"; %endif export LD_AS_NEEDED=0 diff --git a/src/device-manager-dbus.c b/src/device-manager-dbus.c index 8c067af..7752ce6 100644 --- a/src/device-manager-dbus.c +++ b/src/device-manager-dbus.c @@ -219,7 +219,7 @@ static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata); static void handle_set_acm_mode(DBusConnection *conn, DBusMessage *msg, void *userdata); -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name); #endif @@ -433,7 +433,7 @@ static int _translate_external_value(const char *type, int value, device_detecte return 0; } -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ static int handle_bluez_headset_property_changed(DBusConnection *c, DBusMessage *s, pa_device_manager *dm) { DBusMessageIter msg_iter, variant_iter; char *property_name; @@ -507,7 +507,7 @@ static int handle_bluez_headset_property_changed(DBusConnection *c, DBusMessage return 0; } -#endif /* __TIZEN_INTERNAL_BT_SCO__ */ +#endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */ static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) { DBusError error; @@ -554,7 +554,7 @@ static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DB goto fail; } handle_device_status_changed(dm, DEVICE_TYPE_FORWARDING, NULL, NULL, detected); -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ } else if (dbus_message_is_signal(s, DBUS_INTERFACE_BLUEZ_HEADSET, "PropertyChanged")) { if (handle_bluez_headset_property_changed(c, s, dm) < 0) goto fail; @@ -639,7 +639,7 @@ static bool device_is_match_with_mask(pa_tz_device *device, int mask) { device_is_match_type(device, mask & DEVICE_TYPE_FLAGS)); } -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name) { const char *intf = DBUS_INTERFACE_BLUEZ_DEVICE, *prop = "Alias"; DBusMessage *msg, *reply; @@ -687,7 +687,7 @@ static int method_call_bt_get_name(DBusConnection *conn, const char *device_path dbus_message_unref(reply); return 0; } -#endif /* __TIZEN_INTERNAL_BT_SCO__ */ +#endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */ static void array_iter_append(DBusMessageIter *array_iter, pa_idxset *device_list, int mask) { uint32_t device_idx; @@ -732,7 +732,7 @@ static void array_iter_append(DBusMessageIter *array_iter, pa_idxset *device_lis } } -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ static int include_device_filter_func(const void *d, const void *include_device_type) { pa_tz_device *device = (pa_tz_device *)d; @@ -750,14 +750,14 @@ static int exclude_device_filter_func(const void *d, const void *exclude_device_ return (int)!pa_safe_streq(pa_tz_device_get_type(device), (const char *)exclude_device_type); } -#endif /* __TIZEN_INTERNAL_BT_SCO__ */ +#endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) { pa_device_manager *dm = (pa_device_manager *)userdata; DBusMessage *reply = NULL; DBusMessageIter msg_iter, array_iter; int mask; -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ pa_idxset *idxset1, *idxset2; #endif @@ -776,7 +776,7 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage * dbus_message_iter_init_append(reply, &msg_iter); pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiisiib)", &array_iter)); -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ array_iter_append(&array_iter, dm->device_list, mask); #else /* divide into two groups and merge them because dbus message doesn't support sorting or prepend */ @@ -788,7 +788,7 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage * pa_idxset_free(idxset1, NULL); pa_idxset_free(idxset2, NULL); -#endif /* __TIZEN_INTERNAL_BT_SCO__ */ +#endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */ pa_assert_se(dbus_message_iter_close_container(&msg_iter, &array_iter)); diff --git a/src/device-manager.c b/src/device-manager.c index acd3c38..f541685 100644 --- a/src/device-manager.c +++ b/src/device-manager.c @@ -85,7 +85,7 @@ #define DEVICE_API_RAOP "raop" #define DEVICE_API_TUNNEL "tunnel" #define DEVICE_API_RTSP "rtsp" -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ #define DEVICE_API_BTSCO "btsco" #endif #define DEVICE_BUS_USB "usb" @@ -487,7 +487,7 @@ static bool pulse_device_is_tvmic(pa_object *pdevice) { } #endif -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ static bool pulse_device_is_btsco(pa_object *pdevice) { pa_proplist *prop = pulse_device_get_proplist(pdevice); @@ -1198,7 +1198,7 @@ static const char* pulse_device_get_system_id(pa_object *pdevice) { return pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION); else if (pulse_device_is_rtsp(pdevice)) return pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION); -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ else if (pulse_device_is_btsco(pdevice)) return pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION); #endif @@ -1620,7 +1620,7 @@ static void handle_rtsp_pulse_device(pa_object *pdevice, bool is_loaded, pa_devi } } -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ static void handle_external_btsco_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *dm) { const char *name, *system_id; dm_device_direction_t direction; @@ -1662,7 +1662,7 @@ static void handle_external_btsco_pulse_device(pa_object *pdevice, bool is_loade pa_tz_device_free(device); } } -#endif /* __TIZEN_INTERNAL_BT_SCO__ */ +#endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */ static void handle_internal_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *dm) { pa_tz_device *device; @@ -1737,7 +1737,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, pa_dev pulse_device_set_use_internal_codec(PA_OBJECT(sink), true); handle_internal_pulse_device(PA_OBJECT(sink), true, dm); return PA_HOOK_OK; -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ } else if (pulse_device_is_btsco(PA_OBJECT(sink))) { pulse_device_set_use_internal_codec(PA_OBJECT(sink), false); handle_external_btsco_pulse_device(PA_OBJECT(sink), true, dm); @@ -1787,7 +1787,7 @@ static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_ } else if (pulse_device_is_alsa(PA_OBJECT(sink)) || pulse_device_is_tizenaudio(PA_OBJECT(sink))) { handle_internal_pulse_device(PA_OBJECT(sink), false, dm); return PA_HOOK_OK; -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ } else if (pulse_device_is_btsco(PA_OBJECT(sink))) { handle_external_btsco_pulse_device(PA_OBJECT(sink), false, dm); return PA_HOOK_OK; @@ -1829,7 +1829,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, pulse_device_set_use_internal_codec(PA_OBJECT(source), false); handle_rtsp_pulse_device(PA_OBJECT(source), true, dm); return PA_HOOK_OK; -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ } else if (pulse_device_is_btsco(PA_OBJECT(source))) { pulse_device_set_use_internal_codec(PA_OBJECT(source), false); handle_external_btsco_pulse_device(PA_OBJECT(source), true, dm); @@ -1878,7 +1878,7 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc return PA_HOOK_OK; } else if (pulse_device_is_rtsp(PA_OBJECT(source))) { handle_rtsp_pulse_device(PA_OBJECT(source), false, dm); -#ifndef __TIZEN_INTERNAL_BT_SCO__ +#ifdef __TIZEN_TV_EXTERNAL_BT_SCO__ } else if (pulse_device_is_btsco(PA_OBJECT(source))) { handle_external_btsco_pulse_device(PA_OBJECT(source), false, dm); return PA_HOOK_OK; diff --git a/src/module-tizenaudio-policy.c b/src/module-tizenaudio-policy.c index bb331e0..81dbb4e 100644 --- a/src/module-tizenaudio-policy.c +++ b/src/module-tizenaudio-policy.c @@ -85,7 +85,7 @@ struct userdata; #define LOOPBACK_DEFAULT_LATENCY_MSEC 40 #define LOOPBACK_DEFAULT_ADJUST_SEC 3 -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ #define TIMED_BT_SCO_CLOSE_USEC 3000000 #endif @@ -185,7 +185,7 @@ struct userdata { int32_t latency_msec; int32_t adjust_sec; } loopback_args; -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ pa_time_event *time_event_bt_sco_close; #endif }; @@ -212,7 +212,7 @@ static void __load_dump_config(struct userdata *u) iniparser_freedict(dict); } -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ /* threre is only one sco connected device */ static pa_tz_device* _get_sco_connected_device(pa_device_manager *dm) { pa_idxset *device_list; @@ -696,7 +696,7 @@ static bool skip_device(const char *stream_role, const char *device_type) return false; } -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ static bool skip_bt_sco_device(struct userdata *u, const char *stream_role, const char *device_type) { pa_assert(u); pa_assert(stream_role); @@ -827,7 +827,7 @@ static void select_device_by_auto_or_auto_all_routing(struct userdata *u, pa_str if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) continue; pa_log_info(" ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction); -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ if (skip_bt_sco_device(u, data->stream_role, dm_device_type)) continue; #endif @@ -901,7 +901,7 @@ static void select_device_by_auto_last_connected_routing(struct userdata *u, pa_ dm_device_type, dm_device_direction, dm_device_id, creation_time); if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) continue; -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ if (skip_bt_sco_device(u, data->stream_role, dm_device_type)) continue; #endif @@ -1149,7 +1149,7 @@ static void reset_route(struct userdata *u, stream_type_t stream_type) { pa_assert(u); -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ /* update BT SCO: close */ update_bt_sco_state(u, false, true, NULL); #endif @@ -1305,7 +1305,7 @@ static void fill_device_info(hal_route_info *route_info, const char *type, uint3 route_info->num_of_devices -1, type, direction, id); } -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ static pa_hook_result_t update_combine_sink_and_bt_sco(struct userdata *u, pa_stream_manager_hook_data_for_route *data, pa_tz_device *device, const char *stream_role, const char *dm_device_type, pa_sink **combine_sink_arg1, pa_sink **combine_sink_arg2) { @@ -1329,7 +1329,7 @@ static pa_hook_result_t update_combine_sink(struct userdata *u, pa_stream_manage else pa_log_error("[ROUTE][AUTO] could not get sink"); } -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) { if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(stream_role)) { if (update_bt_sco_state(u, true, false, stream_role)) { @@ -1350,7 +1350,7 @@ static pa_hook_result_t update_combine_sink(struct userdata *u, pa_stream_manage void *s = NULL; stream_route_type_t route_type; -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ update_bt_sco_state(u, false, false, NULL); #endif @@ -1436,7 +1436,7 @@ static int32_t update_route_by_preemptive_device(struct userdata *u, pa_stream_m /* if it needs to skip it, keep going to next device for proper UCM setting */ if (skip_device(data->stream_role, dm_device_type)) return -1; -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ if (skip_bt_sco_device(u, data->stream_role, dm_device_type)) return -1; #endif @@ -1492,7 +1492,7 @@ static pa_hook_result_t handle_auto_or_auto_all_routing(struct userdata *u, pa_s /* if it needs to skip it, keep going to next device for proper UCM setting */ if (skip_device(data->stream_role, dm_device_type)) continue; -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ if (skip_bt_sco_device(u, data->stream_role, dm_device_type)) continue; #endif @@ -1513,14 +1513,14 @@ update_auto_active_dev: else pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type); -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ return update_combine_sink_and_bt_sco(u, data, *device, route_info->role, dm_device_type, NULL, NULL); #else return update_combine_sink(u, data, *device, route_info->role, dm_device_type, NULL, NULL); #endif } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) { -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ update_combine_sink_and_bt_sco(u, data, *device, NULL, NULL, &combine_sink_arg1, &combine_sink_arg2); #else update_combine_sink(u, data, *device, NULL, NULL, &combine_sink_arg1, &combine_sink_arg2); @@ -1575,7 +1575,7 @@ static pa_hook_result_t handle_auto_last_connected_routing(struct userdata *u, p continue; if ((use_internal_codec = pa_tz_device_is_use_internal_codec(*device))) { /* if it needs to skip it, keep going to next device for proper UCM setting */ -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ if (skip_device(data->stream_role, dm_device_type) || skip_bt_sco_device(u, data->stream_role, dm_device_type)) #else @@ -1622,7 +1622,7 @@ update_auto_active_dev: pa_log_error("[ROUTE][AUTO_LAST_CONN] could not get sink"); } -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) { if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info->role)) { if (update_bt_sco_state(u, true, false, route_info->role)) { @@ -1674,7 +1674,7 @@ static pa_hook_result_t handle_manual_routing(struct userdata *u, pa_stream_mana pa_log_debug(" ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction); -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ /* Check for availability for opening Bluetooth SCO */ if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO) && IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info->role)) { /* update BT SCO: open */ @@ -2016,7 +2016,7 @@ void pa__done(pa_module *m) if (!(u = m->userdata)) return; -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ bt_sco_close(u, false); #endif diff --git a/src/tizen-device.c b/src/tizen-device.c index cbeae10..0f8a481 100644 --- a/src/tizen-device.c +++ b/src/tizen-device.c @@ -145,7 +145,7 @@ static char* _device_get_info_str(pa_tz_device *device) { pa_strbuf_printf(buf, " Product ID : %04x\n", device->product_id); pa_strbuf_printf(buf, " Specified Stream role : %s\n", device->specified_stream_role); } -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO)) pa_strbuf_printf(buf, " SCO opened : %s\n", pa_yes_no(device->sco_opened)); #endif @@ -494,7 +494,7 @@ pa_tz_device* pa_tz_device_new(pa_tz_device_new_data *data) { device->state = DM_DEVICE_STATE_DEACTIVATED; device->creation_time = pa_rtclock_now(); device->use_internal_codec = data->use_internal_codec; -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ device->sco_opened = false; #endif device->is_running = false; @@ -836,7 +836,7 @@ pa_intset* pa_tz_device_get_stream_list(pa_tz_device *device) { return stream_id_set; } -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ static int method_call_bt_sco_enable_pcm(pa_dbus_connection *conn, bool enable) { DBusMessage *msg, *reply; DBusError err; @@ -1086,5 +1086,5 @@ int pa_tz_device_sco_get_status(pa_tz_device *device, dm_device_bt_sco_status_t pa_log_info("BT SCO (%u) Get Status, %d", device->id, *status); return 0; } -#endif /* __TIZEN_INTERNAL_BT_SCO__ */ +#endif /* __TIZEN_TV_EXTERNAL_BT_SCO__ */ diff --git a/src/tizen-device.h b/src/tizen-device.h index a7649ae..a809eed 100644 --- a/src/tizen-device.h +++ b/src/tizen-device.h @@ -59,8 +59,8 @@ struct pa_tz_device { /* Will be true, if this device uses internal codec(card), * false, if this device uses external card(bt-a2dp, usb */ bool use_internal_codec; +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ /* If this is sco device, this can be used to */ -#ifdef __TIZEN_INTERNAL_BT_SCO__ bool sco_opened; #endif @@ -155,7 +155,7 @@ bool pa_tz_device_is_use_internal_codec(pa_tz_device *device); bool pa_tz_device_is_all_suspended(pa_tz_device *device); pa_intset* pa_tz_device_get_stream_list(pa_tz_device *device); -#ifdef __TIZEN_INTERNAL_BT_SCO__ +#ifndef __TIZEN_TV_EXTERNAL_BT_SCO__ /* Only for BT SCO device */ int pa_tz_device_sco_enable_pcm(pa_tz_device *device, bool enable); int pa_tz_device_sco_open(pa_tz_device *device); -- 2.7.4 From 1677d8a0ef35572e10cb8e8ebd4f7a5814c845de Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Fri, 3 Dec 2021 11:15:30 +0900 Subject: [PATCH 09/16] Support external device playback and capture on sink2/source2 module-alsa-card tries to use 'device_id' that is from udev but tizenaudio-sink2/source2 can't load devices with device_id. This patch makes devices load with device_id and device_string both. [Version] 15.0.20 [Issue Type] New feature Change-Id: I2dcd7b4abdc88abacec5ba997050217c0c8bfc48 Signed-off-by: Jaechul Lee --- Makefile.am | 39 +++--- packaging/pulseaudio-modules-tizen.spec | 2 +- src/hal-interface.c | 4 +- src/hal-interface.h | 2 +- src/module-tizenaudio-sink2.c | 2 +- src/module-tizenaudio-source2.c | 2 +- src/tizenaudio-sink2.c | 175 ++++++++++++++++---------- src/tizenaudio-sink2.h | 12 +- src/tizenaudio-source2.c | 177 ++++++++++++++++---------- src/tizenaudio-source2.h | 12 +- src/tizenaudio-util.c | 217 ++++++++++++++++++++++++++++++++ src/tizenaudio-util.h | 54 ++++++++ 12 files changed, 534 insertions(+), 164 deletions(-) create mode 100644 src/tizenaudio-util.c create mode 100644 src/tizenaudio-util.h diff --git a/Makefile.am b/Makefile.am index 12098ed..b3d0913 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,21 +31,21 @@ MODULE_LDFLAGS = $(AM_LDFLAGS) $(PACORE_LDFLAGS) $(PA_LDFLAGS) -module -disable- MODULE_LIBADD = $(AM_LIBADD) $(PACORE_LIBS) $(PA_LIBS) pulsemodlibexec_LTLIBRARIES = \ - libhal-interface.la \ - libprocessor.la \ - libcommunicator.la \ - libtizenaudio-util.la \ - module-tizenaudio-sink.la \ - module-tizenaudio-source.la \ - module-tizenaudio-sink2.la \ - module-tizenaudio-source2.la \ - module-tizenaudio-policy.la \ - module-tizenaudio-discover.la \ - module-tizenaudio-publish.la \ - module-tizenaudio-echo-cancel.la \ - module-sound-player.la \ - module-tone-player.la \ - module-poweroff.la + libhal-interface.la \ + libprocessor.la \ + libcommunicator.la \ + libtizenaudio-util.la \ + module-tizenaudio-sink.la \ + module-tizenaudio-source.la \ + module-tizenaudio-sink2.la \ + module-tizenaudio-source2.la \ + module-tizenaudio-policy.la \ + module-tizenaudio-discover.la \ + module-tizenaudio-publish.la \ + module-tizenaudio-echo-cancel.la \ + module-sound-player.la \ + module-tone-player.la \ + module-poweroff.la if ENABLE_HALTC pulsemodlibexec_LTLIBRARIES += module-tizenaudio-haltc.la endif @@ -75,7 +75,14 @@ module_tizenaudio_source_la_LDFLAGS = $(MODULE_LDFLAGS) module_tizenaudio_source_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la module_tizenaudio_source_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_source -libtizenaudio_util_la_SOURCES = src/tizenaudio-sink2.c src/tizenaudio-sink2.h src/tizenaudio-source2.c src/tizenaudio-source2.h src/echo-cancel/echo-cancel-def.h +libtizenaudio_util_la_SOURCES = \ + src/tizenaudio-sink2.c \ + src/tizenaudio-sink2.h \ + src/tizenaudio-source2.c \ + src/tizenaudio-source2.h \ + src/tizenaudio-util.c \ + src/tizenaudio-util.h \ + src/echo-cancel/echo-cancel-def.h libtizenaudio_util_la_LDFLAGS = $(AM_LDFLAGS) $(PA_LDFLAGS) -avoid-version libtizenaudio_util_la_LIBADD = $(AM_LIBADD) $(PA_LIBS) libhal-interface.la libtizenaudio_util_la_CFLAGS = $(MODULE_CFLAGS) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 5a5282f..cd1cfef 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.19 +Version: 15.0.20 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/hal-interface.c b/src/hal-interface.c index e108f38..6837508 100644 --- a/src/hal-interface.c +++ b/src/hal-interface.c @@ -433,11 +433,11 @@ int32_t pa_hal_interface_pcm_recover(pa_hal_interface *h, pcm_handle pcm_h, int } int32_t pa_hal_interface_pcm_get_params(pa_hal_interface *h, pcm_handle pcm_h, uint32_t direction, - void **sample_spec, uint32_t *period_size, uint32_t *periods) { + void *sample_spec, uint32_t *period_size, uint32_t *periods) { audio_return_e hal_ret = AUDIO_RET_OK; pa_assert(h); - pa_assert(*sample_spec); + pa_assert(sample_spec); pa_assert(period_size); pa_assert(periods); diff --git a/src/hal-interface.h b/src/hal-interface.h index ebfca2f..800ff6c 100644 --- a/src/hal-interface.h +++ b/src/hal-interface.h @@ -111,7 +111,7 @@ int32_t pa_hal_interface_pcm_write(pa_hal_interface *h, pcm_handle pcm_h, const int32_t pa_hal_interface_pcm_read(pa_hal_interface *h, pcm_handle pcm_h, void *buffer, uint32_t frames); int32_t pa_hal_interface_pcm_get_fd(pa_hal_interface *h, pcm_handle pcm_h, int *fd); int32_t pa_hal_interface_pcm_recover(pa_hal_interface *h, pcm_handle pcm_h, int err); -int32_t pa_hal_interface_pcm_get_params(pa_hal_interface *h, pcm_handle pcm_h, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods); +int32_t pa_hal_interface_pcm_get_params(pa_hal_interface *h, pcm_handle pcm_h, uint32_t direction, void *sample_spec, uint32_t *period_size, uint32_t *periods); int32_t pa_hal_interface_pcm_set_params(pa_hal_interface *h, pcm_handle pcm_h, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods); int32_t pa_hal_interface_add_message_callback(pa_hal_interface *h, hal_message_callback callback, void *user_data); int32_t pa_hal_interface_remove_message_callback(pa_hal_interface *h, hal_message_callback callback); diff --git a/src/module-tizenaudio-sink2.c b/src/module-tizenaudio-sink2.c index 0861262..49410e0 100644 --- a/src/module-tizenaudio-sink2.c +++ b/src/module-tizenaudio-sink2.c @@ -65,7 +65,7 @@ int pa__init(pa_module *m) { goto fail; } - if (!(m->userdata = pa_tizenaudio_sink2_new(m, ma, __FILE__))) + if (!(m->userdata = pa_tizenaudio_sink2_new(m, ma, __FILE__, NULL, NULL, NULL, NULL))) goto fail; pa_modargs_free(ma); diff --git a/src/module-tizenaudio-source2.c b/src/module-tizenaudio-source2.c index 1df595e..cb821fb 100644 --- a/src/module-tizenaudio-source2.c +++ b/src/module-tizenaudio-source2.c @@ -65,7 +65,7 @@ int pa__init(pa_module *m) { goto fail; } - if (!(m->userdata = pa_tizenaudio_source2_new(m, ma, __FILE__))) + if (!(m->userdata = pa_tizenaudio_source2_new(m, ma, __FILE__, NULL, NULL, NULL, NULL))) goto fail; pa_modargs_free(ma); diff --git a/src/tizenaudio-sink2.c b/src/tizenaudio-sink2.c index a7ffd93..ff0dbc7 100644 --- a/src/tizenaudio-sink2.c +++ b/src/tizenaudio-sink2.c @@ -46,12 +46,13 @@ #include #include "hal-interface.h" +#include "tizenaudio-util.h" #include "echo-cancel/echo-cancel-def.h" #define DEFAULT_SINK_NAME "tizenaudio-sink2" #define DEVICE_NAME_MAX 30 -#define DEFAULT_FRAGMENT_MSEC 20 +#define DEFAULT_FRAGMENT_MSEC 10 #define DEFAULT_FRAGMENTS 4 struct userdata { @@ -377,59 +378,39 @@ finish: pa_log_debug("Thread shutting down"); } -static int parse_to_get_card(const char *modarg_device, char *card) { - const char *name_p; - char *card_p; - - if (!strchr(modarg_device, ',')) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - name_p = modarg_device; - card_p = card; - while (*name_p != ',') - *(card_p++) = *(name_p++); - *card_p = '\0'; - - return 0; -} - -static int parse_to_get_device(const char *modarg_device, char *device) { - const char *comma_p; - char *device_p; - - if (!(comma_p = strchr(modarg_device, ','))) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - comma_p++; - device_p = device; - while (*comma_p != '\0') - *(device_p++) = *(comma_p++); - *device_p = '\0'; - - return 0; -} - -pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *driver) { +pa_sink *pa_tizenaudio_sink2_new(pa_module *m, + pa_modargs *ma, + const char *driver, + pa_card *c, + char **device_string, + pa_sample_spec *sample_spec, + pa_channel_map *channel_map) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; pa_sink_new_data data; uint32_t alternate_sample_rate; const char *modarg_device; - char card[DEVICE_NAME_MAX]; - char device[DEVICE_NAME_MAX]; + const char *modarg_device_id; size_t frame_size, buffer_size, period_frames, buffer_frames; + pa_pcm_params_t param; + + uint32_t period_size; + uint32_t periods; pa_assert(m); pa_assert(ma); + /* TODO: It doesn't need to handle sample_spec, channels_map yet because it comes from UCM */ ss = m->core->default_sample_spec; map = m->core->default_channel_map; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { + + if (channel_map && channel_map->channels != ss.channels) + ss.channels = channel_map->channels; + + pa_channel_map_init_extend(&map, ss.channels, PA_CHANNEL_MAP_ALSA); + + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { pa_log_error("Invalid sample format specification or channel map"); goto fail; } @@ -449,19 +430,13 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); - if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { - pa_log_error("device is invalid"); + modarg_device_id = pa_modargs_get_value(ma, "device_id", NULL); + modarg_device = pa_modargs_get_value(ma, "device", NULL); + if (!modarg_device_id && !modarg_device) { + pa_log_error("Failed to get device id or device string"); goto fail; } - if (parse_to_get_card(modarg_device, card) || parse_to_get_device(modarg_device, device)) { - pa_log_error("failed to parse device module argument, %s", modarg_device); - goto fail; - } - - u->card = pa_xstrdup(card); - u->device = pa_xstrdup(device); - u->frag_size = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGMENT_MSEC * PA_USEC_PER_MSEC, &ss); u->nfrags = DEFAULT_FRAGMENTS; if (pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size) < 0 || @@ -469,11 +444,83 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive pa_log_error("fragment_size or fragments are invalid."); goto fail; } - pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); + + frame_size = pa_frame_size(&ss); + buffer_size = (size_t)(u->frag_size * u->nfrags); + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + + param.direction = DIRECTION_OUT; + param.ss = ss; + param.period_size = u->frag_size / pa_frame_size(&ss); + param.periods = u->nfrags; + + pa_log_info("Try to open device with rate(%d), channels(%d), format(%s), period_size(%u), periods(%u)", + ss.rate, ss.channels, pa_sample_format_to_string(ss.format), param.period_size, param.periods); + + if (modarg_device_id && device_string) { + if (pa_tz_util_pcm_open_by_dev_id( + u->hal_interface, + modarg_device_id, + device_string, + ¶m, + (void **)&u->pcm_handle, + &u->card, + &u->device)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + } else if (modarg_device) { + if (pa_tz_util_pcm_open_by_device( + u->hal_interface, + modarg_device, + ¶m, + (void **)&u->pcm_handle, + &u->card, + &u->device)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + } else { + pa_log_error("Device name doesn't exist"); + goto fail; + } + + if (!pa_sample_spec_equal(&ss, ¶m.ss)) { + pa_sample_spec _ss; + char requested_spec[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char selected_spec[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (pa_hal_interface_pcm_get_params(u->hal_interface, u->pcm_handle, 0, (void *)&_ss, &period_size, &periods) < 0) { + pa_log_error("Failed to get pcm params"); + goto fail; + } + + frame_size = pa_frame_size(¶m.ss); + u->frag_size = period_size * frame_size; + /* TODO: can't trust periods value from hal */ + u->nfrags = param.periods; + + buffer_size = (size_t)(u->frag_size * u->nfrags); + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + + pa_log_info("Device doesn't support sample_spec(%s). It was changed to (%s)", + pa_sample_spec_snprint(requested_spec, PA_SAMPLE_SPEC_SNPRINT_MAX, &ss), + pa_sample_spec_snprint(selected_spec, PA_SAMPLE_SPEC_SNPRINT_MAX, ¶m.ss)); + + ss = param.ss; + } + + pa_log_info("Device opened. card(%s), device(%s) rate(%d), channels(%d), format(%s), " + "frag_size(%u), nfrags(%u), period_size(%u), periods(%u)", + u->card, u->device, ss.rate, ss.channels, pa_sample_format_to_string(ss.format), + u->frag_size, u->nfrags, param.period_size, param.periods); pa_sink_new_data_init(&data); data.driver = driver; data.module = m; + data.card = c; pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); pa_sink_new_data_set_sample_spec(&data, &ss); pa_sink_new_data_set_channel_map(&data, &map); @@ -483,14 +530,12 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive pa_proplist_sets(data.proplist, "tizen.device", u->device); pa_proplist_sets(data.proplist, "tizen.version", "2"); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); - - frame_size = pa_frame_size(&ss); - buffer_size = (size_t)(u->frag_size * u->nfrags); - buffer_frames = buffer_size / frame_size; - period_frames = u->frag_size / frame_size; pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); + if (pa_modargs_get_value(ma, "device_id", NULL)) + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_BUS, "usb"); + if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log_error("Invalid properties."); pa_sink_new_data_done(&data); @@ -509,17 +554,7 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb; u->sink->userdata = u; - if (pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, - DIRECTION_OUT, - &u->sink->sample_spec, - u->frag_size / pa_frame_size(&u->sink->sample_spec), - u->nfrags, - (void **)&u->pcm_handle)) { - pa_log_error("Error opening PCM device"); - goto fail; - } + pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); @@ -538,7 +573,9 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive return u->sink; fail: - userdata_free(u); + if (u) + userdata_free(u); + return NULL; } diff --git a/src/tizenaudio-sink2.h b/src/tizenaudio-sink2.h index dd9e9e2..854ea9a 100644 --- a/src/tizenaudio-sink2.h +++ b/src/tizenaudio-sink2.h @@ -29,8 +29,16 @@ #include #include #include - -pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *driver); +#include +#include + +pa_sink *pa_tizenaudio_sink2_new(pa_module *m, + pa_modargs *ma, + const char *driver, + pa_card *c, + char **device_string, + pa_sample_spec *sample_spec, + pa_channel_map *channel_map); void pa_tizenaudio_sink2_free(pa_sink *s); diff --git a/src/tizenaudio-source2.c b/src/tizenaudio-source2.c index 8ddfa2f..846b086 100644 --- a/src/tizenaudio-source2.c +++ b/src/tizenaudio-source2.c @@ -46,12 +46,13 @@ #include #include "hal-interface.h" +#include "tizenaudio-util.h" #include "echo-cancel/echo-cancel-def.h" #define DEFAULT_SOURCE_NAME "tizenaudio-source2" #define DEVICE_NAME_MAX 30 -#define DEFAULT_FRAGMENT_MSEC 20 +#define DEFAULT_FRAGMENT_MSEC 10 #define DEFAULT_FRAGMENTS 4 struct userdata { @@ -382,58 +383,39 @@ finish: pa_log_debug("Thread shutting down"); } -static int parse_to_get_card(const char *modarg_device, char *card) { - const char *name_p; - char *card_p; - - if (!strchr(modarg_device, ',')) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - name_p = modarg_device; - card_p = card; - while (*name_p != ',') - *(card_p++) = *(name_p++); - *card_p = '\0'; - - return 0; -} - -static int parse_to_get_device(const char *modarg_device, char *device) { - const char *comma_p; - char *device_p; - - if (!(comma_p = strchr(modarg_device, ','))) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - comma_p++; - device_p = device; - while (*comma_p != '\0') - *(device_p++) = *(comma_p++); - *device_p = '\0'; - - return 0; -} - -pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *driver) { +pa_source *pa_tizenaudio_source2_new(pa_module *m, + pa_modargs *ma, + const char *driver, + pa_card *c, + char **device_string, + pa_sample_spec *sample_spec, + pa_channel_map *channel_map) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; pa_source_new_data data; uint32_t alternate_sample_rate; const char *modarg_device; - char card[DEVICE_NAME_MAX]; - char device[DEVICE_NAME_MAX]; + const char *modarg_device_id; size_t frame_size, buffer_size, period_frames, buffer_frames; + pa_pcm_params_t param; + + uint32_t period_size; + uint32_t periods; pa_assert(m); + pa_assert(ma); + /* TODO: It doesn't need to handle sample_spec, channels_map yet because it comes from UCM */ ss = m->core->default_sample_spec; map = m->core->default_channel_map; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { + + if (channel_map && channel_map->channels != ss.channels) + ss.channels = channel_map->channels; + + pa_channel_map_init_extend(&map, ss.channels, PA_CHANNEL_MAP_ALSA); + + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { pa_log_error("Invalid sample format specification or channel map"); goto fail; } @@ -452,19 +434,13 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); - if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { - pa_log_error("device is invalid"); + modarg_device_id = pa_modargs_get_value(ma, "device_id", NULL); + modarg_device = pa_modargs_get_value(ma, "device", NULL); + if (!modarg_device_id && !modarg_device) { + pa_log_error("Failed to get device id or device string"); goto fail; } - if (parse_to_get_card(modarg_device, card) || parse_to_get_device(modarg_device, device)) { - pa_log_error("failed to parse device module argument, %s", modarg_device); - goto fail; - } - - u->card = pa_xstrdup(card); - u->device = pa_xstrdup(device); - u->frag_size = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGMENT_MSEC * PA_USEC_PER_MSEC, &ss); u->nfrags = DEFAULT_FRAGMENTS; if (pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size) < 0 || @@ -472,11 +448,83 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d pa_log_error("fragment_size or fragments are invalid."); goto fail; } - pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); + + frame_size = pa_frame_size(&ss); + buffer_size = (size_t)(u->frag_size * u->nfrags); + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + + param.direction = DIRECTION_IN; + param.ss = ss; + param.period_size = u->frag_size / pa_frame_size(&ss); + param.periods = u->nfrags; + + pa_log_info("Try to open device with rate(%d), channels(%d), format(%s), period_size(%u), periods(%u)", + ss.rate, ss.channels, pa_sample_format_to_string(ss.format), param.period_size, param.periods); + + if (modarg_device_id && device_string) { + if (pa_tz_util_pcm_open_by_dev_id( + u->hal_interface, + modarg_device_id, + device_string, + ¶m, + (void **)&u->pcm_handle, + &u->card, + &u->device)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + } else if (modarg_device) { + if (pa_tz_util_pcm_open_by_device( + u->hal_interface, + modarg_device, + ¶m, + (void **)&u->pcm_handle, + &u->card, + &u->device)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + } else { + pa_log_error("Device name doesn't exist"); + goto fail; + } + + if (!pa_sample_spec_equal(&ss, ¶m.ss)) { + pa_sample_spec _ss; + char requested_spec[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char selected_spec[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (pa_hal_interface_pcm_get_params(u->hal_interface, u->pcm_handle, 0, (void *)&_ss, &period_size, &periods) < 0) { + pa_log_error("Failed to get pcm params"); + goto fail; + } + + frame_size = pa_frame_size(¶m.ss); + u->frag_size = period_size * frame_size; + /* TODO: can't trust periods value from hal */ + u->nfrags = param.periods; + + buffer_size = (size_t)(u->frag_size * u->nfrags); + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + + pa_log_info("Device doesn't support sample_spec(%s). It was changed to (%s)", + pa_sample_spec_snprint(requested_spec, PA_SAMPLE_SPEC_SNPRINT_MAX, &ss), + pa_sample_spec_snprint(selected_spec, PA_SAMPLE_SPEC_SNPRINT_MAX, ¶m.ss)); + + ss = param.ss; + } + + pa_log_info("Device opened. card(%s), device(%s) rate(%d), channels(%d), format(%s), " + "frag_size(%u), nfrags(%u), period_size(%u), periods(%u)", + u->card, u->device, ss.rate, ss.channels, pa_sample_format_to_string(ss.format), + u->frag_size, u->nfrags, period_size, param.periods); pa_source_new_data_init(&data); data.driver = driver; data.module = m; + data.card = c; pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME)); pa_source_new_data_set_sample_spec(&data, &ss); pa_source_new_data_set_channel_map(&data, &map); @@ -486,14 +534,12 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d pa_proplist_sets(data.proplist, "tizen.device", u->device); pa_proplist_sets(data.proplist, "tizen.version", "2"); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); - - frame_size = pa_frame_size(&ss); - buffer_size = (size_t)(u->frag_size * u->nfrags); - buffer_frames = buffer_size / frame_size; - period_frames = u->frag_size / frame_size; pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); + if (pa_modargs_get_value(ma, "device_id", NULL)) + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_BUS, "usb"); + if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log_error("Invalid properties."); pa_source_new_data_done(&data); @@ -512,17 +558,8 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb; u->source->userdata = u; - if (pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, - DIRECTION_IN, - &u->source->sample_spec, - u->frag_size / pa_frame_size(&u->source->sample_spec), - u->nfrags, - (void **)&u->pcm_handle)) { - pa_log_error("Error opening PCM device"); - goto fail; - } + pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", + u->card, u->device, u->frag_size, u->nfrags); pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); pa_source_set_rtpoll(u->source, u->rtpoll); @@ -540,7 +577,9 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d return u->source; fail: - userdata_free(u); + if (u) + userdata_free(u); + return NULL; } diff --git a/src/tizenaudio-source2.h b/src/tizenaudio-source2.h index a8e67c0..c1cdcae 100644 --- a/src/tizenaudio-source2.h +++ b/src/tizenaudio-source2.h @@ -29,8 +29,16 @@ #include #include #include - -pa_sink *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *driver); +#include +#include + +pa_source *pa_tizenaudio_source2_new(pa_module *m, + pa_modargs *ma, + const char *driver, + pa_card *c, + char **device_string, + pa_sample_spec *sample_spec, + pa_channel_map *channel_map); void pa_tizenaudio_source2_free(pa_source *s); diff --git a/src/tizenaudio-util.c b/src/tizenaudio-util.c new file mode 100644 index 0000000..17be479 --- /dev/null +++ b/src/tizenaudio-util.c @@ -0,0 +1,217 @@ +/*** + This file is part of PulseAudio. + + Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "hal-interface.h" +#include "tizenaudio-util.h" + +#define CARD_NAME_MAX 32 +#define DEVICE_NAME_MAX 32 + +/* + * Extract card string from the device_string that contains device name like 'hw:1,2' + * card variable will have '1' after calling this function. + */ +static int parse_to_get_card(const char *device_string, char *card, int n, const char *def) { + char *name_p; + char *card_p; + char *sep; + int i; + + /* device_string contains various device name such as 'ALSA,0', 'hw:0,0" and "hw:1,1,1" */ + if (!(sep = strchr(device_string, ':'))) { + + /* It doesn't have a prefix like 'hw:', 'hdmi:' */ + if ((sep = strchr(device_string, ','))) { + size_t size = sep - device_string; + + memcpy(card, device_string, size); + card[size] = '\0'; + + return 0; + } + + /* Can't find card number. Use default */ + if (!def) + return -1; + + snprintf(card, n, "%s", def); + } else { + name_p = ++sep; + card_p = card; + + for (i = 0; i < n; i++) { + if (*name_p == ',' || *name_p == '\0') + break; + + *(card_p++) = *(name_p++); + } + + *card_p = '\0'; + } + + return 0; +} + +/* + * Extract card string from the device_string that contains device name like 'hw:1,2' + * card variable will have '2' after calling this function. + */ +static int parse_to_get_device(const char *device_string, char *device, int n, const char *def) { + char *device_p; + char *sep; + + if (!(sep = strchr(device_string, ','))) { + if (!def) + return -1; + + n = snprintf(device, n, "%s", def); + } else { + sep++; + device_p = device; + + while (*sep != '\0') + *(device_p++) = *(sep++); + + *device_p = '\0'; + } + + return 0; +} + +int32_t pa_hal_interface_pcm_open_by_dev_id(pa_hal_interface *h, + const char *dev_id, + char **device_string, + pa_pcm_params_t *param, + pcm_handle *pcm_h, + char **card, + char **device) { + char **i; + char _card[DEVICE_NAME_MAX]; + char _device[DEVICE_NAME_MAX]; + + pa_assert(dev_id); + pa_assert(device_string); + pa_assert(device_string[0]); + + pa_assert(card); + pa_assert(device); + + for (i = device_string; *i; i++) { + char *d; + + pa_log_debug("Try to open device(%s), id(%s)", *i, dev_id); + + if (!(d = pa_replace(*i, "%f", dev_id))) { + pa_log_error("Error parsing i(%s) dev_id(%s)", *i, dev_id); + continue; + } + + if (parse_to_get_device(d, _device, DEVICE_NAME_MAX, "0") < 0) { + pa_log_error("Failed to parse device_string. It doesn't contain device"); + pa_xfree(d); + continue; + } + + if (parse_to_get_card(d, _card, CARD_NAME_MAX, "0") < 0) { + pa_log_error("Failed to parse card"); + pa_xfree(d); + continue; + } + + if (pa_hal_interface_pcm_open(h, + _card, + _device, + param->direction, + ¶m->ss, + param->period_size, + param->periods, + (void **)pcm_h)) { + pa_log_error("Failed to open PCM device (%s)", d); + pa_xfree(d); + continue; + } + + *card = pa_xstrdup(_card); + *device = pa_xstrdup(_device); + + pa_log_debug("card(%s) device(%s) opened successfully", *card, *device); + + pa_xfree(d); + + return 0; + } + + pa_log_error("Error opening PCM device"); + + return -1; +} + +int32_t pa_hal_interface_pcm_open_by_device(pa_hal_interface *h, + const char* dev, + pa_pcm_params_t *param, + pcm_handle *pcm_h, + char **card, + char **device) { + char _card[DEVICE_NAME_MAX]; + char _device[DEVICE_NAME_MAX]; + + pa_assert(dev); + + pa_log_debug("Try to open device(%s)", dev); + + if (parse_to_get_device(dev, _device, DEVICE_NAME_MAX, NULL) < 0) { + pa_log_error("Failed to parse device. dev(%s)", dev); + return -1; + } + + if (parse_to_get_card(dev, _card, CARD_NAME_MAX, NULL) < 0) { + pa_log_error("Failed to parse card. dev(%s)", dev); + return -1; + } + + if (pa_hal_interface_pcm_open(h, + _card, + _device, + param->direction, + ¶m->ss, + param->period_size, + param->periods, + (void **)pcm_h)) { + pa_log_error("Failed to open PCM device (%s) card(%s), device(%s)", dev, _card, _device); + return -1; + } + + *card = pa_xstrdup(_card); + *device = pa_xstrdup(_device); + + pa_log_debug("card(%s) device(%s) opened successfully", *card, *device); + + return 0; +} diff --git a/src/tizenaudio-util.h b/src/tizenaudio-util.h new file mode 100644 index 0000000..ea74fb9 --- /dev/null +++ b/src/tizenaudio-util.h @@ -0,0 +1,54 @@ +#ifndef footizenaudioutilhfoo +#define footizenaudioutilhfoo + +/*** + This file is part of PulseAudio. + + Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +typedef struct pa_pcm_params { + io_direction_t direction; + pa_sample_spec ss; + uint32_t period_size; + uint32_t periods; +} pa_pcm_params_t; + + +int32_t pa_tz_util_pcm_open_by_dev_id(pa_hal_interface *h, + const char *dev_id, + char **device_string, + pa_pcm_params_t *param, + pcm_handle *pcm_h, + char **card, + char **device); + +int32_t pa_tz_util_pcm_open_by_device(pa_hal_interface *h, + const char* dev, + pa_pcm_params_t *param, + pcm_handle *pcm_h, + char **card, + char **device); +#endif + -- 2.7.4 From 524ffee0ef91c855368f0be0a70d335114d37c7c Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Thu, 2 Jun 2022 11:20:43 +0900 Subject: [PATCH 10/16] Improve latency difference between reference and capture source * Not allow negative latency * Added mchstreamer specific code * Fixed build warning on aarch64 [Version] 15.0.21 [Issue Type] Improvement Change-Id: Idd6c4337ec6567e52dd86bbca5c194a897804b43 Signed-off-by: Jaechul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/echo-cancel/algo_reference_copy.c | 11 ++++++++++- src/echo-cancel/module-tizenaudio-echo-cancel.c | 2 +- src/echo-cancel/processor.c | 16 ++++++++++++++-- src/tizenaudio-sink2.c | 13 ++++++++++--- src/tizenaudio-source2.c | 9 +++++++-- 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index cd1cfef..1b6d631 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.20 +Version: 15.0.21 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/echo-cancel/algo_reference_copy.c b/src/echo-cancel/algo_reference_copy.c index 2d9cf0b..7b397ec 100644 --- a/src/echo-cancel/algo_reference_copy.c +++ b/src/echo-cancel/algo_reference_copy.c @@ -94,13 +94,22 @@ int32_t reference_copy_change_reference_spec(void *priv, pa_sample_spec *source_ pa_assert(map); channels = rc->ss.channels - source_ss->channels; - if (channels <= 0) + if (channels <= 0) { + pa_log_error("No empty channels. reference copy will be disabled"); return -1; + } + + /* TODO: temporary code for supporting mchstreamer. reference copy uses the last 2ch of its channels */ + if (rc->ss.channels == 16) + channels = 2; *sample_spec = rc->ss; sample_spec->channels = rc->reference_channels = channels; pa_channel_map_init_auto(map, channels, PA_CHANNEL_MAP_AIFF); + pa_log_info("reference will be copied to empty channels(%d). source-output ch(%d), source ch(%d)", + channels, rc->ss.channels, source_ss->channels); + return 0; } diff --git a/src/echo-cancel/module-tizenaudio-echo-cancel.c b/src/echo-cancel/module-tizenaudio-echo-cancel.c index f9e13c0..7697368 100644 --- a/src/echo-cancel/module-tizenaudio-echo-cancel.c +++ b/src/echo-cancel/module-tizenaudio-echo-cancel.c @@ -298,7 +298,7 @@ static int process_msg( /* trigger resolves a race condition related to post_process between source and render thread */ if (u->triggered) { - if (code == PA_ECHO_CANCEL_MESSAGE_PUSH_DATA || code == PA_ECHO_CANCEL_MESSAGE_PUSH_ECHO) { + if (code == PA_ECHO_CANCEL_MESSAGE_PUSH_ECHO) { pa_source_output *o = NULL; pa_usec_t latency; diff --git a/src/echo-cancel/processor.c b/src/echo-cancel/processor.c index 0052ab8..dbce5fa 100644 --- a/src/echo-cancel/processor.c +++ b/src/echo-cancel/processor.c @@ -43,6 +43,7 @@ #endif #define MEMBLOCKQ_MAXLENGTH (16 * 1024 * 1024) +#define MEMBLOCKQ_PUSH_REFERENCE_BLOCK_ALIGN typedef struct pa_processor_method_interface pa_processor_method_interface; struct pa_processor { @@ -298,14 +299,24 @@ int pa_processor_setup_reference_memblockq_padding(pa_processor *processor, pa_u pa_assert(processor); bytes = pa_usec_to_bytes(latency, &processor->reference_memblockq_ss); - n = (bytes + (processor->reference_process_bytes - 1)) / processor->reference_process_bytes; +#ifdef MEMBLOCKQ_PUSH_REFERENCE_BLOCK_ALIGN + n = (bytes + (processor->reference_process_bytes - 1)) / processor->reference_process_bytes; pa_silence_memchunk_get( &processor->core->silence_cache, processor->core->mempool, &silence, &processor->reference_memblockq_ss, processor->reference_process_bytes); +#else + n = 1; + pa_silence_memchunk_get( + &processor->core->silence_cache, + processor->core->mempool, + &silence, + &processor->reference_memblockq_ss, + bytes); +#endif write_index = pa_memblockq_get_write_index(processor->reference_memblockq); read_index = pa_memblockq_get_read_index(processor->reference_memblockq); @@ -315,9 +326,10 @@ int pa_processor_setup_reference_memblockq_padding(pa_processor *processor, pa_u pa_memblock_unref(silence.memblock); - pa_log_info("push n(%u) silence blocks. ref_process_bytes(%zu) " + pa_log_info("push n(%u) silence blocks. latency(%" PRId64 "), ref_process_bytes(%zu) " "write_index(%" PRId64 "->%" PRId64 "), read_index(%" PRId64 "->%" PRId64 ")", pa_memblockq_get_nblocks(processor->reference_memblockq), + latency, processor->reference_process_bytes, write_index, pa_memblockq_get_write_index(processor->reference_memblockq), read_index, pa_memblockq_get_read_index(processor->reference_memblockq)); diff --git a/src/tizenaudio-sink2.c b/src/tizenaudio-sink2.c index ff0dbc7..f8601ac 100644 --- a/src/tizenaudio-sink2.c +++ b/src/tizenaudio-sink2.c @@ -169,7 +169,6 @@ static int unsuspend(struct userdata *u) { u->write_count = 0; u->first = true; - u->timestamp = pa_rtclock_now(); pa_log_info("Resumed successfully..."); @@ -245,8 +244,13 @@ static int sink_process_msg( case PA_SINK_MESSAGE_GET_LATENCY: { int64_t r = 0; - if (u->pcm_handle) - r = u->timestamp + pa_bytes_to_usec(u->write_count, &u->sink->sample_spec) - pa_rtclock_now(); + if (u->pcm_handle) { + pa_usec_t now = pa_rtclock_now(); + pa_usec_t write_latency = u->timestamp + pa_bytes_to_usec(u->write_count, &u->sink->sample_spec); + + if (now < write_latency) + r = write_latency - now; + } *((int64_t *) data) = r; @@ -297,6 +301,9 @@ static int process_render(struct userdata *u) { pa_sink_render_full(u->sink, u->frag_size, &chunk); p = pa_memblock_acquire(chunk.memblock); + if (u->first) + u->timestamp = pa_rtclock_now(); + if (pa_hal_interface_pcm_write(u->hal_interface, u->pcm_handle, (const char*)p + chunk.index, (uint32_t)frames_to_write)) { pa_log_error("failed to write pcm. p(%p), size(%zu)", p, frames_to_write); return -1; diff --git a/src/tizenaudio-source2.c b/src/tizenaudio-source2.c index 846b086..948e8f0 100644 --- a/src/tizenaudio-source2.c +++ b/src/tizenaudio-source2.c @@ -248,8 +248,13 @@ static int source_process_msg( case PA_SOURCE_MESSAGE_GET_LATENCY: { uint64_t r = 0; - if (u->pcm_handle) - r = pa_rtclock_now() - (u->timestamp + pa_bytes_to_usec(u->read_count, &u->source->sample_spec)); + if (u->pcm_handle) { + pa_usec_t now = pa_rtclock_now(); + pa_usec_t read_latency = u->timestamp + pa_bytes_to_usec(u->read_count, &u->source->sample_spec); + + if (now > read_latency) + r = now - read_latency; + } *((int64_t *) data) = r; -- 2.7.4 From 6947e28faa9126474a03a5d7924e75bfa288a96f Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Tue, 28 Jun 2022 16:42:58 +0900 Subject: [PATCH 11/16] tizenaudio-util: Fix loading errors This patch fixes undefined symbol: pa_tz_util_pcm_open_by_* [Version] 15.0.22 [Issue Type] Runtime error Change-Id: I7c172938d4480348445458a56e1ba9a8ddf14de2 Signed-off-by: Jaechul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/tizenaudio-util.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 1b6d631..2eae259 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.21 +Version: 15.0.22 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/tizenaudio-util.c b/src/tizenaudio-util.c index 17be479..c4fbc49 100644 --- a/src/tizenaudio-util.c +++ b/src/tizenaudio-util.c @@ -105,7 +105,7 @@ static int parse_to_get_device(const char *device_string, char *device, int n, c return 0; } -int32_t pa_hal_interface_pcm_open_by_dev_id(pa_hal_interface *h, +int32_t pa_tz_util_pcm_open_by_dev_id(pa_hal_interface *h, const char *dev_id, char **device_string, pa_pcm_params_t *param, @@ -173,7 +173,7 @@ int32_t pa_hal_interface_pcm_open_by_dev_id(pa_hal_interface *h, return -1; } -int32_t pa_hal_interface_pcm_open_by_device(pa_hal_interface *h, +int32_t pa_tz_util_pcm_open_by_device(pa_hal_interface *h, const char* dev, pa_pcm_params_t *param, pcm_handle *pcm_h, -- 2.7.4 From ae4ac2a78f77f549956f504f2bc13f003ba2bc4f Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Thu, 30 Jun 2022 13:10:12 +0900 Subject: [PATCH 12/16] echo-cancel: Replace 'algo' prefix with 'method' [Version] 15.0.23 [Issue Type] Rename Change-Id: I8eee586036ef0f107f94413285b22a5736284318 Signed-off-by: Jaechul Lee --- Makefile.am | 8 ++++---- src/echo-cancel/{algo_adrian.c => method_adrian.c} | 10 +++++----- .../{algo_reference_copy.c => method_reference_copy.c} | 0 src/echo-cancel/{algo_speex.c => method_speex.c} | 10 +++++----- src/echo-cancel/{algo_webrtc.cpp => method_webrtc.cpp} | 18 +++++++++--------- 5 files changed, 23 insertions(+), 23 deletions(-) rename src/echo-cancel/{algo_adrian.c => method_adrian.c} (91%) rename src/echo-cancel/{algo_reference_copy.c => method_reference_copy.c} (100%) rename src/echo-cancel/{algo_speex.c => method_speex.c} (95%) rename src/echo-cancel/{algo_webrtc.cpp => method_webrtc.cpp} (93%) diff --git a/Makefile.am b/Makefile.am index b3d0913..cd71bb1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -98,9 +98,9 @@ module_tizenaudio_source2_la_LIBADD = $(MODULE_LIBADD) libtizenaudio-util.la module_tizenaudio_source2_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_source2 libprocessor_la_SOURCES = \ - src/echo-cancel/algo_speex.c \ - src/echo-cancel/algo_reference_copy.c \ - src/echo-cancel/algo_adrian.c \ + src/echo-cancel/method_speex.c \ + src/echo-cancel/method_reference_copy.c \ + src/echo-cancel/method_adrian.c \ src/echo-cancel/adrian-aec.c \ src/echo-cancel/processor.c \ src/echo-cancel/processor.h \ @@ -110,7 +110,7 @@ libprocessor_la_LIBADD = $(AM_LIBADD) $(LIBSPEEX_LIBS) libprocessor_la_CFLAGS = $(AM_CFLAGS) $(PA_CFLAGS) $(LIBSPEEX_CFLAGS) if ENABLE_WEBRTC -libprocessor_la_SOURCES += src/echo-cancel/algo_webrtc.cpp +libprocessor_la_SOURCES += src/echo-cancel/method_webrtc.cpp libprocessor_la_LIBADD += $(WEBRTC_LIBS) libprocessor_la_CPPFLAGS = $(WEBRTC_CFLAGS) $(PA_CFLAGS) -DSUPPORT_METHOD_WEBRTC -std=c++17 endif diff --git a/src/echo-cancel/algo_adrian.c b/src/echo-cancel/method_adrian.c similarity index 91% rename from src/echo-cancel/algo_adrian.c rename to src/echo-cancel/method_adrian.c index a5d2e72..d673dcd 100644 --- a/src/echo-cancel/algo_adrian.c +++ b/src/echo-cancel/method_adrian.c @@ -32,13 +32,13 @@ #include "adrian-aec.h" -struct ec_adrian { +struct method_adrian { int blocksize; AEC *aec; }; void *adrian_create(size_t nframes, pa_sample_spec *ss) { - struct ec_adrian *adrian = NULL; + struct method_adrian *adrian = NULL; pa_assert(ss); @@ -47,7 +47,7 @@ void *adrian_create(size_t nframes, pa_sample_spec *ss) { return NULL; } - adrian = pa_xnew0(struct ec_adrian, 1); + adrian = pa_xnew0(struct method_adrian, 1); if (!(adrian->aec = AEC_init(ss->rate, 0))) { pa_log_error("Failed to init AEC"); @@ -64,7 +64,7 @@ fail: } int32_t adrian_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) { - struct ec_adrian *adrian = priv; + struct method_adrian *adrian = priv; int i; assert(rec); @@ -81,7 +81,7 @@ int32_t adrian_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) { } int32_t adrian_destroy(void *priv) { - struct ec_adrian *adrian = priv; + struct method_adrian *adrian = priv; pa_assert(adrian); diff --git a/src/echo-cancel/algo_reference_copy.c b/src/echo-cancel/method_reference_copy.c similarity index 100% rename from src/echo-cancel/algo_reference_copy.c rename to src/echo-cancel/method_reference_copy.c diff --git a/src/echo-cancel/algo_speex.c b/src/echo-cancel/method_speex.c similarity index 95% rename from src/echo-cancel/algo_speex.c rename to src/echo-cancel/method_speex.c index 161812a..5dd0b5f 100644 --- a/src/echo-cancel/algo_speex.c +++ b/src/echo-cancel/method_speex.c @@ -35,13 +35,13 @@ #include -struct algo_speex { +struct method_speex { SpeexEchoState *echo_state; SpeexPreprocessState *preprocess; }; void *speex_create(size_t nframes, pa_sample_spec *ss) { - struct algo_speex *speex = NULL; + struct method_speex *speex = NULL; spx_int32_t value = 1; int rate; @@ -52,7 +52,7 @@ void *speex_create(size_t nframes, pa_sample_spec *ss) { return NULL; } - speex = pa_xnew0(struct algo_speex, 1); + speex = pa_xnew0(struct method_speex, 1); /* TODO: need to check. weird behavior */ if (ss->channels == 2) @@ -108,7 +108,7 @@ fail: } int32_t speex_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) { - struct algo_speex *speex = priv; + struct method_speex *speex = priv; assert(rec); assert(ref); @@ -125,7 +125,7 @@ int32_t speex_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) { } int32_t speex_destroy(void *priv) { - struct algo_speex *speex = priv; + struct method_speex *speex = priv; if (speex->echo_state) speex_echo_state_destroy(speex->echo_state); diff --git a/src/echo-cancel/algo_webrtc.cpp b/src/echo-cancel/method_webrtc.cpp similarity index 93% rename from src/echo-cancel/algo_webrtc.cpp rename to src/echo-cancel/method_webrtc.cpp index 8253820..4b7721c 100644 --- a/src/echo-cancel/algo_webrtc.cpp +++ b/src/echo-cancel/method_webrtc.cpp @@ -41,8 +41,8 @@ PA_C_DECL_BEGIN #include #include -static void allocate_stream_buffer(struct algo_webrtc *webrtc, size_t nframes); -static void deallocate_stream_buffer(struct algo_webrtc *webrtc); +static void allocate_stream_buffer(struct method_webrtc *webrtc, size_t nframes); +static void deallocate_stream_buffer(struct method_webrtc *webrtc); static void convert_s16_to_float(float *dst, int16_t *src, size_t n); static void convert_float_to_s16(int16_t *dst, float *src, size_t n); @@ -51,7 +51,7 @@ int32_t webrtc_audio_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out); int32_t webrtc_audio_destroy(void *priv); PA_C_DECL_END -struct algo_webrtc { +struct method_webrtc { AudioProcessing *ap; Config config; StreamConfig *sconfig; @@ -75,7 +75,7 @@ struct algo_webrtc { }; void *webrtc_audio_create(size_t nframes, pa_sample_spec *ss) { - struct algo_webrtc *webrtc = NULL; + struct method_webrtc *webrtc = NULL; size_t fixed_bytes, request_bytes; Config config; @@ -101,7 +101,7 @@ void *webrtc_audio_create(size_t nframes, pa_sample_spec *ss) { return NULL; } - webrtc = pa_xnew0(struct algo_webrtc, 1); + webrtc = pa_xnew0(struct method_webrtc, 1); webrtc->ss = *ss; webrtc->fixed_bytes = fixed_bytes; webrtc->fixed_frames = fixed_bytes / pa_frame_size(ss); @@ -164,7 +164,7 @@ fail: } int32_t webrtc_audio_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) { - struct algo_webrtc *webrtc = (struct algo_webrtc *)priv; + struct method_webrtc *webrtc = (struct method_webrtc *)priv; pa_sample_spec ss; size_t frames; @@ -225,7 +225,7 @@ int32_t webrtc_audio_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) } int32_t webrtc_audio_destroy(void *priv) { - struct algo_webrtc *webrtc = (struct algo_webrtc *)priv; + struct method_webrtc *webrtc = (struct method_webrtc *)priv; pa_assert(webrtc); @@ -238,7 +238,7 @@ int32_t webrtc_audio_destroy(void *priv) { return 0; } -static void deallocate_stream_buffer(struct algo_webrtc *webrtc) { +static void deallocate_stream_buffer(struct method_webrtc *webrtc) { pa_assert(webrtc); for (int i = 0; i < webrtc->ss.channels; i++) { @@ -252,7 +252,7 @@ static void deallocate_stream_buffer(struct algo_webrtc *webrtc) { pa_xfree(webrtc->out_fbuf); } -static void allocate_stream_buffer(struct algo_webrtc *webrtc, size_t nframes) { +static void allocate_stream_buffer(struct method_webrtc *webrtc, size_t nframes) { int channels; pa_assert(webrtc); -- 2.7.4 From 296538390258ece146df572170404b1c35a1095c Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Mon, 4 Jul 2022 11:30:59 +0900 Subject: [PATCH 13/16] echo-cancel: Fix coverity issues (PARAMETER_HIDDEN) [Version] 15.0.24 [Issue Type] Coverity Change-Id: Ia5f389a408b7bb97ab379215939d9b910aebb8ee Signed-off-by: Jaechul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/echo-cancel/module-tizenaudio-echo-cancel.c | 26 ++++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 2eae259..ad23656 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.22 +Version: 15.0.24 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/echo-cancel/module-tizenaudio-echo-cancel.c b/src/echo-cancel/module-tizenaudio-echo-cancel.c index 7697368..4b6939b 100644 --- a/src/echo-cancel/module-tizenaudio-echo-cancel.c +++ b/src/echo-cancel/module-tizenaudio-echo-cancel.c @@ -295,29 +295,29 @@ static int process_msg( pa_memchunk *chunk) { struct userdata *u = PA_ECHO_CANCEL(o)->u; + pa_source_output *so = NULL; /* trigger resolves a race condition related to post_process between source and render thread */ if (u->triggered) { if (code == PA_ECHO_CANCEL_MESSAGE_PUSH_ECHO) { - pa_source_output *o = NULL; pa_usec_t latency; - o = find_source_output_by_flags(u->source); - if (!o) { + so = find_source_output_by_flags(u->source); + if (!so) { u->triggered = false; return 0; } - o->post_process = post_process; + so->post_process = post_process; latency = get_round_trip_latency(u); - if (pa_processor_setup_reference_memblockq_padding(o->thread_info.processor, latency) < 0) + if (pa_processor_setup_reference_memblockq_padding(so->thread_info.processor, latency) < 0) pa_log_warn("Failed to setup reference memblockq padding"); u->triggered = false; - pa_log_info("Triggered Echo-Cancellation. index(%d), latency(%" PRIu64 ") usec", o->index, latency); + pa_log_info("Triggered Echo-Cancellation. index(%d), latency(%" PRIu64 ") usec", so->index, latency); } } @@ -330,15 +330,13 @@ static int process_msg( break; case PA_ECHO_CANCEL_MESSAGE_PUSH_ECHO: if (u->enable_in_thread) { - pa_source_output *o = NULL; - pa_assert(u->source); - o = find_source_output_by_flags(u->source); - if (!o) + so = find_source_output_by_flags(u->source); + if (!so) break; - if (pa_processor_push_reference(o->thread_info.processor, chunk) < 0) + if (pa_processor_push_reference(so->thread_info.processor, chunk) < 0) pa_log_error("Failed to push reference data"); } @@ -346,15 +344,15 @@ static int process_msg( case PA_ECHO_CANCEL_MESSAGE_SET_AEC_STATE: { void **v = (void **)data; bool enable = (bool)v[0]; - pa_source_output *o = (pa_source_output *)v[1]; + so = (pa_source_output *)v[1]; u->enable_in_thread = enable; if (enable) { u->triggered = true; } else { - pa_processor_flush(o->thread_info.processor); - o->post_process = NULL; + pa_processor_flush(so->thread_info.processor); + so->post_process = NULL; } break; -- 2.7.4 From 64c9859c2af892966f741a6ff24e39bd261fda68 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Mon, 27 Jun 2022 17:41:30 +0900 Subject: [PATCH 14/16] Enable webrtc-audio-processing by default [Version] 15.0.25 [Issue Type] Improvement Change-Id: Icb43727592ce90077ed6badf8481680dccc57ef1 Signed-off-by: Jaechul Lee --- Makefile.am | 3 ++ packaging/pulseaudio-modules-tizen.spec | 8 ++++- src/echo-cancel/module-tizenaudio-echo-cancel.c | 29 +++++++++++------- src/echo-cancel/processor.c | 39 ++++++++++++------------- src/echo-cancel/processor.h | 7 ++++- 5 files changed, 53 insertions(+), 33 deletions(-) diff --git a/Makefile.am b/Makefile.am index cd71bb1..3723d0a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,6 +119,9 @@ module_tizenaudio_echo_cancel_la_SOURCES = src/echo-cancel/module-tizenaudio-ech module_tizenaudio_echo_cancel_la_LDFLAGS = $(MODULE_LDFLAGS) module_tizenaudio_echo_cancel_la_LIBADD = $(MODULE_LIBADD) libprocessor.la module_tizenaudio_echo_cancel_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_echo_cancel +if ENABLE_WEBRTC +module_tizenaudio_echo_cancel_la_CFLAGS += -DSUPPORT_METHOD_WEBRTC +endif module_sound_player_la_SOURCES = src/module-sound-player.c module_sound_player_la_LDFLAGS = $(MODULE_LDFLAGS) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index ad23656..48a97c9 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.24 +Version: 15.0.25 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ @@ -24,6 +24,9 @@ BuildRequires: pkgconfig(libsystemd) BuildRequires: pkgconfig(dns_sd) BuildRequires: pkgconfig(hal-api-audio) BuildRequires: pkgconfig(speexdsp) +%if "%{tizen_profile_name}" != "tv" +BuildRequires: pkgconfig(webrtc-audio-processing) +%endif BuildRequires: pulseaudio BuildRequires: m4 Requires(post): /sbin/ldconfig @@ -52,6 +55,9 @@ export LD_AS_NEEDED=0 %reconfigure --prefix=%{_prefix} \ --disable-static \ --enable-acm \ +%if "%{tizen_profile_name}" != "tv" + --enable-webrtc \ +%endif %if "%{tizen_profile_name}" == "tv" --enable-vconf-helper %endif diff --git a/src/echo-cancel/module-tizenaudio-echo-cancel.c b/src/echo-cancel/module-tizenaudio-echo-cancel.c index 4b6939b..3442009 100644 --- a/src/echo-cancel/module-tizenaudio-echo-cancel.c +++ b/src/echo-cancel/module-tizenaudio-echo-cancel.c @@ -46,7 +46,7 @@ PA_MODULE_DESCRIPTION("Tizen Audio Echo Cancel"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(true); PA_MODULE_USAGE( - "method= "); + "method= "); #define DEFAULT_PROCESS_MSEC 10 @@ -69,7 +69,7 @@ struct userdata { bool enable; uint32_t n_source_output; - char *default_method; + char *force_method; pa_thread *thread; pa_thread_mq thread_mq; @@ -93,7 +93,6 @@ PA_DEFINE_PRIVATE_CLASS(pa_echo_cancel, pa_msgobject); #define PA_ECHO_CANCEL(o) (pa_echo_cancel_cast(o)) #define MEMBLOCKQ_MAXLENGTH (16 * 1024 * 1024) -#define DEFAULT_AEC_METHOD "speex" static const char* const valid_modargs[] = { "method", @@ -119,7 +118,7 @@ static int proplist_get_fragment_size_usec(pa_proplist *p, pa_sample_spec *sampl return 0; } -static int proplist_get_method(pa_proplist *p, const char *default_method, pa_processor_method_t *method) { +static int proplist_get_method(pa_proplist *p, pa_processor_method_t *method) { const char *m; pa_assert(p); @@ -128,7 +127,7 @@ static int proplist_get_method(pa_proplist *p, const char *default_method, pa_pr if (!(m = pa_proplist_gets(p, PA_PROP_MEDIA_ECHO_CANCEL_METHOD))) return -1; - *method = pa_processor_get_method(m, default_method); + *method = pa_processor_get_method(m); return 0; } @@ -367,14 +366,17 @@ static int process_msg( static pa_hook_result_t source_output_new_cb(pa_core *c, pa_source_output_new_data *data, void *userdata) { struct userdata *u = (struct userdata *)userdata; pa_processor_method_t method; + const char *m; pa_assert(c); pa_assert(u); pa_assert(data); - if (proplist_get_method(data->proplist, u->default_method, &method) < 0) + if (!(m = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_ECHO_CANCEL_METHOD))) return PA_HOOK_OK; + method = pa_processor_get_method(m); + /* TODO: source-output can be moved */ data->flags |= PA_SOURCE_OUTPUT_DONT_MOVE; data->flags |= PA_SOURCE_OUTPUT_ECHO_CANCEL; @@ -432,9 +434,13 @@ static pa_hook_result_t source_output_put_cb(pa_core *c, pa_source_output *o, vo goto fail; } - if (proplist_get_method(o->proplist, u->default_method, &method) < 0) { - pa_log_error("Failed to get method"); - goto fail; + if (u->force_method) { + method = pa_processor_get_method(u->force_method); + } else { + if (proplist_get_method(o->proplist, &method) < 0) { + pa_log_error("Failed to get method"); + goto fail; + } } u->source = o->source; @@ -624,7 +630,7 @@ int pa__init(pa_module *m) { m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->m = m; - u->default_method = pa_xstrdup(pa_modargs_get_value(ma, "method", DEFAULT_AEC_METHOD)); + u->force_method = pa_xstrdup(pa_modargs_get_value(ma, "method", NULL)); u->echo_cancel = pa_msgobject_new(pa_echo_cancel); u->echo_cancel->parent.process_msg = process_msg; @@ -741,7 +747,8 @@ void pa__done(pa_module *m) { pa_thread_mq_done(&u->thread_mq); - pa_xfree(u->default_method); + pa_xfree(u->force_method); + pa_xfree(u); } diff --git a/src/echo-cancel/processor.c b/src/echo-cancel/processor.c index dbce5fa..c77f088 100644 --- a/src/echo-cancel/processor.c +++ b/src/echo-cancel/processor.c @@ -471,33 +471,32 @@ int pa_processor_free(pa_processor *processor) { return 0; } -pa_processor_method_t pa_processor_get_method(const char *request_method, const char *default_method) { - const char *selected; +const char *pa_processor_method_to_string(pa_processor_method_t method) { + if (method >= PA_PROCESSOR_METHOD_MAX) + return NULL; - if (!request_method || !default_method) - return PA_PROCESSOR_SPEEX; + return method_table[method].name; +} - selected = pa_streq(request_method, "default") ? default_method : request_method; +pa_processor_method_t pa_processor_get_method(const char *request_method) { + pa_processor_method_t method; - if (pa_streq(selected, "speex")) - return PA_PROCESSOR_SPEEX; - else if (pa_streq(selected, "adrian")) - return PA_PROCESSOR_ADRIAN; + if (pa_streq(request_method, "speex")) + method = PA_PROCESSOR_SPEEX; + else if (pa_streq(request_method, "adrian")) + method = PA_PROCESSOR_ADRIAN; #ifdef SUPPORT_METHOD_WEBRTC - else if (pa_streq(selected, "webrtc")) - return PA_PROCESSOR_WEBRTC; + else if (pa_streq(request_method, "webrtc")) + method = PA_PROCESSOR_WEBRTC; #endif - else if (pa_streq(selected, "reference_copy")) - return PA_PROCESSOR_REFERENCE_COPY; + else if (pa_streq(request_method, "reference_copy")) + method = PA_PROCESSOR_REFERENCE_COPY; else - return PA_PROCESSOR_SPEEX; -} - -const char *pa_processor_method_to_string(pa_processor_method_t method) { - if (method >= PA_PROCESSOR_METHOD_MAX) - return NULL; + /* request_method could be had 'default' */ + method = PA_PROCESSOR_METHOD_DEFAULT; - return method_table[method].name; + pa_log_info("processing method is selected. request_method(%s), method_to_string(%s)", + request_method, pa_processor_method_to_string(method)); } #ifdef __DEBUG__ diff --git a/src/echo-cancel/processor.h b/src/echo-cancel/processor.h index ea07143..ea14a69 100644 --- a/src/echo-cancel/processor.h +++ b/src/echo-cancel/processor.h @@ -38,6 +38,11 @@ typedef enum { PA_PROCESSOR_WEBRTC, #endif PA_PROCESSOR_REFERENCE_COPY, +#ifdef SUPPORT_METHOD_WEBRTC + PA_PROCESSOR_METHOD_DEFAULT = PA_PROCESSOR_WEBRTC, +#else + PA_PROCESSOR_METHOD_DEFAULT = PA_PROCESSOR_SPEEX, +#endif PA_PROCESSOR_METHOD_MAX, } pa_processor_method_t; @@ -58,7 +63,7 @@ int pa_processor_process(pa_processor *processor, pa_memchunk *rec, pa_memchunk int pa_processor_push_reference(pa_processor *processor, pa_memchunk *chunk); void pa_processor_flush(pa_processor *processor); int pa_processor_free(pa_processor *processor); -pa_processor_method_t pa_processor_get_method(const char *requset_method, const char *default_method); +pa_processor_method_t pa_processor_get_method(const char *requset_method); const char *pa_processor_method_to_string(pa_processor_method_t method); #endif -- 2.7.4 From 9f6d318c9732681b3c98d03fb523872dc4928c73 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Mon, 18 Jul 2022 13:46:15 +0900 Subject: [PATCH 15/16] fixup! Enable webrtc-audio-processing by default [Version] 15.0.26 [Issue Type] Bug Change-Id: I683f8ca264196f01107f4713129e21ab233650ca --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/echo-cancel/processor.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 48a97c9..71b55b2 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.25 +Version: 15.0.26 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/echo-cancel/processor.c b/src/echo-cancel/processor.c index c77f088..8dc6c2d 100644 --- a/src/echo-cancel/processor.c +++ b/src/echo-cancel/processor.c @@ -497,6 +497,8 @@ pa_processor_method_t pa_processor_get_method(const char *request_method) { pa_log_info("processing method is selected. request_method(%s), method_to_string(%s)", request_method, pa_processor_method_to_string(method)); + + return method; } #ifdef __DEBUG__ -- 2.7.4 From 83cceff1a8e745080a28d0b5de31ac436e45086b Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Mon, 8 Aug 2022 17:27:01 +0900 Subject: [PATCH 16/16] fixup! fixup! Enable webrtc-audio-processing by default Fix the following crash error due to invalid enumeration value. processor.c: pa_processor_get_method(498) > processing method is selected. request_method(reference_copy), method_to_string((null)) processor.c: pa_processor_new(169) > Assertion 'method < PA_PROCESSOR_METHOD_MAX' failed at src/echo-cancel/processor.c:169, function pa_processor_new(). Aborting. [Version] 15.0.27 [Issue Type] Bug Change-Id: I331fbea04be4a2d0471b916082f3da298c31a851 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/echo-cancel/processor.h | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 71b55b2..48aacf5 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.26 +Version: 15.0.27 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/echo-cancel/processor.h b/src/echo-cancel/processor.h index ea14a69..625bb25 100644 --- a/src/echo-cancel/processor.h +++ b/src/echo-cancel/processor.h @@ -32,13 +32,11 @@ #include typedef enum { - PA_PROCESSOR_SPEEX, PA_PROCESSOR_ADRIAN, -#ifdef SUPPORT_METHOD_WEBRTC - PA_PROCESSOR_WEBRTC, -#endif PA_PROCESSOR_REFERENCE_COPY, + PA_PROCESSOR_SPEEX, #ifdef SUPPORT_METHOD_WEBRTC + PA_PROCESSOR_WEBRTC, PA_PROCESSOR_METHOD_DEFAULT = PA_PROCESSOR_WEBRTC, #else PA_PROCESSOR_METHOD_DEFAULT = PA_PROCESSOR_SPEEX, -- 2.7.4