diff --git a/src/daemon/pipewire-pulse.conf.in b/src/daemon/pipewire-pulse.conf.in index 5c6893d7f..47c2130d9 100644 --- a/src/daemon/pipewire-pulse.conf.in +++ b/src/daemon/pipewire-pulse.conf.in @@ -142,6 +142,7 @@ pulse.properties = { #pulse.max-sample-cache = 67108864 # max total sample cache size (64MB) #pulse.default.format = F32 #pulse.default.position = [ FL FR ] + #pulse.zeroramp.gap = 0 # detect silence of N samples and fade-in/out } pulse.properties.rules = [ @@ -209,4 +210,13 @@ pulse.rules = [ # matches = [ { application.process.binary = "Discord" } ] # actions = { quirks = [ block-source-volume ] } #} + + { + matches = [ { application.process.binary = "chrome" } ] + actions = { + update-props = { + pulse.zeroramp.gap = 8 + } + } + } ] diff --git a/src/modules/module-protocol-pulse.c b/src/modules/module-protocol-pulse.c index 1a52e390e..5d928a9b9 100644 --- a/src/modules/module-protocol-pulse.c +++ b/src/modules/module-protocol-pulse.c @@ -77,7 +77,8 @@ * #pulse.default.position = [ FL FR ] * #pulse.idle.timeout = 0 * #pulse.max-streams = 64 - * #pulse.max-sample-cache = 67108864 + * #pulse.max-sample-cache = 67108864 + * #pulse.zeroramp.gap = 0 # detect silence of N samples and fade-in/out * } * * pulse.properties.rules = [ @@ -262,6 +263,14 @@ * The maximum total size in bytes of all sample cache entries. Default is * 67108864 (64MB). * + *\code{.unparsed} + * pulse.zeroramp.gap = 0 + *\endcode + * + * Enable silence detection of a playback stream and perform fade-in and fade-out on + * silence boundaries to avoid loud pops. This is a workaround for when the application + * sends silence instead of corking/uncorking to pause/resume the stream. + * * ## Command execution * * As part of the server startup sequence, a set of commands can be executed. diff --git a/src/modules/module-protocol-pulse/internal.h b/src/modules/module-protocol-pulse/internal.h index 9f9531e7e..d0d372c0e 100644 --- a/src/modules/module-protocol-pulse/internal.h +++ b/src/modules/module-protocol-pulse/internal.h @@ -38,6 +38,7 @@ struct defs { uint32_t idle_timeout; uint32_t max_streams; uint32_t max_sample_cache; + uint32_t zeroramp_gap; }; struct stats { diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 807487968..6e15da265 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -69,6 +69,7 @@ #define DEFAULT_IDLE_TIMEOUT "0" #define DEFAULT_MAX_STREAMS "64" #define DEFAULT_MAX_SAMPLE_CACHE "67108864" +#define DEFAULT_ZERORAMP_GAP "0" #define MAX_FORMATS 32 /* The max amount of data we send in one block when capturing. In PulseAudio this @@ -1837,6 +1838,9 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui if (dont_inhibit_auto_suspend) pw_properties_set(props, PW_KEY_NODE_PASSIVE, "true"); + if (impl->defs.zeroramp_gap > 0) + pw_properties_setf(props, "zeroramp.gap", "%d", impl->defs.zeroramp_gap); + stream->stream = pw_stream_new(client->core, name, spa_steal_ptr(props)); if (stream->stream == NULL) goto error_errno; @@ -5666,6 +5670,7 @@ static void load_defaults(struct defs *def, struct pw_properties *props) parse_uint32(props, "pulse.idle.timeout", DEFAULT_IDLE_TIMEOUT, &def->idle_timeout); parse_uint32(props, "pulse.max-streams", DEFAULT_MAX_STREAMS, &def->max_streams); parse_uint32(props, "pulse.max-sample-cache", DEFAULT_MAX_SAMPLE_CACHE, &def->max_sample_cache); + parse_uint32(props, "pulse.zeroramp.gap", DEFAULT_ZERORAMP_GAP, &def->zeroramp_gap); def->sample_spec.channels = def->channel_map.channels; def->quantum_limit = 8192; }