2 This file is part of PulseAudio.
4 Copyright 2015 Sangchul Lee <sc11.lee@samsung.com>
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
34 #include <pulse/xmalloc.h>
35 #include <pulse/proplist.h>
37 #include <pulsecore/module.h>
38 #include <pulsecore/log.h>
39 #include <pulsecore/sink.h>
40 #include <pulsecore/modargs.h>
41 #include <pulsecore/macro.h>
44 #include "stream-manager.h"
45 #include "stream-manager-priv.h"
46 #include "stream-manager-volume-priv.h"
49 #define ARR_ARG_MAX 32
50 #define STREAM_MANAGER_OBJECT_PATH "/org/pulseaudio/StreamManager"
51 #define STREAM_MANAGER_INTERFACE "org.pulseaudio.StreamManager"
52 #define STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO "GetStreamInfo"
53 #define STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST "GetStreamList"
54 #define STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES "SetStreamRouteDevices"
55 #define STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION "SetStreamRouteOption"
56 #define STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL "SetVolumeLevel"
57 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL "GetVolumeLevel"
58 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL "GetVolumeMaxLevel"
59 #define STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE "SetVolumeMute"
60 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE "GetVolumeMute"
61 #define STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE "GetCurrentVolumeType" /* the type that belongs to the stream of the current max priority */
63 #define GET_STREAM_NEW_PROPLIST(stream, type) \
64 (type == STREAM_SINK_INPUT? ((pa_sink_input_new_data*)stream)->proplist : ((pa_source_output_new_data*)stream)->proplist)
66 #define GET_STREAM_PROPLIST(stream, type) \
67 (type == STREAM_SINK_INPUT? ((pa_sink_input*)stream)->proplist : ((pa_source_output*)stream)->proplist)
69 #define GET_STREAM_NEW_SAMPLE_SPEC(stream, type) \
70 (type == STREAM_SINK_INPUT? ((pa_sink_input_new_data*)stream)->sample_spec : ((pa_source_output_new_data*)stream)->sample_spec)
72 #define GET_STREAM_SAMPLE_SPEC(stream, type) \
73 (type == STREAM_SINK_INPUT? ((pa_sink_input*)stream)->sample_spec : ((pa_source_output*)stream)->sample_spec)
76 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata);
77 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
78 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata);
79 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata);
80 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
81 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata);
82 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata);
83 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
84 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
85 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
86 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
87 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
88 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata);
90 enum method_handler_index {
91 METHOD_HANDLER_GET_STREAM_INFO,
92 METHOD_HANDLER_GET_STREAM_LIST,
93 METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES,
94 METHOD_HANDLER_SET_STREAM_ROUTE_OPTION,
95 METHOD_HANDLER_SET_VOLUME_LEVEL,
96 METHOD_HANDLER_GET_VOLUME_LEVEL,
97 METHOD_HANDLER_GET_VOLUME_MAX_LEVEL,
98 METHOD_HANDLER_SET_VOLUME_MUTE,
99 METHOD_HANDLER_GET_VOLUME_MUTE,
100 METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE,
104 static pa_dbus_arg_info get_stream_info_args[] = { { "stream_type", "s", "in" },
105 { "priority", "i", "out" },
106 { "route_type", "i", "out" },
107 { "avail_in_devices", "as", "out" },
108 { "avail_out_devices", "as", "out" },
109 { "avail_frameworks", "as", "out"} };
110 static pa_dbus_arg_info get_stream_list_args[] = { { "stream_type", "as", "out" },
111 { "priority", "ai", "out" } };
112 static pa_dbus_arg_info set_stream_route_devices_args[] = { { "parent_id", "u", "in" },
113 { "route_in_devices", "au", "in" },
114 { "route_out_devices", "au", "in" },
115 { "ret_msg", "s", "out" } };
116 static pa_dbus_arg_info set_stream_route_option_args[] = { { "parent_id", "u", "in" },
117 { "name", "s", "in" },
118 { "value", "i", "in" },
119 { "ret_msg", "s", "out" } };
120 static pa_dbus_arg_info set_volume_level_args[] = { { "io_direction", "s", "in" },
121 { "type", "s", "in" },
122 { "level", "u", "in" },
123 { "ret_msg", "s", "out" } };
124 static pa_dbus_arg_info get_volume_level_args[] = { { "io_direction", "s", "in" },
125 { "type", "s", "in" },
126 { "level", "u", "out" },
127 { "ret_msg", "s", "out" } };
128 static pa_dbus_arg_info get_volume_max_level_args[] = { { "io_direction", "s", "in" },
129 { "type", "s", "in" },
130 { "level", "u", "out" },
131 { "ret_msg", "s", "out" } };
132 static pa_dbus_arg_info set_volume_mute_args[] = { { "io_direction", "s", "in" },
133 { "type", "s", "in" },
134 { "on/off", "u", "in" },
135 { "ret_msg", "s", "out" } };
136 static pa_dbus_arg_info get_volume_mute_args[] = { { "io_direction", "s", "in" },
137 { "type", "s", "in" },
138 { "on/off", "u", "out" },
139 { "ret_msg", "s", "out" } };
140 static pa_dbus_arg_info get_current_volume_type_args[] = { { "io_direction", "s", "in" },
141 { "type", "s", "out" },
142 { "ret_msg", "s", "out" } };
143 static const char* signature_args_for_in[] = { "s", "", "uauau", "usi", "ssu", "ss", "ss", "ssu", "ss", "s"};
145 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
146 [METHOD_HANDLER_GET_STREAM_INFO] = {
147 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO,
148 .arguments = get_stream_info_args,
149 .n_arguments = sizeof(get_stream_info_args) / sizeof(pa_dbus_arg_info),
150 .receive_cb = handle_get_stream_info },
151 [METHOD_HANDLER_GET_STREAM_LIST] = {
152 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST,
153 .arguments = get_stream_list_args,
154 .n_arguments = sizeof(get_stream_list_args) / sizeof(pa_dbus_arg_info),
155 .receive_cb = handle_get_stream_list },
156 [METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES] = {
157 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES,
158 .arguments = set_stream_route_devices_args,
159 .n_arguments = sizeof(set_stream_route_devices_args) / sizeof(pa_dbus_arg_info),
160 .receive_cb = handle_set_stream_route_devices },
161 [METHOD_HANDLER_SET_STREAM_ROUTE_OPTION] = {
162 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION,
163 .arguments = set_stream_route_option_args,
164 .n_arguments = sizeof(set_stream_route_option_args) / sizeof(pa_dbus_arg_info),
165 .receive_cb = handle_set_stream_route_option },
166 [METHOD_HANDLER_SET_VOLUME_LEVEL] = {
167 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL,
168 .arguments = set_volume_level_args,
169 .n_arguments = sizeof(set_volume_level_args) / sizeof(pa_dbus_arg_info),
170 .receive_cb = handle_set_volume_level },
171 [METHOD_HANDLER_GET_VOLUME_LEVEL] = {
172 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL,
173 .arguments = get_volume_level_args,
174 .n_arguments = sizeof(get_volume_level_args) / sizeof(pa_dbus_arg_info),
175 .receive_cb = handle_get_volume_level },
176 [METHOD_HANDLER_GET_VOLUME_MAX_LEVEL] = {
177 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL,
178 .arguments = get_volume_max_level_args,
179 .n_arguments = sizeof(get_volume_max_level_args) / sizeof(pa_dbus_arg_info),
180 .receive_cb = handle_get_volume_max_level },
181 [METHOD_HANDLER_SET_VOLUME_MUTE] = {
182 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE,
183 .arguments = set_volume_mute_args,
184 .n_arguments = sizeof(set_volume_mute_args) / sizeof(pa_dbus_arg_info),
185 .receive_cb = handle_set_volume_mute },
186 [METHOD_HANDLER_GET_VOLUME_MUTE] = {
187 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE,
188 .arguments = get_volume_mute_args,
189 .n_arguments = sizeof(get_volume_mute_args) / sizeof(pa_dbus_arg_info),
190 .receive_cb = handle_get_volume_mute },
191 [METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE] = {
192 .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE,
193 .arguments = get_current_volume_type_args,
194 .n_arguments = sizeof(get_current_volume_type_args) / sizeof(pa_dbus_arg_info),
195 .receive_cb = handle_get_current_volume_type },
198 const char *dbus_str_none = "none";
199 const char* stream_manager_dbus_ret_str[] = {"STREAM_MANAGER_RETURN_OK","STREAM_MANAGER_RETURN_ERROR", "STREAM_MANAGER_RETURN_ERROR_NO_STREAM"};
203 RET_MSG_INDEX_ERROR_NO_STREAM,
206 #ifdef USE_DBUS_PROTOCOL
208 static pa_dbus_interface_info stream_manager_interface_info = {
209 .name = STREAM_MANAGER_INTERFACE,
210 .method_handlers = method_handlers,
211 .n_method_handlers = METHOD_HANDLER_MAX,
212 .property_handlers = ,
213 .n_property_handlers = ,
214 .get_all_properties_cb =,
221 #define STREAM_MGR_INTROSPECT_XML \
222 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
224 " <interface name=\"STREAM_MANAGER_INTERFACE\">" \
225 " <method name=\"STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO\">" \
226 " <arg name=\"stream_type\" direction=\"in\" type=\"s\"/>" \
227 " <arg name=\"priority\" direction=\"out\" type=\"i\"/>" \
228 " <arg name=\"route_type\" direction=\"out\" type=\"i\"/>" \
229 " <arg name=\"avail_in_devices\" direction=\"out\" type=\"as\"/>" \
230 " <arg name=\"avail_out_devices\" direction=\"out\" type=\"as\"/>" \
231 " <arg name=\"avail_frameworks\" direction=\"out\" type=\"as\"/>" \
233 " <method name=\"STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST\">" \
234 " <arg name=\"stream_type\" direction=\"in\" type=\"as\"/>" \
235 " <arg name=\"priority\" direction=\"in\" type=\"ai\"/>" \
237 " <method name=\"STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES\">"\
238 " <arg name=\"parent_id\" direction=\"in\" type=\"u\"/>" \
239 " <arg name=\"route_in_devices\" direction=\"in\" type=\"au\"/>" \
240 " <arg name=\"route_out_devices\" direction=\"in\" type=\"au\"/>" \
241 " <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
243 " <method name=\"STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION\">" \
244 " <arg name=\"parent_id\" direction=\"in\" type=\"u\"/>" \
245 " <arg name=\"name\" direction=\"in\" type=\"s\"/>" \
246 " <arg name=\"value\" direction=\"in\" type=\"i\"/>" \
247 " <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
249 " <method name=\"STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL\">" \
250 " <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>" \
251 " <arg name=\"type\" direction=\"in\" type=\"s\"/>" \
252 " <arg name=\"level\" direction=\"in\" type=\"u\"/>" \
253 " <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
255 " <method name=\"STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL\">" \
256 " <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>" \
257 " <arg name=\"type\" direction=\"in\" type=\"s\"/>" \
258 " <arg name=\"level\" direction=\"out\" type=\"u\"/>" \
259 " <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
261 " <method name=\"STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL\">" \
262 " <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>" \
263 " <arg name=\"type\" direction=\"in\" type=\"s\"/>" \
264 " <arg name=\"level\" direction=\"out\" type=\"u\"/>" \
265 " <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
267 " <method name=\"STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE\">" \
268 " <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>" \
269 " <arg name=\"type\" direction=\"in\" type=\"s\"/>" \
270 " <arg name=\"on/off\" direction=\"in\" type=\"u\"/>" \
271 " <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
273 " <method name=\"STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE\">" \
274 " <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>" \
275 " <arg name=\"type\" direction=\"in\" type=\"s\"/>" \
276 " <arg name=\"on/off\" direction=\"out\" type=\"u\"/>" \
277 " <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
279 " <method name=\"STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE\">" \
280 " <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>" \
281 " <arg name=\"type\" direction=\"out\" type=\"s\"/>" \
282 " <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
285 " <interface name=\"org.freedesktop.DBus.Introspectable\">" \
286 " <method name=\"Introspect\">" \
287 " <arg name=\"data\" type=\"s\" direction=\"out\"/>" \
295 #define STREAM_MANAGER_CLIENT_NAME "SOUND_MANAGER_STREAM_INFO"
297 typedef enum pa_process_stream_result {
298 PA_PROCESS_STREAM_OK,
299 PA_PROCESS_STREAM_STOP,
300 PA_PROCESS_STREAM_SKIP,
301 } pa_process_stream_result_t;
303 typedef enum _process_command_type {
304 PROCESS_COMMAND_PREPARE,
305 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA,
306 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED,
307 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED,
308 PROCESS_COMMAND_UPDATE_VOLUME,
309 PROCESS_COMMAND_ADD_PARENT_ID,
310 PROCESS_COMMAND_REMOVE_PARENT_ID,
311 } process_command_type_t;
313 typedef enum _notify_command_type {
314 NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT,
315 NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA,
316 NOTIFY_COMMAND_CHANGE_ROUTE_START,
317 NOTIFY_COMMAND_CHANGE_ROUTE_END,
318 NOTIFY_COMMAND_UPDATE_ROUTE_OPTION,
319 NOTIFY_COMMAND_INFORM_STREAM_CONNECTED,
320 NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED,
321 } notify_command_type_t;
323 const char* process_command_type_str[] = {
325 "CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA",
326 "CHANGE_ROUTE_BY_STREAM_STARTED",
327 "CHANGE_ROUTE_BY_STREAM_ENDED",
333 const char* notify_command_type_str[] = {
334 "SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT",
335 "CHANGE_ROUTE_START_WITH_NEW_DATA",
336 "CHANGE_ROUTE_START",
338 "UPDATE_ROUTE_OPTION",
339 "INFORM_STREAM_CONNECTED",
340 "INFORM_STREAM_DISCONNECTED",
343 #define STREAM_MAP_FILE "/etc/pulse/stream-map.json"
344 #define STREAM_MAP_STREAMS "streams"
345 #define STREAM_MAP_STREAM_ROLE "role"
346 #define STREAM_MAP_STREAM_PRIORITY "priority"
347 #define STREAM_MAP_STREAM_ROUTE_TYPE "route-type"
348 #define STREAM_MAP_STREAM_DIRECTIONS "directions"
349 #define STREAM_MAP_STREAM_VOLUME_TYPES "volume-types"
350 #define STREAM_MAP_STREAM_VOLUME_TYPE_IN "in"
351 #define STREAM_MAP_STREAM_VOLUME_TYPE_OUT "out"
352 #define STREAM_MAP_STREAM_VOLUME_IS_FOR_HAL "is-hal-volume"
353 #define STREAM_MAP_STREAM_CAPTURE_VOLUME_TYPE "capture-volume-type"
354 #define STREAM_MAP_STREAM_PLAYBACK_VOLUME_TYPE "playback-volume-type"
355 #define STREAM_MAP_STREAM_AVAIL_IN_DEVICES "avail-in-devices"
356 #define STREAM_MAP_STREAM_AVAIL_OUT_DEVICES "avail-out-devices"
357 #define STREAM_MAP_STREAM_AVAIL_FRAMEWORKS "avail-frameworks"
359 typedef struct _stream_parent {
360 pa_idxset *idx_sink_inputs;
361 pa_idxset *idx_source_outputs;
362 pa_idxset *idx_route_in_devices;
363 pa_idxset *idx_route_out_devices;
366 #define AVAIL_DEVICES_MAX 16
367 #define AVAIL_FRAMEWORKS_MAX 16
368 #define AVAIL_STREAMS_MAX 32
369 typedef struct _stream_info_per_type {
372 int32_t num_of_in_devices;
373 int32_t num_of_out_devices;
374 int32_t num_of_frameworks;
375 char *avail_in_devices[AVAIL_DEVICES_MAX];
376 char *avail_out_devices[AVAIL_DEVICES_MAX];
377 char *avail_frameworks[AVAIL_FRAMEWORKS_MAX];
378 } stream_info_per_type;
379 typedef struct _stream_list {
380 int32_t num_of_streams;
381 char* types[AVAIL_STREAMS_MAX];
382 int32_t priorities[AVAIL_STREAMS_MAX];
384 typedef struct _stream_route_option {
387 } stream_route_option;
389 static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, void *user_data);
390 static pa_process_stream_result_t process_stream(stream_type_t type, void *stream, process_command_type_t command, pa_stream_manager *m);
392 static int get_available_streams_from_map(pa_stream_manager *m, stream_list *list) {
394 stream_info *s = NULL;
398 pa_log_info("get_available_streams_from_map");
400 while ((s = pa_hashmap_iterate(m->stream_map, &state, (const void**)&role))) {
401 if (i < AVAIL_STREAMS_MAX) {
402 list->priorities[i] = s->priority;
403 list->types[i++] = role;
404 pa_log_debug(" [%d] stream_type[%s], priority[%d]", i-1, role, s->priority);
406 pa_log_error(" out of range, [%d]", i);
410 list->num_of_streams = i;
411 pa_log_debug(" num_of_streams[%d]",i);
413 pa_log_error("stream_map is not initialized..");
419 static int get_stream_info_from_map(pa_stream_manager *m, const char *stream_role, stream_info_per_type *info) {
422 stream_info *s = NULL;
426 pa_log_info("get_stream_info_from_map : role[%s]", stream_role);
428 s = pa_hashmap_get(m->stream_map, stream_role);
430 info->priority = s->priority;
431 info->route_type = s->route_type;
432 PA_IDXSET_FOREACH(name, s->idx_avail_in_devices, idx) {
433 pa_log_debug(" avail-in-device[%d] name : %s", i, name);
434 if (i < AVAIL_DEVICES_MAX)
435 info->avail_in_devices[i++] = name;
437 pa_log_error(" avail-in-devices, out of range, [%d]", i);
439 info->num_of_in_devices = i;
440 PA_IDXSET_FOREACH(name, s->idx_avail_out_devices, idx) {
441 pa_log_debug(" avail-out-device[%d] name : %s", j, name);
442 if (j < AVAIL_DEVICES_MAX)
443 info->avail_out_devices[j++] = name;
445 pa_log_error(" avail-out-devices, out of range, [%d]", j);
447 info->num_of_out_devices = j;
448 PA_IDXSET_FOREACH(name, s->idx_avail_frameworks, idx) {
449 pa_log_debug(" avail-frameworks[%d] name : %s", k, name);
450 if (k < AVAIL_FRAMEWORKS_MAX)
451 info->avail_frameworks[k++] = name;
453 pa_log_error(" avail-frameworks, out of range, [%d]", k);
455 info->num_of_frameworks = k;
458 pa_log_error("stream_map is not initialized..");
465 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
466 const char *xml = STREAM_MGR_INTROSPECT_XML;
467 DBusMessage *r = NULL;
473 pa_assert_se(r = dbus_message_new_method_return(msg));
474 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
477 pa_assert_se(dbus_connection_send((conn), r, NULL));
478 dbus_message_unref(r);
481 return DBUS_HANDLER_RESULT_HANDLED;
484 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
486 DBusMessage *reply = NULL;
487 DBusMessageIter msg_iter;
488 pa_stream_manager *m = (pa_stream_manager*)userdata;
493 pa_assert_se(dbus_message_get_args(msg, NULL,
495 pa_log_info("handle_get_stream_list() dbus method is called");
497 memset(&list, 0, sizeof(stream_list));
498 pa_assert_se((reply = dbus_message_new_method_return(msg)));
499 dbus_message_iter_init_append(reply, &msg_iter);
500 if(!get_available_streams_from_map(m, &list)) {
501 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &list.types, list.num_of_streams);
502 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, &list.priorities, list.num_of_streams);
504 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
505 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, NULL, 0);
507 pa_assert_se(dbus_connection_send(conn, reply, NULL));
508 dbus_message_unref(reply);
511 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata) {
513 stream_info_per_type info;
514 DBusMessage *reply = NULL;
515 DBusMessageIter msg_iter;
516 pa_stream_manager *m = (pa_stream_manager*)userdata;
522 pa_assert_se(dbus_message_get_args(msg, NULL,
523 DBUS_TYPE_STRING, &type,
525 pa_log_info("handle_get_stream_info(), type[%s]", type);
526 memset(&info, 0, sizeof(stream_info_per_type));
527 pa_assert_se((reply = dbus_message_new_method_return(msg)));
528 dbus_message_iter_init_append(reply, &msg_iter);
529 if(!get_stream_info_from_map(m, type, &info)) {
530 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
531 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
532 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
533 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
534 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
536 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, 0);
537 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, 0);
538 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
539 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
540 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
542 pa_assert_se(dbus_connection_send(conn, reply, NULL));
543 dbus_message_unref(reply);
546 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata) {
549 uint32_t *in_device_list = NULL;
550 uint32_t *out_device_list = NULL;
552 int list_len_out = 0;
554 uint32_t *device_id = NULL;
555 stream_parent *sp = NULL;
556 DBusMessage *reply = NULL;
557 pa_stream_manager *m = (pa_stream_manager*)userdata;
563 pa_assert_se(dbus_message_get_args(msg, NULL,
564 DBUS_TYPE_UINT32, &id,
565 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &in_device_list, &list_len_in,
566 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &out_device_list, &list_len_out,
568 pa_log_info("handle_set_stream_route_devices(), id[%u], in_device_list[%p]:length[%d], out_device_list[%p]:length[%d]",
569 id, in_device_list, list_len_in, out_device_list, list_len_out);
571 pa_assert_se((reply = dbus_message_new_method_return(msg)));
573 sp = pa_hashmap_get(m->stream_parents, (const void*)id);
575 if (!in_device_list && !out_device_list) {
576 pa_log_error("invalid arguments");
580 if (sp->idx_route_in_devices) {
581 PA_IDXSET_FOREACH(device_id, sp->idx_route_in_devices, idx) {
582 pa_idxset_remove_by_data(sp->idx_route_in_devices, device_id, NULL);
585 if (in_device_list && list_len_in) {
586 for (i = 0; i < list_len_in; i++) {
587 pa_idxset_put(sp->idx_route_in_devices, pa_xmemdup(&in_device_list[i], sizeof(uint32_t)), NULL);
588 pa_log_debug(" -- [in] device id:%u", in_device_list[i]);
591 if (m->cur_highest_priority.source_output) {
592 /* if any stream that belongs to this id has been activated, do notify right away */
593 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
594 pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the route change",
595 (m->cur_highest_priority.source_output)->index, id);
596 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, m->cur_highest_priority.source_output);
600 pa_log_error("failed to update, idx_route_in_devices[%p]", sp->idx_route_in_devices);
604 if (sp->idx_route_out_devices) {
605 PA_IDXSET_FOREACH(device_id, sp->idx_route_out_devices, idx) {
606 pa_idxset_remove_by_data(sp->idx_route_out_devices, device_id, NULL);
609 if (out_device_list && list_len_out) {
610 for (i = 0; i < list_len_out; i++) {
611 pa_idxset_put(sp->idx_route_out_devices, pa_xmemdup(&out_device_list[i], sizeof(uint32_t)), NULL);
612 pa_log_debug(" -- [out] device id:%u", out_device_list[i]);
615 if (m->cur_highest_priority.sink_input) {
616 /* if any stream that belongs to this id has been activated, do notify right away */
617 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
618 pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the route change",
619 (m->cur_highest_priority.sink_input)->index, id);
620 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, m->cur_highest_priority.sink_input);
624 pa_log_error("failed to update, idx_route_out_devices[%p]", sp->idx_route_out_devices);
627 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
629 pa_log_error("could not find matching client for this parent_id[%u]", id);
633 pa_assert_se(dbus_connection_send(conn, reply, NULL));
634 dbus_message_unref(reply);
637 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
638 pa_assert_se(dbus_connection_send(conn, reply, NULL));
639 dbus_message_unref(reply);
643 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata) {
645 const char *name = NULL;
647 pa_bool_t updated = FALSE;
648 stream_parent *sp = NULL;
649 stream_route_option route_option;
650 DBusMessage *reply = NULL;
651 pa_stream_manager *m = (pa_stream_manager*)userdata;
657 pa_assert_se(dbus_message_get_args(msg, NULL,
658 DBUS_TYPE_UINT32, &id,
659 DBUS_TYPE_STRING, &name,
660 DBUS_TYPE_INT32, &value,
662 pa_log_info("handle_set_stream_route_option(), name[%s], value[%d]", name, value);
664 pa_assert_se((reply = dbus_message_new_method_return(msg)));
666 sp = pa_hashmap_get(m->stream_parents, (const void*)id);
669 route_option.name = name;
670 route_option.value = value;
672 /* if any stream that belongs to this id has been activated, do notify right away */
673 if (m->cur_highest_priority.sink_input) {
674 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
675 pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the options",
676 (m->cur_highest_priority.sink_input)->index, id);
677 do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, &route_option);
681 if (m->cur_highest_priority.source_output) {
682 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
683 pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the options",
684 (m->cur_highest_priority.source_output)->index, id);
685 do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SOURCE_OUTPUT, &route_option);
690 pa_log_error("invalid state");
691 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
693 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
695 pa_log_error("invalid arguments");
696 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
700 pa_log_error("could not find matching client for this parent_id[%u]", id);
701 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
704 pa_assert_se(dbus_connection_send(conn, reply, NULL));
705 dbus_message_unref(reply);
709 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level) {
710 DBusMessage *signal_msg;
711 DBusMessageIter msg_iter;
714 pa_assert(volume_type);
716 pa_log_debug("Send volume changed signal : direction %s, type %s, level %d", direction, volume_type, volume_level);
718 pa_assert_se(signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, "VolumeChanged"));
719 dbus_message_iter_init_append(signal_msg, &msg_iter);
721 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &direction);
722 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &volume_type);
723 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &volume_level);
725 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
726 dbus_message_unref(signal_msg);
730 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
731 const char *direction = NULL;
732 const char *type = NULL;
734 stream_type_t stream_type = STREAM_SINK_INPUT;
735 DBusMessage *reply = NULL;
736 pa_stream_manager *m = (pa_stream_manager*)userdata;
743 pa_assert_se(dbus_message_get_args(msg, NULL,
744 DBUS_TYPE_STRING, &direction,
745 DBUS_TYPE_STRING, &type,
746 DBUS_TYPE_UINT32, &level,
748 pa_log_info("handle_set_volume_level(), direction[%s], type[%s], level[%u]", direction, type, level);
750 pa_assert_se((reply = dbus_message_new_method_return(msg)));
752 if (pa_streq(direction, "in"))
753 stream_type = STREAM_SOURCE_OUTPUT;
754 else if (pa_streq(direction, "out"))
755 stream_type = STREAM_SINK_INPUT;
757 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
761 if ((ret = set_volume_level_by_type(m, stream_type, type, level)))
762 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
764 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
767 pa_assert_se(dbus_connection_send(conn, reply, NULL));
768 dbus_message_unref(reply);
771 send_volume_changed_signal(conn, direction, type, level);
775 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
776 const char *direction = NULL;
777 const char *type = NULL;
779 stream_type_t stream_type = STREAM_SINK_INPUT;
780 DBusMessage *reply = NULL;
781 pa_stream_manager *m = (pa_stream_manager*)userdata;
786 pa_assert_se(dbus_message_get_args(msg, NULL,
787 DBUS_TYPE_STRING, &direction,
788 DBUS_TYPE_STRING, &type,
790 pa_log_info("handle_get_volume_level(), direction(%s), type(%s)", direction, type);
792 pa_assert_se((reply = dbus_message_new_method_return(msg)));
794 if (pa_streq(direction, "in"))
795 stream_type = STREAM_SOURCE_OUTPUT;
796 else if (pa_streq(direction, "out"))
797 stream_type = STREAM_SINK_INPUT;
799 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
800 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
804 if (get_volume_level_by_type(m, GET_VOLUME_CURRENT_LEVEL, stream_type, type, &level)) {
805 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
806 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
808 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
809 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
813 pa_assert_se(dbus_connection_send(conn, reply, NULL));
814 dbus_message_unref(reply);
818 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
819 const char *direction = NULL;
820 const char *type = NULL;
822 stream_type_t stream_type = STREAM_SINK_INPUT;
823 DBusMessage *reply = NULL;
824 pa_stream_manager *m = (pa_stream_manager*)userdata;
830 pa_assert_se(dbus_message_get_args(msg, NULL,
831 DBUS_TYPE_STRING, &direction,
832 DBUS_TYPE_STRING, &type,
834 pa_log_info("handle_get_volume_max_level(), direction[%s], type[%s]", direction, type);
836 pa_assert_se((reply = dbus_message_new_method_return(msg)));
838 if (pa_streq(direction, "in"))
839 stream_type = STREAM_SOURCE_OUTPUT;
840 else if (pa_streq(direction, "out"))
841 stream_type = STREAM_SINK_INPUT;
843 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
844 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
848 if (get_volume_level_by_type(m, GET_VOLUME_MAX_LEVEL, stream_type, type, &level)) {
849 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
850 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
852 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
853 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
856 pa_assert_se(dbus_connection_send(conn, reply, NULL));
857 dbus_message_unref(reply);
861 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
862 const char *direction = NULL;
863 const char *type = NULL;
864 uint32_t do_mute = 0;
865 stream_type_t stream_type = STREAM_SINK_INPUT;
866 DBusMessage *reply = NULL;
867 pa_stream_manager *m = (pa_stream_manager*)userdata;
873 pa_assert_se(dbus_message_get_args(msg, NULL,
874 DBUS_TYPE_STRING, &direction,
875 DBUS_TYPE_STRING, &type,
876 DBUS_TYPE_UINT32, &do_mute,
878 pa_log_info("handle_set_volume_mute(), direction[%s], type[%s], do_mute[%u]", direction, type, do_mute);
880 pa_assert_se((reply = dbus_message_new_method_return(msg)));
882 if (pa_streq(direction, "in"))
883 stream_type = STREAM_SOURCE_OUTPUT;
884 else if (pa_streq(direction, "out"))
885 stream_type = STREAM_SINK_INPUT;
887 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
891 if (set_volume_mute_by_type(m, stream_type, type, (pa_bool_t)do_mute))
892 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
894 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
897 pa_assert_se(dbus_connection_send(conn, reply, NULL));
898 dbus_message_unref(reply);
902 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
903 const char *direction = NULL;
904 const char *type = NULL;
905 uint32_t is_muted = 0;
906 stream_type_t stream_type = STREAM_SINK_INPUT;
908 DBusMessage *reply = NULL;
909 pa_stream_manager *m = (pa_stream_manager*)userdata;
914 pa_assert_se(dbus_message_get_args(msg, NULL,
915 DBUS_TYPE_STRING, &direction,
916 DBUS_TYPE_STRING, &type,
918 pa_log_info("handle_get_volume_mute(), direction[%s], type[%s]", direction, type);
920 pa_assert_se((reply = dbus_message_new_method_return(msg)));
922 if (pa_streq(direction, "in"))
923 stream_type = STREAM_SOURCE_OUTPUT;
924 else if (pa_streq(direction, "out"))
925 stream_type = STREAM_SINK_INPUT;
927 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
928 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
932 if (get_volume_mute_by_type(m, stream_type, type, (pa_bool_t*)&is_muted)) {
933 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
934 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
936 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
937 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
941 pa_assert_se(dbus_connection_send(conn, reply, NULL));
942 dbus_message_unref(reply);
946 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
947 const char *direction = NULL;
948 const char *type = NULL;
950 stream_type_t stream_type = STREAM_SINK_INPUT;
952 DBusMessage *reply = NULL;
953 pa_stream_manager *m = (pa_stream_manager*)userdata;
958 pa_assert_se(dbus_message_get_args(msg, NULL,
959 DBUS_TYPE_STRING, &direction,
961 pa_log_info("handle_get_current_volume_type(), direction[%s]", direction);
963 pa_assert_se((reply = dbus_message_new_method_return(msg)));
965 if (pa_streq(direction, "in"))
966 stream_type = STREAM_SOURCE_OUTPUT;
967 else if (pa_streq(direction, "out"))
968 stream_type = STREAM_SINK_INPUT;
970 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
971 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
975 s = (stream_type == STREAM_SINK_INPUT)?(void*)(m->cur_highest_priority.sink_input):(void*)(m->cur_highest_priority.source_output);
977 type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE);
978 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID));
979 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
981 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
982 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
986 pa_assert_se(dbus_connection_send(conn, reply, NULL));
987 dbus_message_unref(reply);
991 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
993 pa_stream_manager *m = (pa_stream_manager*)userdata;
999 for (idx = 0; idx < METHOD_HANDLER_MAX; idx++) {
1000 if (dbus_message_is_method_call(msg, STREAM_MANAGER_INTERFACE, method_handlers[idx].method_name )) {
1001 pa_log_debug("Message signature [%s] (Expected [%s])", dbus_message_get_signature(msg), signature_args_for_in[idx]);
1002 if (pa_streq(dbus_message_get_signature(msg), signature_args_for_in[idx])) {
1003 method_handlers[idx].receive_cb(conn, msg, userdata);
1004 return DBUS_HANDLER_RESULT_HANDLED;
1006 pa_log_warn("Wrong Argument Signature");
1007 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_SIGNATURE, "Wrong Signature, Expected %s", signature_args_for_in[idx]);
1008 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1013 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1016 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata) {
1017 pa_stream_manager *u = (pa_stream_manager*)userdata;
1018 const char *path, *interface, *member;
1024 path = dbus_message_get_path(m);
1025 interface = dbus_message_get_interface(m);
1026 member = dbus_message_get_member(m);
1028 pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
1030 if (!pa_streq(path, STREAM_MANAGER_OBJECT_PATH))
1031 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1033 if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1034 return handle_introspect(c, m, u);
1036 return handle_methods(c, m, u);
1039 return DBUS_HANDLER_RESULT_HANDLED;
1043 static int convert_route_type(stream_route_type_t *route_type, const char *route_type_string) {
1046 pa_assert(route_type);
1047 pa_assert(route_type_string);
1049 if (pa_streq("auto", route_type_string))
1050 *route_type = STREAM_ROUTE_TYPE_AUTO;
1051 else if (pa_streq("auto-all", route_type_string))
1052 *route_type = STREAM_ROUTE_TYPE_AUTO_ALL;
1053 else if (pa_streq("manual", route_type_string))
1054 *route_type = STREAM_ROUTE_TYPE_MANUAL;
1057 pa_log_error("Not supported route_type(%s)", route_type_string);
1063 static void dump_stream_map (pa_stream_manager *m) {
1064 stream_info *s = NULL;
1065 const char *role = NULL;
1070 pa_log_debug("==========[START stream-map dump]==========");
1071 while (m->stream_map && (s = pa_hashmap_iterate(m->stream_map, &state, (const void **)&role))) {
1072 pa_log_debug("[role : %s]", role);
1073 pa_log_debug(" - priority : %d", s->priority);
1074 pa_log_debug(" - route-type : %d (0:auto,1:auto-all,2:manual,3:manual-all)", s->route_type);
1075 pa_log_debug(" - volume-types : in[%s], out[%s]", s->volume_type[STREAM_DIRECTION_IN], s->volume_type[STREAM_DIRECTION_OUT]);
1076 pa_log_debug(" - avail-in-devices");
1077 PA_IDXSET_FOREACH(name, s->idx_avail_in_devices, idx)
1078 pa_log_debug(" name[%d] : %s", idx, name);
1079 pa_log_debug(" - avail-out-devices");
1080 PA_IDXSET_FOREACH(name, s->idx_avail_out_devices, idx)
1081 pa_log_debug(" name[%d] : %s", idx, name);
1082 pa_log_debug(" - avail-frameworks");
1083 PA_IDXSET_FOREACH(name, s->idx_avail_frameworks, idx)
1084 pa_log_debug(" name[%d] : %s", idx, name);
1086 pa_log_debug("===========[END stream-map dump]===========");
1090 static int init_stream_map (pa_stream_manager *m) {
1093 json_object *stream_array_o;
1094 json_object *role_o;
1095 json_object *priority_o;
1096 json_object *route_type_o;
1097 json_object *volume_types_o;
1098 json_object *is_hal_volume_o;
1099 json_object *avail_in_devices_o;
1100 json_object *avail_out_devices_o;
1101 json_object *avail_frameworks_o;
1102 int num_of_stream_types = 0;
1103 const char *role = NULL;
1105 int num_of_avail_in_devices;
1106 int num_of_avail_out_devices;
1107 int num_of_avail_frameworks;
1108 json_object *out_device_o;
1109 json_object *in_device_o;
1110 json_object *framework_o;
1111 json_object *stream_o;
1112 json_object *is_hal_volume_in_o;
1113 json_object *is_hal_volume_out_o;
1114 const char *volume_type_in_str = NULL;
1115 const char *volume_type_out_str = NULL;
1116 json_object *volume_type_in_o;
1117 json_object *volume_type_out_o;
1122 o = json_object_from_file(STREAM_MAP_FILE);
1124 pa_log_error("Read stream-map file(%s) failed", STREAM_MAP_FILE);
1127 m->stream_map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1129 if((stream_array_o = json_object_object_get(o, STREAM_MAP_STREAMS)) && json_object_is_type(stream_array_o, json_type_array)){
1130 num_of_stream_types = json_object_array_length(stream_array_o);
1131 for (i = 0; i < num_of_stream_types; i++) {
1133 if((stream_o = json_object_array_get_idx(stream_array_o, i)) && json_object_is_type(stream_o, json_type_object)) {
1134 s = pa_xmalloc0(sizeof(stream_info));
1135 pa_log_debug("stream found [%d]", i);
1136 if((role_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_ROLE)) && json_object_is_type(role_o, json_type_string)) {
1137 role = json_object_get_string(role_o);
1138 pa_log_debug(" - role : %s", role);
1140 pa_log_error("Get stream role failed");
1143 if((priority_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_PRIORITY)) && json_object_is_type(priority_o, json_type_int)) {
1144 s->priority = json_object_get_int(priority_o);
1145 pa_log_debug(" - priority : %d", s->priority);
1147 pa_log_error("Get stream priority failed");
1150 if((route_type_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_ROUTE_TYPE)) && json_object_is_type(route_type_o, json_type_string)) {
1151 if (convert_route_type(&(s->route_type), json_object_get_string(route_type_o))) {
1152 pa_log_error("convert stream route-type failed");
1155 pa_log_debug(" - route-type : %d", s->route_type);
1157 pa_log_error("Get stream route-type failed");
1160 if((volume_types_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_VOLUME_TYPES)) && json_object_is_type(volume_types_o, json_type_object)) {
1161 if((volume_type_in_o = json_object_object_get(volume_types_o, STREAM_MAP_STREAM_VOLUME_TYPE_IN)) && json_object_is_type(volume_type_in_o, json_type_string)) {
1162 volume_type_in_str = json_object_get_string(volume_type_in_o);
1163 if (!pa_streq(volume_type_in_str, "none"))
1164 s->volume_type[STREAM_DIRECTION_IN] = volume_type_in_str;
1166 pa_log_error("Get stream volume-type-in failed");
1169 if((volume_type_out_o = json_object_object_get(volume_types_o, STREAM_MAP_STREAM_VOLUME_TYPE_OUT)) && json_object_is_type(volume_type_out_o, json_type_string)) {
1170 volume_type_out_str = json_object_get_string(volume_type_out_o);
1171 if (!pa_streq(volume_type_out_str, "none"))
1172 s->volume_type[STREAM_DIRECTION_OUT] = volume_type_out_str;
1174 pa_log_error("Get stream volume-type-out failed");
1177 pa_log_debug(" - volume-types : in[%s], out[%s]", s->volume_type[STREAM_DIRECTION_IN], s->volume_type[STREAM_DIRECTION_OUT]);
1179 pa_log_error("Get stream volume-types failed");
1182 if((is_hal_volume_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_VOLUME_IS_FOR_HAL)) && json_object_is_type(is_hal_volume_o, json_type_object)) {
1183 if((is_hal_volume_in_o = json_object_object_get(is_hal_volume_o, STREAM_MAP_STREAM_VOLUME_TYPE_IN)) && json_object_is_type(is_hal_volume_in_o, json_type_int))
1184 s->is_hal_volume[STREAM_DIRECTION_IN] = (pa_bool_t)json_object_get_int(is_hal_volume_in_o);
1186 pa_log_error("Get stream is-hal-volume-in failed");
1189 if((is_hal_volume_out_o = json_object_object_get(is_hal_volume_o, STREAM_MAP_STREAM_VOLUME_TYPE_OUT)) && json_object_is_type(is_hal_volume_out_o, json_type_int))
1190 s->is_hal_volume[STREAM_DIRECTION_OUT] = (pa_bool_t)json_object_get_int(is_hal_volume_out_o);
1192 pa_log_error("Get stream is-hal-volume-out failed");
1195 pa_log_debug(" - is-hal-volume : in[%d], out[%d]", s->is_hal_volume[STREAM_DIRECTION_IN], s->is_hal_volume[STREAM_DIRECTION_OUT]);
1197 pa_log_error("Get stream volume-types failed");
1200 if((avail_in_devices_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_AVAIL_IN_DEVICES)) && json_object_is_type(avail_in_devices_o, json_type_array)) {
1202 s->idx_avail_in_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1203 num_of_avail_in_devices = json_object_array_length(avail_in_devices_o);
1204 pa_log_debug(" - avail-in-devices");
1205 for (j = 0; j < num_of_avail_in_devices; j++) {
1206 if((in_device_o = json_object_array_get_idx(avail_in_devices_o, j)) && json_object_is_type(in_device_o, json_type_string)) {
1207 pa_idxset_put(s->idx_avail_in_devices, (void*)json_object_get_string(in_device_o), NULL);
1208 pa_log_debug(" device[%d] : %s", j, json_object_get_string(in_device_o));
1212 pa_log_error("Get stream avail-in-devices failed");
1215 if((avail_out_devices_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_AVAIL_OUT_DEVICES)) && json_object_is_type(avail_out_devices_o, json_type_array)) {
1217 s->idx_avail_out_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1218 num_of_avail_out_devices = json_object_array_length(avail_out_devices_o);
1219 pa_log_debug(" - avail-out-devices");
1220 for (j = 0; j < num_of_avail_out_devices; j++) {
1221 if((out_device_o = json_object_array_get_idx(avail_out_devices_o, j)) && json_object_is_type(out_device_o, json_type_string)) {
1222 pa_idxset_put(s->idx_avail_out_devices, (void*)json_object_get_string(out_device_o), NULL);
1223 pa_log_debug(" device[%d] : %s", j, json_object_get_string(out_device_o));
1227 pa_log_error("Get stream avail-out-devices failed");
1230 if((avail_frameworks_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_AVAIL_FRAMEWORKS)) && json_object_is_type(avail_frameworks_o, json_type_array)) {
1232 s->idx_avail_frameworks = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1233 num_of_avail_frameworks = json_object_array_length(avail_frameworks_o);
1234 pa_log_debug(" - avail-frameworks");
1235 for (j = 0; j < num_of_avail_frameworks; j++) {
1236 if((framework_o = json_object_array_get_idx(avail_frameworks_o, j)) && json_object_is_type(framework_o, json_type_string)) {
1237 pa_idxset_put(s->idx_avail_frameworks, (void*)json_object_get_string(framework_o), NULL);
1238 pa_log_debug(" framework[%d] : %s", j, json_object_get_string(framework_o));
1242 pa_log_error("Get stream avail-frameworks failed");
1245 pa_hashmap_put(m->stream_map,(void*)role, s);
1249 pa_log_error("Get streams object failed");
1257 pa_log_error("Failed to initialize stream map");
1258 if (m->stream_map) {
1259 PA_HASHMAP_FOREACH(s, m->stream_map, state) {
1260 if (s->idx_avail_in_devices)
1261 pa_idxset_free(s->idx_avail_in_devices, NULL);
1262 if (s->idx_avail_out_devices)
1263 pa_idxset_free(s->idx_avail_out_devices, NULL);
1264 if (s->idx_avail_frameworks)
1265 pa_idxset_free(s->idx_avail_frameworks, NULL);
1268 pa_hashmap_free(m->stream_map);
1273 static void deinit_stream_map (pa_stream_manager *m) {
1274 stream_info *s = NULL;
1278 if (m->stream_map) {
1279 PA_HASHMAP_FOREACH(s, m->stream_map, state) {
1280 if (s->idx_avail_in_devices)
1281 pa_idxset_free(s->idx_avail_in_devices, NULL);
1282 if (s->idx_avail_out_devices)
1283 pa_idxset_free(s->idx_avail_out_devices, NULL);
1284 if (s->idx_avail_frameworks)
1285 pa_idxset_free(s->idx_avail_frameworks, NULL);
1288 pa_hashmap_free(m->stream_map);
1294 static pa_bool_t check_role_to_skip(pa_stream_manager *m, const char *role) {
1295 pa_bool_t ret = TRUE;
1296 stream_info *s = NULL;
1301 if (m->stream_map) {
1302 s = pa_hashmap_get(m->stream_map, role);
1307 pa_log_info("role is [%s], skip(%d)", role, ret);
1312 static pa_bool_t update_priority_of_stream(pa_stream_manager *m, process_command_type_t command, stream_type_t type, void *stream, const char *role) {
1313 stream_info *s = NULL;
1319 s = pa_hashmap_get(m->stream_map, role);
1324 if (command == PROCESS_COMMAND_PREPARE)
1325 pa_proplist_setf(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, "%d", s->priority);
1327 pa_proplist_setf(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, "%d", s->priority);
1333 static pa_bool_t update_routing_type_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, const char *role) {
1334 stream_route_type_t route_type = STREAM_ROUTE_TYPE_AUTO;
1335 stream_info *s = NULL;
1340 if (m->stream_map) {
1341 s = pa_hashmap_get(m->stream_map, role);
1343 route_type = s->route_type;
1347 pa_proplist_setf(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE, "%d", route_type);
1352 static pa_bool_t update_volume_type_of_stream(pa_stream_manager *m, stream_type_t type, void *stream, const char *role) {
1353 const char *volume_type = NULL;
1354 stream_info *s = NULL;
1359 if (m->stream_map) {
1360 s = pa_hashmap_get(m->stream_map, role);
1362 volume_type = s->volume_type[!type];
1367 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE, volume_type);
1369 pa_log_warn("this stream[%p] does not have any volume type, skip updating volume type. stream_type[%d], role[%s]", stream, type, role);
1374 static pa_bool_t update_stream_parent_info(pa_stream_manager *m, process_command_type_t command, stream_type_t type, void *stream) {
1376 uint32_t parent_idx;
1377 stream_parent *sp = NULL;
1382 p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1383 if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1384 pa_log_debug("p_idx(%s), idx(%u)", p_idx, parent_idx);
1385 sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
1387 uint32_t idx = (type==STREAM_SINK_INPUT)?((pa_sink_input*)stream)->index:((pa_source_output*)stream)->index;
1388 if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
1389 /* append this stream to the parent stream info. */
1390 pa_log_debug(" - append this stream(%p, %u) to the list. sp(%p), stream_type(%d)", stream, idx, sp, type);
1391 pa_idxset_put(type==STREAM_SINK_INPUT?(sp->idx_sink_inputs):(sp->idx_source_outputs), stream, NULL);
1393 } else if (command == PROCESS_COMMAND_REMOVE_PARENT_ID) {
1394 /* remove this stream from the parent stream info. */
1395 pa_log_debug(" - remove this stream(%p, %u) from the list. sp(%p), stream_type(%d)", stream, idx, sp, type);
1396 pa_idxset_remove_by_data(type==STREAM_SINK_INPUT?(sp->idx_sink_inputs):(sp->idx_source_outputs), stream, NULL);
1399 pa_log_error("invalid command(%d)", command);
1403 pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
1407 pa_log_warn("p_idx(%s) or idx(%u) is not valid", p_idx, parent_idx);
1413 static pa_bool_t update_the_highest_priority_stream(pa_stream_manager *m, process_command_type_t command, void *mine,
1414 stream_type_t type, const char *role, pa_bool_t *need_to_update) {
1418 const char *priority = NULL;
1419 void *cur_max_stream = NULL;
1420 const char *cur_max_priority = NULL;
1421 const char *cur_max_role = NULL;
1426 pa_log_error("invalid input, role(%s)", role);
1430 *need_to_update = FALSE;
1432 if (type == STREAM_SINK_INPUT) {
1433 cur_max_stream = m->cur_highest_priority.sink_input;
1434 } else if (type == STREAM_SOURCE_OUTPUT) {
1435 cur_max_stream = m->cur_highest_priority.source_output;
1438 pa_log_info("update_the_highest_priority_stream(), stream_type(%d), role(%s), command(%d)", type, role, command);
1439 if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA || command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
1440 if (cur_max_stream == NULL) {
1441 *need_to_update = TRUE;
1442 pa_log_debug("set cur_highest to mine");
1444 /* TODO : need to check if this stream should be played to external devices */
1445 if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA)
1446 priority = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY);
1448 if (cur_max_stream == mine) {
1449 pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, skip it..");
1452 priority = pa_proplist_gets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY);
1454 cur_max_priority = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE_PRIORITY);
1455 cur_max_role = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE);
1456 if (!cur_max_priority || !cur_max_role) {
1457 pa_log_error("Failed to pa_proplist_gets() for getting current max priority(%s) and it's role(%s)", cur_max_priority, cur_max_role);
1460 if (pa_atoi(priority, &p_mine)) {
1461 pa_log_error("Failed to pa_atoi(), priority(%s)", priority);
1464 if (pa_atoi(cur_max_priority, &p_max)) {
1465 pa_log_error("Failed to pa_atoi(), cur_max_priority(%s)", cur_max_priority);
1468 if (p_mine < p_max) {
1469 /* no need to trigger */
1472 *need_to_update = TRUE;
1473 pa_log_debug("update cur_highest to mine(%s)", role);
1477 } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED) {
1478 void *cur_max_stream_tmp = NULL;
1480 const char *_role = NULL;
1482 pa_idxset *streams = NULL;
1483 if (cur_max_stream == mine) {
1484 if (type == STREAM_SINK_INPUT) {
1485 streams = ((pa_sink_input*)mine)->sink->inputs;
1486 } else if (type == STREAM_SOURCE_OUTPUT) {
1487 streams = ((pa_source_output*)mine)->source->outputs;
1489 /* find the next highest priority input */
1490 //PA_IDXSET_FOREACH(i, m->core->sinks, idx) { /* need to check a sink which this stream belongs to */
1491 PA_IDXSET_FOREACH(i, streams, idx) {
1492 if (!(_role = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE))){
1493 pa_log_error("Failed to pa_proplist_gets() for role");
1496 if (!(priority = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE_PRIORITY))){
1497 pa_log_error("Failed to pa_proplist_gets() for priority");
1500 pa_log_debug("role(%s)/priority(%s)/stream(%p)", _role, priority, i);
1501 if (cur_max_priority == NULL) {
1502 cur_max_priority = priority;
1503 cur_max_stream_tmp = i;
1505 if (pa_atoi(cur_max_priority, &p_max)) {
1506 pa_log_error("Failed to pa_atoi(), cur_max_priority(%s)", cur_max_priority);
1509 if (pa_atoi(priority, &p)) {
1510 pa_log_error("Failed to pa_atoi(), priority(%s)", priority);
1514 cur_max_priority = priority;
1515 cur_max_stream_tmp = i;
1519 pa_log_debug("updated max priority(%s)/stream(%p)", cur_max_priority, cur_max_stream_tmp);
1520 if ((p_max > -1) && cur_max_stream_tmp) {
1521 if (type == STREAM_SINK_INPUT) {
1522 m->cur_highest_priority.sink_input = cur_max_stream_tmp;
1523 } else if (type == STREAM_SOURCE_OUTPUT) {
1524 m->cur_highest_priority.source_output = cur_max_stream_tmp;
1527 if (type == STREAM_SINK_INPUT) {
1528 m->cur_highest_priority.sink_input = NULL;
1529 } else if (type == STREAM_SOURCE_OUTPUT) {
1530 m->cur_highest_priority.source_output = NULL;
1533 *need_to_update = TRUE;
1534 pa_log_info("need to update: type(%d), cur_highest_priority(sink_input=%p/source_output=%p)",
1535 type, (void*)m->cur_highest_priority.sink_input, (void*)m->cur_highest_priority.sink_input);
1537 /* no need to trigger */
1544 static void fill_device_info_to_hook_data(void *hook_data, notify_command_type_t command, stream_type_t type, void *stream, pa_stream_manager *m) {
1545 char *device_name = NULL;
1546 const char *p_idx = NULL;
1547 uint32_t parent_idx = 0;
1548 stream_parent *sp = NULL;
1550 pa_stream_manager_hook_data_for_select *select_data = NULL;
1551 pa_stream_manager_hook_data_for_route *route_data = NULL;
1553 pa_idxset *avail_devices;
1556 pa_assert(hook_data);
1558 pa_log_warn("fill_device_info_to_hook_data() for %s", notify_command_type_str[command]);
1561 case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT: {
1562 select_data = (pa_stream_manager_hook_data_for_select*)hook_data;
1563 si = pa_hashmap_get(m->stream_map, select_data->stream_role);
1564 avail_devices = (type==STREAM_SINK_INPUT)?si->idx_avail_out_devices:si->idx_avail_in_devices;
1565 list_len = pa_idxset_size(avail_devices);
1566 select_data->route_type = si->route_type;
1567 device_name = pa_idxset_get_by_data(avail_devices, "none", NULL);
1568 if (list_len == 1 && pa_streq(device_name, "none")) {
1569 /* no available devices for this role */
1571 select_data->idx_avail_devices = avail_devices;
1572 if (si->route_type == STREAM_ROUTE_TYPE_MANUAL) {
1573 p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1574 if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1575 /* find parent idx, it's device info. and it's stream idxs */
1576 sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
1578 select_data->idx_manual_devices = (type==STREAM_SINK_INPUT)?(sp->idx_route_out_devices):(sp->idx_route_in_devices);
1580 pa_log_warn("Failed to get the stream parent of idx(%u)", idx);
1586 case NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA:
1587 case NOTIFY_COMMAND_CHANGE_ROUTE_START:
1588 case NOTIFY_COMMAND_CHANGE_ROUTE_END: {
1589 route_data = (pa_stream_manager_hook_data_for_route*)hook_data;
1590 si = pa_hashmap_get(m->stream_map, route_data->stream_role);
1591 avail_devices = (type==STREAM_SINK_INPUT)?si->idx_avail_out_devices:si->idx_avail_in_devices;
1592 list_len = pa_idxset_size(avail_devices);
1593 route_data->route_type = si->route_type;
1595 if (command == NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA)
1596 p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1597 else if (command == NOTIFY_COMMAND_CHANGE_ROUTE_START || command == NOTIFY_COMMAND_CHANGE_ROUTE_END)
1598 p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1599 if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1600 sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
1602 pa_log_warn("Failed to get the stream parent of idx(%u)", parent_idx);
1604 pa_log_warn("Could not get the parent id of this stream, but keep going...");
1606 device_name = pa_idxset_get_by_data(avail_devices, "none", NULL);
1607 if (list_len == 1 && pa_streq(device_name, "none")) {
1608 /* no available devices for this role */
1610 route_data->idx_avail_devices = avail_devices;
1611 if (si->route_type == STREAM_ROUTE_TYPE_MANUAL) {
1613 route_data->idx_manual_devices = (type==STREAM_SINK_INPUT)?(sp->idx_route_out_devices):(sp->idx_route_in_devices);
1614 route_data->idx_streams = (type==STREAM_SINK_INPUT)?(sp->idx_sink_inputs):(sp->idx_source_outputs);
1616 pa_log_warn("Failed to get the stream parent of idx(%u)", parent_idx);
1627 static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, void *user_data) {
1628 pa_stream_manager_hook_data_for_select hook_call_select_data;
1629 pa_stream_manager_hook_data_for_route hook_call_route_data;
1630 pa_stream_manager_hook_data_for_option hook_call_option_data;
1631 hal_stream_connection_info stream_conn_info;
1632 const char *role = NULL;
1636 pa_log_debug("do_notify(%s): type(%d), user_data(%p)", notify_command_type_str[command], type, user_data);
1639 case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT: {
1640 pa_assert(user_data);
1641 memset(&hook_call_select_data, 0, sizeof(pa_stream_manager_hook_data_for_select));
1644 hook_call_select_data.stream_type = type;
1645 hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1646 fill_device_info_to_hook_data(&hook_call_select_data, command, type, s, m);
1647 hook_call_select_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
1648 if (type == STREAM_SINK_INPUT)
1649 hook_call_select_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
1650 else if (type == STREAM_SOURCE_OUTPUT)
1651 hook_call_select_data.proper_source = &(((pa_source_output_new_data*)s)->source);
1652 pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE), &hook_call_select_data);
1656 case NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA:
1657 case NOTIFY_COMMAND_CHANGE_ROUTE_START: {
1658 pa_assert(user_data);
1659 memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
1662 if (command == NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA) {
1663 hook_call_route_data.origins_from_new_data = TRUE;
1664 role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1665 hook_call_route_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
1666 if (type == STREAM_SINK_INPUT) {
1667 hook_call_route_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
1668 } else if (type == STREAM_SOURCE_OUTPUT) {
1669 hook_call_route_data.proper_source = &(((pa_source_output_new_data*)s)->source);
1672 role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1673 hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
1674 if (type == STREAM_SINK_INPUT) {
1675 if (((pa_sink_input*)s)->sink)
1676 hook_call_route_data.idx_streams = ((pa_sink_input*)s)->sink->inputs;
1677 } else if (type == STREAM_SOURCE_OUTPUT) {
1678 if (((pa_source_output*)s)->source)
1679 hook_call_route_data.idx_streams = ((pa_source_output*)s)->source->outputs;
1682 hook_call_route_data.stream_type = type;
1683 hook_call_route_data.stream_role = role;
1684 fill_device_info_to_hook_data(&hook_call_route_data, command, type, s, m);
1685 if (hook_call_route_data.route_type == STREAM_ROUTE_TYPE_MANUAL) {
1686 if (hook_call_route_data.idx_manual_devices && !pa_idxset_size(hook_call_route_data.idx_manual_devices)) {
1687 pa_log_info("no manual device for this type(%d), need to unset route", type);
1688 hook_call_route_data.stream_role = "reset";
1691 pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data);
1695 case NOTIFY_COMMAND_CHANGE_ROUTE_END: {
1696 memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
1697 s = (type==STREAM_SINK_INPUT)?(void*)(m->cur_highest_priority.sink_input):(void*)(m->cur_highest_priority.source_output);
1699 role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1700 hook_call_route_data.stream_type = type;
1701 hook_call_route_data.stream_role = role;
1702 hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
1703 hook_call_route_data.idx_streams = (type==STREAM_SINK_INPUT)?((pa_sink_input*)s)->sink->inputs:((pa_source_output*)s)->source->outputs;
1704 fill_device_info_to_hook_data(&hook_call_route_data, command, type, s, m);
1706 pa_log_info("no stream for this type(%d), need to unset route", type);
1707 hook_call_route_data.stream_type = type;
1708 hook_call_route_data.stream_role = "reset";
1710 pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data);
1713 case NOTIFY_COMMAND_UPDATE_ROUTE_OPTION: {
1714 pa_assert(user_data);
1715 memset(&hook_call_option_data, 0, sizeof(pa_stream_manager_hook_data_for_option));
1716 s = (type==STREAM_SINK_INPUT)?(void*)(m->cur_highest_priority.sink_input):(void*)(m->cur_highest_priority.source_output);
1718 role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1719 hook_call_option_data.stream_role = role;
1720 hook_call_option_data.name = ((stream_route_option*)user_data)->name;
1721 hook_call_option_data.value = ((stream_route_option*)user_data)->value;
1722 pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_UPDATE_ROUTE_OPTION), &hook_call_option_data);
1726 case NOTIFY_COMMAND_INFORM_STREAM_CONNECTED:
1727 case NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED: {
1728 pa_assert(user_data);
1729 memset(&stream_conn_info, 0, sizeof(hal_stream_connection_info));
1732 stream_conn_info.role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1733 stream_conn_info.direction = (type==STREAM_SINK_INPUT)?DIRECTION_OUT:DIRECTION_IN;
1734 stream_conn_info.idx = (type==STREAM_SINK_INPUT)?((pa_sink_input*)s)->index:((pa_source_output*)s)->index;
1735 stream_conn_info.is_connected = (command == NOTIFY_COMMAND_INFORM_STREAM_CONNECTED)?TRUE:FALSE;
1736 pa_hal_manager_update_stream_connection_info(m->hal, &stream_conn_info);
1744 static pa_process_stream_result_t process_stream(stream_type_t type, void *stream, process_command_type_t command, pa_stream_manager *m) {
1745 pa_process_stream_result_t result = PA_PROCESS_STREAM_OK;
1746 const char *role = NULL;
1747 pa_bool_t ret = TRUE;
1748 pa_bool_t need_update = FALSE;
1749 int32_t volume_ret = 0;
1750 volume_info *v = NULL;
1751 const char *si_volume_type_str = NULL;
1752 const char *prior_priority = NULL;
1753 int32_t prior_p = 0;
1754 pa_format_info *req_format = NULL;
1755 char *format_str = NULL;
1756 const char *rate_str = NULL;
1757 const char *ch_str = NULL;
1759 pa_log_info("START process_stream(%s): stream_type(%d), stream(%p), m(%p)", process_command_type_str[command], type, stream, m);
1763 if (command == PROCESS_COMMAND_PREPARE) {
1764 if (type == STREAM_SINK_INPUT) {
1765 /* Parse request formats for samplerate, channel, format infomation */
1766 if (((pa_sink_input_new_data*)stream)->req_formats) {
1767 req_format = pa_idxset_first(((pa_sink_input_new_data*)stream)->req_formats, NULL);
1768 if (req_format && req_format->plist) {
1769 /* set sample_spec */
1770 rate_str = pa_proplist_gets(req_format->plist, PA_PROP_FORMAT_RATE);
1771 ch_str = pa_proplist_gets(req_format->plist, PA_PROP_FORMAT_CHANNELS);
1772 if (pa_format_info_get_prop_string(req_format, PA_PROP_FORMAT_SAMPLE_FORMAT, &format_str)==0)
1773 ((pa_sink_input_new_data*)stream)->sample_spec.format = pa_parse_sample_format((const char*)format_str);
1774 pa_log_info("req rate(%s), req ch(%s), req format(%s)", rate_str, ch_str, format_str);
1776 ((pa_sink_input_new_data*)stream)->sample_spec.channels = atoi (ch_str);
1778 ((pa_sink_input_new_data*)stream)->sample_spec.rate = atoi (rate_str);
1779 /* set channel map if it is not set by client */
1780 if (!((pa_sink_input_new_data*)stream)->channel_map_is_set) {
1781 pa_channel_map_init_auto(&(((pa_sink_input_new_data*)stream)->channel_map), ((pa_sink_input_new_data*)stream)->sample_spec.channels, PA_CHANNEL_MAP_ALSA);
1782 pa_log_info("set default channel_map: channels(%u)",((pa_sink_input_new_data*)stream)->channel_map.channels);
1783 ((pa_sink_input_new_data*)stream)->channel_map_is_set = TRUE;
1787 pa_log_debug("no request formats available");
1790 role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1792 /* set default value for role and priority */
1793 #define DEFAULT_ROLE "media"
1794 role = DEFAULT_ROLE;
1795 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE, DEFAULT_ROLE);
1796 pa_log_warn("role is null, set default to [%s]", role);
1799 if (check_role_to_skip(m, role)) {
1800 result = PA_PROCESS_STREAM_SKIP;
1804 /* update the priority of this stream */
1805 ret = update_priority_of_stream(m, command, type, stream, role);
1807 pa_log_error("could not update the priority of '%s' role.", role);
1808 result = PA_PROCESS_STREAM_STOP;
1811 /* update the volume type of this stream */
1812 ret = update_volume_type_of_stream(m, type, stream, role);
1814 pa_log_error("could not update the volume type of '%s' role.", role);
1815 result = PA_PROCESS_STREAM_STOP;
1818 /* update the routing type of this stream */
1819 ret = update_routing_type_of_stream(m, stream, type, role);
1821 pa_log_error("could not update the route type of '%s' role.", role);
1822 result = PA_PROCESS_STREAM_STOP;
1826 /* notify to select sink or source */
1827 do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, stream);
1829 } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA || command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
1830 if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA)
1831 role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1833 role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1836 if (check_role_to_skip(m, role)) {
1837 result = PA_PROCESS_STREAM_SKIP;
1841 if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
1842 /* update the priority of this stream */
1843 ret = update_priority_of_stream(m, command, type, stream, role);
1845 pa_log_error("could not update the priority of '%s' role.", role);
1846 result = PA_PROCESS_STREAM_STOP;
1851 /* update the highest priority */
1852 ret = update_the_highest_priority_stream(m, command, stream, type, role, &need_update);
1854 pa_log_error("could not update the highest priority stream");
1855 result = PA_PROCESS_STREAM_SKIP;
1859 /* need to skip if this stream does not belong to internal device */
1860 /* if needed, notify to update */
1862 if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA) {
1863 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA, type, stream);
1864 if (type==STREAM_SINK_INPUT)
1865 m->cur_highest_priority.need_to_update_si = TRUE;
1867 m->cur_highest_priority.need_to_update_so = TRUE;
1869 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, stream);
1870 if (type==STREAM_SINK_INPUT)
1871 m->cur_highest_priority.sink_input = stream;
1873 m->cur_highest_priority.source_output = stream;
1876 if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED)
1877 do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, stream);
1879 } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED) {
1880 role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1883 if (check_role_to_skip(m, role)) {
1884 result = PA_PROCESS_STREAM_SKIP;
1888 /* check if it has already been processed (unlink or state_changed_cb) */
1889 prior_priority = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_ROLE_PRIORITY);
1890 if (prior_priority && !pa_atoi(prior_priority, &prior_p) && (prior_p == -1)) {
1891 pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, skip it..");
1892 result = PA_PROCESS_STREAM_SKIP;
1896 /* mark the priority of this stream to -1 */
1897 pa_proplist_setf(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, "%d", -1);
1898 ret = update_the_highest_priority_stream(m, command, stream, type, role, &need_update);
1900 pa_log_error("could not update the highest priority stream");
1901 result = PA_PROCESS_STREAM_STOP;
1905 do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED, type, stream);
1907 /* need to skip if this stream does not belong to internal device */
1908 /* if needed, notify to update */
1910 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, NULL);
1913 pa_log_error("role is null, skip it");
1916 } else if (command == PROCESS_COMMAND_UPDATE_VOLUME) {
1917 if ((si_volume_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
1918 v = pa_hashmap_get(m->volume_map.out_volumes, si_volume_type_str);
1919 if (v && v->idx_volume_values) {
1920 /* Update volume-level */
1921 volume_ret = set_volume_level_with_new_data(m, type, stream, v->current_level);
1923 pa_log_error("failed to set_volume_level_by_idx(), stream_type(%d), level(%u), ret(0x%x)",
1924 STREAM_SINK_INPUT, v->current_level, volume_ret);
1925 /* Update volume-mute */
1926 volume_ret = set_volume_mute_with_new_data(m, type, stream, v->is_muted);
1928 pa_log_error("failed to set_volume_mute_by_idx(), stream_type(%d), mute(%d), ret(0x%x)",
1929 STREAM_SINK_INPUT, v->is_muted, volume_ret);
1933 } else if (command == PROCESS_COMMAND_ADD_PARENT_ID || command == PROCESS_COMMAND_REMOVE_PARENT_ID) {
1934 if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
1935 if (type == STREAM_SINK_INPUT && m->cur_highest_priority.need_to_update_si) {
1936 m->cur_highest_priority.sink_input = stream;
1937 m->cur_highest_priority.need_to_update_si = FALSE;
1939 if (type == STREAM_SOURCE_OUTPUT && m->cur_highest_priority.need_to_update_so) {
1940 m->cur_highest_priority.source_output = stream;
1941 m->cur_highest_priority.need_to_update_so = FALSE;
1943 if (command == PROCESS_COMMAND_ADD_PARENT_ID)
1944 do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, stream);
1946 /* update parent stream info. */
1947 ret = update_stream_parent_info(m, command, type, stream);
1949 pa_log_warn("could not update the parent information of this stream");
1950 //return PA_PROCESS_STREAM_STOP;
1955 pa_log_info("END process_stream(%s): result(%d)", process_command_type_str[command], result);
1959 static void update_buffer_attribute(stream_type_t stream_type, void *new_data, pa_stream_manager *m) {
1960 int32_t maxlength = -1;
1961 int32_t tlength = -1;
1962 int32_t prebuf = -1;
1963 int32_t minreq = -1;
1964 int32_t fragsize = -1;
1965 const char* audio_latency = NULL;
1968 pa_assert(new_data);
1973 audio_latency = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY);
1974 pa_log_info("audio_latency : %s", audio_latency);
1975 if (audio_latency == NULL)
1978 if (!pa_hal_manager_get_buffer_attribute(m->hal, (io_direction_t)!stream_type, audio_latency, new_data, (uint32_t*)&maxlength, (uint32_t*)&tlength, (uint32_t*)&prebuf, (uint32_t*)&minreq, (uint32_t*)&fragsize)) {
1979 pa_log_info(" - maxlength:%d, tlength:%d, prebuf:%d, minreq:%d, fragsize:%d", maxlength, tlength, prebuf, minreq, fragsize);
1980 pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "maxlength", "%d", maxlength);
1981 pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "tlength", "%d", tlength);
1982 pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "prebuf", "%d", prebuf);
1983 pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "minreq", "%d", minreq);
1984 pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "fragsize", "%d", fragsize);
1990 static pa_hook_result_t sink_input_new_cb(pa_core *core, pa_sink_input_new_data *new_data, pa_stream_manager *m) {
1991 pa_core_assert_ref(core);
1993 pa_log_info("start sink_input_new_cb");
1995 process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_PREPARE, m);
1996 /* Update buffer attributes from HAL */
1997 update_buffer_attribute(STREAM_SINK_INPUT, new_data, m);
1998 process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_UPDATE_VOLUME, m);
1999 process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA, m);
2004 static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2005 pa_core_assert_ref(core);
2006 pa_sink_input_assert_ref(i);
2008 pa_log_info("start sink_input_put_cb, i(%p, index:%u)", i, i->index);
2010 process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_ADD_PARENT_ID, m);
2015 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2016 pa_core_assert_ref(core);
2017 pa_sink_input_assert_ref(i);
2019 pa_log_info("start sink_input_unlink_cb, i(%p, index:%u)", i, i->index);
2020 process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_REMOVE_PARENT_ID, m);
2021 process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
2026 static pa_hook_result_t sink_input_state_changed_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2027 pa_sink_input_state_t state;
2032 state = pa_sink_input_get_state(i);
2033 pa_log_info("start sink_input_state_changed_cb(), sink-input(%p), state(%d)", i, state);
2036 case PA_SINK_INPUT_CORKED: {
2037 process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
2040 case PA_SINK_INPUT_DRAINED:
2041 case PA_SINK_INPUT_RUNNING: {
2042 process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, m);
2052 static pa_hook_result_t sink_input_move_start_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2053 pa_core_assert_ref(core);
2054 pa_sink_input_assert_ref(i);
2056 /* There's no point in doing anything if the core is shut down anyway */
2057 if (core->state == PA_CORE_SHUTDOWN)
2060 pa_log_debug ("sink_input_move_start_cb, i(%p, index:%u)", i, i->index);
2062 set_volume_mute_by_idx(m, STREAM_SINK_INPUT, i->index, TRUE);
2067 static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2068 pa_core_assert_ref(core);
2069 pa_sink_input_assert_ref(i);
2071 /* There's no point in doing anything if the core is shut down anyway */
2072 if (core->state == PA_CORE_SHUTDOWN)
2075 pa_log_debug ("sink_input_move_finish_cb, i(%p, index:%u)", i, i->index);
2077 set_volume_mute_by_idx(m, STREAM_SINK_INPUT, i->index, FALSE);
2082 static pa_hook_result_t source_output_new_cb(pa_core *core, pa_source_output_new_data *new_data, pa_stream_manager *m) {
2083 pa_core_assert_ref(core);
2085 pa_log_info("start source_output_new_new_cb");
2087 process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_PREPARE, m);
2088 /* Update buffer attributes from HAL */
2089 update_buffer_attribute(STREAM_SOURCE_OUTPUT, new_data, m);
2090 process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_UPDATE_VOLUME, m);
2091 process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA, m);
2096 static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2097 pa_core_assert_ref(core);
2098 pa_source_output_assert_ref(o);
2100 pa_log_info("start source_output_put_cb, o(%p, index:%u)", o, o->index);
2102 process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_ADD_PARENT_ID, m);
2107 static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2108 pa_core_assert_ref(core);
2109 pa_source_output_assert_ref(o);
2111 pa_log_info("start source_output_unlink_cb, o(%p, index:%u)", o, o->index);
2113 process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_REMOVE_PARENT_ID, m);
2114 process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
2119 static pa_hook_result_t source_output_state_changed_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2120 pa_source_output_state_t state;
2125 state = pa_source_output_get_state(o);
2126 pa_log_debug("start source_output_state_changed_cb(), source-output(%p), state(%d)", o, state);
2129 case PA_SOURCE_OUTPUT_CORKED: {
2130 process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
2133 case PA_SOURCE_OUTPUT_RUNNING: {
2134 process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, m);
2144 /* Reorganize routing when a device has been connected or disconnected */
2145 static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_device_manager_hook_data_for_conn_changed *conn, pa_stream_manager *m) {
2146 const char *route_type_str = NULL;
2147 stream_route_type_t route_type;
2148 dm_device_direction_t device_direction = DM_DEVICE_DIRECTION_OUT;
2150 device_direction = pa_device_manager_get_device_direction(conn->device);
2151 pa_log_info("device_connection_changed_hook_cb is called. conn(%p), is_connected(%d), device(%p), direction(0x%x)",
2152 conn, conn->is_connected, conn->device, device_direction);
2154 /* If the route type of the stream is not manual, notify again */
2155 if (m->cur_highest_priority.source_output && (device_direction & DM_DEVICE_DIRECTION_IN)) {
2156 route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
2157 if(!pa_atoi(route_type_str, (int32_t*)&route_type))
2158 if (route_type != STREAM_ROUTE_TYPE_MANUAL)
2159 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, m->cur_highest_priority.source_output);
2160 } if (m->cur_highest_priority.sink_input && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
2161 route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(m->cur_highest_priority.sink_input, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
2162 if(!pa_atoi(route_type_str, (int32_t*)&route_type))
2163 if (route_type != STREAM_ROUTE_TYPE_MANUAL)
2164 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, m->cur_highest_priority.sink_input);
2170 /* Reorganize routing when device information has been changed */
2171 static pa_hook_result_t device_information_changed_hook_cb(pa_core *c, pa_device_manager_hook_data_for_info_changed *info, pa_stream_manager *m) {
2172 pa_log_info("device_information_changed_hook_cb is called. info(%p), changed_info(%d), device(%p)",
2173 info, info->changed_info, info->device);
2178 static void subscribe_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, pa_stream_manager *m) {
2179 pa_client *client = NULL;
2180 stream_parent *sp = NULL;
2181 const char *name = NULL;
2182 uint32_t *device_id = NULL;
2184 pa_core_assert_ref(core);
2186 pa_log_info("subscribe_cb() is called, t(%x), idx(%u)", t, idx);
2188 if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE)) {
2189 client = pa_idxset_get_by_index(core->clients, idx);
2190 if (client == NULL) {
2191 pa_log_error(" - could not find any client that has idx(%u)", idx);
2194 name = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME);
2195 if (strncmp (name, STREAM_MANAGER_CLIENT_NAME, strlen(STREAM_MANAGER_CLIENT_NAME))) {
2196 pa_log_warn(" - this is not a client(%s) that we should take care of, skip it", name);
2199 /* add a stream parent */
2200 sp = pa_xmalloc0(sizeof(stream_parent));
2201 sp->idx_sink_inputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2202 sp->idx_source_outputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2203 sp->idx_route_in_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2204 sp->idx_route_out_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2205 pa_hashmap_put(m->stream_parents, (void*)idx, sp);
2206 pa_log_debug(" - add sp(%p), idx(%u)", sp, idx);
2207 } else if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE)) {
2208 /* remove the stream parent */
2209 sp = pa_hashmap_get(m->stream_parents, (const void*)idx);
2211 pa_log_debug(" - remove sp(%p), idx(%u)", sp, idx);
2212 pa_hashmap_remove(m->stream_parents, (const void*)idx);
2213 if (sp->idx_route_in_devices)
2214 PA_IDXSET_FOREACH(device_id, sp->idx_route_in_devices, _idx)
2215 pa_xfree(device_id);
2216 if (sp->idx_route_out_devices)
2217 PA_IDXSET_FOREACH(device_id, sp->idx_route_out_devices, _idx)
2218 pa_xfree(device_id);
2219 pa_idxset_free(sp->idx_sink_inputs, NULL);
2220 pa_idxset_free(sp->idx_source_outputs, NULL);
2221 pa_idxset_free(sp->idx_route_in_devices, NULL);
2222 pa_idxset_free(sp->idx_route_out_devices, NULL);
2225 pa_log_error(" - could not find any stream_parent that has idx(%u)", idx);
2230 static int init_ipc (pa_stream_manager *m) {
2232 #ifdef USE_DBUS_PROTOCOL
2234 pa_log_info("Initialization for IPC");
2235 m->dbus_protocol = pa_dbus_protocol_get(m->core);
2236 pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, &stream_manager_interface_info, m) >= 0);
2237 pa_assert_se(pa_dbus_protocol_register_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2240 pa_dbus_connection *conn = NULL;
2241 static const DBusObjectPathVTable vtable = {
2242 .message_function = method_handler_for_vt,
2246 pa_log_info("Initialization for IPC");
2248 dbus_error_init(&err);
2250 if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) {
2252 pa_dbus_connection_unref(conn);
2254 pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message);
2257 pa_log_notice("Got dbus connection");
2259 m->dbus_conn = conn;
2260 pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(conn), STREAM_MANAGER_OBJECT_PATH, &vtable, m));
2263 pa_log_error("DBUS is not supported\n");
2269 pa_log_error("Failed to initialize stream manager ipc");
2273 static void deinit_ipc (pa_stream_manager *m) {
2277 #ifdef USE_DBUS_PROTOCOL
2278 if (m->dbus_protocol) {
2279 pa_assert_se(pa_dbus_protocol_unregister_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2280 pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, stream_manager_interface_info.name) >= 0);
2281 pa_dbus_protocol_unref(m->dbus_protocol);
2282 m->dbus_protocol = NULL;
2286 if(!dbus_connection_unregister_object_path(pa_dbus_connection_get(m->dbus_conn), STREAM_MANAGER_OBJECT_PATH))
2287 pa_log_error("Failed to unregister object path");
2288 m->dbus_conn = NULL;
2295 pa_stream_manager* pa_stream_manager_init(pa_core *c) {
2296 pa_stream_manager *m;
2300 m = pa_xnew0(pa_stream_manager, 1);
2303 m->hal = pa_hal_manager_get(c, NULL);
2306 #ifdef USE_DBUS_PROTOCOL
2307 m->dbus_protocol = NULL;
2309 m->dbus_conn = NULL;
2315 if (init_stream_map(m))
2318 if (init_volume_map(m))
2321 m->stream_parents = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2323 m->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_new_cb, m);
2324 m->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_put_cb, m);
2325 m->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_unlink_cb, m);
2326 m->sink_input_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_state_changed_cb, m);
2327 m->sink_input_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_move_start_cb, m);
2328 m->sink_input_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_move_finish_cb, m);
2329 m->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_new_cb, m);
2330 m->source_output_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_put_cb, m);
2331 m->source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_unlink_cb, m);
2332 m->source_output_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_state_changed_cb, m);
2335 m->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_CLIENT | PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, (pa_subscription_cb_t)subscribe_cb, m);
2337 m->comm.comm = pa_communicator_get(c);
2338 m->comm.comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm,PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
2339 PA_HOOK_EARLY + 10, (pa_hook_cb_t) device_connection_changed_hook_cb, m);
2340 m->comm.comm_hook_device_information_changed_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm,PA_COMMUNICATOR_HOOK_DEVICE_INFORMATION_CHANGED),
2341 PA_HOOK_EARLY, (pa_hook_cb_t) device_information_changed_hook_cb, m);
2346 pa_log_error("Failed to initialize stream-manager");
2347 deinit_volume_map(m);
2348 deinit_stream_map(m);
2351 pa_hal_manager_unref(m->hal);
2356 void pa_stream_manager_done(pa_stream_manager *m) {
2360 if (m->comm.comm_hook_device_connection_changed_slot)
2361 pa_hook_slot_free(m->comm.comm_hook_device_connection_changed_slot);
2362 if (m->comm.comm_hook_device_information_changed_slot)
2363 pa_hook_slot_free(m->comm.comm_hook_device_information_changed_slot);
2364 pa_communicator_unref(m->comm.comm);
2367 if (m->subscription)
2368 pa_subscription_free(m->subscription);
2370 if (m->sink_input_new_slot)
2371 pa_hook_slot_free(m->sink_input_new_slot);
2372 if (m->sink_input_put_slot)
2373 pa_hook_slot_free(m->sink_input_put_slot);
2374 if (m->sink_input_unlink_slot)
2375 pa_hook_slot_free(m->sink_input_unlink_slot);
2376 if (m->sink_input_state_changed_slot)
2377 pa_hook_slot_free(m->sink_input_state_changed_slot);
2378 if (m->sink_input_move_start_slot)
2379 pa_hook_slot_free(m->sink_input_move_start_slot);
2380 if (m->sink_input_move_finish_slot)
2381 pa_hook_slot_free(m->sink_input_move_finish_slot);
2382 if (m->source_output_new_slot)
2383 pa_hook_slot_free(m->source_output_new_slot);
2384 if (m->source_output_put_slot)
2385 pa_hook_slot_free(m->source_output_put_slot);
2386 if (m->source_output_unlink_slot)
2387 pa_hook_slot_free(m->source_output_unlink_slot);
2388 if (m->source_output_state_changed_slot)
2389 pa_hook_slot_free(m->source_output_state_changed_slot);
2391 if (m->stream_parents)
2392 pa_hashmap_free(m->stream_parents);
2394 deinit_volume_map(m);
2395 deinit_stream_map(m);
2399 pa_hal_manager_unref(m->hal);