Some sink flags are really just a product of what callbacks set on the sink. Rather than assert when the flags don't match the callbacks registered, just set them automatically. --- src/modules/alsa/alsa-sink.c | 11 +++------ src/modules/alsa/alsa-source.c | 11 +++------ src/modules/bluetooth/module-bluetooth-device.c | 4 +- src/modules/echo-cancel/module-echo-cancel.c | 4 +- src/modules/module-equalizer-sink.c | 2 +- src/modules/module-ladspa-sink.c | 2 +- src/modules/module-solaris.c | 4 +- src/modules/module-tunnel.c | 2 +- src/modules/oss/module-oss.c | 3 -- src/modules/raop/module-raop-sink.c | 2 +- src/pulse/def.h | 18 +++++++++++----- src/pulsecore/sink.c | 24 +++++++++++++++++----- src/pulsecore/source.c | 24 +++++++++++++++++----- 13 files changed, 66 insertions(+), 45 deletions(-) diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 0164040..8f31901 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1759,9 +1759,9 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB, pa_bool_t sync_v return 0; } - if (!u->mixer_path->has_volume) + if (!u->mixer_path->has_volume) { pa_log_info("Driver does not support hardware volume control, falling back to software volume control."); - else { + } else { if (u->mixer_path->has_dB) { pa_log_info("Hardware volume ranges from %0.2f dB to %0.2f dB.", u->mixer_path->min_dB, u->mixer_path->max_dB); @@ -1779,13 +1779,11 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB, pa_bool_t sync_v u->sink->get_volume = sink_get_volume_cb; u->sink->set_volume = sink_set_volume_cb; - u->sink->write_volume = sink_write_volume_cb; - u->sink->flags |= PA_SINK_HW_VOLUME_CTRL; if (u->mixer_path->has_dB) { u->sink->flags |= PA_SINK_DECIBEL_VOLUME; if (sync_volume) { - u->sink->flags |= PA_SINK_SYNC_VOLUME; + u->sink->write_volume = sink_write_volume_cb; pa_log_info("Successfully enabled synchronous volume."); } } @@ -1798,11 +1796,10 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB, pa_bool_t sync_v } else { u->sink->get_mute = sink_get_mute_cb; u->sink->set_mute = sink_set_mute_cb; - u->sink->flags |= PA_SINK_HW_MUTE_CTRL; pa_log_info("Using hardware mute control."); } - if (u->sink->flags & (PA_SINK_HW_VOLUME_CTRL|PA_SINK_HW_MUTE_CTRL)) { + if (u->mixer_path->has_volume || u->mixer_path->has_mute) { int (*mixer_callback)(snd_mixer_elem_t *, unsigned int); if (u->sink->flags & PA_SINK_SYNC_VOLUME) { u->mixer_pd = pa_alsa_mixer_pdata_new(); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index f847b1e..52dd65e 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -1534,9 +1534,9 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB, pa_bool_t sync_v return 0; } - if (!u->mixer_path->has_volume) + if (!u->mixer_path->has_volume) { pa_log_info("Driver does not support hardware volume control, falling back to software volume control."); - else { + } else { if (u->mixer_path->has_dB) { pa_log_info("Hardware volume ranges from %0.2f dB to %0.2f dB.", u->mixer_path->min_dB, u->mixer_path->max_dB); @@ -1554,13 +1554,11 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB, pa_bool_t sync_v u->source->get_volume = source_get_volume_cb; u->source->set_volume = source_set_volume_cb; - u->source->write_volume = source_write_volume_cb; - u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; if (u->mixer_path->has_dB) { u->source->flags |= PA_SOURCE_DECIBEL_VOLUME; if (sync_volume) { - u->source->flags |= PA_SOURCE_SYNC_VOLUME; + u->source->write_volume = source_write_volume_cb; pa_log_info("Successfully enabled synchronous volume."); } } @@ -1573,11 +1571,10 @@ static int setup_mixer(struct userdata *u, pa_bool_t ignore_dB, pa_bool_t sync_v } else { u->source->get_mute = source_get_mute_cb; u->source->set_mute = source_set_mute_cb; - u->source->flags |= PA_SOURCE_HW_MUTE_CTRL; pa_log_info("Using hardware mute control."); } - if (u->source->flags & (PA_SOURCE_HW_VOLUME_CTRL|PA_SOURCE_HW_MUTE_CTRL)) { + if (u->mixer_path->has_volume || u->mixer_path->has_mute) { int (*mixer_callback)(snd_mixer_elem_t *, unsigned int); if (u->source->flags & PA_SOURCE_SYNC_VOLUME) { u->mixer_pd = pa_alsa_mixer_pdata_new(); diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 288ad2f..448e252 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -2022,7 +2022,7 @@ static int add_sink(struct userdata *u) { return -1; } - u->sink = pa_sink_new(u->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY | (u->profile == PROFILE_HSP ? PA_SINK_HW_VOLUME_CTRL : 0)); + u->sink = pa_sink_new(u->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY); pa_sink_new_data_done(&data); if (!u->sink) { @@ -2084,7 +2084,7 @@ static int add_source(struct userdata *u) { return -1; } - u->source = pa_source_new(u->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY | (u->profile == PROFILE_HSP ? PA_SOURCE_HW_VOLUME_CTRL : 0)); + u->source = pa_source_new(u->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY); pa_source_new_data_done(&data); if (!u->source) { diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c index b84bf1d..7939f5e 100644 --- a/src/modules/echo-cancel/module-echo-cancel.c +++ b/src/modules/echo-cancel/module-echo-cancel.c @@ -1519,7 +1519,7 @@ int pa__init(pa_module*m) { } u->source = pa_source_new(m->core, &source_data, - PA_SOURCE_HW_MUTE_CTRL|PA_SOURCE_HW_VOLUME_CTRL|PA_SOURCE_DECIBEL_VOLUME| + PA_SOURCE_DECIBEL_VOLUME| (source_master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY))); pa_source_new_data_done(&source_data); @@ -1567,7 +1567,7 @@ int pa__init(pa_module*m) { } u->sink = pa_sink_new(m->core, &sink_data, - PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME| + PA_SINK_DECIBEL_VOLUME| (sink_master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))); pa_sink_new_data_done(&sink_data); diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c index e7d8790..753202d 100644 --- a/src/modules/module-equalizer-sink.c +++ b/src/modules/module-equalizer-sink.c @@ -1178,7 +1178,7 @@ int pa__init(pa_module*m) { } u->sink = pa_sink_new(m->core, &sink_data, - PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME| + PA_SINK_DECIBEL_VOLUME| (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))); pa_sink_new_data_done(&sink_data); diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index 9cce269..acf2d0e 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -883,7 +883,7 @@ int pa__init(pa_module*m) { } u->sink = pa_sink_new(m->core, &sink_data, - PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME| + PA_SINK_DECIBEL_VOLUME| (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))); pa_sink_new_data_done(&sink_data); diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index 0e4e401..89ebdee 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -933,7 +933,7 @@ int pa__init(pa_module *m) { goto fail; } - u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL); + u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY); pa_source_new_data_done(&source_new_data); pa_xfree(name_buf); @@ -981,7 +981,7 @@ int pa__init(pa_module *m) { goto fail; } - u->sink = pa_sink_new(m->core, &sink_new_data, PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL|PA_SINK_HW_MUTE_CTRL); + u->sink = pa_sink_new(m->core, &sink_new_data, PA_SINK_HARDWARE|PA_SINK_LATENCY); pa_sink_new_data_done(&sink_new_data); pa_assert(u->sink); diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 4b1ae7d..aa7ad13 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -2003,7 +2003,7 @@ int pa__init(pa_module*m) { goto fail; } - u->sink = pa_sink_new(m->core, &data, PA_SINK_NETWORK|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL|PA_SINK_HW_MUTE_CTRL); + u->sink = pa_sink_new(m->core, &data, PA_SINK_NETWORK|PA_SINK_LATENCY); pa_sink_new_data_done(&data); if (!u->sink) { diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c index 2a99d11..f40cb1d 100644 --- a/src/modules/oss/module-oss.c +++ b/src/modules/oss/module-oss.c @@ -1418,11 +1418,9 @@ int pa__init(pa_module*m) { if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0) pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno)); - else { if (u->sink && (u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM))) { pa_log_debug("Found hardware mixer track for playback."); - u->sink->flags |= PA_SINK_HW_VOLUME_CTRL; u->sink->get_volume = sink_get_volume; u->sink->set_volume = sink_set_volume; u->sink->n_volume_steps = 101; @@ -1431,7 +1429,6 @@ int pa__init(pa_module*m) { if (u->source && (u->mixer_devmask & (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) { pa_log_debug("Found hardware mixer track for recording."); - u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; u->source->get_volume = source_get_volume; u->source->set_volume = source_set_volume; u->source->n_volume_steps = 101; diff --git a/src/modules/raop/module-raop-sink.c b/src/modules/raop/module-raop-sink.c index 87e7bc1..b62d8fc 100644 --- a/src/modules/raop/module-raop-sink.c +++ b/src/modules/raop/module-raop-sink.c @@ -596,7 +596,7 @@ int pa__init(pa_module*m) { u->sink->userdata = u; u->sink->set_volume = sink_set_volume_cb; u->sink->set_mute = sink_set_mute_cb; - u->sink->flags = PA_SINK_LATENCY|PA_SINK_NETWORK|PA_SINK_HW_VOLUME_CTRL; + u->sink->flags = PA_SINK_LATENCY|PA_SINK_NETWORK; pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); diff --git a/src/pulse/def.h b/src/pulse/def.h index 16b2e59..32169de 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -712,7 +712,8 @@ typedef enum pa_sink_flags { /**< Flag to pass when no specific options are needed (used to avoid casting) \since 0.9.19 */ PA_SINK_HW_VOLUME_CTRL = 0x0001U, - /**< Supports hardware volume control */ + /**< Supports hardware volume control. This is a dynamic flag and may + * change at runtime after the sink has initialized */ PA_SINK_LATENCY = 0x0002U, /**< Supports latency querying */ @@ -725,10 +726,12 @@ typedef enum pa_sink_flags { /**< Is a networked sink of some kind. \since 0.9.7 */ PA_SINK_HW_MUTE_CTRL = 0x0010U, - /**< Supports hardware mute control \since 0.9.11 */ + /**< Supports hardware mute control. This is a dynamic flag and may + * change at runtime after the sink has initialized \since 0.9.11 */ PA_SINK_DECIBEL_VOLUME = 0x0020U, - /**< Volume can be translated to dB with pa_sw_volume_to_dB() + /**< Volume can be translated to dB with pa_sw_volume_to_dB(). This is a + * dynamic flag and may change at runtime after the sink has initialized * \since 0.9.11 */ PA_SINK_FLAT_VOLUME = 0x0040U, @@ -820,7 +823,8 @@ typedef enum pa_source_flags { /**< Flag to pass when no specific options are needed (used to avoid casting) \since 0.9.19 */ PA_SOURCE_HW_VOLUME_CTRL = 0x0001U, - /**< Supports hardware volume control */ + /**< Supports hardware volume control. This is a dynamic flag and may + * change at runtime after the source has initialized */ PA_SOURCE_LATENCY = 0x0002U, /**< Supports latency querying */ @@ -833,10 +837,12 @@ typedef enum pa_source_flags { /**< Is a networked source of some kind. \since 0.9.7 */ PA_SOURCE_HW_MUTE_CTRL = 0x0010U, - /**< Supports hardware mute control \since 0.9.11 */ + /**< Supports hardware mute control. This is a dynamic flag and may + * change at runtime after the source has initialized \since 0.9.11 */ PA_SOURCE_DECIBEL_VOLUME = 0x0020U, - /**< Volume can be translated to dB with pa_sw_volume_to_dB() + /**< Volume can be translated to dB with pa_sw_volume_to_dB(). This is a + * dynamic flag and may change at runtime after the source has initialized * \since 0.9.11 */ PA_SOURCE_DYNAMIC_LATENCY = 0x0040U, diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 45761a6..15c07a5 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -462,8 +462,19 @@ void pa_sink_put(pa_sink* s) { pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency); /* Generally, flags should be initialized via pa_sink_new(). As a - * special exception we allow volume related flags to be set - * between _new() and _put(). */ + * special exception we allow some volume related flags to be set + * between _new() and _put(). However some are dictated by what + * callbacks were registered so we set those here. + * + * Note: All of these flags set here can change over the life time + * of the sink. */ + s->flags &= ~(PA_SINK_HW_VOLUME_CTRL|PA_SINK_HW_MUTE_CTRL|PA_SINK_SYNC_VOLUME|PA_SINK_FLAT_VOLUME); + if (s->get_volume || s->set_volume) + s->flags |= PA_SINK_HW_VOLUME_CTRL; + if (s->get_mute || s->set_mute) + s->flags |= PA_SINK_HW_MUTE_CTRL; + if (s->write_volume) + s->flags |= PA_SINK_SYNC_VOLUME; /* XXX: Currently decibel volume is disabled for all sinks that use volume * sharing. When the master sink supports decibel volume, it would be good @@ -472,12 +483,17 @@ void pa_sink_put(pa_sink* s) { * a master sink to another. One solution for this problem would be to * remove user-visible volume altogether from filter sinks when volume * sharing is used, but the current approach was easier to implement... */ + /* We always support decibel volumes in software, otherwise we leave it to + * the sink implementor to set this flag as needed. + * + * Note: This flag can also change over the life time of the sink. */ if (!(s->flags & PA_SINK_HW_VOLUME_CTRL) && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) s->flags |= PA_SINK_DECIBEL_VOLUME; if ((s->flags & PA_SINK_DECIBEL_VOLUME) && s->core->flat_volumes) s->flags |= PA_SINK_FLAT_VOLUME; + if (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) { pa_sink *root_sink = s->input_to_master->sink; @@ -506,10 +522,6 @@ void pa_sink_put(pa_sink* s) { pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0)); pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY)); pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_DYNAMIC_LATENCY)); - pa_assert(!(s->flags & PA_SINK_HW_VOLUME_CTRL) || s->set_volume); - pa_assert(!(s->flags & PA_SINK_SYNC_VOLUME) || (s->flags & PA_SINK_HW_VOLUME_CTRL)); - pa_assert(!(s->flags & PA_SINK_SYNC_VOLUME) || s->write_volume); - pa_assert(!(s->flags & PA_SINK_HW_MUTE_CTRL) || s->set_mute); pa_assert(s->monitor_source->thread_info.fixed_latency == s->thread_info.fixed_latency); pa_assert(s->monitor_source->thread_info.min_latency == s->thread_info.min_latency); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 7024802..121c358 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -394,8 +394,19 @@ void pa_source_put(pa_source *s) { pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency); /* Generally, flags should be initialized via pa_source_new(). As a - * special exception we allow volume related flags to be set - * between _new() and _put(). */ + * special exception we allow some volume related flags to be set + * between _new() and _put(). However some are dictated by what + * callbacks were registered so we set those here. + * + * Note: All of these flags set here can change over the life time + * of the source. */ + s->flags &= ~(PA_SOURCE_HW_VOLUME_CTRL|PA_SOURCE_HW_MUTE_CTRL|PA_SOURCE_SYNC_VOLUME|PA_SOURCE_FLAT_VOLUME); + if (s->get_volume || s->set_volume) + s->flags |= PA_SOURCE_HW_VOLUME_CTRL; + if (s->get_mute || s->set_mute) + s->flags |= PA_SOURCE_HW_MUTE_CTRL; + if (s->write_volume) + s->flags |= PA_SOURCE_SYNC_VOLUME; /* XXX: Currently decibel volume is disabled for all sources that use volume * sharing. When the master source supports decibel volume, it would be good @@ -404,12 +415,17 @@ void pa_source_put(pa_source *s) { * a master source to another. One solution for this problem would be to * remove user-visible volume altogether from filter sources when volume * sharing is used, but the current approach was easier to implement... */ + /* We always support decibel volumes in software, otherwise we leave it to + * the source implementor to set this flag as needed. + * + * Note: This flag can also change over the life time of the source. */ if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL) && !(s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER)) s->flags |= PA_SOURCE_DECIBEL_VOLUME; if ((s->flags & PA_SOURCE_DECIBEL_VOLUME) && s->core->flat_volumes) s->flags |= PA_SOURCE_FLAT_VOLUME; + if (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER) { pa_source *root_source = s->output_from_master->source; @@ -436,10 +452,6 @@ void pa_source_put(pa_source *s) { && ((s->flags & PA_SOURCE_DECIBEL_VOLUME || (s->flags & PA_SOURCE_SHARE_VOLUME_WITH_MASTER))))); pa_assert(!(s->flags & PA_SOURCE_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1); pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0)); - pa_assert(!(s->flags & PA_SOURCE_HW_VOLUME_CTRL) || s->set_volume); - pa_assert(!(s->flags & PA_SOURCE_SYNC_VOLUME) || (s->flags & PA_SOURCE_HW_VOLUME_CTRL)); - pa_assert(!(s->flags & PA_SOURCE_SYNC_VOLUME) || s->write_volume); - pa_assert(!(s->flags & PA_SOURCE_HW_MUTE_CTRL) || s->set_mute); pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0); -- 1.7.6