From 2e0bbdaefe031e2c493ed48ed781aa4cd24393d4 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Wed, 17 Mar 2021 16:05:44 +0900 Subject: [PATCH 01/16] stream-manager-dbus: remove unnessary dbus_launch_mdnsd() mdnsd is changed to launch by socket activation [Version] 13.0.51 [Issue Type] Dependancy Change-Id: Id957b580d877c802d282fe746248564998552b20 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager-dbus.c | 44 --------------------------------- 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 351047c..8446dce 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.50 +Version: 13.0.51 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager-dbus.c b/src/stream-manager-dbus.c index 2f6e4c6..e68cda6 100644 --- a/src/stream-manager-dbus.c +++ b/src/stream-manager-dbus.c @@ -2230,40 +2230,6 @@ finish: dbus_message_unref(reply); } -static int dbus_launch_mdnsd(pa_stream_manager *m, DBusConnection *conn) { - DBusMessage *msg, *reply; - DBusError err; - const char *name = NULL; - - pa_log_info("launching mdnsd"); - - if (!(msg = dbus_message_new_method_call("net.netconfig", - "/net/netconfig/network", - "net.netconfig.network", - "LaunchMdns"))) { - pa_log_error("dbus method call failed"); - return -1; - } - - name = dbus_bus_get_unique_name(conn); - pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)); - - dbus_error_init(&err); - - reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_TIMEOUT_USE_DEFAULT, &err); - dbus_message_unref(msg); - if (!reply) { - pa_log_error("Failed to method call : %s", err.message); - dbus_error_free(&err); - return -1; - } - - dbus_message_unref(reply); - pa_log_info("success"); - - return 0; -} - static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata) { pa_stream_manager *m = (pa_stream_manager *)userdata; const char *type = NULL; @@ -2355,11 +2321,6 @@ static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg goto error; } - if (dbus_launch_mdnsd(m, conn) == -1) { - pa_log_error("failed to launch mdnsd!!!"); - goto error; - } - if (pa_module_load(&module, m->core, "module-tizenaudio-discover", NULL)) { pa_log_error("failed to load module"); goto error; @@ -2401,11 +2362,6 @@ static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, goto error; } - if (dbus_launch_mdnsd(m, conn) == -1) { - pa_log_error("failed to launch mdnsd!!!"); - goto error; - } - if (pa_module_load(&module, m->core, "module-native-protocol-tcp", "auth-anonymous=1")) { pa_log_error("failed to load module"); goto error; -- 2.7.4 From 144ce706b93a7741bff1a0b9f69b65d544481606 Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Thu, 18 Mar 2021 20:23:31 +0900 Subject: [PATCH 02/16] stream-manager: Apply designated initializers to arrays [Version] 13.0.52 [Issue Type] Refactoring Change-Id: If23ef59b2702618943f2029bd4bcaf35015bba3d Signed-off-by: Sangchul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager.c | 34 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 8446dce..2d4862d 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.51 +Version: 13.0.52 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager.c b/src/stream-manager.c index 034bf0a..c2b4c80 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -82,26 +82,26 @@ static const char* stream_manager_media_names_for_skip[NAME_FOR_SKIP_MAX] = {"pu #define TIMED_UNMUTE_USEC 300000 static const char* process_command_type_str[] = { - "PREPARE", - "CHANGE_ROUTE_BY_STREAM_STARTED", - "CHANGE_ROUTE_BY_STREAM_ENDED", - "CHANGE_ROUTE_BY_STATE_CHANGED_RUNNING", - "CHANGE_ROUTE_BY_STATE_CHANGED_CORKED", - "CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED", - "UPDATE_VOLUME", - "ADD_PARENT_ID", - "REMOVE_PARENT_ID", - "UPDATE_BUFFER_ATTR", - "APPLY_FILTER", + [PROCESS_COMMAND_PREPARE] = "PREPARE", + [PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED] = "CHANGE_ROUTE_BY_STREAM_STARTED", + [PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED] = "CHANGE_ROUTE_BY_STREAM_ENDED", + [PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_RUNNING] = "CHANGE_ROUTE_BY_STATE_CHANGED_RUNNING", + [PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_CORKED] = "CHANGE_ROUTE_BY_STATE_CHANGED_CORKED", + [PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED] = "CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED", + [PROCESS_COMMAND_UPDATE_VOLUME] = "UPDATE_VOLUME", + [PROCESS_COMMAND_ADD_PARENT_ID] = "ADD_PARENT_ID", + [PROCESS_COMMAND_REMOVE_PARENT_ID] = "REMOVE_PARENT_ID", + [PROCESS_COMMAND_UPDATE_BUFFER_ATTR] = "UPDATE_BUFFER_ATTR", + [PROCESS_COMMAND_APPLY_FILTER] = "APPLY_FILTER", }; static const char* notify_command_type_str[] = { - "SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT", - "CHANGE_ROUTE_START", - "CHANGE_ROUTE_END", - "UPDATE_ROUTE_OPTION", - "INFORM_STREAM_CONNECTED", - "INFORM_STREAM_DISCONNECTED", + [NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT] = "SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT", + [NOTIFY_COMMAND_CHANGE_ROUTE_START] = "CHANGE_ROUTE_START", + [NOTIFY_COMMAND_CHANGE_ROUTE_END] = "CHANGE_ROUTE_END", + [NOTIFY_COMMAND_UPDATE_ROUTE_OPTION] = "UPDATE_ROUTE_OPTION", + [NOTIFY_COMMAND_INFORM_STREAM_CONNECTED] = "INFORM_STREAM_CONNECTED", + [NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED] = "INFORM_STREAM_DISCONNECTED", }; #define STREAM_MAP_FILE "/etc/pulse/stream-map.json" -- 2.7.4 From 60e8045a5a78f7cec6bedd4bb7f5cc6ad2f236ed Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Thu, 18 Mar 2021 20:32:50 +0900 Subject: [PATCH 03/16] stream-manager: Rename enum and function Incorrect names are revised generically to embrace the actual doing in the function. [Version] 13.0.53 [Issue Type] Rename Change-Id: I2860404667916d7487131fccc02de4fa141f7074 Signed-off-by: Sangchul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager-priv.h | 4 ++-- src/stream-manager.c | 30 +++++++++++++++--------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 2d4862d..6c7bd8b 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.52 +Version: 13.0.53 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager-priv.h b/src/stream-manager-priv.h index 390b156..677deff 100644 --- a/src/stream-manager-priv.h +++ b/src/stream-manager-priv.h @@ -72,8 +72,8 @@ typedef enum _process_command_type { PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_CORKED, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, PROCESS_COMMAND_UPDATE_VOLUME, - PROCESS_COMMAND_ADD_PARENT_ID, - PROCESS_COMMAND_REMOVE_PARENT_ID, + PROCESS_COMMAND_ADD_STREAM, + PROCESS_COMMAND_REMOVE_STREAM, PROCESS_COMMAND_UPDATE_BUFFER_ATTR, PROCESS_COMMAND_APPLY_FILTER, } process_command_type_t; diff --git a/src/stream-manager.c b/src/stream-manager.c index c2b4c80..8ff7dde 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -89,8 +89,8 @@ static const char* process_command_type_str[] = { [PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_CORKED] = "CHANGE_ROUTE_BY_STATE_CHANGED_CORKED", [PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED] = "CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED", [PROCESS_COMMAND_UPDATE_VOLUME] = "UPDATE_VOLUME", - [PROCESS_COMMAND_ADD_PARENT_ID] = "ADD_PARENT_ID", - [PROCESS_COMMAND_REMOVE_PARENT_ID] = "REMOVE_PARENT_ID", + [PROCESS_COMMAND_ADD_STREAM] = "ADD_STREAM", + [PROCESS_COMMAND_REMOVE_STREAM] = "REMOVE_STREAM", [PROCESS_COMMAND_UPDATE_BUFFER_ATTR] = "UPDATE_BUFFER_ATTR", [PROCESS_COMMAND_APPLY_FILTER] = "APPLY_FILTER", }; @@ -1230,12 +1230,12 @@ static bool update_stream_parent_info(pa_stream_manager *m, process_command_type sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx); if (sp) { uint32_t idx = GET_STREAM_INDEX(stream, type); - if (command == PROCESS_COMMAND_ADD_PARENT_ID) { + if (command == PROCESS_COMMAND_ADD_STREAM) { /* append this stream to the parent stream info. */ pa_log_debug(" - append this stream(%p, %u) to the list. sp(%p), stream_type(%d)", stream, idx, sp, type); pa_idxset_put(type == STREAM_SINK_INPUT ? (sp->idx_sink_inputs) : (sp->idx_source_outputs), stream, NULL); return true; - } else if (command == PROCESS_COMMAND_REMOVE_PARENT_ID) { + } else if (command == PROCESS_COMMAND_REMOVE_STREAM) { /* remove this stream from the parent stream info. */ pa_log_debug(" - remove this stream(%p, %u) from the list. sp(%p), stream_type(%d)", stream, idx, sp, type); pa_idxset_remove_by_data(type == STREAM_SINK_INPUT ? (sp->idx_sink_inputs) : (sp->idx_source_outputs), stream, NULL); @@ -2280,7 +2280,7 @@ static process_stream_result_t handle_command_update_volume(pa_stream_manager *m return PROCESS_STREAM_RESULT_OK; } -static process_stream_result_t handle_command_add_remove_parent_id(pa_stream_manager *m, process_command_type_t command, +static process_stream_result_t handle_command_add_remove_stream(pa_stream_manager *m, process_command_type_t command, void *stream, stream_type_t type, bool is_new_data) { const char *role = NULL; const char *route_type_str = NULL; @@ -2289,8 +2289,8 @@ static process_stream_result_t handle_command_add_remove_parent_id(pa_stream_man pa_assert(m); pa_assert(stream); - if (command != PROCESS_COMMAND_ADD_PARENT_ID && - command != PROCESS_COMMAND_REMOVE_PARENT_ID) + if (command != PROCESS_COMMAND_ADD_STREAM && + command != PROCESS_COMMAND_REMOVE_STREAM) return PROCESS_STREAM_RESULT_SKIP; if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE))) { @@ -2309,7 +2309,7 @@ static process_stream_result_t handle_command_add_remove_parent_id(pa_stream_man } if (!IS_ROUTE_TYPE_FOR_EXTERNAL_DEV(route_type_str, route_type)) { - if (command == PROCESS_COMMAND_ADD_PARENT_ID && CHECK_STREAM_RUNNING(stream, type)) { + if (command == PROCESS_COMMAND_ADD_STREAM && CHECK_STREAM_RUNNING(stream, type)) { if (type == STREAM_SINK_INPUT && m->cur_highest_priority.need_to_update_si) { m->cur_highest_priority.sink_input = stream; m->cur_highest_priority.role_si = role; @@ -2373,9 +2373,9 @@ process_stream_result_t process_stream(pa_stream_manager *m, void *stream, strea case PROCESS_COMMAND_UPDATE_VOLUME: result = handle_command_update_volume(m, stream, type, is_new_data); break; - case PROCESS_COMMAND_ADD_PARENT_ID: - case PROCESS_COMMAND_REMOVE_PARENT_ID: - result = handle_command_add_remove_parent_id(m, command, stream, type, is_new_data); + case PROCESS_COMMAND_ADD_STREAM: + case PROCESS_COMMAND_REMOVE_STREAM: + result = handle_command_add_remove_stream(m, command, stream, type, is_new_data); break; case PROCESS_COMMAND_UPDATE_BUFFER_ATTR: update_buffer_attribute(m, stream, type, is_new_data); @@ -2507,7 +2507,7 @@ static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_st pa_log_info("sink-input(%p, index:%u)", i, i->index); - process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_ADD_PARENT_ID, false); + process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_ADD_STREAM, false); process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_APPLY_FILTER, false); process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_VOLUME, false); if (is_stream_related_call_active_routing(PA_OBJECT(i))) { @@ -2534,7 +2534,7 @@ static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, pa remove_sink_input_from_muted_streams(m, i); remove_sink_input_from_ducking_streams(m, i); - process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_REMOVE_PARENT_ID, false); + process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_REMOVE_STREAM, false); process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false); return PA_HOOK_OK; @@ -2668,7 +2668,7 @@ static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o, pa_log_info("source-output(%p, index:%u)", o, o->index); update_mirroring_streams(m, o, true); - process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_ADD_PARENT_ID, false); + process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_ADD_STREAM, false); process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_VOLUME, false); if (is_stream_related_call_active_routing(PA_OBJECT(o))) { change_active_route_for_call(m, PA_OBJECT(o), true); @@ -2690,7 +2690,7 @@ static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output } update_mirroring_streams(m, o, false); process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false); - process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_REMOVE_PARENT_ID, false); + process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_REMOVE_STREAM, false); return PA_HOOK_OK; } -- 2.7.4 From 6bce670f413163517cfbc107d8a9399924accf6c Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Thu, 18 Mar 2021 21:19:13 +0900 Subject: [PATCH 04/16] Add support for notifying stream connection information to the policy implementation [Version] 13.0.54 [Issue Type] New feature Change-Id: I63ebdd3e62a40d54b04e0ac83f1654015e6095cb Signed-off-by: Sangchul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/communicator.h | 1 + src/module-tizenaudio-policy.c | 16 ++++++++++++++ src/stream-manager.c | 38 ++++++++++++++++++++++++++------- src/stream-manager.h | 8 +++++++ 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 6c7bd8b..6478812 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.53 +Version: 13.0.54 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/communicator.h b/src/communicator.h index 6dd40fc..f41ef58 100644 --- a/src/communicator.h +++ b/src/communicator.h @@ -27,6 +27,7 @@ typedef enum pa_communicator_hook { PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE, /* It is fired when a stream is created and needs to be set to sink or source */ PA_COMMUNICATOR_HOOK_CHANGE_ROUTE, /* It is fired when routing using internal codec should be processed */ + PA_COMMUNICATOR_HOOK_STREAM_CONNECTION_CHANGED, /* It is fired when a stream is connected or disconnected */ PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED, /* It is fired when a device is connected or disconnected */ PA_COMMUNICATOR_HOOK_DEVICE_STATE_CHANGED, /* It is fired when a device's state is changed, it will be replaced by RUNNING_CHANGED */ PA_COMMUNICATOR_HOOK_DEVICE_RUNNING_CHANGED, /* It is fired when a device's running state is changed */ diff --git a/src/module-tizenaudio-policy.c b/src/module-tizenaudio-policy.c index 09759e3..6aa2778 100644 --- a/src/module-tizenaudio-policy.c +++ b/src/module-tizenaudio-policy.c @@ -158,6 +158,7 @@ struct userdata { pa_communicator *comm; pa_hook_slot *comm_hook_select_proper_sink_or_source_slot; pa_hook_slot *comm_hook_change_route_slot; + pa_hook_slot *comm_hook_stream_connection_changed_slot; pa_hook_slot *comm_hook_device_connection_changed_slot; pa_hook_slot *comm_hook_update_info_slot; } communicator; @@ -1675,6 +1676,18 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_ return PA_HOOK_OK; } +static pa_hook_result_t stream_connection_changed_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_stream *data, struct userdata *u) { + pa_assert(c); + pa_assert(data); + pa_assert(u); + + pa_log_info("[STREAM][%s] stream(%p, type:%d, role:%s, parent_id:%s)", + data->is_connected ? "connected" : "disconnected", + data->stream, data->stream_type, data->stream_role, data->parent_id); + + return PA_HOOK_OK; +} + static pa_hook_result_t update_info_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_update_info *data, struct userdata *u) { pa_assert(c); pa_assert(data); @@ -1821,6 +1834,9 @@ int pa__init(pa_module *m) u->communicator.comm_hook_change_route_slot = pa_hook_connect( pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), PA_HOOK_EARLY, (pa_hook_cb_t)route_change_hook_cb, u); + u->communicator.comm_hook_stream_connection_changed_slot = pa_hook_connect( + pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_STREAM_CONNECTION_CHANGED), + PA_HOOK_EARLY, (pa_hook_cb_t)stream_connection_changed_hook_cb, u); u->communicator.comm_hook_device_connection_changed_slot = pa_hook_connect( pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED), PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, u); diff --git a/src/stream-manager.c b/src/stream-manager.c index 8ff7dde..8232c1a 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -1793,6 +1793,25 @@ static ret_msg_t prepare_and_invoke_hook_to_change_route(pa_stream_manager *m, n return ret; } +static ret_msg_t prepare_and_invoke_hook_to_inform_stream_connection(pa_stream_manager *m, bool is_connected, + stream_type_t type, void *s) { + pa_stream_manager_hook_data_for_stream hook_call_stream_data; + + pa_assert(m); + pa_assert(s); + + hook_call_stream_data.stream = s; + hook_call_stream_data.stream_type = type; + hook_call_stream_data.stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE); + hook_call_stream_data.parent_id = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_PARENT_ID); + hook_call_stream_data.is_connected = is_connected; + + if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_STREAM_CONNECTION_CHANGED), &hook_call_stream_data)) + return RET_MSG_ERROR_INTERNAL; + + return RET_MSG_OK; +} + ret_msg_t do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, bool is_new_data, void *user_data) { hal_stream_connection_info stream_conn_info; hal_route_option route_option; @@ -1838,14 +1857,17 @@ ret_msg_t do_notify(pa_stream_manager *m, notify_command_type_t command, stream_ pa_assert(user_data); memset(&stream_conn_info, 0, sizeof(hal_stream_connection_info)); s = user_data; - if (s) { - stream_conn_info.role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE); - stream_conn_info.direction = (type == STREAM_SINK_INPUT) ? DIRECTION_OUT : DIRECTION_IN; - stream_conn_info.idx = GET_STREAM_INDEX(s, type); - stream_conn_info.is_connected = (command == NOTIFY_COMMAND_INFORM_STREAM_CONNECTED) ? true : false; - if (pa_hal_interface_notify_stream_connection_changed(m->hal, &stream_conn_info)) - ret = RET_MSG_ERROR_INTERNAL; - } + + ret = prepare_and_invoke_hook_to_inform_stream_connection(m, command == NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, s); + if (ret != RET_MSG_OK) + pa_log_error("failed to prepare_and_invoke_hook_to_inform_stream_connection()"); + stream_conn_info.role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE); + stream_conn_info.direction = (type == STREAM_SINK_INPUT) ? DIRECTION_OUT : DIRECTION_IN; + stream_conn_info.idx = GET_STREAM_INDEX(s, type); + stream_conn_info.is_connected = (command == NOTIFY_COMMAND_INFORM_STREAM_CONNECTED); + if (pa_hal_interface_notify_stream_connection_changed(m->hal, &stream_conn_info)) + ret = RET_MSG_ERROR_INTERNAL; + break; } } diff --git a/src/stream-manager.h b/src/stream-manager.h index 1aae92c..ffb9d34 100644 --- a/src/stream-manager.h +++ b/src/stream-manager.h @@ -146,6 +146,14 @@ typedef struct _hook_call_data_for_route { bool origins_from_new_data; } pa_stream_manager_hook_data_for_route; +typedef struct _hook_call_data_for_stream { + void *stream; + const char *stream_role; + const char *parent_id; + stream_type_t stream_type; + bool is_connected; +} pa_stream_manager_hook_data_for_stream; + typedef struct _hook_call_data_for_update_info { const char *stream_role; const char *name; -- 2.7.4 From 5e4cb76033a4a929c90b4dfb57e69c42ec3f58cc Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Fri, 19 Mar 2021 14:34:21 +0900 Subject: [PATCH 05/16] stream-manager: handle ramp finished task at core mainloop Sometimes sd handle is accessed simultaneously, which may leads to memory corruption. [Version] 13.0.55 [Issue Type] Bug fix Change-Id: I214c58c1ccde292c918033aaded695f6b59324ef --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager-priv.h | 8 ++ src/stream-manager.c | 133 ++++++++++++++++++++++---------- 3 files changed, 101 insertions(+), 42 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 6478812..51228a8 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.54 +Version: 13.0.55 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager-priv.h b/src/stream-manager-priv.h index 677deff..e3d9298 100644 --- a/src/stream-manager-priv.h +++ b/src/stream-manager-priv.h @@ -233,6 +233,10 @@ typedef struct _filter_info { uint32_t n_controls; } filter_info; +typedef struct _stream_manager_msg { + pa_msgobject parent; +} stream_manager_msg; + struct _stream_manager { PA_REFCNT_DECLARE; @@ -255,6 +259,10 @@ struct _stream_manager { pa_time_event *time_event_for_unmute; pa_hashmap *filter_infos; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + stream_manager_msg *msg; + pa_hook_slot *sink_input_new_slot, *sink_input_put_slot, diff --git a/src/stream-manager.c b/src/stream-manager.c index 8232c1a..9a69289 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -129,6 +129,17 @@ static const char* notify_command_type_str[] = { #define STREAM_MAP_STREAM_AVAIL_OUT_DEVICES "avail-out-devices" #define STREAM_MAP_STREAM_AVAIL_FRAMEWORKS "avail-frameworks" +PA_DEFINE_PRIVATE_CLASS(stream_manager_msg, pa_msgobject); + +enum { + MESSAGE_RAMP_FINISHED, +}; + +struct stream_manager_param { + pa_stream_manager *m; + pa_sink_input *i; +}; + static bool is_valid_notify_command(notify_command_type_t command) { return (command < sizeof(notify_command_type_str) / sizeof(char *)); } @@ -2566,7 +2577,7 @@ static pa_hook_result_t sink_input_state_changed_cb(pa_core *core, pa_sink_input pa_assert(i); pa_assert(m); - pa_log_debug("sink-input(%p, index:%u), state(%d)", i, i->index, i->state); + pa_log_debug("sink-input(%p, index:%u, state:%d)", i, i->index, i->state); switch (i->state) { case PA_SINK_INPUT_CORKED: @@ -2615,8 +2626,7 @@ static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input * } static pa_hook_result_t sink_input_ramp_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) { - stream_ducking *sd; - void *state; + struct stream_manager_param param = { m, i }; pa_core_assert_ref(core); pa_sink_input_assert_ref(i); @@ -2625,44 +2635,9 @@ static pa_hook_result_t sink_input_ramp_finish_cb(pa_core *core, pa_sink_input * if (core->state == PA_CORE_SHUTDOWN) return PA_HOOK_OK; - pa_log_debug("sink-input(%p, index:%u)", i, i->index); - - /* Find a context id from all the ducked stream list by this stream index. - * Check the number of managed streams of the context id, if it is the last one - * then broadcast a signal with context id.*/ - PA_HASHMAP_FOREACH(sd, m->stream_duckings, state) { - if (!pa_idxset_get_by_data(sd->idx_ducking_streams, i, NULL)) { - pa_log_debug("not found matched stream(%p, index:%u) in sd(%p)", i, i->index, sd); - continue; - } - - pa_log_info("found matched stream(%p, index:%u) in sd(%p, ducking_stream_count:%d, state:%u)", - i, i->index, sd, sd->ducking_stream_count, sd->state); - - if (sd->ducking_stream_count <= 0) - continue; - - /* Remove trigger when unducked */ - if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) - pa_idxset_remove_by_data(sd->idx_ducking_streams, (void *)i, NULL); - - /* Send signal when all streams are ducked. - * Note that the condition of increasing count value below is located in - * handle_activate_ducking() of DBus handler. */ - if (--sd->ducking_stream_count == 0) { - if (sd->state == STREAM_DUCKING_STATE_DUCKING) { - sd->state = STREAM_DUCKING_STATE_DUCKED; - } else if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) { - sd->state = STREAM_DUCKING_STATE_UNDUCKED; - } else { - pa_log_warn("sd->state(%d), already ducked or unducked, skip sending signal", sd->state); - continue; - } - - pa_log_info("send signal for ramp finished - sd(%p, state:%u)", sd, sd->state); - send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd)); - } - } + pa_log_info("sink-input(%p, index:%u)", i, i->index); + pa_asyncmsgq_send(m->thread_mq.outq, PA_MSGOBJECT(m->msg), MESSAGE_RAMP_FINISHED, ¶m, 0, NULL); + pa_log_info("sink-input(%p, index:%u) : pa_asyncmsgq_send() done", i, i->index); return PA_HOOK_OK; } @@ -3765,6 +3740,70 @@ const char* pa_stream_manager_get_volume_type(pa_stream_manager *m, stream_type_ return s->volume_types[stream_type == STREAM_SINK_INPUT ? STREAM_DIRECTION_OUT : STREAM_DIRECTION_IN]; } +static int stream_manager_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct stream_manager_param* param = (struct stream_manager_param*)data; + pa_stream_manager *m; + pa_sink_input *i; + stream_ducking *sd; + void *state; + + pa_assert(param); + + m = param->m; + i = param->i; + + pa_log_info("code(%d), sink-input(%p, index:%u, state:%d)", code, i, i->index, i->state); + + if (param->m->core->state == PA_CORE_SHUTDOWN) + return 0; + + switch (code) { + case MESSAGE_RAMP_FINISHED: + /* Find a context id from all the ducked stream list by this stream index. + * Check the number of managed streams of the context id, if it is the last one + * then broadcast a signal with context id.*/ + PA_HASHMAP_FOREACH(sd, m->stream_duckings, state) { + if (!pa_idxset_get_by_data(sd->idx_ducking_streams, i, NULL)) { + pa_log_debug("not found matched stream(%p, index:%u) in sd(%p)", i, i->index, sd); + continue; + } + + pa_log_info("found matched stream(%p, index:%u) in sd(%p, ducking_stream_count:%d, state:%u)", + i, i->index, sd, sd->ducking_stream_count, sd->state); + + if (sd->ducking_stream_count <= 0) + continue; + + /* Remove trigger when unducked */ + if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) + pa_idxset_remove_by_data(sd->idx_ducking_streams, (void *)i, NULL); + + /* Send signal when all streams are ducked. + * Note that the condition of increasing count value below is located in + * handle_activate_ducking() of DBus handler. */ + if (--sd->ducking_stream_count == 0) { + if (sd->state == STREAM_DUCKING_STATE_DUCKING) { + sd->state = STREAM_DUCKING_STATE_DUCKED; + } else if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) { + sd->state = STREAM_DUCKING_STATE_UNDUCKED; + } else { + pa_log_warn("sd->state(%d), already ducked or unducked, skip sending signal", sd->state); + continue; + } + + pa_log_info("send signal for ramp finished - sd(%p, state:%u)", sd, sd->state); + send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd)); + } + } + break; + + default: + pa_assert_not_reached(); + } + + return 0; +} + pa_stream_manager* pa_stream_manager_get(pa_core *c) { pa_stream_manager *m; @@ -3779,6 +3818,14 @@ pa_stream_manager* pa_stream_manager_get(pa_core *c) { PA_REFCNT_INIT(m); m->core = c; + m->rtpoll = pa_rtpoll_new(); + if (pa_thread_mq_init(&m->thread_mq, m->core->mainloop, m->rtpoll) < 0) { + pa_log("pa_thread_mq_init() failed."); + goto fail; + } + m->msg = pa_msgobject_new(stream_manager_msg); + m->msg->parent.process_msg = stream_manager_process_msg; + if (!(m->hal = pa_hal_interface_get(c))) goto fail; @@ -3921,6 +3968,10 @@ void pa_stream_manager_unref(pa_stream_manager *m) { if (PA_REFCNT_DEC(m) > 0) return; + pa_thread_mq_done(&m->thread_mq); + pa_rtpoll_free(m->rtpoll); + pa_xfree(m->msg); + free_hook_slots(m); if (m->comm.comm) -- 2.7.4 From 1a8818f89985dc752e2d95b021803d2edbdb70d6 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Tue, 23 Mar 2021 20:30:55 +0900 Subject: [PATCH 06/16] Revert "stream-manager: handle ramp finished task at core mainloop" [Version] 13.0.56 [Issue Type] Revert This reverts commit 5e4cb76033a4a929c90b4dfb57e69c42ec3f58cc. Change-Id: I04b5587085b31c29ed57dabac3c42ccc0b4f9869 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager-priv.h | 8 -- src/stream-manager.c | 133 ++++++++++---------------------- 3 files changed, 42 insertions(+), 101 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 51228a8..2214288 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.55 +Version: 13.0.56 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager-priv.h b/src/stream-manager-priv.h index e3d9298..677deff 100644 --- a/src/stream-manager-priv.h +++ b/src/stream-manager-priv.h @@ -233,10 +233,6 @@ typedef struct _filter_info { uint32_t n_controls; } filter_info; -typedef struct _stream_manager_msg { - pa_msgobject parent; -} stream_manager_msg; - struct _stream_manager { PA_REFCNT_DECLARE; @@ -259,10 +255,6 @@ struct _stream_manager { pa_time_event *time_event_for_unmute; pa_hashmap *filter_infos; - pa_thread_mq thread_mq; - pa_rtpoll *rtpoll; - stream_manager_msg *msg; - pa_hook_slot *sink_input_new_slot, *sink_input_put_slot, diff --git a/src/stream-manager.c b/src/stream-manager.c index 9a69289..8232c1a 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -129,17 +129,6 @@ static const char* notify_command_type_str[] = { #define STREAM_MAP_STREAM_AVAIL_OUT_DEVICES "avail-out-devices" #define STREAM_MAP_STREAM_AVAIL_FRAMEWORKS "avail-frameworks" -PA_DEFINE_PRIVATE_CLASS(stream_manager_msg, pa_msgobject); - -enum { - MESSAGE_RAMP_FINISHED, -}; - -struct stream_manager_param { - pa_stream_manager *m; - pa_sink_input *i; -}; - static bool is_valid_notify_command(notify_command_type_t command) { return (command < sizeof(notify_command_type_str) / sizeof(char *)); } @@ -2577,7 +2566,7 @@ static pa_hook_result_t sink_input_state_changed_cb(pa_core *core, pa_sink_input pa_assert(i); pa_assert(m); - pa_log_debug("sink-input(%p, index:%u, state:%d)", i, i->index, i->state); + pa_log_debug("sink-input(%p, index:%u), state(%d)", i, i->index, i->state); switch (i->state) { case PA_SINK_INPUT_CORKED: @@ -2626,7 +2615,8 @@ static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input * } static pa_hook_result_t sink_input_ramp_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) { - struct stream_manager_param param = { m, i }; + stream_ducking *sd; + void *state; pa_core_assert_ref(core); pa_sink_input_assert_ref(i); @@ -2635,9 +2625,44 @@ static pa_hook_result_t sink_input_ramp_finish_cb(pa_core *core, pa_sink_input * if (core->state == PA_CORE_SHUTDOWN) return PA_HOOK_OK; - pa_log_info("sink-input(%p, index:%u)", i, i->index); - pa_asyncmsgq_send(m->thread_mq.outq, PA_MSGOBJECT(m->msg), MESSAGE_RAMP_FINISHED, ¶m, 0, NULL); - pa_log_info("sink-input(%p, index:%u) : pa_asyncmsgq_send() done", i, i->index); + pa_log_debug("sink-input(%p, index:%u)", i, i->index); + + /* Find a context id from all the ducked stream list by this stream index. + * Check the number of managed streams of the context id, if it is the last one + * then broadcast a signal with context id.*/ + PA_HASHMAP_FOREACH(sd, m->stream_duckings, state) { + if (!pa_idxset_get_by_data(sd->idx_ducking_streams, i, NULL)) { + pa_log_debug("not found matched stream(%p, index:%u) in sd(%p)", i, i->index, sd); + continue; + } + + pa_log_info("found matched stream(%p, index:%u) in sd(%p, ducking_stream_count:%d, state:%u)", + i, i->index, sd, sd->ducking_stream_count, sd->state); + + if (sd->ducking_stream_count <= 0) + continue; + + /* Remove trigger when unducked */ + if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) + pa_idxset_remove_by_data(sd->idx_ducking_streams, (void *)i, NULL); + + /* Send signal when all streams are ducked. + * Note that the condition of increasing count value below is located in + * handle_activate_ducking() of DBus handler. */ + if (--sd->ducking_stream_count == 0) { + if (sd->state == STREAM_DUCKING_STATE_DUCKING) { + sd->state = STREAM_DUCKING_STATE_DUCKED; + } else if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) { + sd->state = STREAM_DUCKING_STATE_UNDUCKED; + } else { + pa_log_warn("sd->state(%d), already ducked or unducked, skip sending signal", sd->state); + continue; + } + + pa_log_info("send signal for ramp finished - sd(%p, state:%u)", sd, sd->state); + send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd)); + } + } return PA_HOOK_OK; } @@ -3740,70 +3765,6 @@ const char* pa_stream_manager_get_volume_type(pa_stream_manager *m, stream_type_ return s->volume_types[stream_type == STREAM_SINK_INPUT ? STREAM_DIRECTION_OUT : STREAM_DIRECTION_IN]; } -static int stream_manager_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { - struct stream_manager_param* param = (struct stream_manager_param*)data; - pa_stream_manager *m; - pa_sink_input *i; - stream_ducking *sd; - void *state; - - pa_assert(param); - - m = param->m; - i = param->i; - - pa_log_info("code(%d), sink-input(%p, index:%u, state:%d)", code, i, i->index, i->state); - - if (param->m->core->state == PA_CORE_SHUTDOWN) - return 0; - - switch (code) { - case MESSAGE_RAMP_FINISHED: - /* Find a context id from all the ducked stream list by this stream index. - * Check the number of managed streams of the context id, if it is the last one - * then broadcast a signal with context id.*/ - PA_HASHMAP_FOREACH(sd, m->stream_duckings, state) { - if (!pa_idxset_get_by_data(sd->idx_ducking_streams, i, NULL)) { - pa_log_debug("not found matched stream(%p, index:%u) in sd(%p)", i, i->index, sd); - continue; - } - - pa_log_info("found matched stream(%p, index:%u) in sd(%p, ducking_stream_count:%d, state:%u)", - i, i->index, sd, sd->ducking_stream_count, sd->state); - - if (sd->ducking_stream_count <= 0) - continue; - - /* Remove trigger when unducked */ - if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) - pa_idxset_remove_by_data(sd->idx_ducking_streams, (void *)i, NULL); - - /* Send signal when all streams are ducked. - * Note that the condition of increasing count value below is located in - * handle_activate_ducking() of DBus handler. */ - if (--sd->ducking_stream_count == 0) { - if (sd->state == STREAM_DUCKING_STATE_DUCKING) { - sd->state = STREAM_DUCKING_STATE_DUCKED; - } else if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) { - sd->state = STREAM_DUCKING_STATE_UNDUCKED; - } else { - pa_log_warn("sd->state(%d), already ducked or unducked, skip sending signal", sd->state); - continue; - } - - pa_log_info("send signal for ramp finished - sd(%p, state:%u)", sd, sd->state); - send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd)); - } - } - break; - - default: - pa_assert_not_reached(); - } - - return 0; -} - pa_stream_manager* pa_stream_manager_get(pa_core *c) { pa_stream_manager *m; @@ -3818,14 +3779,6 @@ pa_stream_manager* pa_stream_manager_get(pa_core *c) { PA_REFCNT_INIT(m); m->core = c; - m->rtpoll = pa_rtpoll_new(); - if (pa_thread_mq_init(&m->thread_mq, m->core->mainloop, m->rtpoll) < 0) { - pa_log("pa_thread_mq_init() failed."); - goto fail; - } - m->msg = pa_msgobject_new(stream_manager_msg); - m->msg->parent.process_msg = stream_manager_process_msg; - if (!(m->hal = pa_hal_interface_get(c))) goto fail; @@ -3968,10 +3921,6 @@ void pa_stream_manager_unref(pa_stream_manager *m) { if (PA_REFCNT_DEC(m) > 0) return; - pa_thread_mq_done(&m->thread_mq); - pa_rtpoll_free(m->rtpoll); - pa_xfree(m->msg); - free_hook_slots(m); if (m->comm.comm) -- 2.7.4 From 98cb10c7170457fe5960cdcd56aa6f179f1d1990 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Wed, 24 Mar 2021 16:08:00 +0900 Subject: [PATCH 07/16] stream-manager: handle ramp finished task only at the main thread Sometimes sd handle is accessed simultaneously in different thread, which may leads to memory corruption. This patch makes to handle ramp finish task directly only if inside of main thread. Otherwise, request a message to make it handle from the main thread. To avoid possible deadlock, request by posting(async) instead of send(sync). [Version] 13.0.57 [Issue Type] Bug fix Change-Id: I178dbc5b29adccc6f74e41b7e105681c3fd570d0 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager-priv.h | 8 ++ src/stream-manager.c | 158 ++++++++++++++++++++++++-------- 3 files changed, 128 insertions(+), 40 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 2214288..f01676e 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.56 +Version: 13.0.57 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager-priv.h b/src/stream-manager-priv.h index 677deff..e3d9298 100644 --- a/src/stream-manager-priv.h +++ b/src/stream-manager-priv.h @@ -233,6 +233,10 @@ typedef struct _filter_info { uint32_t n_controls; } filter_info; +typedef struct _stream_manager_msg { + pa_msgobject parent; +} stream_manager_msg; + struct _stream_manager { PA_REFCNT_DECLARE; @@ -255,6 +259,10 @@ struct _stream_manager { pa_time_event *time_event_for_unmute; pa_hashmap *filter_infos; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + stream_manager_msg *msg; + pa_hook_slot *sink_input_new_slot, *sink_input_put_slot, diff --git a/src/stream-manager.c b/src/stream-manager.c index 8232c1a..8dec615 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -129,6 +129,62 @@ static const char* notify_command_type_str[] = { #define STREAM_MAP_STREAM_AVAIL_OUT_DEVICES "avail-out-devices" #define STREAM_MAP_STREAM_AVAIL_FRAMEWORKS "avail-frameworks" +PA_DEFINE_PRIVATE_CLASS(stream_manager_msg, pa_msgobject); + +enum { + MESSAGE_RAMP_FINISHED, +}; + +struct stream_manager_param { + pa_stream_manager *m; + pa_sink_input *sink_input; + uint32_t index; +}; + +/* Called from main context */ +static void process_ramp_finish(struct stream_manager_param *param) { + stream_ducking *sd; + void *state; + + /* Find a context id from all the ducked stream list by this stream index. + * Check the number of managed streams of the context id, if it is the last one + * then broadcast a signal with context id.*/ + PA_HASHMAP_FOREACH(sd, param->m->stream_duckings, state) { + if (!pa_idxset_get_by_data(sd->idx_ducking_streams, param->sink_input, NULL)) { + pa_log_debug("not found matched stream(%p, index:%u) in sd(%p)", + param->sink_input, param->index, sd); + continue; + } + + pa_log_info("found matched stream(%p, index:%u) in sd(%p, ducking_stream_count:%d, state:%u)", + param->sink_input, param->index, sd, sd->ducking_stream_count, sd->state); + + if (sd->ducking_stream_count <= 0) + continue; + + /* Remove trigger when unducked */ + if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) + pa_idxset_remove_by_data(sd->idx_ducking_streams, (void *)param->sink_input, NULL); + + /* Send signal when all streams are ducked. + * Note that the condition of increasing count value below is located in + * handle_activate_ducking() of DBus handler. */ + if (--sd->ducking_stream_count == 0) { + if (sd->state == STREAM_DUCKING_STATE_DUCKING) { + sd->state = STREAM_DUCKING_STATE_DUCKED; + } else if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) { + sd->state = STREAM_DUCKING_STATE_UNDUCKED; + } else { + pa_log_warn("sd->state(%d), already ducked or unducked, skip sending signal", sd->state); + continue; + } + + pa_log_info("send signal for ramp finished - sd(%p, state:%u)", sd, sd->state); + send_ducking_state_changed_signal(pa_dbus_connection_get(param->m->dbus_conn), sd->trigger_index, is_stream_ducked(sd)); + } + } +} + static bool is_valid_notify_command(notify_command_type_t command) { return (command < sizeof(notify_command_type_str) / sizeof(char *)); } @@ -1966,7 +2022,7 @@ static process_stream_result_t handle_command_prepare(pa_stream_manager *m, void pa_assert(stream); if (type == STREAM_SINK_INPUT) { - /* Parse request formats for samplerate, channel, format infomation */ + /* Parse request formats for samplerate, channel, format information */ if (((pa_sink_input_new_data*)stream)->req_formats) { req_format = pa_idxset_first(((pa_sink_input_new_data*)stream)->req_formats, NULL); if (req_format && req_format->plist) { @@ -2566,7 +2622,7 @@ static pa_hook_result_t sink_input_state_changed_cb(pa_core *core, pa_sink_input pa_assert(i); pa_assert(m); - pa_log_debug("sink-input(%p, index:%u), state(%d)", i, i->index, i->state); + pa_log_debug("sink-input(%p, index:%u, state:%d)", i, i->index, i->state); switch (i->state) { case PA_SINK_INPUT_CORKED: @@ -2614,9 +2670,15 @@ static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input * return PA_HOOK_OK; } +static bool is_in_main_thread() +{ + return (getpid() == gettid()); +} + +/* Called from either IO thread context or main context */ +/* FIXME : make this callback be invoked from the main context only */ static pa_hook_result_t sink_input_ramp_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) { - stream_ducking *sd; - void *state; + struct stream_manager_param param; pa_core_assert_ref(core); pa_sink_input_assert_ref(i); @@ -2625,43 +2687,20 @@ static pa_hook_result_t sink_input_ramp_finish_cb(pa_core *core, pa_sink_input * if (core->state == PA_CORE_SHUTDOWN) return PA_HOOK_OK; - pa_log_debug("sink-input(%p, index:%u)", i, i->index); - - /* Find a context id from all the ducked stream list by this stream index. - * Check the number of managed streams of the context id, if it is the last one - * then broadcast a signal with context id.*/ - PA_HASHMAP_FOREACH(sd, m->stream_duckings, state) { - if (!pa_idxset_get_by_data(sd->idx_ducking_streams, i, NULL)) { - pa_log_debug("not found matched stream(%p, index:%u) in sd(%p)", i, i->index, sd); - continue; - } - - pa_log_info("found matched stream(%p, index:%u) in sd(%p, ducking_stream_count:%d, state:%u)", - i, i->index, sd, sd->ducking_stream_count, sd->state); - - if (sd->ducking_stream_count <= 0) - continue; - - /* Remove trigger when unducked */ - if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) - pa_idxset_remove_by_data(sd->idx_ducking_streams, (void *)i, NULL); + param.m = m; + param.sink_input = i; + param.index = i->index; - /* Send signal when all streams are ducked. - * Note that the condition of increasing count value below is located in - * handle_activate_ducking() of DBus handler. */ - if (--sd->ducking_stream_count == 0) { - if (sd->state == STREAM_DUCKING_STATE_DUCKING) { - sd->state = STREAM_DUCKING_STATE_DUCKED; - } else if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) { - sd->state = STREAM_DUCKING_STATE_UNDUCKED; - } else { - pa_log_warn("sd->state(%d), already ducked or unducked, skip sending signal", sd->state); - continue; - } + pa_log_info("sink-input(%p, index:%u)", i, i->index); - pa_log_info("send signal for ramp finished - sd(%p, state:%u)", sd, sd->state); - send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd)); - } + if (is_in_main_thread()) { + process_ramp_finish(¶m); + pa_log_info("sink-input(%p, index:%u) : direct process_ramp_finish() done", i, i->index); + } else { + /* Post message to make process_ramp_finish() run from main thread */ + pa_asyncmsgq_post(m->thread_mq.outq, PA_MSGOBJECT(m->msg), MESSAGE_RAMP_FINISHED, + pa_xmemdup(¶m, sizeof(struct stream_manager_param)), 0, NULL, pa_xfree); + pa_log_info("sink-input(%p, index:%u) : posting MESSAGE_RAMP_FINISHED done", i, i->index); } return PA_HOOK_OK; @@ -3765,6 +3804,30 @@ const char* pa_stream_manager_get_volume_type(pa_stream_manager *m, stream_type_ return s->volume_types[stream_type == STREAM_SINK_INPUT ? STREAM_DIRECTION_OUT : STREAM_DIRECTION_IN]; } +static int stream_manager_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct stream_manager_param *param = (struct stream_manager_param *)data; + + pa_assert(param); + pa_assert(param->m); + pa_assert(param->m->core); + + pa_log_info("code(%d), sink-input(%p, index:%u)", code, param->sink_input, param->index); + + if (param->m->core->state == PA_CORE_SHUTDOWN) + return 0; + + switch (code) { + case MESSAGE_RAMP_FINISHED: + process_ramp_finish(param); + break; + + default: + pa_assert_not_reached(); + } + + return 0; +} + pa_stream_manager* pa_stream_manager_get(pa_core *c) { pa_stream_manager *m; @@ -3779,6 +3842,14 @@ pa_stream_manager* pa_stream_manager_get(pa_core *c) { PA_REFCNT_INIT(m); m->core = c; + m->rtpoll = pa_rtpoll_new(); + if (pa_thread_mq_init(&m->thread_mq, m->core->mainloop, m->rtpoll) < 0) { + pa_log("pa_thread_mq_init() failed."); + goto fail; + } + m->msg = pa_msgobject_new(stream_manager_msg); + m->msg->parent.process_msg = stream_manager_process_msg; + if (!(m->hal = pa_hal_interface_get(c))) goto fail; @@ -3840,6 +3911,11 @@ pa_stream_manager* pa_stream_manager_get(pa_core *c) { fail: pa_log_error("failed to initialize stream-manager"); + + pa_thread_mq_done(&m->thread_mq); + pa_rtpoll_free(m->rtpoll); + pa_xfree(m->msg); + deinit_volumes(m); deinit_stream_map(m); deinit_filters(m); @@ -3921,6 +3997,10 @@ void pa_stream_manager_unref(pa_stream_manager *m) { if (PA_REFCNT_DEC(m) > 0) return; + pa_thread_mq_done(&m->thread_mq); + pa_rtpoll_free(m->rtpoll); + pa_xfree(m->msg); + free_hook_slots(m); if (m->comm.comm) -- 2.7.4 From cccecc52adeea52077908828d9125610234151ac Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Wed, 17 Mar 2021 13:22:30 +0900 Subject: [PATCH 08/16] stream-manager: Pass parent id when calling callback for selecting sink or source It is also fixed to pass parent_id as unsigned integer to STREAM CONNECTION CHANGED callback. [Version] 13.0.58 [Issue Type] Improvement Change-Id: I64d300df0c7cc3f68fa97d6bffb809e38421801f Signed-off-by: Sangchul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-policy.c | 6 +++--- src/stream-manager.c | 25 ++++++++++++++++++++----- src/stream-manager.h | 3 ++- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index f01676e..0b48635 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.57 +Version: 13.0.58 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-policy.c b/src/module-tizenaudio-policy.c index 6aa2778..c18391c 100644 --- a/src/module-tizenaudio-policy.c +++ b/src/module-tizenaudio-policy.c @@ -971,8 +971,8 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre pa_assert(data); pa_assert(u); - pa_log_info("[SELECT] data(%p), stream_type(%d), stream_role(%s), device_role(%s), route_type(%d)", - data, data->stream_type, data->stream_role, data->device_role, data->route_type); + pa_log_info("[SELECT] data(%p), stream_type(%d), stream_role(%s), device_role(%s), route_type(%d), parent_id(%d)", + data, data->stream_type, data->stream_role, data->device_role, data->route_type, data->parent_id); null_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_NULL, PA_NAMEREG_SINK); null_source = (pa_source*)pa_namereg_get(u->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE); @@ -1681,7 +1681,7 @@ static pa_hook_result_t stream_connection_changed_hook_cb(pa_core *c, pa_stream_ pa_assert(data); pa_assert(u); - pa_log_info("[STREAM][%s] stream(%p, type:%d, role:%s, parent_id:%s)", + pa_log_info("[STREAM][%s] stream(%p, type:%d, role:%s, parent_id:%d)", data->is_connected ? "connected" : "disconnected", data->stream, data->stream_type, data->stream_role, data->parent_id); diff --git a/src/stream-manager.c b/src/stream-manager.c index 8dec615..15c1191 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -1718,6 +1718,8 @@ static ret_msg_t prepare_and_invoke_hook_to_select_device(pa_stream_manager *m, pa_stream_manager_hook_data_for_select hook_call_select_data; pa_idxset *filtered_avail_devices = NULL; void *s = NULL; + const char *parent_id; + uint32_t parent_id_u; pa_assert(m); pa_assert(user_data); @@ -1760,6 +1762,13 @@ static ret_msg_t prepare_and_invoke_hook_to_select_device(pa_stream_manager *m, if (hook_call_select_data.route_type == STREAM_ROUTE_TYPE_MANUAL) CONVERT_TO_DEVICE_ROLE(hook_call_select_data.stream_role, hook_call_select_data.device_role); + parent_id = is_new_data ? pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_PARENT_ID) : + pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_PARENT_ID); + if (parent_id && pa_atou(parent_id, &parent_id_u) == 0) + hook_call_select_data.parent_id = parent_id_u; + else + hook_call_select_data.parent_id = -1; + if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE), &hook_call_select_data)) { ret = RET_MSG_ERROR_INTERNAL; } else { @@ -1820,8 +1829,6 @@ static ret_msg_t prepare_and_invoke_hook_to_change_route(pa_stream_manager *m, n hook_call_route_data.stream = NULL; } } - if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data)) - ret = RET_MSG_ERROR_INTERNAL; } else { memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route)); @@ -1842,24 +1849,32 @@ static ret_msg_t prepare_and_invoke_hook_to_change_route(pa_stream_manager *m, n hook_call_route_data.stream = NULL; hook_call_route_data.stream_type = type; } - if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data)) - ret = RET_MSG_ERROR_INTERNAL; } + if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data)) + ret = RET_MSG_ERROR_INTERNAL; + return ret; } static ret_msg_t prepare_and_invoke_hook_to_inform_stream_connection(pa_stream_manager *m, bool is_connected, stream_type_t type, void *s) { pa_stream_manager_hook_data_for_stream hook_call_stream_data; + const char *parent_id; + uint32_t parent_id_u; pa_assert(m); pa_assert(s); + memset(&hook_call_stream_data, 0, sizeof(pa_stream_manager_hook_data_for_stream)); hook_call_stream_data.stream = s; hook_call_stream_data.stream_type = type; hook_call_stream_data.stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE); - hook_call_stream_data.parent_id = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_PARENT_ID); + parent_id = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_PARENT_ID); + if (parent_id && pa_atou(parent_id, &parent_id_u) == 0) + hook_call_stream_data.parent_id = parent_id_u; + else + hook_call_stream_data.parent_id = -1; hook_call_stream_data.is_connected = is_connected; if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_STREAM_CONNECTION_CHANGED), &hook_call_stream_data)) diff --git a/src/stream-manager.h b/src/stream-manager.h index ffb9d34..96b8fb2 100644 --- a/src/stream-manager.h +++ b/src/stream-manager.h @@ -119,6 +119,7 @@ typedef struct _hook_call_data_for_select { const char *stream_role; const char *device_role; const char *occupying_role; + int32_t parent_id; stream_type_t stream_type; stream_route_type_t route_type; pa_sink **proper_sink; @@ -149,7 +150,7 @@ typedef struct _hook_call_data_for_route { typedef struct _hook_call_data_for_stream { void *stream; const char *stream_role; - const char *parent_id; + int32_t parent_id; stream_type_t stream_type; bool is_connected; } pa_stream_manager_hook_data_for_stream; -- 2.7.4 From 64bf38bd9afae04238769bdb724a163e578ee1a2 Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Fri, 19 Mar 2021 08:58:42 +0900 Subject: [PATCH 09/16] tizenaudio-policy: Preparation for new loopback module management [Version] 13.0.59 [Issue Type] Improvement Change-Id: I1fa78fdc41913f0db7e8d08b0ebe4d4c33b21c62 Signed-off-by: Sangchul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-policy.c | 152 ++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 1 deletion(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 0b48635..e0f63c5 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.58 +Version: 13.0.59 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-policy.c b/src/module-tizenaudio-policy.c index c18391c..bb3a727 100644 --- a/src/module-tizenaudio-policy.c +++ b/src/module-tizenaudio-policy.c @@ -150,6 +150,12 @@ static device_type_t convert_device_type_str(const char *device) 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; @@ -172,6 +178,7 @@ struct userdata { 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; @@ -446,6 +453,134 @@ static void update_bt_sco_option(struct userdata *u, const char* role) { } } +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; @@ -1801,6 +1936,16 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_devi 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; @@ -1862,6 +2007,8 @@ int pa__init(pa_module *m) 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"); @@ -1888,6 +2035,11 @@ void pa__done(pa_module *m) 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); -- 2.7.4 From d270f69cd111cc69a4a8d340255ed8ef0b4125ae Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Tue, 6 Apr 2021 11:24:46 +0900 Subject: [PATCH 10/16] tizenaudio-policy: Apply new loopback module management Comparing with the previous logic, it is now possible to load multiple loopback modules. - Each loopback module can be loaded per parent id. - Loading trigger point is moved from route_change_hook_cb() to select_device_by_manual_routing() It relates to VPR-402. [Version] 13.0.60 [Issue Type] New feature Change-Id: I516f541a1af0548b99c2f3c80e98e12756776117 Signed-off-by: Sangchul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-policy.c | 102 +++++++------------------------- src/stream-manager.c | 2 +- 3 files changed, 22 insertions(+), 84 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index e0f63c5..3310887 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.59 +Version: 13.0.60 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-policy.c b/src/module-tizenaudio-policy.c index bb3a727..2efbc89 100644 --- a/src/module-tizenaudio-policy.c +++ b/src/module-tizenaudio-policy.c @@ -182,8 +182,6 @@ struct userdata { struct { int32_t latency_msec; int32_t adjust_sec; - pa_sink *sink; - pa_source *source; } loopback_args; pa_time_event *time_event_bt_sco_close; }; @@ -581,46 +579,6 @@ unload: 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; - const char *volume_type; - - pa_assert(u); - - if (load && u->loopback_args.sink && u->loopback_args.source) { - 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", - u->loopback_args.sink->name, u->loopback_args.source->name, - u->loopback_args.latency_msec, u->loopback_args.adjust_sec, - PA_PROP_MEDIA_TIZEN_VOLUME_TYPE, volume_type); - if (u->module_loopback) - pa_module_unload(u->module_loopback, true); - - if (pa_module_load(&u->module_loopback, u->core, MODULE_LOOPBACK, args)) - pa_log_error("failed to load module-loopback with (%s)", args); - else - pa_log_info(" -- load module-loopback with (%s)", args); - pa_xfree(args); - - } else if (!load) { - if (u->module_loopback) { - pa_module_unload(u->module_loopback, true); - u->module_loopback = NULL; - u->loopback_args.sink = NULL; - u->loopback_args.source = NULL; - pa_log_info(" -- unload module-loopback"); - } - } else { - pa_log_error(" -- failed to update loopback module"); - } -} - static pa_sink *load_combine_sink_module(struct userdata *u, const char *combine_sink_name, pa_sink *sink1, pa_sink *sink2, pa_sink_input *stream) { pa_module **combine_sink_module = NULL; @@ -1016,6 +974,14 @@ static void select_device_by_manual_routing(struct userdata *u, pa_stream_manage else *(data->proper_source) = pa_tz_device_get_source(device, data->device_role); } + /* Update in/out devices for the loopback module arguments and load the module. */ + if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) { + if ((data->stream_type == STREAM_SINK_INPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_OUT)) + update_loopback_module_args(u, data->parent_id, pa_tz_device_get_sink(device, NULL), NULL); + else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_IN)) + update_loopback_module_args(u, data->parent_id, NULL, pa_tz_device_get_source(device, NULL)); + load_loopback_module_by_parent_id(u, data->parent_id); + } } } } @@ -1171,13 +1137,6 @@ static void reset_route(struct userdata *u, stream_type_t stream_type) { pa_assert(u); - if (u->module_loopback) { - if (stream_type == STREAM_SINK_INPUT && u->loopback_args.sink->use_internal_codec) - update_loopback_module(u, false); - else if (stream_type == STREAM_SOURCE_OUTPUT && u->loopback_args.source->use_internal_codec) - update_loopback_module(u, false); - } - /* update BT SCO: close */ update_bt_sco_state(u, false, true, NULL); @@ -1684,13 +1643,6 @@ static pa_hook_result_t handle_manual_routing(struct userdata *u, pa_stream_mana /* update BT SCO: close */ update_bt_sco_state(u, false, false, NULL); } - /* Check for in/out devices in case of loopback */ - if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) { - if ((data->stream_type == STREAM_SINK_INPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_OUT)) - u->loopback_args.sink = pa_tz_device_get_sink(*device, NULL); - else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_IN)) - u->loopback_args.source = pa_tz_device_get_source(*device, NULL); - } if (IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) { if ((use_internal_codec = pa_tz_device_is_use_internal_codec(*device))) @@ -1700,11 +1652,6 @@ static pa_hook_result_t handle_manual_routing(struct userdata *u, pa_stream_mana } } } - if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) { - /* load module-loopback */ - if (u->loopback_args.sink && u->loopback_args.source) - update_loopback_module(u, true); - } return PA_HOOK_OK; } @@ -1767,18 +1714,8 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_ route_info.role = data->stream_role; if (IS_AUTO_ROUTE_TYPE_SERIES(data->route_type)) { - pa_idxset *conn_devices = NULL; - - /* unload module-loopback */ - if (u->module_loopback) { - if (data->stream_type == STREAM_SINK_INPUT && u->loopback_args.sink->use_internal_codec) - update_loopback_module(u, false); - else if (data->stream_type == STREAM_SOURCE_OUTPUT && u->loopback_args.source->use_internal_codec) - update_loopback_module(u, false); - } + pa_idxset *conn_devices = pa_device_manager_get_device_list(u->device_manager); - /* get current connected devices */ - conn_devices = pa_device_manager_get_device_list(u->device_manager); if (data->route_type == STREAM_ROUTE_TYPE_AUTO || data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) { if ((result = handle_auto_or_auto_all_routing(u, data, &route_info, conn_devices, &device))) return result; @@ -1820,6 +1757,13 @@ static pa_hook_result_t stream_connection_changed_hook_cb(pa_core *c, pa_stream_ data->is_connected ? "connected" : "disconnected", data->stream, data->stream_type, data->stream_role, data->parent_id); + if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK) && !data->is_connected) { + pa_sink_input *i = data->stream_type == STREAM_SINK_INPUT ? (pa_sink_input *)data->stream : NULL; + pa_source_output *o = data->stream_type == STREAM_SINK_INPUT ? NULL : (pa_source_output *)data->stream; + + unload_loopback_modules_by_stream_disconnect(u, data->parent_id, i, o); + } + return PA_HOOK_OK; } @@ -1920,17 +1864,11 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_devi /* unload combine sink for external devices */ unload_combine_sink_module(u, SINK_NAME_COMBINED_EX, null_sink); - /* unload loopback module */ - if (u->module_loopback) - if (u->loopback_args.sink == pa_tz_device_get_sink(conn->device, NULL)) - update_loopback_module(u, false); - } - if (device_direction & DM_DEVICE_DIRECTION_IN) { - /* unload loopback module */ - if (u->module_loopback) - if (u->loopback_args.source == pa_tz_device_get_source(conn->device, NULL)) - update_loopback_module(u, false); + unload_loopback_modules_by_device_disconnect(u, pa_tz_device_get_sink(conn->device, NULL), NULL); } + + if (device_direction & DM_DEVICE_DIRECTION_IN) + unload_loopback_modules_by_device_disconnect(u, NULL, pa_tz_device_get_source(conn->device, NULL)); } return PA_HOOK_OK; diff --git a/src/stream-manager.c b/src/stream-manager.c index 15c1191..8043287 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -2103,7 +2103,7 @@ static process_stream_result_t handle_command_prepare(pa_stream_manager *m, void update_preferred_device_role(m, stream, type); /* check if it is a virtual stream */ - if (check_name_is_vstream(stream, type, is_new_data)) { + if (check_name_is_vstream(stream, type, is_new_data) && !pa_safe_streq(role, STREAM_ROLE_LOOPBACK)) { pa_log_debug("skip notifying for selecting sink/source, rather set it to null sink/source"); /* set it to null sink/source */ if (is_new_data) -- 2.7.4 From f49985f02d8d1e49a4e2075f3b9f2d651c571770 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Mon, 29 Mar 2021 14:17:04 +0900 Subject: [PATCH 11/16] aec-manager: Add audio AEC manager added new feature [Version] 13.0.61 [Issue Type] New feature Change-Id: I401390836ee34ea4444180e9725febd1720ac4a4 Signed-off-by: Jaechul Lee --- Makefile.am | 9 ++ configure.ac | 12 ++ packaging/pulseaudio-modules-tizen.spec | 6 +- src/aec-manager.c | 267 ++++++++++++++++++++++++++++++++ src/aec-manager.h | 38 +++++ src/device-manager.c | 24 ++- src/module-tizenaudio-sink.c | 75 ++++++++- src/module-tizenaudio-source.c | 75 ++++++++- 8 files changed, 492 insertions(+), 14 deletions(-) create mode 100644 src/aec-manager.c create mode 100644 src/aec-manager.h diff --git a/Makefile.am b/Makefile.am index e66660b..495578e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,10 @@ AM_LIBADD = $(PTHREAD_LIBS) $(INTLLIBS) AM_LDFLAGS = $(NODELETE_LDFLAGS) MODULE_CFLAGS = $(AM_CFLAGS) $(PACORE_CFLAGS) $(PA_CFLAGS) -D__TIZEN__ +if ENABLE_AEC +MODULE_CFLAGS += -DSUPPORT_AEC +endif + MODULE_LDFLAGS = $(AM_LDFLAGS) $(PACORE_LDFLAGS) $(PA_LDFLAGS) -module -disable-static -avoid-version MODULE_LIBADD = $(AM_LIBADD) $(PACORE_LIBS) $(PA_LIBS) @@ -94,6 +98,11 @@ module_tizenaudio_policy_la_SOURCES = \ src/device-manager-db.c src/device-manager-db-priv.h \ src/tizen-device.c src/tizen-device.h src/tizen-device-def.c src/tizen-device-def.h \ src/subscribe-observer.c src/subscribe-observer.h + +if ENABLE_AEC +module_tizenaudio_policy_la_SOURCES += src/aec-manager.c src/aec-manager.h +endif + module_tizenaudio_policy_la_LDFLAGS = $(MODULE_LDFLAGS) -L$(pulsemodlibexecdir) module_tizenaudio_policy_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS) $(INIPARSER_LIBS) $(LIBJSON_LIBS) libhal-interface.la libcommunicator.la module_tizenaudio_policy_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) $(VCONF_CFLAGS) $(INIPARSER_CFLAGS) $(LIBJSON_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_policy diff --git a/configure.ac b/configure.ac index ac631fa..d1720a3 100644 --- a/configure.ac +++ b/configure.ac @@ -393,6 +393,18 @@ AC_ARG_ENABLE(acm, AC_HELP_STRING([--enable-acm], [using acm]), AM_CONDITIONAL(ENABLE_ACM, test "x$ENABLE_ACM" = "xyes") dnl end -------------------------------------------------------------------- +dnl use aec ---------------------------------------------------------------- +AC_ARG_ENABLE(aec, AC_HELP_STRING([--enable-aec], [using aec]), +[ + case "${enableval}" in + yes) ENABLE_AEC=yes ;; + no) ENABLE_AEC=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-aec) ;; + esac + ],[USE_AEC=no]) +AM_CONDITIONAL(ENABLE_AEC, test "x$ENABLE_AEC" = "xyes") +dnl end -------------------------------------------------------------------- + #### D-Bus support (optional) #### AC_ARG_ENABLE([dbus], diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 3310887..13add09 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.60 +Version: 13.0.61 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ @@ -46,7 +46,9 @@ export LD_AS_NEEDED=0 %reconfigure --prefix=%{_prefix} \ --disable-static \ --enable-acm \ -%if "%{tizen_profile_name}" == "tv" +%if "%{tizen_profile_name}" != "tv" + --enable-aec +%else --enable-vconf-helper %endif # --enable-haltc diff --git a/src/aec-manager.c b/src/aec-manager.c new file mode 100644 index 0000000..8ed96b5 --- /dev/null +++ b/src/aec-manager.c @@ -0,0 +1,267 @@ +/*** + This file is part of PulseAudio. + + Copyright 2021 Jaechul Lee + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "aec-manager.h" + +#define AEC_MANAGER_OBJECT_PATH "/org/pulseaudio/AecManager" +#define AEC_MANAGER_INTERFACE "org.pulseaudio.AecManager" + +#define AEC_MANAGER_METHOD_NAME_ON "On" +#define AEC_MANAGER_METHOD_NAME_OFF "Off" +#define AEC_MANAGER_METHOD_NAME_GET_SINK_PARAMS "GetSinkParam" +#define AEC_MANAGER_METHOD_NAME_GET_SOURCE_PARAMS "GetSourceParam" + +#define AEC_UNIX_SOCKET_PATH "/tmp/.aec.socket" + +static struct aec_manager { + pa_dbus_connection *dbus_conn; + pa_source *source; /* builtin-mic */ + pa_sink *sink; /* builtin-spk */ +} am; + +enum { + SINK_MESSAGE_SET_AEC_STATE = PA_SINK_MESSAGE_MAX, + SINK_MESSAGE_GET_AEC_PARAMS, +}; + +enum { + SOURCE_MESSAGE_SET_AEC_STATE = PA_SOURCE_MESSAGE_MAX, + SOURCE_MESSAGE_GET_AEC_PARAMS, +}; + +#define AEC_MANAGER_INTROSPECT_XML \ + DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ + "" \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + "" + +enum method_handler_index { + METHOD_HANDLER_ON, + METHOD_HANDLER_OFF, + METHOD_HANDLER_GET_SINK_PARAMS, + METHOD_HANDLER_GET_SOURCE_PARAMS, + METHOD_HANDLER_MAX +}; + +static void handle_method_on(DBusConnection *conn, DBusMessage *msg, void *userdata); +static void handle_method_off(DBusConnection *conn, DBusMessage *msg, void *userdata); +static void handle_method_get_sink_params(DBusConnection *conn, DBusMessage *msg, void *userdata); +static void handle_method_get_source_params(DBusConnection *conn, DBusMessage *msg, void *userdata); + +static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = { + [METHOD_HANDLER_ON] = { + .method_name = AEC_MANAGER_METHOD_NAME_ON, + .receive_cb = handle_method_on }, + [METHOD_HANDLER_OFF] = { + .method_name = AEC_MANAGER_METHOD_NAME_OFF, + .receive_cb = handle_method_off }, + [METHOD_HANDLER_GET_SINK_PARAMS] = { + .method_name = AEC_MANAGER_METHOD_NAME_GET_SINK_PARAMS, + .receive_cb = handle_method_get_sink_params }, + [METHOD_HANDLER_GET_SOURCE_PARAMS] = { + .method_name = AEC_MANAGER_METHOD_NAME_GET_SOURCE_PARAMS, + .receive_cb = handle_method_get_source_params }, +}; + +static void send_get_param_reply(DBusConnection *conn, DBusMessage *msg, aec_params_t* param) { + DBusMessage *reply = NULL; + DBusMessageIter msg_iter; + + const char *ptr1 = param->card; + const char *ptr2 = param->device; + + reply = dbus_message_new_method_return(msg); + if (!reply) { + pa_log_error("Failed to alloc reply"); + return; + } + + dbus_message_iter_init_append(reply, &msg_iter); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->rate); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->channels); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->format); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->frag_size); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, ¶m->nfrags); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &ptr1); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &ptr2); + dbus_connection_send(conn, reply, NULL); + + dbus_message_unref(reply); +} + +static void handle_method_on(DBusConnection *conn, DBusMessage *msg, void *userdata) { + pa_asyncmsgq_post(am.sink->asyncmsgq, PA_MSGOBJECT(am.sink), + SINK_MESSAGE_SET_AEC_STATE, (void *)TRUE, 0, NULL, NULL); + pa_asyncmsgq_post(am.source->asyncmsgq, PA_MSGOBJECT(am.source), + SOURCE_MESSAGE_SET_AEC_STATE, (void *)TRUE, 0, NULL, NULL); + + pa_dbus_send_empty_reply(conn, msg); +} + +static void handle_method_off(DBusConnection *conn, DBusMessage *msg, void *userdata) { + pa_asyncmsgq_post(am.sink->asyncmsgq, PA_MSGOBJECT(am.sink), + SINK_MESSAGE_SET_AEC_STATE, (void *)FALSE, 0, NULL, NULL); + pa_asyncmsgq_post(am.source->asyncmsgq, PA_MSGOBJECT(am.source), + SOURCE_MESSAGE_SET_AEC_STATE, (void *)FALSE, 0, NULL, NULL); + + pa_dbus_send_empty_reply(conn, msg); +} + +static void handle_method_get_sink_params(DBusConnection *conn, DBusMessage *msg, void *userdata) { + aec_params_t param; + + pa_asyncmsgq_send(am.sink->asyncmsgq, PA_MSGOBJECT(am.sink), + SINK_MESSAGE_GET_AEC_PARAMS, ¶m, 0, NULL); + + send_get_param_reply(conn, msg, ¶m); +} + +static void handle_method_get_source_params(DBusConnection *conn, DBusMessage *msg, void *userdata) { + aec_params_t param; + + pa_asyncmsgq_send(am.source->asyncmsgq, PA_MSGOBJECT(am.source), + SOURCE_MESSAGE_GET_AEC_PARAMS, ¶m, 0, NULL); + + send_get_param_reply(conn, msg, ¶m); +} + +static DBusHandlerResult method_handler_for_vt(DBusConnection *conn, DBusMessage *m, void *userdata) { + const char *path, *interface, *member; + DBusMessage *r = NULL; + + pa_assert(conn); + pa_assert(m); + + path = dbus_message_get_path(m); + interface = dbus_message_get_interface(m); + member = dbus_message_get_member(m); + + pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member); + + if (!pa_safe_streq(path, AEC_MANAGER_OBJECT_PATH)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) { + r = dbus_message_new_method_return(m); + if (r) { + const char *xml = AEC_MANAGER_INTROSPECT_XML; + dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID); + dbus_connection_send((conn), r, NULL); + dbus_message_unref(r); + } + } else { + int i; + for (i = 0; i < METHOD_HANDLER_MAX; i++) { + if (dbus_message_is_method_call(m, AEC_MANAGER_INTERFACE, + method_handlers[i].method_name)) + method_handlers[i].receive_cb(conn, m, NULL); + } + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +int aec_manager_init(pa_core *core, pa_source *source, pa_sink *sink) { + DBusError err; + pa_dbus_connection *conn = NULL; + static const DBusObjectPathVTable vtable = { + .message_function = method_handler_for_vt, + }; + + if (!source || !sink) { + pa_log_error("AEC init failed. source(%p)/sink(%p) is null.", source, sink); + return -1; + } + + dbus_error_init(&err); + if (!(conn = pa_dbus_bus_get(core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) { + if (conn) + pa_dbus_connection_unref(conn); + + dbus_error_free(&err); + pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message); + return -1; + } + + am.dbus_conn = conn; + if (!dbus_connection_register_object_path(pa_dbus_connection_get(conn), + AEC_MANAGER_OBJECT_PATH, &vtable, NULL)) { + pa_dbus_connection_unref(conn); + pa_log_error("Failed to register object path"); + return -1; + } + + am.source = source; + am.sink = sink; + + pa_log_info("AEC init success"); + + return 0; +} + +void aec_manager_deinit(void) { + if (am.dbus_conn) + pa_dbus_connection_unref(am.dbus_conn); + + pa_log_info("AEC deinit success"); +} diff --git a/src/aec-manager.h b/src/aec-manager.h new file mode 100644 index 0000000..d30f788 --- /dev/null +++ b/src/aec-manager.h @@ -0,0 +1,38 @@ +/*** + This file is part of PulseAudio. + + Copyright 2021 Jaechul Lee + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifndef footizenaecmanagerfoo +#define footizenaecmanagerfoo + +typedef struct aec_params { + int rate; + int channels; + int format; + int frag_size; + int nfrags; + char card[32]; + char device[32]; +} aec_params_t; + +int aec_manager_init(pa_core *core, pa_source *source, pa_sink *sink); +void aec_manager_deinit(); + +#endif diff --git a/src/device-manager.c b/src/device-manager.c index 14b2b89..aef1eee 100644 --- a/src/device-manager.c +++ b/src/device-manager.c @@ -49,6 +49,10 @@ #include "device-manager-dbus-priv.h" #include "device-manager-db-priv.h" +#ifdef SUPPORT_AEC +#include "aec-manager.h" +#endif + #define SHARED_DEVICE_MANAGER "tizen-device-manager" #define DEVICE_MAP_FILE "/etc/pulse/device-map.json" @@ -2905,6 +2909,8 @@ static pa_hook_result_t device_running_changed_hook_cb(pa_core *c, pa_tz_device_ pa_device_manager* pa_device_manager_get(pa_core *c) { pa_device_manager *dm; + pa_source *source; + pa_sink *sink; pa_assert(c); @@ -2961,12 +2967,17 @@ pa_device_manager* pa_device_manager_get(pa_core *c) { } /* Just for convenience when test*/ - if (!_device_manager_set_default_sink(dm, DEVICE_TYPE_SPEAKER, "normal")) { + sink = _device_manager_set_default_sink(dm, DEVICE_TYPE_SPEAKER, "normal"); + if (!sink) pa_log_warn("Set default sink with speaker(normal) failed"); - } - if (!_device_manager_set_default_source(dm, DEVICE_TYPE_MIC, "normal")) { + + source = _device_manager_set_default_source(dm, DEVICE_TYPE_MIC, "normal"); + if (!source) pa_log_warn("Set default source with mic(normal) failed"); - } + +#ifdef SUPPORT_AEC + aec_manager_init(dm->core, source, sink); +#endif pa_shared_set(c, SHARED_DEVICE_MANAGER, dm); @@ -3044,4 +3055,9 @@ void pa_device_manager_unref(pa_device_manager *dm) { pa_shared_remove(dm->core, SHARED_DEVICE_MANAGER); pa_xfree(dm); + +#ifdef SUPPORT_AEC + aec_manager_deinit(); +#endif + } diff --git a/src/module-tizenaudio-sink.c b/src/module-tizenaudio-sink.c index 03f1e4d..c8f1d35 100644 --- a/src/module-tizenaudio-sink.c +++ b/src/module-tizenaudio-sink.c @@ -47,6 +47,10 @@ #include "hal-interface.h" +#ifdef SUPPORT_AEC +#include "aec-manager.h" +#endif + PA_MODULE_AUTHOR("Tizen"); PA_MODULE_DESCRIPTION("Tizen Audio Sink"); PA_MODULE_VERSION(PACKAGE_VERSION); @@ -74,6 +78,13 @@ PA_MODULE_USAGE( #define DEVICE_NAME_MAX 30 +#ifdef SUPPORT_AEC +enum { + PA_SINK_MESSAGE_SET_AEC_STATE = PA_SINK_MESSAGE_MAX, + PA_SINK_MESSAGE_GET_AEC_PARAMS, +}; +#endif + struct userdata { pa_core *core; pa_module *module; @@ -100,6 +111,11 @@ struct userdata { uint64_t write_count; pa_hal_interface *hal_interface; + +#ifdef SUPPORT_AEC + bool aec_enable; + pa_sample_spec ss; +#endif }; static const char* const valid_modargs[] = { @@ -159,7 +175,7 @@ static int suspend(struct userdata *u) { u->rtpoll_item = NULL; } - pa_log_info("Device suspended...[%s,%s]", u->card, u->device); + pa_log_info("Device suspended..."); return 0; } @@ -170,6 +186,9 @@ static int unsuspend(struct userdata *u) { int32_t ret; size_t frame_size; + char *card = u->card; + char *device = u->device; + pa_assert(u); pa_assert(!u->pcm_handle); @@ -182,9 +201,16 @@ static int unsuspend(struct userdata *u) { goto fail; } +#ifdef SUPPORT_AEC + if (u->aec_enable) { + card = "Loopback"; + device = "0,0"; + } +#endif + ret = pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, + card, + device, DIRECTION_OUT, &sample_spec, u->frag_size / frame_size, @@ -201,7 +227,7 @@ static int unsuspend(struct userdata *u) { u->write_count = 0; u->first = true; - pa_log_info("Resumed successfully..."); + pa_log_info("Resumed successfully...device(%s:%s)", card, device); return 0; @@ -278,6 +304,36 @@ static int sink_process_msg( *((pa_usec_t*)data) = latency; return 0; } +#ifdef SUPPORT_AEC + case PA_SINK_MESSAGE_SET_AEC_STATE: { + pa_sink *s = PA_SINK(o); + bool enable = (bool)data; + + if (u->aec_enable == enable) + return 0; + + pa_log_info("AEC enable(%d)", enable); + + u->aec_enable = enable; + if (s->thread_info.state == PA_SINK_RUNNING) { + suspend(u); + unsuspend(u); + } + + return 0; + } + case PA_SINK_MESSAGE_GET_AEC_PARAMS: { + aec_params_t *params = (aec_params_t *)data; + params->rate = u->ss.rate; + params->channels = u->ss.channels; + params->format = u->ss.format; + params->frag_size = u->frag_size; + params->nfrags = u->nfrags; + snprintf(params->card, DEVICE_NAME_MAX, "%s", u->card); + snprintf(params->device, DEVICE_NAME_MAX, "%s", u->device); + return 0; + } +#endif } return pa_sink_process_msg(o, code, data, offset, chunk); @@ -519,6 +575,7 @@ int pa__init(pa_module*m) { const char *modarg_device; char card[DEVICE_NAME_MAX]; char device[DEVICE_NAME_MAX]; + size_t frame_size, buffer_size, period_frames, buffer_frames; pa_assert(m); @@ -546,6 +603,9 @@ int pa__init(pa_module*m) { u->first = true; u->hal_interface = pa_hal_interface_get(u->core); u->rtpoll = pa_rtpoll_new(); +#ifdef SUPPORT_AEC + u->ss = ss; +#endif pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { @@ -595,6 +655,13 @@ int pa__init(pa_module*m) { pa_proplist_sets(data.proplist, "tizen.device", u->device); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); + frame_size = pa_frame_size(&ss); + buffer_size = u->frag_size * u->nfrags; + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); + if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log_error("Invalid properties."); pa_sink_new_data_done(&data); diff --git a/src/module-tizenaudio-source.c b/src/module-tizenaudio-source.c index c0337e0..4ec1330 100644 --- a/src/module-tizenaudio-source.c +++ b/src/module-tizenaudio-source.c @@ -47,6 +47,10 @@ #include "hal-interface.h" +#ifdef SUPPORT_AEC +#include "aec-manager.h" +#endif + PA_MODULE_AUTHOR("Tizen"); PA_MODULE_DESCRIPTION("Tizen Audio Source"); PA_MODULE_VERSION(PACKAGE_VERSION); @@ -70,6 +74,13 @@ PA_MODULE_USAGE( #define DEVICE_NAME_MAX 30 +#ifdef SUPPORT_AEC +enum { + PA_SOURCE_MESSAGE_SET_AEC_STATE = PA_SOURCE_MESSAGE_MAX, + PA_SOURCE_MESSAGE_GET_AEC_PARAMS, +}; +#endif + struct userdata { pa_core *core; pa_module *module; @@ -95,6 +106,11 @@ struct userdata { uint64_t read_count; pa_usec_t latency_time; pa_hal_interface *hal_interface; + +#ifdef SUPPORT_AEC + bool aec_enable; + pa_sample_spec ss; +#endif }; static const char* const valid_modargs[] = { @@ -152,7 +168,7 @@ static int suspend(struct userdata *u) { u->rtpoll_item = NULL; } - pa_log_info("Device suspended...[%s,%s]", u->card, u->device); + pa_log_info("Device suspended..."); return 0; } @@ -163,6 +179,9 @@ static int unsuspend(struct userdata *u) { int32_t ret; size_t frame_size; + char *card = u->card; + char *device = u->device; + pa_assert(u); pa_assert(!u->pcm_handle); @@ -175,9 +194,16 @@ static int unsuspend(struct userdata *u) { goto fail; } +#ifdef SUPPORT_AEC + if (u->aec_enable) { + card = "Loopback"; + device = "1,1"; + } +#endif + ret = pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, + card, + device, DIRECTION_IN, &sample_spec, u->frag_size / frame_size, @@ -194,7 +220,7 @@ static int unsuspend(struct userdata *u) { u->read_count = 0; u->first = true; - pa_log_info("Resumed successfully..."); + pa_log_info("Resumed successfully...device(%s:%s)", card, device); return 0; @@ -265,6 +291,36 @@ static int source_process_msg( *((pa_usec_t*)data) = u->timestamp > now ? 0ULL : now - u->timestamp; return 0; } +#ifdef SUPPORT_AEC + case PA_SOURCE_MESSAGE_SET_AEC_STATE: { + pa_source *s = PA_SOURCE(o); + bool enable = (bool)data; + + if (u->aec_enable == enable) + return 0; + + pa_log_info("AEC enable(%d)", enable); + + u->aec_enable = enable; + if (s->thread_info.state == PA_SOURCE_RUNNING) { + suspend(u); + unsuspend(u); + } + + return 0; + } + case PA_SOURCE_MESSAGE_GET_AEC_PARAMS: { + aec_params_t *params = (aec_params_t *)data; + params->rate = u->ss.rate; + params->channels = u->ss.channels; + params->format = u->ss.format; + params->frag_size = u->frag_size; + params->nfrags = u->nfrags; + snprintf(params->card, DEVICE_NAME_MAX, "%s", u->card); + snprintf(params->device, DEVICE_NAME_MAX, "%s", u->device); + return 0; + } +#endif } return pa_source_process_msg(o, code, data, offset, chunk); @@ -463,6 +519,7 @@ int pa__init(pa_module*m) { const char *modarg_device; char card[DEVICE_NAME_MAX]; char device[DEVICE_NAME_MAX]; + size_t frame_size, buffer_size, period_frames, buffer_frames; pa_assert(m); @@ -490,6 +547,9 @@ int pa__init(pa_module*m) { u->first = true; u->hal_interface = pa_hal_interface_get(u->core); u->rtpoll = pa_rtpoll_new(); +#ifdef SUPPORT_AEC + u->ss = ss; +#endif pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); if (!(modarg_device = pa_modargs_get_value(ma, "device", NULL))) { @@ -526,6 +586,13 @@ int pa__init(pa_module*m) { pa_proplist_sets(data.proplist, "tizen.device", u->device); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); + frame_size = pa_frame_size(&ss); + buffer_size = u->frag_size * u->nfrags; + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); + pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); + if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log_error("Invalid properties."); pa_source_new_data_done(&data); -- 2.7.4 From 6ee4ef64b2d71bedd17136d044868d7ea4b4db2e Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Tue, 27 Apr 2021 20:12:24 +0900 Subject: [PATCH 12/16] device-manager: enhance some if-else cascaded statements [Version] 13.0.62 [Issue Type] Revise Change-Id: I9f8ac0a13e3ee0ed92530f466537e7290e4e16e0 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/device-manager.c | 174 ++++++++++++++++++-------------- 2 files changed, 98 insertions(+), 78 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 13add09..1c4f294 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.61 +Version: 13.0.62 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/device-manager.c b/src/device-manager.c index aef1eee..fbefe47 100644 --- a/src/device-manager.c +++ b/src/device-manager.c @@ -227,6 +227,48 @@ static internal_codec_device internal_codec_devices[DEVICE_INDEX_MAX] = { .is_running[1] = false }, }; +typedef struct _device_module { + const char *module_name[2]; /* in/out */ + const char *device_string; + int (*custom_device_get_func)(pa_object *, char *); +} device_module_t; + +static int pulse_device_get_alsa_device_name(pa_object *pdevice, char *device_name); +static int pulse_device_get_tizen_device_name(pa_object *pdevice, char *device_name); + +static const device_module_t module_table[] = { + [DM_DEVICE_CLASS_NONE] = { + .module_name = { NULL, NULL }, + .device_string = NULL, + .custom_device_get_func = NULL + }, + [DM_DEVICE_CLASS_ALSA] = { + .module_name = { "module-alsa-source", "module-alsa-sink" }, + .device_string = NULL, + .custom_device_get_func = pulse_device_get_alsa_device_name + }, + [DM_DEVICE_CLASS_TIZEN] = { + .module_name = { "module-tizenaudio-source", "module-tizenaudio-sink" }, + .device_string = NULL, + .custom_device_get_func = pulse_device_get_tizen_device_name + }, + [DM_DEVICE_CLASS_BT] = { + .module_name = { NULL, "module-bluez5-device" }, + .device_string = "bt", + .custom_device_get_func = NULL + }, + [DM_DEVICE_CLASS_NULL] = { + .module_name = { "module-null-source", "module-null-sink" }, + .device_string = "null", + .custom_device_get_func = NULL + }, + [DM_DEVICE_CLASS_ACM] = { + .module_name = { NULL, "module-acm-sink" }, + .device_string = "acm", + .custom_device_get_func = NULL + } +}; + void simple_device_dump(pa_log_level_t level, const char *prefix, int id, const char *type, const char *name, int direction, int state) { pa_logl(level, "%s device id(%d) type(%s) name (%s) direction(%d) state(%d)", pa_strempty(prefix), id, pa_strnull(type), pa_strnull(name), direction, state); @@ -555,69 +597,18 @@ static bool pulse_device_is_monitor(pa_object *pdevice) { prop = pulse_device_get_proplist(pdevice); if ((device_class = pa_proplist_gets(prop, PA_PROP_DEVICE_CLASS))) { - if (pa_safe_streq(device_class, DEVICE_CLASS_MONITOR)) { + if (pa_safe_streq(device_class, DEVICE_CLASS_MONITOR)) return true; - } else { - return false; - } - } else { - return false; } -} - -/* Actually this device_name is not exactly same with alsa's form (ex. "hw:0,1") - * this is part of that. (ex. "0,1") */ -static int pulse_device_get_device_name(pa_object *pdevice, char *device_name) { - pa_proplist *prop; - prop = pulse_device_get_proplist(pdevice); - - if (pulse_device_is_alsa(pdevice)) { - const char *device_string_prop; - char *name_p; - - if (!(device_string_prop = pa_proplist_gets(prop, PA_PROP_DEVICE_STRING))) { - pa_log_error("failed to get property 'device.string'"); - return -1; - } - if (!(name_p = strchr(device_string_prop, ':'))) { - pa_log_error("failed to parse device string"); - return -1; - } - strncpy(device_name, name_p + 1, DEVICE_NAME_MAX); - } else if (pulse_device_is_tizenaudio(pdevice)) { - const char *card, *device; - if (!(card = pa_proplist_gets(prop, "tizen.card"))) { - pa_log_error("failed to get property 'tizen.card'"); - return -1; - } - if (!(device = pa_proplist_gets(prop, "tizen.device"))) { - pa_log_error("failed to get property 'tizen.device'"); - return -1; - } - snprintf(device_name, DEVICE_NAME_MAX, "%s,%s", card, device); - } else { - return -1; - } - return 0; + return false; } static const char* device_class_get_module_name(dm_device_class_t device_class, bool is_sink) { - if (device_class == DM_DEVICE_CLASS_NONE) { + if (device_class >= DM_DEVICE_CLASS_MAX) return NULL; - } else if (device_class == DM_DEVICE_CLASS_ALSA) { - return is_sink ? "module-alsa-sink" : "module-alsa-source"; - } else if (device_class == DM_DEVICE_CLASS_TIZEN) { - return is_sink ? "module-tizenaudio-sink" : "module-tizenaudio-source"; - } else if (device_class == DM_DEVICE_CLASS_BT) { - return is_sink ? "module-bluez5-device" : NULL; - } else if (device_class == DM_DEVICE_CLASS_NULL) { - return is_sink ? "module-null-sink" : "module-null-source"; - } else if (device_class == DM_DEVICE_CLASS_ACM) { - return is_sink ? "module-acm-sink" : NULL; - } else { - return NULL; - } + + return module_table[device_class].module_name[is_sink]; } static device_type_info* _device_manager_get_type_info(pa_idxset *type_infos, const char *type, const char *role) { @@ -935,6 +926,45 @@ static bool pulse_device_params_is_equal(pa_object *pdevice, const char *params) return device_params_is_equal(params, removed_module_args); } +static int pulse_device_get_alsa_device_name(pa_object *pdevice, char *device_name) { + pa_proplist *prop; + const char *device_string_prop; + char *name_p; + + prop = pulse_device_get_proplist(pdevice); + + if (!(device_string_prop = pa_proplist_gets(prop, PA_PROP_DEVICE_STRING))) { + pa_log_error("failed to get property 'device.string'"); + return -1; + } + if (!(name_p = strchr(device_string_prop, ':'))) { + pa_log_error("failed to parse device string"); + return -1; + } + + snprintf(device_name, DEVICE_NAME_MAX, "alsa:%s", name_p + 1); + return 0; +} + +static int pulse_device_get_tizen_device_name(pa_object *pdevice, char *device_name) { + pa_proplist *prop; + const char *card, *device; + + prop = pulse_device_get_proplist(pdevice); + + if (!(card = pa_proplist_gets(prop, "tizen.card"))) { + pa_log_error("failed to get property 'tizen.card'"); + return -1; + } + if (!(device = pa_proplist_gets(prop, "tizen.device"))) { + pa_log_error("failed to get property 'tizen.device'"); + return -1; + } + + snprintf(device_name, DEVICE_NAME_MAX, "tizen:%s,%s", card, device); + return 0; +} + static int pulse_device_get_device_string(pa_object *pdevice, char *device_string) { dm_device_class_t device_class; char device_name[DEVICE_NAME_MAX]; @@ -943,29 +973,19 @@ static int pulse_device_get_device_string(pa_object *pdevice, char *device_strin pa_assert(device_string); device_class = pulse_device_get_class(pdevice); + if (device_class <= DM_DEVICE_CLASS_NONE || + device_class >= DM_DEVICE_CLASS_MAX) + return -1; - if (device_class == DM_DEVICE_CLASS_ALSA) { - if (pulse_device_get_device_name(pdevice, device_name) < 0) - return -1; - snprintf(device_string, DEVICE_STR_MAX, "alsa:%s", device_name); - return 0; - } else if (device_class == DM_DEVICE_CLASS_NULL) { - snprintf(device_string, DEVICE_STR_MAX, "null"); - return 0; - } else if (device_class == DM_DEVICE_CLASS_TIZEN) { - if (pulse_device_get_device_name(pdevice, device_name) < 0) - return -1; - snprintf(device_string, DEVICE_STR_MAX, "tizen:%s", device_name); - return 0; - } else if (device_class == DM_DEVICE_CLASS_BT) { - snprintf(device_string, DEVICE_STR_MAX, "bt"); - return 0; - } else if (device_class == DM_DEVICE_CLASS_ACM) { - snprintf(device_string, DEVICE_STR_MAX, "acm"); - return 0; - } else { + if (module_table[device_class].custom_device_get_func && + module_table[device_class].custom_device_get_func(pdevice, device_name) < 0) return -1; - } + + snprintf(device_string, DEVICE_STR_MAX, "%s", + module_table[device_class].device_string ? + module_table[device_class].device_string : device_name); + + return 0; } /* pdevice is sink or source */ -- 2.7.4 From a6bd7d4bde162a37fbfc3a37ddb88458d961fb03 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Tue, 1 Jun 2021 16:55:06 +0900 Subject: [PATCH 13/16] stream/device-manager: use PA_DEFAULT_CONFIG_DIR instead of hardcoding for configuration path [Version] 13.0.63 [Issue Type] New HAL Change-Id: I9e5072c5db449a699b231275883608a55f77f288 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/device-manager.c | 2 +- src/stream-manager.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 1c4f294..7b3abc2 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.62 +Version: 13.0.63 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/device-manager.c b/src/device-manager.c index fbefe47..ef81274 100644 --- a/src/device-manager.c +++ b/src/device-manager.c @@ -55,7 +55,7 @@ #define SHARED_DEVICE_MANAGER "tizen-device-manager" -#define DEVICE_MAP_FILE "/etc/pulse/device-map.json" +#define DEVICE_MAP_FILE PA_DEFAULT_CONFIG_DIR"/device-map.json" #define DEVICE_STR_MAX 40 #define DEVICE_DIRECTION_MAX 3 #define DEVICE_PARAM_STRING_MAX 150 diff --git a/src/stream-manager.c b/src/stream-manager.c index 8043287..fe45e37 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -104,7 +104,7 @@ static const char* notify_command_type_str[] = { [NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED] = "INFORM_STREAM_DISCONNECTED", }; -#define STREAM_MAP_FILE "/etc/pulse/stream-map.json" +#define STREAM_MAP_FILE PA_DEFAULT_CONFIG_DIR"/stream-map.json" #define STREAM_MAP_VOLUMES "volumes" #define STREAM_MAP_VOLUME_TYPE "type" #define STREAM_MAP_VOLUME_IS_FOR_HAL "is-hal-volume" -- 2.7.4 From e4458cd898d6f348101a5f054694484803e30e70 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Thu, 10 Jun 2021 17:40:50 +0900 Subject: [PATCH 14/16] Fix SVACE defect (MEMORY_LEAK.EX) [Version] 13.0.64 [Issue Type] Svace Change-Id: I1535c4d0f48d2be2e6c4fc54c2b30a6c668dd59e --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/device-manager-dbus.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 7b3abc2..d72bf2c 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.63 +Version: 13.0.64 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/device-manager-dbus.c b/src/device-manager-dbus.c index 2bc5dbd..ccab821 100644 --- a/src/device-manager-dbus.c +++ b/src/device-manager-dbus.c @@ -478,6 +478,7 @@ static int handle_bluez_headset_property_changed(DBusConnection *c, DBusMessage } if (_translate_external_value(DEVICE_TYPE_BT_SCO, status, &detected) < 0) { pa_log_warn("failed to translate bt-sco detected value"); + pa_xfree(name); return -1; } handle_device_status_changed(dm, DEVICE_TYPE_BT_SCO, name, dbus_message_get_path(s), detected); -- 2.7.4 From 1fe59e21c6c8f5aac919b7e08dba449ad4ffb503 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Mon, 17 May 2021 17:57:49 +0900 Subject: [PATCH 15/16] tizenaudio-sink/source: write or read by calculated period size instead of fixed time. As this code is workaround code for supporting various hw model such as qualcomm board, will be refactored soon by using parameters given at loading time. In addition, use _hal_sysconfdir instead of _sysconfdir macro in spec [Version] 13.0.65 [Issue Type] Bring-up Change-Id: I96fef562cd7af2a67d3bed90b5db9f4def3edad4 --- packaging/pulseaudio-modules-tizen.spec | 7 +++++-- src/module-tizenaudio-sink.c | 16 ++++++++++++++++ src/module-tizenaudio-source.c | 10 +++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index d72bf2c..067da12 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.64 +Version: 13.0.65 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ @@ -40,7 +40,10 @@ PulseAudio module-acm-sink for sending PCM data to ACM core. %setup -q %build -export CFLAGS="%{optflags} -fno-strict-aliasing -D__TIZEN__ -DSYSCONFDIR=\\\"%{_sysconfdir}\\\" " +export CFLAGS="%{optflags} -fno-strict-aliasing -D__TIZEN__ -DSYSCONFDIR=\\\"%{_hal_sysconfdir}\\\" " +%if "%{tizen_profile_name}" != "tv" + export CFLAGS+=" -DTIZEN_TV"; +%endif export LD_AS_NEEDED=0 %reconfigure --prefix=%{_prefix} \ diff --git a/src/module-tizenaudio-sink.c b/src/module-tizenaudio-sink.c index c8f1d35..62a12d5 100644 --- a/src/module-tizenaudio-sink.c +++ b/src/module-tizenaudio-sink.c @@ -419,11 +419,19 @@ static int process_render(struct userdata *u, pa_usec_t now) { if (u->first) { pa_log_debug("Fill initial buffer"); +#ifdef TIZEN_TV frames_to_write = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec) / frame_size; +#else + frames_to_write = u->frag_size / frame_size; +#endif u->timestamp = u->timestamp_written = now; } else { +#ifdef TIZEN_TV /* Write pcm every 10ms */ frames_to_write = pa_usec_to_bytes((10 * PA_USEC_PER_MSEC), &u->sink->sample_spec) / frame_size; +#else + frames_to_write = (u->frag_size / u->nfrags); +#endif if (frames_to_write > avail) break; } @@ -480,14 +488,22 @@ static void thread_func(void *userdata) { goto fail; if (work_done == 0) { +#ifdef TIZEN_TV pa_rtpoll_set_timer_relative(u->rtpoll, (10 * PA_USEC_PER_MSEC)); +#else + pa_rtpoll_set_timer_relative(u->rtpoll, (20 * PA_USEC_PER_MSEC)); +#endif } else { if (u->first) { pa_log_info("Starting playback."); pa_hal_interface_pcm_start(u->hal_interface, u->pcm_handle); u->first = false; } +#ifdef TIZEN_TV pa_rtpoll_set_timer_relative(u->rtpoll, (10 * PA_USEC_PER_MSEC)); +#else + pa_rtpoll_set_timer_relative(u->rtpoll, (20 * PA_USEC_PER_MSEC)); +#endif } } else { pa_rtpoll_set_timer_disabled(u->rtpoll); diff --git a/src/module-tizenaudio-source.c b/src/module-tizenaudio-source.c index 4ec1330..4beabf5 100644 --- a/src/module-tizenaudio-source.c +++ b/src/module-tizenaudio-source.c @@ -365,9 +365,13 @@ static int process_render(struct userdata *u, pa_usec_t now) { break; } +#ifdef TIZEN_TV 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); +#else + frames_to_read = (u->frag_size / u->nfrags); + chunk.length = frames_to_read * frame_size; +#endif chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length); if (frames_to_read > (size_t)avail) @@ -431,7 +435,11 @@ static void thread_func(void *userdata) { goto fail; if (work_done == 0) { +#ifdef TIZEN_TV pa_rtpoll_set_timer_relative(u->rtpoll, (10 * PA_USEC_PER_MSEC)); +#else + pa_rtpoll_set_timer_relative(u->rtpoll, (20 * PA_USEC_PER_MSEC)); +#endif } else { pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp); } -- 2.7.4 From 78efdc4a4b432f70f7b31cf5fdc2e83e9386f4ab Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Tue, 29 Jun 2021 21:35:46 +0900 Subject: [PATCH 16/16] fixup! tizenaudio-sink/source: write or read by calculated period size instead of fixed time. [Version] 13.0.66 [Issue Type] Bug Change-Id: I59f0fe0901e6f07a9a071cd29f08e681162dc527 --- packaging/pulseaudio-modules-tizen.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 067da12..aeedf99 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.65 +Version: 13.0.66 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ @@ -41,7 +41,7 @@ PulseAudio module-acm-sink for sending PCM data to ACM core. %build export CFLAGS="%{optflags} -fno-strict-aliasing -D__TIZEN__ -DSYSCONFDIR=\\\"%{_hal_sysconfdir}\\\" " -%if "%{tizen_profile_name}" != "tv" +%if "%{tizen_profile_name}" == "tv" export CFLAGS+=" -DTIZEN_TV"; %endif -- 2.7.4