pa_hook_slot *source_output_fixate_slot;
pa_hook_slot *source_output_put_slot;
+ pa_hook_slot *source_output_unlink_slot;
pa_hook_slot *source_output_unlink_post_slot;
+ pa_hook_slot *source_output_move_start_slot;
+ pa_hook_slot *source_output_move_finish_slot;
+
pa_rtpoll *rtpoll;
pa_thread *thread;
pa_thread_mq thread_mq;
NULL,
};
+static bool proplist_test_tizen_version2(pa_proplist *p) {
+ const char *tizen_version;
+ uint32_t version;
+
+ pa_assert(p);
+
+ if (!(tizen_version = pa_proplist_gets(p, "tizen.version")))
+ return false;
+
+ if (pa_atou(tizen_version, &version))
+ return false;
+
+ if (version < 2)
+ return false;
+
+ return true;
+}
+
+static void process_msg_main_thread(pa_msgobject *o, int code, void *userdata) {
+ pa_assert(o);
+ pa_assert(userdata);
+
+ o->process_msg(o, code, userdata, 0UL, NULL);
+}
+
static int proplist_get_fragment_size_usec(pa_proplist *p, pa_sample_spec *sample_spec, pa_usec_t *usec) {
const char *prop_fragsize;
uint32_t fragsize;
char *processor_str = NULL;
pa_processor_holder *holder;
- pa_usec_t process_usec;
+ pa_usec_t process_usec = 10 * PA_USEC_PER_MSEC;
pa_assert(core);
pa_assert(data);
processors_list = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_PREPROCESSOR_METHOD);
pa_assert(processors_list);
- if (proplist_get_fragment_size_usec(data->source->proplist, &data->source->sample_spec, &process_usec) < 0) {
- pa_processor_holder_free(holder);
- pa_log_error("Failed to get source fragment usec. use default process usec");
- return NULL;
- }
+ if (proplist_get_fragment_size_usec(data->source->proplist, &data->source->sample_spec, &process_usec) < 0)
+ pa_log_warn("Failed to get source fragment usec. use default process usec");
+
+ pa_log_info("request to build processors_list(%s)", processors_list);
while ((processor_str = pa_split(processors_list, ",", &state))) {
pa_processor *processor;
pa_assert(o);
holder = (pa_processor_holder *)o->thread_info.processor_holder;
- pa_processor_holder_free(holder);
+ if (holder) {
+ pa_processor_holder_free(holder);
+ o->thread_info.processor_holder = NULL;
+ }
o->preprocess = NULL;
o->thread_info.processor_holder = NULL;
/* chunk must contain resampled sound pcm */
pa_processor_holder_push_data(holder, chunk);
+
ret = pa_processor_holder_pump(holder);
if (ret != PROCESSOR_OK) {
if (ret != -PROCESSOR_ERR_BUFFERING)
return PA_HOOK_OK;
holder = (pa_processor_holder *)o->thread_info.processor_holder;
+ if (!holder) {
+ pa_log_error("Failed to get processor holder");
+ return PA_HOOK_OK;
+ }
- pa_assert(holder);
- pa_assert(pa_processor_holder_get_current_source(holder)); /* source must be set at ADD_SOURCE_OUTPUT */
+ if (!proplist_test_tizen_version2(o->source->proplist)) {
+ pa_msgobject *msgobject = PA_MSGOBJECT(u->preprocessor);
+ pa_assert(msgobject);
+
+ process_msg_main_thread(msgobject, PA_SOURCE_MESSAGE_PREPROCESSOR_ADD_OUTPUT, o);
+
+ connect_to_reference_sink(holder, PA_MSGOBJECT(u->preprocessor), u->asyncmsgq_sink, true);
+
+ return PA_HOOK_OK;
+ }
connect_to_reference_sink(holder, PA_MSGOBJECT(u->preprocessor), u->asyncmsgq_sink, true);
return PA_HOOK_OK;
}
+static pa_hook_result_t source_output_unlink_cb(pa_core *c, pa_source_output *o, void *userdata) {
+ struct userdata *u = (struct userdata *)userdata;
+ pa_processor_holder *holder;
+
+ pa_assert(c);
+ pa_assert(o);
+ pa_assert(u);
+
+ if (!is_preprocessor_marked(o->flags))
+ return PA_HOOK_OK;
+
+ holder = (pa_processor_holder *)o->thread_info.processor_holder;
+ if (!holder) {
+ pa_log_error("Failed to get processor holder");
+ return PA_HOOK_OK;
+ }
+
+ /* in case of normal source(not tizen2)
+ * This should be destroy in unlink process
+ * because o->source wouldn't exist in the unlink_post step. */
+ if (!proplist_test_tizen_version2(o->source->proplist)) {
+ pa_msgobject *msgobject = PA_MSGOBJECT(u->preprocessor);
+ pa_assert(msgobject);
+
+ process_msg_main_thread(msgobject, PA_SOURCE_MESSAGE_PREPROCESSOR_DESTROY, o);
+
+ connect_to_reference_sink(holder, NULL, NULL, false);
+ }
+
+ return PA_HOOK_OK;
+}
+
/* This function will be also called when source unlink */
static pa_hook_result_t source_output_unlink_post_cb(pa_core *c, pa_source_output *o, void *userdata) {
struct userdata *u = (struct userdata *)userdata;
return PA_HOOK_OK;
holder = (pa_processor_holder *)o->thread_info.processor_holder;
+ if (!holder) {
+ pa_log_info("holder doesn't exist. source-output might not be connected to tizen2 source");
+ return PA_HOOK_OK;
+ }
connect_to_reference_sink(holder, NULL, NULL, false);
return PA_HOOK_OK;
}
+static pa_hook_result_t source_output_move_start_cb(pa_core *c, pa_source_output *o, void *userdata) {
+ struct userdata *u = (struct userdata *)userdata;
+
+ pa_assert(c);
+ pa_assert(o);
+ pa_assert(u);
+
+ if (!proplist_test_tizen_version2(o->source->proplist)) {
+ pa_msgobject *msgobject = PA_MSGOBJECT(u->preprocessor);
+ pa_assert(msgobject);
+
+ process_msg_main_thread(msgobject, PA_SOURCE_MESSAGE_PREPROCESSOR_REMOVE_OUTPUT, o);
+ }
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_move_finish_cb(pa_core *c, pa_source_output *o, void *userdata) {
+ struct userdata *u = (struct userdata *)userdata;
+
+ pa_assert(c);
+ pa_assert(o);
+ pa_assert(u);
+
+ if (!proplist_test_tizen_version2(o->source->proplist)) {
+ pa_msgobject *msgobject = PA_MSGOBJECT(u->preprocessor);
+ pa_assert(msgobject);
+
+ process_msg_main_thread(msgobject, PA_SOURCE_MESSAGE_PREPROCESSOR_ADD_OUTPUT, o);
+ }
+
+ return PA_HOOK_OK;
+}
+
static void thread_func(void *userdata) {
struct userdata *u = (struct userdata *)userdata;
goto fail;
}
+ u->source_output_unlink_slot =
+ pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK],
+ PA_HOOK_EARLY, (pa_hook_cb_t) source_output_unlink_cb, u);
+
u->source_output_unlink_post_slot =
pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST],
PA_HOOK_EARLY, (pa_hook_cb_t) source_output_unlink_post_cb, u);
pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT],
PA_HOOK_LATE, (pa_hook_cb_t) source_output_put_cb, u);
+ u->source_output_move_start_slot =
+ pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START],
+ PA_HOOK_LATE, (pa_hook_cb_t) source_output_move_start_cb, u);
+
+ u->source_output_move_finish_slot =
+ pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH],
+ PA_HOOK_LATE, (pa_hook_cb_t) source_output_move_finish_cb, u);
+
/* TODO : need to check sink configuration change */
pa_modargs_free(ma);
processor->audio_effect = audio_effect_create(audio_effect_method, ss->rate, ss->channels,
format, processor->process_frames);
+
if (!processor->audio_effect) {
pa_log_error("Failed to create audio effect. audio_effect_method(%d), "
"rate(%d), ch(%d), format(%d), frames(%zu)",
}
process_framesize = audio_effect_get_process_framesize(processor->audio_effect);
-
if (process_framesize > 0) {
processor->process_frames = process_framesize;
processor->process_usec = pa_processor_frame_to_usec(processor->process_frames, ss);
processor->process_bytes = pa_usec_to_bytes(processor->process_usec, ss);
- pa_log_info("Changed process_frame. constraint process_frame(%zu)", processor->process_frames);
+ pa_log_info("Changed process_frame. constraint process_frame(%zu), usec(%" PRIu64 "ms), bytes(%zu)",
+ processor->process_frames,
+ processor->process_usec / PA_USEC_PER_MSEC,
+ processor->process_bytes);
}
pa_silence_memchunk_get(&core->silence_cache, core->mempool, &silence, &processor->ss, 0);
ochunk.length = chunk->length;
ochunk.memblock = pa_memblock_new(processor->core->mempool, ochunk.length);
- recording = pa_memblock_acquire_chunk(chunk);
- output = pa_memblock_acquire_chunk(&ochunk);
+ recording = (uint8_t *)pa_memblock_acquire_chunk(chunk);
+ output = (uint8_t *)pa_memblock_acquire_chunk(&ochunk);
debug_timestamp_begin(processor);
} else {
char *reference_dump = pa_processor_reference_dump_index(processor->reference);
- // need to add chunk->index
pa_log_debug("Post-process(%s). rec(%" PRIu64 "ms), ref(%" PRIu64 "ms), out(%" PRIu64 "ms), " \
"reference memblockq %s, silence %d",
pa_processor_method_str(processor->method),
}
const char *pa_processor_method_str(pa_processor_method_t method) {
- static const char *method_table[] = { "speex", "webrtc", "reference_copy", "rnnoise", "none-pse" };
+ static const char *method_table[] = {
+ [PROCESSOR_METHOD_SPEEX] = "speex",
+ [PROCESSOR_METHOD_WEBRTC] = "webrtc",
+ [PROCESSOR_METHOD_REFERENCE_COPY] = "reference_copy",
+ [PROCESSOR_METHOD_RNNOISE] = "rnnoise",
+ [PROCESSOR_METHOD_NONE_PSE] = "none-pse" };
if (method >= PROCESSOR_METHOD_MAX)
return NULL;
}
int pa_processor_holder_push_data(pa_processor_holder *holder, pa_memchunk *chunk) {
+ int ret;
+
pa_assert(holder);
pa_assert(chunk);
- return pa_memblockq_push(holder->input, chunk);
+ ret = pa_memblockq_push(holder->input, chunk);
+
+ pa_log_debug("push data to the input queue. chunk length(%zu), memblockq length(%zu)",
+ chunk->length, pa_memblockq_get_length(holder->input));
+
+ return ret;
}
int pa_processor_holder_push_reference_data(pa_processor_holder *holder, pa_memchunk *chunk) {
int pa_processor_holder_pull_data(pa_processor_holder *holder, pa_memchunk *chunk) {
int r;
+ size_t length;
pa_assert(holder);
pa_assert(chunk);
- if ((r = pa_memblockq_peek(holder->output, chunk)) < 0)
+ length = pa_memblockq_get_length(holder->output);
+
+ if ((r = pa_memblockq_peek_fixed_size(holder->output, length, chunk)) < 0)
pa_log_error("Failed to get memblock from output memblockq");
/* chunk ref count must be one after dropping */
pa_memblockq_drop(holder->output, chunk->length);
+ pa_log_debug("pull from the output queue. chunk length(%zu), memblockq_length(%zu)",
+ chunk->length, pa_memblockq_get_length(holder->output));
+
return r;
}
process_size = pa_processor_get_process_bytes(p);
length = pa_memblockq_get_length(pull_queue);
- if (length < process_size)
+ if (length < process_size) {
+ pa_log_info("processor(%s) needs process_size(%zu) but there are bytes(%zu) in the queue",
+ pa_processor_method_str(p->method), process_size, length);
return -PROCESSOR_ERR_BUFFERING;
+ }
while (length >= process_size) {
ret = pa_memblockq_peek_fixed_size(pull_queue, process_size, &chunk);
if ((ret = pa_processor_process(p, &chunk)) < 0) {
pa_memblock_unref(chunk.memblock);
pa_memblockq_drop(pull_queue, chunk.length);
+ pa_log_error("Failed to process");
return ret;
}
}
length = pa_memblockq_get_length(pull_queue);
- if (length > 0) {
- pa_memblockq_peek_fixed_size(pull_queue, length, &chunk);
- pa_memblockq_push(holder->output, &chunk);
- pa_memblock_unref(chunk.memblock);
- pa_memblockq_drop(pull_queue, chunk.length);
+
+ while (length > 0) {
+ pa_memchunk tchunk;
+
+ pa_memblockq_peek(pull_queue, &tchunk);
+ pa_memblockq_push(holder->output, &tchunk);
+ pa_memblock_unref(tchunk.memblock);
+ pa_memblockq_drop(pull_queue, tchunk.length);
+ length = pa_memblockq_get_length(pull_queue);
}
return 0;