hal: tizenaudio reference sink / source add pcm interface 99/51199/14
authorKimJeongYeon <jeongyeon.kim@samsung.com>
Thu, 5 Nov 2015 07:46:00 +0000 (16:46 +0900)
committerKimJeongYeon <jeongyeon.kim@samsung.com>
Wed, 18 Nov 2015 00:43:28 +0000 (09:43 +0900)
Signed-off-by: KimJeongYeon <jeongyeon.kim@samsung.com>
Change-Id: Ibadd26341eb91fd2c081e7ef38e062d479d71329

src/hal-manager.c
src/hal-manager.h
src/module-tizenaudio-sink.c
src/module-tizenaudio-source.c
src/tizen-audio.h

index bb595200b401f951a6ba966faeff1d1742ce901a..15bcbbc8d178b4baf52be48569c31c1ea2738d6d 100644 (file)
@@ -75,6 +75,10 @@ pa_hal_manager* pa_hal_manager_get(pa_core *core) {
         h->intf.pcm_avail = dlsym(h->dl_handle, "audio_pcm_avail");
         h->intf.pcm_write = dlsym(h->dl_handle, "audio_pcm_write");
         h->intf.pcm_read = dlsym(h->dl_handle, "audio_pcm_read");
+        h->intf.pcm_get_fd = dlsym(h->dl_handle, "audio_pcm_get_fd");
+        h->intf.pcm_recover = dlsym(h->dl_handle, "audio_pcm_recover");
+        h->intf.pcm_get_params = dlsym(h->dl_handle, "audio_pcm_get_params");
+        h->intf.pcm_set_params = dlsym(h->dl_handle, "audio_pcm_set_params");
         if (h->intf.init) {
             /* TODO : no need to pass platform_data as second param. need to fix hal. */
             if (h->intf.init(&h->data) != AUDIO_RET_OK) {
@@ -307,7 +311,7 @@ int32_t pa_hal_manager_get_buffer_attribute(pa_hal_manager *h, hal_stream_info *
     return ret;
 }
 
-int32_t pa_hal_manager_pcm_open(pa_hal_manager *h, pcm_handle *pcm_h, io_direction_t direction, pa_sample_spec *sample_spec) {
+int32_t pa_hal_manager_pcm_open(pa_hal_manager *h, pcm_handle *pcm_h, io_direction_t direction, pa_sample_spec *sample_spec, uint32_t period_size, uint32_t periods) {
     int32_t ret = 0;
     audio_return_t hal_ret = AUDIO_RET_OK;
 
@@ -315,7 +319,7 @@ int32_t pa_hal_manager_pcm_open(pa_hal_manager *h, pcm_handle *pcm_h, io_directi
     pa_assert(pcm_h);
     pa_assert(sample_spec);
 
-    if (AUDIO_IS_ERROR(hal_ret = h->intf.pcm_open(h->data, pcm_h, sample_spec, direction))) {
+    if (AUDIO_IS_ERROR(hal_ret = h->intf.pcm_open(h->data, pcm_h, direction, sample_spec, period_size, periods))) {
         pa_log_error("pcm_open returns error:0x%x", hal_ret);
         ret = -1;
     }
@@ -408,3 +412,62 @@ int32_t pa_hal_manager_pcm_read(pa_hal_manager *h, pcm_handle pcm_h, void *buffe
     }
     return ret;
 }
+
+int32_t pa_hal_manager_pcm_get_fd(pa_hal_manager *h, pcm_handle pcm_h, int *fd) {
+    int32_t ret = 0;
+    audio_return_t hal_ret = AUDIO_RET_OK;
+
+    pa_assert(h);
+    pa_assert(pcm_h);
+    pa_assert(fd);
+
+    if (AUDIO_IS_ERROR(hal_ret = h->intf.pcm_get_fd(h->data, pcm_h, fd))) {
+        pa_log_error("pcm_get_fd returns error:0x%x", hal_ret);
+        ret = -1;
+    }
+    return ret;
+}
+
+int32_t pa_hal_manager_pcm_recover(pa_hal_manager *h, pcm_handle pcm_h, int err) {
+    int32_t ret = 0;
+    audio_return_t hal_ret = AUDIO_RET_OK;
+
+    pa_assert(h);
+    pa_assert(pcm_h);
+
+    if (AUDIO_IS_ERROR(hal_ret = h->intf.pcm_recover(h->data, pcm_h, err))) {
+        pa_log_error("pcm_recover returns error:0x%x", hal_ret);
+        ret = -1;
+    }
+    return ret;
+}
+
+int32_t pa_hal_manager_pcm_get_params(pa_hal_manager *h, pcm_handle pcm_h, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods) {
+    int32_t ret = 0;
+    audio_return_t hal_ret = AUDIO_RET_OK;
+
+    pa_assert(h);
+    pa_assert(*sample_spec);
+    pa_assert(period_size);
+    pa_assert(periods);
+
+    if (AUDIO_IS_ERROR(hal_ret = h->intf.pcm_get_params(h->data, pcm_h, direction, sample_spec, period_size, periods))) {
+        pa_log_error("pcm_get_params returns error:0x%x", hal_ret);
+        ret = -1;
+    }
+    return ret;
+}
+
+int32_t pa_hal_manager_pcm_set_params(pa_hal_manager *h, pcm_handle pcm_h, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods) {
+    int32_t ret = 0;
+    audio_return_t hal_ret = AUDIO_RET_OK;
+
+    pa_assert(h);
+    pa_assert(sample_spec);
+
+    if (AUDIO_IS_ERROR(hal_ret = h->intf.pcm_set_params(h->data, pcm_h, direction, sample_spec, period_size, periods))) {
+        pa_log_error("pcm_set_params returns error:0x%x", hal_ret);
+        ret = -1;
+    }
+    return ret;
+}
index 3b50050695badae1854bf06b187e6429ef253b08..5d445ccdf81ca70a028e9c7f0b274071faff893b 100644 (file)
@@ -56,12 +56,16 @@ int32_t pa_hal_manager_do_route(pa_hal_manager *h, hal_route_info *info);
 int32_t pa_hal_manager_update_route_option(pa_hal_manager *h, hal_route_option *option);
 int32_t pa_hal_manager_update_stream_connection_info(pa_hal_manager *h, hal_stream_connection_info *info);
 int32_t pa_hal_manager_get_buffer_attribute(pa_hal_manager *h, hal_stream_info *info, uint32_t *maxlength, uint32_t *tlength, uint32_t *prebuf, uint32_t* minreq, uint32_t *fragsize);
-int32_t pa_hal_manager_pcm_open(pa_hal_manager *h, pcm_handle *pcm_h, io_direction_t direction, pa_sample_spec *sample_spec);
+int32_t pa_hal_manager_pcm_open(pa_hal_manager *h, pcm_handle *pcm_h, io_direction_t direction, pa_sample_spec *sample_spec, uint32_t period_size, uint32_t periods);
 int32_t pa_hal_manager_pcm_start(pa_hal_manager *h, pcm_handle pcm_h);
 int32_t pa_hal_manager_pcm_stop(pa_hal_manager *h, pcm_handle pcm_h);
 int32_t pa_hal_manager_pcm_close(pa_hal_manager *h, pcm_handle pcm_h);
 int32_t pa_hal_manager_pcm_available(pa_hal_manager *h, pcm_handle pcm_h, uint32_t *available);
 int32_t pa_hal_manager_pcm_write(pa_hal_manager *h, pcm_handle pcm_h, const void *buffer, uint32_t frames);
 int32_t pa_hal_manager_pcm_read(pa_hal_manager *h, pcm_handle pcm_h, void *buffer, uint32_t frames);
+int32_t pa_hal_manager_pcm_get_fd(pa_hal_manager *h, pcm_handle pcm_h, int *fd);
+int32_t pa_hal_manager_pcm_recover(pa_hal_manager *h, pcm_handle pcm_h, int err);
+int32_t pa_hal_manager_pcm_get_params(pa_hal_manager *h, pcm_handle pcm_h, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+int32_t pa_hal_manager_pcm_set_params(pa_hal_manager *h, pcm_handle pcm_h, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
 
 #endif
index da750c48dcdf08272df1ebc05d75a3745853dc47..17712df25aceccc4ae3182a426d3def34fa9791c 100644 (file)
@@ -1,7 +1,7 @@
 /***
   This file is part of PulseAudio.
 
-  Copyright 2004-2008 Lennart Poettering
+  Copyright (c) 2015 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
@@ -42,6 +42,7 @@
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
+#include <pulsecore/poll.h>
 
 #include "hal-manager.h"
 #include "module-tizenaudio-sink-symdef.h"
@@ -80,15 +81,18 @@ struct userdata {
     pa_rtpoll *rtpoll;
 
     void *pcm_handle;
+    uint32_t nfrags;
+    uint32_t frag_size;
 
     pa_usec_t block_usec;
     pa_usec_t timestamp;
 
     char* device_name;
-    bool first, after_rewind;
+    bool first;
+
+    pa_rtpoll_item *rtpoll_item;
 
     uint64_t write_count;
-    uint64_t since_start;
     pa_hal_manager *hal_manager;
 };
 
@@ -108,6 +112,31 @@ 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_manager_pcm_get_fd(u->hal_manager, 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;
@@ -116,9 +145,15 @@ static int suspend(struct userdata *u) {
 
     ret = pa_hal_manager_pcm_close(u->hal_manager, u->pcm_handle);
     if (ret) {
-        pa_log("Error closing PCM device %x", 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...[%s]", u->device_name);
 
     return 0;
@@ -133,16 +168,22 @@ static int unsuspend(struct userdata *u) {
 
     pa_log_info("Trying resume...");
     sample_spec = u->sink->sample_spec;
-    ret = pa_hal_manager_pcm_open(u->hal_manager, (void **)&u->pcm_handle, DIRECTION_OUT, &sample_spec);
+    ret = pa_hal_manager_pcm_open(u->hal_manager,
+              (void **)&u->pcm_handle,
+              DIRECTION_OUT,
+              &sample_spec,
+              u->frag_size / pa_frame_size(&sample_spec),
+              u->nfrags);
     if (ret) {
-        pa_log("Error opening PCM device %x", ret);
+        pa_log_error("Error opening PCM device %x", ret);
         goto fail;
     }
-    pa_log_info("Trying sw param...");
+
+    if (build_pollfd(u) < 0)
+        goto fail;
 
     u->write_count = 0;
     u->first = true;
-    u->since_start = 0;
 
     pa_log_info("Resumed successfully...");
 
@@ -179,6 +220,11 @@ static int sink_process_msg(
 
                 case PA_SINK_IDLE:
                 case PA_SINK_RUNNING: {
+                    if (u->sink->thread_info.state == PA_SINK_INIT) {
+                        if (build_pollfd(u) < 0)
+                            return -PA_ERR_IO;
+                    }
+
                     u->timestamp = pa_rtclock_now();
                     if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
                         if ((r = unsuspend(u)) < 0)
@@ -225,6 +271,10 @@ static void sink_update_requested_latency_cb(pa_sink *s) {
 }
 
 static void process_rewind(struct userdata *u, pa_usec_t now) {
+#if 1
+    /* Rewind not supported */
+    pa_sink_process_rewind(u->sink, 0);
+#else
     size_t rewind_nbytes, in_buffer;
     pa_usec_t delay;
 
@@ -256,30 +306,37 @@ static void process_rewind(struct userdata *u, pa_usec_t now) {
     return;
 
 do_nothing:
-
     pa_sink_process_rewind(u->sink, 0);
+#endif
 }
 
-static void process_render(struct userdata *u, pa_usec_t now) {
+static int process_render(struct userdata *u, pa_usec_t now) {
+    int work_done = 0;
     size_t ate = 0;
     void *p;
     size_t frames_to_write, frame_size;
-    uint32_t avail;
-    pa_assert(u);
+    uint32_t avail = 0;
 
-    if (u->first) {
-        pa_log_info("Starting playback.");
-        pa_hal_manager_pcm_start(u->hal_manager, u->pcm_handle);
-        u->first = false;
-    }
+    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);
 
         pa_hal_manager_pcm_available(u->hal_manager, u->pcm_handle, &avail);
-        frame_size = pa_frame_size(&u->sink->sample_spec);
-        frames_to_write = u->sink->thread_info.max_request / frame_size;
+        if ((avail == 0) && !(u->first)) {
+            break;
+        }
+
+        if (u->first) {
+            pa_log_debug("Fill initial buffer");
+            frames_to_write = (u->frag_size * u->nfrags) / frame_size;
+        } else {
+            frames_to_write = u->sink->thread_info.max_request / frame_size;
+            if (frames_to_write > avail)
+                break;
+        }
 
         pa_sink_render_full(u->sink, frames_to_write * frame_size, &chunk);
         p = pa_memblock_acquire(chunk.memblock);
@@ -290,17 +347,23 @@ static void process_render(struct userdata *u, pa_usec_t now) {
         pa_memblock_unref(chunk.memblock);
         u->timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec);
 
+        work_done = 1;
+
         ate += chunk.length;
         if (ate >= u->sink->thread_info.max_request) {
             break;
         }
     }
+
+    return work_done;
 }
 
 static void thread_func(void *userdata) {
     struct userdata *u = userdata;
+    unsigned short revents = 0;
 
     pa_assert(u);
+
     pa_log_debug("Thread starting up");
     pa_thread_mq_install(&u->thread_mq);
     u->timestamp = pa_rtclock_now();
@@ -318,11 +381,27 @@ static void thread_func(void *userdata) {
         /* Render some data and drop it immediately */
         if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
             if (u->timestamp <= now) {
-                process_render(u, now);
+                int work_done = process_render(u, now);
+
+                if (work_done < 0)
+                    goto fail;
+
+                if (work_done == 0) {
+                    pa_rtpoll_set_timer_relative(u->rtpoll, (10 * PA_USEC_PER_MSEC));
+                } else {
+                    if (u->first) {
+                        pa_log_info("Starting playback.");
+                        pa_hal_manager_pcm_start(u->hal_manager, u->pcm_handle);
+                        u->first = false;
+                    }
+                    pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
+                }
+            } else {
+                pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
             }
-            pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
-        } else
+        } else {
             pa_rtpoll_set_timer_disabled(u->rtpoll);
+        }
 
         /* Hmm, nothing to do. Let's sleep */
         if ((ret = pa_rtpoll_run(u->rtpoll, true)) < 0)
@@ -330,6 +409,22 @@ static void thread_func(void *userdata) {
 
         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_manager_pcm_recover(u->hal_manager, u->pcm_handle, revents);
+                    u->first = true;
+                    revents = 0;
+                } else {
+                    //pa_log_debug("Poll wakeup.", revents);
+                }
+            }
+        }
     }
 
 fail:
@@ -346,7 +441,6 @@ int pa__init(pa_module*m) {
     struct userdata *u = NULL;
     pa_sample_spec ss;
     pa_channel_map map;
-    uint32_t nfrags, frag_size;
     pa_modargs *ma = NULL;
     pa_sink_new_data data;
     size_t nbytes;
@@ -355,26 +449,20 @@ int pa__init(pa_module*m) {
     pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("Failed to parse module arguments.");
+        pa_log_error("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("Invalid sample format specification or channel map");
+        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("Failed to parse alternate sample rate");
-        goto fail;
-    }
-
-    if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 ||
-        pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0) {
-        pa_log("Failed to parse buffer metrics");
+        pa_log_error("Failed to parse alternate sample rate");
         goto fail;
     }
 
@@ -386,6 +474,15 @@ int pa__init(pa_module*m) {
     u->rtpoll = pa_rtpoll_new();
     pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
 
+    u->frag_size = 0;
+    u->nfrags = 0;
+    pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size);
+    pa_modargs_get_value_u32(ma, "fragments", &u->nfrags);
+    if (u->frag_size == 0 || u->nfrags == 0) {
+        pa_log_error("fragment_size or fragments are invalid.");
+        goto fail;
+    }
+
     pa_sink_new_data_init(&data);
     data.driver = __FILE__;
     data.module = m;
@@ -398,7 +495,7 @@ int pa__init(pa_module*m) {
     pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen");
 
     if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
-        pa_log("Invalid properties");
+        pa_log_error("Invalid properties.");
         pa_sink_new_data_done(&data);
         goto fail;
     }
@@ -407,7 +504,7 @@ int pa__init(pa_module*m) {
     pa_sink_new_data_done(&data);
 
     if (!u->sink) {
-        pa_log("Failed to create sink object.");
+        pa_log_error("Failed to create sink object.");
         goto fail;
     }
 
@@ -427,7 +524,7 @@ int pa__init(pa_module*m) {
     pa_sink_set_max_request(u->sink, nbytes);
 
     if (!(u->thread = pa_thread_new("tizenaudio-sink", thread_func, u))) {
-        pa_log("Failed to create thread.");
+        pa_log_error("Failed to create thread.");
         goto fail;
     }
     pa_sink_set_fixed_latency(u->sink, u->block_usec);
index 9a8116c86572cf3e484eaaa721fb854ab7a53e52..7479cf47f8dfee2cc979eb5876dc926c34f6298a 100644 (file)
@@ -1,7 +1,7 @@
 /***
   This file is part of PulseAudio.
 
-  Copyright 2004-2008 Lennart Poettering
+  Copyright (c) 2015 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
@@ -42,6 +42,7 @@
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
+#include <pulsecore/poll.h>
 
 #include "hal-manager.h"
 #include "module-tizenaudio-source-symdef.h"
@@ -81,15 +82,18 @@ struct userdata {
     pa_rtpoll *rtpoll;
 
     void *pcm_handle;
+    uint32_t nfrags;
+    uint32_t frag_size;
 
     pa_usec_t block_usec;
     pa_usec_t timestamp;
 
     char* device_name;
-    bool first, after_rewind;
+    bool first;
+
+    pa_rtpoll_item *rtpoll_item;
 
     uint64_t read_count;
-    uint64_t since_start;
     pa_usec_t latency_time;
     pa_hal_manager *hal_manager;
 };
@@ -110,6 +114,31 @@ 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_manager_pcm_get_fd(u->hal_manager, 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;
@@ -118,9 +147,15 @@ static int suspend(struct userdata *u) {
 
     ret = pa_hal_manager_pcm_close(u->hal_manager, u->pcm_handle);
     if (ret) {
-        pa_log("Error closing PCM device %x", 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...[%s]", u->device_name);
 
     return 0;
@@ -135,16 +170,22 @@ static int unsuspend(struct userdata *u) {
 
     pa_log_info("Trying resume...");
     sample_spec = u->source->sample_spec;
-    ret = pa_hal_manager_pcm_open(u->hal_manager, (void **)&u->pcm_handle, DIRECTION_IN, &sample_spec);
+    ret = pa_hal_manager_pcm_open(u->hal_manager,
+              (void **)&u->pcm_handle,
+              DIRECTION_IN,
+              &sample_spec,
+              u->frag_size / pa_frame_size(&sample_spec),
+              u->nfrags);
     if (ret) {
-        pa_log("Error opening PCM device %x", ret);
+        pa_log_error("Error opening PCM device %x", ret);
         goto fail;
     }
-    pa_log_info("Trying sw param...");
+
+    if (build_pollfd(u) < 0)
+        goto fail;
 
     u->read_count = 0;
     u->first = true;
-    u->since_start = 0;
 
     pa_log_info("Resumed successfully...");
 
@@ -181,6 +222,11 @@ static int source_process_msg(
 
                 case PA_SOURCE_IDLE:
                 case PA_SOURCE_RUNNING: {
+                    if (u->source->thread_info.state == PA_SOURCE_INIT) {
+                        if (build_pollfd(u) < 0)
+                            return -PA_ERR_IO;
+                    }
+
                     u->timestamp = pa_rtclock_now();
                     if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
                         if ((r = unsuspend(u)) < 0)
@@ -225,25 +271,25 @@ static void source_update_requested_latency_cb(pa_source *s) {
     pa_source_set_max_rewind_within_thread(s, nbytes);
 }
 
-static void process_render(struct userdata *u, pa_usec_t now) {
+static int process_render(struct userdata *u, pa_usec_t now) {
+    int work_done = 0;
     size_t ate = 0;
     void *p;
     size_t frames_to_read, frame_size;
-    uint32_t avail;
-    pa_assert(u);
+    uint32_t avail = 0;
 
-    if (u->first) {
-        pa_log_info("Starting capture.");
-        pa_hal_manager_pcm_start(u->hal_manager, u->pcm_handle);
-        u->first = false;
-    }
+    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->source->sample_spec);
 
         pa_hal_manager_pcm_available(u->hal_manager, u->pcm_handle, &avail);
-        frame_size = pa_frame_size(&u->source->sample_spec);
+        if (avail == 0) {
+            break;
+        }
+
         frames_to_read = pa_usec_to_bytes(u->block_usec, &u->source->sample_spec) / frame_size;
 
         chunk.length = pa_usec_to_bytes(u->block_usec, &u->source->sample_spec);
@@ -263,15 +309,20 @@ static void process_render(struct userdata *u, pa_usec_t now) {
 
         u->timestamp += pa_bytes_to_usec(chunk.length, &u->source->sample_spec);
 
+        work_done = 1;
+
         ate += chunk.length;
         if (ate >= pa_usec_to_bytes(u->block_usec, &u->source->sample_spec)) {
             break;
         }
     }
+
+    return work_done;
 }
 
 static void thread_func(void *userdata) {
     struct userdata *u = userdata;
+    unsigned short revents = 0;
 
     pa_assert(u);
     pa_log_debug("Thread starting up");
@@ -288,11 +339,30 @@ static void thread_func(void *userdata) {
         /* Render some data and drop it immediately */
         if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
             if (u->timestamp <= now) {
-                process_render(u, now);
+                int work_done;
+
+                if (u->first) {
+                    pa_log_info("Starting capture.");
+                    pa_hal_manager_pcm_start(u->hal_manager, u->pcm_handle);
+                    u->first = false;
+                }
+
+                work_done = process_render(u, now);
+
+                if (work_done < 0)
+                    goto fail;
+
+                if (work_done == 0) {
+                    pa_rtpoll_set_timer_relative(u->rtpoll, (10 * PA_USEC_PER_MSEC));
+                } else {
+                    pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
+                }
+            } else {
+                pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
             }
-            pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
-        } else
+        } else {
             pa_rtpoll_set_timer_disabled(u->rtpoll);
+        }
 
         /* Hmm, nothing to do. Let's sleep */
         if ((ret = pa_rtpoll_run(u->rtpoll, true)) < 0)
@@ -300,6 +370,22 @@ static void thread_func(void *userdata) {
 
         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_manager_pcm_recover(u->hal_manager, u->pcm_handle, revents);
+                    u->first = true;
+                    revents = 0;
+                } else {
+                    //pa_log_debug("Poll wakeup.", revents);
+                }
+            }
+        }
     }
 
 fail:
@@ -316,7 +402,6 @@ int pa__init(pa_module*m) {
     struct userdata *u = NULL;
     pa_sample_spec ss;
     pa_channel_map map;
-    uint32_t nfrags, frag_size;
     pa_modargs *ma = NULL;
     pa_source_new_data data;
     uint32_t alternate_sample_rate;
@@ -324,26 +409,20 @@ int pa__init(pa_module*m) {
     pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("Failed to parse module arguments.");
+        pa_log_error("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("Invalid sample format specification or channel map");
+        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("Failed to parse alternate sample rate");
-        goto fail;
-    }
-
-    if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 ||
-        pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0) {
-        pa_log("Failed to parse buffer metrics");
+        pa_log_error("Failed to parse alternate sample rate");
         goto fail;
     }
 
@@ -355,6 +434,15 @@ int pa__init(pa_module*m) {
     u->rtpoll = pa_rtpoll_new();
     pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
 
+    u->frag_size = 0;
+    u->nfrags = 0;
+    pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size);
+    pa_modargs_get_value_u32(ma, "fragments", &u->nfrags);
+    if (u->frag_size == 0 || u->nfrags == 0) {
+        pa_log_error("fragment_size or fragments are invalid.");
+        goto fail;
+    }
+
     pa_source_new_data_init(&data);
     data.driver = __FILE__;
     data.module = m;
@@ -367,7 +455,7 @@ int pa__init(pa_module*m) {
     pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen");
 
     if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
-        pa_log("Invalid properties");
+        pa_log_error("Invalid properties.");
         pa_source_new_data_done(&data);
         goto fail;
     }
@@ -376,7 +464,7 @@ int pa__init(pa_module*m) {
     pa_source_new_data_done(&data);
 
     if (!u->source) {
-        pa_log("Failed to create source object.");
+        pa_log_error("Failed to create source object.");
         goto fail;
     }
 
@@ -390,12 +478,12 @@ int pa__init(pa_module*m) {
     unsuspend (u);
 
     u->block_usec = BLOCK_USEC;
-    u->latency_time = BLOCK_USEC;
+    u->latency_time = u->block_usec;
 
     pa_source_set_max_rewind(u->source, 0);
 
     if (!(u->thread = pa_thread_new("tizenaudio-source", thread_func, u))) {
-        pa_log("Failed to create thread.");
+        pa_log_error("Failed to create thread.");
         goto fail;
     }
     pa_source_set_fixed_latency(u->source, u->block_usec);
index f47a3b8dee1d5318497d59a16f6642858b9433cb..c4c7765b7f9044384b9a834b81a6fbc0d3d4a5ff 100644 (file)
@@ -84,13 +84,17 @@ typedef struct audio_interface {
     audio_return_t (*get_buffer_attr)(void *userdata, uint32_t direction, const char *latency, uint32_t samplerate, int format, uint32_t channels,
                                       uint32_t *maxlength, uint32_t *tlength, uint32_t *prebuf, uint32_t* minreq, uint32_t *fragsize);
     /* Interface of PCM device */
-    audio_return_t (*pcm_open)(void *userdata, void **pcm_handle, void *sample_spec, uint32_t direction);
+    audio_return_t (*pcm_open)(void *userdata, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
     audio_return_t (*pcm_start)(void *userdata, void *pcm_handle);
     audio_return_t (*pcm_stop)(void *userdata, void *pcm_handle);
     audio_return_t (*pcm_close)(void *userdata, void *pcm_handle);
     audio_return_t (*pcm_avail)(void *userdata, void *pcm_handle, uint32_t *avail);
     audio_return_t (*pcm_write)(void *userdata, void *pcm_handle, const void *buffer, uint32_t frames);
     audio_return_t (*pcm_read)(void *userdata, void *pcm_handle, void *buffer, uint32_t frames);
+    audio_return_t (*pcm_get_fd)(void *userdata, void *pcm_handle, int *fd);
+    audio_return_t (*pcm_recover)(void *userdata, void *pcm_handle, int err);
+    audio_return_t (*pcm_get_params)(void *userdata, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+    audio_return_t (*pcm_set_params)(void *userdata, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
 } audio_interface_t;
 
 audio_return_t audio_init(void **userdata);
@@ -106,11 +110,15 @@ audio_return_t audio_update_route_option(void *userdata, audio_route_option_t *o
 audio_return_t audio_update_stream_connection_info(void *userdata, audio_stream_info_t *info, uint32_t is_connected);
 audio_return_t audio_get_buffer_attr(void *userdata, uint32_t direction, const char *latency, uint32_t samplerate, int format, uint32_t channels,
                                      uint32_t *maxlength, uint32_t *tlength, uint32_t *prebuf, uint32_t* minreq, uint32_t *fragsize);
-audio_return_t audio_pcm_open(void *userdata, void **pcm_handle, void *sample_spec, uint32_t direction);
+audio_return_t audio_pcm_open(void *userdata, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
 audio_return_t audio_pcm_start(void *userdata, void *pcm_handle);
 audio_return_t audio_pcm_stop(void *userdata, void *pcm_handle);
 audio_return_t audio_pcm_close(void *userdata, void *pcm_handle);
 audio_return_t audio_pcm_avail(void *userdata, void *pcm_handle, uint32_t *avail);
 audio_return_t audio_pcm_write(void *userdata, void *pcm_handle, const void *buffer, uint32_t frames);
 audio_return_t audio_pcm_read(void *userdata, void *pcm_handle, void *buffer, uint32_t frames);
+audio_return_t audio_pcm_get_fd(void *userdata, void *pcm_handle, int *fd);
+audio_return_t audio_pcm_recover(void *userdata, void *pcm_handle, int err);
+audio_return_t audio_pcm_get_params(void *userdata, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+audio_return_t audio_pcm_set_params(void *userdata, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
 #endif