tizenaudio-sink2: Use hardware interrupt for playback 89/262189/5
authorJaechul Lee <jcsing.lee@samsung.com>
Wed, 4 Aug 2021 01:01:56 +0000 (10:01 +0900)
committerJaechul Lee <jcsing.lee@samsung.com>
Thu, 5 Aug 2021 09:49:19 +0000 (18:49 +0900)
 * 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 <jcsing.lee@samsung.com>
packaging/pulseaudio-modules-tizen.spec
src/module-tizenaudio-sink2.c

index 3986972..6f220f2 100644 (file)
@@ -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+
index f8a6059..e4e61e9 100644 (file)
@@ -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=<number of channels> "
         "channel_map=<channel map>"
         "fragments=<number of fragments> "
-        "fragment_size=<fragment size> "
-        "block_msec=<sink keep> "
-        "max_request_msec=<maximum buffer request of device> ");
+        "fragment_size=<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);