ALCboolean alc_pulse_init(BackendFuncs *func_list) { ALCboolean ret = ALC_FALSE; if(pulse_load()) { pa_threaded_mainloop *loop; pulse_ctx_flags = 0; if(!GetConfigValueBool("pulse", "spawn-server", 0)) pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; if((loop=pa_threaded_mainloop_new()) && pa_threaded_mainloop_start(loop) >= 0) { pa_context *context; pa_threaded_mainloop_lock(loop); context = connect_context(loop, AL_TRUE); if(context) { *func_list = pulse_funcs; ret = ALC_TRUE; /* Some libraries (Phonon, Qt) set some pulseaudio properties * through environment variables, which causes all streams in * the process to inherit them. This attempts to filter those * properties out by setting them to 0-length data. */ prop_filter = pa_proplist_new(); pa_proplist_set(prop_filter, PA_PROP_MEDIA_ROLE, NULL, 0); pa_proplist_set(prop_filter, "phonon.streamid", NULL, 0); pa_context_disconnect(context); pa_context_unref(context); } pa_threaded_mainloop_unlock(loop); pa_threaded_mainloop_stop(loop); } if(loop) pa_threaded_mainloop_free(loop); } return ret; }
pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) { DBusMessageIter dict_iter; DBusMessageIter dict_entry_iter; char *signature; pa_proplist *proplist = NULL; const char *key = NULL; const uint8_t *value = NULL; int value_length = 0; pa_assert(c); pa_assert(msg); pa_assert(iter); pa_assert(signature = dbus_message_iter_get_signature(iter)); pa_assert_se(pa_streq(signature, "a{say}")); dbus_free(signature); proplist = pa_proplist_new(); dbus_message_iter_recurse(iter, &dict_iter); while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) { dbus_message_iter_recurse(&dict_iter, &dict_entry_iter); dbus_message_iter_get_basic(&dict_entry_iter, &key); dbus_message_iter_next(&dict_entry_iter); if (strlen(key) <= 0 || !pa_ascii_valid(key)) { pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key: '%s'.", key); goto fail; } dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length); pa_assert(value_length >= 0); pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0); dbus_message_iter_next(&dict_iter); } dbus_message_iter_next(iter); return proplist; fail: if (proplist) pa_proplist_free(proplist); return NULL; }
static pa_hook_result_t sink_input_neew(void *hook_data, void *call_data, void *slot_data) { static uint32_t route_flags = PA_POLICY_GROUP_FLAG_SET_SINK | PA_POLICY_GROUP_FLAG_ROUTE_AUDIO; static pa_volume_t max_volume = PA_VOLUME_NORM; struct pa_sink_input_new_data *data = (struct pa_sink_input_new_data *)call_data; struct userdata *u = (struct userdata *)slot_data; uint32_t flags; const char *group_name; const char *sinp_name; const char *sink_name; int local_route; int local_volume; struct pa_policy_group *group; pa_assert(u); pa_assert(data); if ((group_name = pa_classify_sink_input_by_data(u,data,&flags)) != NULL && (group = pa_policy_group_find(u, group_name) ) != NULL ){ /* Let's just set the policy group property here already so that we * don't have to classify again when the sink input is put, because we * can just retrieve the group from the proplist. Also, this prevents * the classification from breaking later because of the proplist * overwriting done below. */ pa_proplist_sets(data->proplist, PA_PROP_POLICY_GROUP, group_name); /* Proplist overwriting can also mess up the retrieval of * stream-specific flags later on, so we need to store those to the * proplist as well (ugly hack). We could probably cope without this * one though, since the stream-specific flags don't really seem to be * used. */ pa_proplist_set(data->proplist, PA_PROP_POLICY_STREAM_FLAGS, (void*)&flags, sizeof(flags)); if (group->properties != NULL) { pa_proplist_update(data->proplist, PA_UPDATE_REPLACE, group->properties); pa_log_debug("new sink input inserted into %s. " "force the following properties:", group_name); } if (group->sink != NULL) { sinp_name = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_NAME); if (!sinp_name) sinp_name = "<unknown>"; local_route = flags & PA_POLICY_LOCAL_ROUTE; local_volume = flags & PA_POLICY_LOCAL_VOLMAX; if (group->mutebyrt && !local_route) { sink_name = u->nullsink->name; pa_log_debug("force stream '%s'/'%s' to sink '%s' due to " "mute-by-route", group_name,sinp_name, sink_name); #ifdef HAVE_OLD_LIBPULSE data->sink = u->nullsink->sink; #else pa_sink_input_new_data_set_sink(data, u->nullsink->sink, false); #endif } else if (group->flags & route_flags) { sink_name = pa_sink_ext_get_name(group->sink); pa_log_debug("force stream '%s'/'%s' to sink '%s'", group_name, sinp_name, sink_name); #ifdef HAVE_OLD_LIBPULSE data->sink = group->sink; #else pa_sink_input_new_data_set_sink(data, group->sink, false); #endif } if (local_volume) { pa_log_debug("force stream '%s'/'%s' volume to %d", group_name, sinp_name, (max_volume * 100) / PA_VOLUME_NORM); pa_cvolume_set(&data->volume, data->channel_map.channels, max_volume); data->volume_is_set = TRUE; data->save_volume = FALSE; } } } return PA_HOOK_OK; }
void on_set_common(pa_proplist* p, pa_tagstruct* t, pa_core* c) { pa_log_info("on_set_common"); const char* attribute = pa_proplist_gets(p, PROPLIST_KEY_ATTRIBUTE); if (!attribute) { pa_log_error("on_set_common: attribute not found!"); return; } if (!strcmp(attribute, PROPLIST_VALUE_GET_INFO)) { const char* str_device = pa_proplist_gets(p, PROPLIST_KEY_DEVICE); if (!str_device) { pa_log_error("on_set_common device not specific!"); return; } int device_id = atoi(str_device); pa_sink* sink = NULL; pa_source* source = NULL; sink = find_sink(c, device_id); if (!sink) { source = find_source(c, device_id); } if (!sink && !source) { pa_log_error("do not find any sink or source of device %d", device_id); return; } int n_used = 0; if (sink) { n_used = pa_module_get_n_used(sink->module); } else { n_used = pa_module_get_n_used(source->module); } char value[32]; snprintf(value, sizeof(value), "%d", n_used); pa_proplist* replyp = pa_proplist_new(); pa_proplist_sets(replyp, PROPLIST_KEY_VALUE, value); pa_tagstruct_put_proplist(t, replyp); pa_proplist_free(replyp); } else if (!strcmp(attribute, PROPLIST_VALUE_REMOTE_SINK)) { #ifdef HAVE_WEB_SOCKET extern void start_web_socket(); start_web_socket(); #endif on_set_debug(c, p, EAUDIO_STREAM_DEVICE_VIRTUALOUPUT_REMOTE, NULL); } else if (!strcmp(attribute, PROPLIST_VALUE_FILE_SINK)) { const char* str_path = pa_proplist_gets(p, PROPLIST_VALUE_PATH); char args[64] = { 0 }; if (str_path) { snprintf(args, sizeof(args), "path=%s", str_path); } on_set_debug(c, p, EAUDIO_STREAM_DEVICE_VIRTUALOUPUT_FILE, str_path ? args : NULL); } else if (!strcmp(attribute, PROPLIST_VALUE_ALSA_BUFFER)) { const char* str_device = pa_proplist_gets(p, PROPLIST_KEY_DEVICE); if (!str_device) { pa_log_error("on_set_common alsa-buffer device not specific!"); return; } int device = atoi(str_device); pa_sink* s = find_sink(c, device); if (!s) { pa_log_error("sink not found %d", device); return; } pa_usec_t left_to_play = pa_sink_get_left_to_play(s); pa_proplist* replyp = pa_proplist_new(); pa_proplist_set(replyp, PROPLIST_KEY_COMMAND_RESULT, &left_to_play, sizeof(left_to_play)); pa_tagstruct_put_proplist(t, replyp); pa_proplist_free(replyp); } else if (!strcmp(attribute, PROPLIST_VALUE_STOP_TEST)) { pthread_t tid_stop; int err = pthread_create(&tid_stop, NULL, stop_thread, NULL); if (err != 0) { pa_log_error("can't create thread: %s\n", strerror(err)); return; } } #ifdef HAVE_WEB_SOCKET else if (!strcmp(attribute, "web-start")) { extern void start_web_socket(); start_web_socket(); } else if (!strcmp(attribute, "web-stop")) { extern void stop_web_socket(); stop_web_socket(); } #endif }