return DEVICE_UNKNOWN;
}
+typedef struct _loopback_module {
+ pa_sink *sink;
+ pa_source *source;
+ pa_module *module;
+} loopback_module;
+
struct userdata {
pa_core *core;
pa_module *module;
uint32_t module_null_sink_index;
uint32_t module_null_source_index;
pa_module *module_loopback;
+ pa_hashmap *loopback_modules;
struct {
int32_t latency_msec;
int32_t adjust_sec;
}
}
+static void update_loopback_module_args(struct userdata* u, int32_t parent_id, pa_sink *sink, pa_source *source)
+{
+ loopback_module *loopback;
+
+ pa_assert(u);
+
+ if (parent_id < 0) {
+ pa_log_error("invalid parent_id(%d)", parent_id);
+ return;
+ }
+
+ loopback = pa_hashmap_get(u->loopback_modules, (const void*)parent_id);
+ if (!loopback) {
+ loopback = pa_xnew0(loopback_module, 1);
+ pa_hashmap_put(u->loopback_modules, (void*)parent_id, loopback);
+ }
+ if (sink)
+ loopback->sink = sink;
+ if (source)
+ loopback->source = source;
+
+ pa_log_info("loopback module for parent_id(%d) is updated, sink(%s), source(%s)",
+ parent_id, loopback->sink ? loopback->sink->name : "null", loopback->source ? loopback->source->name : "null");
+}
+
+static void load_loopback_module_by_parent_id(struct userdata* u, int32_t parent_id)
+{
+ loopback_module *loopback;
+ char *args;
+ const char *volume_type;
+
+ pa_assert(u);
+
+ if (parent_id < 0) {
+ pa_log_error("invalid parent_id(%d)", parent_id);
+ return;
+ }
+
+ loopback = pa_hashmap_get(u->loopback_modules, (const void*)parent_id);
+ if (!loopback) {
+ pa_log_error("could not find loopback module for parent_id(%d)", parent_id);
+ return;
+ }
+
+ if (!loopback->sink || !loopback->source) {
+ pa_log_debug("sink(%p) or source(%p) is not set", loopback->sink, loopback->source);
+ return;
+ }
+
+ if (!u->loopback_args.latency_msec)
+ u->loopback_args.latency_msec = LOOPBACK_DEFAULT_LATENCY_MSEC;
+ if (!u->loopback_args.adjust_sec)
+ u->loopback_args.adjust_sec = LOOPBACK_DEFAULT_ADJUST_SEC;
+
+ volume_type = pa_stream_manager_get_volume_type(u->stream_manager, STREAM_SINK_INPUT, STREAM_ROLE_LOOPBACK);
+ args = pa_sprintf_malloc("sink=%s source=%s latency_msec=%d adjust_time=%d sink_input_properties=%s=%s",
+ loopback->sink->name, loopback->source->name,
+ u->loopback_args.latency_msec, u->loopback_args.adjust_sec,
+ PA_PROP_MEDIA_TIZEN_VOLUME_TYPE, volume_type);
+
+ if (pa_module_load(&loopback->module, u->core, MODULE_LOOPBACK, args))
+ pa_log_error("failed to load module-loopback for parent_id(%d) with (%s)", parent_id, args);
+ else
+ pa_log_info("load module-loopback(%p) for parent_id(%d) with (%s)", loopback->module, parent_id, args);
+
+ pa_xfree(args);
+}
+
+static void unload_loopback_modules_by_device_disconnect(struct userdata* u, pa_sink *sink, pa_source *source)
+{
+ loopback_module *loopback;
+ int32_t parent_id;
+ void *state;
+
+ pa_assert(u);
+
+ pa_log_info("disconnected sink(%s), source(%s)", sink ? sink->name : "null", source ? source->name : "null");
+
+ PA_HASHMAP_FOREACH_KV(parent_id, loopback, u->loopback_modules, state) {
+ if (loopback->module &&
+ ((sink && (loopback->sink == sink)) ||
+ (source && (loopback->source == source)))) {
+ pa_log_info(" -- unload module-loopback(%p) for parent_id(%d)", loopback->module, parent_id);
+ pa_hashmap_remove_and_free(u->loopback_modules, (const void*)parent_id);
+ }
+ }
+}
+
+static void unload_loopback_modules_by_stream_disconnect(struct userdata* u, int32_t parent_id, pa_sink_input *i, pa_source_output *o)
+{
+ loopback_module *loopback;
+
+ pa_assert(u);
+
+ if (parent_id < 0)
+ return;
+
+ if (!i && !o)
+ return;
+
+ loopback = pa_hashmap_get(u->loopback_modules, (const void*)parent_id);
+ if (!loopback)
+ return;
+
+ if (!loopback->module) {
+ pa_log_info("module is not loaded yet");
+ return;
+ }
+
+ pa_log_info("disconnected sink-input(%p) or source-output(%p) of parent_id(%d)", i, o, parent_id);
+
+ if (i && loopback->sink)
+ if (pa_idxset_get_by_data(loopback->sink->inputs, i, NULL) && pa_idxset_size(loopback->sink->inputs))
+ goto unload;
+
+ if (o && loopback->source)
+ if (pa_idxset_get_by_data(loopback->source->outputs, o, NULL) && pa_idxset_size(loopback->source->outputs))
+ goto unload;
+
+ pa_log_warn("no loopback module to be unloaded with parent_id(%d), sink-input(%p), source-output(%p)", parent_id, i, o);
+
+ return;
+
+unload:
+ pa_log_info(" -- unload module-loopback(%p) for parent_id(%d)", loopback->module, parent_id);
+ pa_hashmap_remove_and_free(u->loopback_modules, (const void*)parent_id);
+}
+
/* Load/Unload module-loopback */
static void update_loopback_module(struct userdata *u, bool load) {
char *args = NULL;
return PA_HOOK_OK;
}
+static void loopback_module_free(loopback_module *loopback) {
+ pa_assert(loopback);
+
+ pa_log_info("unload module-loopback(%p)", loopback->module);
+
+ pa_module_unload(loopback->module, true);
+
+ pa_xfree(loopback);
+}
+
int pa__init(pa_module *m)
{
pa_modargs *ma = NULL;
u->module_null_source_index = module_loaded->index;
pa_xfree(args);
+ u->loopback_modules = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t)loopback_module_free);
+
__load_dump_config(u);
pa_log_info("Tizen Audio Policy module is loaded\n");
bt_sco_close(u, false);
+ if (u->loopback_modules) {
+ pa_hashmap_remove_all(u->loopback_modules);
+ pa_hashmap_free(u->loopback_modules);
+ }
+
if (u->module_null_sink_index != PA_INVALID_INDEX)
pa_module_unload_by_index(m->core, u->module_null_sink_index, true);