#endif
/* Sink & Source names */
-#define SINK_HIGH_LATENCY "alsa_output.4.analog-stereo"
+#define SINK_HIGH_LATENCY "alsa_output.4.analog-stereo"
#define SINK_HIGH_LATENCY_UHQA "alsa_output.4.analog-stereo-uhqa"
+#define SINK_COMBINED "sink_combined"
+#define SINK_NULL "sink_null"
+#define SOURCE_NULL "source_null"
/* Policies */
#define POLICY_HIGH_LATENCY "high-latency"
pa_hook_slot *comm_hook_select_proper_sink_or_source_slot;
pa_hook_slot *comm_hook_change_route_slot;
pa_hook_slot *comm_hook_update_route_options_slot;
+ pa_hook_slot *comm_hook_device_connection_changed_slot;
} communicator;
pa_hal_manager *hal_manager;
#ifdef DEVICE_MANAGER
pa_device_manager *device_manager;
#endif
+ pa_module *module_combine_sink;
+ pa_module *module_null_sink;
+ pa_module *module_null_source;
};
enum {
dm_device *device = NULL;
dm_device_direction_t device_direction = DM_DEVICE_DIRECTION_NONE;
pa_idxset *conn_devices = NULL;
+ pa_sink *combine_sink_arg1 = NULL;
+ pa_sink *combine_sink_arg2 = NULL;
+
+ pa_log_info("select_proper_sink_or_source_hook_cb is called. (%p), stream_type(%d), stream_role(%s), route_type(%d)",
+ data, data->stream_type, data->stream_role, data->route_type);
if ((data->route_type == STREAM_ROUTE_TYPE_AUTO || data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) && data->idx_avail_devices) {
/* Get current connected devices */
conn_devices = pa_device_manager_get_device_list(u->device_manager);
PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
- pa_log_debug("-- [AUTO] avail_device[%u] for this role[%s]: type(%s)", idx, data->stream_role, device_type);
+ pa_log_debug("[AUTO(_ALL)] avail_device[%u] for this role[%s]: type(%s)", idx, data->stream_role, device_type);
PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
dm_device_type = pa_device_manager_get_device_type(device);
dm_device_subtype = pa_device_manager_get_device_subtype(device);
device_direction = pa_device_manager_get_device_direction(device);
- pa_log_debug("-- [AUTO] conn_devices, type[%s], subtype[%s], direction[%p]", dm_device_type, dm_device_subtype, device_direction);
+ pa_log_debug("[AUTO(_ALL)] conn_devices, type[%s], subtype[%s], direction[%p]", dm_device_type, dm_device_subtype, device_direction);
if (pa_streq(device_type, dm_device_type) &&
(((data->stream_type==STREAM_SINK_INPUT) && (device_direction & DM_DEVICE_DIRECTION_OUT)) ||
((data->stream_type==STREAM_SOURCE_OUTPUT) && (device_direction & DM_DEVICE_DIRECTION_IN)))) {
- pa_log_debug("-- [AUTO] found a matched device: type[%s], direction[%p]", device_type, device_direction);
- if (data->stream_type == STREAM_SINK_INPUT)
+ pa_log_debug("[AUTO(_ALL)] found a matched device: type[%s], direction[%p]", device_type, device_direction);
+
+ if (data->stream_type == STREAM_SINK_INPUT && u->module_combine_sink) {
+ *(data->proper_sink) = pa_namereg_get(u->module->core, SINK_COMBINED, PA_NAMEREG_SINK);
+ pa_log_debug("[AUTO(_ALL)] found the combine-sink, set it to the sink");
+ } else if (data->stream_type == STREAM_SINK_INPUT)
*(data->proper_sink) = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
else
*(data->proper_source) = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
} else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL && data->idx_manual_devices && data->idx_avail_devices) {
PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
- pa_log_debug("-- [MANUAL] avail_device[%u] for this role[%s]: type(%s)", idx, data->stream_role, device_type);
+ pa_log_debug("[MANUAL] avail_device[%u] for this role[%s]: type(%s)", idx, data->stream_role, device_type);
PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, m_idx) {
device = pa_device_manager_get_device_by_id(u->device_manager, *device_id);
if (device) {
dm_device_type = pa_device_manager_get_device_type(device);
dm_device_subtype = pa_device_manager_get_device_subtype(device);
device_direction = pa_device_manager_get_device_direction(device);
- pa_log_debug("-- [MANUAL] manual_devices, type[%s], subtype[%s], direction[%p], device id[%u]",
+ pa_log_debug("[MANUAL] manual_devices, type[%s], subtype[%s], direction[%p], device id[%u]",
dm_device_type, dm_device_subtype, device_direction, *device_id);
if (pa_streq(device_type, dm_device_type) &&
(((data->stream_type==STREAM_SINK_INPUT) && (device_direction & DM_DEVICE_DIRECTION_OUT)) ||
((data->stream_type==STREAM_SOURCE_OUTPUT) && (device_direction & DM_DEVICE_DIRECTION_IN)))) {
- pa_log_debug("-- [MANUAL] found a matched device: type[%s], direction[0x%x]", device_type, device_direction);
+ pa_log_debug("[MANUAL] found a matched device: type[%s], direction[0x%x]", device_type, device_direction);
if (data->stream_type == STREAM_SINK_INPUT)
*(data->proper_sink) = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
else
if ((data->stream_type==STREAM_SINK_INPUT)?!(*(data->proper_sink)):!(*(data->proper_source))) {
pa_log_warn("could not find a proper sink/source, set it to null sink/source");
if (data->stream_type == STREAM_SINK_INPUT)
- *(data->proper_sink) = (pa_sink*)pa_namereg_get(u->core, "null", PA_NAMEREG_SINK);
+ *(data->proper_sink) = (pa_sink*)pa_namereg_get(u->core, SINK_NULL, PA_NAMEREG_SINK);
else
- *(data->proper_source) = (pa_source*)pa_namereg_get(u->core, "null", PA_NAMEREG_SOURCE);
+ *(data->proper_source) = (pa_source*)pa_namereg_get(u->core, SOURCE_NULL, PA_NAMEREG_SOURCE);
}
SUCCESS:
#endif
#ifdef DEVICE_MANAGER
int32_t i = 0;
uint32_t idx = 0;
- uint32_t m_idx = 0;
+ uint32_t d_idx = 0;
+ uint32_t s_idx = 0;
uint32_t *stream_idx = NULL;
hal_route_info route_info = {NULL, NULL, 0};
uint32_t conn_idx = 0;
pa_sink *sink = NULL;
pa_source *source = NULL;
pa_idxset *conn_devices = NULL;
+ pa_sink *combine_sink_arg1 = NULL;
+ pa_sink *combine_sink_arg2 = NULL;
+ char *args = NULL;
pa_log_info("route_change_hook_cb is called. (%p), stream_type(%d), stream_role(%s), route_type(%d)",
data, data->stream_type, data->stream_role, data->route_type);
if (device_state == DM_DEVICE_STATE_ACTIVATED &&
(((data->stream_type==STREAM_SINK_INPUT) && (device_direction & DM_DEVICE_DIRECTION_OUT)) ||
((data->stream_type==STREAM_SOURCE_OUTPUT) && (device_direction & DM_DEVICE_DIRECTION_IN)))) {
- pa_log_debug("-- [RESET] found a matched device and set state to DE-ACTIVATED: type[%s], direction[%p]", dm_device_type, device_direction);
+ pa_log_debug("[RESET] found a matched device and set state to DE-ACTIVATED: type[%s], direction[%p]", dm_device_type, device_direction);
/* set device state to deactivated */
pa_device_manager_set_device_state(device, DM_DEVICE_STATE_DEACTIVATED);
}
route_info.device_infos = pa_xmalloc0(sizeof(hal_device_info)*route_info.num_of_devices);
route_info.device_infos[0].direction = (data->stream_type==STREAM_SINK_INPUT)?DIRECTION_OUT:DIRECTION_IN;
+ /* unload combine sink */
+ if (data->stream_type==STREAM_SINK_INPUT && u->module_combine_sink) {
+ pa_log_debug ("[RESET] unload module[%s]", SINK_COMBINED);
+ pa_sink_suspend(pa_namereg_get(u->module->core, SINK_COMBINED, PA_NAMEREG_SINK), TRUE, PA_SUSPEND_USER);
+ pa_module_unload(u->module->core, u->module_combine_sink, TRUE);
+ u->module_combine_sink = NULL;
+ }
+
} else if ((data->route_type == STREAM_ROUTE_TYPE_AUTO || data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) && data->idx_avail_devices) {
/* Get current connected devices */
conn_devices = pa_device_manager_get_device_list(u->device_manager);
PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
- pa_log_debug("-- [AUTO] avail_device[%u] for this role[%s]: type[%s]", idx, route_info.role, device_type);
+ pa_log_debug("[AUTO(_ALL)] avail_device[%u] for this role[%s]: type[%s]", idx, route_info.role, device_type);
PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
dm_device_type = pa_device_manager_get_device_type(device);
dm_device_subtype = pa_device_manager_get_device_subtype(device);
device_direction = pa_device_manager_get_device_direction(device);
device_idx = pa_device_manager_get_device_id(device);
- pa_log_debug("-- [AUTO] conn_devices, type[%s], subtype[%s], direction[%p], id[%u]",
+ pa_log_debug("[AUTO(_ALL)] conn_devices, type[%s], subtype[%s], direction[%p], id[%u]",
dm_device_type, dm_device_subtype, device_direction, device_idx);
if (pa_streq(device_type, dm_device_type) &&
(((data->stream_type==STREAM_SINK_INPUT) && (device_direction & DM_DEVICE_DIRECTION_OUT)) ||
route_info.device_infos[route_info.num_of_devices-1].type = dm_device_type;
route_info.device_infos[route_info.num_of_devices-1].direction = (data->stream_type==STREAM_SINK_INPUT)?DIRECTION_OUT:DIRECTION_IN;
route_info.device_infos[route_info.num_of_devices-1].id = device_idx;
- pa_log_debug("-- [AUTO] found a matched device and set state to ACTIVATED: type[%s], direction[%p], id[%u]",
+ pa_log_debug("[AUTO(_ALL)] found a matched device and set state to ACTIVATED: type[%s], direction[%p], id[%u]",
route_info.device_infos[route_info.num_of_devices-1].type, device_direction, device_idx);
/* Set device state to activated */
pa_device_manager_set_device_state(device, DM_DEVICE_STATE_ACTIVATED);
break;
}
}
- if (data->route_type == STREAM_ROUTE_TYPE_AUTO && route_info.num_of_devices) {
+ if (data->route_type == STREAM_ROUTE_TYPE_AUTO && device) {
/* Set other device's state to deactivated */
PA_IDXSET_FOREACH(_device, conn_devices, conn_idx) {
if (device == _device)
}
/* Move sink-inputs/source-outputs if needed */
- if (!data->origins_from_new_data) {
+ if (data->stream_type == STREAM_SINK_INPUT)
+ sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+ else if (data->stream_type == STREAM_SOURCE_OUTPUT)
+ source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
+ if (data->idx_streams) {
+ PA_IDXSET_FOREACH (s, data->idx_streams, s_idx) {
+ if (sink && (sink != ((pa_sink_input*)s)->sink)) {
+ pa_sink_input_move_to(s, sink, FALSE);
+ pa_log_debug("[AUTO] *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, sink, sink->name);
+ } else if (source && (source != ((pa_source_output*)s)->source)) {
+ pa_source_output_move_to(s, source, FALSE);
+ pa_log_debug("[AUTO] *** source-output(%p,%u) moves to source(%p,%s)", s, ((pa_source_output*)s)->index, source, source->name);
+ }
+ }
+ }
+ /* unload combine sink */
+ if (data->stream_type==STREAM_SINK_INPUT && u->module_combine_sink) {
+ pa_sink *combine_sink = pa_namereg_get(u->module->core, SINK_COMBINED, PA_NAMEREG_SINK);
+ if (combine_sink->inputs) {
+ PA_IDXSET_FOREACH (s, combine_sink->inputs, s_idx) {
+ pa_sink_input_move_to(s, sink, FALSE);
+ pa_log_debug("[AUTO] *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, sink, sink->name);
+ }
+ }
+ pa_log_debug ("[AUTO] unload module[%s]", SINK_COMBINED);
+ pa_sink_suspend(pa_namereg_get(u->module->core, SINK_COMBINED, PA_NAMEREG_SINK), TRUE, PA_SUSPEND_USER);
+ pa_module_unload(u->module->core, u->module_combine_sink, TRUE);
+ u->module_combine_sink = NULL;
+ }
+ break;
+
+ } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL && device) {
+ /* find the proper sink/source */
+ /* currently, we support two sinks for combining */
+ if (data->stream_type == STREAM_SINK_INPUT && u->module_combine_sink) {
+ sink = pa_namereg_get(u->module->core, SINK_COMBINED, PA_NAMEREG_SINK);
+ pa_log_debug ("[AUTO_ALL] found the combine_sink already existed");
+ } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg1) {
+ sink = combine_sink_arg1 = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+ pa_log_debug ("[AUTO_ALL] combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, combine_sink_arg2);
+ } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg2) {
+ sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+ if(sink && !pa_streq(sink->name, combine_sink_arg1->name)) {
+ pa_log_debug ("[AUTO_ALL] combine_sink_arg2[%s]", sink->name);
+ combine_sink_arg2 = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+ /* load combine sink */
+ if (!u->module_combine_sink) {
+ args = pa_sprintf_malloc("sink_name=%s slaves=\"%s,%s\"", SINK_COMBINED, combine_sink_arg1->name, combine_sink_arg2->name);
+ pa_log_debug ("[AUTO_ALL] combined sink is not prepared, now load module[%s]", args);
+ u->module_combine_sink = pa_module_load(u->module->core, "module-combine-sink", args);
+ pa_xfree(args);
+ }
+ sink = pa_namereg_get(u->module->core, SINK_COMBINED, PA_NAMEREG_SINK);
+ PA_IDXSET_FOREACH (s, combine_sink_arg1->inputs, s_idx) {
+ pa_sink_input_move_to(s, sink, FALSE);
+ pa_log_debug("[AUTO_ALL] *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, sink, sink->name);
+ }
+ }
+ } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
+ source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
+ }
+
+ if (data->origins_from_new_data) {
if (data->stream_type == STREAM_SINK_INPUT)
- sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
- else if (data->stream_type == STREAM_SOURCE_OUTPUT)
- source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
+ *(data->proper_sink) = sink;
+ else
+ *(data->proper_source) = source;
+ } else {
+ /* Move sink-inputs/source-outputs if needed */
if (data->idx_streams) {
- PA_IDXSET_FOREACH (s, data->idx_streams, idx) {
- if (sink && sink != (data->origins_from_new_data?((pa_sink_input_new_data*)s)->sink:((pa_sink_input*)s)->sink))
+ PA_IDXSET_FOREACH (s, data->idx_streams, s_idx) {
+ if (sink && (sink != ((pa_sink_input*)s)->sink)) {
pa_sink_input_move_to(s, sink, FALSE);
- else if (source && source != (data->origins_from_new_data?((pa_source_output_new_data*)s)->source:((pa_source_output*)s)->source))
+ pa_log_debug("[AUTO(_ALL)] *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, sink, sink->name);
+ } else if (source && (source != ((pa_source_output*)s)->source)) {
pa_source_output_move_to(s, source, FALSE);
+ pa_log_debug("[AUTO(_ALL)] *** source-output(%p,%u) moves to source(%p,%s)", s, ((pa_source_output*)s)->index, source, source->name);
+ }
+ }
+ }
+ if (u->module_null_sink) {
+ pa_sink *null_sink = pa_namereg_get(u->module->core, SINK_NULL, PA_NAMEREG_SINK);
+ if (null_sink) {
+ PA_IDXSET_FOREACH (s, null_sink->inputs, s_idx) {
+ pa_sink_input_move_to(s, sink, FALSE);
+ pa_log_debug("[AUTO(_ALL)] *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, sink, sink->name);
+ }
}
}
}
- break;
}
}
+
if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL && route_info.num_of_devices) {
/* Set other device's state to deactivated */
PA_IDXSET_FOREACH(_device, conn_devices, conn_idx) {
} else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL && data->idx_manual_devices && data->idx_avail_devices) {
PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
- pa_log_debug("-- [MANUAL] avail_device[%u] for this role[%s]: type(%s)", idx, data->stream_role, device_type);
- PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, m_idx) {
+ pa_log_debug("[MANUAL] avail_device[%u] for this role[%s]: type(%s)", idx, data->stream_role, device_type);
+ PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, d_idx) {
+ pa_log_debug("[MANUAL] manual_device[%u] for this role[%s]: device_id(%u)", idx, data->stream_role, *device_id);
device = pa_device_manager_get_device_by_id(u->device_manager, *device_id);
if (device) {
dm_device_type = pa_device_manager_get_device_type(device);
dm_device_subtype = pa_device_manager_get_device_subtype(device);
device_direction = pa_device_manager_get_device_direction(device);
- pa_log_debug("-- [MANUAL] manual_devices, type[%s], subtype[%s], direction[%p]", dm_device_type, dm_device_subtype, device_direction);
+ pa_log_debug("[MANUAL] manual_device, type[%s], subtype[%s], direction[%p]", dm_device_type, dm_device_subtype, device_direction);
if (pa_streq(device_type, dm_device_type) &&
(((data->stream_type==STREAM_SINK_INPUT) && (device_direction & DM_DEVICE_DIRECTION_OUT)) ||
((data->stream_type==STREAM_SOURCE_OUTPUT) && (device_direction & DM_DEVICE_DIRECTION_IN)))) {
- pa_log_debug("-- [MANUAL] found a matched device: type[%s], direction[%p]", device_type, device_direction);
+ pa_log_debug("[MANUAL] found a matched device: type[%s], direction[%p]", device_type, device_direction);
route_info.num_of_devices++;
route_info.device_infos = pa_xrealloc(route_info.device_infos, sizeof(hal_device_info)*route_info.num_of_devices);
route_info.device_infos[route_info.num_of_devices-1].type = dm_device_type;
route_info.device_infos[route_info.num_of_devices-1].direction = (data->stream_type==STREAM_SINK_INPUT)?DIRECTION_OUT:DIRECTION_IN;
- pa_log_debug("-- [MANUAL] found a matched device and set state to ACTIVATED: type[%s], direction[%p]",
+ pa_log_debug("[MANUAL] found a matched device and set state to ACTIVATED: type[%s], direction[%p]",
route_info.device_infos[route_info.num_of_devices-1].type, device_direction);
/* Set device state to activated */
pa_device_manager_set_device_state(device, DM_DEVICE_STATE_ACTIVATED);
}
/* Move sink-inputs/source-outputs if needed */
- if (!data->origins_from_new_data) {
+ if (device && !data->origins_from_new_data) {
if (data->stream_type == STREAM_SINK_INPUT)
sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
else if (data->stream_type == STREAM_SOURCE_OUTPUT)
source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
if (data->idx_streams) {
PA_IDXSET_FOREACH (s, data->idx_streams, idx) {
- if (sink && sink != (data->origins_from_new_data?((pa_sink_input_new_data*)s)->sink:((pa_sink_input*)s)->sink))
+ if (sink && (sink != ((pa_sink_input*)s)->sink)) {
pa_sink_input_move_to(s, sink, FALSE);
- else if (source && source != (data->origins_from_new_data?((pa_source_output_new_data*)s)->source:((pa_source_output*)s)->source))
+ pa_log_debug("[MANUAL] *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, sink, sink->name);
+ } else if (source && (source != ((pa_source_output*)s)->source)) {
pa_source_output_move_to(s, source, FALSE);
+ pa_log_debug("[MANUAL] *** source-output(%p,%u) moves to source(%p,%s)", s, ((pa_source_output*)s)->index, source, source->name);
+ }
}
}
}
int i = 0;
hal_route_option route_option;
- pa_log("route_options_update_hook_cb is called. (%p), stream_role(%s), route_options(%p), num_of_options(%d)",
+ pa_log_info("route_options_update_hook_cb is called. (%p), stream_role(%s), route_options(%p), num_of_options(%d)",
data, data->stream_role, data->route_options, pa_idxset_size(data->route_options));
route_option.role = data->stream_role;
route_option.num_of_options = pa_idxset_size(data->route_options);
route_option.options = pa_xmalloc0(sizeof(char*)*route_option.num_of_options);
while (data->route_options && (option_name = pa_idxset_iterate(data->route_options, &state, NULL))) {
- pa_log("-- option : %s", option_name);
+ pa_log_debug("-- option : %s", option_name);
route_option.options[i++] = option_name;
}
return PA_HOOK_OK;
}
+/* Reorganize routing when a device has been connected or disconnected */
+static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_device_manager_hook_data_for_conn_changed *conn, struct userdata *u) {
+ uint32_t s_idx = 0;
+ pa_sink_input *s = NULL;
+ const char *device_type = NULL;
+ const char *device_subtype = NULL;
+ dm_device_direction_t device_direction = DM_DEVICE_DIRECTION_OUT;
+
+ device_direction = pa_device_manager_get_device_direction(conn->device);
+ device_type = pa_device_manager_get_device_type(conn->device);
+ device_subtype = pa_device_manager_get_device_subtype(conn->device);
+ pa_log_info("device_connection_changed_hook_cb is called. conn(%p), is_connected(%d), device(%p,%s,%s), direction(%p)",
+ conn, conn->is_connected, conn->device, device_type, device_subtype, device_direction);
+
+ if (!conn->is_connected && pa_streq(DEVICE_TYPE_BT, device_type) &&
+ device_subtype && pa_streq(DEVICE_PROFILE_BT_A2DP, device_subtype) &&
+ device_direction == DM_DEVICE_DIRECTION_OUT) {
+ if (u->module_combine_sink) {
+ /* unload combine sink */
+ pa_sink *combine_sink = pa_namereg_get(u->module->core, SINK_COMBINED, PA_NAMEREG_SINK);
+ pa_sink *null_sink = pa_namereg_get(u->module->core, SINK_NULL, PA_NAMEREG_SINK);
+ if (combine_sink->inputs) {
+ PA_IDXSET_FOREACH (s, combine_sink->inputs, s_idx) {
+ pa_sink_input_move_to(s, null_sink, FALSE);
+ pa_log_debug(" *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, null_sink, null_sink->name);
+ }
+ }
+ pa_sink_suspend(pa_namereg_get(u->module->core, SINK_COMBINED, PA_NAMEREG_SINK), TRUE, PA_SUSPEND_USER);
+ pa_module_unload(u->module->core, u->module_combine_sink, TRUE);
+ u->module_combine_sink = NULL;
+ }
+ }
+
+ return PA_HOOK_OK;
+}
+
#ifdef HAVE_DBUS
static void _do_something1(char* arg1, int arg2, void *data)
{
{
pa_modargs *ma = NULL;
struct userdata *u;
+ char *args = NULL;
pa_assert(m);
u->communicator.comm_hook_update_route_options_slot = pa_hook_connect(
pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_UPDATE_ROUTE_OPTIONS),
PA_HOOK_EARLY, (pa_hook_cb_t)route_options_update_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);
}
u->stream_manager = pa_stream_manager_init(u->core);
u->device_manager = pa_device_manager_init(u->core);
#endif
+ /* load null sink/source */
+ args = pa_sprintf_malloc("sink_name=%s", SINK_NULL);
+ u->module_null_sink = pa_module_load(u->module->core, "module-null-sink", args);
+ pa_xfree(args);
+ args = pa_sprintf_malloc("source_name=%s", SOURCE_NULL);
+ u->module_null_source = pa_module_load(u->module->core, "module-null-source", args);
+ pa_xfree(args);
+
__load_dump_config(u);
#ifdef HAVE_DBUS
if (!(u = m->userdata))
return;
+
+ pa_module_unload(u->module->core, u->module_null_sink, TRUE);
+ u->module_null_sink = NULL;
+ pa_module_unload(u->module->core, u->module_null_source, TRUE);
+ u->module_null_source = NULL;
+
#ifdef HAVE_DBUS
dbus_deinit(u);
#endif
pa_hook_slot_free(u->communicator.comm_hook_change_route_slot);
if (u->communicator.comm_hook_change_route_slot)
pa_hook_slot_free(u->communicator.comm_hook_update_route_options_slot);
+ if (u->communicator.comm_hook_device_connection_changed_slot)
+ pa_hook_slot_free(u->communicator.comm_hook_device_connection_changed_slot);
pa_communicator_unref(u->communicator.comm);
}
volume_info* v = NULL;
void *state = NULL;
const char *vol_type_str = NULL;
-
pa_assert(m);
dict = iniparser_load(VOLUME_INI_TUNED_PATH);
ret = -1;
goto FAILURE;
}
+ if (key) {
+ free(key);
+ key = NULL;
+ }
}
/* Load gain table */
ret = -1;
goto FAILURE;
}
+ if (key) {
+ free(key);
+ key = NULL;
+ }
}
FAILURE:
return ret;
}
-static int is_hal_volume_by_type(pa_stream_manager *m, const char *volume_type, stream_type_t stream_type, pa_bool_t *is_hal_volume) {
+static int is_hal_volume_by_type(pa_stream_manager *m, stream_type_t stream_type, const char *volume_type, pa_bool_t *is_hal_volume) {
volume_info *v = NULL;
void * volumes = NULL;
pa_assert(m);
- pa_assert(is_hal_volume);
pa_assert(volume_type);
+ pa_assert(is_hal_volume);
volumes = (stream_type==STREAM_SINK_INPUT)?m->volume_map.out_volumes:m->volume_map.in_volumes;
if (volumes) {
return 0;
}
-#ifdef PRIMARY_VOLUME
-int _set_primary_volume(pa_stream_manager *m, void* key, int volumetype, int is_new) {
- const int NO_INSTANCE = -1;
- const int CAPURE_ONLY = -2; /* check mm_sound.c */
-
- int ret = -1;
- int default_primary_vol = NO_INSTANCE;
- int default_primary_vol_prio = NO_INSTANCE;
-
- struct primary_volume_type_info* p_volume = NULL;
- struct primary_volume_type_info* n_p_volume = NULL;
- struct primary_volume_type_info* new_volume = NULL;
-
- /* descending order */
- int priority[] = {
- AUDIO_PRIMARY_VOLUME_TYPE_SYSTEM,
- AUDIO_PRIMARY_VOLUME_TYPE_NOTIFICATION,
- AUDIO_PRIMARY_VOLUME_TYPE_ALARM,
- AUDIO_PRIMARY_VOLUME_TYPE_RINGTONE,
- AUDIO_PRIMARY_VOLUME_TYPE_MEDIA,
- AUDIO_PRIMARY_VOLUME_TYPE_VOICE,
- AUDIO_PRIMARY_VOLUME_TYPE_CALL,
- AUDIO_PRIMARY_VOLUME_TYPE_VOIP,
- AUDIO_PRIMARY_VOLUME_TYPE_FIXED,
- AUDIO_PRIMARY_VOLUME_TYPE_MAX /* for capture handle */
- };
-
- if(is_new) {
- new_volume = pa_xnew0(struct primary_volume_type_info, 1);
- new_volume->key = key;
- new_volume->volumetype = volumetype;
- new_volume->priority = priority[volumetype];
-
- /* no items */
- if(m->primary_volume == NULL) {
- PA_LLIST_PREPEND(struct primary_volume_type_info, m->primary_volume, new_volume);
- } else {
- /* already added */
- PA_LLIST_FOREACH_SAFE(p_volume, n_p_volume, m->primary_volume) {
- if(p_volume->key == key) {
- ret = 0;
- pa_xfree(new_volume);
- goto exit;
- }
- }
-
- /* add item */
- PA_LLIST_FOREACH_SAFE(p_volume, n_p_volume, m->primary_volume) {
- if(p_volume->priority <= priority[volumetype]) {
- PA_LLIST_INSERT_AFTER(struct primary_volume_type_info, m->primary_volume, p_volume, new_volume);
- break;
- } else if(p_volume->priority > priority[volumetype]) {
- PA_LLIST_PREPEND(struct primary_volume_type_info, m->primary_volume, new_volume);
- break;
- }
- }
- }
- pa_log_info("add volume data to primary volume list. volumetype(%d), priority(%d)", new_volume->volumetype, new_volume->priority);
- } else { /* remove(unlink) */
- PA_LLIST_FOREACH_SAFE(p_volume, n_p_volume, m->primary_volume) {
- if(p_volume->key == key) {
- PA_LLIST_REMOVE(struct primary_volume_type_info, m->primary_volume, p_volume);
- pa_log_info("remove volume data from primary volume list. volumetype(%d), priority(%d)", p_volume->volumetype, p_volume->priority);
- pa_xfree(p_volume);
- break;
- }
- }
- }
-
- if(m->primary_volume) {
- if(m->primary_volume->volumetype == AUDIO_PRIMARY_VOLUME_TYPE_MAX) {
- default_primary_vol = CAPURE_ONLY;
- default_primary_vol_prio = CAPURE_ONLY;
- } else {
- default_primary_vol = m->primary_volume->volumetype;
- default_primary_vol_prio = m->primary_volume->priority;
- }
- }
- pa_log_info("current primary volumetype(%d), priority(%d)", default_primary_vol, default_primary_vol_prio);
-
- if(vconf_set_int(VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, default_primary_vol) < 0) {
- ret = -1;
- pa_log_info("VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE set failed default_primary_vol(%d)", default_primary_vol);
- }
-
-exit:
-
- return ret;
-}
-#endif
-
static int get_volume_value(pa_stream_manager *m, stream_type_t stream_type, pa_bool_t is_hal_volume, const char *volume_type, uint32_t volume_level, double *volume_value) {
int ret = 0;
double volume_linear = 1.0f;
-
pa_assert(m);
pa_assert(volume_type);
pa_assert(volume_value);
const char *volume_type_str = NULL;
const char *modifier_gain = NULL;
void *s = NULL;
- void *volumes = NULL;
+ pa_hashmap *volumes = NULL;
pa_assert(m);
pa_assert(volume_type);
/* Check if it is related to HAL volume */
- if (is_hal_volume_by_type(m, volume_type, stream_type, &is_hal_volume)) {
+ if (is_hal_volume_by_type(m, stream_type, volume_type, &is_hal_volume)) {
pa_log_error("failed to is_hal_volume_by_type(), stream_type(%d), volume_type(%s)", stream_type, volume_type);
return -1;
}
int32_t get_volume_level_by_type(pa_stream_manager *m, pa_volume_get_command_t command, stream_type_t stream_type, const char *volume_type, uint32_t *volume_level) {
int32_t ret = 0;
pa_bool_t is_hal_volume = FALSE;
- void *volumes = NULL;
+ pa_hashmap *volumes = NULL;
pa_assert(m);
pa_assert(volume_type);
/* Check if it is related to HAL volume */
- if (is_hal_volume_by_type(m, volume_type, stream_type, &is_hal_volume)) {
+ if (is_hal_volume_by_type(m, stream_type, volume_type, &is_hal_volume)) {
pa_log_error("failed to is_hal_volume_by_type(), stream_type(%d), volume_type(%s)", stream_type, volume_type);
return -1;
}
double volume_linear = 1.0f;
const char *volume_type_str = NULL;
const char *modifier_gain = NULL;
-
pa_assert(m);
s = pa_idxset_get_by_index(stream_type==STREAM_SINK_INPUT?m->core->sink_inputs:m->core->source_outputs, idx);
}
/* Check if it is related to HAL volume */
- if (is_hal_volume_by_type(m, volume_type_str, stream_type, &is_hal_volume)) {
+ if (is_hal_volume_by_type(m, stream_type, volume_type_str, &is_hal_volume)) {
pa_log_error("failed to is_hal_volume_by_type(), stream_type(%d), volume_type(%s)", stream_type, volume_type_str);
return -1;
}
double volume_linear = 1.0f;
const char *volume_type_str = NULL;
const char *modifier_gain = NULL;
-
pa_assert(m);
if ((volume_type_str = pa_proplist_gets(stream_type==STREAM_SINK_INPUT?((pa_sink_input_new_data*)nd)->proplist:((pa_source_output_new_data*)nd)->proplist, PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
}
/* Check if it is related to HAL volume */
- if (is_hal_volume_by_type(m, volume_type_str, stream_type, &is_hal_volume)) {
+ if (is_hal_volume_by_type(m, stream_type, volume_type_str, &is_hal_volume)) {
pa_log_error("failed to is_hal_volume_by_type(), stream_type(%d), volume_type(%s)", stream_type, volume_type_str);
return -1;
}
void *s = NULL;
uint32_t idx = 0;
const char *volume_type_str = NULL;
+ volume_info *v = NULL;
+ pa_hashmap *volumes = NULL;
+ pa_bool_t muted_by_type = FALSE;
pa_assert(m);
pa_log_info("set_volume_mute_by_idx, stream_type:%d stream_idx:%u mute:%d", stream_type, stream_idx, mute);
if ((volume_type_str = pa_proplist_gets((stream_type==STREAM_SINK_INPUT)?((pa_sink_input*)s)->proplist:((pa_source_output*)s)->proplist, PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
/* do nothing */
} else {
- pa_log_debug("stream[%d] doesn't have volume type", stream_idx);
- return -1;
+ pa_log_warn("stream[%d] doesn't have volume type", stream_idx);
}
} else {
pa_log_warn("stream[%u] doesn't exist", stream_idx);
- return -1;
}
}
- /* Check if it is related to HAL volume */
- if (is_hal_volume_by_type(m, volume_type_str, stream_type, &is_hal_volume)) {
- pa_log_error("failed to is_hal_volume_by_type(), stream_type(%d), volume_type(%s)", stream_type, volume_type_str);
- return -1;
- }
-
- if (is_hal_volume)
- if (pa_hal_manager_set_mute(m->hal, volume_type_str, (stream_type==STREAM_SINK_INPUT)?DIRECTION_OUT:DIRECTION_IN, mute))
+ /* Get mute state of the volume type of this stream */
+ if (volume_type_str) {
+ volumes = (stream_type==STREAM_SINK_INPUT)?m->volume_map.out_volumes:m->volume_map.in_volumes;
+ if (volumes) {
+ v = pa_hashmap_get(volumes, volume_type_str);
+ if (v)
+ muted_by_type = v->is_muted;
+ } else {
+ pa_log_error("could not get volumes in volume map, stream_type(%d), volume_type(%s)", stream_type, volume_type_str);
return -1;
+ }
+ }
- PA_IDXSET_FOREACH(s, (stream_type==STREAM_SINK_INPUT)?m->core->sink_inputs:m->core->source_outputs, idx) {
- /* Update mute of the stream if it has requested idx */
- if (stream_idx == idx) {
- if (stream_type == STREAM_SINK_INPUT)
- pa_sink_input_set_mute((pa_sink_input*)s, mute, TRUE);
- else if (stream_type == STREAM_SOURCE_OUTPUT)
- pa_source_output_set_mute((pa_source_output*)s, mute, TRUE);
- break;
+ if (!muted_by_type) {
+ PA_IDXSET_FOREACH(s, (stream_type==STREAM_SINK_INPUT)?m->core->sink_inputs:m->core->source_outputs, idx) {
+ /* Update mute of the stream if it has requested idx */
+ if (stream_idx == idx) {
+ if (stream_type == STREAM_SINK_INPUT)
+ pa_sink_input_set_mute((pa_sink_input*)s, mute, TRUE);
+ else if (stream_type == STREAM_SOURCE_OUTPUT)
+ pa_source_output_set_mute((pa_source_output*)s, mute, TRUE);
+ break;
+ }
}
}
}
/* Check if it is related to HAL volume */
- if (is_hal_volume_by_type(m, volume_type_str, stream_type, &is_hal_volume)) {
+ if (is_hal_volume_by_type(m, stream_type, volume_type_str, &is_hal_volume)) {
pa_log_error("failed to is_hal_volume_by_type(), stream_type(%d), volume_type(%s)", stream_type, volume_type_str);
return -1;
}
void *state = NULL;
uint32_t idx = 0;
pa_assert(m);
+
pa_log_debug("==========[START volume-map dump]==========");
while (m->volume_map.in_volumes && (s = pa_hashmap_iterate(m->volume_map.in_volumes, &state, &volume_type))) {
if (s) {
int ret = 0;
int i = 0;
void *state = NULL;
- void *volumes = NULL;
+ pa_hashmap *volumes = NULL;
stream_info *s = NULL;
volume_info *v = NULL;
pa_assert(m);
}
#endif
-#ifdef PRIMARY_VOLUME
- vconf_set_int (VCONFKEY_SOUND_PRIMARY_VOLUME_TYPE, -1);
-#endif
FAILURE:
return ret;
}
int32_t get_volume_mute_by_type(pa_stream_manager *m, stream_type_t stream_type, const char *volume_type, pa_bool_t *mute) {
volume_info *v = NULL;
- void *volumes = NULL;
+ pa_hashmap *volumes = NULL;
pa_assert(m);
pa_assert(volume_type);
pa_assert(mute);
pa_bool_t is_hal_volume = FALSE;
volume_info *v = NULL;
void *s = NULL;
- void *volumes = NULL;
+ pa_hashmap *volumes = NULL;
uint32_t idx;
const char *volume_type_str = NULL;
pa_assert(m);
pa_assert(volume_type);
/* Check if it is related to HAL volume */
- if (is_hal_volume_by_type(m, volume_type, stream_type, &is_hal_volume)) {
+ if (is_hal_volume_by_type(m, stream_type, volume_type, &is_hal_volume)) {
pa_log_error("failed to is_hal_volume_by_type(), stream_type(%d), volume_type(%s)", stream_type, volume_type);
return -1;
}
#define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL "GetVolumeMaxLevel"
#define STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE "SetVolumeMute"
#define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE "GetVolumeMute"
+#define STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE "GetCurrentVolumeType" /* the type that belongs to the stream of the current max priority */
#define GET_STREAM_NEW_PROPLIST(stream, type) \
(type == STREAM_SINK_INPUT? ((pa_sink_input_new_data*)stream)->proplist : ((pa_source_output_new_data*)stream)->proplist)
static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata);
enum method_handler_index {
METHOD_HANDLER_GET_STREAM_INFO,
METHOD_HANDLER_GET_VOLUME_MAX_LEVEL,
METHOD_HANDLER_SET_VOLUME_MUTE,
METHOD_HANDLER_GET_VOLUME_MUTE,
+ METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE,
METHOD_HANDLER_MAX
};
{ "type", "s", "in" },
{ "on/off", "u", "out" },
{ "ret_msg", "s", "out" } };
-static char* signature_args_for_in[] = { "s", "", "uauau", "uas", "ssu", "ss", "ss", "ssu", "ss"};
+static pa_dbus_arg_info get_current_volume_type_args[] = { { "io_direction", "s", "in" },
+ { "type", "s", "out" },
+ { "ret_msg", "s", "out" } };
+static char* signature_args_for_in[] = { "s", "", "uauau", "uas", "ssu", "ss", "ss", "ssu", "ss", "s"};
static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
[METHOD_HANDLER_GET_STREAM_INFO] = {
.arguments = get_volume_mute_args,
.n_arguments = sizeof(get_volume_mute_args) / sizeof(pa_dbus_arg_info),
.receive_cb = handle_get_volume_mute },
+ [METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE] = {
+ .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE,
+ .arguments = get_current_volume_type_args,
+ .n_arguments = sizeof(get_current_volume_type_args) / sizeof(pa_dbus_arg_info),
+ .receive_cb = handle_get_current_volume_type },
};
-const char* stream_manager_dbus_ret_str[] = {"STREAM_MANAGER_RETURN_OK","STREAM_MANAGER_RETURN_ERROR"};
+const char *dbus_str_none = "none";
+const char* stream_manager_dbus_ret_str[] = {"STREAM_MANAGER_RETURN_OK","STREAM_MANAGER_RETURN_ERROR", "STREAM_MANAGER_RETURN_ERROR_NO_STREAM"};
enum {
RET_MSG_INDEX_OK,
- RET_MSG_INDEX_ERROR
+ RET_MSG_INDEX_ERROR,
+ RET_MSG_INDEX_ERROR_NO_STREAM,
};
#ifdef USE_DBUS_PROTOCOL
" <arg name=\"on/off\" direction=\"out\" type=\"u\"/>" \
" <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
" </method>" \
+ " <method name=\"STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE\">" \
+ " <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>" \
+ " <arg name=\"type\" direction=\"out\" type=\"s\"/>" \
+ " <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
+ " </method>" \
" </interface>" \
" <interface name=\"org.freedesktop.DBus.Introspectable\">" \
" <method name=\"Introspect\">" \
typedef enum _process_command_type {
PROCESS_COMMAND_PREPARE,
+ PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA,
PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED,
PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED,
PROCESS_COMMAND_UPDATE_VOLUME,
- PROCESS_COMMAND_INFORM_STREAM_CONNECTED,
- PROCESS_COMMAND_INFORM_STREAM_DISCONNECTED,
PROCESS_COMMAND_ADD_PARENT_ID,
PROCESS_COMMAND_REMOVE_PARENT_ID,
} process_command_type_t;
NOTIFY_COMMAND_CHANGE_ROUTE_START,
NOTIFY_COMMAND_CHANGE_ROUTE_END,
NOTIFY_COMMAND_UPDATE_ROUTE_OPTIONS,
+ NOTIFY_COMMAND_INFORM_STREAM_CONNECTED,
+ NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED,
} notify_command_type_t;
const char* process_command_type_str[] = {
"PREPARE",
+ "CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA",
"CHANGE_ROUTE_BY_STREAM_STARTED",
"CHANGE_ROUTE_BY_STREAM_ENDED",
"UPDATE_VOLUME",
- "INFORM_STREAM_CONNECTED",
- "INFORM_STREAM_DISCONNECTED",
"ADD_PARENT_ID",
"REMOVE_PARENT_ID",
};
"CHANGE_ROUTE_START",
"CHANGE_ROUTE_END",
"UPDATE_ROUTE_OPTIONS",
+ "INFORM_STREAM_CONNECTED",
+ "INFORM_STREAM_DISCONNECTED",
};
#define STREAM_MAP_FILE "/etc/pulse/stream-map.json"
int32_t priorities[AVAIL_STREAMS_MAX];
} stream_list;
-static void do_notify(notify_command_type_t command, stream_type_t type, pa_stream_manager *m, void *user_data);
+static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, void *user_data);
static pa_process_stream_result_t process_stream(stream_type_t type, void *stream, process_command_type_t command, pa_stream_manager *m);
static int get_available_streams_from_map(pa_stream_manager *m, stream_list *list) {
uint32_t *out_device_list = NULL;
int list_len_in = 0;
int list_len_out = 0;
+ uint32_t idx = 0;
+ uint32_t *device_id = NULL;
stream_parent *sp = NULL;
DBusMessage *reply = NULL;
pa_stream_manager *m = (pa_stream_manager*)userdata;
if (sp) {
if (!in_device_list && !out_device_list) {
pa_log_error("invalid arguments");
- pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
- pa_assert_se(dbus_connection_send(conn, reply, NULL));
- dbus_message_unref(reply);
- return;
+ goto FAILURE;
}
- if (in_device_list && list_len_in) {
- if (sp->idx_route_in_devices) {
- pa_idxset_remove_all(sp->idx_route_in_devices, NULL);
+
+ if (sp->idx_route_in_devices) {
+ PA_IDXSET_FOREACH(device_id, sp->idx_route_in_devices, idx) {
+ pa_idxset_remove_by_data(sp->idx_route_in_devices, device_id, NULL);
+ pa_xfree(device_id);
+ }
+ if (in_device_list && list_len_in) {
for (i = 0; i < list_len_in; i++) {
- pa_idxset_put(sp->idx_route_in_devices, &in_device_list[i], NULL);
+ pa_idxset_put(sp->idx_route_in_devices, pa_xmemdup(&in_device_list[i], sizeof(uint32_t)), NULL);
pa_log_debug(" -- [in] device id:%u", in_device_list[i]);
}
- if (m->cur_highest_priority.source_output) {
- /* if any stream that belongs to this id has been activated, do notify right away */
- if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
- pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the route change",
- (m->cur_highest_priority.source_output)->index, id);
- do_notify(NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, m, m->cur_highest_priority.source_output);
- }
+ }
+ if (m->cur_highest_priority.source_output) {
+ /* if any stream that belongs to this id has been activated, do notify right away */
+ if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
+ pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the route change",
+ (m->cur_highest_priority.source_output)->index, id);
+ do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, m->cur_highest_priority.source_output);
}
}
+ } else {
+ pa_log_error("failed to update, idx_route_in_devices[%p]", sp->idx_route_in_devices);
+ goto FAILURE;
}
- if (out_device_list && list_len_out) {
- if (sp->idx_route_out_devices) {
- pa_idxset_remove_all(sp->idx_route_out_devices, NULL);
+
+ if (sp->idx_route_out_devices) {
+ PA_IDXSET_FOREACH(device_id, sp->idx_route_out_devices, idx) {
+ pa_idxset_remove_by_data(sp->idx_route_out_devices, device_id, NULL);
+ pa_xfree(device_id);
+ }
+ if (out_device_list && list_len_out) {
for (i = 0; i < list_len_out; i++) {
- pa_idxset_put(sp->idx_route_out_devices, &out_device_list[i], NULL);
+ pa_idxset_put(sp->idx_route_out_devices, pa_xmemdup(&out_device_list[i], sizeof(uint32_t)), NULL);
pa_log_debug(" -- [out] device id:%u", out_device_list[i]);
}
- if (m->cur_highest_priority.sink_input) {
- /* if any stream that belongs to this id has been activated, do notify right away */
- if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
- pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the route change",
- (m->cur_highest_priority.sink_input)->index, id);
- do_notify(NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, m, m->cur_highest_priority.sink_input);
- }
+ }
+ if (m->cur_highest_priority.sink_input) {
+ /* if any stream that belongs to this id has been activated, do notify right away */
+ if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
+ pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the route change",
+ (m->cur_highest_priority.sink_input)->index, id);
+ do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, m->cur_highest_priority.sink_input);
}
}
+ } else {
+ pa_log_error("failed to update, idx_route_out_devices[%p]", sp->idx_route_out_devices);
+ goto FAILURE;
}
pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
} else {
pa_log_error("could not find matching client for this parent_id[%u]", id);
- pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
+ goto FAILURE;
}
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
+ return;
+FAILURE:
+ pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
+ pa_assert_se(dbus_connection_send(conn, reply, NULL));
+ dbus_message_unref(reply);
+ return;
}
static void handle_set_stream_route_options(DBusConnection *conn, DBusMessage *msg, void *userdata) {
if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the options",
(m->cur_highest_priority.sink_input)->index, id);
- do_notify(NOTIFY_COMMAND_UPDATE_ROUTE_OPTIONS, STREAM_SINK_INPUT, m, sp->idx_route_options);
+ do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTIONS, STREAM_SINK_INPUT, sp->idx_route_options);
}
}
if (m->cur_highest_priority.source_output) {
if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the options",
(m->cur_highest_priority.source_output)->index, id);
- do_notify(NOTIFY_COMMAND_UPDATE_ROUTE_OPTIONS, STREAM_SOURCE_OUTPUT, m, sp->idx_route_options);
+ do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTIONS, STREAM_SOURCE_OUTPUT, sp->idx_route_options);
}
}
pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
+ return;
}
static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
FAILURE:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
+ return;
}
static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
FAILURE:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
+ return;
}
static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
FAILURE:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
+ return;
}
static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
FAILURE:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
+ return;
}
static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
FAILURE:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
+ return;
+}
+
+static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ const char *direction = NULL;
+ const char *type = NULL;
+ void *s = NULL;
+ stream_type_t stream_type = STREAM_SINK_INPUT;
+
+ DBusMessage *reply = NULL;
+ pa_stream_manager *m = (pa_stream_manager*)userdata;
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(m);
+
+ pa_assert_se(dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &direction,
+ DBUS_TYPE_INVALID));
+ pa_log_info("handle_get_current_volume_type(), direction[%s]", direction);
+
+ pa_assert_se((reply = dbus_message_new_method_return(msg)));
+
+ if (pa_streq(direction, "in"))
+ stream_type = STREAM_SOURCE_OUTPUT;
+ else if (pa_streq(direction, "out"))
+ stream_type = STREAM_SINK_INPUT;
+ else {
+ pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
+ pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
+ goto FAILURE;
+ }
+
+ s = (stream_type == STREAM_SINK_INPUT)?m->cur_highest_priority.sink_input:m->cur_highest_priority.source_output;
+ if (s) {
+ type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE);
+ pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID));
+ pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
+ } else {
+ pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
+ 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));
+ }
+
+FAILURE:
+ pa_assert_se(dbus_connection_send(conn, reply, NULL));
+ dbus_message_unref(reply);
+ return;
}
static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
char *volume_type_out_str = NULL;
json_object *volume_type_in_o;
json_object *volume_type_out_o;
+ void *state = NULL;
pa_assert(m);
return 0;
failed:
if (m->stream_map) {
- if (s->idx_avail_in_devices)
- pa_idxset_free(s->idx_avail_in_devices, NULL);
- if (s->idx_avail_out_devices)
- pa_idxset_free(s->idx_avail_out_devices, NULL);
- if (s->idx_avail_frameworks)
- pa_idxset_free(s->idx_avail_frameworks, NULL);
+ PA_HASHMAP_FOREACH(s, m->stream_map, state) {
+ if (s->idx_avail_in_devices)
+ pa_idxset_free(s->idx_avail_in_devices, NULL);
+ if (s->idx_avail_out_devices)
+ pa_idxset_free(s->idx_avail_out_devices, NULL);
+ if (s->idx_avail_frameworks)
+ pa_idxset_free(s->idx_avail_frameworks, NULL);
+ pa_xfree(s);
+ }
pa_hashmap_free(m->stream_map);
}
return -1;
return FALSE;
}
} else {
- pa_log_error("p_idx(%s) or idx(%u) is not valid", p_idx, parent_idx);
+ pa_log_warn("p_idx(%s) or idx(%u) is not valid", p_idx, parent_idx);
return FALSE;
}
return TRUE;
cur_max_stream = m->cur_highest_priority.source_output;
}
- pa_log_info("update_the_highest_priority_stream(), command(%d), stream_type(%d), role(%s)", command, type, role);
- if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
+ pa_log_info("update_the_highest_priority_stream(), stream_type(%d), role(%s), command(%d)", type, role, command);
+ if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA || command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
if (cur_max_stream == NULL) {
*need_to_update = TRUE;
- pa_log_debug("to be : set cur_highest to mine");
+ pa_log_debug("set cur_highest to mine");
} else {
/* TODO : need to check if this stream should be played to external devices */
- priority = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY);
+ if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA)
+ priority = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY);
+ else {
+ if (cur_max_stream == (type==STREAM_SINK_INPUT)?((pa_sink_input*)mine):((pa_source_output*)mine)) {
+ pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, skip it..");
+ return FALSE;
+ }
+ priority = pa_proplist_gets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY);
+ }
cur_max_priority = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE_PRIORITY);
cur_max_role = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE);
if (!cur_max_priority || !cur_max_role) {
return TRUE;
} else {
*need_to_update = TRUE;
- pa_log_debug("to be : update cur_highest to mine(%s)", role);
+ pa_log_debug("update cur_highest to mine(%s)", role);
}
}
}
if (sp)
select_data->idx_manual_devices = (type==STREAM_SINK_INPUT)?(sp->idx_route_out_devices):(sp->idx_route_in_devices);
else
- pa_log_error("Failed to get the stream parent of idx(%u)", idx);
+ pa_log_warn("Failed to get the stream parent of idx(%u)", idx);
}
}
}
/* set route options */
route_data->idx_route_options = sp->idx_route_options;
} else
- pa_log_error("Failed to get the stream parent of idx(%u)", parent_idx);
+ pa_log_warn("Failed to get the stream parent of idx(%u)", parent_idx);
} else
pa_log_warn("Could not get the parent id of this stream, but keep going...");
route_data->idx_manual_devices = (type==STREAM_SINK_INPUT)?(sp->idx_route_out_devices):(sp->idx_route_in_devices);
route_data->idx_streams = (type==STREAM_SINK_INPUT)?(sp->idx_sink_inputs):(sp->idx_source_outputs);
} else
- pa_log_error("Failed to get the stream parent of idx(%u)", parent_idx);
+ pa_log_warn("Failed to get the stream parent of idx(%u)", parent_idx);
}
}
break;
return;
}
-static void do_notify(notify_command_type_t command, stream_type_t type, pa_stream_manager *m, void *user_data) {
+static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, void *user_data) {
char *priority = NULL;
char *role = NULL;
pa_stream_manager_hook_data_for_select hook_call_select_data;
pa_stream_manager_hook_data_for_route hook_call_route_data;
pa_stream_manager_hook_data_for_options hook_call_options_data;
+ hal_stream_connection_info stream_conn_info;
void *s;
pa_assert(m);
role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
hook_call_route_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
if (type == STREAM_SINK_INPUT) {
- if (((pa_sink_input_new_data*)s)->sink)
- hook_call_route_data.idx_streams = ((pa_sink_input_new_data*)s)->sink->inputs;
hook_call_route_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
} else if (type == STREAM_SOURCE_OUTPUT) {
- if (((pa_source_output_new_data*)s)->source)
- hook_call_route_data.idx_streams = ((pa_source_output_new_data*)s)->source->outputs;
hook_call_route_data.proper_source = &(((pa_source_output_new_data*)s)->source);
}
} else {
priority = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE_PRIORITY);
role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
- hook_call_route_data.idx_streams = (type==STREAM_SINK_INPUT)?((pa_sink_input*)s)->sink->inputs:((pa_source_output*)s)->source->outputs;
+ if (type == STREAM_SINK_INPUT) {
+ if (((pa_sink_input*)s)->sink)
+ hook_call_route_data.idx_streams = ((pa_sink_input*)s)->sink->inputs;
+ } else if (type == STREAM_SOURCE_OUTPUT) {
+ if (((pa_source_output*)s)->source)
+ hook_call_route_data.idx_streams = ((pa_source_output*)s)->source->outputs;
+ }
}
hook_call_route_data.stream_type = type;
hook_call_route_data.stream_role = role;
fill_device_info_to_hook_data(&hook_call_route_data, command, type, s, m);
+ if (hook_call_route_data.route_type == STREAM_ROUTE_TYPE_MANUAL) {
+ if (!pa_idxset_size(hook_call_route_data.idx_manual_devices)) {
+ pa_log_info("no manual device for this type(%d), need to unset route", type);
+ hook_call_route_data.stream_role = "reset";
+ }
+ }
pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data);
}
break;
}
case NOTIFY_COMMAND_CHANGE_ROUTE_END: {
- pa_stream_manager_hook_data_for_route hook_call_data;
- memset(&hook_call_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
+ memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
s = (type==STREAM_SINK_INPUT)?m->cur_highest_priority.sink_input:m->cur_highest_priority.source_output;
if (s) {
priority = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE_PRIORITY);
role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
- hook_call_data.stream_type = type;
- hook_call_data.stream_role = role;
- hook_call_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
- hook_call_data.idx_streams = (type==STREAM_SINK_INPUT)?((pa_sink_input*)s)->sink->inputs:((pa_source_output*)s)->source->outputs;
- fill_device_info_to_hook_data(&hook_call_data, command, type, s, m);
+ hook_call_route_data.stream_type = type;
+ hook_call_route_data.stream_role = role;
+ hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
+ hook_call_route_data.idx_streams = (type==STREAM_SINK_INPUT)?((pa_sink_input*)s)->sink->inputs:((pa_source_output*)s)->source->outputs;
+ fill_device_info_to_hook_data(&hook_call_route_data, command, type, s, m);
} else {
pa_log_info("no stream for this type(%d), need to unset route", type);
- hook_call_data.stream_type = type;
- hook_call_data.stream_role = "reset";
+ hook_call_route_data.stream_type = type;
+ hook_call_route_data.stream_role = "reset";
}
- pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_data);
+ pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data);
break;
}
case NOTIFY_COMMAND_UPDATE_ROUTE_OPTIONS: {
}
break;
}
+ case NOTIFY_COMMAND_INFORM_STREAM_CONNECTED:
+ case NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED: {
+ 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 = (type==STREAM_SINK_INPUT)?((pa_sink_input*)s)->index:((pa_source_output*)s)->index;
+ stream_conn_info.is_connected = (command == NOTIFY_COMMAND_INFORM_STREAM_CONNECTED)?TRUE:FALSE;
+ pa_hal_manager_update_stream_connection_info(m->hal, &stream_conn_info);
+ }
+ break;
+ }
}
return;
}
int32_t volume_ret = 0;
volume_info *v = NULL;
const char *si_volume_type_str = NULL;
+ const char *prior_priority = NULL;
+ int32_t prior_p = 0;
pa_log_info("START process_stream(%s): stream_type(%d), stream(%p), m(%p)", process_command_type_str[command], type, stream, m);
pa_assert(stream);
}
/* notify to select sink or source */
- do_notify(NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, m, stream);
+ do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, stream);
- } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
- role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
+ } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA || command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
+ if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA)
+ role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
+ else
+ role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
/* skip roles */
if (check_role_to_skip(m, role)) {
goto FAILURE;
}
+ if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
+ /* update the priority of this stream */
+ ret = update_priority_of_stream(m, command, type, stream, role);
+ if (ret == FALSE) {
+ pa_log_error("could not update the priority of '%s' role.", role);
+ result = PA_PROCESS_STREAM_STOP;
+ goto FAILURE;
+ }
+ }
+
/* update the highest priority */
ret = update_the_highest_priority_stream(m, command, stream, type, role, &need_update);
if (ret == FALSE) {
pa_log_error("could not update the highest priority stream");
- result = PA_PROCESS_STREAM_STOP;
+ result = PA_PROCESS_STREAM_SKIP;
goto FAILURE;
}
/* need to skip if this stream does not belong to internal device */
/* if needed, notify to update */
if (need_update) {
- do_notify(NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA, type, m, stream);
- if (type==STREAM_SINK_INPUT)
- m->cur_highest_priority.need_to_update_si = TRUE;
- else
- m->cur_highest_priority.need_to_update_so = TRUE;
+ if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA) {
+ do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA, type, stream);
+ if (type==STREAM_SINK_INPUT)
+ m->cur_highest_priority.need_to_update_si = TRUE;
+ else
+ m->cur_highest_priority.need_to_update_so = TRUE;
+ } else {
+ do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, stream);
+ if (type==STREAM_SINK_INPUT)
+ m->cur_highest_priority.sink_input = stream;
+ else
+ m->cur_highest_priority.source_output = stream;
+ }
}
+ if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED)
+ do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, stream);
} else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED) {
role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
result = PA_PROCESS_STREAM_SKIP;
goto FAILURE;
}
+
+ /* check if it has already been processed (unlink or state_changed_cb) */
+ prior_priority = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_ROLE_PRIORITY);
+ if (prior_priority && !pa_atoi(prior_priority, &prior_p) && (prior_p == -1)) {
+ pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, skip it..");
+ result = PA_PROCESS_STREAM_SKIP;
+ goto FAILURE;
+ }
+
/* mark the priority of this stream to -1 */
pa_proplist_setf(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, "%d", -1);
ret = update_the_highest_priority_stream(m, command, stream, type, role, &need_update);
goto FAILURE;
}
+ do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED, type, stream);
+
/* need to skip if this stream does not belong to internal device */
/* if needed, notify to update */
if (need_update)
- do_notify(NOTIFY_COMMAND_CHANGE_ROUTE_END, type, m, NULL);
+ do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, NULL);
} else {
pa_log_error("role is null, skip it");
}
}
- } else if (command == PROCESS_COMMAND_INFORM_STREAM_CONNECTED || command == PROCESS_COMMAND_INFORM_STREAM_DISCONNECTED) {
- hal_stream_connection_info stream_conn_info;
- memset(&stream_conn_info, 0, sizeof(hal_stream_connection_info));
- if (stream) {
- stream_conn_info.role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
- stream_conn_info.direction = (type==STREAM_SINK_INPUT)?DIRECTION_OUT:DIRECTION_IN;
- stream_conn_info.idx = (type==STREAM_SINK_INPUT)?((pa_sink_input*)stream)->index:((pa_source_output*)stream)->index;
- stream_conn_info.is_connected = (command == PROCESS_COMMAND_INFORM_STREAM_CONNECTED)?TRUE:FALSE;
- pa_hal_manager_update_stream_connection_info(m->hal, &stream_conn_info);
- }
-
} else if (command == PROCESS_COMMAND_ADD_PARENT_ID || command == PROCESS_COMMAND_REMOVE_PARENT_ID) {
if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
if (type == STREAM_SINK_INPUT && m->cur_highest_priority.need_to_update_si) {
m->cur_highest_priority.source_output = stream;
m->cur_highest_priority.need_to_update_so = FALSE;
}
+ if (command == PROCESS_COMMAND_ADD_PARENT_ID)
+ do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, stream);
}
/* update parent stream info. */
ret = update_stream_parent_info(m, command, type, stream);
pa_log_info("start sink_input_new_cb");
process_result = process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_PREPARE, m);
-
/* Update buffer attributes from HAL */
update_buffer_attribute(m->hal, new_data);
-
process_result = process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_UPDATE_VOLUME, m);
- process_result = process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, m);
+ process_result = process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA, m);
return PA_HOOK_OK;
}
static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
const char *si_volume_type_str = NULL;
pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
-#ifdef PRIMARY_VOLUME
- uint32_t volume_type = 0;
-#endif
+
pa_core_assert_ref(core);
pa_sink_input_assert_ref(i);
pa_log_info("start sink_input_put_cb, i(%p, index:%u)", i, i->index);
process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_ADD_PARENT_ID, m);
- process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_INFORM_STREAM_CONNECTED, m);
-
- if ((si_volume_type_str = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
-#ifdef PRIMARY_VOLUME
- pa_atou(si_volume_type_str, &volume_type);
- _set_primary_volume(m, (void*)i, volume_type, true);
-#endif
- }
return PA_HOOK_OK;
}
static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
-#ifdef PRIMARY_VOLUME
- uint32_t volume_type = 0;
- const char *si_volume_type_str;
-#endif
+
pa_core_assert_ref(core);
pa_sink_input_assert_ref(i);
pa_log_info("start sink_input_unlink_cb, i(%p, index:%u)", i, i->index);
- process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_INFORM_STREAM_DISCONNECTED, m);
process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_REMOVE_PARENT_ID, m);
process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
-#ifdef PRIMARY_VOLUME
- if((si_volume_type_str = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
- pa_atou(si_volume_type_str, &volume_type);
- _set_primary_volume(m, (void*)i, volume_type, false);
- }
-#endif
-
return PA_HOOK_OK;
}
-static pa_hook_result_t sink_input_state_changed_hook_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
+static pa_hook_result_t sink_input_state_changed_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
pa_sink_input_state_t state;
+ pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
-#ifdef PRIMARY_VOLUME
- uint32_t volume_type = 0;
-#endif
pa_assert(i);
pa_assert(m);
state = pa_sink_input_get_state(i);
- pa_log_info("start sink_input_state_changed_hook_cb(), sink-input(%p), state(%d)", i, state);
+ pa_log_info("start sink_input_state_changed_cb(), sink-input(%p), state(%d)", i, state);
switch(state) {
case PA_SINK_INPUT_CORKED: {
-#ifdef PRIMARY_VOLUME
- _set_primary_volume(m, (void*)i, volume_type, false);
-#endif
+ process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
break;
}
case PA_SINK_INPUT_DRAINED:
case PA_SINK_INPUT_RUNNING: {
-#ifdef PRIMARY_VOLUME
- const char *si_volume_type_str;
- uint32_t volume_type = 0;
- if ((si_volume_type_str = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
- pa_atou(si_volume_type_str, &volume_type);
- _set_primary_volume(m, (void*)i, volume_type, true);
- }
-#endif
+ process_result = process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, m);
break;
}
default:
return PA_HOOK_OK;
}
+static pa_hook_result_t sink_input_move_start_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
+ int32_t audio_ret = 0;
+
+ pa_core_assert_ref(core);
+ pa_sink_input_assert_ref(i);
+
+ /* There's no point in doing anything if the core is shut down anyway */
+ if (core->state == PA_CORE_SHUTDOWN)
+ return PA_HOOK_OK;
+
+ pa_log_debug ("sink_input_move_start_cb, i(%p, index:%u)", i, i->index);
+
+ set_volume_mute_by_idx(m, STREAM_SINK_INPUT, i->index, TRUE);
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
+ int32_t audio_ret = 0;
+
+ pa_core_assert_ref(core);
+ pa_sink_input_assert_ref(i);
+
+ /* There's no point in doing anything if the core is shut down anyway */
+ if (core->state == PA_CORE_SHUTDOWN)
+ return PA_HOOK_OK;
+
+ pa_log_debug ("sink_input_move_finish_cb, i(%p, index:%u)", i, i->index);
+
+ set_volume_mute_by_idx(m, STREAM_SINK_INPUT, i->index, FALSE);
+
+ return PA_HOOK_OK;
+}
+
static pa_hook_result_t source_output_new_cb(pa_core *core, pa_source_output_new_data *new_data, pa_stream_manager *m) {
pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
pa_log_info("start source_output_new_new_cb");
process_result = process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_PREPARE, m);
-
/* Update buffer attributes from HAL */
update_buffer_attribute(m->hal, new_data);
-
process_result = process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_UPDATE_VOLUME, m);
- process_result = process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, m);
+ process_result = process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA, m);
return PA_HOOK_OK;
}
pa_log_info("start source_output_put_cb, o(%p, index:%u)", o, o->index);
process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_ADD_PARENT_ID, m);
- process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_INFORM_STREAM_CONNECTED, m);
-
-#ifdef PRIMARY_VOLUME
- _set_primary_volume(m, (void*)o, AUDIO_PRIMARY_VOLUME_TYPE_MAX/*source-output use PRIMARY_MAX*/, true);
-#endif
return PA_HOOK_OK;
}
pa_log_info("start source_output_unlink_cb, o(%p, index:%u)", o, o->index);
- process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_INFORM_STREAM_DISCONNECTED, m);
process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_REMOVE_PARENT_ID, m);
process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
-#ifdef PRIMARY_VOLUME
- _set_primary_volume(m, (void*)o, AUDIO_PRIMARY_VOLUME_TYPE_MAX/*source-output use PRIMARY_MAX*/, false);
-#endif
-
return PA_HOOK_OK;
}
-static pa_hook_result_t source_output_state_changed_hook_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
+static pa_hook_result_t source_output_state_changed_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
pa_source_output_state_t state;
+ pa_process_stream_result_t process_result = PA_PROCESS_STREAM_OK;
pa_assert(o);
pa_assert(m);
state = pa_source_output_get_state(o);
- pa_log_debug("start source_output_state_changed_hook_cb(), source-output(%p), state(%d)", o, state);
+ pa_log_debug("start source_output_state_changed_cb(), source-output(%p), state(%d)", o, state);
switch(state) {
case PA_SOURCE_OUTPUT_CORKED: {
+ process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
break;
}
case PA_SOURCE_OUTPUT_RUNNING: {
+ process_result = process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, m);
break;
}
default:
/* Reorganize routing when a device has been connected or disconnected */
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) {
+ const char *route_type_str = NULL;
+ stream_route_type_t route_type;
dm_device_direction_t device_direction = DM_DEVICE_DIRECTION_OUT;
device_direction = pa_device_manager_get_device_direction(conn->device);
- pa_log_debug("device_connection_changed_hook_cb is called. conn(%p), is_connected(%d), device(%p), direction(%p)",
+ pa_log_info("device_connection_changed_hook_cb is called. conn(%p), is_connected(%d), device(%p), direction(%p)",
conn, conn->is_connected, conn->device, device_direction);
- /* If needed, notify again */
- if (m->cur_highest_priority.source_output && (device_direction & DM_DEVICE_DIRECTION_IN))
- do_notify(NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, m, m->cur_highest_priority.source_output);
- if (m->cur_highest_priority.sink_input && (device_direction & DM_DEVICE_DIRECTION_OUT))
- do_notify(NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, m, m->cur_highest_priority.sink_input);
+ /* If the route type of the stream is not manual, notify again */
+ if (m->cur_highest_priority.source_output && (device_direction & DM_DEVICE_DIRECTION_IN)) {
+ route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
+ if(!pa_atoi(route_type_str, &route_type))
+ if (route_type != STREAM_ROUTE_TYPE_MANUAL)
+ do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, m->cur_highest_priority.source_output);
+ } if (m->cur_highest_priority.sink_input && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
+ route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(m->cur_highest_priority.sink_input, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
+ if(!pa_atoi(route_type_str, &route_type))
+ if (route_type != STREAM_ROUTE_TYPE_MANUAL)
+ do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, m->cur_highest_priority.sink_input);
+ }
return PA_HOOK_OK;
}
/* Reorganize routing when device information has been changed */
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) {
- pa_log_debug("device_information_changed_hook_cb is called. info(%p), changed_info(%d), device(%p)",
+ pa_log_info("device_information_changed_hook_cb is called. info(%p), changed_info(%d), device(%p)",
info, info->changed_info, info->device);
return PA_HOOK_OK;
pa_client *client = NULL;
stream_parent *sp = NULL;
const char *name = NULL;
+ uint32_t *device_id = NULL;
+ uint32_t _idx = 0;
pa_core_assert_ref(core);
pa_assert(m);
pa_log_info("subscribe_cb() is called, t(%x), idx(%u)", t, idx);
pa_log_debug(" - add sp(%p), idx(%u)", sp, idx);
} else if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE)) {
/* remove the stream parent */
- stream_parent *sp = NULL;
sp = pa_hashmap_get(m->stream_parents, idx);
if (sp) {
pa_log_debug(" - remove sp(%p), idx(%u)", sp, idx);
pa_hashmap_remove(m->stream_parents, idx);
+ if (sp->idx_route_in_devices)
+ PA_IDXSET_FOREACH(device_id, sp->idx_route_in_devices, _idx)
+ pa_xfree(device_id);
+ if (sp->idx_route_out_devices)
+ PA_IDXSET_FOREACH(device_id, sp->idx_route_out_devices, _idx)
+ pa_xfree(device_id);
pa_idxset_free(sp->idx_sink_inputs, NULL);
pa_idxset_free(sp->idx_source_outputs, NULL);
pa_idxset_free(sp->idx_route_in_devices, NULL);
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);
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);
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);
- 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_hook_cb, m);
+ 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);
+ 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);
+ 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);
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);
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);
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);
- 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_hook_cb, m);
+ 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);
+
m->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_CLIENT | PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, subscribe_cb, m);
m->comm.comm = pa_communicator_get(c);
m->comm.comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm,PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
- PA_HOOK_EARLY, (pa_hook_cb_t) device_connection_changed_hook_cb, m);
+ PA_HOOK_EARLY + 10, (pa_hook_cb_t) device_connection_changed_hook_cb, m);
m->comm.comm_hook_device_information_changed_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm,PA_COMMUNICATOR_HOOK_DEVICE_INFORMATION_CHANGED),
PA_HOOK_EARLY, (pa_hook_cb_t) device_information_changed_hook_cb, m);
pa_hook_slot_free(m->sink_input_unlink_slot);
if (m->sink_input_state_changed_slot)
pa_hook_slot_free(m->sink_input_state_changed_slot);
+ if (m->sink_input_move_start_slot)
+ pa_hook_slot_free(m->sink_input_move_start_slot);
+ if (m->sink_input_move_finish_slot)
+ pa_hook_slot_free(m->sink_input_move_finish_slot);
if (m->source_output_new_slot)
pa_hook_slot_free(m->source_output_new_slot);
if (m->source_output_put_slot)