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) {
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;
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;
}
}
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;
+}
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
/***
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
#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"
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;
};
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;
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;
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...");
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)
}
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;
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);
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();
/* 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)
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:
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;
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;
}
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;
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;
}
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;
}
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);
/***
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
#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"
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;
};
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;
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;
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...");
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)
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);
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");
/* 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)
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:
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;
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;
}
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;
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;
}
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;
}
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);
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);
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