Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 4
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,14 @@ ------------------------------------------------------------------- +Fri Feb 18 14:59:46 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.47 + +------------------------------------------------------------------- +Thu Feb 17 13:55:01 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.46 + +------------------------------------------------------------------- Fri Feb 4 06:41:51 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.45
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.45 +Version: 0.3.47 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
pipewire-0.3.45.tar.gz/pipewire-jack/src/match-rules.c
Deleted
@@ -1,141 +0,0 @@ -/* PipeWire - * - * Copyright © 2021 Wim Taymans - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <math.h> -#include <time.h> -#include <regex.h> - -#include "config.h" - -#include <spa/utils/json.h> -#include <spa/utils/string.h> - -#include <pipewire/pipewire.h> - -static bool find_match(struct spa_json *arr, const struct spa_dict *props) -{ - struct spa_json it[1]; - - while (spa_json_enter_object(arr, &it[0]) > 0) { - char key[256], val[1024]; - const char *str, *value; - int match = 0, fail = 0; - int len; - - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { - bool success = false; - - if ((len = spa_json_next(&it[0], &value)) <= 0) - break; - - str = spa_dict_lookup(props, key); - - if (spa_json_is_null(value, len)) { - success = str == NULL; - } else { - if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0) - continue; - value = val; - len = strlen(val); - } - if (str != NULL) { - if (value[0] == '~') { - regex_t preg; - if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) { - if (regexec(&preg, str, 0, NULL, 0) == 0) - success = true; - regfree(&preg); - } - } else if (strncmp(str, value, len) == 0 && - strlen(str) == (size_t)len) { - success = true; - } - } - if (success) { - match++; - pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value); - } - else - fail++; - } - if (match > 0 && fail == 0) - return true; - } - return false; -} - -int pw_jack_match_rules(const char *rules, size_t size, const struct spa_dict *props, - int (*matched) (void *data, const char *action, const char *val, size_t len), - void *data) -{ - const char *val; - struct spa_json it[4], actions; - int count = 0; - - spa_json_init(&it[0], rules, size); - if (spa_json_enter_array(&it[0], &it[1]) < 0) - return 0; - - while (spa_json_enter_object(&it[1], &it[2]) > 0) { - char key[64]; - bool have_match = false, have_actions = false; - - while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) { - if (spa_streq(key, "matches")) { - if (spa_json_enter_array(&it[2], &it[3]) < 0) - break; - - have_match = find_match(&it[3], props); - } - else if (spa_streq(key, "actions")) { - if (spa_json_enter_object(&it[2], &actions) > 0) - have_actions = true; - } - else if (spa_json_next(&it[2], &val) <= 0) - break; - } - if (!have_match || !have_actions) - continue; - - while (spa_json_get_string(&actions, key, sizeof(key)) > 0) { - int res, len; - pw_log_debug("action %s", key); - - if ((len = spa_json_next(&actions, &val)) <= 0) - break; - - if (spa_json_is_container(val, len)) - len = spa_json_container_len(&actions, val, len); - - if ((res = matched(data, key, val, len)) < 0) - return res; - - count += res; - } - } - return count; -}
View file
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel
Deleted
-(directory)
View file
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel/aec-null.c
Deleted
@@ -1,64 +0,0 @@ -/* PipeWire - * - * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include "echo-cancel.h" - -struct impl { - uint32_t channels; -}; - -static void *null_create(const struct pw_properties *args, const struct spa_audio_info_raw *info) -{ - struct impl *impl; - impl = calloc(1, sizeof(struct impl)); - impl->channels = info->channels; - return impl; -} - -static void null_destroy(void *ec) -{ - free(ec); -} - -static int null_run(void *ec, const float *rec[], const float *play[], float *out[], uint32_t n_samples) -{ - struct impl *impl = ec; - uint32_t i; - for (i = 0; i < impl->channels; i++) - memcpy(out[i], rec[i], n_samples * sizeof(float)); - return 0; -} - -static const struct echo_cancel_info echo_cancel_null_impl = { - .name = "null", - .info = SPA_DICT_INIT(NULL, 0), - .latency = NULL, - - .create = null_create, - .destroy = null_destroy, - - .run = null_run, -}; - -const struct echo_cancel_info *echo_cancel_null = &echo_cancel_null_impl;
View file
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel/aec-webrtc.cpp
Deleted
@@ -1,163 +0,0 @@ -/* PipeWire - * - * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com> - * © 2021 Arun Raghavan <arun@asymptotic.io> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include <memory> -#include <utility> - -#include "echo-cancel.h" - -#include <pipewire/pipewire.h> - -#include <webrtc/modules/audio_processing/include/audio_processing.h> -#include <webrtc/modules/interface/module_common_types.h> -#include <webrtc/system_wrappers/include/trace.h> - -struct impl { - std::unique_ptr<webrtc::AudioProcessing> apm; - spa_audio_info_raw info; - std::unique_ptr<float *[]> play_buffer, rec_buffer, out_buffer; - - impl(std::unique_ptr<webrtc::AudioProcessing> apm, const spa_audio_info_raw& info) - : apm(std::move(apm)), - info(info), - play_buffer(std::make_unique<float *[]>(info.channels)), - rec_buffer(std::make_unique<float *[]>(info.channels)), - out_buffer(std::make_unique<float *[]>(info.channels)) - { } -}; - -static void *webrtc_create(const struct pw_properties *args, const spa_audio_info_raw *info) -{ - bool extended_filter = pw_properties_get_bool(args, "webrtc.extended_filter", true); - bool delay_agnostic = pw_properties_get_bool(args, "webrtc.delay_agnostic", true); - bool high_pass_filter = pw_properties_get_bool(args, "webrtc.high_pass_filter", true); - bool noise_suppression = pw_properties_get_bool(args, "webrtc.noise_suppression", true); - bool voice_detection = pw_properties_get_bool(args, "webrtc.voice_detection", true); - - // Note: AGC seems to mess up with Agnostic Delay Detection, especially with speech, - // result in very poor performance, disable by default - bool gain_control = pw_properties_get_bool(args, "webrtc.gain_control", false); - - // Disable experimental flags by default - bool experimental_agc = pw_properties_get_bool(args, "webrtc.experimental_agc", false); - bool experimental_ns = pw_properties_get_bool(args, "webrtc.experimental_ns", false); - - // FIXME: Intelligibility enhancer is not currently supported - // This filter will modify playback buffer (when calling ProcessReverseStream), but now - // playback buffer modifications are discarded. - - webrtc::Config config; - config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(extended_filter)); - config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(delay_agnostic)); - config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(experimental_agc)); - config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns)); - - webrtc::ProcessingConfig pconfig = {{ - webrtc::StreamConfig(info->rate, info->channels, false), /* input stream */ - webrtc::StreamConfig(info->rate, info->channels, false), /* output stream */ - webrtc::StreamConfig(info->rate, info->channels, false), /* reverse input stream */ - webrtc::StreamConfig(info->rate, info->channels, false), /* reverse output stream */ - }}; - - auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config)); - if (apm->Initialize(pconfig) != webrtc::AudioProcessing::kNoError) { - pw_log_error("Error initialising webrtc audio processing module"); - return nullptr; - } - - apm->high_pass_filter()->Enable(high_pass_filter); - // Always disable drift compensation since it requires drift sampling - apm->echo_cancellation()->enable_drift_compensation(false); - apm->echo_cancellation()->Enable(true); - // TODO: wire up supression levels to args - apm->echo_cancellation()->set_suppression_level(webrtc::EchoCancellation::kHighSuppression); - apm->noise_suppression()->set_level(webrtc::NoiseSuppression::kHigh); - apm->noise_suppression()->Enable(noise_suppression); - apm->voice_detection()->Enable(voice_detection); - // TODO: wire up AGC parameters to args - apm->gain_control()->set_analog_level_limits(0, 255); - apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital); - apm->gain_control()->Enable(gain_control); - - return new impl(std::move(apm), *info); -} - -static void webrtc_destroy(void *ec) -{ - auto impl = static_cast<struct impl *>(ec); - - delete impl; -} - -static int webrtc_run(void *ec, const float *rec[], const float *play[], float *out[], uint32_t n_samples) -{ - auto impl = static_cast<struct impl *>(ec); - webrtc::StreamConfig config = - webrtc::StreamConfig(impl->info.rate, impl->info.channels, false); - unsigned int num_blocks = n_samples * 1000 / impl->info.rate / 10; - - if (n_samples * 1000 / impl->info.rate % 10 != 0) { - pw_log_error("Buffers must be multiples of 10ms in length (currently %u samples)", n_samples); - return -1; - } - - for (size_t i = 0; i < num_blocks; i ++) { - for (size_t j = 0; j < impl->info.channels; j++) { - impl->play_buffer[j] = const_cast<float *>(play[j]) + config.num_frames() * i; - impl->rec_buffer[j] = const_cast<float *>(rec[j]) + config.num_frames() * i; - impl->out_buffer[j] = out[j] + config.num_frames() * i; - } - /* FIXME: ProcessReverseStream may change the playback buffer, in which - * case we should use that, if we ever expose the intelligibility - * enhancer */ - if (impl->apm->ProcessReverseStream(impl->play_buffer.get(), config, config, impl->play_buffer.get()) != - webrtc::AudioProcessing::kNoError) { - pw_log_error("Processing reverse stream failed"); - } - - // Extra delay introduced by multiple frames - impl->apm->set_stream_delay_ms((num_blocks - 1) * 10); - - if (impl->apm->ProcessStream(impl->rec_buffer.get(), config, config, impl->out_buffer.get()) != - webrtc::AudioProcessing::kNoError) { - pw_log_error("Processing stream failed"); - } - } - - return 0; -} - -static const struct echo_cancel_info echo_cancel_webrtc_impl = { - .name = "webrtc", - .info = SPA_DICT_INIT(NULL, 0), - .latency = "480/48000", - - .create = webrtc_create, - .destroy = webrtc_destroy, - - .run = webrtc_run, -}; - -const struct echo_cancel_info *echo_cancel_webrtc = &echo_cancel_webrtc_impl;
View file
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel/echo-cancel.h
Deleted
@@ -1,50 +0,0 @@ -/* PipeWire - * - * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include "config.h" - -#include <spa/utils/dict.h> -#include <spa/param/audio/raw.h> - -#include <pipewire/properties.h> - -struct echo_cancel_info { - const char *name; - const struct spa_dict info; - const char *latency; - - void *(*create) (const struct pw_properties *args, const struct spa_audio_info_raw *info); - void (*destroy) (void *ec); - - int (*run) (void *ec, const float *rec[], const float *play[], float *out[], uint32_t n_samples); -}; - -#define echo_cancel_create(i,...) (i)->create(__VA_ARGS__) -#define echo_cancel_destroy(i,...) (i)->destroy(__VA_ARGS__) -#define echo_cancel_run(i,...) (i)->run(__VA_ARGS__) - -#ifdef HAVE_WEBRTC -extern const struct echo_cancel_info *echo_cancel_webrtc; -#endif -extern const struct echo_cancel_info *echo_cancel_null;
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/media-roles.c
Deleted
@@ -1,40 +0,0 @@ -/* PipeWire - * - * Copyright © 2020 Wim Taymans - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include <stddef.h> - -#include "media-roles.h" - -const struct str_map media_role_map[] = { - { "Movie", "video", }, - { "Music", "music", }, - { "Game", "game", }, - { "Notification", "event", }, - { "Communication", "phone", }, - { "Movie", "animation", }, - { "Production", "production", }, - { "Accessibility", "a11y", }, - { "Test", "test", }, - { NULL, NULL }, -};
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/media-roles.h
Deleted
@@ -1,50 +0,0 @@ -/* PipeWire - * - * Copyright © 2020 Wim Taymans - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifndef PULSE_SERVER_MEDIA_ROLES_H -#define PULSE_SERVER_MEDIA_ROLES_H - -#include <stddef.h> - -#include <spa/utils/string.h> - -struct str_map { - const char *pw_str; - const char *pa_str; - const struct str_map *child; -}; - -extern const struct str_map media_role_map[]; - -static inline const struct str_map *str_map_find(const struct str_map *map, const char *pw, const char *pa) -{ - size_t i; - for (i = 0; map[i].pw_str; i++) - if ((pw && spa_streq(map[i].pw_str, pw)) || - (pa && spa_streq(map[i].pa_str, pa))) - return &map[i]; - return NULL; -} - -#endif /* PULSE_SERVER_MEDIA_ROLES_H */
View file
pipewire-0.3.45.tar.gz/.gitlab-ci.yml -> pipewire-0.3.47.tar.gz/.gitlab-ci.yml
Changed
@@ -25,7 +25,7 @@ .fedora: variables: # Update this tag when you want to trigger a rebuild - FDO_DISTRIBUTION_TAG: '2022-01-28.0' + FDO_DISTRIBUTION_TAG: '2022-02-16.0' FDO_DISTRIBUTION_VERSION: '35' FDO_DISTRIBUTION_PACKAGES: >- alsa-lib-devel @@ -142,7 +142,7 @@ FDO_DISTRIBUTION_EXEC: >- mkdir -p /opt ; cd /opt ; - curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64 + curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/cxx/linux64 --form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN ; tar xf /tmp/cov-analysis-linux64.tgz ; mv cov-analysis-linux64-* coverity ;
View file
pipewire-0.3.45.tar.gz/NEWS -> pipewire-0.3.47.tar.gz/NEWS
Changed
@@ -1,3 +1,110 @@ +# PipeWire 0.3.47 (2022-02-18) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +This is a quick emergency release to fix some severe +problems with the previous release. + +## Highlights + - Fixes a bug in pulse-server that caused cached notifications + to play multiple times. (#2142) + - Removed check and warnings to catch leaked listeners on the + proxy. This might access invalid memory and cause infinite + loops in older wireplumber. + +Older versions: + +# PipeWire 0.3.46 (2022-02-17) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + - Fix a critical bug in pipewire-pulse buffer size handling that made some + apps (MuseScore, ... ) stutter. + - Fix a critical bug where devices would not show when the kernel was + compiled without VERBOSE_PROCSFS. + - JACK clients will now use lock-quantum by default. This makes sure that + all dynamic quantum changes are disabled while a JACK app is running. + The only way to force a quantum chance is through a JACK app or with + the metadata. + - Almost all limits on number of ports, clients and nodes are removed. + - A Dummy fallback sink is now automatically created when there are no + other sinks. This avoids stalling browsers. + - Sound sharing with Zoom should work better. A new WirePlumber release + might be required. + - Many more fixes and improvements. + + +## PipeWire + - Update docs with new config overrides. + - The rule matching logic was moved to config and code is now shared with + pulse-server and JACK. + - Add new Romanian translation. + - When a quantum is forced with metadata, any node that asked to lock-quantum + is ignored so that the quantum change can happen. + - Fix a bug where a mixer was removed twice, leading to potential memory + corruption. + - The port limits on nodes and filters are now removed. Some code was + simplified. + - Fix a potential leak because listeners where removed while they could be + emitted. + - Improve context.exec and avoid zombie processes. + +## Modules + - The RAOP module now has a default latency of 2 seconds, like PulseAudio. + - The echo-cancel module now uses the plugin loader to load the backends. + This makes it possible to add custom, out of tree, echo cancel plugins. + +## Tools + - Improve help of pw-link. + - Output to stdout and error to stderr. Use setlinebuf for stdout to improve + piping between apps. (#2110) + +## SPA + - Improve removing sources when dispatching. Also improve performance now + that a destroy loop can be removed. (#2114) + - Fix an fd leak in the logger when logging to a file. + - Improve loop enter/leave checks and support recursive loops. + +## pulse-server + - Clamp various buffer attributes to the max length. Fixes some issues + with various applications. (#2100) + - Module properties are now remapped correctly from their pulseaudio variant + to the PipeWire ones. + - Fix module index in introspect. Use the right index when loaded from our + internal modules. (#2101) + - Improve argument parsing and node.description. (#2086) + - The sink-index should now be filled in correctly when playing a sample. + (#2129) + - module-always-sink is now implemented and loaded by default. (#1838) + - Add support for loading some modules only once. + - Module load and unload now does extra sync to make it appear synchronous, + like in PulseAudio. This improves sounds sharing in Zoom. + +## ALSA + - Fix critial bug where alsa devices would not show when the kernel was + compiled without VERBOSE_PROCFS. + - Some corner cases were fixed in the ALSA timing code. When the capture node + is follower, it will now not try to read too much data and xrun but it will + instead produce a cycle of silence. + - Various fixes and improvements to make ALSA devices resync to the driver + more quickly and accurately. + +## JACK + - Add an option to name the defauld device as `system` to improve + compatibility with some applications, + - Use lock-quantum by default. This makes sure that all dynamic quantum + changes are disabled while a JACK app is running. The only way to force + a quantum chance is through a JACK app or with the metadata. + - It is now possible to do IPC calls from the data thread. Note that this + is a very bad idea but required for compatibility with JACK2. + +## GStreamer + - GStreamer sink will now set a default channelmap to make it possible to + remap to the channel layout of the device. + # PipeWire 0.3.45 (2022-02-03) This is a bugfix release that is API and ABI compatible with previous @@ -62,9 +169,6 @@ switch quantum and ensure it can't change for the lifetime of the JACK app. (#2079) -Older versions: - - # PipeWire 0.3.44 (2022-01-27) This is a bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.45.tar.gz/doc/pipewire-daemon.dox -> pipewire-0.3.47.tar.gz/doc/pipewire-daemon.dox
Changed
@@ -62,8 +62,18 @@ - `$sysconfdir/pipewire/pipewire.conf` (usually `/etc/pipewire/pipewire.conf`) - `$datadir/pipewire/pipewire.conf` (usually `/usr/share/pipewire/pipewire.conf`) -The first configuration file found is loaded, the PipeWire daemon does not -currently combine configuration files. +The first configuration file found is loaded as the base configuration. + +Next, configuration sections are collected in the directories in this +order: + +- `$datadir/pipewire/pipewire.conf.d/` (usually `/usr/share/pipewire/pipewire.conf.d/`) +- `$sysconfdir/pipewire/pipewire.conf.d/` (usually `/etc/pipewire/pipewire.conf.d/`) +- `$XDG_CONFIG_HOME/pipewire/pipewire.conf.d/` (usually `$HOME/.config/pipewire/pipewire.conf.d/`) + +They are applied to the global configuration file. Properties are overwritten +and array elements are appended. This makes it possible to make small custom customizations +or additions to the main configuration file. The environment variables `PIPEWIRE_CONFIG_DIR`, `PIPEWIRE_CONFIG_PREFIX` and `PIPEWIRE_CONFIG_NAME` can be used to specify an alternative config
View file
pipewire-0.3.45.tar.gz/doc/pipewire-modules.dox -> pipewire-0.3.47.tar.gz/doc/pipewire-modules.dox
Changed
@@ -59,6 +59,7 @@ - \subpage page_module_echo_cancel - \subpage page_module_example_sink - \subpage page_module_example_source +- \subpage page_module_fallback_sink - \subpage page_module_filter_chain - \subpage page_module_link_factory - \subpage page_module_loopback
View file
pipewire-0.3.45.tar.gz/man/meson.build -> pipewire-0.3.47.tar.gz/man/meson.build
Changed
@@ -19,7 +19,7 @@ 'pw-profiler.1.rst.in', ] -if not get_option('pipewire-jack').disabled() +if get_option('pipewire-jack').allowed() manpages += 'pw-jack.1.rst.in' endif
View file
pipewire-0.3.45.tar.gz/man/pipewire.conf.5.rst.in -> pipewire-0.3.47.tar.gz/man/pipewire.conf.5.rst.in
Changed
@@ -19,13 +19,19 @@ *@PIPEWIRE_CONFDATADIR@/pipewire.conf* +*@PIPEWIRE_CONFDATADIR@/pipewire.conf.d/* + +*@PIPEWIRE_CONFIG_DIR@/pipewire.conf.d/* + +*$XDG_CONFIG_HOME/pipewire/pipewire.conf.d/* + DESCRIPTION =========== PipeWire is a service that facilitates sharing of multimedia content between devices and applications. -On startup, the daemon reads a configuration file to configure +On startup, the daemon reads a main configuration file to configure itself. It executes a series of commands listed in the config file. @@ -34,6 +40,13 @@ and ``PIPEWIRE_CONFIG_NAME`` can be used to specify an alternative config directory, subdirectory and file respectively. +Next to the configuration file can be a directory with the same name as +the file with a ``.d/`` suffix. All directories in the SYNOPSIS_ directory +search paths are traversed in the listed order and the contents of the +``*.conf`` files inside them are appended to the main configuration file +as overrides. Object sections are merged and array sections are appended. + + CONFIGURATION FILE FORMAT ========================= @@ -51,6 +64,17 @@ name = [ { k = v1 } { k = v2 } ] # an array of dictionaries + +The configuration files can be expressed in full JSON syntax but for ease +of use, a relaxed format may be used where: + + * ``:`` to delimit keys and values can be substuted by ``=`` or a space. + * ``"`` around keys and string can be omited as long as no special characters + are used in the strings. + * ``,`` to separate objects can be replaced with a whitespace character. + * ``#`` can be used to start a comment until the line end + + CONFIGURATION FILE SECTIONS ===========================
View file
pipewire-0.3.45.tar.gz/meson.build -> pipewire-0.3.47.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', ['c' ], - version : '0.3.45', + version : '0.3.47', license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ], meson_version : '>= 0.59.0', default_options : [ 'warning_level=3', @@ -202,8 +202,6 @@ cdata.set_quoted('PIPEWIRE_CONFIG_DIR', pipewire_configdir) cdata.set_quoted('PLUGINDIR', spa_plugindir) cdata.set_quoted('SPADATADIR', spa_datadir) -# FIXME: --with-memory-alignment],[8,N,malloc,pagesize (default is 32)]) option -cdata.set('MEMORY_ALIGNMENT_MALLOC', 1) cdata.set_quoted('PA_ALSA_PATHS_DIR', alsadatadir / 'paths') cdata.set_quoted('PA_ALSA_PROFILE_SETS_DIR', alsadatadir / 'profile-sets') @@ -211,95 +209,38 @@ cdata.set('WORDS_BIGENDIAN', 1) endif -check_headers = [['dlfcn.h','HAVE_DLFCN_H'], - ['inttypes.h', 'HAVE_INTTYPES_H'], - ['memory.h', 'HAVE_MEMORY_H'], - ['poll.h', 'HAVE_POLL_H'], - ['stddef.h', 'HAVE_STDDEF_H'], - ['stdint.h', 'HAVE_STDINT_H'], - ['stdio_ext.h', 'HAVE_STDIO_EXT_H'], - ['strings.h', 'HAVE_STRINGS_H'], - ['string.h', 'HAVE_STRING_H'], +check_headers = [ ['sys/mount.h', 'HAVE_SYS_MOUNT_H'], ['sys/param.h', 'HAVE_SYS_PARAM_H'], - ['sys/poll.h', 'HAVE_SYS_POLL_H'], - ['sys/prctl.h', 'HAVE_SYS_PRCTL_H'], ['sys/random.h', 'HAVE_SYS_RANDOM_H'], - ['sys/socket.h', 'HAVE_SYS_SOCKET_H'], - ['sys/stat.h', 'HAVE_SYS_STAT_H'], - ['sys/times.h', 'HAVE_SYS_TIMES_H'], - ['sys/time.h', 'HAVE_SYS_TIME_H'], - ['sys/types.h', 'HAVE_SYS_TYPES_H'], - ['sys/utsname.h', 'HAVE_SYS_UTSNAME_H'], ['sys/vfs.h', 'HAVE_SYS_VFS_H'], - ['sys/wait.h', 'HAVE_SYS_WAIT_H'], ['pwd.h', 'HAVE_PWD_H'], - ['ucontext.h', 'HAVE_UCONTEXT_H'], - ['unistd.h', 'HAVE_UNISTD_H'], ] foreach h : check_headers - if cc.has_header(h.get(0)) - cdata.set(h.get(1), 1) - endif + cdata.set(h.get(1), cc.has_header(h.get(0))) endforeach -if cc.has_function('poll', prefix : '#include<poll.h>') - cdata.set('HAVE_POLL', 1) -endif -if cc.has_function('pselect', prefix : '#include<sys/select.h>') - cdata.set('HAVE_PSELECT', 1) -endif -cdata.set('HAVE_MMAP', 1) - -if cc.has_function('posix_memalign', prefix : '#include<stdlib.h>') - cdata.set('HAVE_POSIX_MEMALIGN', 1) -endif -if cc.has_function('getpagesize', prefix : '#include<unistd.h>') - cdata.set('HAVE_GETPAGESIZE', 1) -endif -if cc.has_function('gettid', prefix : '#include<unistd.h>', args: [ '-D_GNU_SOURCE' ]) - cdata.set('HAVE_GETTID', 1) -endif -if cc.has_function('clock_gettime', prefix : '#include <time.h>') - cdata.set('HAVE_CLOCK_GETTIME', 1) -endif - -if cc.has_type('ptrdiff_t', prefix : '#include <stddef.h>') - cdata.set('HAVE_PTRDIFF_T', 1) -endif - -if cc.has_header_symbol('string.h', 'strndupa', args : [ '-D_GNU_SOURCE' ]) - cdata.set('HAVE_STRNDUPA', 1) -endif - -if cc.has_function('mkstemp', prefix : '#include <stdlib.h>') - cdata.set('HAVE_MKSTEMP', 1) -endif - -if cc.has_function('memfd_create', prefix : '#include <sys/mman.h>', args : [ '-D_GNU_SOURCE' ]) - cdata.set('HAVE_MEMFD_CREATE', 1) -endif - -if cc.has_function('getrandom', prefix : '#include <stddef.h>\n#include <sys/random.h>', args : [ '-D_GNU_SOURCE' ]) - cdata.set('HAVE_GETRANDOM', 1) -endif +check_functions = [ + ['gettid', '#include <unistd.h>', ['-D_GNU_SOURCE']], + ['memfd_create', '#include <sys/mman.h>', ['-D_GNU_SOURCE']], + ['getrandom', '#include <stddef.h>\n#include <sys/random.h>', ['-D_GNU_SOURCE']], + ['sigabbrev_np', '#include <string.h>', ['-D_GNU_SOURCE']], +] -if cc.has_function('sigabbrev_np', prefix : '#include <string.h>', args : [ '-D_GNU_SOURCE' ]) - cdata.set('HAVE_SIGABBREV_NP', 1) -endif +foreach f : check_functions + cdata.set('HAVE_' + f.get(0).to_upper(), + cc.has_function(f.get(0), prefix: f.get(1), args: f.get(2))) +endforeach -if cc.get_define('SYS_pidfd_open', prefix : '#include <sys/syscall.h>') != '' - cdata.set('HAVE_PIDFD_OPEN', 1) -endif +cdata.set('HAVE_PIDFD_OPEN', + cc.get_define('SYS_pidfd_open', prefix: '#include <sys/syscall.h>') != '') systemd = dependency('systemd', required: get_option('systemd')) systemd_dep = dependency('libsystemd',required: get_option('systemd')) summary({'systemd conf data': systemd.found()}, bool_yn: true) summary({'libsystemd': systemd_dep.found()}, bool_yn: true) -if systemd.found() and systemd_dep.found() - cdata.set('HAVE_SYSTEMD', 1) -endif +cdata.set('HAVE_SYSTEMD', systemd.found() and systemd_dep.found()) configinc = include_directories('.') includes_inc = include_directories('include') @@ -326,9 +267,7 @@ pthread_lib = dependency('threads') dbus_dep = dependency('dbus-1', required : get_option('dbus')) summary({'dbus (Bluetooth, rt, portal, pw-reserve)': dbus_dep.found()}, bool_yn: true, section: 'Misc dependencies') -if dbus_dep.found() - cdata.set('HAVE_DBUS', 1) -endif +cdata.set('HAVE_DBUS', dbus_dep.found()) sdl_dep = dependency('sdl2', required : get_option('sdl2')) summary({'SDL2 (video examples)': sdl_dep.found()}, bool_yn: true, section: 'Misc dependencies') drm_dep = dependency('libdrm', required : false) @@ -342,9 +281,7 @@ ncurses_dep = dependency('ncursesw', required : false) sndfile_dep = dependency('sndfile', version : '>= 1.0.20', required : get_option('sndfile')) summary({'sndfile': sndfile_dep.found()}, bool_yn: true, section: 'pw-cat/pw-play/pw-dump/filter-chain') -if sndfile_dep.found() - cdata.set('HAVE_SNDFILE', 1) -endif +cdata.set('HAVE_SNDFILE', sndfile_dep.found()) pulseaudio_dep = dependency('libpulse', required : get_option('libpulse')) summary({'libpulse': pulseaudio_dep.found()}, bool_yn: true, section: 'Streaming between daemons') avahi_dep = dependency('avahi-client', required : get_option('avahi')) @@ -361,14 +298,10 @@ libusb_dep = dependency('libusb-1.0', required : get_option('libusb')) summary({'libusb (Bluetooth quirks)': libusb_dep.found()}, bool_yn: true, section: 'Backend') -if libusb_dep.found() - cdata.set('HAVE_LIBUSB', 1) -endif +cdata.set('HAVE_LIBUSB', libusb_dep.found()) cap_lib = dependency('libcap', required : false) -if cap_lib.found() - cdata.set('HAVE_LIBCAP', 1) -endif +cdata.set('HAVE_LIBCAP', cap_lib.found()) gst_option = get_option('gstreamer') gst_deps_def = { @@ -403,18 +336,13 @@ gst_dp_found = gst_dep.length() > 0 summary({'gstreamer-device-provider': gst_dp_found}, bool_yn: true, section: 'Backend') -if not get_option('gstreamer-device-provider').disabled() - cdata.set('HAVE_GSTREAMER_DEVICE_PROVIDER', 1) -endif +cdata.set('HAVE_GSTREAMER_DEVICE_PROVIDER', get_option('gstreamer-device-provider').allowed()) webrtc_dep = dependency('webrtc-audio-processing', version : ['>= 0.2', '< 1.0'], required : get_option('echo-cancel-webrtc')) summary({'WebRTC Echo Canceling': webrtc_dep.found()}, bool_yn: true, section: 'Misc dependencies') - -if webrtc_dep.found() - cdata.set('HAVE_WEBRTC', 1) -endif +cdata.set('HAVE_WEBRTC', webrtc_dep.found()) # On FreeBSD, epoll-shim library is required for eventfd() and timerfd() epoll_shim_dep = (build_machine.system() == 'freebsd' @@ -450,35 +378,33 @@ lilv_lib = dependency('lilv-0', required: get_option('lv2')) summary({'lilv (for lv2 plugins)': lilv_lib.found()}, bool_yn: true) -if lilv_lib.found() - cdata.set('HAVE_LILV', 1) -endif +cdata.set('HAVE_LILV', lilv_lib.found()) installed_tests_metadir = pipewire_datadir / 'installed-tests' / pipewire_name installed_tests_execdir = pipewire_libexecdir / 'installed-tests' / pipewire_name -installed_tests_enabled = not get_option('installed_tests').disabled() +installed_tests_enabled = get_option('installed_tests').allowed()
View file
pipewire-0.3.45.tar.gz/pipewire-jack/src/meson.build -> pipewire-0.3.47.tar.gz/pipewire-jack/src/meson.build
Changed
@@ -1,7 +1,6 @@ pipewire_jack_sources = [ 'export.c', 'pipewire-jack.c', - 'match-rules.c', 'ringbuffer.c', 'uuid.c', ]
View file
pipewire-0.3.45.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.47.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -64,15 +64,13 @@ #define JACK_CLIENT_NAME_SIZE 128 #define JACK_PORT_NAME_SIZE 256 -#define JACK_PORT_MAX 4096 #define JACK_PORT_TYPE_SIZE 32 -#define CONNECTION_NUM_FOR_PORT 1024 #define MONITOR_EXT " Monitor" +#define MAX_MIDI_MIX 1024 #define MAX_BUFFER_FRAMES 8192 #define MAX_ALIGN 16 -#define MAX_PORTS 1024 #define MAX_BUFFERS 2 #define MAX_BUFFER_DATAS 1u @@ -380,6 +378,7 @@ } rt; pthread_mutex_t rt_lock; + unsigned int rt_locked:1; unsigned int started:1; unsigned int active:1; @@ -396,6 +395,7 @@ unsigned int filter_name:1; unsigned int freewheeling:1; unsigned int locked_process:1; + unsigned int default_as_system:1; int self_connect_mode; int rt_max; @@ -808,7 +808,9 @@ int res = 0; \ if (c->callback) { \ if (pthread_mutex_trylock(&c->rt_lock) == 0) { \ + c->rt_locked = true; \ res = c->callback(__VA_ARGS__); \ + c->rt_locked = false; \ pthread_mutex_unlock(&c->rt_lock); \ } \ } \ @@ -859,6 +861,8 @@ static int do_sync(struct client *client) { + bool in_data_thread = pw_data_loop_in_thread(client->loop); + if (pw_thread_loop_in_thread(client->context.loop)) { pw_log_warn("sync requested from callback"); return 0; @@ -869,8 +873,14 @@ client->pending_sync = pw_proxy_sync((struct pw_proxy*)client->core, client->pending_sync); while (true) { + if (in_data_thread && client->rt_locked) + pthread_mutex_unlock(&client->rt_lock); + pw_thread_loop_wait(client->context.loop); + if (in_data_thread && client->rt_locked) + pthread_mutex_lock(&client->rt_lock); + if (client->error) return client->last_res; @@ -891,6 +901,7 @@ struct client *client = data; client->node = NULL; spa_hook_remove(&client->proxy_listener); + spa_hook_remove(&client->node_listener); } static void on_node_bound(void *data, uint32_t global_id) @@ -3087,7 +3098,8 @@ } -static int execute_match(void *data, const char *action, const char *val, int len) +static int execute_match(void *data, const char *location, const char *action, + const char *val, size_t len) { struct client *client = data; if (spa_streq(action, "update-props")) @@ -3095,19 +3107,6 @@ return 1; } -static int apply_jack_rules(void *data, const char *location, const char *section, - const char *str, size_t len) -{ - struct client *client = data; - const struct pw_properties *p = - pw_context_get_properties(client->context.context); - - if (p != NULL) - pw_jack_match_rules(str, len, &p->dict, execute_match, client); - - return 0; -} - SPA_EXPORT jack_client_t * jack_client_open (const char *client_name, jack_options_t options, @@ -3171,15 +3170,15 @@ if ((str = getenv("PIPEWIRE_PROPS")) != NULL) pw_properties_update_string(client->props, str, strlen(str)); - - pw_context_conf_section_for_each(client->context.context, "jack.rules", - apply_jack_rules, client); + pw_context_conf_section_match_rules(client->context.context, "jack.rules", + &client->props->dict, execute_match, client); client->show_monitor = pw_properties_get_bool(client->props, "jack.show-monitor", true); client->merge_monitor = pw_properties_get_bool(client->props, "jack.merge-monitor", false); client->short_name = pw_properties_get_bool(client->props, "jack.short-name", false); client->filter_name = pw_properties_get_bool(client->props, "jack.filter-name", false); client->locked_process = pw_properties_get_bool(client->props, "jack.locked-process", true); + client->default_as_system = pw_properties_get_bool(client->props, "jack.default-as-system", false); client->self_connect_mode = SELF_CONNECT_ALLOW; if ((str = pw_properties_get(client->props, "jack.self-connect-mode")) != NULL) { @@ -3221,8 +3220,8 @@ spa_list_init(&client->mix); spa_list_init(&client->free_mix); - pw_map_init(&client->ports[SPA_DIRECTION_INPUT], MAX_PORTS, 32); - pw_map_init(&client->ports[SPA_DIRECTION_OUTPUT], MAX_PORTS, 32); + pw_map_init(&client->ports[SPA_DIRECTION_INPUT], 32, 32); + pw_map_init(&client->ports[SPA_DIRECTION_OUTPUT], 32, 32); spa_list_init(&client->free_ports); pw_thread_loop_start(client->context.loop); @@ -3278,6 +3277,8 @@ pw_properties_set(client->props, PW_KEY_MEDIA_ROLE, "DSP"); if (pw_properties_get(client->props, PW_KEY_NODE_ALWAYS_PROCESS) == NULL) pw_properties_set(client->props, PW_KEY_NODE_ALWAYS_PROCESS, "true"); + if (pw_properties_get(client->props, PW_KEY_NODE_LOCK_QUANTUM) == NULL) + pw_properties_set(client->props, PW_KEY_NODE_LOCK_QUANTUM, "true"); pw_properties_set(client->props, PW_KEY_NODE_TRANSPORT_SYNC, "true"); client->node = pw_core_create_object(client->core, @@ -3295,8 +3296,8 @@ &client->proxy_listener, &node_proxy_events, client); client->info = SPA_NODE_INFO_INIT(); - client->info.max_input_ports = MAX_PORTS; - client->info.max_output_ports = MAX_PORTS; + client->info.max_input_ports = UINT32_MAX; + client->info.max_output_ports = UINT32_MAX; client->info.change_mask = SPA_NODE_CHANGE_MASK_FLAGS | SPA_NODE_CHANGE_MASK_PROPS; client->info.flags = SPA_NODE_FLAG_RT; @@ -3383,11 +3384,14 @@ pw_thread_loop_stop(c->context.loop); - if (c->registry) + if (c->registry) { + spa_hook_remove(&c->registry_listener); pw_proxy_destroy((struct pw_proxy*)c->registry); + } if (c->metadata && c->metadata->proxy) { pw_proxy_destroy((struct pw_proxy*)c->metadata->proxy); } + spa_hook_remove(&c->core_listener); pw_core_disconnect(c->core); pw_context_destroy(c->context.context); @@ -3996,15 +4000,12 @@ int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes) { struct client *c = (struct client *) client; - char latency[128]; spa_return_val_if_fail(c != NULL, -EINVAL); - snprintf(latency, sizeof(latency), "%d/%d", nframes, jack_get_sample_rate(client)); - pw_log_info("%p: buffer-size %s", client, latency); + pw_log_info("%p: buffer-size %u", client, nframes); pw_thread_loop_lock(c->context.loop); - pw_properties_set(c->props, PW_KEY_NODE_LATENCY, latency); pw_properties_setf(c->props, PW_KEY_NODE_FORCE_QUANTUM, "%u", nframes); c->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS; @@ -4334,7 +4335,7 @@ { struct mix *mix; void *ptr = p->emptyptr; - struct spa_pod_sequence *seq[CONNECTION_NUM_FOR_PORT]; + struct spa_pod_sequence *seq[MAX_MIDI_MIX]; uint32_t n_seq = 0; jack_midi_clear_buffer(ptr); @@ -4358,6 +4359,8 @@ continue;
View file
pipewire-0.3.45.tar.gz/po/LINGUAS -> pipewire-0.3.47.tar.gz/po/LINGUAS
Changed
@@ -36,6 +36,7 @@ pl pt_BR pt +ro ru sk sr@latin
View file
pipewire-0.3.45.tar.gz/po/POTFILES.in -> pipewire-0.3.47.tar.gz/po/POTFILES.in
Changed
@@ -2,6 +2,7 @@ src/daemon/pipewire.desktop.in src/modules/module-protocol-pulse/modules/module-tunnel-sink.c src/modules/module-protocol-pulse/modules/module-tunnel-source.c +src/modules/module-fallback-sink.c src/modules/module-pulse-tunnel.c src/modules/module-zeroconf-discover.c src/tools/pw-cat.c
View file
pipewire-0.3.47.tar.gz/po/ro.po
Added
@@ -0,0 +1,679 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the pipewire package. +# +# Sergiu Bivol <sergiu@cip.md>, 2022. +msgid "" +msgstr "" +"Project-Id-Version: pipewire\n" +"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/issues/" +"new\n" +"POT-Creation-Date: 2021-11-17 15:06+0100\n" +"PO-Revision-Date: 2022-02-05 12:06+0000\n" +"Last-Translator: Sergiu Bivol <sergiu@cip.md>\n" +"Language-Team: Romanian\n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 <" +" 20)) ? 1 : 2;\n" +"X-Generator: Lokalize 21.12.2\n" + +#: src/daemon/pipewire.c:45 +#, c-format +msgid "" +"%s [options]\n" +" -h, --help Show this help\n" +" --version Show version\n" +" -c, --config Load config (Default %s)\n" +msgstr "" +"%s [opțiuni]\n" +" -h, --help Arată acest ajutor\n" +" --version Arată versiunea\n" +" -c, --config Încarcă configurare (implicit %s)\n" + +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:185 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:185 +#, c-format +msgid "Tunnel to %s/%s" +msgstr "Tunelează spre %s/%s" + +#: src/modules/module-pulse-tunnel.c:536 +#, c-format +msgid "Tunnel for %s@%s" +msgstr "Tunelează pentru %s@%s" + +#: src/modules/module-zeroconf-discover.c:332 +msgid "Unknown device" +msgstr "Dispozitiv necunoscut" + +#: src/modules/module-zeroconf-discover.c:344 +#, c-format +msgid "%s on %s@%s" +msgstr "%s pe %s@%s" + +#: src/modules/module-zeroconf-discover.c:348 +#, c-format +msgid "%s on %s" +msgstr "%s pe %s" + +#: src/tools/pw-cat.c:1058 +#, c-format +msgid "" +"%s [options] <file>\n" +" -h, --help Show this help\n" +" --version Show version\n" +" -v, --verbose Enable verbose operations\n" +"\n" +msgstr "" +"%s [opțiuni] <fișier>\n" +" -h, --help Arată acest ajutor\n" +" --version Arată versiunea\n" +" -v, --verbose Activează operații verboase\n" +"\n" + +#: src/tools/pw-cat.c:1065 +#, c-format +msgid "" +" -R, --remote Remote daemon name\n" +" --media-type Set media type (default %s)\n" +" --media-category Set media category (default %s)\n" +" --media-role Set media role (default %s)\n" +" --target Set node target (default %s)\n" +" 0 means don't link\n" +" --latency Set node latency (default %s)\n" +" Xunit (unit = s, ms, us, ns)\n" +" or direct samples (256)\n" +" the rate is the one of the source " +"file\n" +" --list-targets List available targets for --target\n" +"\n" +msgstr "" +" -R, --remote Denumirea demonului distant\n" +" --media-type Stabilește tipul mediului (implicit " +"%s)\n" +" --media-category Stabilește categoria mediului" +" (implicit %s)\n" +" --media-role Stabilește rolul mediului (implicit " +"%s)\n" +" --target Stabilește ținta nodului (implicit " +"%s)\n" +" 0 înseamnă „nu lega”\n" +" --latency Stabilește latența nodului (implicit " +"%s)\n" +" Xunit (unitate = s, ms, us, ns)\n" +" sau mostre directe (256)\n" +" rata este cea a fișierului sursă\n" +" --list-targets Enumeră țintele disponibile pentru" +" --target\n" +"\n" + +#: src/tools/pw-cat.c:1083 +#, c-format +msgid "" +" --rate Sample rate (req. for rec) (default " +"%u)\n" +" --channels Number of channels (req. for rec) " +"(default %u)\n" +" --channel-map Channel map\n" +" one of: \"stereo\", " +"\"surround-51\",... or\n" +" comma separated list of channel " +"names: eg. \"FL,FR\"\n" +" --format Sample format %s (req. for rec) " +"(default %s)\n" +" --volume Stream volume 0-1.0 (default %.3f)\n" +" -q --quality Resampler quality (0 - 15) (default " +"%d)\n" +"\n" +msgstr "" +" --rate Rată de eșantionare (nec. pt." +" înregistrare) (implicit %u)\n" +" --channels Număr de canale (nec. pt." +" înregistrare) (implicit %u)\n" +" --channel-map Hartă canale\n" +" una dintre: \"stereo\"," +" \"surround-51\",... sau listă\n" +" separată prin virgulă cu denumiri" +" de canale: de ex. \"FL,FR\"\n" +" --format Format de eșantionare %s (nec. pt." +" înregistrare) (implicit %s)\n" +" --volume Volum flux 0-1.0 (implicit %.3f)\n" +" -q --quality Calitate de re-eșantionare (0 - 15)" +" (implicit %d)\n" +"\n" + +#: src/tools/pw-cat.c:1100 +msgid "" +" -p, --playback Playback mode\n" +" -r, --record Recording mode\n" +" -m, --midi Midi mode\n" +" -d, --dsd DSD mode\n" +"\n" +msgstr "" +" -p, --playback Regim de redare\n" +" -r, --record Regim de înregistrare\n" +" -m, --midi Regim MIDI\n" +" -d, --dsd regim DSD\n" +"\n" + +#: src/tools/pw-cli.c:3018 +#, c-format +msgid "" +"%s [options] [command]\n" +" -h, --help Show this help\n" +" --version Show version\n" +" -d, --daemon Start as daemon (Default false)\n" +" -r, --remote Remote daemon name\n" +"\n" +msgstr "" +"%s [opțiuni] [comandă]\n" +" -h, --help Arată acest ajutor\n" +" --version Arată versiunea\n" +" -d, --daemon Pornește ca demon (implicit fals)\n" +" -r, --remote Denumire demon distant\n" +"\n" + +#: spa/plugins/alsa/acp/acp.c:321 +msgid "Pro Audio" +msgstr "Pro Audio" + +#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648 +#: spa/plugins/bluez5/bluez5-device.c:1145 +msgid "Off" +msgstr "Oprit" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2652 +msgid "Input" +msgstr "Intrare" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2653 +msgid "Docking Station Input" +msgstr "Intrare stație de andocare" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2654 +msgid "Docking Station Microphone" +msgstr "Microfon stație de andocare" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2655 +msgid "Docking Station Line In"
View file
pipewire-0.3.45.tar.gz/po/sv.po -> pipewire-0.3.47.tar.gz/po/sv.po
Changed
@@ -1,9 +1,9 @@ # Swedish translation for pipewire. -# Copyright © 2008-2021 Free Software Foundation, Inc. +# Copyright © 2008-2022 Free Software Foundation, Inc. # This file is distributed under the same license as the pipewire package. # Daniel Nylander <po@danielnylander.se>, 2008, 2012. # Josef Andersson <josef.andersson@fripost.org>, 2014, 2017. -# Anders Jonsson <anders.jonsson@norsjovallen.se>, 2021. +# Anders Jonsson <anders.jonsson@norsjovallen.se>, 2021, 2022. # # Termer: # input/output: ingång/utgång (det handlar om ljud) @@ -19,8 +19,8 @@ "Project-Id-Version: pipewire\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/" "issues\n" -"POT-Creation-Date: 2021-09-21 15:31+0000\n" -"PO-Revision-Date: 2021-09-21 21:51+0200\n" +"POT-Creation-Date: 2022-02-13 15:33+0000\n" +"PO-Revision-Date: 2022-02-14 22:57+0100\n" "Last-Translator: Anders Jonsson <anders.jonsson@norsjovallen.se>\n" "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" "Language: sv\n" @@ -28,7 +28,7 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Poedit 3.0\n" +"X-Generator: Poedit 3.0.1\n" #: src/daemon/pipewire.c:45 #, c-format @@ -51,43 +51,36 @@ msgid "Start the PipeWire Media System" msgstr "Starta mediasystemet PipeWire" -#: src/examples/media-session/alsa-monitor.c:656 -#: spa/plugins/alsa/acp/compat.c:189 -msgid "Built-in Audio" -msgstr "Inbyggt ljud" - -#: src/examples/media-session/alsa-monitor.c:660 -#: spa/plugins/alsa/acp/compat.c:194 -msgid "Modem" -msgstr "Modem" - -#: src/examples/media-session/alsa-monitor.c:669 -#: src/modules/module-zeroconf-discover.c:296 -msgid "Unknown device" -msgstr "Okänd enhet" - -#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:173 -#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:173 +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:188 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:188 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunnel till %s/%s" -#: src/modules/module-pulse-tunnel.c:534 +#: src/modules/module-fallback-sink.c:51 +msgid "Dummy Output" +msgstr "Attrapputgång" + +#: src/modules/module-pulse-tunnel.c:536 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunnel för %s@%s" -#: src/modules/module-zeroconf-discover.c:308 +#: src/modules/module-zeroconf-discover.c:332 +msgid "Unknown device" +msgstr "Okänd enhet" + +#: src/modules/module-zeroconf-discover.c:344 #, c-format msgid "%s on %s@%s" msgstr "%s på %s@%s" -#: src/modules/module-zeroconf-discover.c:312 +#: src/modules/module-zeroconf-discover.c:348 #, c-format msgid "%s on %s" msgstr "%s på %s" -#: src/tools/pw-cat.c:1055 +#: src/tools/pw-cat.c:1075 #, c-format msgid "" "%s [options] <file>\n" @@ -102,7 +95,7 @@ " -v, --verbose Aktivera utförliga operationer\n" "\n" -#: src/tools/pw-cat.c:1062 +#: src/tools/pw-cat.c:1082 #, c-format msgid "" " -R, --remote Remote daemon name\n" @@ -132,7 +125,7 @@ " --list-targets Lista tillgängliga mål för --target\n" "\n" -#: src/tools/pw-cat.c:1080 +#: src/tools/pw-cat.c:1100 #, c-format msgid "" " --rate Sample rate (req. for rec) (default " @@ -167,7 +160,7 @@ "%d)\n" "\n" -#: src/tools/pw-cat.c:1097 +#: src/tools/pw-cat.c:1117 msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n" @@ -181,7 +174,7 @@ " -d, --dsd DSD-läge\n" "\n" -#: src/tools/pw-cli.c:2954 +#: src/tools/pw-cli.c:3050 #, c-format msgid "" "%s [options] [command]\n" @@ -198,12 +191,12 @@ " -r, --remote Fjärrdemonnamn\n" "\n" -#: spa/plugins/alsa/acp/acp.c:310 +#: spa/plugins/alsa/acp/acp.c:321 msgid "Pro Audio" msgstr "Professionellt ljud" -#: spa/plugins/alsa/acp/acp.c:433 spa/plugins/alsa/acp/alsa-mixer.c:4648 -#: spa/plugins/bluez5/bluez5-device.c:1135 +#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648 +#: spa/plugins/bluez5/bluez5-device.c:1159 msgid "Off" msgstr "Av" @@ -230,7 +223,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:2657 #: spa/plugins/alsa/acp/alsa-mixer.c:2741 -#: spa/plugins/bluez5/bluez5-device.c:1292 +#: spa/plugins/bluez5/bluez5-device.c:1328 msgid "Microphone" msgstr "Mikrofon" @@ -296,7 +289,7 @@ msgstr "Ingen basökning" #: spa/plugins/alsa/acp/alsa-mixer.c:2672 -#: spa/plugins/bluez5/bluez5-device.c:1297 +#: spa/plugins/bluez5/bluez5-device.c:1333 msgid "Speaker" msgstr "Högtalare" @@ -411,7 +404,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4484 #: spa/plugins/alsa/acp/alsa-mixer.c:4642 -#: spa/plugins/bluez5/bluez5-device.c:1282 +#: spa/plugins/bluez5/bluez5-device.c:1318 msgid "Headset" msgstr "Headset" @@ -561,13 +554,13 @@ #: spa/plugins/alsa/acp/alsa-util.c:1239 #, c-format msgid "" -"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s" -"%lu ms).\n" +"snd_pcm_delay() returned a value that is exceptionally large: %li byte " +"(%s%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgid_plural "" -"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s" -"%lu ms).\n" +"snd_pcm_delay() returned a value that is exceptionally large: %li bytes " +"(%s%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgstr[0] "" @@ -617,65 +610,73 @@ "Förmodligen är detta ett fel i ALSA-drivrutinen ”%s”. Vänligen rapportera " "problemet till ALSA-utvecklarna." -#: spa/plugins/alsa/acp/channelmap.h:466 +#: spa/plugins/alsa/acp/channelmap.h:464 msgid "(invalid)" msgstr "(ogiltig)" -#: spa/plugins/bluez5/bluez5-device.c:1145 +#: spa/plugins/alsa/acp/compat.c:189 +msgid "Built-in Audio" +msgstr "Inbyggt ljud"
View file
pipewire-0.3.45.tar.gz/spa/include/meson.build -> pipewire-0.3.47.tar.gz/spa/include/meson.build
Changed
@@ -3,6 +3,7 @@ 'control', 'debug', 'graph', + 'interfaces', 'monitor', 'node', 'param',
View file
pipewire-0.3.45.tar.gz/spa/include/spa/debug/buffer.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/buffer.h
Changed
@@ -38,14 +38,11 @@ * \{ */ +#include <spa/debug/log.h> #include <spa/debug/mem.h> #include <spa/debug/types.h> #include <spa/buffer/type-info.h> -#ifndef spa_debug -#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) -#endif - static inline int spa_debug_buffer(int indent, const struct spa_buffer *buffer) { uint32_t i;
View file
pipewire-0.3.45.tar.gz/spa/include/spa/debug/dict.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/dict.h
Changed
@@ -34,12 +34,9 @@ * \{ */ +#include <spa/debug/log.h> #include <spa/utils/dict.h> -#ifndef spa_debug -#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) -#endif - static inline int spa_debug_dict(int indent, const struct spa_dict *dict) { const struct spa_dict_item *item;
View file
pipewire-0.3.45.tar.gz/spa/include/spa/debug/format.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/format.h
Changed
@@ -35,6 +35,7 @@ */ #include <spa/pod/parser.h> +#include <spa/debug/log.h> #include <spa/debug/types.h> #include <spa/param/type-info.h> #include <spa/param/format-utils.h> @@ -45,7 +46,7 @@ { switch (type) { case SPA_TYPE_Bool: - fprintf(stderr, "%s", *(int32_t *) body ? "true" : "false"); + spa_debugn("%s", *(int32_t *) body ? "true" : "false"); break; case SPA_TYPE_Id: { @@ -55,41 +56,41 @@ snprintf(tmp, sizeof(tmp), "%d", *(int32_t*)body); str = tmp; } - fprintf(stderr, "%s", str); + spa_debugn("%s", str); break; } case SPA_TYPE_Int: - fprintf(stderr, "%d", *(int32_t *) body); + spa_debugn("%d", *(int32_t *) body); break; case SPA_TYPE_Long: - fprintf(stderr, "%" PRIi64, *(int64_t *) body); + spa_debugn("%" PRIi64, *(int64_t *) body); break; case SPA_TYPE_Float: - fprintf(stderr, "%f", *(float *) body); + spa_debugn("%f", *(float *) body); break; case SPA_TYPE_Double: - fprintf(stderr, "%g", *(double *) body); + spa_debugn("%g", *(double *) body); break; case SPA_TYPE_String: - fprintf(stderr, "%s", (char *) body); + spa_debugn("%s", (char *) body); break; case SPA_TYPE_Rectangle: { struct spa_rectangle *r = (struct spa_rectangle *)body; - fprintf(stderr, "%" PRIu32 "x%" PRIu32, r->width, r->height); + spa_debugn("%" PRIu32 "x%" PRIu32, r->width, r->height); break; } case SPA_TYPE_Fraction: { struct spa_fraction *f = (struct spa_fraction *)body; - fprintf(stderr, "%" PRIu32 "/%" PRIu32, f->num, f->denom); + spa_debugn("%" PRIu32 "/%" PRIu32, f->num, f->denom); break; } case SPA_TYPE_Bitmap: - fprintf(stderr, "Bitmap"); + spa_debugn("Bitmap"); break; case SPA_TYPE_Bytes: - fprintf(stderr, "Bytes"); + spa_debugn("Bytes"); break; case SPA_TYPE_Array: { @@ -97,17 +98,17 @@ struct spa_pod_array_body *b = (struct spa_pod_array_body *)body; int i = 0; info = info && info->values ? info->values : info; - fprintf(stderr, "< "); + spa_debugn("< "); SPA_POD_ARRAY_BODY_FOREACH(b, size, p) { if (i++ > 0) - fprintf(stderr, ", "); + spa_debugn(", "); spa_debug_format_value(info, b->child.type, p, b->child.size); } - fprintf(stderr, " >"); + spa_debugn(" >"); break; } default: - fprintf(stderr, "INVALID type %d", type); + spa_debugn("INVALID type %d", type); break; } return 0; @@ -133,7 +134,7 @@ media_type = spa_debug_type_find_name(spa_type_media_type, mtype); media_subtype = spa_debug_type_find_name(spa_type_media_subtype, mstype); - fprintf(stderr, "%*s %s/%s\n", indent, "", + spa_debug("%*s %s/%s", indent, "", media_type ? spa_debug_type_short_name(media_type) : "unknown", media_subtype ? spa_debug_type_short_name(media_subtype) : "unknown"); @@ -160,7 +161,7 @@ ti = spa_debug_type_find(info, prop->key); key = ti ? ti->name : NULL; - fprintf(stderr, "%*s %16s : (%s) ", indent, "", + spa_debugn("%*s %16s : (%s) ", indent, "", key ? spa_debug_type_short_name(key) : "unknown", spa_debug_type_short_name(spa_types[type].name)); @@ -185,17 +186,17 @@ break; } - fprintf(stderr, "%s", ssep); + spa_debugn("%s", ssep); for (i = 1; i < n_vals; i++) { vals = SPA_PTROFF(vals, size, void); if (i > 1) - fprintf(stderr, "%s", sep); + spa_debugn("%s", sep); spa_debug_format_value(ti ? ti->values : NULL, type, vals, size); } - fprintf(stderr, "%s", esep); + spa_debugn("%s", esep); } - fprintf(stderr, "\n"); + spa_debugn("\n"); } return 0; }
View file
pipewire-0.3.47.tar.gz/spa/include/spa/debug/log.h
Added
@@ -0,0 +1,53 @@ +/* Simple Plugin API + * + * Copyright © 2022 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_DEBUG_LOG_H +#define SPA_DEBUG_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +/** + * \addtogroup spa_debug + * \{ + */ + +#ifndef spa_debug +#define spa_debug(fmt,...) ({ printf(fmt"\n", ## __VA_ARGS__); }) +#endif +#ifndef spa_debugn +#define spa_debugn(fmt,...) ({ printf(fmt, ## __VA_ARGS__); }) +#endif + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_DEBUG_LOGH */
View file
pipewire-0.3.45.tar.gz/spa/include/spa/debug/mem.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/mem.h
Changed
@@ -29,16 +29,14 @@ extern "C" { #endif +#include <inttypes.h> + /** * \addtogroup spa_debug * \{ */ -#include <spa/utils/dict.h> - -#ifndef spa_debug -#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) -#endif +#include <spa/debug/log.h> static inline int spa_debug_mem(int indent, const void *data, size_t size) {
View file
pipewire-0.3.45.tar.gz/spa/include/spa/debug/node.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/node.h
Changed
@@ -35,12 +35,9 @@ */ #include <spa/node/node.h> +#include <spa/debug/log.h> #include <spa/debug/dict.h> -#ifndef spa_debug -#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) -#endif - static inline int spa_debug_port_info(int indent, const struct spa_port_info *info) { spa_debug("%*s" "struct spa_port_info %p:", indent, "", info);
View file
pipewire-0.3.45.tar.gz/spa/include/spa/debug/pod.h -> pipewire-0.3.47.tar.gz/spa/include/spa/debug/pod.h
Changed
@@ -34,15 +34,12 @@ * \{ */ +#include <spa/debug/log.h> #include <spa/debug/mem.h> #include <spa/debug/types.h> #include <spa/pod/pod.h> #include <spa/pod/iter.h> -#ifndef spa_debug -#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) -#endif - static inline int spa_debug_pod_value(int indent, const struct spa_type_info *info, uint32_t type, void *body, uint32_t size)
View file
pipewire-0.3.47.tar.gz/spa/include/spa/interfaces
Added
+(directory)
View file
pipewire-0.3.47.tar.gz/spa/include/spa/interfaces/audio
Added
+(directory)
View file
pipewire-0.3.47.tar.gz/spa/include/spa/interfaces/audio/aec.h
Added
@@ -0,0 +1,95 @@ +/* PipeWire + * + * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + +#include <spa/utils/dict.h> +#include <spa/utils/hook.h> +#include <spa/param/audio/raw.h> + +#ifndef SPA_AUDIO_AEC_H +#define SPA_AUDIO_AEC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SPA_TYPE_INTERFACE_AUDIO_AEC SPA_TYPE_INFO_INTERFACE_BASE "Audio:AEC" + +#define SPA_VERSION_AUDIO_AEC 0 +struct spa_audio_aec { + struct spa_interface iface; + const char *name; + const struct spa_dict *info; + const char *latency; +}; + +struct spa_audio_aec_info { +#define SPA_AUDIO_AEC_CHANGE_MASK_PROPS (1u<<0) + uint64_t change_mask; + + const struct spa_dict *props; +}; + +struct spa_audio_aec_events { +#define SPA_VERSION_AUDIO_AEC_EVENTS 0 + uint32_t version; /**< version of this structure */ + + /** Emitted when info changes */ + void (*info) (void *data, const struct spa_audio_aec_info *info); +}; + +struct spa_audio_aec_methods { +#define SPA_VERSION_AUDIO_AEC_METHODS 0 + uint32_t version; + + int (*add_listener) (void *object, + struct spa_hook *listener, + const struct spa_audio_aec_events *events, + void *data); + + int (*init) (void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info); + int (*run) (void *data, const float *rec[], const float *play[], float *out[], uint32_t n_samples); + int (*set_props) (void *data, const struct spa_dict *args); +}; + +#define spa_audio_aec_method(o,method,version,...) \ +({ \ + int _res = -ENOTSUP; \ + struct spa_audio_aec *_o = o; \ + spa_interface_call_res(&_o->iface, \ + struct spa_audio_aec_methods, _res, \ + method, version, ##__VA_ARGS__); \ + _res; \ +}) + +#define spa_audio_aec_add_listener(o,...) spa_audio_aec_method(o, add_listener, 0, __VA_ARGS__) +#define spa_audio_aec_init(o,...) spa_audio_aec_method(o, init, 0, __VA_ARGS__) +#define spa_audio_aec_run(o,...) spa_audio_aec_method(o, run, 0, __VA_ARGS__) +#define spa_audio_aec_set_props(o,...) spa_audio_aec_method(o, set_props, 0, __VA_ARGS__) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_AUDIO_AEC_H */
View file
pipewire-0.3.45.tar.gz/spa/include/spa/support/loop.h -> pipewire-0.3.47.tar.gz/spa/include/spa/support/loop.h
Changed
@@ -66,6 +66,8 @@ int fd; uint32_t mask; uint32_t rmask; + /* private data for the loop implementer */ + void *priv; }; typedef int (*spa_invoke_func_t) (struct spa_loop *loop,
View file
pipewire-0.3.45.tar.gz/spa/include/spa/utils/defs.h -> pipewire-0.3.47.tar.gz/spa/include/spa/utils/defs.h
Changed
@@ -228,6 +228,9 @@ #define SPA_RESTRICT #endif +#define SPA_ROUND_DOWN(num,value) ((num) - ((num) % (value))) +#define SPA_ROUND_UP(num,value) ((((num) + (value) - 1) / (value)) * (value)) + #define SPA_ROUND_DOWN_N(num,align) ((num) & ~((align) - 1)) #define SPA_ROUND_UP_N(num,align) SPA_ROUND_DOWN_N((num) + ((align) - 1),align)
View file
pipewire-0.3.45.tar.gz/spa/include/spa/utils/names.h -> pipewire-0.3.47.tar.gz/spa/include/spa/utils/names.h
Changed
@@ -82,6 +82,8 @@ #define SPA_NAME_AUDIO_ADAPT "audio.adapt" /**< combination of a node and an * audio.convert. Does clock slaving */ +#define SPA_NAME_AEC "audio.aec" /**< Echo canceling */ + /** video processing */ #define SPA_NAME_VIDEO_PROCESS_FORMAT "video.process.format" /**< processes raw video from one format * to another */
View file
pipewire-0.3.45.tar.gz/spa/meson.build -> pipewire-0.3.47.tar.gz/spa/meson.build
Changed
@@ -31,7 +31,7 @@ subdir('include') -if not get_option('spa-plugins').disabled() +if get_option('spa-plugins').allowed() udevrulesdir = get_option('udevrulesdir') if udevrulesdir == '' # absolute path, otherwise meson prepends the prefix @@ -74,6 +74,6 @@ subdir('tools') subdir('tests') -if not get_option('examples').disabled() +if get_option('examples').allowed() subdir('examples') endif
View file
pipewire-0.3.47.tar.gz/spa/plugins/aec
Added
+(directory)
View file
pipewire-0.3.47.tar.gz/spa/plugins/aec/aec-null.c
Added
@@ -0,0 +1,179 @@ +/* PipeWire + * + * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <spa/interfaces/audio/aec.h> +#include <spa/support/log.h> +#include <spa/utils/string.h> +#include <spa/utils/names.h> +#include <spa/support/plugin.h> + +struct impl { + struct spa_handle handle; + struct spa_audio_aec aec; + struct spa_log *log; + + struct spa_hook_list hooks_list; + + uint32_t channels; +}; + +static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.aec.null"); +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT &log_topic + +static int null_init(void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info) +{ + struct impl *impl = data; + impl->channels = info->channels; + return 0; +} + +static int null_run(void *data, const float *rec[], const float *play[], float *out[], uint32_t n_samples) +{ + struct impl *impl = data; + uint32_t i; + for (i = 0; i < impl->channels; i++) + memcpy(out[i], rec[i], n_samples * sizeof(float)); + return 0; +} + +static struct spa_audio_aec_methods impl_aec = { + .init = null_init, + .run = null_run, +}; + +static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) +{ + struct impl *impl; + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + impl = (struct impl *) handle; + + if (spa_streq(type, SPA_TYPE_INTERFACE_AUDIO_AEC)) + *interface = &impl->aec; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + spa_return_val_if_fail(handle != NULL, -EINVAL); + + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct impl); +} + +static int +impl_init(const struct spa_handle_factory *factory, + struct spa_handle *handle, + const struct spa_dict *info, + const struct spa_support *support, + uint32_t n_support) +{ + struct impl *impl; + + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(handle != NULL, -EINVAL); + + handle->get_interface = impl_get_interface; + handle->clear = impl_clear; + + impl = (struct impl *) handle; + + impl->aec.iface = SPA_INTERFACE_INIT( + SPA_TYPE_INTERFACE_AUDIO_AEC, + SPA_VERSION_AUDIO_AEC, + &impl_aec, impl); + impl->aec.name = "null"; + impl->aec.info = NULL; + impl->aec.latency = NULL; + + impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + spa_log_topic_init(impl->log, &log_topic); + + spa_hook_list_init(&impl->hooks_list); + + return 0; +} + +static const struct spa_interface_info impl_interfaces[] = { + {SPA_TYPE_INTERFACE_AUDIO_AEC,}, +}; + +static int +impl_enum_interface_info(const struct spa_handle_factory *factory, + const struct spa_interface_info **info, + uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(info != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *info = &impl_interfaces[*index]; + break; + default: + return 0; + } + (*index)++; + return 1; +} + +const struct spa_handle_factory spa_aec_exaudio_factory = { + SPA_VERSION_HANDLE_FACTORY, + SPA_NAME_AEC, + NULL, + impl_get_size, + impl_init, + impl_enum_interface_info, +}; + + +SPA_EXPORT +int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) +{ + spa_return_val_if_fail(factory != NULL, -EINVAL); + spa_return_val_if_fail(index != NULL, -EINVAL); + + switch (*index) { + case 0: + *factory = &spa_aec_exaudio_factory; + break; + default: + return 0; + } + (*index)++; + return 1; +}
View file
pipewire-0.3.47.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Added
@@ -0,0 +1,278 @@ +/* PipeWire + * + * Copyright © 2021 Wim Taymans <wim.taymans@gmail.com> + * © 2021 Arun Raghavan <arun@asymptotic.io> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <memory> +#include <utility> + +#include <spa/interfaces/audio/aec.h> +#include <spa/support/log.h> +#include <spa/utils/string.h> +#include <spa/utils/names.h> +#include <spa/support/plugin.h> + +#include <webrtc/modules/audio_processing/include/audio_processing.h> +#include <webrtc/modules/interface/module_common_types.h> +#include <webrtc/system_wrappers/include/trace.h> + +struct impl_data { + struct spa_handle handle; + struct spa_audio_aec aec; + + struct spa_log *log; + std::unique_ptr<webrtc::AudioProcessing> apm; + spa_audio_info_raw info; + std::unique_ptr<float *[]> play_buffer, rec_buffer, out_buffer; +}; + +static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.eac.webrtc"); +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT &log_topic + +static bool webrtc_get_spa_bool(const struct spa_dict *args, const char *key, bool default_value) { + const char *str_val; + bool value = default_value; + str_val = spa_dict_lookup(args, key); + if (str_val != NULL) + value =spa_atob(str_val); + + return value; +} + +static int webrtc_init(void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info) +{ + auto impl = reinterpret_cast<struct impl_data*>(data); + + bool extended_filter = webrtc_get_spa_bool(args, "webrtc.extended_filter", true); + bool delay_agnostic = webrtc_get_spa_bool(args, "webrtc.delay_agnostic", true); + bool high_pass_filter = webrtc_get_spa_bool(args, "webrtc.high_pass_filter", true); + bool noise_suppression = webrtc_get_spa_bool(args, "webrtc.noise_suppression", true); + bool voice_detection = webrtc_get_spa_bool(args, "webrtc.voice_detection", true); + + // Note: AGC seems to mess up with Agnostic Delay Detection, especially with speech, + // result in very poor performance, disable by default + bool gain_control = webrtc_get_spa_bool(args, "webrtc.gain_control", false); + + // Disable experimental flags by default + bool experimental_agc = webrtc_get_spa_bool(args, "webrtc.experimental_agc", false); + bool experimental_ns = webrtc_get_spa_bool(args, "webrtc.experimental_ns", false); + + // FIXME: Intelligibility enhancer is not currently supported + // This filter will modify playback buffer (when calling ProcessReverseStream), but now + // playback buffer modifications are discarded. + + webrtc::Config config; + config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(extended_filter)); + config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(delay_agnostic)); + config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(experimental_agc)); + config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns)); + + webrtc::ProcessingConfig pconfig = {{ + webrtc::StreamConfig(info->rate, info->channels, false), /* input stream */ + webrtc::StreamConfig(info->rate, info->channels, false), /* output stream */ + webrtc::StreamConfig(info->rate, info->channels, false), /* reverse input stream */ + webrtc::StreamConfig(info->rate, info->channels, false), /* reverse output stream */ + }}; + + auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config)); + if (apm->Initialize(pconfig) != webrtc::AudioProcessing::kNoError) { + spa_log_error(impl->log, "Error initialising webrtc audio processing module"); + return -1; + } + + apm->high_pass_filter()->Enable(high_pass_filter); + // Always disable drift compensation since it requires drift sampling + apm->echo_cancellation()->enable_drift_compensation(false); + apm->echo_cancellation()->Enable(true); + // TODO: wire up supression levels to args + apm->echo_cancellation()->set_suppression_level(webrtc::EchoCancellation::kHighSuppression); + apm->noise_suppression()->set_level(webrtc::NoiseSuppression::kHigh); + apm->noise_suppression()->Enable(noise_suppression); + apm->voice_detection()->Enable(voice_detection); + // TODO: wire up AGC parameters to args + apm->gain_control()->set_analog_level_limits(0, 255); + apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital); + apm->gain_control()->Enable(gain_control); + impl->apm = std::move(apm); + impl->info = *info; + impl->play_buffer = std::make_unique<float *[]>(info->channels); + impl->rec_buffer = std::make_unique<float *[]>(info->channels); + impl->out_buffer = std::make_unique<float *[]>(info->channels); + return 0; +} + +static int webrtc_run(void *data, const float *rec[], const float *play[], float *out[], uint32_t n_samples) +{ + auto impl = reinterpret_cast<struct impl_data*>(data); + webrtc::StreamConfig config = + webrtc::StreamConfig(impl->info.rate, impl->info.channels, false); + unsigned int num_blocks = n_samples * 1000 / impl->info.rate / 10; + + if (n_samples * 1000 / impl->info.rate % 10 != 0) { + spa_log_error(impl->log, "Buffers must be multiples of 10ms in length (currently %u samples)", n_samples); + return -1; + } + + for (size_t i = 0; i < num_blocks; i ++) { + for (size_t j = 0; j < impl->info.channels; j++) { + impl->play_buffer[j] = const_cast<float *>(play[j]) + config.num_frames() * i; + impl->rec_buffer[j] = const_cast<float *>(rec[j]) + config.num_frames() * i; + impl->out_buffer[j] = out[j] + config.num_frames() * i; + } + /* FIXME: ProcessReverseStream may change the playback buffer, in which + * case we should use that, if we ever expose the intelligibility + * enhancer */ + if (impl->apm->ProcessReverseStream(impl->play_buffer.get(), config, config, impl->play_buffer.get()) != + webrtc::AudioProcessing::kNoError) { + spa_log_error(impl->log, "Processing reverse stream failed"); + } + + // Extra delay introduced by multiple frames + impl->apm->set_stream_delay_ms((num_blocks - 1) * 10); + + if (impl->apm->ProcessStream(impl->rec_buffer.get(), config, config, impl->out_buffer.get()) != + webrtc::AudioProcessing::kNoError) { + spa_log_error(impl->log, "Processing stream failed"); + } + } + + return 0; +} + +static struct spa_audio_aec_methods impl_aec = { + SPA_VERSION_AUDIO_AEC_METHODS, + .add_listener = NULL, + .init = webrtc_init, + .run = webrtc_run, +}; + +static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) +{ + auto impl = reinterpret_cast<struct impl_data*>(handle); + + spa_return_val_if_fail(handle != NULL, -EINVAL); + spa_return_val_if_fail(interface != NULL, -EINVAL); + + if (spa_streq(type, SPA_TYPE_INTERFACE_AUDIO_AEC)) + *interface = &impl->aec; + else + return -ENOENT; + + return 0; +} + +static int impl_clear(struct spa_handle *handle) +{ + spa_return_val_if_fail(handle != NULL, -EINVAL); + auto impl = reinterpret_cast<struct impl_data*>(handle); + impl->~impl_data(); + return 0; +} + +static size_t +impl_get_size(const struct spa_handle_factory *factory, + const struct spa_dict *params) +{ + return sizeof(struct impl_data); +} +
View file
pipewire-0.3.47.tar.gz/spa/plugins/aec/meson.build
Added
@@ -0,0 +1,16 @@ +aec_null = shared_library('spa-aec-null', + [ 'aec-null.c' ], + include_directories : [ configinc ], + dependencies : [ spa_dep ], + install : true, + install_dir : spa_plugindir / 'aec') + +if webrtc_dep.found() + aec_webrtc = shared_library('spa-aec-webrtc', + [ 'aec-webrtc.cpp' ], + include_directories : [ configinc ], + dependencies : [ spa_dep, webrtc_dep ], + install : true, + install_dir : spa_plugindir / 'aec') +endif +
View file
pipewire-0.3.45.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -1516,8 +1516,10 @@ /* get the current params */ CHECK(snd_pcm_sw_params_current(hndl, params), "sw_params_current"); - CHECK(snd_pcm_sw_params_set_tstamp_mode(hndl, params, SND_PCM_TSTAMP_ENABLE), "sw_params_set_tstamp_mode"); - + CHECK(snd_pcm_sw_params_set_tstamp_mode(hndl, params, SND_PCM_TSTAMP_ENABLE), + "sw_params_set_tstamp_mode"); + CHECK(snd_pcm_sw_params_set_tstamp_type(hndl, params, SND_PCM_TSTAMP_TYPE_MONOTONIC), + "sw_params_set_tstamp_type"); #if 0 snd_pcm_uframes_t boundary; CHECK(snd_pcm_sw_params_get_boundary(params, &boundary), "get_boundary"); @@ -1644,6 +1646,9 @@ case SND_PCM_STATE_SUSPENDED: spa_log_info(state->log, "%s: recover from state %s", state->props.device, snd_pcm_state_name(st)); + res = snd_pcm_resume(state->hndl); + if (res >= 0) + return res; err = -ESTRPIPE; break; default: @@ -1668,10 +1673,10 @@ return do_start(state); } -static int get_status(struct state *state, snd_pcm_uframes_t *delay, snd_pcm_uframes_t *target) +static int get_avail(struct state *state, uint64_t current_time) { - snd_pcm_sframes_t avail; int res; + snd_pcm_sframes_t avail; if (SPA_UNLIKELY((avail = snd_pcm_avail(state->hndl)) < 0)) { if ((res = alsa_recover(state, avail)) < 0) @@ -1684,6 +1689,48 @@ } else { state->alsa_recovering = false; } + return avail; +} + +#if 0 +static int get_avail_htimestamp(struct state *state, uint64_t current_time) +{ + int res; + snd_pcm_uframes_t avail; + snd_htimestamp_t tstamp; + uint64_t then; + + if ((res = snd_pcm_htimestamp(state->hndl, &avail, &tstamp)) < 0) { + if ((res = alsa_recover(state, avail)) < 0) + return res; + if ((res = snd_pcm_htimestamp(state->hndl, &avail, &tstamp)) < 0) { + spa_log_warn(state->log, "%s: snd_pcm_htimestamp error: %s", + state->props.device, snd_strerror(res)); + avail = state->threshold * 2; + } + } else { + state->alsa_recovering = false; + } + + if ((then = SPA_TIMESPEC_TO_NSEC(&tstamp)) != 0) { + if (then < current_time) + avail += (current_time - then) * state->rate / SPA_NSEC_PER_SEC; + else + avail -= (then - current_time) * state->rate / SPA_NSEC_PER_SEC; + } + return SPA_MIN(avail, state->buffer_frames); +} +#endif + +static int get_status(struct state *state, uint64_t current_time, + snd_pcm_uframes_t *delay, snd_pcm_uframes_t *target) +{ + int avail; + + if ((avail = get_avail(state, current_time)) < 0) + return avail; + + avail = SPA_MIN(avail, (int)state->buffer_frames); *target = state->threshold + state->headroom; @@ -1704,7 +1751,7 @@ return 0; } -static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t delay, +static int update_time(struct state *state, uint64_t current_time, snd_pcm_sframes_t delay, snd_pcm_sframes_t target, bool follower) { double err, corr; @@ -1717,8 +1764,8 @@ if (SPA_UNLIKELY(state->dll.bw == 0.0)) { spa_dll_set_bw(&state->dll, SPA_DLL_BW_MAX, state->threshold, state->rate); - state->next_time = nsec; - state->base_time = nsec; + state->next_time = current_time; + state->base_time = current_time; } diff = (int32_t) (state->last_threshold - state->threshold); @@ -1727,9 +1774,20 @@ spa_log_trace(state->log, "%p: follower:%d quantum change %d -> %d (%d) %f", state, follower, state->last_threshold, state->threshold, diff, err); state->last_threshold = state->threshold; + state->alsa_sync = true; } - err = SPA_CLAMP(err, -state->max_error, state->max_error); - corr = spa_dll_update(&state->dll, err); + if (err > state->max_error) { + err = state->max_error; + state->alsa_sync = true; + } else if (err < -state->max_error) { + err = -state->max_error; + state->alsa_sync = true; + } + + if (!follower || state->matching) + corr = spa_dll_update(&state->dll, err); + else + corr = 1.0; if (diff < 0) state->next_time += diff / corr * 1e9 / state->rate; @@ -1737,11 +1795,11 @@ if (SPA_UNLIKELY((state->next_time - state->base_time) > BW_PERIOD)) { state->base_time = state->next_time; - spa_log_debug(state->log, "%p: follower:%d match:%d rate:%f " - "bw:%f thr:%u del:%ld target:%ld err:%f", - state, follower, state->matching, corr, state->dll.bw, - state->threshold, delay, target, - err); + spa_log_debug(state->log, "%s: follower:%d match:%d rate:%f " + "bw:%f thr:%u del:%ld target:%ld err:%f max:%f", + state->props.device, follower, state->matching, + corr, state->dll.bw, state->threshold, delay, target, + err, state->max_error); } if (state->rate_match) { @@ -1756,7 +1814,7 @@ state->next_time += state->threshold / corr * 1e9 / state->rate; if (SPA_LIKELY(!follower && state->clock)) { - state->clock->nsec = nsec; + state->clock->nsec = current_time; state->clock->position += state->duration; state->clock->duration = state->duration; state->clock->delay = delay + state->delay; @@ -1765,7 +1823,7 @@ } spa_log_trace_fp(state->log, "%p: follower:%d %"PRIu64" %f %ld %f %f %u", - state, follower, nsec, corr, delay, err, state->threshold * corr, + state, follower, current_time, corr, delay, err, state->threshold * corr, state->threshold); return 0; @@ -1804,6 +1862,7 @@ state->rate_denom = state->position->clock.rate.denom; state->threshold = (state->duration * state->rate + state->rate_denom-1) / state->rate_denom; state->resample = ((uint32_t)state->rate != state->rate_denom) || state->matching; + state->alsa_sync = true; } } @@ -1811,45 +1870,42 @@ { snd_pcm_t *hndl = state->hndl; const snd_pcm_channel_area_t *my_areas; - snd_pcm_uframes_t written, frames, offset, off, to_write, total_written; + snd_pcm_uframes_t written, frames, offset, off, to_write, total_written, max_write; snd_pcm_sframes_t commitres; int res = 0; check_position_config(state); + max_write = state->buffer_frames; + if (state->following && state->alsa_started) { - uint64_t nsec; + uint64_t current_time; snd_pcm_uframes_t delay, target; - if (SPA_UNLIKELY((res = get_status(state, &delay, &target)) < 0)) + current_time = state->position->clock.nsec; + + if (SPA_UNLIKELY((res = get_status(state, current_time, &delay, &target)) < 0)) return res; - if (SPA_UNLIKELY(!state->alsa_recovering && delay > target + state->threshold)) { + if (SPA_UNLIKELY(state->alsa_sync)) { spa_log_warn(state->log, "%s: follower delay:%ld target:%ld thr:%u, resync", state->props.device, delay, target, state->threshold); - spa_dll_init(&state->dll);
View file
pipewire-0.3.45.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/alsa-pcm.h
Changed
@@ -189,8 +189,6 @@ uint32_t start_delay; uint32_t duration; - uint32_t last_duration; - uint64_t last_position; unsigned int alsa_started:1; unsigned int alsa_sync:1; unsigned int alsa_recovering:1; @@ -210,7 +208,6 @@ int64_t sample_count; int64_t sample_time; - uint64_t current_time; uint64_t next_time; uint64_t base_time;
View file
pipewire-0.3.45.tar.gz/spa/plugins/alsa/alsa-udev.c -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/alsa-udev.c
Changed
@@ -246,6 +246,60 @@ *d = 0; } +static int check_device_pcm_class(const char *devname) +{ + FILE *f; + char path[PATH_MAX]; + char buf[16]; + size_t sz; + + /* Check device class */ + spa_scnprintf(path, sizeof(path), "/sys/class/sound/%s/pcm_class", + devname); + f = fopen(path, "r"); + if (f == NULL) + return -errno; + sz = fread(buf, 1, sizeof(buf) - 1, f); + buf[sz] = '\0'; + fclose(f); + return spa_strstartswith(buf, "modem") ? -ENXIO : 0; +} + +static int get_num_pcm_devices(unsigned int card_id) +{ + char prefix[32]; + DIR *snd = NULL; + struct dirent *entry; + int num_dev = 0; + int res; + + /* Check if card has PCM devices, without opening them */ + + spa_scnprintf(prefix, sizeof(prefix), "pcmC%uD", card_id); + + if ((snd = opendir("/dev/snd")) == NULL) + return -errno; + + while ((errno = 0, entry = readdir(snd)) != NULL) { + if (!(entry->d_type == DT_CHR && + spa_strstartswith(entry->d_name, prefix))) + continue; + + res = check_device_pcm_class(entry->d_name); + if (res != -ENXIO) { + /* count device also if sysfs status file not accessible */ + ++num_dev; + } + } + if (errno != 0) + res = -errno; + else + res = num_dev; + + closedir(snd); + return res; +} + static int check_device_available(struct impl *this, struct device *device, int *num_pcm) { char path[PATH_MAX]; @@ -256,13 +310,27 @@ struct dirent *entry, *entry_pcm; int res; + res = get_num_pcm_devices(device->id); + if (res < 0) { + spa_log_error(this->log, "Error finding PCM devices for ALSA card %u: %s", + (unsigned int)device->id, spa_strerror(res)); + return res; + } + *num_pcm = res; + + spa_log_debug(this->log, "card %u has %d pcm device(s)", (unsigned int)device->id, *num_pcm); + /* * Check if some pcm devices of the card are busy. Check it via /proc, as we * don't want to actually open any devices using alsa-lib (generates uncontrolled * number of inotify events), or replicate its subdevice logic. + * + * The /proc/asound directory might not exist if kernel is compiled with + * CONFIG_SND_PROCFS=n, and the pcmXX directories may be missing if compiled + * with CONFIG_SND_VERBOSE_PROCFS=n. In those cases, the busy check always succeeds. */ - *num_pcm = 0; + res = 0; spa_scnprintf(path, sizeof(path), "/proc/asound/card%u", (unsigned int)device->id); @@ -274,16 +342,9 @@ spa_strstartswith(entry->d_name, "pcm"))) continue; - /* Check device class */ - spa_scnprintf(path, sizeof(path), "/sys/class/sound/pcmC%uD%s/pcm_class", + spa_scnprintf(path, sizeof(path), "pcmC%uD%s", (unsigned int)device->id, entry->d_name+3); - f = fopen(path, "r"); - if (f == NULL) - goto done; - sz = fread(buf, 1, sizeof(buf) - 1, f); - buf[sz] = '\0'; - fclose(f); - if (spa_strstartswith(buf, "modem")) + if (check_device_pcm_class(path) < 0) continue; /* Check busy status */ @@ -310,7 +371,7 @@ if (!spa_strstartswith(buf, "closed")) { spa_log_debug(this->log, "card %u pcm device %s busy", (unsigned int)device->id, entry->d_name); - errno = EBUSY; + res = -EBUSY; goto done; } spa_log_debug(this->log, "card %u pcm device %s free", @@ -319,8 +380,6 @@ if (errno != 0) goto done; - ++*num_pcm; - closedir(pcm); pcm = NULL; } @@ -328,7 +387,10 @@ goto done; done: - res = -errno; + if (errno != 0) { + spa_log_info(this->log, "card %u: failed to find busy status (%s)", + (unsigned int)device->id, spa_strerror(-errno)); + } if (card) closedir(card); if (pcm) @@ -352,15 +414,16 @@ * device->emitted to true. alsalib functions can be used after that. */ + snprintf(path, sizeof(path), "hw:%u", id); + if ((res = check_device_available(this, device, &pcm)) < 0) return res; if (pcm == 0) { spa_log_debug(this->log, "no pcm devices for %s", path); device->ignored = true; - return 0; + return -ENODEV; } - snprintf(path, sizeof(path), "hw:%u", id); spa_log_debug(this->log, "emitting card %s", path); device->emitted = true;
View file
pipewire-0.3.45.tar.gz/spa/plugins/alsa/mixer/profile-sets/texas-instruments-pcm2902.conf -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/mixer/profile-sets/texas-instruments-pcm2902.conf
Changed
@@ -16,12 +16,14 @@ ; Texas Instruments PCM2902 ; ; This is a generic chip used in multiple products, including at least -; Behringer U-Phoria UMC22, Behringer Xenyx 302USB, Intopic Jazz-UB700 and -; some unbranded "usb mini microphone". +; Behringer U-Phoria UMC22, Behringer U-Phoria UM2, Behringer Xenyx 302USB, +; Intopic Jazz-UB700 and some unbranded "usb mini microphone". ; ; Behringer UMC22 has stereo input (representing two physical mono inputs), ; others have mono input. ; +; (Behringer UMC22 and UM2 are "the same device" with different controls) +; ; Some devices have a mic input path, but at least Behringer Xenyx 302USB ; doesn't have any input mixer controls. ;
View file
pipewire-0.3.45.tar.gz/spa/plugins/alsa/test-timer.c -> pipewire-0.3.47.tar.gz/spa/plugins/alsa/test-timer.c
Changed
@@ -45,10 +45,12 @@ unsigned int rate; unsigned int channels; snd_pcm_uframes_t period; + snd_pcm_uframes_t buffer_frames; snd_pcm_t *hndl; int timerfd; + double max_error; float accumulator; uint64_t next_time; @@ -103,15 +105,36 @@ static int on_timer_wakeup(struct state *state) { - snd_pcm_sframes_t avail, delay; + snd_pcm_sframes_t delay; double error, corr; - - /* check the delay in the device */ - CHECK(snd_pcm_avail_delay(state->hndl, &avail, &delay), "delay"); +#if 1 + snd_pcm_sframes_t avail; + CHECK(snd_pcm_avail_delay(state->hndl, &avail, &delay), "delay"); +#else + snd_pcm_uframes_t avail; + snd_htimestamp_t tstamp; + uint64_t then; + + CHECK(snd_pcm_htimestamp(state->hndl, &avail, &tstamp), "htimestamp"); + delay = state->buffer_frames - avail; + + then = TIMESPEC_TO_NSEC(&tstamp); + if (then != 0) { + if (then < state->next_time) { + delay -= (state->next_time - then) * state->rate / NSEC_PER_SEC; + } else { + delay += (then - state->next_time) * state->rate / NSEC_PER_SEC; + } + } +#endif /* calculate the error, we want to have exactly 1 period of * samples remaining in the device when we wakeup. */ error = (double)delay - (double)state->period; + if (error > state->max_error) + error = state->max_error; + else if (error < -state->max_error) + error = -state->max_error; /* update the dll with the error, this gives a rate correction */ corr = spa_dll_update(&state->dll, error); @@ -124,12 +147,6 @@ if (state->next_time - state->prev_time > BW_PERIOD) { state->prev_time = state->next_time; - - /* reduce bandwidth and show some stats */ - if (state->dll.bw > SPA_DLL_BW_MIN) - spa_dll_set_bw(&state->dll, state->dll.bw / 2.0, - state->period, state->rate); - fprintf(stdout, "corr:%f error:%f bw:%f\n", corr, error, state->dll.bw); } @@ -144,6 +161,7 @@ struct state state = { 0, }; const char *device = DEFAULT_DEVICE; snd_pcm_hw_params_t *hparams; + snd_pcm_sw_params_t *sparams; struct timespec now; CHECK(snd_pcm_open(&state.hndl, device, SND_PCM_STREAM_PLAYBACK, 0), "open %s failed", device); @@ -165,12 +183,25 @@ &state.rate, 0), "set rate"); CHECK(snd_pcm_hw_params(state.hndl, hparams), "hw_params"); + CHECK(snd_pcm_hw_params_get_buffer_size(hparams, &state.buffer_frames), "get_buffer_size_max"); + fprintf(stdout, "opened format:%s rate:%u channels:%u\n", snd_pcm_format_name(SND_PCM_FORMAT_S32_LE), state.rate, state.channels); + snd_pcm_sw_params_alloca(&sparams); +#if 0 + CHECK(snd_pcm_sw_params_current(state.hndl, sparams), "sw_params_current"); + CHECK(snd_pcm_sw_params_set_tstamp_mode(state.hndl, sparams, SND_PCM_TSTAMP_ENABLE), + "sw_params_set_tstamp_type"); + CHECK(snd_pcm_sw_params_set_tstamp_type(state.hndl, sparams, SND_PCM_TSTAMP_TYPE_MONOTONIC), + "sw_params_set_tstamp_type"); + CHECK(snd_pcm_sw_params(state.hndl, sparams), "sw_params"); +#endif + spa_dll_init(&state.dll); spa_dll_set_bw(&state.dll, SPA_DLL_BW_MAX, state.period, state.rate); + state.max_error = 256.0; if ((state.timerfd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) perror("timerfd");
View file
pipewire-0.3.45.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.47.tar.gz/spa/plugins/bluez5/backend-native.c
Changed
@@ -594,7 +594,7 @@ /* Check if USB ALT6 is really available on the device */ if (device->adapter->bus_type == BUS_TYPE_USB && !msbc_alt1_ok && msbc_ok) { -#if HAVE_LIBUSB +#ifdef HAVE_LIBUSB if (device->adapter->source_id == SOURCE_ID_USB) { msbc_ok = check_usb_altsetting_6(backend, device->adapter->vendor_id, device->adapter->product_id);
View file
pipewire-0.3.45.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.47.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -425,12 +425,6 @@ } } -static inline void add_dict(struct spa_pod_builder *builder, const char *key, const char *val) -{ - spa_pod_builder_string(builder, key); - spa_pod_builder_string(builder, val); -} - static int a2dp_codec_to_endpoint(const struct a2dp_codec *codec, const char * endpoint, char** object_path)
View file
pipewire-0.3.45.tar.gz/spa/plugins/bluez5/meson.build -> pipewire-0.3.47.tar.gz/spa/plugins/bluez5/meson.build
Changed
@@ -5,24 +5,14 @@ endif endforeach -if not get_option('bluez5-backend-hsp-native').disabled() - cdata.set('HAVE_BLUEZ_5_BACKEND_HSP_NATIVE', 1) - cdata.set('HAVE_BLUEZ_5_BACKEND_NATIVE', 1) -endif -if not get_option('bluez5-backend-hfp-native').disabled() - cdata.set('HAVE_BLUEZ_5_BACKEND_HFP_NATIVE', 1) - cdata.set('HAVE_BLUEZ_5_BACKEND_NATIVE', 1) -endif -if not get_option('bluez5-backend-ofono').disabled() - cdata.set('HAVE_BLUEZ_5_BACKEND_OFONO', 1) -endif -if not get_option('bluez5-backend-hsphfpd').disabled() - cdata.set('HAVE_BLUEZ_5_BACKEND_HSPHFPD', 1) -endif - -if dependency('bluez', version: '< 6', required: false).found() - cdata.set('HAVE_BLUEZ_5_HCI', 1) -endif +cdata.set('HAVE_BLUEZ_5_BACKEND_NATIVE', + get_option('bluez5-backend-hsp-native').allowed() or + get_option('bluez5-backend-hfp-native').allowed()) +cdata.set('HAVE_BLUEZ_5_BACKEND_HSP_NATIVE', get_option('bluez5-backend-hsp-native').allowed()) +cdata.set('HAVE_BLUEZ_5_BACKEND_HFP_NATIVE', get_option('bluez5-backend-hfp-native').allowed()) +cdata.set('HAVE_BLUEZ_5_BACKEND_OFONO', get_option('bluez5-backend-ofono').allowed()) +cdata.set('HAVE_BLUEZ_5_BACKEND_HSPHFPD', get_option('bluez5-backend-hsphfpd').allowed()) +cdata.set('HAVE_BLUEZ_5_HCI', dependency('bluez', version: '< 6', required: false).found()) bluez5_sources = [ 'plugin.c', @@ -44,18 +34,18 @@ install_data(bluez5_data, install_dir : spa_datadir / 'bluez5') -if not get_option('bluez5-backend-hsp-native').disabled() or not get_option('bluez5-backend-hfp-native').disabled() +if get_option('bluez5-backend-hsp-native').allowed() or get_option('bluez5-backend-hfp-native').allowed() if libusb_dep.found() bluez5_deps += libusb_dep endif bluez5_sources += ['backend-native.c'] endif -if not get_option('bluez5-backend-ofono').disabled() +if get_option('bluez5-backend-ofono').allowed() bluez5_sources += ['backend-ofono.c'] endif -if not get_option('bluez5-backend-hsphfpd').disabled() +if get_option('bluez5-backend-hsphfpd').allowed() bluez5_sources += ['backend-hsphfpd.c'] endif
View file
pipewire-0.3.45.tar.gz/spa/plugins/meson.build -> pipewire-0.3.47.tar.gz/spa/plugins/meson.build
Changed
@@ -1,16 +1,16 @@ if alsa_dep.found() subdir('alsa') endif -if not get_option('audioconvert').disabled() +if get_option('audioconvert').allowed() subdir('audioconvert') endif -if not get_option('audiomixer').disabled() +if get_option('audiomixer').allowed() subdir('audiomixer') endif -if not get_option('control').disabled() +if get_option('control').allowed() subdir('control') endif -if not get_option('audiotestsrc').disabled() +if get_option('audiotestsrc').allowed() subdir('audiotestsrc') endif if bluez_dep.found() @@ -22,19 +22,19 @@ if jack_dep.found() subdir('jack') endif -if not get_option('support').disabled() +if get_option('support').allowed() subdir('support') endif -if not get_option('test').disabled() +if get_option('test').allowed() subdir('test') endif -if not get_option('videoconvert').disabled() +if get_option('videoconvert').allowed() subdir('videoconvert') endif -if not get_option('videotestsrc').disabled() +if get_option('videotestsrc').allowed() subdir('videotestsrc') endif -if not get_option('volume').disabled() +if get_option('volume').allowed() subdir('volume') endif if vulkan_headers @@ -51,3 +51,5 @@ if libcamera_dep.found() subdir('libcamera') endif + +subdir('aec') \ No newline at end of file
View file
pipewire-0.3.45.tar.gz/spa/plugins/support/logger.c -> pipewire-0.3.47.tar.gz/spa/plugins/support/logger.c
Changed
@@ -57,6 +57,7 @@ struct spa_log log; FILE *file; + bool close_file; struct spa_system *system; struct spa_source source; @@ -285,6 +286,9 @@ support_log_free_patterns(&this->patterns); + if (this->close_file && this->file != NULL) + fclose(this->file); + if (this->have_source) { spa_loop_remove_source(this->source.loop, &this->source); spa_system_close(this->system, this->source.fd); @@ -356,6 +360,8 @@ this->file = fopen(str, "w"); if (this->file == NULL) fprintf(stderr, "Warning: failed to open file %s: (%m)", str); + else + this->close_file = true; } if ((str = spa_dict_lookup(info, SPA_KEY_LOG_PATTERNS)) != NULL) support_log_parse_patterns(&this->patterns, str);
View file
pipewire-0.3.45.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.47.tar.gz/spa/plugins/support/loop.c
Changed
@@ -48,6 +48,7 @@ #define MAX_ALIGN 8 #define ITEM_ALIGN 8 #define DATAS_SIZE (4096*8) +#define MAX_EP 32 /** \cond */ @@ -74,11 +75,11 @@ struct spa_system *system; struct spa_list source_list; - struct spa_list destroy_list; struct spa_hook_list hooks_list; int poll_fd; pthread_t thread; + int enter_count; struct spa_source *wakeup; int ack_fd; @@ -113,6 +114,7 @@ { struct impl *impl = object; source->loop = &impl->loop; + source->priv = NULL; return spa_system_pollfd_add(impl->system, impl->poll_fd, source->fd, source->mask, source); } @@ -125,6 +127,12 @@ static int loop_remove_source(void *object, struct spa_source *source) { struct impl *impl = object; + struct spa_poll_event *e; + if ((e = source->priv)) { + /* active in an iteration of the loop, remove it from there */ + e->data = NULL; + source->priv = NULL; + } source->loop = NULL; return spa_system_pollfd_del(impl->system, impl->poll_fd, source->fd); } @@ -289,35 +297,43 @@ static void loop_enter(void *object) { struct impl *impl = object; - impl->thread = pthread_self(); + pthread_t thread_id = pthread_self(); + + if (impl->enter_count == 0) { + spa_return_if_fail(impl->thread == 0); + impl->thread = thread_id; + impl->enter_count = 1; + } else { + spa_return_if_fail(impl->enter_count > 0); + spa_return_if_fail(impl->thread == thread_id); + impl->enter_count++; + } spa_log_trace(impl->log, "%p: enter %lu", impl, impl->thread); } static void loop_leave(void *object) { struct impl *impl = object; + pthread_t thread_id = pthread_self(); + + spa_return_if_fail(impl->enter_count > 0); + spa_return_if_fail(impl->thread == thread_id); + spa_log_trace(impl->log, "%p: leave %lu", impl, impl->thread); - impl->thread = 0; -} -static inline void process_destroy(struct impl *impl) -{ - struct source_impl *source, *tmp; - spa_list_for_each_safe(source, tmp, &impl->destroy_list, link) - free(source); - spa_list_init(&impl->destroy_list); + if (--impl->enter_count == 0) + impl->thread = 0; } static int loop_iterate(void *object, int timeout) { struct impl *impl = object; - struct spa_loop *loop = &impl->loop; - struct spa_poll_event ep[32]; + struct spa_poll_event ep[MAX_EP], *e; int i, nfds; spa_loop_control_hook_before(&impl->hooks_list); - nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout); + nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, MAX_EP, timeout); spa_loop_control_hook_after(&impl->hooks_list); @@ -330,15 +346,19 @@ for (i = 0; i < nfds; i++) { struct spa_source *s = ep[i].data; s->rmask = ep[i].events; + /* already active in another iteration of the loop, + * remove it from that iteration */ + if (SPA_UNLIKELY(e = s->priv)) + e->data = NULL; + s->priv = &ep[i]; } for (i = 0; i < nfds; i++) { struct spa_source *s = ep[i].data; - if (SPA_LIKELY(s->rmask && s->fd != -1 && s->loop == loop)) + if (SPA_LIKELY(s && s->rmask)) { + s->priv = NULL; s->func(s); + } } - if (SPA_UNLIKELY(!spa_list_is_empty(&impl->destroy_list))) - process_destroy(impl); - return nfds; } @@ -692,7 +712,7 @@ spa_system_close(impl->impl->system, source->fd); source->fd = -1; } - spa_list_insert(&impl->impl->destroy_list, &impl->link); + free(source); } static const struct spa_loop_methods impl_loop = { @@ -756,11 +776,13 @@ impl = (struct impl *) handle; + if (impl->enter_count != 0) + spa_log_warn(impl->log, "%p: loop is entered %d times", + impl, impl->enter_count); + spa_list_consume(source, &impl->source_list, link) loop_destroy_source(impl, &source->source); - process_destroy(impl); - spa_system_close(impl->system, impl->ack_fd); spa_system_close(impl->system, impl->poll_fd); @@ -822,7 +844,6 @@ impl->poll_fd = res; spa_list_init(&impl->source_list); - spa_list_init(&impl->destroy_list); spa_hook_list_init(&impl->hooks_list); impl->buffer_data = SPA_PTR_ALIGN(impl->buffer_mem, MAX_ALIGN, uint8_t);
View file
pipewire-0.3.45.tar.gz/spa/plugins/support/meson.build -> pipewire-0.3.47.tar.gz/spa/plugins/support/meson.build
Changed
@@ -23,7 +23,7 @@ install_dir : spa_plugindir / 'support') spa_support_dep = declare_dependency(link_with: spa_support_lib) -if not get_option('evl').disabled() +if get_option('evl').allowed() evl_inc = include_directories('/usr/evl/include') evl_lib = cc.find_library('evl', dirs: ['/usr/evl/lib/'],
View file
pipewire-0.3.45.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/client-rt.conf.in
Changed
@@ -2,6 +2,11 @@ # # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes # or in ~/.config/pipewire for local changes. +# +# It is also possible to place a file with an updated section in +# @PIPEWIRE_CONFIG_DIR@/client-rt.conf.d/ for system-wide changes or in +# ~/.config/pipewire/client-rt.conf.d/ for local changes. +# context.properties = { ## Configure properties in the system.
View file
pipewire-0.3.45.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/client.conf.in
Changed
@@ -2,7 +2,11 @@ # # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes # or in ~/.config/pipewire for local changes. - +# +# It is also possible to place a file with an updated section in +# @PIPEWIRE_CONFIG_DIR@/client.conf.d/ for system-wide changes or in +# ~/.config/pipewire/client.conf.d/ for local changes. +# context.properties = { ## Configure properties in the system. #mem.warn-mlock = false
View file
pipewire-0.3.45.tar.gz/src/daemon/jack.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/jack.conf.in
Changed
@@ -2,6 +2,11 @@ # # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes # or in ~/.config/pipewire for local changes. +# +# It is also possible to place a file with an updated section in +# @PIPEWIRE_CONFIG_DIR@/jack.conf.d/ for system-wide changes or in +# ~/.config/pipewire/jack.conf.d/ for local changes. +# context.properties = { ## Configure properties in the system. @@ -60,7 +65,10 @@ # global properties for all jack clients jack.properties = { #node.latency = 1024/48000 - #node.lock-quantum = false + #node.rate = 1/48000 + #node.quantum = 1024/48000 + #node.lock-quantum = true + #node.force-quantum = 0 #jack.show-monitor = true #jack.merge-monitor = false #jack.short-name = false @@ -73,6 +81,7 @@ # ignore-all: Ignore all self connect requests #jack.self-connect-mode = allow #jack.locked-process = true + #jack.default-as-system = false } # client specific properties
View file
pipewire-0.3.45.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/minimal.conf.in
Changed
@@ -2,6 +2,11 @@ # # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes # or in ~/.config/pipewire for local changes. +# +# It is also possible to place a file with an updated section in +# @PIPEWIRE_CONFIG_DIR@/minimal.conf.d/ for system-wide changes or in +# ~/.config/pipewire/minimal.conf.d/ for local changes. +# context.properties = { ## Configure properties in the system.
View file
pipewire-0.3.45.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
@@ -2,6 +2,11 @@ # # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes # or in ~/.config/pipewire for local changes. +# +# It is also possible to place a file with an updated section in +# @PIPEWIRE_CONFIG_DIR@/pipewire-pulse.conf.d/ for system-wide changes or in +# ~/.config/pipewire/pipewire-pulse.conf.d/ for local changes. +# context.properties = { ## Configure properties in the system. @@ -67,6 +72,7 @@ # Extra modules can be loaded here. Setup in default.pa can be moved here context.exec = [ + { path = "pactl" args = "load-module module-always-sink" } #{ path = "pactl" args = "load-module module-switch-on-connect" } #{ path = "/usr/bin/sh" args = "~/.config/pipewire/default.pw" } ]
View file
pipewire-0.3.45.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.47.tar.gz/src/daemon/pipewire.conf.in
Changed
@@ -2,6 +2,11 @@ # # Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes # or in ~/.config/pipewire for local changes. +# +# It is also possible to place a file with an updated section in +# @PIPEWIRE_CONFIG_DIR@/pipewire.conf.d/ for system-wide changes or in +# ~/.config/pipewire/pipewire.conf.d/ for local changes. +# context.properties = { ## Configure properties in the system. @@ -24,7 +29,7 @@ #default.clock.rate = 48000 #default.clock.allowed-rates = [ 48000 ] #default.clock.quantum = 1024 - #default.clock.min-quantum = 32 + default.clock.min-quantum = 16 #default.clock.max-quantum = 2048 #default.clock.quantum-limit = 8192 #default.video.width = 640
View file
pipewire-0.3.45.tar.gz/src/daemon/systemd/meson.build -> pipewire-0.3.47.tar.gz/src/daemon/systemd/meson.build
Changed
@@ -1,6 +1,6 @@ -if not get_option('systemd-system-service').disabled() +if get_option('systemd-system-service').allowed() subdir('system') endif -if not get_option('systemd-user-service').disabled() +if get_option('systemd-user-service').allowed() subdir('user') endif
View file
pipewire-0.3.45.tar.gz/src/gst/gstpipewire.c -> pipewire-0.3.47.tar.gz/src/gst/gstpipewire.c
Changed
@@ -51,7 +51,7 @@ gst_element_register (plugin, "pipewiresink", GST_RANK_NONE, GST_TYPE_PIPEWIRE_SINK); -#if HAVE_GSTREAMER_DEVICE_PROVIDER +#ifdef HAVE_GSTREAMER_DEVICE_PROVIDER if (!gst_device_provider_register (plugin, "pipewiredeviceprovider", GST_RANK_PRIMARY + 1, GST_TYPE_PIPEWIRE_DEVICE_PROVIDER)) return FALSE;
View file
pipewire-0.3.45.tar.gz/src/gst/gstpipewireformat.c -> pipewire-0.3.47.tar.gz/src/gst/gstpipewireformat.c
Changed
@@ -445,6 +445,44 @@ return TRUE; } +static void +set_default_channels (struct spa_pod_builder *b, uint32_t channels) +{ + uint32_t position[SPA_AUDIO_MAX_CHANNELS] = {0}; + gboolean ok = TRUE; + + switch (channels) { + case 8: + position[6] = SPA_AUDIO_CHANNEL_SL; + position[7] = SPA_AUDIO_CHANNEL_SR; + SPA_FALLTHROUGH + case 6: + position[5] = SPA_AUDIO_CHANNEL_LFE; + SPA_FALLTHROUGH + case 5: + position[4] = SPA_AUDIO_CHANNEL_FC; + SPA_FALLTHROUGH + case 4: + position[2] = SPA_AUDIO_CHANNEL_RL; + position[3] = SPA_AUDIO_CHANNEL_RR; + SPA_FALLTHROUGH + case 2: + position[0] = SPA_AUDIO_CHANNEL_FL; + position[1] = SPA_AUDIO_CHANNEL_FR; + break; + case 1: + position[0] = SPA_AUDIO_CHANNEL_MONO; + break; + default: + ok = FALSE; + break; + } + + if (ok) + spa_pod_builder_add (b, SPA_FORMAT_AUDIO_position, + SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id, channels, position), 0); +} + static gboolean handle_audio_fields (ConvertData *d) { @@ -538,8 +576,10 @@ } if (i > 0) { choice = spa_pod_builder_pop(&d->b, &f); - if (i == 1) + if (i == 1) { choice->body.type = SPA_CHOICE_None; + set_default_channels (&d->b, v); + } } } return TRUE;
View file
pipewire-0.3.45.tar.gz/src/gst/meson.build -> pipewire-0.3.47.tar.gz/src/gst/meson.build
Changed
@@ -8,7 +8,7 @@ 'gstpipewiresrc.c', ] -if not get_option('gstreamer-device-provider').disabled() +if get_option('gstreamer-device-provider').allowed() pipewire_gst_sources += [ 'gstpipewiredeviceprovider.c' ] endif
View file
pipewire-0.3.45.tar.gz/src/meson.build -> pipewire-0.3.47.tar.gz/src/meson.build
Changed
@@ -3,10 +3,10 @@ subdir('daemon') subdir('tools') subdir('modules') -if not get_option('examples').disabled() +if get_option('examples').allowed() subdir('examples') endif -if not get_option('tests').disabled() +if get_option('tests').allowed() subdir('tests') endif
View file
pipewire-0.3.45.tar.gz/src/modules/meson.build -> pipewire-0.3.47.tar.gz/src/modules/meson.build
Changed
@@ -10,6 +10,7 @@ 'module-echo-cancel.c', 'module-example-sink.c', 'module-example-source.c', + 'module-fallback-sink.c', 'module-filter-chain.c', 'module-link-factory.c', 'module-loopback.c', @@ -109,22 +110,15 @@ pipewire_module_echo_cancel_sources = [ 'module-echo-cancel.c', - 'module-echo-cancel/aec-null.c', ] -if webrtc_dep.found() - pipewire_module_echo_cancel_sources += [ - 'module-echo-cancel/aec-webrtc.cpp' - ] -endif - pipewire_module_echo_cancel = shared_library('pipewire-module-echo-cancel', pipewire_module_echo_cancel_sources, include_directories : [configinc], install : true, install_dir : modules_install_dir, install_rpath: modules_install_dir, - dependencies : [mathlib, dl_lib, pipewire_dep, webrtc_dep], + dependencies : [mathlib, dl_lib, pipewire_dep], ) pipewire_module_profiler = shared_library('pipewire-module-profiler', @@ -223,7 +217,6 @@ 'module-protocol-pulse/extensions/ext-stream-restore.c', 'module-protocol-pulse/format.c', 'module-protocol-pulse/manager.c', - 'module-protocol-pulse/media-roles.c', 'module-protocol-pulse/message.c', 'module-protocol-pulse/message-handler.c', 'module-protocol-pulse/module.c', @@ -231,6 +224,7 @@ 'module-protocol-pulse/pending-sample.c', 'module-protocol-pulse/pulse-server.c', 'module-protocol-pulse/quirks.c', + 'module-protocol-pulse/remap.c', 'module-protocol-pulse/reply.c', 'module-protocol-pulse/sample.c', 'module-protocol-pulse/sample-play.c', @@ -238,6 +232,7 @@ 'module-protocol-pulse/stream.c', 'module-protocol-pulse/utils.c', 'module-protocol-pulse/volume.c', + 'module-protocol-pulse/modules/module-always-sink.c', 'module-protocol-pulse/modules/module-combine-sink.c', 'module-protocol-pulse/modules/module-echo-cancel.c', 'module-protocol-pulse/modules/module-ladspa-sink.c', @@ -265,7 +260,6 @@ 'module-protocol-pulse/dbus-name.c', ] pipewire_module_protocol_pulse_deps += dbus_dep - cdata.set('HAVE_DBUS', 1) endif if avahi_dep.found() @@ -274,7 +268,7 @@ 'module-zeroconf-discover/avahi-poll.c', ] pipewire_module_protocol_pulse_deps += avahi_dep - cdata.set('HAVE_AVAHI', 1) + cdata.set('HAVE_AVAHI', true) endif pipewire_module_protocol_pulse = shared_library('pipewire-module-protocol-pulse', @@ -499,3 +493,12 @@ ) endif summary({'x11-bell': build_module_x11_bell}, bool_yn: true, section: 'Optional Modules') + +pipewire_module_fallback_sink = shared_library('pipewire-module-fallback-sink', + [ 'module-fallback-sink.c' ], + include_directories : [configinc], + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep], +)
View file
pipewire-0.3.45.tar.gz/src/modules/module-access.c -> pipewire-0.3.47.tar.gz/src/modules/module-access.c
Changed
@@ -32,10 +32,10 @@ #include "config.h" -#if HAVE_SYS_VFS_H +#ifdef HAVE_SYS_VFS_H #include <sys/vfs.h> #endif -#if HAVE_SYS_MOUNT_H +#ifdef HAVE_SYS_MOUNT_H #include <sys/mount.h> #endif
View file
pipewire-0.3.45.tar.gz/src/modules/module-client-node/client-node.c -> pipewire-0.3.47.tar.gz/src/modules/module-client-node/client-node.c
Changed
@@ -47,28 +47,14 @@ /** \cond */ -#define MAX_INPUTS 1024 -#define MAX_OUTPUTS 1024 - #define MAX_BUFFERS 64 #define MAX_METAS 16u #define MAX_DATAS 64u #define MAX_AREAS 2048 -#define MAX_MIX 128 - -#define CHECK_IN_PORT_ID(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_INPUTS) -#define CHECK_OUT_PORT_ID(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_OUTPUTS) -#define CHECK_PORT_ID(this,d,p) (CHECK_IN_PORT_ID(this,d,p) || CHECK_OUT_PORT_ID(this,d,p)) -#define CHECK_FREE_IN_PORT(this,d,p) (CHECK_IN_PORT_ID(this,d,p) && (this)->in_ports[p] == NULL) -#define CHECK_FREE_OUT_PORT(this,d,p) (CHECK_OUT_PORT_ID(this,d,p) && (this)->out_ports[p] == NULL) -#define CHECK_FREE_PORT(this,d,p) (CHECK_FREE_IN_PORT (this,d,p) || CHECK_FREE_OUT_PORT (this,d,p)) -#define CHECK_IN_PORT(this,d,p) (CHECK_IN_PORT_ID(this,d,p) && (this)->in_ports[p]) -#define CHECK_OUT_PORT(this,d,p) (CHECK_OUT_PORT_ID(this,d,p) && (this)->out_ports[p]) -#define CHECK_PORT(this,d,p) (CHECK_IN_PORT (this,d,p) || CHECK_OUT_PORT (this,d,p)) - -#define GET_IN_PORT(this,p) (this->in_ports[p]) -#define GET_OUT_PORT(this,p) (this->out_ports[p]) -#define GET_PORT(this,d,p) (d == SPA_DIRECTION_INPUT ? GET_IN_PORT(this,p) : GET_OUT_PORT(this,p)) + +#define CHECK_FREE_PORT(this,d,p) (p <= pw_map_get_size(&this->ports[d]) && !CHECK_PORT(this,d,p)) +#define CHECK_PORT(this,d,p) (pw_map_lookup(&this->ports[d], p) != NULL) +#define GET_PORT(this,d,p) (pw_map_lookup(&this->ports[d], p)) #define CHECK_PORT_BUFFER(this,b,p) (b < p->n_buffers) @@ -129,10 +115,7 @@ struct spa_source data_source; int writefd; - uint32_t n_inputs; - uint32_t n_outputs; - struct port *in_ports[MAX_INPUTS]; - struct port *out_ports[MAX_OUTPUTS]; + struct pw_map ports[2]; struct port dummy; @@ -213,8 +196,7 @@ mix_id = 0; else mix_id++; - if (mix_id >= MAX_MIX) - return NULL; + len = pw_array_get_len(&p->mix, struct mix); if (mix_id >= len) { size_t need = sizeof(struct mix) * (mix_id + 1 - len); @@ -432,19 +414,19 @@ { struct node *this = object; struct spa_hook_list save; - uint32_t i; + union pw_map_item *item; spa_return_val_if_fail(this != NULL, -EINVAL); spa_hook_list_isolate(&this->hooks, &save, listener, events, data); - for (i = 0; i < MAX_INPUTS; i++) { - if (this->in_ports[i]) - emit_port_info(this, this->in_ports[i]); + pw_array_for_each(item, &this->ports[SPA_DIRECTION_INPUT].items) { + if (item->data) + emit_port_info(this, item->data); } - for (i = 0; i < MAX_OUTPUTS; i++) { - if (this->out_ports[i]) - emit_port_info(this, this->out_ports[i]); + pw_array_for_each(item, &this->ports[SPA_DIRECTION_OUTPUT].items) { + if (item->data) + emit_port_info(this, item->data); } spa_hook_list_join(&this->hooks, &save); @@ -537,18 +519,8 @@ pw_array_clear(&port->mix); pw_array_init(&port->mix, sizeof(struct mix) * 2); - if (port->direction == SPA_DIRECTION_INPUT) { - if (this->in_ports[port->id] == port) { - this->in_ports[port->id] = NULL; - this->n_inputs--; - } - } - else { - if (this->out_ports[port->id] == port) { - this->out_ports[port->id] = NULL; - this->n_outputs--; - } - } + pw_map_insert_at(&this->ports[port->direction], port->id, NULL); + if (!port->removed) spa_node_emit_port_info(&this->hooks, port->direction, port->id, NULL); } @@ -598,9 +570,9 @@ spa_return_val_if_fail(this != NULL, -EINVAL); spa_return_val_if_fail(num != 0, -EINVAL); - spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); port = GET_PORT(this, direction, port_id); + spa_return_val_if_fail(port != NULL, -EINVAL); pw_log_debug("%p: seq:%d port %d.%d id:%u start:%u num:%u n_params:%d", this, seq, direction, port_id, id, start, num, port->n_params); @@ -649,15 +621,15 @@ struct mix *mix; spa_return_val_if_fail(this != NULL, -EINVAL); - if(!CHECK_PORT(this, direction, port_id)) + + port = GET_PORT(this, direction, port_id); + if(port == NULL) return param == NULL ? 0 : -EINVAL; pw_log_debug("%p: port %d.%d set param %s %d", this, direction, port_id, spa_debug_type_find_name(spa_type_param, id), id); - port = GET_PORT(this, direction, port_id); - if (id == SPA_PARAM_Format) { pw_array_for_each(mix, &port->mix) clear_buffers(this, mix); @@ -687,10 +659,9 @@ direction == SPA_DIRECTION_INPUT ? "input" : "output", port_id, mix_id, data, size); - if (!CHECK_PORT(this, direction, port_id)) - return data == NULL ? 0 : -EINVAL; - port = GET_PORT(this, direction, port_id); + if (port == NULL) + return data == NULL ? 0 : -EINVAL; if ((mix = find_mix(port, mix_id)) == NULL || !mix->valid) return -EINVAL; @@ -752,13 +723,13 @@ uint32_t i, j, peer_id; struct pw_client_node_buffer *mb; - if (!CHECK_PORT(this, direction, port_id)) + p = GET_PORT(this, direction, port_id); + if (p == NULL) return n_buffers == 0 ? 0 : -EINVAL; if (n_buffers > MAX_BUFFERS) return -ENOSPC; - p = GET_PORT(this, direction, port_id); spa_log_debug(this->log, "%p: %s port %d.%d use buffers %p %u flags:%08x", this, direction == SPA_DIRECTION_INPUT ? "input" : "output", @@ -920,7 +891,7 @@ struct node *this = object; spa_return_val_if_fail(this != NULL, -EINVAL); - spa_return_val_if_fail(CHECK_OUT_PORT(this, SPA_DIRECTION_OUTPUT, port_id), -EINVAL); + spa_return_val_if_fail(CHECK_PORT(this, SPA_DIRECTION_OUTPUT, port_id), -EINVAL); spa_log_trace_fp(this->log, "reuse buffer %d", buffer_id); @@ -1011,8 +982,6 @@ spa_log_debug(this->log, "%p: got port update change:%08x params:%d", this, change_mask, n_params); - if (!CHECK_PORT_ID(this, direction, port_id)) - return -EINVAL; remove = (change_mask == 0); @@ -1027,6 +996,9 @@ struct port *target; if (port == NULL) { + if (!CHECK_FREE_PORT(this, direction, port_id)) + return -EINVAL; + target = &this->dummy; spa_zero(this->dummy); target->direction = direction; @@ -1076,9 +1048,8 @@ direction == SPA_DIRECTION_INPUT ? "input" : "output", port_id, mix_id, buffers, n_buffers); - spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); - p = GET_PORT(this, direction, port_id); + spa_return_val_if_fail(p != NULL, -EINVAL); if (direction == SPA_DIRECTION_OUTPUT)
View file
pipewire-0.3.45.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.47.tar.gz/src/modules/module-client-node/remote-node.c
Changed
@@ -42,7 +42,6 @@ #include "pipewire/extensions/client-node.h" #define MAX_BUFFERS 64 -#define MAX_MIX 4096 PW_LOG_TOPIC_EXTERN(mod_topic); #define PW_LOG_TOPIC_DEFAULT mod_topic @@ -74,7 +73,6 @@ int rtwritefd; struct pw_memmap *activation; - struct mix mix_pool[MAX_MIX]; struct spa_list mix[2]; struct spa_list free_mix; @@ -241,15 +239,17 @@ if ((mix = find_mix(data, direction, port_id, mix_id))) return mix; - if (spa_list_is_empty(&data->free_mix)) - return NULL; - port = pw_impl_node_find_port(data->node, direction, port_id); if (port == NULL) return NULL; - mix = spa_list_first(&data->free_mix, struct mix, link); - spa_list_remove(&mix->link); + if (spa_list_is_empty(&data->free_mix)) { + if ((mix = calloc(1, sizeof(*mix))) == NULL) + return NULL; + } else { + mix = spa_list_first(&data->free_mix, struct mix, link); + spa_list_remove(&mix->link); + } mix_init(mix, port, mix_id); spa_list_append(&data->mix[direction], &mix->link); @@ -986,21 +986,24 @@ clear_buffers(data, mix); pw_array_clear(&mix->buffers); - spa_list_remove(&mix->mix.link); spa_list_append(&data->free_mix, &mix->link); pw_impl_port_release_mix(mix->port, &mix->mix); } static void clean_node(struct node_data *d) { - struct mix *mix, *tmp; + struct mix *mix; if (d->have_transport) { - spa_list_for_each_safe(mix, tmp, &d->mix[SPA_DIRECTION_INPUT], link) + spa_list_consume(mix, &d->mix[SPA_DIRECTION_INPUT], link) clear_mix(d, mix); - spa_list_for_each_safe(mix, tmp, &d->mix[SPA_DIRECTION_OUTPUT], link) + spa_list_consume(mix, &d->mix[SPA_DIRECTION_OUTPUT], link) clear_mix(d, mix); } + spa_list_consume(mix, &d->free_mix, link) { + spa_list_remove(&mix->link); + free(mix); + } clean_transport(d); } @@ -1121,6 +1124,7 @@ pw_log_debug("%p: removed", data); spa_hook_remove(&data->proxy_client_node_listener); + spa_hook_remove(&data->client_node_listener); if (data->node) { spa_hook_remove(&data->node_listener); @@ -1220,7 +1224,6 @@ struct pw_impl_node *node = object; struct pw_proxy *client_node; struct node_data *data; - int i; user_data_size = SPA_ROUND_UP_N(user_data_size, __alignof__(struct node_data)); @@ -1254,8 +1257,6 @@ spa_list_init(&data->free_mix); spa_list_init(&data->mix[0]); spa_list_init(&data->mix[1]); - for (i = 0; i < MAX_MIX; i++) - spa_list_append(&data->free_mix, &data->mix_pool[i].link); spa_list_init(&data->links);
View file
pipewire-0.3.45.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.47.tar.gz/src/modules/module-echo-cancel.c
Changed
@@ -43,10 +43,14 @@ #include <spa/param/audio/raw.h> #include <spa/param/profiler.h> #include <spa/pod/builder.h> +#include <spa/support/plugin.h> #include <spa/utils/json.h> +#include <spa/utils/names.h> #include <spa/utils/result.h> #include <spa/utils/ringbuffer.h> #include <spa/utils/string.h> +#include <spa/support/plugin-loader.h> +#include <spa/interfaces/audio/aec.h> #include <pipewire/private.h> #include <pipewire/impl.h> @@ -54,8 +58,6 @@ #include <pipewire/extensions/profiler.h> -#include "module-echo-cancel/echo-cancel.h" - /** \page page_module_echo_cancel PipeWire Module: Echo Cancel * * The `echo-cancel` module performs echo cancellation. The module creates @@ -68,8 +70,8 @@ * * - `source.props = {}`: properties to be passed to the source stream * - `sink.props = {}`: properties to be passed to the sink stream - * - `aec.method = <str>`: the echo cancellation method. Currently supported: - * `webrtc`. Leave unset to use the default method (`webrtc`). + * - `library.name = <str>`: the echo cancellation library Currently supported: + * `aec/libspa-aec-exaudio`. Leave unset to use the default method (`aec/libspa-aec-exaudio`). * - `aec.args = <str>`: arguments to pass to the echo cancellation method * * ## General options @@ -94,7 +96,7 @@ * context.modules = [ * { name = libpipewire-module-echo-cancel * args = { - * # aec.method = webrtc + * # library.name = aec/libspa-aec-exaudio * # node.latency = 1024/48000 * source.props = { * node.name = "Echo Cancellation Source" @@ -138,7 +140,7 @@ "[ audio.position=<channel map> ] " "[ buffer.max_size=<max buffer size in ms> ] " "[ buffer.play_delay=<play delay in ms> ] " - "[ aec.method=<aec method> ] " + "[ library.name =<library name> ] " "[ aec.args=<aec arguments> ] " "[ source.props=<properties> ] " "[ sink.props=<properties> ] " }, @@ -185,8 +187,7 @@ uint32_t out_ringsize; struct spa_ringbuffer out_ring; - const struct echo_cancel_info *aec_info; - void *aec; + struct spa_audio_aec *aec; uint32_t aec_blocksize; unsigned int capture_ready:1; @@ -197,6 +198,9 @@ uint32_t max_buffer_size; uint32_t buffer_delay; + + struct spa_handle *spa_handle; + struct spa_plugin_loader *loader; }; static void do_unload_module(void *obj, void *data, int res, uint32_t id) @@ -283,7 +287,7 @@ pw_stream_queue_buffer(impl->playback, pout); /* Now run the canceller */ - echo_cancel_run(impl->aec_info, impl->aec, rec, play_delayed, out, size / sizeof(float)); + spa_audio_aec_run(impl->aec, rec, play_delayed, out, size / sizeof(float)); /* Next, copy over the output to the output ringbuffer */ avail = spa_ringbuffer_get_write_index(&impl->out_ring, &oindex); @@ -647,8 +651,8 @@ pw_properties_set(props, PW_KEY_NODE_LINK_GROUP, str); if ((str = pw_properties_get(impl->source_props, PW_KEY_NODE_LATENCY)) != NULL) pw_properties_set(props, PW_KEY_NODE_LATENCY, str); - else if (impl->aec_info->latency) - pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec_info->latency); + else if (impl->aec->latency) + pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec->latency); impl->capture = pw_stream_new(impl->core, "Echo-Cancel Capture", props); @@ -680,8 +684,8 @@ pw_properties_set(props, PW_KEY_NODE_LINK_GROUP, str); if ((str = pw_properties_get(impl->sink_props, PW_KEY_NODE_LATENCY)) != NULL) pw_properties_set(props, PW_KEY_NODE_LATENCY, str); - else if (impl->aec_info->latency) - pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec_info->latency); + else if (impl->aec->latency) + pw_properties_set(props, PW_KEY_NODE_LATENCY, impl->aec->latency); impl->playback = pw_stream_new(impl->core, "Echo-Cancel Playback", props); @@ -803,8 +807,8 @@ pw_stream_destroy(impl->sink); if (impl->core && impl->do_disconnect) pw_core_disconnect(impl->core); - if (impl->aec) - echo_cancel_destroy(impl->aec_info, impl->aec); + if (impl->spa_handle) + spa_plugin_loader_unload(impl->loader, impl->spa_handle); pw_properties_free(impl->source_props); pw_properties_free(impl->sink_props); @@ -893,7 +897,10 @@ struct impl *impl; uint32_t id = pw_global_get_id(pw_impl_module_get_global(module)); const char *str; - int res; + const char *path; + int res = 0; + struct spa_handle *handle = NULL; + void *iface; PW_LOG_TOPIC_INIT(mod_topic); @@ -967,31 +974,66 @@ if (pw_properties_get(impl->sink_props, PW_KEY_MEDIA_CLASS) == NULL) pw_properties_set(impl->sink_props, PW_KEY_MEDIA_CLASS, "Audio/Sink"); - if ((str = pw_properties_get(props, "aec.method")) == NULL) - str = "webrtc"; + if ((str = pw_properties_get(props, "aec.method")) != NULL) + pw_log_warn("aec.method is not supported anymore use library.name"); -#ifdef HAVE_WEBRTC - if (spa_streq(str, "webrtc")) - impl->aec_info = echo_cancel_webrtc; - else -#endif - impl->aec_info = echo_cancel_null; + /* Use webrtc as default */ + if ((path = pw_properties_get(props, "library.name")) == NULL) + path = "aec/libspa-aec-webrtc"; + + struct spa_dict_item info_items[] = { + { SPA_KEY_LIBRARY_NAME, path }, + }; + struct spa_dict info = SPA_DICT_INIT_ARRAY(info_items); + + impl->loader = spa_support_find(context->support, context->n_support, SPA_TYPE_INTERFACE_PluginLoader); + if (impl->loader == NULL) { + pw_log_error("a plugin loader is needed"); + return -EINVAL; + } + + handle = spa_plugin_loader_load(impl->loader, SPA_NAME_AEC, &info); + if (handle == NULL) { + pw_log_error("AEC codec plugin %s not available library.name %s", SPA_NAME_AEC, path); + return -ENOENT; + } + + if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_AUDIO_AEC, &iface)) < 0) { + pw_log_error("can't get %s interface %d", SPA_TYPE_INTERFACE_AUDIO_AEC, res); + return res; + } + impl->aec = iface; + impl->spa_handle = handle; + if (impl->aec->iface.version != SPA_VERSION_AUDIO_AEC) { + pw_log_error("codec plugin %s has incompatible ABI version (%d != %d)", + SPA_NAME_AEC, impl->aec->iface.version, SPA_VERSION_AUDIO_AEC); + res = -ENOENT; + goto error; + } + + (void)SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_AUDIO_AEC, (struct spa_audio_aec *)impl->aec); + + pw_log_info("Using plugin AEC %s", impl->aec->name); if ((str = pw_properties_get(props, "aec.args")) != NULL) aec_props = pw_properties_new_string(str); else aec_props = pw_properties_new(NULL, NULL); - impl->aec = echo_cancel_create(impl->aec_info, aec_props, &impl->info); + if (spa_audio_aec_init(impl->aec, &aec_props->dict, &impl->info)) { + pw_log_error("codec plugin %s create failed", impl->aec->name); + res = -ENOENT; + goto error; + } pw_properties_free(aec_props); - if (impl->aec_info->latency) { + if (impl->aec->latency) { unsigned int num, denom, req_num, req_denom; unsigned int factor = 0; unsigned int new_num = 0;
View file
pipewire-0.3.47.tar.gz/src/modules/module-fallback-sink.c
Added
@@ -0,0 +1,473 @@ +/* PipeWire + * + * Copyright © 2021 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "config.h" + +#include <spa/utils/result.h> +#include <spa/utils/string.h> +#include <spa/param/audio/raw.h> + +#include <pipewire/impl.h> +#include <pipewire/i18n.h> + +/** \page page_module_fallback_sink PipeWire Module: Fallback Sink + * + * Fallback sink, which appear dynamically when no other sinks are + * present. This is only useful for Pulseaudio compatibility. + */ + +#define NAME "fallback-sink" + +#define DEFAULT_SINK_NAME "auto_null" +#define DEFAULT_SINK_DESCRIPTION _("Dummy Output") + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +#define MODULE_USAGE ("[ sink.name=<str> ] " \ + "[ sink.description=<str> ] ") + +static const struct spa_dict_item module_props[] = { + { PW_KEY_MODULE_AUTHOR, "Pauli Virtanen <pav@iki.fi>" }, + { PW_KEY_MODULE_DESCRIPTION, "Dynamically appearing fallback sink" }, + { PW_KEY_MODULE_USAGE, MODULE_USAGE }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; + +struct bitmap { + uint8_t *data; + size_t size; + size_t items; +}; + +struct impl { + struct pw_context *context; + + struct pw_impl_module *module; + struct spa_hook module_listener; + + struct pw_core *core; + struct pw_registry *registry; + struct pw_proxy *sink; + + struct spa_hook core_listener; + struct spa_hook core_proxy_listener; + struct spa_hook registry_listener; + struct spa_hook sink_listener; + + struct pw_properties *properties; + + struct bitmap sink_ids; + struct bitmap fallback_sink_ids; + + int check_seq; + + unsigned int do_disconnect:1; + unsigned int scheduled:1; +}; + +static int bitmap_add(struct bitmap *map, uint32_t i) +{ + const uint32_t pos = (i >> 3); + const uint8_t mask = 1 << (i & 0x7); + + if (pos >= map->size) { + size_t new_size = map->size + pos + 16; + void *p; + + p = realloc(map->data, new_size); + if (!p) + return -errno; + + memset((uint8_t*)p + map->size, 0, new_size - map->size); + map->data = p; + map->size = new_size; + } + + if (map->data[pos] & mask) + return 1; + + map->data[pos] |= mask; + ++map->items; + + return 0; +} + +static bool bitmap_remove(struct bitmap *map, uint32_t i) +{ + const uint32_t pos = (i >> 3); + const uint8_t mask = 1 << (i & 0x7); + + if (pos >= map->size) + return false; + + if (!(map->data[pos] & mask)) + return false; + + map->data[pos] &= ~mask; + --map->items; + + return true; +} + +static void bitmap_free(struct bitmap *map) +{ + free(map->data); + spa_zero(*map); +} + +static int add_id(struct bitmap *map, uint32_t id) +{ + int res; + + if (id == SPA_ID_INVALID) + return -EINVAL; + + if ((res = bitmap_add(map, id)) < 0) + pw_log_error("%s", spa_strerror(res)); + + return res; +} + +static void reschedule_check(struct impl *impl) +{ + if (!impl->scheduled) + return; + + impl->check_seq = pw_core_sync(impl->core, 0, impl->check_seq); +} + +static void schedule_check(struct impl *impl) +{ + if (impl->scheduled) + return; + + impl->scheduled = true; + impl->check_seq = pw_core_sync(impl->core, 0, impl->check_seq); +} + +static void sink_proxy_removed(void *data) +{ + struct impl *impl = data; + + pw_proxy_destroy(impl->sink); +} + +static void sink_proxy_bound(void *data, uint32_t id) +{ + struct impl *impl = data; + + add_id(&impl->sink_ids, id); + add_id(&impl->fallback_sink_ids, id); + + reschedule_check(impl); + schedule_check(impl); +} + +static void sink_proxy_destroy(void *data) +{ + struct impl *impl = data; +
View file
pipewire-0.3.45.tar.gz/src/modules/module-profiler.c -> pipewire-0.3.47.tar.gz/src/modules/module-profiler.c
Changed
@@ -214,10 +214,17 @@ spa_list_for_each(t, &node->rt.target_list, link) { struct pw_impl_node *n = t->node; struct pw_node_activation *na; + struct spa_fraction latency; if (n == NULL || n == node) continue; + latency = n->latency; + if (n->force_quantum != 0) + latency.num = n->force_quantum; + if (n->force_rate != 0) + latency.denom = n->force_rate; + na = n->rt.activation; spa_pod_builder_prop(&b, SPA_PROFILER_followerBlock, 0); spa_pod_builder_add_struct(&b, @@ -228,7 +235,7 @@ SPA_POD_Long(na->awake_time), SPA_POD_Long(na->finish_time), SPA_POD_Int(na->status), - SPA_POD_Fraction(&n->latency)); + SPA_POD_Fraction(&latency)); } spa_pod_builder_pop(&b, &f[0]);
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-native.c
Changed
@@ -35,7 +35,7 @@ #include <fcntl.h> #include <sys/file.h> #include <ctype.h> -#if HAVE_PWD_H +#ifdef HAVE_PWD_H #include <pwd.h> #endif #if defined(__FreeBSD__)
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-native/local-socket.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-native/local-socket.c
Changed
@@ -35,7 +35,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <sys/file.h> -#if HAVE_PWD_H +#ifdef HAVE_PWD_H #include <pwd.h> #endif
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/client.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/client.c
Changed
@@ -313,7 +313,7 @@ } /* returns true if an event with the (mask, event, index) triplet should be dropped because it is redundant */ -static bool client_prune_subscribe_events(struct client *client, uint32_t mask, uint32_t event, uint32_t index) +static bool client_prune_subscribe_events(struct client *client, uint32_t event, uint32_t index) { struct message *m, *t; @@ -376,7 +376,7 @@ pw_log_debug("client %p: SUBSCRIBE event:%08x index:%u", client, event, index); - if (client_prune_subscribe_events(client, mask, event, index)) + if (client_prune_subscribe_events(client, event, index)) return 0; struct message *reply = message_alloc(client->impl, -1, 0);
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c
Changed
@@ -43,7 +43,6 @@ #include "../extension.h" #include "../format.h" #include "../manager.h" -#include "../media-roles.h" #include "../message.h" #include "../reply.h" #include "../volume.h"
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c
Changed
@@ -42,8 +42,8 @@ #include "../extension.h" #include "../format.h" #include "../manager.h" -#include "../media-roles.h" #include "../message.h" +#include "../remap.h" #include "../reply.h" #include "../volume.h" #include "registry.h"
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/message.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/message.c
Changed
@@ -28,15 +28,14 @@ #include <spa/debug/buffer.h> #include <spa/utils/defs.h> #include <spa/utils/string.h> -#include <pipewire/keys.h> #include <pipewire/log.h> #include "defs.h" #include "format.h" #include "internal.h" #include "log.h" -#include "media-roles.h" #include "message.h" +#include "remap.h" #include "volume.h" #define MAX_SIZE (256*1024) @@ -65,20 +64,6 @@ return v * v * v; } -static const struct str_map key_table[] = { - { PW_KEY_DEVICE_BUS_PATH, "device.bus_path" }, - { PW_KEY_DEVICE_FORM_FACTOR, "device.form_factor" }, - { PW_KEY_DEVICE_ICON_NAME, "device.icon_name" }, - { PW_KEY_DEVICE_INTENDED_ROLES, "device.intended_roles" }, - { PW_KEY_NODE_DESCRIPTION, "device.description" }, - { PW_KEY_MEDIA_ICON_NAME, "media.icon_name" }, - { PW_KEY_APP_ICON_NAME, "application.icon_name" }, - { PW_KEY_APP_PROCESS_MACHINE_ID, "application.process.machine_id" }, - { PW_KEY_APP_PROCESS_SESSION_ID, "application.process.session_id" }, - { PW_KEY_MEDIA_ROLE, "media.role", media_role_map }, - { NULL, NULL }, -}; - static int read_u8(struct message *m, uint8_t *val) { if (m->offset + 1 > m->length) @@ -153,7 +138,7 @@ TAG_INVALID)) < 0) return res; - if (remap && (map = str_map_find(key_table, NULL, key)) != NULL) { + if (remap && (map = str_map_find(props_key_map, NULL, key)) != NULL) { key = map->pw_str; if (map->child != NULL && (map = str_map_find(map->child, NULL, data)) != NULL) @@ -567,7 +552,7 @@ int l; const struct str_map *map; - if (remap && (map = str_map_find(key_table, key, NULL)) != NULL) { + if (remap && (map = str_map_find(props_key_map, key, NULL)) != NULL) { key = map->pa_str; if (map->child != NULL && (map = str_map_find(map->child, val, NULL)) != NULL)
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/module.c
Changed
@@ -25,6 +25,7 @@ #include <stdlib.h> #include <string.h> +#include <ctype.h> #include <spa/utils/defs.h> #include <spa/utils/list.h> @@ -41,6 +42,7 @@ #include "internal.h" #include "log.h" #include "module.h" +#include "remap.h" static void on_module_unload(void *obj, void *data, int res, uint32_t index) { @@ -139,8 +141,11 @@ { char *s = strdup(str), *p = s, *e, f; const char *k, *v; + const struct str_map *map; while (*p) { + while (*p && isspace(*p)) + p++; e = strchr(p, '='); if (e == NULL) break; @@ -168,6 +173,13 @@ if (*e != '\0') p++; *e = '\0'; + + if ((map = str_map_find(props_key_map, NULL, k)) != NULL) { + k = map->pw_str; + if (map->child != NULL && + (map = str_map_find(map->child, NULL, v)) != NULL) + v = map->pw_str; + } pw_properties_set(props, k, v); } free(s); @@ -248,29 +260,30 @@ #include "modules/registry.h" static const struct module_info module_list[] = { - { "module-combine-sink", create_module_combine_sink, }, - { "module-echo-cancel", create_module_echo_cancel, }, - { "module-ladspa-sink", create_module_ladspa_sink, }, - { "module-ladspa-source", create_module_ladspa_source, }, - { "module-loopback", create_module_loopback, }, - { "module-null-sink", create_module_null_sink, }, - { "module-native-protocol-tcp", create_module_native_protocol_tcp, }, - { "module-pipe-source", create_module_pipe_source, }, - { "module-pipe-sink", create_module_pipe_sink, }, - { "module-raop-discover", create_module_raop_discover, }, - { "module-remap-sink", create_module_remap_sink, }, - { "module-remap-source", create_module_remap_source, }, - { "module-simple-protocol-tcp", create_module_simple_protocol_tcp, }, - { "module-switch-on-connect", create_module_switch_on_connect, }, - { "module-tunnel-sink", create_module_tunnel_sink, }, - { "module-tunnel-source", create_module_tunnel_source, }, - { "module-zeroconf-discover", create_module_zeroconf_discover, }, + { "module-always-sink", 1, create_module_always_sink, }, + { "module-combine-sink", 0, create_module_combine_sink, }, + { "module-echo-cancel", 0, create_module_echo_cancel, }, + { "module-ladspa-sink", 0, create_module_ladspa_sink, }, + { "module-ladspa-source", 0, create_module_ladspa_source, }, + { "module-loopback", 0, create_module_loopback, }, + { "module-null-sink", 0, create_module_null_sink, }, + { "module-native-protocol-tcp", 0, create_module_native_protocol_tcp, }, + { "module-pipe-source", 0, create_module_pipe_source, }, + { "module-pipe-sink", 0, create_module_pipe_sink, }, + { "module-raop-discover", 1, create_module_raop_discover, }, + { "module-remap-sink", 0, create_module_remap_sink, }, + { "module-remap-source", 0, create_module_remap_source, }, + { "module-simple-protocol-tcp", 0, create_module_simple_protocol_tcp, }, + { "module-switch-on-connect", 1, create_module_switch_on_connect, }, + { "module-tunnel-sink", 0, create_module_tunnel_sink, }, + { "module-tunnel-source", 0, create_module_tunnel_source, }, + { "module-zeroconf-discover", 1, create_module_zeroconf_discover, }, #ifdef HAVE_AVAHI - { "module-zeroconf-publish", create_module_zeroconf_publish, }, + { "module-zeroconf-publish", 0, create_module_zeroconf_publish, }, #endif - { "module-roc-sink", create_module_roc_sink, }, - { "module-roc-source", create_module_roc_source, }, - { "module-x11-bell", create_module_x11_bell, }, + { "module-roc-sink", 0, create_module_roc_sink, }, + { "module-roc-source", 0, create_module_roc_source, }, + { "module-x11-bell", 0, create_module_x11_bell, }, }; static const struct module_info *find_module_info(const char *name) @@ -285,6 +298,13 @@ return NULL; } +static int find_module_by_name(void *item_data, void *data) +{ + const char *name = data; + const struct module *module = item_data; + return spa_streq(module->name, name) ? 1 : 0; +} + struct module *module_create(struct client *client, const char *name, const char *args) { struct impl *impl = client->impl; @@ -296,6 +316,17 @@ errno = ENOENT; return NULL; } + + if (info->load_once) { + int exists; + exists = pw_map_for_each(&impl->modules, find_module_by_name, + (void *)name); + if (exists) { + errno = EEXIST; + return NULL; + } + } + module = info->create(impl, args); if (module == NULL) return NULL;
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/module.h -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/module.h
Changed
@@ -37,6 +37,7 @@ struct module_info { const char *name; + unsigned int load_once:1; struct module *(*create) (struct impl *impl, const char *args); };
View file
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-always-sink.c
Added
@@ -0,0 +1,136 @@ +/* PipeWire + * + * Copyright © 2022 Wim Taymans <wim.taymans@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <pipewire/pipewire.h> + +#include "../module.h" + +#define NAME "always-sink" + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +struct module_always_sink_data { + struct module *module; + + struct pw_impl_module *mod; + struct spa_hook mod_listener; +}; + +static void module_destroy(void *data) +{ + struct module_always_sink_data *d = data; + spa_hook_remove(&d->mod_listener); + d->mod = NULL; + module_schedule_unload(d->module); +} + +static const struct pw_impl_module_events module_events = { + PW_VERSION_IMPL_MODULE_EVENTS, + .destroy = module_destroy +}; + +static int module_always_sink_load(struct client *client, struct module *module) +{ + struct module_always_sink_data *data = module->user_data; + FILE *f; + char *args; + const char *str; + size_t size; + + f = open_memstream(&args, &size); + fprintf(f, "{"); + if ((str = pw_properties_get(module->props, "sink_name")) != NULL) + fprintf(f, " sink.name = \"%s\"", str); + fprintf(f, " }"); + fclose(f); + + data->mod = pw_context_load_module(module->impl->context, + "libpipewire-module-fallback-sink", + args, NULL); + free(args); + + if (data->mod == NULL) + return -errno; + + pw_impl_module_add_listener(data->mod, + &data->mod_listener, + &module_events, data); + return 0; +} + +static int module_always_sink_unload(struct module *module) +{ + struct module_always_sink_data *d = module->user_data; + + if (d->mod) { + spa_hook_remove(&d->mod_listener); + pw_impl_module_destroy(d->mod); + d->mod = NULL; + } + return 0; +} + +static const struct module_methods module_always_sink_methods = { + VERSION_MODULE_METHODS, + .load = module_always_sink_load, + .unload = module_always_sink_unload, +}; + +static const struct spa_dict_item module_always_sink_info[] = { + { PW_KEY_MODULE_AUTHOR, "Pauli Virtanen <pav@iki.fi>" }, + { PW_KEY_MODULE_DESCRIPTION, "Always keeps at least one sink loaded even if it's a null one" }, + { PW_KEY_MODULE_USAGE, "sink_name=<name of sink>" }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; + +struct module *create_module_always_sink(struct impl *impl, const char *argument) +{ + struct module *module; + struct pw_properties *props = NULL; + int res; + + PW_LOG_TOPIC_INIT(mod_topic); + + props = pw_properties_new_dict(&SPA_DICT_INIT_ARRAY(module_always_sink_info)); + if (props == NULL) { + res = -EINVAL; + goto out; + } + if (argument) + module_args_add_props(props, argument); + + module = module_new(impl, &module_always_sink_methods, sizeof(struct module_always_sink_data)); + if (module == NULL) { + res = -errno; + goto out; + } + module->props = props; + + return module; +out: + pw_properties_free(props); + errno = -res; + return NULL; +}
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c
Changed
@@ -39,6 +39,8 @@ #define MAX_SINKS 64 /* ... good enough for anyone */ +#define TIMEOUT_SINKS_MSEC 2000 + static const struct spa_dict_item module_combine_sink_info[] = { { PW_KEY_MODULE_AUTHOR, "Arun Raghavan <arun@asymptotic.io>" }, { PW_KEY_MODULE_DESCRIPTION, "Combine multiple sinks into a single sink" }, @@ -61,6 +63,7 @@ struct spa_hook stream_listener; struct module_combine_sink_data *data; bool cleanup; + bool started; }; struct module_combine_sink_data { @@ -80,8 +83,14 @@ struct combine_stream streams[MAX_SINKS]; struct spa_source *cleanup; + struct spa_source *sinks_timeout; struct spa_audio_info_raw info; + + unsigned int sinks_pending; + unsigned int source_started:1; + unsigned int load_emitted:1; + unsigned int start_error:1; }; /* Core connection: mainly to unload the module if the connection errors out */ @@ -161,6 +170,24 @@ pw_stream_queue_buffer(data->sink, in); } +static void check_initialized(struct module_combine_sink_data *data) +{ + struct module *module = data->module; + + if (data->load_emitted) + return; + + if (data->start_error) { + pw_log_debug("module load error"); + data->load_emitted = true; + module_emit_loaded(module, -EIO); + } else if (data->sinks_pending == 0 && data->source_started) { + pw_log_debug("module loaded"); + data->load_emitted = true; + module_emit_loaded(module, 0); + } +} + static void on_in_stream_state_changed(void *d, enum pw_stream_state old, enum pw_stream_state state, const char *error) { @@ -168,6 +195,14 @@ struct module *module = data->module; uint32_t i; + if (!data->source_started && state != PW_STREAM_STATE_CONNECTING) { + /* Input stream appears on server */ + data->source_started = true; + if (state < PW_STREAM_STATE_PAUSED) + data->start_error = true; + check_initialized(data); + } + switch (state) { case PW_STREAM_STATE_PAUSED: pw_stream_flush(data->sink, false); @@ -199,6 +234,16 @@ { struct combine_stream *s = data; + if (!s->started && state != PW_STREAM_STATE_CONNECTING) { + /* Output stream appears on server */ + s->started = true; + if (s->data->sinks_pending > 0) + --s->data->sinks_pending; + if (state < PW_STREAM_STATE_PAUSED) + s->data->start_error = true; + check_initialized(s->data); + } + if (state == PW_STREAM_STATE_UNCONNECTED) { s->cleanup = true; pw_loop_signal_event(s->data->module->impl->loop, s->data->cleanup); @@ -270,12 +315,13 @@ pw_properties_set(props, PW_KEY_NODE_DONT_RECONNECT, "true"); pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); pw_properties_set(props, PW_KEY_NODE_PASSIVE, "true"); + pw_properties_setf(props, "pulse.module.id", "%u", data->module->index); cstream->data = data; cstream->stream = pw_stream_new(data->core, NULL, props); if (cstream->stream == NULL) { pw_log_error("Could not create stream"); - return; + goto error; } pw_stream_add_listener(cstream->stream, @@ -295,8 +341,14 @@ PW_STREAM_FLAG_RT_PROCESS, params, n_params)) < 0) { pw_log_error("Could not connect to sink '%s'", sink_name); - return; + goto error; } + + return; + +error: + data->start_error = true; + check_initialized(data); } static const struct pw_manager_events manager_events = { @@ -325,6 +377,17 @@ } } +static void on_sinks_timeout(void *d, uint64_t count) +{ + struct module_combine_sink_data *data = d; + + if (data->load_emitted) + return; + + data->start_error = true; + check_initialized(data); +} + static int module_combine_sink_load(struct client *client, struct module *module) { struct module_combine_sink_data *data = module->user_data; @@ -354,6 +417,7 @@ pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->index); pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->index); pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); + pw_properties_setf(props, "pulse.module.id", "%u", module->index); if ((str = pw_properties_get(module->props, "sink_properties")) != NULL) module_args_add_props(props, str); @@ -379,7 +443,7 @@ return res; data->manager = pw_manager_new(data->core); - if (client->manager == NULL) + if (data->manager == NULL) return -errno; pw_manager_add_listener(data->manager, &data->manager_listener, @@ -387,7 +451,15 @@ data->cleanup = pw_loop_add_event(module->impl->loop, on_cleanup, data); - return 0; + data->sinks_timeout = pw_loop_add_timer(module->impl->loop, on_sinks_timeout, data); + if (data->sinks_timeout) { + struct timespec timeout = {0}, interval = {0}; + timeout.tv_sec = TIMEOUT_SINKS_MSEC / 1000; + timeout.tv_nsec = (TIMEOUT_SINKS_MSEC % 1000) * SPA_NSEC_PER_MSEC; + pw_loop_update_timer(module->impl->loop, data->sinks_timeout, &timeout, &interval, false); + } + + return data->load_emitted ? 0 : SPA_RESULT_RETURN_ASYNC(0); } static int module_combine_sink_unload(struct module *module) @@ -398,6 +470,9 @@ if (d->cleanup != NULL) pw_loop_destroy_source(module->impl->loop, d->cleanup); + if (d->sinks_timeout != NULL) + pw_loop_destroy_source(module->impl->loop, d->sinks_timeout); + /* Note that we explicitly disconnect the hooks to avoid having the * cleanup triggered again in those callbacks */ if (d->sink != NULL) { @@ -440,7 +515,8 @@ const char *str; char *sink_name = NULL, **sink_names = NULL; struct spa_audio_info_raw info = { 0 }; - int i, n, res; + int i, res; + int num_sinks = 0; PW_LOG_TOPIC_INIT(mod_topic); @@ -460,7 +536,7 @@ } if ((str = pw_properties_get(props, "slaves")) != NULL) { - sink_names = pw_split_strv(str, ",", MAX_SINKS, &n); + sink_names = pw_split_strv(str, ",", MAX_SINKS, &num_sinks); pw_properties_set(props, "slaves", NULL); }
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c
Changed
@@ -75,6 +75,8 @@ pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->index); pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->index); + pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); + pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{"); @@ -215,6 +217,14 @@ if (pw_properties_get(capture_props, PW_KEY_DEVICE_CLASS) == NULL) pw_properties_set(capture_props, PW_KEY_DEVICE_CLASS, "filter"); + if ((str = pw_properties_get(capture_props, PW_KEY_NODE_DESCRIPTION)) == NULL) { + str = pw_properties_get(capture_props, PW_KEY_NODE_NAME); + pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, + "%s Sink", str); + } else { + pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str); + } + if ((str = pw_properties_get(props, "master")) != NULL || (str = pw_properties_get(props, "sink_master")) != NULL) { pw_properties_set(playback_props, PW_KEY_NODE_TARGET, str);
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c
Changed
@@ -75,6 +75,8 @@ pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->index); pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->index); + pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); + pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{"); @@ -203,11 +205,11 @@ module_args_add_props(props, argument); if ((str = pw_properties_get(props, "source_name")) != NULL) { - pw_properties_set(capture_props, PW_KEY_NODE_NAME, str); + pw_properties_set(playback_props, PW_KEY_NODE_NAME, str); pw_properties_set(props, "source_name", NULL); } if ((str = pw_properties_get(props, "source_properties")) != NULL) { - module_args_add_props(capture_props, str); + module_args_add_props(playback_props, str); pw_properties_set(props, "source_properties", NULL); } if (pw_properties_get(playback_props, PW_KEY_MEDIA_CLASS) == NULL) @@ -215,17 +217,25 @@ if (pw_properties_get(playback_props, PW_KEY_DEVICE_CLASS) == NULL) pw_properties_set(playback_props, PW_KEY_DEVICE_CLASS, "filter"); + if ((str = pw_properties_get(playback_props, PW_KEY_NODE_DESCRIPTION)) == NULL) { + str = pw_properties_get(playback_props, PW_KEY_NODE_NAME); + pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, + "%s Source", str); + } else { + pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str); + } + if ((str = pw_properties_get(props, "master")) != NULL || (str = pw_properties_get(props, "source_master")) != NULL) { - pw_properties_set(playback_props, PW_KEY_NODE_TARGET, str); + pw_properties_set(capture_props, PW_KEY_NODE_TARGET, str); pw_properties_set(props, "master", NULL); } - if (module_args_to_audioinfo(impl, props, &capture_info) < 0) { + if (module_args_to_audioinfo(impl, props, &playback_info) < 0) { res = -EINVAL; goto out; } - playback_info = capture_info; + capture_info = playback_info; position_to_props(&capture_info, capture_props); position_to_props(&playback_info, playback_props);
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c
Changed
@@ -72,6 +72,8 @@ pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index); pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index); + pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); + pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{");
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c
Changed
@@ -115,6 +115,8 @@ pw_core_add_listener(d->core, &d->core_listener, &core_events, module); + pw_properties_setf(module->props, "pulse.module.id", "%u", module->index); + d->proxy = pw_core_create_object(d->core, "adapter", PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, module->props ? &module->props->dict : NULL, 0);
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c
Changed
@@ -159,6 +159,8 @@ &data->core_listener, &core_events, data); + pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); + data->capture = pw_stream_new(data->core, "pipesink capture", data->capture_props); data->capture_props = NULL;
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c
Changed
@@ -180,6 +180,9 @@ &data->core_listener, &core_events, data); + pw_properties_setf(data->playback_props, "pulse.module.id", + "%u", module->index); + data->playback = pw_stream_new(data->core, "pipesource playback", data->playback_props); data->playback_props = NULL;
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c
Changed
@@ -69,6 +69,8 @@ pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index); pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index); + pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); + pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{");
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c
Changed
@@ -69,6 +69,8 @@ pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index); pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index); + pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); + pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{");
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c
Changed
@@ -67,22 +67,15 @@ { struct module_roc_sink_data *data = module->user_data; FILE *f; - const char *str; char *args; size_t size; + pw_properties_setf(data->sink_props, "pulse.module.id", + "%u", module->index); + f = open_memstream(&args, &size); fprintf(f, "{"); - /* Can't just serialise this dict because the "null" method gets - * interpreted as a JSON null */ - if ((str = pw_properties_get(data->roc_props, "local.ip"))) - fprintf(f, " local.ip = \"%s\"", str); - if ((str = pw_properties_get(data->roc_props, "remote.ip"))) - fprintf(f, " remote.ip = \"%s\"", str); - if ((str = pw_properties_get(data->roc_props, "remote.source.port"))) - fprintf(f, " remote.source.port = \"%s\"", str); - if ((str = pw_properties_get(data->roc_props, "remote.repair.port"))) - fprintf(f, " remote.repair.port = \"%s\"", str); + pw_properties_serialize_dict(f, &data->roc_props->dict, 0); fprintf(f, " } sink.props = {"); pw_properties_serialize_dict(f, &data->sink_props->dict, 0); fprintf(f, " } }");
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c
Changed
@@ -67,24 +67,15 @@ { struct module_roc_source_data *data = module->user_data; FILE *f; - const char *str; char *args; size_t size; + pw_properties_setf(data->source_props, "pulse.module.id", + "%u", module->index); + f = open_memstream(&args, &size); fprintf(f, "{"); - /* Can't just serialise this dict because the "null" method gets - * interpreted as a JSON null */ - if ((str = pw_properties_get(data->roc_props, "local.ip"))) - fprintf(f, " local.ip = \"%s\"", str); - if ((str = pw_properties_get(data->roc_props, "local.source.port"))) - fprintf(f, " local.source.port = \"%s\"", str); - if ((str = pw_properties_get(data->roc_props, "local.repair.port"))) - fprintf(f, " local.repair.port = \"%s\"", str); - if ((str = pw_properties_get(data->roc_props, "sess.latency.msec"))) - fprintf(f, " sess.latency.msec = \"%s\"", str); - if ((str = pw_properties_get(data->roc_props, "resampler.profile"))) - fprintf(f, " resampler.profile = \"%s\"", str); + pw_properties_serialize_dict(f, &data->roc_props->dict, 0); fprintf(f, " } source.props = {"); pw_properties_serialize_dict(f, &data->source_props->dict, 0); fprintf(f, " } }");
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c
Changed
@@ -73,6 +73,9 @@ server = pw_properties_get(module->props, "server"); + pw_properties_setf(data->stream_props, "pulse.module.id", + "%u", module->index); + f = open_memstream(&args, &size); fprintf(f, "{"); pw_properties_serialize_dict(f, &module->props->dict, 0);
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c
Changed
@@ -71,6 +71,9 @@ size_t size; const char *server; + pw_properties_setf(data->stream_props, "pulse.module.id", + "%u", module->index); + server = pw_properties_get(module->props, "server"); f = open_memstream(&args, &size);
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c
Changed
@@ -591,7 +591,7 @@ } data->manager = pw_manager_new(data->core); - if (client->manager == NULL) { + if (data->manager == NULL) { pw_log_error("failed to create pipewire manager: %m"); return -errno; }
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/registry.h -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/modules/registry.h
Changed
@@ -28,6 +28,7 @@ struct impl; +struct module *create_module_always_sink(struct impl *impl, const char *argument); struct module *create_module_combine_sink(struct impl *impl, const char *argument); struct module *create_module_echo_cancel(struct impl *impl, const char *argument); struct module *create_module_ladspa_sink(struct impl *impl, const char *argument);
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/operation.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/operation.c
Changed
@@ -33,7 +33,9 @@ #include "operation.h" #include "reply.h" -int operation_new(struct client *client, uint32_t tag) +int operation_new_cb(struct client *client, uint32_t tag, + void (*callback)(void *data, struct client *client, uint32_t tag), + void *data) { struct operation *o; @@ -42,6 +44,8 @@ o->client = client; o->tag = tag; + o->callback = callback; + o->data = data; spa_list_append(&client->operations, &o->link); pw_manager_sync(client->manager); @@ -51,6 +55,11 @@ return 0; } +int operation_new(struct client *client, uint32_t tag) +{ + return operation_new_cb(client, tag, NULL, NULL); +} + void operation_free(struct operation *o) { spa_list_remove(&o->link); @@ -63,6 +72,9 @@ pw_log_info("[%s]: tag:%u complete", client->name, o->tag); - reply_simple_ack(client, o->tag); + if (o->callback) + o->callback(o->data, client, o->tag); + else + reply_simple_ack(client, o->tag); operation_free(o); }
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/operation.h -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/operation.h
Changed
@@ -35,9 +35,14 @@ struct spa_list link; struct client *client; uint32_t tag; + void (*callback) (void *data, struct client *client, uint32_t tag); + void *data; }; int operation_new(struct client *client, uint32_t tag); +int operation_new_cb(struct client *client, uint32_t tag, + void (*callback) (void *data, struct client *client, uint32_t tag), + void *data); void operation_free(struct operation *o); void operation_complete(struct operation *o);
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
@@ -209,14 +209,14 @@ } static int send_object_event(struct client *client, struct pw_manager_object *o, - uint32_t facility) + uint32_t type) { uint32_t event = 0, mask = 0, res_index = o->index; if (pw_manager_object_is_sink(o)) { client_queue_subscribe_event(client, SUBSCRIPTION_MASK_SINK, - SUBSCRIPTION_EVENT_SINK | facility, + SUBSCRIPTION_EVENT_SINK | type, res_index); } if (pw_manager_object_is_source_or_monitor(o)) { @@ -248,7 +248,7 @@ if (event != SPA_ID_INVALID) client_queue_subscribe_event(client, mask, - event | facility, + event | type, res_index); return 0; } @@ -374,15 +374,14 @@ if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH) attr->maxlength = MAXLENGTH; - attr->maxlength -= attr->maxlength % frame_size; - attr->maxlength = SPA_MAX(attr->maxlength, frame_size); + attr->maxlength = SPA_ROUND_UP(attr->maxlength, frame_size); + + minreq = SPA_MIN(minreq, attr->maxlength); if (attr->tlength == (uint32_t) -1) attr->tlength = frac_to_bytes_round_up(s->default_tlength, &s->ss); - if (attr->tlength > attr->maxlength) - attr->tlength = attr->maxlength; - attr->tlength -= attr->tlength % frame_size; - attr->tlength = SPA_MAX(attr->tlength, frame_size); + attr->tlength = SPA_MIN(attr->tlength, attr->maxlength); + attr->tlength = SPA_ROUND_UP(attr->tlength, frame_size); attr->tlength = SPA_MAX(attr->tlength, minreq); if (attr->minreq == (uint32_t) -1) { @@ -390,13 +389,13 @@ /* With low-latency, tlength/4 gives a decent default in all of traditional, * adjust latency and early request modes. */ uint32_t m = attr->tlength / 4; - m -= m % frame_size; + m = SPA_ROUND_DOWN(m, frame_size); attr->minreq = SPA_MIN(process, m); } attr->minreq = SPA_MAX(attr->minreq, minreq); if (attr->tlength < attr->minreq+frame_size) - attr->tlength = attr->minreq + frame_size; + attr->tlength = SPA_MIN(attr->minreq + frame_size, attr->maxlength); if (s->early_requests) { latency = attr->minreq; @@ -406,7 +405,7 @@ else latency = attr->minreq; - latency -= latency % frame_size; + latency = SPA_ROUND_DOWN(latency, frame_size); if (attr->tlength >= latency) attr->tlength -= latency; @@ -418,20 +417,20 @@ } if (attr->tlength < latency + 2 * attr->minreq) - attr->tlength = latency + 2 * attr->minreq; + attr->tlength = SPA_MIN(latency + 2 * attr->minreq, attr->maxlength); - attr->minreq -= attr->minreq % frame_size; + attr->minreq = SPA_ROUND_DOWN(attr->minreq, frame_size); if (attr->minreq <= 0) { attr->minreq = frame_size; attr->tlength += frame_size*2; } if (attr->tlength <= attr->minreq) - attr->tlength = attr->minreq*2 + frame_size; + attr->tlength = SPA_MIN(attr->minreq*2 + frame_size, attr->maxlength); max_prebuf = attr->tlength + frame_size - attr->minreq; if (attr->prebuf == (uint32_t) -1 || attr->prebuf > max_prebuf) attr->prebuf = max_prebuf; - attr->prebuf -= attr->prebuf % frame_size; + attr->prebuf = SPA_ROUND_DOWN(attr->prebuf, frame_size); attr->fragsize = 0; @@ -947,6 +946,9 @@ pw_log_info("[%s] SUBSCRIBE tag:%u mask:%08x", client->name, tag, mask); + if (mask & ~SUBSCRIPTION_MASK_ALL) + return -EINVAL; + client->subscribed = mask; return reply_simple_ack(client, tag); @@ -2322,11 +2324,11 @@ return o; } -static void sample_play_ready(void *data, uint32_t index) +static void sample_play_ready_reply(void *data, struct client *client, uint32_t tag) { struct pending_sample *ps = data; - struct client *client = ps->client; struct message *reply; + uint32_t index = id_to_index(client->manager, ps->play->id); pw_log_info("[%s] PLAY_SAMPLE tag:%u index:%u", client->name, ps->tag, index); @@ -2340,6 +2342,13 @@ client_queue_message(client, reply); } +static void sample_play_ready(void *data, uint32_t id) +{ + struct pending_sample *ps = data; + struct client *client = ps->client; + operation_new_cb(client, ps->tag, sample_play_ready_reply, ps); +} + static void on_sample_done(void *obj, void *data, int res, uint32_t id) { struct pending_sample *ps = obj; @@ -3556,6 +3565,9 @@ snprintf(monitor_name, size, "%s.monitor", name); if ((str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID)) != NULL) + module_id = id_to_index(manager, (uint32_t)atoi(str)); + if (module_id == SPA_ID_INVALID && + (str = spa_dict_lookup(info->props, "pulse.module.id")) != NULL) module_id = (uint32_t)atoi(str); if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL) card_id = (uint32_t)atoi(str); @@ -3601,7 +3613,7 @@ TAG_STRING, desc, TAG_SAMPLE_SPEC, &dev_info.ss, TAG_CHANNEL_MAP, &dev_info.map, - TAG_U32, id_to_index(manager, module_id), /* module index */ + TAG_U32, module_id, /* module index */ TAG_CVOLUME, &dev_info.volume_info.volume, TAG_BOOLEAN, dev_info.volume_info.mute, TAG_U32, o->index, /* monitor source index */ @@ -3760,6 +3772,9 @@ snprintf(monitor_desc, size, "Monitor of %s", desc); if ((str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID)) != NULL) + module_id = id_to_index(manager, (uint32_t)atoi(str)); + if (module_id == SPA_ID_INVALID && + (str = spa_dict_lookup(info->props, "pulse.module.id")) != NULL) module_id = (uint32_t)atoi(str); if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL) card_id = (uint32_t)atoi(str); @@ -3804,7 +3819,7 @@ TAG_STRING, is_monitor ? monitor_desc : desc, TAG_SAMPLE_SPEC, &dev_info.ss, TAG_CHANNEL_MAP, &dev_info.map, - TAG_U32, id_to_index(manager, module_id), /* module index */ + TAG_U32, module_id, /* module index */ TAG_CVOLUME, &dev_info.volume_info.volume, TAG_BOOLEAN, dev_info.volume_info.mute, TAG_U32, is_monitor ? o->index : SPA_ID_INVALID,/* monitor of sink */ @@ -3908,7 +3923,11 @@ return -ENOENT; if ((str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID)) != NULL) + module_id = id_to_index(manager, (uint32_t)atoi(str)); + if (module_id == SPA_ID_INVALID && + (str = spa_dict_lookup(info->props, "pulse.module.id")) != NULL) module_id = (uint32_t)atoi(str); + if (!pw_manager_object_is_virtual(o) && (str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL) client_id = (uint32_t)atoi(str); @@ -3929,7 +3948,7 @@ message_put(m, TAG_U32, o->index, /* sink_input index */ TAG_STRING, get_media_name(info), - TAG_U32, id_to_index(manager, module_id), /* module index */ + TAG_U32, module_id, /* module index */ TAG_U32, id_to_index(manager, client_id), /* client index */ TAG_U32, peer_index, /* sink index */ TAG_SAMPLE_SPEC, &dev_info.ss, @@ -3984,7 +4003,11 @@ return -ENOENT; if ((str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID)) != NULL) + module_id = id_to_index(manager, (uint32_t)atoi(str)); + if (module_id == SPA_ID_INVALID &&
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/quirks.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/quirks.c
Changed
@@ -46,111 +46,8 @@ return 0; } -static bool find_match(struct spa_json *arr, const struct spa_dict *props) -{ - struct spa_json it[1]; - - while (spa_json_enter_object(arr, &it[0]) > 0) { - char key[256], val[1024]; - const char *str, *value; - int match = 0, fail = 0; - int len; - - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { - bool success = false; - - if ((len = spa_json_next(&it[0], &value)) <= 0) - break; - - str = spa_dict_lookup(props, key); - - if (spa_json_is_null(value, len)) { - success = str == NULL; - } else { - if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0) - continue; - value = val; - len = strlen(val); - } - if (str != NULL) { - if (value[0] == '~') { - regex_t preg; - if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) { - if (regexec(&preg, str, 0, NULL, 0) == 0) - success = true; - regfree(&preg); - } - } else if (strncmp(str, value, len) == 0 && - strlen(str) == (size_t)len) { - success = true; - } - } - if (success) { - match++; - pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value); - } - else - fail++; - } - if (match > 0 && fail == 0) - return true; - } - return false; -} - -static int pw_conf_match_rules(const char *rules, size_t size, const struct spa_dict *props, - int (*matched) (void *data, const char *action, const char *val, int len), - void *data) -{ - const char *val; - struct spa_json it[4], actions; - int count = 0; - - spa_json_init(&it[0], rules, size); - if (spa_json_enter_array(&it[0], &it[1]) < 0) - return 0; - - while (spa_json_enter_object(&it[1], &it[2]) > 0) { - char key[64]; - bool have_match = false, have_actions = false; - - while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) { - if (spa_streq(key, "matches")) { - if (spa_json_enter_array(&it[2], &it[3]) < 0) - break; - - have_match = find_match(&it[3], props); - } - else if (spa_streq(key, "actions")) { - if (spa_json_enter_object(&it[2], &actions) > 0) - have_actions = true; - } - else if (spa_json_next(&it[2], &val) <= 0) - break; - } - if (!have_match || !have_actions) - continue; - - while (spa_json_get_string(&actions, key, sizeof(key)) > 0) { - int res, len; - pw_log_debug("action %s", key); - - if ((len = spa_json_next(&actions, &val)) <= 0) - break; - - if (spa_json_is_container(val, len)) - len = spa_json_container_len(&actions, val, len); - - if ((res = matched(data, key, val, len)) < 0) - return res; - - count += res; - } - } - return count; -} - -static int client_rule_matched(void *data, const char *action, const char *val, int len) +static int apply_match(void *data, const char *location, const char *action, + const char *val, size_t len) { struct client *client = data; @@ -170,19 +67,10 @@ return 0; } -static int apply_pulse_rules(void *data, const char *location, const char *section, - const char *str, size_t len) -{ - struct client *client = data; - pw_conf_match_rules(str, len, &client->props->dict, - client_rule_matched, client); - return 0; -} - int client_update_quirks(struct client *client) { struct impl *impl = client->impl; struct pw_context *context = impl->context; - return pw_context_conf_section_for_each(context, "pulse.rules", - apply_pulse_rules, client); + return pw_context_conf_section_match_rules(context, "pulse.rules", + &client->props->dict, apply_match, client); }
View file
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/remap.c
Added
@@ -0,0 +1,56 @@ +/* PipeWire + * + * Copyright © 2020 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stddef.h> + +#include <pipewire/keys.h> + +#include "remap.h" + +const struct str_map media_role_map[] = { + { "Movie", "video", }, + { "Music", "music", }, + { "Game", "game", }, + { "Notification", "event", }, + { "Communication", "phone", }, + { "Movie", "animation", }, + { "Production", "production", }, + { "Accessibility", "a11y", }, + { "Test", "test", }, + { NULL, NULL }, +}; + +const struct str_map props_key_map[] = { + { PW_KEY_DEVICE_BUS_PATH, "device.bus_path" }, + { PW_KEY_DEVICE_FORM_FACTOR, "device.form_factor" }, + { PW_KEY_DEVICE_ICON_NAME, "device.icon_name" }, + { PW_KEY_DEVICE_INTENDED_ROLES, "device.intended_roles" }, + { PW_KEY_NODE_DESCRIPTION, "device.description" }, + { PW_KEY_MEDIA_ICON_NAME, "media.icon_name" }, + { PW_KEY_APP_ICON_NAME, "application.icon_name" }, + { PW_KEY_APP_PROCESS_MACHINE_ID, "application.process.machine_id" }, + { PW_KEY_APP_PROCESS_SESSION_ID, "application.process.session_id" }, + { PW_KEY_MEDIA_ROLE, "media.role", media_role_map }, + { NULL, NULL }, +};
View file
pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/remap.h
Added
@@ -0,0 +1,52 @@ +/* PipeWire + * + * Copyright © 2020 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef PULSE_SERVER_REMAP_H +#define PULSE_SERVER_REMAP_H + +#include <stddef.h> + +#include <spa/utils/string.h> + +struct str_map { + const char *pw_str; + const char *pa_str; + const struct str_map *child; +}; + +extern const struct str_map media_role_map[]; + +extern const struct str_map props_key_map[]; + +static inline const struct str_map *str_map_find(const struct str_map *map, const char *pw, const char *pa) +{ + size_t i; + for (i = 0; map[i].pw_str; i++) + if ((pw && spa_streq(map[i].pw_str, pw)) || + (pa && spa_streq(map[i].pa_str, pa))) + return &map[i]; + return NULL; +} + +#endif /* PULSE_SERVER_REMAP_H */
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/sample-play.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/sample-play.c
Changed
@@ -53,8 +53,8 @@ sample_play_emit_done(p, -EIO); break; case PW_STREAM_STATE_PAUSED: - p->index = pw_stream_get_node_id(p->stream); - sample_play_emit_ready(p, p->index); + p->id = pw_stream_get_node_id(p->stream); + sample_play_emit_ready(p, p->id); break; default: break;
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/sample-play.h -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/sample-play.h
Changed
@@ -56,7 +56,7 @@ struct sample *sample; struct pw_stream *stream; struct spa_io_rate_match *rate_match; - uint32_t index; + uint32_t id; struct spa_hook listener; struct pw_context *context; struct pw_loop *main_loop;
View file
pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/server.c -> pipewire-0.3.47.tar.gz/src/modules/module-protocol-pulse/server.c
Changed
@@ -226,7 +226,8 @@ if (errno == EINTR) continue; res = -errno; - if (res != -EAGAIN && res != -EWOULDBLOCK) + if (res != -EAGAIN && res != -EWOULDBLOCK && + res != -EPIPE && res != -ECONNRESET) pw_log_warn("recv client:%p res %zd: %m", client, r); goto exit; } @@ -327,6 +328,7 @@ error: switch (res) { case -EPIPE: + case -ECONNRESET: pw_log_info("server %p: client %p [%s] disconnected", client->server, client, client->name); SPA_FALLTHROUGH;
View file
pipewire-0.3.45.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.47.tar.gz/src/modules/module-raop-sink.c
Changed
@@ -93,6 +93,8 @@ #define DEFAULT_CHANNELS "2" #define DEFAULT_POSITION "[ FL FR ]" +#define DEFAULT_LATENCY (DEFAULT_RATE*2) + #define MODULE_USAGE "[ node.latency=<latency as fraction> ] " \ "[ node.name=<name of the nodes> ] " \ "[ node.description=<description of the nodes> ] " \ @@ -687,7 +689,9 @@ if ((str = spa_dict_lookup(headers, "Audio-Latency")) != NULL) { if (!spa_atou32(str, &impl->latency, 0)) - impl->latency = 0; + impl->latency = DEFAULT_LATENCY; + } else { + impl->latency = DEFAULT_LATENCY; } spa_zero(latency);
View file
pipewire-0.3.45.tar.gz/src/pipewire/conf.c -> pipewire-0.3.47.tar.gz/src/pipewire/conf.c
Changed
@@ -34,7 +34,8 @@ #include <unistd.h> #include <sys/wait.h> #include <dirent.h> -#if HAVE_PWD_H +#include <regex.h> +#ifdef HAVE_PWD_H #include <pwd.h> #endif #ifdef __FreeBSD__ @@ -733,6 +734,16 @@ if (pid == 0) { char *cmd, **argv; + /* Double fork to avoid zombies; we don't want to set SIGCHLD handler */ + pid = fork(); + + if (pid < 0) { + pw_log_error("fork error: %m"); + exit(1); + } else if (pid != 0) { + exit(0); + } + cmd = spa_aprintf("%s %s", key, args ? args : ""); argv = pw_split_strv(cmd, " \t", INT_MAX, &n_args); free(cmd); @@ -744,13 +755,18 @@ if (res == -1) { res = -errno; pw_log_error("execvp error '%s': %m", key); - return res; } - } - else { + + exit(1); + } else if (pid < 0) { + pw_log_error("fork error: %m"); + } else { int status = 0; - res = waitpid(pid, &status, WNOHANG); - pw_log_info("exec got pid %d res:%d status:%d", pid, res, status); + do { + errno = 0; + res = waitpid(pid, &status, 0); + } while (res < 0 && errno == EINTR); + pw_log_debug("exec got pid %d res:%d status:%d", (int)pid, res, status); } return 0; } @@ -810,6 +826,7 @@ return res; } + SPA_EXPORT int pw_context_conf_section_for_each(struct pw_context *context, const char *section, int (*callback) (void *data, const char *location, const char *section, @@ -819,7 +836,7 @@ struct pw_properties *conf = context->conf; const char *path = NULL; const struct spa_dict_item *it; - int res; + int res = 0; spa_dict_for_each(it, &conf->dict) { if (spa_strendswith(it->key, "config.path")) { @@ -882,3 +899,153 @@ update_props, &data); return data.count; } + +struct match { + const struct spa_dict *props; + int (*matched) (void *data, const char *location, const char *action, + const char *val, size_t len); + void *data; +}; + +/* + * { + * # all keys must match the value. ~ in value starts regex. + * <key> = <value> + * ... + * } + */ +static bool find_match(struct spa_json *arr, const struct spa_dict *props) +{ + struct spa_json it[1]; + + while (spa_json_enter_object(arr, &it[0]) > 0) { + char key[256], val[1024]; + const char *str, *value; + int match = 0, fail = 0; + int len; + + while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + bool success = false; + + if ((len = spa_json_next(&it[0], &value)) <= 0) + break; + + str = spa_dict_lookup(props, key); + + if (spa_json_is_null(value, len)) { + success = str == NULL; + } else { + if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0) + continue; + value = val; + len = strlen(val); + } + if (str != NULL) { + if (value[0] == '~') { + regex_t preg; + if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) { + if (regexec(&preg, str, 0, NULL, 0) == 0) + success = true; + regfree(&preg); + } + } else if (strncmp(str, value, len) == 0 && + strlen(str) == (size_t)len) { + success = true; + } + } + if (success) { + match++; + pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value); + } + else + fail++; + } + if (match > 0 && fail == 0) + return true; + } + return false; +} + +/** + * rules = [ + * { + * matches = [ + * # any of the items in matches needs to match, it one does, + * # actions are emited. + * { + * # all keys must match the value. ~ in value starts regex. + * <key> = <value> + * ... + * } + * ... + * ] + * actions = { + * <action> = <value> + * ... + * } + * } + * ] + */ +static int match_rules(void *data, const char *location, const char *section, + const char *str, size_t len) +{ + struct match *match = data; + const struct spa_dict *props = match->props; + const char *val; + struct spa_json it[4], actions; + + spa_json_init(&it[0], str, len); + if (spa_json_enter_array(&it[0], &it[1]) < 0) + return 0; + + while (spa_json_enter_object(&it[1], &it[2]) > 0) { + char key[64]; + bool have_match = false, have_actions = false; + + while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) { + if (spa_streq(key, "matches")) { + if (spa_json_enter_array(&it[2], &it[3]) < 0) + break; + + have_match = find_match(&it[3], props); + } + else if (spa_streq(key, "actions")) { + if (spa_json_enter_object(&it[2], &actions) > 0) + have_actions = true; + } + else if (spa_json_next(&it[2], &val) <= 0) + break; + } + if (!have_match || !have_actions) + continue; + + while (spa_json_get_string(&actions, key, sizeof(key)) > 0) { + int res, len; + pw_log_debug("action %s", key); + + if ((len = spa_json_next(&actions, &val)) <= 0) + break; + + if (spa_json_is_container(val, len))
View file
pipewire-0.3.45.tar.gz/src/pipewire/context.c -> pipewire-0.3.47.tar.gz/src/pipewire/context.c
Changed
@@ -1068,7 +1068,7 @@ struct pw_impl_node *n, *s, *target, *fallback; uint32_t max_quantum, min_quantum, def_quantum, lim_quantum, rate_quantum; uint32_t *rates, n_rates, def_rate; - bool freewheel = false, global_force_rate, force_rate, global_force_quantum; + bool freewheel = false, global_force_rate, force_rate, force_quantum, global_force_quantum; pw_log_info("%p: busy:%d reason:%s", context, impl->recalc, reason); @@ -1083,7 +1083,7 @@ get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &lim_quantum, &rate_quantum); rates = get_rates(context, &def_rate, &n_rates, &global_force_rate); - global_force_quantum = rate_quantum == 0; + force_quantum = global_force_quantum = rate_quantum == 0; force_rate = global_force_rate; /* start from all drivers and group all nodes that are linked @@ -1183,6 +1183,7 @@ def_quantum = min_quantum = max_quantum = s->force_quantum; rate_quantum = 0; quantum_stamp = s->stamp; + force_quantum = true; } if (!global_force_rate && s->force_rate > 0 && s->stamp > rate_stamp) { @@ -1213,6 +1214,8 @@ running = !n->passive; } + if (force_quantum) + lock_quantum = false; if (force_rate) lock_rate = false;
View file
pipewire-0.3.45.tar.gz/src/pipewire/context.h -> pipewire-0.3.47.tar.gz/src/pipewire/context.h
Changed
@@ -123,6 +123,12 @@ int (*callback) (void *data, const char *location, const char *section, const char *str, size_t len), void *data); +/** emit callback for all matched properties. Since 0.3.46 */ +int pw_context_conf_section_match_rules(struct pw_context *context, const char *section, + struct spa_dict *props, + int (*callback) (void *data, const char *location, const char *action, + const char *str, size_t len), + void *data); /** Get the context support objects */ const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support);
View file
pipewire-0.3.45.tar.gz/src/pipewire/filter.c -> pipewire-0.3.47.tar.gz/src/pipewire/filter.c
Changed
@@ -50,7 +50,6 @@ #define MAX_BUFFERS 64 #define MASK_BUFFERS (MAX_BUFFERS-1) -#define MAX_PORTS 1024 static bool mlock_warned = false; @@ -142,7 +141,7 @@ } rt; struct spa_list port_list; - struct port *ports[2][MAX_PORTS]; + struct pw_map ports[2]; uint32_t change_mask_all; struct spa_node_info info; @@ -306,27 +305,17 @@ enum spa_direction direction, uint32_t user_data_size) { struct port *p; - int i; - - for (i = 0; i < MAX_PORTS; i++) { - if ((filter->ports[direction][i]) == NULL) - break; - } - if (i == MAX_PORTS) - return NULL; p = calloc(1, sizeof(struct port) + user_data_size); p->filter = filter; p->direction = direction; - p->id = i; p->latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); p->latency[SPA_DIRECTION_OUTPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); spa_list_init(&p->param_list); spa_ringbuffer_init(&p->dequeued.ring); spa_ringbuffer_init(&p->queued.ring); - - filter->ports[direction][i] = p; + p->id = pw_map_insert_new(&filter->ports[direction], p); spa_list_append(&filter->port_list, &p->link); return p; @@ -334,10 +323,9 @@ static inline struct port *get_port(struct filter *filter, enum spa_direction direction, uint32_t port_id) { - if ((direction != SPA_DIRECTION_INPUT && direction != SPA_DIRECTION_OUTPUT) || - port_id >= MAX_PORTS) + if ((direction != SPA_DIRECTION_INPUT && direction != SPA_DIRECTION_OUTPUT)) return NULL; - return filter->ports[direction][port_id]; + return pw_map_lookup(&filter->ports[direction], port_id); } static inline int push_queue(struct port *port, struct queue *queue, struct buffer *buffer) @@ -1241,6 +1229,8 @@ spa_list_init(&impl->param_list); spa_list_init(&impl->port_list); + pw_map_init(&impl->ports[SPA_DIRECTION_INPUT], 32, 32); + pw_map_init(&impl->ports[SPA_DIRECTION_OUTPUT], 32, 32); spa_hook_list_init(&this->listener_list); spa_list_init(&this->controls); @@ -1377,6 +1367,9 @@ spa_hook_list_clean(&impl->hooks); spa_hook_list_clean(&filter->listener_list); + pw_map_clear(&impl->ports[SPA_DIRECTION_INPUT]); + pw_map_clear(&impl->ports[SPA_DIRECTION_OUTPUT]); + free(filter->name); if (impl->data.context) @@ -1496,8 +1489,8 @@ SPA_NODE_CHANGE_MASK_PARAMS; impl->info = SPA_NODE_INFO_INIT(); - impl->info.max_input_ports = MAX_PORTS; - impl->info.max_output_ports = MAX_PORTS; + impl->info.max_input_ports = UINT32_MAX; + impl->info.max_output_ports = UINT32_MAX; impl->info.flags = impl->process_rt ? SPA_NODE_FLAG_RT : 0; impl->info.props = &filter->properties->dict; impl->params[IDX_Props] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_WRITE); @@ -1722,7 +1715,7 @@ spa_node_emit_port_info(&impl->hooks, port->direction, port->id, NULL); spa_list_remove(&port->link); - impl->ports[port->direction][port->id] = NULL; + pw_map_remove(&impl->ports[port->direction], port->id); clear_buffers(port); clear_params(impl, port, SPA_ID_INVALID);
View file
pipewire-0.3.45.tar.gz/src/pipewire/map.h -> pipewire-0.3.47.tar.gz/src/pipewire/map.h
Changed
@@ -115,7 +115,7 @@ */ static inline void pw_map_init(struct pw_map *map, size_t size, size_t extend) { - pw_array_init(&map->items, extend); + pw_array_init(&map->items, extend * sizeof(union pw_map_item)); pw_array_ensure_size(&map->items, size * sizeof(union pw_map_item)); map->free_list = SPA_ID_INVALID; }
View file
pipewire-0.3.45.tar.gz/src/pipewire/proxy.c -> pipewire-0.3.47.tar.gz/src/pipewire/proxy.c
Changed
@@ -256,9 +256,6 @@ pw_proxy_emit_destroy(proxy); } - spa_hook_list_clean(&proxy->listener_list); - spa_hook_list_clean(&proxy->object_listener_list); - pw_proxy_unref(proxy); } @@ -298,6 +295,22 @@ pw_log_debug("%p: free %u", proxy, proxy->id); /** client must explicitly destroy all proxies */ assert(proxy->destroyed); + +#if DEBUG_LISTENERS + { + struct spa_hook *h; + spa_list_for_each(h, &proxy->object_listener_list.list, link) { + pw_log_warn("%p: proxy %u: leaked object listener %p", + proxy, proxy->id, h); + break; + } + spa_list_for_each(h, &proxy->listener_list.list, link) { + pw_log_warn("%p: proxy %u: leaked listener %p", + proxy, proxy->id, h); + break; + } + } +#endif free(proxy); }
View file
pipewire-0.3.45.tar.gz/src/pipewire/stream.c -> pipewire-0.3.47.tar.gz/src/pipewire/stream.c
Changed
@@ -48,7 +48,6 @@ #define MAX_BUFFERS 64 #define MASK_BUFFERS (MAX_BUFFERS-1) -#define MAX_PORTS 1 static bool mlock_warned = false;
View file
pipewire-0.3.45.tar.gz/src/pipewire/utils.c -> pipewire-0.3.47.tar.gz/src/pipewire/utils.c
Changed
@@ -27,7 +27,7 @@ #include <fcntl.h> #include <unistd.h> #include <errno.h> -#if HAVE_SYS_RANDOM_H +#ifdef HAVE_SYS_RANDOM_H #include <sys/random.h> #endif #include <string.h>
View file
pipewire-0.3.45.tar.gz/src/tools/meson.build -> pipewire-0.3.47.tar.gz/src/tools/meson.build
Changed
@@ -34,7 +34,7 @@ endif build_pw_cat = false -if not get_option('pw-cat').disabled() and sndfile_dep.found() +if get_option('pw-cat').allowed() and sndfile_dep.found() build_pw_cat = true pwcat_sources = [
View file
pipewire-0.3.45.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.47.tar.gz/src/tools/pw-cat.c
Changed
@@ -648,7 +648,7 @@ struct data *data = userdata; if (data->verbose) - fprintf(stdout, "remote %"PRIu32" is named \"%s\"\n", + printf("remote %"PRIu32" is named \"%s\"\n", info->id, info->name); } @@ -808,7 +808,7 @@ id, type, name, media_class, desc ? : "", prio); spa_dict_for_each(item, props) { - fprintf(stdout, "\t\t%s = \"%s\"\n", item->key, item->value); + printf("\t\t%s = \"%s\"\n", item->key, item->value); } } @@ -1533,7 +1533,7 @@ return EXIT_SUCCESS; case OPT_VERSION: - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", prog, @@ -1930,14 +1930,21 @@ } error_connect_fail: - if (data.stream) + if (data.stream) { + spa_hook_remove(&data.stream_listener); pw_stream_destroy(data.stream); + } error_no_stream: - if (data.metadata) + if (data.metadata) { + spa_hook_remove(&data.metadata_listener); pw_proxy_destroy((struct pw_proxy*)data.metadata); - if (data.registry) + } + if (data.registry) { + spa_hook_remove(&data.registry_listener); pw_proxy_destroy((struct pw_proxy*)data.registry); + } error_no_registry: + spa_hook_remove(&data.core_listener); pw_core_disconnect(data.core); error_ctx_connect_failed: pw_context_destroy(data.context);
View file
pipewire-0.3.45.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.47.tar.gz/src/tools/pw-cli.c
Changed
@@ -40,7 +40,7 @@ #define FNM_EXTMATCH 0 #endif -#define spa_debug(...) fprintf(stdout,__VA_ARGS__);fputc('\n', stdout) +#define spa_debug(fmt,...) printf(fmt, ## __VA_ARGS__) #include <spa/utils/result.h> #include <spa/utils/string.h> @@ -157,15 +157,15 @@ const struct spa_dict_item *item; if (header) - fprintf(stdout, "%c\tproperties:\n", mark); + printf("%c\tproperties:\n", mark); if (props == NULL || props->n_items == 0) { if (header) - fprintf(stdout, "\t\tnone\n"); + printf("\t\tnone\n"); return; } spa_dict_for_each(item, props) { - fprintf(stdout, "%c\t\t%s = \"%s\"\n", mark, item->key, item->value); + printf("%c\t\t%s = \"%s\"\n", mark, item->key, item->value); } } @@ -174,16 +174,16 @@ uint32_t i; if (header) - fprintf(stdout, "%c\tparams: (%u)\n", mark, n_params); + printf("%c\tparams: (%u)\n", mark, n_params); if (params == NULL || n_params == 0) { if (header) - fprintf(stdout, "\t\tnone\n"); + printf("\t\tnone\n"); return; } for (i = 0; i < n_params; i++) { const struct spa_type_info *type_info = spa_type_param; - fprintf(stdout, "%c\t %d (%s) %c%c\n", + printf("%c\t %d (%s) %c%c\n", params[i].user > 0 ? mark : ' ', params[i].id, spa_debug_type_find_name(type_info, params[i].id), params[i].flags & SPA_PARAM_INFO_READ ? 'r' : '-', @@ -257,9 +257,9 @@ { size_t i; - fprintf(stdout, "Available commands:\n"); + printf("Available commands:\n"); for (i = 0; i < SPA_N_ELEMENTS(command_list); i++) { - fprintf(stdout, "\t%-20.20s\t%s\n", command_list[i].name, command_list[i].description); + printf("\t%-20.20s\t%s\n", command_list[i].name, command_list[i].description); } return true; } @@ -284,7 +284,7 @@ } id = pw_map_insert_new(&data->vars, module); - fprintf(stdout, "%d = @module:%d\n", id, pw_global_get_id(pw_impl_module_get_global(module))); + printf("%d = @module:%d\n", id, pw_global_get_id(pw_impl_module_get_global(module))); return true; } @@ -295,7 +295,7 @@ free(rd->name); rd->name = info->name ? strdup(info->name) : NULL; if (rd->data->interactive) - fprintf(stdout, "remote %d is named '%s'\n", rd->id, rd->name); + printf("remote %d is named '%s'\n", rd->id, rd->name); } static void set_prompt(struct remote_data *rd) @@ -353,7 +353,7 @@ if (filter && !global_matches(global, filter)) return 0; - fprintf(stdout, "\tid %d, type %s/%d\n", global->id, + printf("\tid %d, type %s/%d\n", global->id, global->type, global->version); if (global->properties) print_properties(&global->properties->dict, ' ', false); @@ -383,7 +383,7 @@ global->properties = props ? pw_properties_new_dict(props) : NULL; if (rd->data->monitoring) { - fprintf(stdout, "remote %d added global: ", rd->id); + printf("remote %d added global: ", rd->id); print_global(global, NULL); } @@ -396,7 +396,7 @@ ret = bind_global(rd, global, &error); if (!ret) { if (rd->data->interactive) - fprintf(stdout, "Error: \"%s\"\n", error); + fprintf(stderr, "Error: \"%s\"\n", error); free(error); } } @@ -424,12 +424,12 @@ global = pw_map_lookup(&rd->globals, id); if (global == NULL) { - fprintf(stdout, "remote %d removed unknown global %d\n", rd->id, id); + fprintf(stderr, "remote %d removed unknown global %d\n", rd->id, id); return; } if (rd->data->monitoring) { - fprintf(stdout, "remote %d removed global: ", rd->id); + printf("remote %d removed global: ", rd->id); print_global(global, NULL); } @@ -536,7 +536,7 @@ spa_list_append(&data->remotes, &rd->link); if (rd->data->interactive) - fprintf(stdout, "%d = @remote:%p\n", rd->id, rd->core); + printf("%d = @remote:%p\n", rd->id, rd->core); data->current = rd; @@ -592,7 +592,7 @@ struct remote_data *rd; spa_list_for_each(rd, &data->remotes, link) - fprintf(stdout, "\t%d = @remote:%p '%s'\n", rd->id, rd->core, rd->name); + printf("\t%d = @remote:%p '%s'\n", rd->id, rd->core, rd->name); return true; } @@ -631,10 +631,10 @@ if (global == NULL) return; - fprintf(stdout, "\tid: %d\n", global->id); - fprintf(stdout, "\tpermissions: "PW_PERMISSION_FORMAT"\n", + printf("\tid: %d\n", global->id); + printf("\tpermissions: "PW_PERMISSION_FORMAT"\n", PW_PERMISSION_ARGS(global->permissions)); - fprintf(stdout, "\ttype: %s/%d\n", global->type, global->version); + printf("\ttype: %s/%d\n", global->type, global->version); } static void info_core(struct proxy_data *pd) @@ -642,11 +642,11 @@ struct pw_core_info *info = pd->info; info_global(pd); - fprintf(stdout, "\tcookie: %u\n", info->cookie); - fprintf(stdout, "\tuser-name: \"%s\"\n", info->user_name); - fprintf(stdout, "\thost-name: \"%s\"\n", info->host_name); - fprintf(stdout, "\tversion: \"%s\"\n", info->version); - fprintf(stdout, "\tname: \"%s\"\n", info->name); + printf("\tcookie: %u\n", info->cookie); + printf("\tuser-name: \"%s\"\n", info->user_name); + printf("\thost-name: \"%s\"\n", info->host_name); + printf("\tversion: \"%s\"\n", info->version); + printf("\tname: \"%s\"\n", info->name); print_properties(info->props, MARK_CHANGE(PW_CORE_CHANGE_MASK_PROPS), true); info->change_mask = 0; } @@ -656,9 +656,9 @@ struct pw_module_info *info = pd->info; info_global(pd); - fprintf(stdout, "\tname: \"%s\"\n", info->name); - fprintf(stdout, "\tfilename: \"%s\"\n", info->filename); - fprintf(stdout, "\targs: \"%s\"\n", info->args); + printf("\tname: \"%s\"\n", info->name); + printf("\tfilename: \"%s\"\n", info->filename); + printf("\targs: \"%s\"\n", info->args); print_properties(info->props, MARK_CHANGE(PW_MODULE_CHANGE_MASK_PROPS), true); info->change_mask = 0; } @@ -668,16 +668,16 @@ struct pw_node_info *info = pd->info; info_global(pd); - fprintf(stdout, "%c\tinput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS), + printf("%c\tinput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS), info->n_input_ports, info->max_input_ports); - fprintf(stdout, "%c\toutput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_OUTPUT_PORTS), + printf("%c\toutput ports: %u/%u\n", MARK_CHANGE(PW_NODE_CHANGE_MASK_OUTPUT_PORTS), info->n_output_ports, info->max_output_ports); - fprintf(stdout, "%c\tstate: \"%s\"", MARK_CHANGE(PW_NODE_CHANGE_MASK_STATE), + printf("%c\tstate: \"%s\"", MARK_CHANGE(PW_NODE_CHANGE_MASK_STATE), pw_node_state_as_string(info->state)); if (info->state == PW_NODE_STATE_ERROR && info->error) - fprintf(stdout, " \"%s\"\n", info->error); + printf(" \"%s\"\n", info->error); else - fprintf(stdout, "\n");
View file
pipewire-0.3.45.tar.gz/src/tools/pw-dot.c -> pipewire-0.3.47.tar.gz/src/tools/pw-dot.c
Changed
@@ -609,6 +609,8 @@ static void destroy_proxy(void *user_data) { struct global *g = user_data; + spa_hook_remove(&g->object_listener); + spa_hook_remove(&g->proxy_listener); pw_properties_free(g->props); if (g->info) g->info_destroy(g->info); @@ -760,9 +762,9 @@ pw_main_loop_quit(d->loop); } -static void show_help(const char *name) +static void show_help(const char *name, bool error) { - fprintf(stdout, "%s [options]\n" + fprintf(error ? stderr : stdout, "%s [options]\n" " -h, --help Show this help\n" " --version Show version\n" " -a, --all Show all object types\n" @@ -801,10 +803,10 @@ while ((c = getopt_long(argc, argv, "hVasdr:o:L9", long_options, NULL)) != -1) { switch (c) { case 'h' : - show_help(argv[0]); + show_help(argv[0], false); return 0; case 'V' : - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", argv[0], @@ -840,7 +842,7 @@ fprintf(stderr, "orthogonal edges enabled\n"); break; default: - show_help(argv[0]); + show_help(argv[0], true); return -1; } } @@ -891,7 +893,9 @@ draw_graph(&data, dot_path); dot_str_clear(&data.dot_str); + spa_hook_remove(&data.registry_listener); pw_proxy_destroy((struct pw_proxy*)data.registry); + spa_hook_remove(&data.core_listener); pw_context_destroy(data.context); pw_main_loop_destroy(data.loop); pw_deinit();
View file
pipewire-0.3.45.tar.gz/src/tools/pw-dump.c -> pipewire-0.3.47.tar.gz/src/tools/pw-dump.c
Changed
@@ -1458,9 +1458,9 @@ pw_main_loop_quit(d->loop); } -static void show_help(struct data *data, const char *name) +static void show_help(struct data *data, const char *name, bool error) { - fprintf(stdout, "%s [options] [<id>]\n" + fprintf(error ? stderr : stdout, "%s [options] [<id>]\n" " -h, --help Show this help\n" " --version Show version\n" " -r, --remote Remote daemon name\n" @@ -1492,14 +1492,15 @@ data.out = stdout; if (isatty(fileno(data.out)) && getenv("NO_COLOR") == NULL) colors = true; + setlinebuf(data.out); while ((c = getopt_long(argc, argv, "hVr:mNC", long_options, NULL)) != -1) { switch (c) { case 'h' : - show_help(&data, argv[0]); + show_help(&data, argv[0], false); return 0; case 'V' : - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", argv[0], @@ -1524,12 +1525,13 @@ else if (!strcmp(optarg, "always")) colors = true; else { - show_help(&data, argv[0]); + fprintf(stderr, "Unknown color: %s\n", optarg); + show_help(&data, argv[0], true); return -1; } break; default: - show_help(&data, argv[0]); + show_help(&data, argv[0], true); return -1; } } @@ -1581,7 +1583,9 @@ if (data.info) pw_core_info_free(data.info); + spa_hook_remove(&data.registry_listener); pw_proxy_destroy((struct pw_proxy*)data.registry); + spa_hook_remove(&data.core_listener); pw_context_destroy(data.context); pw_main_loop_destroy(data.loop); pw_deinit();
View file
pipewire-0.3.45.tar.gz/src/tools/pw-link.c -> pipewire-0.3.47.tar.gz/src/tools/pw-link.c
Changed
@@ -179,15 +179,15 @@ prefix2 = " "; } - fprintf(stdout, "%s%s%s%s\n", data->prefix, prefix, + printf("%s%s%s%s\n", data->prefix, prefix, id, port_name(buffer, sizeof(buffer), n, p)); if (verbose) { port_path(buffer, sizeof(buffer), n, p); if (buffer[0] != '\0') - fprintf(stdout, "%s %s%s%s\n", data->prefix, prefix2, prefix, buffer); + printf("%s %s%s%s\n", data->prefix, prefix2, prefix, buffer); port_alias(buffer, sizeof(buffer), n, p); if (buffer[0] != '\0') - fprintf(stdout, "%s %s%s%s\n", data->prefix, prefix2, prefix, buffer); + printf("%s %s%s%s\n", data->prefix, prefix2, prefix, buffer); } } @@ -426,7 +426,7 @@ if (data->opt_id) snprintf(id, sizeof(id), "%4d ", link->id); - fprintf(stdout, "%s%s%s -> %s\n", data->prefix, id, + printf("%s%s%s -> %s\n", data->prefix, id, port_name(buffer1, sizeof(buffer1), n1, p1), port_name(buffer2, sizeof(buffer2), n2, p2)); return 0; @@ -552,9 +552,9 @@ pw_main_loop_quit(data->loop); } -static void show_help(struct data *data, const char *name) +static void show_help(struct data *data, const char *name, bool error) { - fprintf(stdout, "%1$s : PipeWire port and link manager.\n" + fprintf(error ? stderr : stdout, "%1$s : PipeWire port and link manager.\n" "Generic: %1$s [options]\n" " -h, --help Show this help\n" " --version Show version\n" @@ -563,11 +563,11 @@ " -o, --output List output ports\n" " -i, --input List input ports\n" " -l, --links List links\n" - " -m, --monitor Monitor links\n" + " -m, --monitor Monitor links and ports\n" " -I, --id List IDs\n" " -v, --verbose Verbose port properties\n" "Connect: %1$s [options] output input\n" - " -L, --linger Linger (for use with -m)\n" + " -L, --linger Linger (default, unless -m is used)\n" " -P, --passive Passive link\n" " -p, --props=PROPS Properties as JSON object\n" "Disconnect: %1$s -d [options] output input\n" @@ -602,6 +602,8 @@ pw_init(&argc, &argv); spa_list_init(&data.objects); + setlinebuf(stdout); + data.props = pw_properties_new(NULL, NULL); if (data.props == NULL) { fprintf(stderr, "can't create properties: %m\n"); @@ -611,10 +613,10 @@ while ((c = getopt_long(argc, argv, "hVr:oilmIvLPp:d", long_options, NULL)) != -1) { switch (c) { case 'h': - show_help(&data, argv[0]); + show_help(&data, argv[0], NULL); return 0; case 'V': - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", argv[0], @@ -655,12 +657,17 @@ data.opt_mode |= MODE_DISCONNECT; break; default: - show_help(&data, argv[0]); + show_help(&data, argv[0], true); return -1; } } if (argc == 1) - show_help(&data, argv[0]); + show_help(&data, argv[0], true); + + if (data.opt_id && (data.opt_mode & MODE_LIST) == 0) { + fprintf(stderr, "-I option needs one or more of -l, -i or -o\n"); + return -1; + } if ((data.opt_mode & MODE_MONITOR) == 0) pw_properties_set(data.props, PW_KEY_OBJECT_LINGER, "true"); @@ -729,7 +736,7 @@ do_list(&data); } else if (data.opt_mode & MODE_DISCONNECT) { if (data.opt_output == NULL) { - fprintf(stderr, "missing link-id or output and input port names\n"); + fprintf(stderr, "missing link-id or output and input port names to disconnect\n"); return -1; } if ((res = do_unlink_ports(&data)) < 0) { @@ -739,7 +746,7 @@ } else { if (data.opt_output == NULL || data.opt_input == NULL) { - fprintf(stderr, "missing output and input port names\n"); + fprintf(stderr, "missing output and input port names to connect\n"); return -1; } if ((res = do_link_ports(&data)) < 0) { @@ -758,7 +765,9 @@ regfree(data.out_regex); if (data.in_regex) regfree(data.in_regex); + spa_hook_remove(&data.registry_listener); pw_proxy_destroy((struct pw_proxy*)data.registry); + spa_hook_remove(&data.core_listener); pw_core_disconnect(data.core); pw_context_destroy(data.context); pw_main_loop_destroy(data.loop);
View file
pipewire-0.3.45.tar.gz/src/tools/pw-loopback.c -> pipewire-0.3.47.tar.gz/src/tools/pw-loopback.c
Changed
@@ -80,9 +80,9 @@ }; -static void show_help(struct data *data, const char *name) +static void show_help(struct data *data, const char *name, bool error) { - fprintf(stdout, "%s [options]\n" + fprintf(error ? stderr : stdout, "%s [options]\n" " -h, --help Show this help\n" " --version Show version\n" " -r, --remote Remote daemon name\n" @@ -142,10 +142,10 @@ while ((c = getopt_long(argc, argv, "hVr:g:c:m:l:C:P:i:o:", long_options, NULL)) != -1) { switch (c) { case 'h': - show_help(&data, argv[0]); + show_help(&data, argv[0], false); return 0; case 'V': - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", argv[0], @@ -180,7 +180,7 @@ pw_properties_update_string(data.playback_props, optarg, strlen(optarg)); break; default: - show_help(&data, argv[0]); + show_help(&data, argv[0], true); return -1; } }
View file
pipewire-0.3.45.tar.gz/src/tools/pw-metadata.c -> pipewire-0.3.47.tar.gz/src/tools/pw-metadata.c
Changed
@@ -70,11 +70,11 @@ if ((d->opt_id == SPA_ID_INVALID || d->opt_id == id) && (d->opt_key == NULL || spa_streq(d->opt_key, key))) { if (key == NULL) { - fprintf(stdout, "remove: id:%u all keys\n", id); + printf("remove: id:%u all keys\n", id); } else if (value == NULL) { - fprintf(stdout, "remove: id:%u key:'%s'\n", id, key); + printf("remove: id:%u key:'%s'\n", id, key); } else { - fprintf(stdout, "update: id:%u key:'%s' value:'%s' type:'%s'\n", id, key, value, type); + printf("update: id:%u key:'%s' value:'%s' type:'%s'\n", id, key, value, type); } } @@ -106,23 +106,23 @@ return; } - fprintf(stdout, "Found \"%s\" metadata %d\n", d->opt_name, id); + printf("Found \"%s\" metadata %d\n", d->opt_name, id); d->metadata = pw_registry_bind(d->registry, id, type, PW_VERSION_METADATA, 0); if (d->opt_delete) { if (d->opt_id != SPA_ID_INVALID) { if (d->opt_key != NULL) - fprintf(stdout, "delete property: id:%u key:%s\n", d->opt_id, d->opt_key); + printf("delete property: id:%u key:%s\n", d->opt_id, d->opt_key); else - fprintf(stdout, "delete properties: id:%u\n", d->opt_id); + printf("delete properties: id:%u\n", d->opt_id); pw_metadata_set_property(d->metadata, d->opt_id, d->opt_key, NULL, NULL); } else { - fprintf(stdout, "delete all properties\n"); + printf("delete all properties\n"); pw_metadata_clear(d->metadata); } } else if (d->opt_id != SPA_ID_INVALID && d->opt_key != NULL && d->opt_value != NULL) { - fprintf(stdout, "set property: id:%u key:%s value:%s type:%s\n", + printf("set property: id:%u key:%s value:%s type:%s\n", d->opt_id, d->opt_key, d->opt_value, d->opt_type); pw_metadata_set_property(d->metadata, d->opt_id, d->opt_key, d->opt_type, d->opt_value); } else { @@ -170,9 +170,9 @@ pw_main_loop_quit(data->loop); } -static void show_help(struct data *data, const char *name) +static void show_help(struct data *data, const char *name, bool error) { - fprintf(stdout, "%s [options] [ id [ key [ value [ type ] ] ] ]\n" + fprintf(error ? stderr : stdout, "%s [options] [ id [ key [ value [ type ] ] ] ]\n" " -h, --help Show this help\n" " --version Show version\n" " -r, --remote Remote daemon name\n" @@ -196,6 +196,8 @@ { NULL, 0, NULL, 0} }; + setlinebuf(stdout); + pw_init(&argc, &argv); data.opt_name = "default"; @@ -203,10 +205,10 @@ while ((c = getopt_long(argc, argv, "hVr:mdn:", long_options, NULL)) != -1) { switch (c) { case 'h': - show_help(&data, argv[0]); + show_help(&data, argv[0], false); return 0; case 'V': - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", argv[0], @@ -226,7 +228,7 @@ data.opt_name = optarg; break; default: - show_help(&data, argv[0]); + show_help(&data, argv[0], true); return -1; } } @@ -281,7 +283,9 @@ if (data.metadata) pw_proxy_destroy((struct pw_proxy*)data.metadata); + spa_hook_remove(&data.registry_listener); pw_proxy_destroy((struct pw_proxy*)data.registry); + spa_hook_remove(&data.core_listener); pw_core_disconnect(data.core); pw_context_destroy(data.context); pw_main_loop_destroy(data.loop);
View file
pipewire-0.3.45.tar.gz/src/tools/pw-mididump.c -> pipewire-0.3.47.tar.gz/src/tools/pw-mididump.c
Changed
@@ -113,7 +113,7 @@ ev.data = SPA_POD_BODY(&c->value), ev.size = SPA_POD_BODY_SIZE(&c->value); - fprintf(stdout, "%4d: ", c->offset); + printf("%4d: ", c->offset); midi_file_dump_event(stdout, &ev); } @@ -175,9 +175,9 @@ return 0; } -static void show_help(const char *name) +static void show_help(const char *name, bool error) { - fprintf(stdout, "%s [options] [FILE]\n" + fprintf(error ? stderr : stdout, "%s [options] [FILE]\n" " -h, --help Show this help\n" " --version Show version\n" " -r, --remote Remote daemon name\n", @@ -197,13 +197,15 @@ pw_init(&argc, &argv); + setlinebuf(stdout); + while ((c = getopt_long(argc, argv, "hVr:", long_options, NULL)) != -1) { switch (c) { case 'h': - show_help(argv[0]); + show_help(argv[0], false); return 0; case 'V': - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", argv[0], @@ -214,7 +216,7 @@ data.opt_remote = optarg; break; default: - show_help(argv[0]); + show_help(argv[0], true); return -1; } }
View file
pipewire-0.3.45.tar.gz/src/tools/pw-mon.c -> pipewire-0.3.47.tar.gz/src/tools/pw-mon.c
Changed
@@ -48,10 +48,10 @@ { .prefix = "*", .suffix = "" }, }; -#define with_prefix(use_prefix_, stream_) \ - for (bool once_ = !!fprintf(stream_, "%s", (pprefix[!!(use_prefix_)]).prefix); \ +#define with_prefix(use_prefix_) \ + for (bool once_ = !!printf("%s", (pprefix[!!(use_prefix_)]).prefix); \ once_; \ - once_ = false, fprintf(stream_, "%s", (pprefix[!!(use_prefix_)]).suffix)) + once_ = false, printf("%s", (pprefix[!!(use_prefix_)]).suffix)) struct param { @@ -175,13 +175,13 @@ { struct param *p; - with_prefix(use_prefix, stderr) { - fprintf(stderr, "\tparams:\n"); + with_prefix(use_prefix) { + printf("\tparams:\n"); } spa_list_for_each(p, &data->param_list, link) { - with_prefix(p->changed, stderr) { - fprintf(stderr, "\t id:%u (%s)\n", + with_prefix(p->changed) { + printf("\t id:%u (%s)\n", p->id, spa_debug_type_find_name(spa_type_param, p->id)); if (spa_pod_is_object_type(p->param, SPA_TYPE_OBJECT_Format)) @@ -197,20 +197,20 @@ { const struct spa_dict_item *item; - with_prefix(use_prefix, stderr) { - fprintf(stderr, "\tproperties:\n"); + with_prefix(use_prefix) { + printf("\tproperties:\n"); if (props == NULL || props->n_items == 0) { - fprintf(stderr, "\t\tnone\n"); + printf("\t\tnone\n"); return; } } spa_dict_for_each(item, props) { - with_prefix(use_prefix, stderr) { + with_prefix(use_prefix) { if (item->value) - fprintf(stderr, "\t\t%s = \"%s\"\n", item->key, item->value); + printf("\t\t%s = \"%s\"\n", item->key, item->value); else - fprintf(stderr, "\t\t%s = (null)\n", item->key); + printf("\t\t%s = (null)\n", item->key); } } } @@ -221,12 +221,12 @@ { bool print_all = true, print_mark = true; - fprintf(stderr, "\ttype: %s\n", PW_TYPE_INTERFACE_Core); - fprintf(stderr, "\tcookie: %u\n", info->cookie); - fprintf(stderr, "\tuser-name: \"%s\"\n", info->user_name); - fprintf(stderr, "\thost-name: \"%s\"\n", info->host_name); - fprintf(stderr, "\tversion: \"%s\"\n", info->version); - fprintf(stderr, "\tname: \"%s\"\n", info->name); + printf("\ttype: %s\n", PW_TYPE_INTERFACE_Core); + printf("\tcookie: %u\n", info->cookie); + printf("\tuser-name: \"%s\"\n", info->user_name); + printf("\thost-name: \"%s\"\n", info->host_name); + printf("\tversion: \"%s\"\n", info->version); + printf("\tname: \"%s\"\n", info->name); if (print_all) { print_properties(info->props, MARK_CHANGE(PW_CORE_CHANGE_MASK_PROPS)); } @@ -239,23 +239,23 @@ print_all = true; if (data->info == NULL) { - fprintf(stderr, "added:\n"); + printf("added:\n"); print_mark = false; } else { - fprintf(stderr, "changed:\n"); + printf("changed:\n"); print_mark = true; } info = data->info = pw_module_info_update(data->info, info); - fprintf(stderr, "\tid: %d\n", data->id); - fprintf(stderr, "\tpermissions: "PW_PERMISSION_FORMAT"\n", + printf("\tid: %d\n", data->id); + printf("\tpermissions: "PW_PERMISSION_FORMAT"\n", PW_PERMISSION_ARGS(data->permissions)); - fprintf(stderr, "\ttype: %s (version %d)\n", data->type, data->version); - fprintf(stderr, "\tname: \"%s\"\n", info->name); - fprintf(stderr, "\tfilename: \"%s\"\n", info->filename); - fprintf(stderr, "\targs: \"%s\"\n", info->args); + printf("\ttype: %s (version %d)\n", data->type, data->version); + printf("\tname: \"%s\"\n", info->name); + printf("\tfilename: \"%s\"\n", info->filename); + printf("\targs: \"%s\"\n", info->args); if (print_all) { print_properties(info->props, MARK_CHANGE(PW_MODULE_CHANGE_MASK_PROPS)); } @@ -273,37 +273,37 @@ print_all = true; if (data->first) { - fprintf(stderr, "added:\n"); + printf("added:\n"); print_mark = false; data->first = false; } else { - fprintf(stderr, "changed:\n"); + printf("changed:\n"); print_mark = true; } - fprintf(stderr, "\tid: %d\n", data->id); - fprintf(stderr, "\tpermissions: "PW_PERMISSION_FORMAT"\n", + printf("\tid: %d\n", data->id); + printf("\tpermissions: "PW_PERMISSION_FORMAT"\n", PW_PERMISSION_ARGS(data->permissions)); - fprintf(stderr, "\ttype: %s (version %d)\n", data->type, data->version); + printf("\ttype: %s (version %d)\n", data->type, data->version); if (print_all) { print_params(data, MARK_CHANGE(PW_NODE_CHANGE_MASK_PARAMS)); - with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS), stderr) { - fprintf(stderr, "\tinput ports: %u/%u\n", + with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS)) { + printf("\tinput ports: %u/%u\n", info->n_input_ports, info->max_input_ports); } - with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_OUTPUT_PORTS), stderr) { - fprintf(stderr, "\toutput ports: %u/%u\n", + with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_OUTPUT_PORTS)) { + printf("\toutput ports: %u/%u\n", info->n_output_ports, info->max_output_ports); } - with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_STATE), stderr) { - fprintf(stderr, "\tstate: \"%s\"", + with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_STATE)) { + printf("\tstate: \"%s\"", pw_node_state_as_string(info->state)); } if (info->state == PW_NODE_STATE_ERROR && info->error) - fprintf(stderr, " \"%s\"\n", info->error); + printf(" \"%s\"\n", info->error); else - fprintf(stderr, "\n"); + printf("\n"); print_properties(info->props, MARK_CHANGE(PW_NODE_CHANGE_MASK_PROPS)); } } @@ -346,21 +346,21 @@ print_all = true; if (data->first) { - fprintf(stderr, "added:\n"); + printf("added:\n"); print_mark = false; data->first = false; } else { - fprintf(stderr, "changed:\n"); + printf("changed:\n"); print_mark = true; } - fprintf(stderr, "\tid: %d\n", data->id); - fprintf(stderr, "\tpermissions: "PW_PERMISSION_FORMAT"\n", + printf("\tid: %d\n", data->id); + printf("\tpermissions: "PW_PERMISSION_FORMAT"\n", PW_PERMISSION_ARGS(data->permissions)); - fprintf(stderr, "\ttype: %s (version %d)\n", data->type, data->version); + printf("\ttype: %s (version %d)\n", data->type, data->version); - fprintf(stderr, "\tdirection: \"%s\"\n", pw_direction_as_string(info->direction)); + printf("\tdirection: \"%s\"\n", pw_direction_as_string(info->direction)); if (print_all) { print_params(data, MARK_CHANGE(PW_PORT_CHANGE_MASK_PARAMS)); print_properties(info->props, MARK_CHANGE(PW_PORT_CHANGE_MASK_PROPS)); @@ -405,23 +405,23 @@ print_all = true; if (data->info == NULL) { - fprintf(stderr, "added:\n"); + printf("added:\n"); print_mark = false; } else { - fprintf(stderr, "changed:\n"); + printf("changed:\n");
View file
pipewire-0.3.45.tar.gz/src/tools/pw-profiler.c -> pipewire-0.3.47.tar.gz/src/tools/pw-profiler.c
Changed
@@ -131,7 +131,7 @@ if (d->driver_id == 0) { d->driver_id = driver_id; - fprintf(stderr, "logging driver %u\n", driver_id); + printf("logging driver %u\n", driver_id); } else if (d->driver_id != driver_id) return -1; @@ -162,7 +162,7 @@ strncpy(d->followers[idx].name, name, MAX_NAME); d->followers[idx].name[MAX_NAME-1] = '\0'; d->followers[idx].id = id; - fprintf(stderr, "logging follower %u (\"%s\")\n", id, name); + printf("logging follower %u (\"%s\")\n", id, name); return idx; } @@ -243,7 +243,7 @@ d->last_status = point->clock.nsec; } else if (point->clock.nsec - d->last_status > SPA_NSEC_PER_SEC) { - fprintf(stderr, "logging %"PRIi64" samples %"PRIi64" seconds [CPU %f %f %f]\r", + printf("logging %"PRIi64" samples %"PRIi64" seconds [CPU %f %f %f]\r", d->count, (int64_t) ((d->last_status - d->start_status) / SPA_NSEC_PER_SEC), point->cpu_load[0], point->cpu_load[1], point->cpu_load[2]); d->last_status = point->clock.nsec; @@ -259,7 +259,7 @@ if (d->driver_id == 0) return; - fprintf(stderr, "\ndumping scripts for %d followers\n", d->n_followers); + printf("\ndumping scripts for %d followers\n", d->n_followers); out = fopen("Timing1.plot", "w"); if (out == NULL) { @@ -420,7 +420,7 @@ "gnuplot Timing5.plot\n"); fclose(out); } - fprintf(stderr, "run 'sh generate_timings.sh' and load Timings.html in a browser\n"); + printf("run 'sh generate_timings.sh' and load Timings.html in a browser\n"); } static void profiler_profile(void *data, const struct spa_pod *pod) @@ -487,7 +487,7 @@ if (proxy == NULL) goto error_proxy; - fprintf(stderr, "Attaching to Profiler id:%d\n", id); + printf("Attaching to Profiler id:%d\n", id); d->profiler = proxy; pw_proxy_add_object_listener(proxy, &d->profiler_listener, &profiler_events, d); @@ -539,9 +539,9 @@ pw_main_loop_quit(d->loop); } -static void show_help(const char *name) +static void show_help(const char *name, bool error) { - fprintf(stdout, "%s [options]\n" + fprintf(error ? stderr : stdout, "%s [options]\n" " -h, --help Show this help\n" " --version Show version\n" " -r, --remote Remote daemon name\n" @@ -570,10 +570,10 @@ while ((c = getopt_long(argc, argv, "hVr:o:", long_options, NULL)) != -1) { switch (c) { case 'h': - show_help(argv[0]); + show_help(argv[0], false); return 0; case 'V': - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", argv[0], @@ -587,7 +587,7 @@ opt_remote = optarg; break; default: - show_help(argv[0]); + show_help(argv[0], true); return -1; } } @@ -628,7 +628,7 @@ return -1; } - fprintf(stderr, "Logging to %s\n", data.filename); + printf("Logging to %s\n", data.filename); pw_core_add_listener(data.core, &data.core_listener, @@ -643,8 +643,13 @@ pw_main_loop_run(data.loop); - pw_proxy_destroy((struct pw_proxy*)data.profiler); + if (data.profiler) { + spa_hook_remove(&data.profiler_listener); + pw_proxy_destroy((struct pw_proxy*)data.profiler); + } + spa_hook_remove(&data.registry_listener); pw_proxy_destroy((struct pw_proxy*)data.registry); + spa_hook_remove(&data.core_listener); pw_context_destroy(data.context); pw_main_loop_destroy(data.loop);
View file
pipewire-0.3.45.tar.gz/src/tools/pw-reserve.c -> pipewire-0.3.47.tar.gz/src/tools/pw-reserve.c
Changed
@@ -50,24 +50,24 @@ static void reserve_acquired(void *data, struct rd_device *d) { - fprintf(stdout, "reserve acquired\n"); + printf("reserve acquired\n"); } static void reserve_release(void *data, struct rd_device *d, int forced) { struct impl *impl = data; - fprintf(stdout, "reserve release\n"); + printf("reserve release\n"); rd_device_complete_release(impl->device, true); } static void reserve_busy(void *data, struct rd_device *d, const char *name, int32_t prio) { - fprintf(stdout, "reserve busy %s, prio %d\n", name, prio); + printf("reserve busy %s, prio %d\n", name, prio); } static void reserve_available(void *data, struct rd_device *d, const char *name) { - fprintf(stdout, "reserve available %s\n", name); + printf("reserve available %s\n", name); } static const struct rd_device_callbacks reserve_callbacks = { @@ -86,9 +86,9 @@ #define DEFAULT_APPNAME "pw-reserve" #define DEFAULT_PRIORITY 0 -static void show_help(const char *name) +static void show_help(const char *name, bool error) { - fprintf(stdout, "%s [options]\n" + fprintf(error ? stderr : stdout, "%s [options]\n" " -h, --help Show this help\n" " --version Show version\n" " -n, --name Name to reserve (Audio0, Midi0, Video0, ..)\n" @@ -119,15 +119,17 @@ { NULL, 0, NULL, 0} }; + setlinebuf(stdout); + pw_init(&argc, &argv); while ((c = getopt_long(argc, argv, "hVn:a:p:m", long_options, NULL)) != -1) { switch (c) { case 'h': - show_help(argv[0]); + show_help(argv[0], false); return 0; case 'V': - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", argv[0], @@ -147,7 +149,7 @@ opt_monitor = true; break; default: - fprintf(stderr, "invalid option '%c'\n", c); + show_help(argv[0], true); return -1; } }
View file
pipewire-0.3.45.tar.gz/src/tools/pw-top.c -> pipewire-0.3.47.tar.gz/src/tools/pw-top.c
Changed
@@ -374,7 +374,7 @@ } } else if (spa_streq(type, PW_TYPE_INTERFACE_Profiler)) { if (d->profiler != NULL) { - fprintf(stderr, "Ignoring profiler %d: already attached\n", id); + printf("Ignoring profiler %d: already attached\n", id); return; } @@ -443,9 +443,9 @@ pw_main_loop_quit(d->loop); } -static void show_help(const char *name) +static void show_help(const char *name, bool error) { - fprintf(stdout, "%s [options]\n" + fprintf(error ? stderr : stdout, "%s [options]\n" " -h, --help Show this help\n" " --version Show version\n" " -r, --remote Remote daemon name\n", @@ -506,10 +506,10 @@ while ((c = getopt_long(argc, argv, "hVr:o:", long_options, NULL)) != -1) { switch (c) { case 'h': - show_help(argv[0]); + show_help(argv[0], false); return 0; case 'V': - fprintf(stdout, "%s\n" + printf("%s\n" "Compiled with libpipewire %s\n" "Linked with libpipewire %s\n", argv[0], @@ -520,7 +520,7 @@ opt_remote = optarg; break; default: - show_help(argv[0]); + show_help(argv[0], true); return -1; } } @@ -584,8 +584,13 @@ spa_list_consume(n, &data.node_list, link) remove_node(&data, n); - pw_proxy_destroy((struct pw_proxy*)data.profiler); + if (data.profiler) { + spa_hook_remove(&data.profiler_listener); + pw_proxy_destroy((struct pw_proxy*)data.profiler); + } + spa_hook_remove(&data.registry_listener); pw_proxy_destroy((struct pw_proxy*)data.registry); + spa_hook_remove(&data.core_listener); pw_context_destroy(data.context); pw_main_loop_destroy(data.loop);
View file
pipewire-0.3.45.tar.gz/test/meson.build -> pipewire-0.3.47.tar.gz/test/meson.build
Changed
@@ -75,6 +75,14 @@ link_with: pwtest_lib) ) +test('test-loop', + executable('test-loop', + 'test-loop.c', + include_directories: pwtest_inc, + dependencies: [ spa_dep ], + link_with: pwtest_lib) +) + test('test-context', executable('test-context', 'test-context.c',
View file
pipewire-0.3.45.tar.gz/test/pwtest-compat.c -> pipewire-0.3.47.tar.gz/test/pwtest-compat.c
Changed
@@ -24,7 +24,7 @@ #include "config.h" -#if !HAVE_SIGABBREV_NP +#ifndef HAVE_SIGABBREV_NP #include <stddef.h> #include <signal.h>
View file
pipewire-0.3.45.tar.gz/test/pwtest.c -> pipewire-0.3.47.tar.gz/test/pwtest.c
Changed
@@ -36,10 +36,10 @@ #include <stdio.h> #include <unistd.h> #include <signal.h> -#if HAVE_PIDFD_OPEN +#ifdef HAVE_PIDFD_OPEN #include <sys/syscall.h> #endif -#if HAVE_LIBCAP +#ifdef HAVE_LIBCAP #include <sys/capability.h> #endif #include <sys/epoll.h> @@ -177,7 +177,7 @@ static void pwtest_backtrace(pid_t p) { -#if HAVE_GSTACK +#ifdef HAVE_GSTACK char pid[11]; pid_t parent, child; int status; @@ -305,12 +305,14 @@ struct spa_handle **hnd; SPA_FOR_EACH_ELEMENT(plugin->handles, hnd) { - if (*hnd) + if (*hnd) { + spa_handle_clear(*hnd); free(*hnd); + } } SPA_FOR_EACH_ELEMENT(plugin->dlls, dll) { if (*dll) - dlclose(dll); + dlclose(*dll); } free(plugin); } @@ -362,12 +364,13 @@ r = spa_handle_factory_init(factory, handle, info, plugin->support, plugin->nsupport); pwtest_neg_errno_ok(r); if ((r = spa_handle_get_interface(handle, interface_name, &iface)) != 0) { - dlclose(hnd); + spa_handle_clear(handle); free(handle); + dlclose(hnd); return -ENOSYS; } - plugin->handles[plugin->ndlls++] = hnd; + plugin->dlls[plugin->ndlls++] = hnd; plugin->handles[plugin->nhandles++] = handle; plugin->support[plugin->nsupport++] = SPA_SUPPORT_INIT(interface_name, iface); @@ -820,7 +823,7 @@ size_t nevents = 0; int r; -#if HAVE_PIDFD_OPEN +#ifdef HAVE_PIDFD_OPEN pidfd = syscall(SYS_pidfd_open, pid, 0); #else errno = ENOSYS; @@ -1168,7 +1171,7 @@ static bool is_debugger_attached(void) { bool rc = false; -#if HAVE_LIBCAP +#ifdef HAVE_LIBCAP int status; int pid = fork();
View file
pipewire-0.3.45.tar.gz/test/test-context.c -> pipewire-0.3.47.tar.gz/test/test-context.c
Changed
@@ -233,7 +233,7 @@ SPA_TYPE_INTERFACE_Loop, SPA_TYPE_INTERFACE_LoopUtils, SPA_TYPE_INTERFACE_Log, -#if HAVE_DBUS +#ifdef HAVE_DBUS SPA_TYPE_INTERFACE_DBus, #endif SPA_TYPE_INTERFACE_CPU
View file
pipewire-0.3.45.tar.gz/test/test-lib.c -> pipewire-0.3.47.tar.gz/test/test-lib.c
Changed
@@ -44,6 +44,8 @@ pwtest_str_eq(headerversion, version_expected); pwtest_str_eq(libversion, version_expected); + pw_deinit(); + return PWTEST_PASS; }
View file
pipewire-0.3.47.tar.gz/test/test-loop.c
Added
@@ -0,0 +1,237 @@ +/* PipeWire + * + * Copyright © 2022 Wim Taymans <wim.taymans@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/eventfd.h> + +#include "pwtest.h" + +#include <pipewire/pipewire.h> + +struct obj { + int x; + struct spa_source source; +}; + +struct data { + struct pw_main_loop *ml; + struct pw_loop *l; + struct obj *a, *b; + int count; +}; + +static void on_event(struct spa_source *source) +{ + struct data *d = source->data; + + pw_loop_remove_source(d->l, &d->a->source); + pw_loop_remove_source(d->l, &d->b->source); + close(d->a->source.fd); + close(d->b->source.fd); + free(d->a); + free(d->b); + + pw_main_loop_quit(d->ml); +} + +PWTEST(pwtest_loop_destroy2) +{ + struct data data; + + pw_init(0, NULL); + + spa_zero(data); + data.ml = pw_main_loop_new(NULL); + pwtest_ptr_notnull(data.ml); + + data.l = pw_main_loop_get_loop(data.ml); + pwtest_ptr_notnull(data.l); + + data.a = calloc(1, sizeof(*data.a)); + data.b = calloc(1, sizeof(*data.b)); + + data.a->source.func = on_event; + data.a->source.fd = eventfd(0, 0); + data.a->source.mask = SPA_IO_IN; + data.a->source.data = &data; + data.b->source.func = on_event; + data.b->source.fd = eventfd(0, 0); + data.b->source.mask = SPA_IO_IN; + data.b->source.data = &data; + + pw_loop_add_source(data.l, &data.a->source); + pw_loop_add_source(data.l, &data.b->source); + + write(data.a->source.fd, &(uint64_t){1}, sizeof(uint64_t)); + write(data.b->source.fd, &(uint64_t){1}, sizeof(uint64_t)); + + pw_main_loop_run(data.ml); + pw_main_loop_destroy(data.ml); + + pw_deinit(); + + return PWTEST_PASS; +} + +static void +on_event_recurse1(struct spa_source *source) +{ + static bool first = true; + struct data *d = source->data; + uint64_t val; + + ++d->count; + pwtest_int_lt(d->count, 3); + + read(source->fd, &val, sizeof(val)); + + if (first) { + first = false; + pw_loop_enter(d->l); + pw_loop_iterate(d->l, -1); + pw_loop_leave(d->l); + } + pw_main_loop_quit(d->ml); +} + +PWTEST(pwtest_loop_recurse1) +{ + struct data data; + + pw_init(0, NULL); + + spa_zero(data); + data.ml = pw_main_loop_new(NULL); + pwtest_ptr_notnull(data.ml); + + data.l = pw_main_loop_get_loop(data.ml); + pwtest_ptr_notnull(data.l); + + data.a = calloc(1, sizeof(*data.a)); + data.b = calloc(1, sizeof(*data.b)); + + data.a->source.func = on_event_recurse1; + data.a->source.fd = eventfd(0, 0); + data.a->source.mask = SPA_IO_IN; + data.a->source.data = &data; + data.b->source.func = on_event_recurse1; + data.b->source.fd = eventfd(0, 0); + data.b->source.mask = SPA_IO_IN; + data.b->source.data = &data; + + pw_loop_add_source(data.l, &data.a->source); + pw_loop_add_source(data.l, &data.b->source); + + write(data.a->source.fd, &(uint64_t){1}, sizeof(uint64_t)); + write(data.b->source.fd, &(uint64_t){1}, sizeof(uint64_t)); + + pw_main_loop_run(data.ml); + pw_main_loop_destroy(data.ml); + + pw_deinit(); + + free(data.a); + free(data.b); + + return PWTEST_PASS; +} + +static void +on_event_recurse2(struct spa_source *source) +{ + static bool first = true; + struct data *d = source->data; + uint64_t val; + + ++d->count; + pwtest_int_lt(d->count, 3); + + read(source->fd, &val, sizeof(val)); + + if (first) { + first = false; + pw_loop_enter(d->l); + pw_loop_iterate(d->l, -1); + pw_loop_leave(d->l); + } else { + pw_loop_remove_source(d->l, &d->a->source); + pw_loop_remove_source(d->l, &d->b->source); + close(d->a->source.fd); + close(d->b->source.fd); + free(d->a); + free(d->b); + } + pw_main_loop_quit(d->ml); +} + +PWTEST(pwtest_loop_recurse2) +{ + struct data data; + + pw_init(0, NULL); + + spa_zero(data); + data.ml = pw_main_loop_new(NULL); + pwtest_ptr_notnull(data.ml);
View file
pipewire-0.3.45.tar.gz/test/test-pwtest.c -> pipewire-0.3.47.tar.gz/test/test-pwtest.c
Changed
@@ -32,7 +32,7 @@ PWTEST(compat_sigabbrev_np) { -#if !HAVE_SIGABBREV_NP +#ifndef HAVE_SIGABBREV_NP pwtest_str_eq(sigabbrev_np(SIGABRT), "ABRT"); pwtest_str_eq(sigabbrev_np(SIGSEGV), "SEGV"); pwtest_str_eq(sigabbrev_np(SIGSTOP), "STOP");
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.