diff options
29 files changed, 339 insertions, 271 deletions
diff --git a/src/daemon/main.c b/src/daemon/main.c index a4f0af7d..c456e6d1 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -908,6 +908,11 @@ int main(int argc, char *argv[]) { pa_log_info(_("Machine ID is %s."), s); pa_xfree(s); + if ((s = pa_session_id())) { + pa_log_info(_("Session ID is %s."), s); + pa_xfree(s); + } + if (!(s = pa_get_runtime_dir())) goto finish; pa_log_info(_("Using runtime directory %s."), s); diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 401b003f..2fbcd7be 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -483,7 +483,13 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle } } - *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) - process_usec; + *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec); + + if (*sleep_usec > process_usec) + *sleep_usec -= process_usec; + else + *sleep_usec = 0; + return work_done ? 1 : 0; } @@ -605,7 +611,13 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle } } - *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) - process_usec; + *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec); + + if (*sleep_usec > process_usec) + *sleep_usec -= process_usec; + else + *sleep_usec = 0; + return work_done ? 1 : 0; } @@ -919,7 +931,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { return 0; if (mask & SND_CTL_EVENT_MASK_VALUE) { - pa_sink_get_volume(u->sink, TRUE); + pa_sink_get_volume(u->sink, TRUE, FALSE); pa_sink_get_mute(u->sink, TRUE); } @@ -1652,7 +1664,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); - pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL)); + pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL), profile); pa_sink_new_data_init(&data); data.driver = driver; @@ -1662,7 +1674,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca pa_sink_new_data_set_sample_spec(&data, &ss); pa_sink_new_data_set_channel_map(&data, &map); - pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle); + pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle, u->mixer_elem); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags)); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size)); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 99e825c4..c59fc75f 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -465,7 +465,13 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled } } - *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec) - process_usec; + *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec); + + if (*sleep_usec > process_usec) + *sleep_usec -= process_usec; + else + *sleep_usec = 0; + return work_done ? 1 : 0; } @@ -575,7 +581,13 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled } } - *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec) - process_usec; + *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec); + + if (*sleep_usec > process_usec) + *sleep_usec -= process_usec; + else + *sleep_usec = 0; + return work_done ? 1 : 0; } @@ -1507,7 +1519,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); - pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL)); + pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL), profile); pa_source_new_data_init(&data); data.driver = driver; @@ -1517,7 +1529,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p pa_source_new_data_set_sample_spec(&data, &ss); pa_source_new_data_set_channel_map(&data, &map); - pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle); + pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle, u->mixer_elem); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags)); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size)); diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index fbf88b08..d2dc6e87 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -529,39 +529,51 @@ static const struct pa_alsa_profile_info device_table[] = { "hw", N_("Analog Mono"), "analog-mono", - 1 }, + 1, + "Master", "PCM", + "Capture", "Mic" }, {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }}, "front", N_("Analog Stereo"), "analog-stereo", - 10 }, + 10, + "Master", "PCM", + "Capture", "Mic" }, {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }}, "iec958", N_("Digital Stereo (IEC958)"), "iec958-stereo", - 5 }, + 5, + "IEC958", NULL, + "IEC958 In", NULL }, {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }}, "hdmi", N_("Digital Stereo (HDMI)"), "hdmi-stereo", - 4 }, + 4, + "IEC958", NULL, + "IEC958 In", NULL }, {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }}, "surround40", N_("Analog Surround 4.0"), "analog-surround-40", - 7 }, + 7, + "Master", "PCM", + "Capture", "Mic" }, {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }}, "a52", N_("Digital Surround 4.0 (IEC958/AC3)"), "iec958-ac3-surround-40", - 2 }, + 2, + "Master", "PCM", + "Capture", "Mic" }, {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, @@ -569,7 +581,9 @@ static const struct pa_alsa_profile_info device_table[] = { "surround41", N_("Analog Surround 4.1"), "analog-surround-41", - 7 }, + 7, + "Master", "PCM", + "Capture", "Mic" }, {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, @@ -577,7 +591,9 @@ static const struct pa_alsa_profile_info device_table[] = { "surround50", N_("Analog Surround 5.0"), "analog-surround-50", - 7 }, + 7, + "Master", "PCM", + "Capture", "Mic" }, {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, @@ -585,7 +601,9 @@ static const struct pa_alsa_profile_info device_table[] = { "surround51", N_("Analog Surround 5.1"), "analog-surround-51", - 8 }, + 8, + "Master", "PCM", + "Capture", "Mic" }, {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, @@ -593,7 +611,9 @@ static const struct pa_alsa_profile_info device_table[] = { "a52", N_("Digital Surround 5.1 (IEC958/AC3)"), "iec958-ac3-surround-51", - 3 }, + 3, + "IEC958", NULL, + "IEC958 In", NULL }, {{ 8, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, @@ -602,9 +622,11 @@ static const struct pa_alsa_profile_info device_table[] = { "surround71", N_("Analog Surround 7.1"), "analog-surround-71", - 7 }, + 7, + "Master", "PCM", + "Capture", "Mic" }, - {{ 0, { 0 }}, NULL, NULL, NULL, 0 } + {{ 0, { 0 }}, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL } }; snd_pcm_t *pa_alsa_open_by_device_id_auto( @@ -1095,7 +1117,8 @@ int pa_alsa_find_mixer_and_elem( snd_pcm_t *pcm, snd_mixer_t **_m, snd_mixer_elem_t **_e, - const char *control_name) { + const char *control_name, + const pa_alsa_profile_info *profile) { int err; snd_mixer_t *m; @@ -1107,6 +1130,11 @@ int pa_alsa_find_mixer_and_elem( pa_assert(_m); pa_assert(_e); + if (control_name && *control_name == 0) { + pa_log_debug("Hardware mixer usage disabled because empty control name passed"); + return -1; + } + if ((err = snd_mixer_open(&m, 0)) < 0) { pa_log("Error opening mixer: %s", snd_strerror(err)); return -1; @@ -1149,6 +1177,8 @@ int pa_alsa_find_mixer_and_elem( case SND_PCM_STREAM_PLAYBACK: if (control_name) e = pa_alsa_find_elem(m, control_name, NULL, TRUE); + else if (profile) + e = pa_alsa_find_elem(m, profile->playback_control_name, profile->playback_control_fallback, TRUE); else e = pa_alsa_find_elem(m, "Master", "PCM", TRUE); break; @@ -1156,6 +1186,8 @@ int pa_alsa_find_mixer_and_elem( case SND_PCM_STREAM_CAPTURE: if (control_name) e = pa_alsa_find_elem(m, control_name, NULL, FALSE); + else if (profile) + e = pa_alsa_find_elem(m, profile->record_control_name, profile->record_control_fallback, FALSE); else e = pa_alsa_find_elem(m, "Capture", "Mic", FALSE); break; @@ -1483,7 +1515,7 @@ void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t * pa_alsa_init_proplist_card(c, p, card); } -void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) { +void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm, snd_mixer_elem_t *elem) { snd_pcm_hw_params_t *hwparams; snd_pcm_info_t *info; int bits, err; @@ -1499,6 +1531,9 @@ void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) { pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits); } + if (elem) + pa_proplist_sets(p, "alsa.mixer_element", snd_mixer_selem_get_name(elem)); + if ((err = snd_pcm_info(pcm, info)) < 0) pa_log_warn("Error fetching PCM info: %s", snd_strerror(err)); else diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 9fce6daf..c8acc7c9 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -53,18 +53,20 @@ int pa_alsa_set_hw_params( int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min); -int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); -snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback); -int pa_alsa_find_mixer_and_elem(snd_pcm_t *pcm, snd_mixer_t **_m, snd_mixer_elem_t **_e, const char *control_name); - typedef struct pa_alsa_profile_info { pa_channel_map map; const char *alsa_name; const char *description; /* internationalized */ const char *name; unsigned priority; + const char *playback_control_name, *playback_control_fallback; + const char *record_control_name, *record_control_fallback; } pa_alsa_profile_info; +int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev); +snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback); +int pa_alsa_find_mixer_and_elem(snd_pcm_t *pcm, snd_mixer_t **_m, snd_mixer_elem_t **_e, const char *control_name, const pa_alsa_profile_info*profile); + /* Picks a working profile based on the specified ss/map */ snd_pcm_t *pa_alsa_open_by_device_id_auto( const char *dev_id, @@ -123,7 +125,7 @@ void pa_alsa_redirect_errors_dec(void); void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info); void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card); -void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm); +void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm, snd_mixer_elem_t *elem); pa_bool_t pa_alsa_init_description(pa_proplist *p); int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents); diff --git a/src/modules/module-cork-music-on-phone.c b/src/modules/module-cork-music-on-phone.c index c0f5eea4..d3a2b00e 100644 --- a/src/modules/module-cork-music-on-phone.c +++ b/src/modules/module-cork-music-on-phone.c @@ -143,7 +143,6 @@ static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, struc } static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, struct userdata *u) { - pa_core_assert_ref(core); pa_sink_input_assert_ref(i); return process(u, i, FALSE); diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c index 0ca3dd83..7d87ca0f 100644 --- a/src/modules/module-device-restore.c +++ b/src/modules/module-device-restore.c @@ -191,7 +191,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 name = pa_sprintf_malloc("sink:%s", sink->name); entry.channel_map = sink->channel_map; - entry.volume = *pa_sink_get_volume(sink, FALSE); + entry.volume = *pa_sink_get_volume(sink, FALSE, TRUE); entry.muted = pa_sink_get_mute(sink, FALSE); } else { diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c index bdb8bb71..a1a8726f 100644 --- a/src/modules/module-lirc.c +++ b/src/modules/module-lirc.c @@ -63,8 +63,6 @@ struct userdata { float mute_toggle_save; }; -static int lirc_in_use = 0; - static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; char *name = NULL, *code = NULL; @@ -122,39 +120,39 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event pa_log("Failed to get sink '%s'", u->sink_name); else { int i; - pa_cvolume cv = *pa_sink_get_volume(s, FALSE); + pa_cvolume cv = *pa_sink_get_volume(s, FALSE, FALSE); #define DELTA (PA_VOLUME_NORM/20) switch (volchange) { case UP: for (i = 0; i < cv.channels; i++) { - cv.values[i] += DELTA; - - if (cv.values[i] > PA_VOLUME_NORM) - cv.values[i] = PA_VOLUME_NORM; + if (cv.values[i] < PA_VOLUME_MAX - DELTA) + cv.values[i] += DELTA; + else + cv.values[i] = PA_VOLUME_MAX; } - pa_sink_set_volume(s, &cv, TRUE, TRUE); + pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE); break; case DOWN: for (i = 0; i < cv.channels; i++) { - if (cv.values[i] >= DELTA) + if (cv.values[i] > DELTA) cv.values[i] -= DELTA; else cv.values[i] = PA_VOLUME_MUTED; } - pa_sink_set_volume(s, &cv, TRUE, TRUE); + pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE); break; case MUTE: - pa_sink_set_mute(s, 0); + pa_sink_set_mute(s, TRUE); break; case RESET: - pa_sink_set_mute(s, 1); + pa_sink_set_mute(s, FALSE); break; case MUTE_TOGGLE: @@ -163,7 +161,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event break; case INVALID: - ; + pa_assert_not_reached(); } } } @@ -189,11 +187,6 @@ int pa__init(pa_module*m) { pa_assert(m); - if (lirc_in_use) { - pa_log("module-lirc may no be loaded twice."); - return -1; - } - if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; @@ -219,8 +212,6 @@ int pa__init(pa_module*m) { u->io = m->core->mainloop->io_new(m->core->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); - lirc_in_use = 1; - pa_modargs_free(ma); return 0; @@ -252,6 +243,4 @@ void pa__done(pa_module*m) { pa_xfree(u->sink_name); pa_xfree(u); - - lirc_in_use = 0; } diff --git a/src/modules/module-match.c b/src/modules/module-match.c index d7365ca7..625f2a8b 100644 --- a/src/modules/module-match.c +++ b/src/modules/module-match.c @@ -216,7 +216,7 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v pa_cvolume cv; pa_log_debug("changing volume of sink input '%s' to 0x%03x", n, r->volume); pa_cvolume_set(&cv, si->sample_spec.channels, r->volume); - pa_sink_input_set_volume(si, &cv, TRUE); + pa_sink_input_set_volume(si, &cv, TRUE, TRUE); } } } diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c index 2f87dd22..d8b9c79e 100644 --- a/src/modules/module-mmkbd-evdev.c +++ b/src/modules/module-mmkbd-evdev.c @@ -52,17 +52,6 @@ PA_MODULE_USAGE("device=<evdev device> sink=<sink name>"); #define DEFAULT_DEVICE "/dev/input/event0" -/* - * This isn't defined in older kernel headers and there is no way of - * detecting it. - */ -struct _input_id { - __u16 bustype; - __u16 vendor; - __u16 product; - __u16 version; -}; - static const char* const valid_modargs[] = { "device", "sink", @@ -113,31 +102,31 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event pa_log("Failed to get sink '%s'", u->sink_name); else { int i; - pa_cvolume cv = *pa_sink_get_volume(s, FALSE); + pa_cvolume cv = *pa_sink_get_volume(s, FALSE, FALSE); #define DELTA (PA_VOLUME_NORM/20) switch (volchange) { case UP: for (i = 0; i < cv.channels; i++) { - cv.values[i] += DELTA; - - if (cv.values[i] > PA_VOLUME_NORM) - cv.values[i] = PA_VOLUME_NORM; + if (cv.values[i] < PA_VOLUME_MAX - DELTA) + cv.values[i] += DELTA; + else + cv.values[i] = PA_VOLUME_MAX; } - pa_sink_set_volume(s, &cv, TRUE, TRUE); + pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE); break; case DOWN: for (i = 0; i < cv.channels; i++) { - if (cv.values[i] >= DELTA) + if (cv.values[i] > DELTA) cv.values[i] -= DELTA; else cv.values[i] = PA_VOLUME_MUTED; } - pa_sink_set_volume(s, &cv, TRUE, TRUE); + pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE); break; case MUTE_TOGGLE: @@ -146,7 +135,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event break; case INVALID: - ; + pa_assert_not_reached(); } } } @@ -169,7 +158,7 @@ int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; int version; - struct _input_id input_id; + struct input_id input_id; char name[256]; uint8_t evtype_bitmask[EV_MAX/8 + 1]; @@ -180,15 +169,15 @@ int pa__init(pa_module*m) { goto fail; } - m->userdata = u = pa_xnew(struct userdata,1); + m->userdata = u = pa_xnew(struct userdata, 1); u->module = m; u->io = NULL; u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); u->fd = -1; u->fd_type = 0; - if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) { - pa_log("failed to open evdev device: %s", pa_cstrerror(errno)); + if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY|O_NOCTTY)) < 0) { + pa_log("Failed to open evdev device: %s", pa_cstrerror(errno)); goto fail; } @@ -208,7 +197,7 @@ int pa__init(pa_module*m) { input_id.vendor, input_id.product, input_id.version, input_id.bustype); memset(name, 0, sizeof(name)); - if(ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { + if (ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { pa_log("EVIOCGNAME failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c index 2c90e726..70cd89a7 100644 --- a/src/modules/module-stream-restore.c +++ b/src/modules/module-stream-restore.c @@ -91,15 +91,14 @@ struct userdata { pa_idxset *subscribed; }; -#define ENTRY_VERSION 1 +#define ENTRY_VERSION 2 struct entry { uint8_t version; - pa_bool_t muted_valid:1, relative_volume_valid:1, absolute_volume_valid:1, device_valid:1; + pa_bool_t muted_valid:1, volume_valid:1, device_valid:1; pa_bool_t muted:1; pa_channel_map channel_map; - pa_cvolume relative_volume; - pa_cvolume absolute_volume; + pa_cvolume volume; char device[PA_NAME_MAX]; } PA_GCC_PACKED; @@ -192,13 +191,12 @@ static struct entry* read_entry(struct userdata *u, const char *name) { goto fail; } - if ((e->relative_volume_valid || e->absolute_volume_valid) && !pa_channel_map_valid(&e->channel_map)) { + if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) { pa_log_warn("Invalid channel map stored in database for stream %s", name); goto fail; } - if ((e->relative_volume_valid && (!pa_cvolume_valid(&e->relative_volume) || e->relative_volume.channels != e->channel_map.channels)) || - (e->absolute_volume_valid && (!pa_cvolume_valid(&e->absolute_volume) || e->absolute_volume.channels != e->channel_map.channels))) { + if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) { pa_log_warn("Invalid volume stored in database for stream %s", name); goto fail; } @@ -251,14 +249,9 @@ static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) { (a->muted_valid && (a->muted != b->muted))) return FALSE; - t = b->relative_volume; - if (a->relative_volume_valid != b->relative_volume_valid || - (a->relative_volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->relative_volume))) - return FALSE; - - t = b->absolute_volume; - if (a->absolute_volume_valid != b->absolute_volume_valid || - (a->absolute_volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->absolute_volume))) + t = b->volume; + if (a->volume_valid != b->volume_valid || + (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume))) return FALSE; return TRUE; @@ -291,22 +284,24 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (!(name = get_name(sink_input->proplist, "sink-input"))) return; - entry.channel_map = sink_input->channel_map; - - pa_sink_input_get_relative_volume(sink_input, &entry.relative_volume); - entry.relative_volume_valid = sink_input->save_volume; + if ((old = read_entry(u, name))) + entry = *old; - if (sink_input->sink->flags & PA_SINK_FLAT_VOLUME) { - entry.absolute_volume = *pa_sink_input_get_volume(sink_input); - entry.absolute_volume_valid = sink_input->save_volume; - } else - entry.absolute_volume_valid = FALSE; + if (sink_input->save_volume) { + entry.channel_map = sink_input->channel_map; + pa_sink_input_get_volume(sink_input, &entry.volume, FALSE); + entry.volume_valid = TRUE; + } - entry.muted = pa_sink_input_get_mute(sink_input); - entry.muted_valid = sink_input->save_muted; + if (sink_input->save_muted) { + entry.muted = pa_sink_input_get_mute(sink_input); + entry.muted_valid = TRUE; + } - pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device)); - entry.device_valid = sink_input->save_sink; + if (sink_input->save_sink) { + pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device)); + entry.device_valid = TRUE; + } } else { pa_source_output *source_output; @@ -319,13 +314,16 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3 if (!(name = get_name(source_output->proplist, "source-output"))) return; - entry.channel_map = source_output->channel_map; + if ((old = read_entry(u, name))) + entry = *old; - pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device)); - entry.device_valid = source_output->save_source; + if (source_output->save_source) { + pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device)); + entry.device_valid = source_output->save_source; + } } - if ((old = read_entry(u, name))) { + if (old) { if (entries_equal(old, &entry)) { pa_xfree(old); @@ -400,42 +398,24 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu if ((e = read_entry(u, name))) { - if (u->restore_volume) { + if (u->restore_volume && e->volume_valid) { if (!new_data->volume_is_set) { pa_cvolume v; - pa_cvolume_init(&v); - - if (new_data->sink->flags & PA_SINK_FLAT_VOLUME) { - - /* We don't check for e->device_valid here because - that bit marks whether it is a good choice for - restoring, not just if the data is filled in. */ - if (e->absolute_volume_valid && - (e->device[0] == 0 || pa_streq(new_data->sink->name, e->device))) { - - v = e->absolute_volume; - new_data->volume_is_absolute = TRUE; - } else if (e->relative_volume_valid) { - v = e->relative_volume; - new_data->volume_is_absolute = FALSE; - } - - } else if (e->relative_volume_valid) { - v = e->relative_volume; - new_data->volume_is_absolute = FALSE; - } - if (v.channels > 0) { - pa_log_info("Restoring volume for sink input %s.", name); - pa_sink_input_new_data_set_volume(new_data, pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map)); - new_data->save_volume = TRUE; - } + pa_log_info("Restoring volume for sink input %s.", name); + v = e->volume; + pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map); + pa_sink_input_new_data_set_volume(new_data, &v); + + new_data->volume_is_absolute = FALSE; + new_data->save_volume = FALSE; } else pa_log_debug("Not restoring volume for sink input %s, because already set.", name); } if (u->restore_muted && e->muted_valid) { + if (!new_data->muted_is_set) { pa_log_info("Restoring mute state for sink input %s.", name); pa_sink_input_new_data_set_muted(new_data, e->muted); @@ -532,30 +512,15 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) { } pa_xfree(n); - if (u->restore_volume) { + if (u->restore_volume && e->volume_valid) { pa_cvolume v; - pa_cvolume_init(&v); - if (si->sink->flags & PA_SINK_FLAT_VOLUME) { - - if (e->absolute_volume_valid && - (e->device[0] == 0 || pa_streq(e->device, si->sink->name))) - v = e->absolute_volume; - else if (e->relative_volume_valid) { - pa_cvolume t = *pa_sink_get_volume(si->sink, FALSE); - pa_sw_cvolume_multiply(&v, &e->relative_volume, pa_cvolume_remap(&t, &si->sink->channel_map, &e->channel_map)); - } - } else if (e->relative_volume_valid) - v = e->relative_volume; - - if (v.channels > 0) { - pa_log_info("Restoring volume for sink input %s.", name); - pa_sink_input_set_volume(si, pa_cvolume_remap(&v, &e->channel_map, &si->channel_map), TRUE); - } + v = e->volume; + pa_log_info("Restoring volume for sink input %s.", name); + pa_sink_input_set_volume(si, pa_cvolume_remap(&v, &e->channel_map, &si->channel_map), FALSE, FALSE); } - if (u->restore_muted && - e->muted_valid) { + if (u->restore_muted && e->muted_valid) { pa_log_info("Restoring mute state for sink input %s.", name); pa_sink_input_set_mute(si, e->muted, TRUE); } @@ -610,10 +575,10 @@ static void dump_database(struct userdata *u) { if ((e = read_entry(u, name))) { char t[256]; pa_log("name=%s", name); - pa_log("device=%s", e->device); + pa_log("device=%s %s", e->device, pa_yes_no(e->device_valid)); pa_log("channel_map=%s", pa_channel_map_snprint(t, sizeof(t), &e->channel_map)); - pa_log("volume=%s", pa_cvolume_snprint(t, sizeof(t), &e->volume)); - pa_log("mute=%s", pa_yes_no(e->muted)); + pa_log("volume=%s %s", pa_cvolume_snprint(t, sizeof(t), &e->volume), pa_yes_no(e->volume_valid)); + pa_log("mute=%s %s", pa_yes_no(e->muted), pa_yes_no(e->volume_valid)); pa_xfree(e); } @@ -674,8 +639,8 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio pa_channel_map cm; pa_tagstruct_puts(reply, name); - pa_tagstruct_put_channel_map(reply, (e->relative_volume_valid || e->absolute_volume_valid) ? &e->channel_map : pa_channel_map_init(&cm)); - pa_tagstruct_put_cvolume(reply, e->absolute_volume_valid ? &e->absolute_volume : (e->relative_volume_valid ? &e->relative_volume : pa_cvolume_init(&r))); + pa_tagstruct_put_channel_map(reply, e->volume_valid ? &e->channel_map : pa_channel_map_init(&cm)); + pa_tagstruct_put_cvolume(reply, e->volume_valid ? &e->volume : pa_cvolume_init(&r)); pa_tagstruct_puts(reply, e->device_valid ? e->device : NULL); pa_tagstruct_put_boolean(reply, e->muted_valid ? e->muted : FALSE); @@ -718,7 +683,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio if (pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_get_channel_map(t, &entry.channel_map) || - pa_tagstruct_get_cvolume(t, &entry.absolute_volume) < 0 || + pa_tagstruct_get_cvolume(t, &entry.volume) < 0 || pa_tagstruct_gets(t, &device) < 0 || pa_tagstruct_get_boolean(t, &muted) < 0) goto fail; @@ -726,11 +691,10 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio if (!name || !*name) goto fail; - entry.relative_volume = entry.absolute_volume; - entry.absolute_volume_valid = entry.relative_volume_valid = entry.relative_volume.channels > 0; + entry.volume_valid = entry.volume.channels > 0; - if (entry.relative_volume_valid) - if (!pa_cvolume_compatible_with_channel_map(&entry.relative_volume, &entry.channel_map)) + if (entry.volume_valid) + if (!pa_cvolume_compatible_with_channel_map(&entry.volume, &entry.channel_map)) goto fail; entry.muted = muted; diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c index 83e69d1b..2c7fdc12 100644 --- a/src/modules/module-x11-publish.c +++ b/src/modules/module-x11-publish.c @@ -136,7 +136,7 @@ static void x11_kill_cb(pa_x11_wrapper *w, void *userdata) { int pa__init(pa_module*m) { struct userdata *u; pa_modargs *ma = NULL; - char *mid; + char *mid, *sid; char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; const char *t; @@ -170,6 +170,11 @@ int pa__init(pa_module*m) { pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID", u->id); + if ((sid = pa_session_id())) { + pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SESSION_ID", sid); + pa_xfree(sid); + } + publish_servers(u, pa_native_protocol_servers(u->protocol)); if ((t = pa_modargs_get_value(ma, "source", NULL))) @@ -219,6 +224,7 @@ void pa__done(pa_module*m) { pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SINK"); pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SOURCE"); pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_COOKIE"); + pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SESSION_ID"); XSync(pa_x11_wrapper_get_display(u->x11_wrapper), False); } diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c index 855e8a35..9f7863f5 100644 --- a/src/modules/oss/module-oss.c +++ b/src/modules/oss/module-oss.c @@ -617,7 +617,7 @@ static int unsuspend(struct userdata *u) { build_pollfd(u); if (u->sink) - pa_sink_get_volume(u->sink, TRUE); + pa_sink_get_volume(u->sink, TRUE, FALSE); if (u->source) pa_source_get_volume(u->source, TRUE); diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c index 3bec742f..4970363b 100644 --- a/src/pulse/client-conf-x11.c +++ b/src/pulse/client-conf-x11.c @@ -57,8 +57,23 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { } if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) { + pa_bool_t disable_autospawn = TRUE; + pa_xfree(c->default_server); c->default_server = pa_xstrdup(t); + + if (pa_x11_get_prop(d, "PULSE_SESSION_ID", t, sizeof(t))) { + char *id; + + if ((id = pa_session_id())) { + if (pa_streq(t, id)) + disable_autospawn = FALSE; + pa_xfree(id); + } + } + + if (disable_autospawn) + c->autospawn = FALSE; } if (pa_x11_get_prop(d, "PULSE_SINK", t, sizeof(t))) { diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c index 58bc3f90..940d0b67 100644 --- a/src/pulse/client-conf.c +++ b/src/pulse/client-conf.c @@ -92,28 +92,18 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) { /* Prepare the configuration parse table */ pa_config_item table[] = { - { "daemon-binary", pa_config_parse_string, NULL, NULL }, - { "extra-arguments", pa_config_parse_string, NULL, NULL }, - { "default-sink", pa_config_parse_string, NULL, NULL }, - { "default-source", pa_config_parse_string, NULL, NULL }, - { "default-server", pa_config_parse_string, NULL, NULL }, - { "autospawn", pa_config_parse_bool, NULL, NULL }, - { "cookie-file", pa_config_parse_string, NULL, NULL }, - { "disable-shm", pa_config_parse_bool, NULL, NULL }, - { "shm-size-bytes", pa_config_parse_size, NULL, NULL }, + { "daemon-binary", pa_config_parse_string, &c->daemon_binary, NULL }, + { "extra-arguments", pa_config_parse_string, &c->extra_arguments, NULL }, + { "default-sink", pa_config_parse_string, &c->default_sink, NULL }, + { "default-source", pa_config_parse_string, &c->default_source, NULL }, + { "default-server", pa_config_parse_string, &c->default_server, NULL }, + { "autospawn", pa_config_parse_bool, &c->autospawn, NULL }, + { "cookie-file", pa_config_parse_string, &c->cookie_file, NULL }, + { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, + { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, { NULL, NULL, NULL, NULL }, }; - table[0].data = &c->daemon_binary; - table[1].data = &c->extra_arguments; - table[2].data = &c->default_sink; - table[3].data = &c->default_source; - table[4].data = &c->default_server; - table[5].data = &c->autospawn; - table[6].data = &c->cookie_file; - table[7].data = &c->disable_shm; - table[8].data = &c->shm_size; - if (filename) { if (!(f = fopen(filename, "r"))) { @@ -160,6 +150,9 @@ int pa_client_conf_env(pa_client_conf *c) { if ((e = getenv(ENV_DEFAULT_SERVER))) { pa_xfree(c->default_server); c->default_server = pa_xstrdup(e); + + /* We disable autospawning automatically if a specific server was set */ + c->autospawn = FALSE; } if ((e = getenv(ENV_DAEMON_BINARY))) { diff --git a/src/pulse/context.c b/src/pulse/context.c index ef36f090..4aad737f 100644 --- a/src/pulse/context.c +++ b/src/pulse/context.c @@ -186,10 +186,10 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char * #endif c->conf = pa_client_conf_new(); + pa_client_conf_load(c->conf, NULL); #ifdef HAVE_X11 pa_client_conf_from_x11(c->conf, NULL); #endif - pa_client_conf_load(c->conf, NULL); pa_client_conf_env(c->conf); if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) { @@ -925,7 +925,9 @@ int pa_context_connect( PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID); PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID); - if (!server) + if (server) + c->conf->autospawn = FALSE; + else server = c->conf->default_server; pa_context_ref(c); @@ -967,18 +969,18 @@ int pa_context_connect( /* The user instance via PF_LOCAL */ c->server_list = prepend_per_user(c->server_list); + } - /* Set up autospawning */ - if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) { + /* Set up autospawning */ + if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) { - if (getuid() == 0) - pa_log_debug("Not doing autospawn since we are root."); - else { - c->do_autospawn = TRUE; + if (getuid() == 0) + pa_log_debug("Not doing autospawn since we are root."); + else { + c->do_autospawn = TRUE; - if (api) - c->spawn_api = *api; - } + if (api) + c->spawn_api = *api; } } diff --git a/src/pulse/volume.c b/src/pulse/volume.c index ad3b3a49..6848771e 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -120,7 +120,7 @@ pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) { return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a) / v); } -#define USER_DECIBEL_RANGE 60 +#define USER_DECIBEL_RANGE 90 pa_volume_t pa_sw_volume_from_dB(double dB) { if (isinf(dB) < 0 || dB <= -USER_DECIBEL_RANGE) diff --git a/src/pulse/volume.h b/src/pulse/volume.h index c3c396c8..5b7e1213 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -24,6 +24,7 @@ ***/ #include <inttypes.h> +#include <limits.h> #include <pulse/cdecl.h> #include <pulse/gccmacro.h> @@ -102,12 +103,15 @@ PA_C_DECL_BEGIN * > PA_VOLUME_NORM: increased volume */ typedef uint32_t pa_volume_t; -/** Normal volume (100%) */ +/** Normal volume (100%, 0 dB) */ #define PA_VOLUME_NORM ((pa_volume_t) 0x10000U) -/** Muted volume (0%) */ +/** Muted volume (0%, -inf dB) */ #define PA_VOLUME_MUTED ((pa_volume_t) 0U) +/** Maximum volume we can store. \since 0.9.15 */ +#define PA_VOLUME_MAX ((pa_volume_t) UINT32_MAX) + /** A structure encapsulating a per-channel volume */ typedef struct pa_cvolume { uint8_t channels; /**< Number of channels */ diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index 3ea1dca5..15fe525c 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -524,7 +524,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu } pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); - pa_sink_set_volume(sink, &cvolume, TRUE, TRUE); + pa_sink_set_volume(sink, &cvolume, TRUE, TRUE, TRUE); return 0; } @@ -566,7 +566,7 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb } pa_cvolume_set(&cvolume, si->sample_spec.channels, volume); - pa_sink_input_set_volume(si, &cvolume, TRUE); + pa_sink_input_set_volume(si, &cvolume, TRUE, TRUE); return 0; } @@ -1516,7 +1516,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b nl = 1; } - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE))); + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE, TRUE))); pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, FALSE))); pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED)); } diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index b0911ef1..604678be 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -258,10 +258,10 @@ char *pa_sink_list_to_string(pa_core *c) { sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME " : "", sink->flags & PA_SINK_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "", sink_state_to_string(pa_sink_get_state(sink)), - pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)), + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE, FALSE)), sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "", - sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE)) : "", - pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE), &sink->channel_map), + sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE, FALSE)) : "", + pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE, FALSE), &sink->channel_map), pa_volume_snprint(v, sizeof(v), sink->base_volume), sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "", sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "", @@ -507,6 +507,9 @@ char *pa_sink_input_list_to_string(pa_core *c) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28]; pa_usec_t cl; const char *cmn; + pa_cvolume v; + + pa_sink_input_get_volume(i, &v, TRUE); cmn = pa_channel_map_to_pretty_name(&i->channel_map); @@ -547,9 +550,9 @@ char *pa_sink_input_list_to_string(pa_core *c) { i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND ? "FAIL_ON_SUSPEND " : "", state_table[pa_sink_input_get_state(i)], i->sink->index, i->sink->name, - pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), - pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_input_get_volume(i)), - pa_cvolume_get_balance(pa_sink_input_get_volume(i), &i->channel_map), + pa_cvolume_snprint(cv, sizeof(cv), &v), + pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &v), + pa_cvolume_get_balance(&v, &i->channel_map), pa_yes_no(pa_sink_input_get_mute(i)), (double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC, clt, diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 56253391..24d929d7 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2462,7 +2462,7 @@ char *pa_machine_id(void) { pa_strip_nl(ln); if (r && ln[0]) - return pa_xstrdup(ln); + return pa_utf8_filter(ln); } /* The we fall back to the host name. It supposed to be somewhat @@ -2480,13 +2480,16 @@ char *pa_machine_id(void) { break; } else if (strlen(c) < l-1) { + char *u; if (*c == 0) { pa_xfree(c); break; } - return c; + u = pa_utf8_filter(c); + pa_xfree(c); + return u; } /* Hmm, the hostname is as long the space we offered the @@ -2498,10 +2501,19 @@ char *pa_machine_id(void) { } /* If no hostname was set we use the POSIX hostid. It's usually - * the IPv4 address. Mit not be that stable. */ + * the IPv4 address. Might not be that stable. */ return pa_sprintf_malloc("%08lx", (unsigned long) gethostid); } +char *pa_session_id(void) { + const char *e; + + if (!(e = getenv("XDG_SESSION_COOKIE"))) + return NULL; + + return pa_utf8_filter(e); +} + char *pa_uname_string(void) { struct utsname u; diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 0ba33f31..f96fa443 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -202,6 +202,7 @@ pa_bool_t pa_in_system_mode(void); #define pa_streq(a,b) (!strcmp((a),(b))) char *pa_machine_id(void); +char *pa_session_id(void); char *pa_uname_string(void); #ifdef HAVE_VALGRIND_MEMCHECK_H diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c index af5f0aa6..eac8927c 100644 --- a/src/pulsecore/proplist-util.c +++ b/src/pulsecore/proplist-util.c @@ -231,12 +231,11 @@ void pa_init_proplist(pa_proplist *p) { } if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_SESSION_ID)) { - const char *t; + char *s; - if ((t = getenv("XDG_SESSION_COOKIE"))) { - char *c = pa_utf8_filter(t); - pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_SESSION_ID, c); - pa_xfree(c); + if ((s = pa_session_id())) { + pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_SESSION_ID, s); + pa_xfree(s); } } } diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index a024471c..7e7126ea 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -638,7 +638,8 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da pa_assert(t >= k*2+s); if (conn->sink_input) { - pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); + pa_cvolume volume; + pa_sink_input_get_volume(conn->sink_input, &volume, TRUE); rate = (int32_t) conn->sink_input->sample_spec.rate; lvolume = (int32_t) ((volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); rvolume = (int32_t) ((volume.values[volume.channels == 2 ? 1 : 0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); @@ -778,7 +779,7 @@ static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void * volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; volume.channels = conn->sink_input->sample_spec.channels; - pa_sink_input_set_volume(conn->sink_input, &volume, TRUE); + pa_sink_input_set_volume(conn->sink_input, &volume, TRUE, TRUE); ok = 1; } else ok = 0; diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 7c2183d8..aecaf71c 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2819,7 +2819,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin PA_TAG_SAMPLE_SPEC, &fixed_ss, PA_TAG_CHANNEL_MAP, &sink->channel_map, PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE), + PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE, FALSE), PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE), PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL, @@ -2943,6 +2943,7 @@ static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_m static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) { pa_sample_spec fixed_ss; pa_usec_t sink_latency; + pa_cvolume v; pa_assert(t); pa_sink_input_assert_ref(s); @@ -2956,7 +2957,7 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_tagstruct_putu32(t, s->sink->index); pa_tagstruct_put_sample_spec(t, &fixed_ss); pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s)); + pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE)); pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency)); pa_tagstruct_put_usec(t, sink_latency); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); @@ -3321,11 +3322,11 @@ static void command_set_volume( CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY); if (sink) - pa_sink_set_volume(sink, &volume, TRUE, TRUE); + pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE); else if (source) pa_source_set_volume(source, &volume); else if (si) - pa_sink_input_set_volume(si, &volume, TRUE); + pa_sink_input_set_volume(si, &volume, TRUE, TRUE); pa_pstream_send_simple_ack(c->pstream, tag); } diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index b1b9fb56..65f1fd5e 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -176,16 +176,8 @@ int pa_sink_input_new( pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID); if (!data->volume_is_set) { - - if (data->sink->flags & PA_SINK_FLAT_VOLUME) { - data->volume = *pa_sink_get_volume(data->sink, FALSE); - pa_cvolume_remap(&data->volume, &data->sink->channel_map, &data->channel_map); - data->volume_is_absolute = TRUE; - } else { - pa_cvolume_reset(&data->volume, data->sample_spec.channels); - data->volume_is_absolute = FALSE; - } - + pa_cvolume_reset(&data->volume, data->sample_spec.channels); + data->volume_is_absolute = FALSE; data->save_volume = FALSE; } @@ -279,10 +271,9 @@ int pa_sink_input_new( /* When the 'absolute' bool is not set then we'll treat the volume * as relative to the sink volume even in flat volume mode */ - pa_cvolume t = *pa_sink_get_volume(data->sink, FALSE); - pa_cvolume_remap(&t, &data->sink->channel_map, &data->channel_map); - - pa_sw_cvolume_multiply(&i->virtual_volume, &data->volume, &t); + pa_cvolume v = data->sink->reference_volume; + pa_cvolume_remap(&v, &data->sink->channel_map, &data->channel_map); + pa_sw_cvolume_multiply(&i->virtual_volume, &data->volume, &v); } else i->virtual_volume = data->volume; @@ -451,7 +442,7 @@ void pa_sink_input_unlink(pa_sink_input *i) { if (i->sink->flags & PA_SINK_FLAT_VOLUME) { pa_cvolume new_volume; pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE); + pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE); } if (i->sink->asyncmsgq) @@ -529,7 +520,7 @@ void pa_sink_input_put(pa_sink_input *i) { if (i->sink->flags & PA_SINK_FLAT_VOLUME) { pa_cvolume new_volume; pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE); + pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE); } else pa_sink_input_set_relative_volume(i, &i->virtual_volume); @@ -881,13 +872,21 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) { } /* Called from main context */ -void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save) { +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute) { + pa_cvolume v; + pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(volume); pa_assert(pa_cvolume_valid(volume)); pa_assert(pa_cvolume_compatible(volume, &i->sample_spec)); + if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) { + v = i->sink->reference_volume; + pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map); + volume = pa_sw_cvolume_multiply(&v, &v, volume); + } + if (pa_cvolume_equal(volume, &i->virtual_volume)) return; @@ -901,7 +900,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo * volumes and update the flat volume of the sink */ pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE); + pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE, FALSE); } else { @@ -921,11 +920,18 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo } /* Called from main context */ -const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) { +pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute) { pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - return &i->virtual_volume; + if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) { + pa_cvolume v = i->sink->reference_volume; + pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map); + pa_sw_cvolume_divide(volume, &i->virtual_volume, &v); + } else + *volume = i->virtual_volume; + + return volume; } /* Called from main context */ @@ -936,7 +942,8 @@ pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) { pa_assert(v); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - /* This always returns a relative volume, even in flat volume mode */ + /* This always returns the relative volume. Converts the float + * version into a pa_cvolume */ v->channels = i->sample_spec.channels; @@ -1152,7 +1159,7 @@ int pa_sink_input_start_move(pa_sink_input *i) { /* We might need to update the sink's volume if we are in flat * volume mode. */ pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE); + pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE); } pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0); @@ -1239,13 +1246,13 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) { pa_cvolume new_volume; /* Make relative volume absolute again */ - pa_cvolume t = dest->virtual_volume; + pa_cvolume t = dest->reference_volume; pa_cvolume_remap(&t, &dest->channel_map, &i->channel_map); pa_sw_cvolume_multiply(&i->virtual_volume, &i->virtual_volume, &t); /* We might need to update the sink's volume if we are in flat volume mode. */ pa_sink_update_flat_volume(i->sink, &new_volume); - pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE); + pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE); } pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 96ad2baf..98144d41 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -91,6 +91,7 @@ struct pa_sink_input { pa_sink_input *sync_prev, *sync_next; + /* Also see http://pulseaudio.org/wiki/InternalVolumes */ pa_cvolume virtual_volume; /* The volume clients are informed about */ pa_cvolume volume_factor; /* An internally used volume factor that can be used by modules to apply effects and suchlike without having that visible to the outside */ double relative_volume[PA_CHANNELS_MAX]; /* The calculated volume relative to the sink volume as linear factors. */ @@ -309,11 +310,14 @@ void pa_sink_input_kill(pa_sink_input*i); pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency); -void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save); -const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i); +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute); +pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute); + pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v); + void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save); pa_bool_t pa_sink_input_get_mute(pa_sink_input *i); + void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p); pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 93800d14..30fa5579 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -202,7 +202,7 @@ pa_sink* pa_sink_new( s->inputs = pa_idxset_new(NULL, NULL); s->n_corked = 0; - s->virtual_volume = data->volume; + s->reference_volume = s->virtual_volume = data->volume; pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels); s->base_volume = PA_VOLUME_NORM; s->n_volume_steps = PA_VOLUME_NORM+1; @@ -351,11 +351,12 @@ void pa_sink_put(pa_sink* s) { if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) { s->flags |= PA_SINK_DECIBEL_VOLUME; - - s->thread_info.soft_volume = s->soft_volume; - s->thread_info.soft_muted = s->muted; + s->base_volume = PA_VOLUME_NORM; } + s->thread_info.soft_volume = s->soft_volume; + s->thread_info.soft_muted = s->muted; + if (s->flags & PA_SINK_DECIBEL_VOLUME) s->n_volume_steps = PA_VOLUME_NORM+1; @@ -1046,16 +1047,16 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) { pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(s->flags & PA_SINK_FLAT_VOLUME); - /* This is called whenever a sink input volume changes and we - * might need to fix up the sink volume accordingly. Please note - * that we don't actually update the sinks volume here, we only - * return how it needs to be updated. The caller should then call - * pa_sink_set_volume().*/ + /* This is called whenever a sink input volume changes or a sink + * input is added/removed and we might need to fix up the sink + * volume accordingly. Please note that we don't actually update + * the sinks volume here, we only return how it needs to be + * updated. The caller should then call pa_sink_set_volume().*/ if (pa_idxset_isempty(s->inputs)) { /* In the special case that we have no sink input we leave the * volume unmodified. */ - *new_volume = s->virtual_volume; + *new_volume = s->reference_volume; return; } @@ -1142,7 +1143,7 @@ void pa_sink_propagate_flat_volume(pa_sink *s) { } /* Called from main thread */ -void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) { +void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference) { pa_bool_t virtual_volume_changed; pa_sink_assert_ref(s); @@ -1154,6 +1155,9 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat virtual_volume_changed = !pa_cvolume_equal(volume, &s->virtual_volume); s->virtual_volume = *volume; + if (become_reference) + s->reference_volume = s->virtual_volume; + /* Propagate this volume change back to the inputs */ if (virtual_volume_changed) if (propagate && (s->flags & PA_SINK_FLAT_VOLUME)) @@ -1161,8 +1165,8 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat if (s->set_volume) { /* If we have a function set_volume(), then we do not apply a - * soft volume by default. However, set_volume() is apply one - * to s->soft_volume */ + * soft volume by default. However, set_volume() is free to + * apply one to s->soft_volume */ pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels); s->set_volume(s); @@ -1194,7 +1198,7 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) { } /* Called from main thread */ -const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) { +const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_bool_t reference) { pa_sink_assert_ref(s); if (s->refresh_volume || force_refresh) { @@ -1207,6 +1211,8 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) { if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) { + s->reference_volume = s->virtual_volume; + if (s->flags & PA_SINK_FLAT_VOLUME) pa_sink_propagate_flat_volume(s); @@ -1214,7 +1220,7 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) { } } - return &s->virtual_volume; + return reference ? &s->reference_volume : &s->virtual_volume; } /* Called from main thread */ @@ -1226,7 +1232,11 @@ void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) { if (pa_cvolume_equal(&s->virtual_volume, new_volume)) return; - s->virtual_volume = *new_volume; + s->reference_volume = s->virtual_volume = *new_volume; + + if (s->flags & PA_SINK_FLAT_VOLUME) + pa_sink_propagate_flat_volume(s); + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index cb4697f9..352282b8 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -74,8 +74,10 @@ struct pa_sink { pa_volume_t base_volume; /* shall be constant */ unsigned n_volume_steps; /* shall be constant */ - pa_cvolume virtual_volume; /* The volume clients are informed about */ - pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through */ + /* Also see http://pulseaudio.org/wiki/InternalVolumes */ + pa_cvolume virtual_volume; /* The volume clients are informed about */ + pa_cvolume reference_volume; /* The volume taken as refernce base for relative sink input volumes */ + pa_cvolume soft_volume; /* The internal software volume we apply to all PCM data while it passes through */ pa_bool_t muted:1; pa_bool_t refresh_volume:1; @@ -255,8 +257,9 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend); void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume); void pa_sink_propagate_flat_volume(pa_sink *s); -void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg); -const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh); +void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference); +const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh, pa_bool_t reference); + void pa_sink_set_mute(pa_sink *sink, pa_bool_t mute); pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refresh); |