#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(
"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
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;
"channel_map",
"fragments",
"fragment_size",
- "block_msec",
- "max_request_msec",
NULL
};
return -1;
}
pollfd->fd = fd;
- pollfd->events = /* POLLOUT | */ POLLERR | POLLNVAL;
+ pollfd->events = POLLOUT | POLLERR | POLLNVAL;
return 0;
}
u->write_count = 0;
u->first = true;
+ u->timestamp = pa_rtclock_now();
pa_log_info("Resumed successfully...");
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;
}
}
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);
#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) {
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 */
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];
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);
}
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;
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,
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);