From cafa82a93f92ffd6e9505db143a03ea781822ccb Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Wed, 4 Aug 2021 10:01:56 +0900 Subject: [PATCH] tizenaudio-sink2: Use hardware interrupt for playback * Remove unused arguments (block_msec, max_request_msec) * Use fixed latency * Use poll event [Version] 13.0.69 [Issue Type] Improvement Change-Id: I404474e0da9837df6fc202cc793af0b5d2c6d799 Signed-off-by: Jaechul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-sink2.c | 171 +++++++++----------------------- 2 files changed, 46 insertions(+), 127 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 3986972..6f220f2 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.68 +Version: 13.0.69 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-sink2.c b/src/module-tizenaudio-sink2.c index f8a6059..e4e61e9 100644 --- a/src/module-tizenaudio-sink2.c +++ b/src/module-tizenaudio-sink2.c @@ -48,7 +48,7 @@ #include "hal-interface.h" PA_MODULE_AUTHOR("Tizen"); -PA_MODULE_DESCRIPTION("Tizen Audio Sink"); +PA_MODULE_DESCRIPTION("Tizen Audio Sink2"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(false); PA_MODULE_USAGE( @@ -60,17 +60,9 @@ PA_MODULE_USAGE( "channels= " "channel_map=" "fragments= " - "fragment_size= " - "block_msec= " - "max_request_msec= "); + "fragment_size= "); -#define DEFAULT_SINK_NAME "tizenaudio-sink" - -/* block_usec should be less than amount of fragment_size * fragments */ -#define DEFAULT_BLOCK_USEC (PA_USEC_PER_SEC * 0.05) - -/* Sink device consumes that amount of maximum buffer at every request */ -#define DEFAULT_MAX_REQUEST_USEC (PA_USEC_PER_SEC * 0.032) +#define DEFAULT_SINK_NAME "tizenaudio-sink2" #define DEVICE_NAME_MAX 30 @@ -82,16 +74,12 @@ struct userdata { 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; - pa_usec_t block_usec; - pa_usec_t max_request_usec; - pa_usec_t timestamp; - pa_usec_t timestamp_written; - char* card; char* device; bool first; @@ -112,8 +100,6 @@ static const char* const valid_modargs[] = { "channel_map", "fragments", "fragment_size", - "block_msec", - "max_request_msec", NULL }; @@ -137,7 +123,7 @@ static int build_pollfd(struct userdata *u) { return -1; } pollfd->fd = fd; - pollfd->events = /* POLLOUT | */ POLLERR | POLLNVAL; + pollfd->events = POLLOUT | POLLERR | POLLNVAL; return 0; } @@ -200,6 +186,7 @@ static int unsuspend(struct userdata *u) { u->write_count = 0; u->first = true; + u->timestamp = pa_rtclock_now(); pa_log_info("Resumed successfully..."); @@ -268,14 +255,13 @@ static int sink_process_msg( switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { - pa_usec_t now = pa_rtclock_now(); - pa_usec_t latency = 0ULL; - if (u->timestamp > now) { - if ((u->timestamp - now) > (now - u->timestamp_written)) { - latency = (u->timestamp - now) + (u->timestamp_written - now); - } - } - *((pa_usec_t*)data) = 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; } } @@ -283,22 +269,7 @@ static int sink_process_msg( return pa_sink_process_msg(o, code, data, offset, chunk); } -static void sink_update_requested_latency_cb(pa_sink *s) { - struct userdata *u; - - pa_sink_assert_ref(s); - pa_assert_se((u = s->userdata)); - - u->block_usec = pa_sink_get_requested_latency_within_thread(s); - - if (u->block_usec == (pa_usec_t)-1) - u->block_usec = s->thread_info.max_latency; - - pa_sink_set_max_rewind_within_thread(s, pa_usec_to_bytes(u->block_usec, &s->sample_spec)); - pa_sink_set_max_request_within_thread(s, pa_usec_to_bytes(u->max_request_usec, &s->sample_spec)); -} - -static void process_rewind(struct userdata *u, pa_usec_t now) { +static void process_rewind(struct userdata *u) { #if 1 /* Rewind not supported */ pa_sink_process_rewind(u->sink, 0); @@ -338,60 +309,35 @@ do_nothing: #endif } -static int process_render(struct userdata *u, pa_usec_t now) { - int work_done = 0; - size_t ate = 0; +static int process_render(struct userdata *u) { void *p; - size_t frames_to_write, frame_size; + size_t frame_size = pa_frame_size(&u->sink->sample_spec); + size_t frames_to_write = u->frag_size / u->nfrags; uint32_t avail = 0; + pa_memchunk chunk; pa_assert(u); - /* Fill the buffer up the latency size */ - while (u->timestamp < now + u->block_usec) { - pa_memchunk chunk; - frame_size = pa_frame_size(&u->sink->sample_spec); - if (frame_size == 0) { - pa_log_error("Unexpected frame size zero!"); - break; - } - - pa_hal_interface_pcm_available(u->hal_interface, u->pcm_handle, &avail); - if ((avail == 0) && !(u->first)) { - break; - } - - if (u->first) { - pa_log_debug("Fill initial buffer"); - - frames_to_write = u->frag_size / frame_size; - u->timestamp = u->timestamp_written = now; - } else { - frames_to_write = (u->frag_size / u->nfrags); - - if (frames_to_write > avail) - break; - } - - pa_sink_render_full(u->sink, frames_to_write * frame_size, &chunk); - p = pa_memblock_acquire(chunk.memblock); + pa_hal_interface_pcm_available(u->hal_interface, u->pcm_handle, &avail); + if (frames_to_write > avail) { + pa_log_debug("not enough avail size. frames_to_write(%d), avail(%d)", frames_to_write, avail); + return 0; + } - pa_hal_interface_pcm_write(u->hal_interface, u->pcm_handle, (const char*)p + chunk.index, (uint32_t)frames_to_write); + pa_sink_render_full(u->sink, frames_to_write * frame_size, &chunk); + p = pa_memblock_acquire(chunk.memblock); - pa_memblock_release(chunk.memblock); - pa_memblock_unref(chunk.memblock); - u->timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec); - u->timestamp_written = 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(%d)", p, frames_to_write); + return -1; + } - work_done = 1; + pa_memblock_release(chunk.memblock); + pa_memblock_unref(chunk.memblock); - ate += chunk.length; - if (ate >= u->sink->thread_info.max_request) { - break; - } - } + u->write_count += chunk.length; - return work_done; + return 0; } static void thread_func(void *userdata) { @@ -407,35 +353,23 @@ static void thread_func(void *userdata) { pa_thread_mq_install(&u->thread_mq); + u->timestamp = pa_rtclock_now(); + for (;;) { - pa_usec_t now = 0; int ret; - if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) - now = pa_rtclock_now(); - if (PA_UNLIKELY(u->sink->thread_info.rewind_requested)) - process_rewind(u, now); + process_rewind(u); - /* Render some data and drop it immediately */ if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) { - int work_done = process_render(u, now); - - if (work_done < 0) + if (process_render(u)) goto fail; - if (work_done == 0) { - pa_rtpoll_set_timer_relative(u->rtpoll, (20 * PA_USEC_PER_MSEC)); - } else { - if (u->first) { - pa_log_info("Starting playback."); - pa_hal_interface_pcm_start(u->hal_interface, u->pcm_handle); - u->first = false; - } - pa_rtpoll_set_timer_relative(u->rtpoll, (20 * PA_USEC_PER_MSEC)); + if (u->first) { + pa_log_info("Starting playback."); + pa_hal_interface_pcm_start(u->hal_interface, u->pcm_handle); + u->first = false; } - } else { - pa_rtpoll_set_timer_disabled(u->rtpoll); } /* Hmm, nothing to do. Let's sleep */ @@ -515,8 +449,6 @@ int pa__init(pa_module*m) { pa_modargs *ma = NULL; pa_sink_new_data data; uint32_t alternate_sample_rate; - uint32_t block_msec; - uint32_t max_request_msec; const char *modarg_device; char card[DEVICE_NAME_MAX]; char device[DEVICE_NAME_MAX]; @@ -546,6 +478,7 @@ int pa__init(pa_module*m) { 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); @@ -572,19 +505,6 @@ int pa__init(pa_module*m) { } pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); - /* Optional */ - block_msec = DEFAULT_BLOCK_USEC / PA_USEC_PER_MSEC; - pa_modargs_get_value_u32(ma, "block_msec", &block_msec); - u->block_usec = (pa_usec_t) block_msec * PA_USEC_PER_MSEC; - - /* Optional */ - max_request_msec = DEFAULT_MAX_REQUEST_USEC / PA_USEC_PER_MSEC; - pa_modargs_get_value_u32(ma, "max_request_msec", &max_request_msec); - u->max_request_usec = (pa_usec_t) max_request_msec * PA_USEC_PER_MSEC; - - u->timestamp = 0ULL; - u->timestamp_written = 0ULL; - pa_sink_new_data_init(&data); data.driver = __FILE__; data.module = m; @@ -620,7 +540,6 @@ int pa__init(pa_module*m) { u->sink->parent.process_msg = sink_process_msg; u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb; - u->sink->update_requested_latency = sink_update_requested_latency_cb; u->sink->userdata = u; if (pa_hal_interface_pcm_open(u->hal_interface, @@ -638,14 +557,14 @@ int pa__init(pa_module*m) { pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); - pa_sink_set_max_rewind(u->sink, 0); - pa_sink_set_max_request(u->sink, pa_usec_to_bytes(u->max_request_usec, &u->sink->sample_spec)); + 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-sink", thread_func, u))) { pa_log_error("Failed to create thread."); goto fail; } - pa_sink_set_fixed_latency(u->sink, u->block_usec); + pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(buffer_size, &ss)); pa_sink_put(u->sink); pa_modargs_free(ma); -- 2.7.4