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 6
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Mon Apr 4 15:18:29 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.49 + +------------------------------------------------------------------- Thu Mar 3 11:50:58 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.48
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.48 +Version: 0.3.49 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
pipewire-0.3.48.tar.gz/.gitignore -> pipewire-0.3.49.tar.gz/.gitignore
Changed
@@ -1,3 +1,4 @@ +.* .tarball-version .version .*.swp @@ -6,9 +7,6 @@ *.tar.gz *.tar.xz *.o -build/ -builddir/ -config.h.meson cscope.out cscope.in.out cscope.po.out
View file
pipewire-0.3.48.tar.gz/.gitlab-ci.yml -> pipewire-0.3.49.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-02-16.0' + FDO_DISTRIBUTION_TAG: '2022-03-05.0' FDO_DISTRIBUTION_VERSION: '35' FDO_DISTRIBUTION_PACKAGES: >- alsa-lib-devel @@ -66,6 +66,8 @@ ninja-build pkgconf python3-pip + pulseaudio-utils + openal-soft FDO_DISTRIBUTION_EXEC: >- pip3 install meson
View file
pipewire-0.3.48.tar.gz/Makefile.in -> pipewire-0.3.49.tar.gz/Makefile.in
Changed
@@ -17,6 +17,7 @@ run: all SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins \ + SPA_DATA_DIR=$(SOURCE_ROOT)/spa/plugins \ PIPEWIRE_MODULE_DIR=$(BUILD_ROOT)/src/modules \ PATH=$(BUILD_ROOT)/src/examples:$(PATH) \ PIPEWIRE_CONFIG_DIR=$(BUILD_ROOT)/src/daemon \ @@ -26,6 +27,7 @@ run-pulse: all SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins \ + SPA_DATA_DIR=$(SOURCE_ROOT)/spa/plugins \ PIPEWIRE_MODULE_DIR=$(BUILD_ROOT)/src/modules \ PIPEWIRE_CONFIG_DIR=$(BUILD_ROOT)/src/daemon \ ACP_PATHS_DIR=$(SOURCE_ROOT)/spa/plugins/alsa/mixer/paths \ @@ -46,11 +48,13 @@ monitor: all SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins \ + SPA_DATA_DIR=$(SOURCE_ROOT)/spa/plugins \ PIPEWIRE_MODULE_DIR=$(BUILD_ROOT)/src/modules/ \ $(BUILD_ROOT)/src/tools/pw-mon cli: all SPA_PLUGIN_DIR=$(BUILD_ROOT)/spa/plugins \ + SPA_DATA_DIR=$(SOURCE_ROOT)/spa/plugins \ PIPEWIRE_MODULE_DIR=$(BUILD_ROOT)/src/modules/ \ $(BUILD_ROOT)/src/tools/pw-cli
View file
pipewire-0.3.48.tar.gz/NEWS -> pipewire-0.3.49.tar.gz/NEWS
Changed
@@ -1,3 +1,77 @@ +# PipeWire 0.3.49 (2022-03-31) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + - Sample rate switching should work again. + - pw-dot can now use the output of pw-dump to render a graph. + - Bluetooth A2DP streaming was improved that would reduce stuttering on + some devices. + - A JACK bug was fixed that would sometimes make it impossible to add more + tracks in Ardour. (#1714) + - Many bugfixes and improvements. + +## PipeWire + - Fix a potential crash when NULL params were configured. + - Add some simple functional tests to avoid some recent regressions. Improve + the test framework for this as well. + - Improvements to the poll loop to avoid some use-after-free scenarios. + - Fix samplerate switching again. + - setlocale is not called anymore from the pipewire library. This should be + called by the application. (#2223) + - pw_init() and pw_deinit() can now be nested and called multiple times. + - pw_stream will now report the resampler delay in the pw_time.queued field. + +## modules + - module-filter-chain now supports arbitrary many properties and will use + property hints to assign them the right type. + - The ROC modules now accept a sink/source_properties parameter. + - The module-rt can now also be built without RT-Kit support. + - module-echo-cancel can now use a fraction to specify the delay for more + precise control. + +## SPA + - The channelmixer will now do upmixing by default and will not use + normalization. It will also use a simple upmixing algorithm that duplicates + channels by default. A more interesting upmix method is also available (PSD) + but needs to be enabled manually. (#861) + - Add SSE optimized (de)interleave functions for 32 bits samples with and + without byteswap. + - JSON parsing of empty strings will now give an invalid number instead of + 0. + - JSON numbers are now parsed and serialized in a locale independent way so + that , and . are not mixed up. + - The resampler will now report the resample delay and queued samples as the + extra delay. + +## tools + - pw-cat will read more dsf files correctly and will not crash at the end. + - pw-top now has a man page. + - pw-dot can now use the output of pw-dump to render a graph. + +## bluetooth + - Improve interactions with oFono. + - Fix recovery with slow connections. + - Improve frame size of AptX-ll. + - A2DP can now use any quantum and will flush packets in smaller chunks + when needed to adapt. This improves stuttering in some cases. + +## pulse-server + - The server configuration can now be placed in pulse.properties section, + which also makes it possible to have custom overrides. + - Implement FIX_ flags for capture as well. + - Small fixes and improvements in module loading. + +## JACK + - Clear the last error before executing a new action or else we could end up + with error from a previous action. This causes some problems in Ardour where + adding a track would fail after some time. (#1714) + + +Older versions: + + # PipeWire 0.3.48 (2022-03-03) This is a bugfix release that is API and ABI compatible with previous @@ -73,9 +147,6 @@ - Don't try to connect HSP/HFP when no backend is available. -Older versions: - - # PipeWire 0.3.47 (2022-02-18) This is a bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.48.tar.gz/README.md -> pipewire-0.3.49.tar.gz/README.md
Changed
@@ -189,7 +189,7 @@ ## Documentation -Find tutorials and design documentation [here](doc/index.md). +Find tutorials and design documentation [here](doc/index.dox). The (incomplete) autogenerated API docs are [here](https://docs.pipewire.org).
View file
pipewire-0.3.48.tar.gz/doc/dma-buf.dox -> pipewire-0.3.49.tar.gz/doc/dma-buf.dox
Changed
@@ -138,6 +138,15 @@ using a proper graphics API (such as EGL, Vulkan or VA-API) to process the DMA-BUFs. +# Size of DMA-BUFs + +When importing a DMA-BUF with a proper graphics API the size of a single buffer plane +is no relevant property since it will be derived by the driver from the other properties. +Therefore consumers should ignore the field `maxsize` of a `spa_data` and the field +`size` of a `spa_chunk` struct. Producers are allowed to set both to 0. +In cases where mapping a single plane is required the size should be obtained locally +via the filedescriptor. + # v4l2 Another use case for streaming via DMA-BUFs are exporting a camera feed from v4l2
View file
pipewire-0.3.48.tar.gz/man/meson.build -> pipewire-0.3.49.tar.gz/man/meson.build
Changed
@@ -17,6 +17,7 @@ 'pw-mididump.1.rst.in', 'pw-mon.1.rst.in', 'pw-profiler.1.rst.in', + 'pw-top.1.rst.in', ] if get_option('pipewire-jack').allowed()
View file
pipewire-0.3.49.tar.gz/man/pw-top.1.rst.in
Added
@@ -0,0 +1,82 @@ +pw-top +###### + +--------------------------- +The PipeWire process viewer +--------------------------- + +:Manual section: 1 +:Manual group: General Commands Manual + +SYNOPSIS +======== + +| **pw-top** [*options*] + +DESCRIPTION +=========== + +The *pw-top* program provides a dynamic real-time view of the pipewire +node and device statistics. + +The columns presented are as follows: + +S + Measurement status. + ! representing inactive - no connections + + Blank representing active + +ID + The ID of the pipewire node/device, as found in *pw-dump* + +QUANT + Current quantum at which the device/node is polled. + See https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/FAQ#pipewire-buffering-explained + +RATE + Sample rate used for communicating with this device/node. + +WAIT + +BUSY + +W/Q + Ratio of WAIT / QUANT. + +B/Q + Ratio of BUSY / QUANT + +ERR + Total of Xruns and Errors + +NAME + Name assigned to the device/node, as found in *pw-dump* node.name + + Names are prefixed by *+* when they are linked to a driver (entry above with no +) + + +OPTIONS +======= + +-h | --help + Show help. + +-r | --remote=NAME + The name the *remote* instance to monitor. If left unspecified, + a connection is made to the default PipeWire instance. + +--version + Show version information. + + +AUTHORS +======= + +The PipeWire Developers <@PACKAGE_BUGREPORT@>; PipeWire is available from @PACKAGE_URL@ + +SEE ALSO +======== + +``pipewire(1)``, +
View file
pipewire-0.3.48.tar.gz/meson.build -> pipewire-0.3.49.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', ['c' ], - version : '0.3.48', + version : '0.3.49', license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ], meson_version : '>= 0.59.0', default_options : [ 'warning_level=3',
View file
pipewire-0.3.48.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.49.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -298,7 +298,6 @@ int pending_sync; int last_sync; int last_res; - bool error; struct spa_node_info info; @@ -845,7 +844,6 @@ id, seq, res, spa_strerror(res), message); if (id == PW_ID_CORE) { - client->error = true; client->last_res = res; if (!client->destroyed) do_callback(client, shutdown_callback, client->shutdown_arg); @@ -867,9 +865,8 @@ pw_log_warn("sync requested from callback"); return 0; } - if (client->error) - return client->last_res; + client->last_res = 0; client->pending_sync = pw_proxy_sync((struct pw_proxy*)client->core, client->pending_sync); while (true) { @@ -881,7 +878,7 @@ if (in_data_thread && client->rt_locked) pthread_mutex_lock(&client->rt_lock); - if (client->error) + if (client->last_res < 0) return client->last_res; if (client->pending_sync == client->last_sync) @@ -3314,7 +3311,7 @@ while (true) { pw_thread_loop_wait(client->context.loop); - if (client->error) + if (client->last_res < 0) goto init_failed; if (client->has_transport)
View file
pipewire-0.3.48.tar.gz/po/pl.po -> pipewire-0.3.49.tar.gz/po/pl.po
Changed
@@ -1,15 +1,15 @@ # Polish translation for pipewire. -# Copyright © 2008-2021 the pipewire authors. +# Copyright © 2008-2022 the pipewire authors. # This file is distributed under the same license as the pipewire package. -# Piotr Drąg <piotrdrag@gmail.com>, 2008, 2012-2021. +# Piotr Drąg <piotrdrag@gmail.com>, 2008, 2012-2022. # msgid "" msgstr "" "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-10-09 15:35+0200\n" +"POT-Creation-Date: 2022-02-13 15:33+0000\n" +"PO-Revision-Date: 2022-03-13 12:05+0100\n" "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n" "Language-Team: Polish <community-poland@mozilla.org>\n" "Language: pl\n" @@ -41,43 +41,36 @@ msgid "Start the PipeWire Media System" msgstr "Uruchomienie systemu multimediów PipeWire" -#: src/examples/media-session/alsa-monitor.c:656 -#: spa/plugins/alsa/acp/compat.c:189 -msgid "Built-in Audio" -msgstr "Wbudowany dźwięk" - -#: 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 "Nieznane urządzenie" - -#: 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 "Tunel do %s/%s" -#: src/modules/module-pulse-tunnel.c:534 +#: src/modules/module-fallback-sink.c:51 +msgid "Dummy Output" +msgstr "Głuche wyjście" + +#: src/modules/module-pulse-tunnel.c:536 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunel dla %s@%s" -#: src/modules/module-zeroconf-discover.c:308 +#: src/modules/module-zeroconf-discover.c:332 +msgid "Unknown device" +msgstr "Nieznane urządzenie" + +#: src/modules/module-zeroconf-discover.c:344 #, c-format msgid "%s on %s@%s" msgstr "%s na %s@%s" -#: src/modules/module-zeroconf-discover.c:312 +#: src/modules/module-zeroconf-discover.c:348 #, c-format msgid "%s on %s" msgstr "%s na %s" -#: src/tools/pw-cat.c:1055 +#: src/tools/pw-cat.c:1075 #, c-format msgid "" "%s [options] <file>\n" @@ -92,7 +85,7 @@ " -v, --verbose Wyświetla więcej komunikatów\n" "\n" -#: src/tools/pw-cat.c:1062 +#: src/tools/pw-cat.c:1082 #, c-format msgid "" " -R, --remote Remote daemon name\n" @@ -130,7 +123,7 @@ "docelowych dla --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 " @@ -166,7 +159,7 @@ "(domyślnie %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" @@ -180,7 +173,7 @@ " -d, --dsd Tryb DSD\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 Nazwa zdalnej usługi\n" "\n" -#: spa/plugins/alsa/acp/acp.c:310 +#: spa/plugins/alsa/acp/acp.c:321 msgid "Pro Audio" msgstr "Dźwięk w zastosowaniach profesjonalnych" -#: 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 "Wyłączone" @@ -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 "Brak podbicia basów" #: 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 "Głośnik" @@ -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 "Słuchawki z mikrofonem" @@ -623,65 +616,73 @@ "Prawdopodobnie jest to błąd sterownika ALSA „%s”. Proszę zgłosić ten problem " "programistom usługi ALSA." -#: spa/plugins/alsa/acp/channelmap.h:466 +#: spa/plugins/alsa/acp/channelmap.h:464 msgid "(invalid)" msgstr "(nieprawidłowe)" -#: spa/plugins/bluez5/bluez5-device.c:1145 +#: spa/plugins/alsa/acp/compat.c:189 +msgid "Built-in Audio" +msgstr "Wbudowany dźwięk" + +#: spa/plugins/alsa/acp/compat.c:194 +msgid "Modem" +msgstr "Modem" + +#: spa/plugins/bluez5/bluez5-device.c:1170 msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" msgstr "Bramka dźwięku (źródło A2DP i AG HSP/HFP)" -#: spa/plugins/bluez5/bluez5-device.c:1168 +#: spa/plugins/bluez5/bluez5-device.c:1195 #, c-format msgid "High Fidelity Playback (A2DP Sink, codec %s)" msgstr "Odtwarzanie o wysokiej dokładności (odpływ A2DP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1171 +#: spa/plugins/bluez5/bluez5-device.c:1198 #, c-format msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" msgstr "Dupleks o wysokiej dokładności (źródło/odpływ A2DP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1178 +#: spa/plugins/bluez5/bluez5-device.c:1206 msgid "High Fidelity Playback (A2DP Sink)" msgstr "Odtwarzanie o wysokiej dokładności (odpływ A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:1180 +#: spa/plugins/bluez5/bluez5-device.c:1208 msgid "High Fidelity Duplex (A2DP Source/Sink)" msgstr "Dupleks o wysokiej dokładności (źródło/odpływ A2DP)"
View file
pipewire-0.3.48.tar.gz/spa/include/spa/debug/format.h -> pipewire-0.3.49.tar.gz/spa/include/spa/debug/format.h
Changed
@@ -69,7 +69,7 @@ spa_debugn("%f", *(float *) body); break; case SPA_TYPE_Double: - spa_debugn("%g", *(double *) body); + spa_debugn("%f", *(double *) body); break; case SPA_TYPE_String: spa_debugn("%s", (char *) body);
View file
pipewire-0.3.48.tar.gz/spa/include/spa/utils/hook.h -> pipewire-0.3.49.tar.gz/spa/include/spa/utils/hook.h
Changed
@@ -261,8 +261,10 @@ * The below (pseudo)code is a minimal example outlining the use of hooks: * \code{.c} * // the public interface + * #define VERSION_BAR_EVENTS 0 // version of the vtable * struct bar_events { - * uint32_t version; + * uint32_t version; // NOTE: an integral member named `version` + * // must be present in the vtable * void (*boom)(void *data, const char *msg); * }; * @@ -272,17 +274,23 @@ * }; * * void party_add_event_listener(struct party *p, struct spa_hook *listener, - * struct bar_events *events, void *data) + * const struct bar_events *events, void *data) * { * spa_hook_list_append(&p->bar_list, listener, events, data); * } * * static void party_on(struct party *p) * { - * spa_hook_list_call(&p->list, struct bar_events, - * boom, // function name - * 0 // hardcoded version, - * "party on, wayne"); + * // NOTE: this is a macro, it evaluates to an integer, + * // which is the number of hooks called + * spa_hook_list_call(&p->list, + * struct bar_events, // vtable type + * boom, // function name + * 0, // hardcoded version, + * // usually the version in which `boom` + * // has been added to the vtable + * "party on, wayne" // function argument(s) + * ); * } * \endcode * @@ -293,7 +301,8 @@ * printf("%s", msg); * } * - * static const struct bar_events { + * static const struct bar_events events = { + * .version = VERSION_BAR_EVENTS, // version of the implemented interface * .boom = boom_cb, * }; * @@ -302,7 +311,7 @@ * struct spa_hook hook; * struct party *p = start_the_party(); * - * party_add_event_listener(p, &hook, boom_cb, userdata); + * party_add_event_listener(p, &hook, &events, userdata); * * mainloop(); * return 0;
View file
pipewire-0.3.48.tar.gz/spa/include/spa/utils/json.h -> pipewire-0.3.49.tar.gz/spa/include/spa/utils/json.h
Changed
@@ -34,8 +34,11 @@ #include <stdlib.h> #include <stdint.h> #include <string.h> +#include <math.h> +#include <float.h> #include <spa/utils/defs.h> +#include <spa/utils/string.h> /** \defgroup spa_json JSON * Relaxed JSON variant parsing @@ -237,9 +240,10 @@ static inline int spa_json_parse_float(const char *val, int len, float *result) { char *end; - *result = strtof(val, &end); - return end == val + len; + *result = spa_strtof(val, &end); + return len > 0 && end == val + len; } + static inline bool spa_json_is_float(const char *val, int len) { float dummy; @@ -254,12 +258,25 @@ return spa_json_parse_float(value, len, res); } +static inline char *spa_json_format_float(char *str, int size, float val) +{ + if (SPA_UNLIKELY(!isnormal(val))) { + if (val == INFINITY) + val = FLT_MAX; + else if (val == -INFINITY) + val = FLT_MIN; + else + val = 0.0f; + } + return spa_dtoa(str, size, val); +} + /* int */ static inline int spa_json_parse_int(const char *val, int len, int *result) { char *end; *result = strtol(val, &end, 0); - return end == val + len; + return len > 0 && end == val + len; } static inline bool spa_json_is_int(const char *val, int len) {
View file
pipewire-0.3.48.tar.gz/spa/include/spa/utils/string.h -> pipewire-0.3.49.tar.gz/spa/include/spa/utils/string.h
Changed
@@ -32,6 +32,8 @@ #include <stdarg.h> #include <stdbool.h> #include <errno.h> +#include <stdlib.h> +#include <locale.h> #include <spa/utils/defs.h> @@ -264,6 +266,27 @@ } /** + * Convert \a str to a float in the C locale. + * + * If \a endptr is not NULL, a pointer to the character after the last character + * used in the conversion is stored in the location referenced by endptr. + * + * \return the result float. + */ +static inline float spa_strtof(const char *str, char **endptr) +{ + static locale_t locale = NULL; + float v; + if (SPA_UNLIKELY(locale == NULL)) + locale = newlocale(LC_ALL_MASK, "C", NULL); + if (locale != NULL) + v = strtof_l(str, endptr, locale); + else + v = strtof(str, endptr); + return v; +} + +/** * Convert \a str to a float and store the result in \a val. * * On failure, the value of \a val is unmodified. @@ -277,9 +300,8 @@ if (!str || *str =='\0') return false; - errno = 0; - v = strtof(str, &endptr); + v = spa_strtof(str, &endptr); if (errno != 0 || *endptr != '\0') return false; @@ -288,6 +310,27 @@ } /** + * Convert \a str to a double in the C locale. + * + * If \a endptr is not NULL, a pointer to the character after the last character + * used in the conversion is stored in the location referenced by endptr. + * + * \return the result float. + */ +static inline double spa_strtod(const char *str, char **endptr) +{ + static locale_t locale = NULL; + double v; + if (SPA_UNLIKELY(locale == NULL)) + locale = newlocale(LC_ALL_MASK, "C", NULL); + if (locale != NULL) + v = strtod_l(str, endptr, locale); + else + v = strtod(str, endptr); + return v; +} + +/** * Convert \a str to a double and store the result in \a val. * * On failure, the value of \a val is unmodified. @@ -303,7 +346,7 @@ return false; errno = 0; - v = strtod(str, &endptr); + v = spa_strtod(str, &endptr); if (errno != 0 || *endptr != '\0') return false; @@ -311,6 +354,16 @@ return true; } +static inline char *spa_dtoa(char *str, size_t size, double val) +{ + int i, l; + l = spa_scnprintf(str, size, "%f", val); + for (i = 0; i < l; i++) + if (str[i] == ',') + str[i] = '.'; + return str; +} + /** * \} */
View file
pipewire-0.3.48.tar.gz/spa/plugins/aec/aec-null.c -> pipewire-0.3.49.tar.gz/spa/plugins/aec/aec-null.c
Changed
@@ -151,7 +151,7 @@ return 1; } -const struct spa_handle_factory spa_aec_exaudio_factory = { +const struct spa_handle_factory spa_aec_null_factory = { SPA_VERSION_HANDLE_FACTORY, SPA_NAME_AEC, NULL, @@ -169,7 +169,7 @@ switch (*index) { case 0: - *factory = &spa_aec_exaudio_factory; + *factory = &spa_aec_null_factory; break; default: return 0;
View file
pipewire-0.3.48.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.49.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Changed
@@ -250,7 +250,7 @@ return 1; } -const struct spa_handle_factory spa_aec_exaudio_factory = { +const struct spa_handle_factory spa_aec_webrtc_factory = { SPA_VERSION_HANDLE_FACTORY, SPA_NAME_AEC, NULL, @@ -268,7 +268,7 @@ switch (*index) { case 0: - *factory = &spa_aec_exaudio_factory; + *factory = &spa_aec_webrtc_factory; break; default: return 0;
View file
pipewire-0.3.48.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.49.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
@@ -160,7 +160,7 @@ SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_latencyOffsetNsec), SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, INT64_MAX)); + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, 2 * SPA_NSEC_PER_SEC)); break; case 4: if (!this->is_iec958 && !this->is_hdmi) @@ -310,20 +310,18 @@ case SPA_PARAM_Props: { struct props *p = &this->props; - struct spa_process_latency_info info; struct spa_pod *iec958_codecs = NULL, *params = NULL; + int64_t lat_ns = -1; if (param == NULL) { reset_props(p); return 0; } - info = this->process_latency; - spa_pod_parse_object(param, SPA_TYPE_OBJECT_Props, NULL, SPA_PROP_device, SPA_POD_OPT_Stringn(p->device, sizeof(p->device)), - SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&info.ns), + SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&lat_ns), SPA_PROP_iec958Codecs, SPA_POD_OPT_Pod(&iec958_codecs), SPA_PROP_params, SPA_POD_OPT_Pod(¶ms)); @@ -342,8 +340,12 @@ this->port_params[PORT_EnumFormat].user++; } spa_alsa_parse_prop_params(this, params); - handle_process_latency(this, &info); - + if (lat_ns != -1) { + struct spa_process_latency_info info; + info = this->process_latency; + info.ns = lat_ns; + handle_process_latency(this, &info); + } emit_node_info(this, false); emit_port_info(this, false); break;
View file
pipewire-0.3.48.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.49.tar.gz/spa/plugins/alsa/alsa-pcm-source.c
Changed
@@ -160,7 +160,7 @@ SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_latencyOffsetNsec), SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, INT64_MAX)); + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, 2 * SPA_NSEC_PER_SEC)); break; default: param = spa_alsa_enum_propinfo(this, result.index - 4, &b); @@ -290,24 +290,27 @@ case SPA_PARAM_Props: { struct props *p = &this->props; - struct spa_process_latency_info info; struct spa_pod *params = NULL; + int64_t lat_ns = -1; if (param == NULL) { reset_props(p); return 0; } - info = this->process_latency; - spa_pod_parse_object(param, SPA_TYPE_OBJECT_Props, NULL, SPA_PROP_device, SPA_POD_OPT_Stringn(p->device, sizeof(p->device)), - SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&info.ns), + SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&lat_ns), SPA_PROP_params, SPA_POD_OPT_Pod(¶ms)); spa_alsa_parse_prop_params(this, params); - handle_process_latency(this, &info); + if (lat_ns != -1) { + struct spa_process_latency_info info; + info = this->process_latency; + info.ns = lat_ns; + handle_process_latency(this, &info); + } emit_node_info(this, false); emit_port_info(this, false);
View file
pipewire-0.3.48.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.49.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -237,7 +237,7 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("api.alsa.period-size"), SPA_PROP_INFO_description, SPA_POD_String("Period Size"), - SPA_PROP_INFO_type, SPA_POD_Int(state->default_period_size), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->default_period_size, 0, 8192), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 6: @@ -245,7 +245,7 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("api.alsa.period-num"), SPA_PROP_INFO_description, SPA_POD_String("Number of Periods"), - SPA_PROP_INFO_type, SPA_POD_Int(state->default_period_num), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->default_period_num, 0, 1024), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 7: @@ -253,7 +253,7 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("api.alsa.headroom"), SPA_PROP_INFO_description, SPA_POD_String("Headroom"), - SPA_PROP_INFO_type, SPA_POD_Int(state->default_headroom), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->default_headroom, 0, 8192), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 8: @@ -261,7 +261,7 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("api.alsa.start-delay"), SPA_PROP_INFO_description, SPA_POD_String("Start Delay"), - SPA_PROP_INFO_type, SPA_POD_Int(state->default_start_delay), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->default_start_delay, 0, 8192), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 9: @@ -269,7 +269,7 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("api.alsa.disable-mmap"), SPA_PROP_INFO_description, SPA_POD_String("Disable MMAP"), - SPA_PROP_INFO_type, SPA_POD_Bool(state->disable_mmap), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(state->disable_mmap), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 10: @@ -277,7 +277,7 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("api.alsa.disable-batch"), SPA_PROP_INFO_description, SPA_POD_String("Disable Batch"), - SPA_PROP_INFO_type, SPA_POD_Bool(state->disable_batch), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(state->disable_batch), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 11: @@ -285,7 +285,7 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("api.alsa.use-chmap"), SPA_PROP_INFO_description, SPA_POD_String("Use the driver channelmap"), - SPA_PROP_INFO_type, SPA_POD_Bool(state->props.use_chmap), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(state->props.use_chmap), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 12: @@ -293,7 +293,7 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("api.alsa.multi-rate"), SPA_PROP_INFO_description, SPA_POD_String("Support multiple rates"), - SPA_PROP_INFO_type, SPA_POD_Bool(state->multi_rate), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(state->multi_rate), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 13: @@ -301,7 +301,8 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("latency.internal.rate"), SPA_PROP_INFO_description, SPA_POD_String("Internal latency in samples"), - SPA_PROP_INFO_type, SPA_POD_Int(state->process_latency.rate), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(state->process_latency.rate, + 0, 65536), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 14: @@ -309,7 +310,8 @@ SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("latency.internal.ns"), SPA_PROP_INFO_description, SPA_POD_String("Internal latency in nanoseconds"), - SPA_PROP_INFO_type, SPA_POD_Long(state->process_latency.ns), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(state->process_latency.ns, + 0, 2 * SPA_NSEC_PER_SEC), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; case 15: @@ -429,7 +431,7 @@ } else continue; - spa_log_debug(state->log, "key:'%s' val:'%s'", name, value); + spa_log_info(state->log, "key:'%s' val:'%s'", name, value); alsa_set_param(state, name, value); changed++; }
View file
pipewire-0.3.48.tar.gz/spa/plugins/alsa/test-timer.c -> pipewire-0.3.49.tar.gz/spa/plugins/alsa/test-timer.c
Changed
@@ -25,6 +25,7 @@ #include <stdio.h> #include <stdbool.h> #include <limits.h> +#include <getopt.h> #include <math.h> #include <sys/timerfd.h> @@ -42,6 +43,8 @@ #define BW_PERIOD (NSEC_PER_SEC * 3) struct state { + const char *device; + unsigned int format; unsigned int rate; unsigned int channels; snd_pcm_uframes_t period; @@ -77,27 +80,39 @@ } \ } +#define LOOP(type,areas,scale) { \ + uint32_t i, j; \ + type *samples, v; \ + samples = (type*)((uint8_t*)areas[0].addr + (areas[0].first + offset*areas[0].step) / 8); \ + for (i = 0; i < frames; i++) { \ + state->accumulator += M_PI_M2 * 440 / state->rate; \ + if (state->accumulator >= M_PI_M2) \ + state->accumulator -= M_PI_M2; \ + v = sin(state->accumulator) * scale; \ + for (j = 0; j < state->channels; j++) \ + *samples++ = v; \ + } \ +} + static int write_period(struct state *state) { snd_pcm_uframes_t frames = state->period; snd_pcm_uframes_t offset; const snd_pcm_channel_area_t* areas; - uint32_t i, j; - int32_t *samples, v; snd_pcm_mmap_begin(state->hndl, &areas, &offset, &frames); - samples = (int32_t*)((uint8_t*)areas[0].addr + (areas[0].first + offset*areas[0].step) / 8); - - for (i = 0; i < frames; i++) { - state->accumulator += M_PI_M2 * 440 / state->rate; - if (state->accumulator >= M_PI_M2) - state->accumulator -= M_PI_M2; - v = sin(state->accumulator) * 0x7fffffff; - - for (j = 0; j < state->channels; j++) - *samples++ = v; + switch (state->format) { + case SND_PCM_FORMAT_S32_LE: + LOOP(int32_t, areas, 0x7fffffff); + break; + case SND_PCM_FORMAT_S16_LE: + LOOP(int16_t, areas, 0x7fff); + break; + default: + break; } + snd_pcm_mmap_commit(state->hndl, offset, frames) ; return 0; @@ -156,27 +171,89 @@ return 0; } +static unsigned int format_from_string(const char *str) +{ + if (strcmp(str, "S32_LE") == 0) + return SND_PCM_FORMAT_S32_LE; + else if (strcmp(str, "S32_BE") == 0) + return SND_PCM_FORMAT_S32_BE; + else if (strcmp(str, "S24_LE") == 0) + return SND_PCM_FORMAT_S24_LE; + else if (strcmp(str, "S24_BE") == 0) + return SND_PCM_FORMAT_S24_BE; + else if (strcmp(str, "S24_3LE") == 0) + return SND_PCM_FORMAT_S24_3LE; + else if (strcmp(str, "S24_3_BE") == 0) + return SND_PCM_FORMAT_S24_3BE; + else if (strcmp(str, "S16_LE") == 0) + return SND_PCM_FORMAT_S16_LE; + else if (strcmp(str, "S16_BE") == 0) + return SND_PCM_FORMAT_S16_BE; + return 0; +} + +static void show_help(const char *name, bool error) +{ + fprintf(error ? stderr : stdout, "%s [options]\n" + " -h, --help Show this help\n" + " -D, --device device name (default %s)\n", + name, DEFAULT_DEVICE); +} + int main(int argc, char *argv[]) { 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); - + char c; + static const struct option long_options[] = { + { "help", no_argument, NULL, 'h' }, + { "device", required_argument, NULL, 'D' }, + { "format", required_argument, NULL, 'f' }, + { "rate", required_argument, NULL, 'r' }, + { "channels", required_argument, NULL, 'c' }, + { NULL, 0, NULL, 0} + }; + state.device = DEFAULT_DEVICE; + state.format = SND_PCM_FORMAT_S16_LE; state.rate = 44100; state.channels = 2; state.period = 1024; + while ((c = getopt_long(argc, argv, "hD:f:r:c:", long_options, NULL)) != -1) { + switch (c) { + case 'h': + show_help(argv[0], false); + return 0; + case 'D': + state.device = optarg; + break; + case 'f': + state.format = format_from_string(optarg); + break; + case 'r': + state.rate = atoi(optarg); + break; + case 'c': + state.channels = atoi(optarg); + break; + default: + show_help(argv[0], true); + return -1; + } + } + + CHECK(snd_pcm_open(&state.hndl, state.device, SND_PCM_STREAM_PLAYBACK, 0), + "open %s failed", state.device); + /* hw params */ snd_pcm_hw_params_alloca(&hparams); snd_pcm_hw_params_any(state.hndl, hparams); CHECK(snd_pcm_hw_params_set_access(state.hndl, hparams, SND_PCM_ACCESS_MMAP_INTERLEAVED), "set interleaved"); CHECK(snd_pcm_hw_params_set_format(state.hndl, hparams, - SND_PCM_FORMAT_S32_LE), "set format"); + state.format), "set format"); CHECK(snd_pcm_hw_params_set_channels_near(state.hndl, hparams, &state.channels), "set channels"); CHECK(snd_pcm_hw_params_set_rate_near(state.hndl, hparams, @@ -186,7 +263,7 @@ 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), + snd_pcm_format_name(state.format), state.rate, state.channels); snd_pcm_sw_params_alloca(&sparams);
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
@@ -542,7 +542,6 @@ res = spa_pod_parse_object(format, SPA_TYPE_OBJECT_Format, NULL, SPA_FORMAT_AUDIO_format, SPA_POD_OPT_Id(&info->format), - SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels), SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position)); if (position == NULL ||
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops-c.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/channelmix-ops-c.c
Changed
@@ -246,6 +246,16 @@ for (i = 0; i < n_dst; i++) memset(d[i], 0, n_samples * sizeof(float)); } + else if (mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { + for (n = 0; n < n_samples; n++) { + float c = s[0][n] + s[1][n]; + d[0][n] = s[0][n] * v0; + d[1][n] = s[1][n] * v1; + d[2][n] = c * v2; + d[3][n] = c; + } + lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples); + } else if (v0 == 1.0f && v1 == 1.0f) { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; @@ -289,6 +299,18 @@ for (i = 0; i < n_dst; i++) memset(d[i], 0, n_samples * sizeof(float)); } + else if (mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { + for (n = 0; n < n_samples; n++) { + float c = s[0][n] + s[1][n]; + d[0][n] = s[0][n] * v0; + d[1][n] = s[1][n] * v1; + d[2][n] = c * v2; + d[3][n] = c; + d[4][n] = s[0][n] * v4; + d[5][n] = s[1][n] * v5; + } + lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples); + } else if (v0 == 1.0f && v1 == 1.0f) { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; @@ -347,6 +369,20 @@ for (i = 0; i < n_dst; i++) memset(d[i], 0, n_samples * sizeof(float)); } + else if (mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { + for (n = 0; n < n_samples; n++) { + float c = s[0][n] + s[1][n]; + d[0][n] = s[0][n] * v0; + d[1][n] = s[1][n] * v1; + d[2][n] = c * v2; + d[3][n] = c; + d[4][n] = s[0][n] * v4; + d[5][n] = s[1][n] * v5; + d[6][n] = s[0][n] * v6; + d[7][n] = s[1][n] * v7; + } + lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples); + } else if (v0 == 1.0f && v1 == 1.0f && v4 == 1.0f && v5 == 1.0f) { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n];
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/channelmix-ops.c
Changed
@@ -210,7 +210,8 @@ unassigned = src_mask & ~dst_mask; keep = dst_mask & ~src_mask; - if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX)) + if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX) || + mix->upmix == CHANNELMIX_UPMIX_NONE) keep = 0; keep |= FRONT;
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix-ops.h -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/channelmix-ops.h
Changed
@@ -26,6 +26,7 @@ #include <stdio.h> #include <spa/utils/defs.h> +#include <spa/utils/string.h> #include <spa/param/audio/raw.h> #undef SPA_LOG_TOPIC_DEFAULT @@ -61,6 +62,10 @@ #define CHANNELMIX_OPTION_NORMALIZE (1<<1) /**< normalize volumes */ #define CHANNELMIX_OPTION_UPMIX (1<<2) /**< do simple upmixing */ uint32_t options; +#define CHANNELMIX_UPMIX_NONE (0) /**< disable upmixing */ +#define CHANNELMIX_UPMIX_SIMPLE (1) /**< simple upmixing */ +#define CHANNELMIX_UPMIX_PSD (2) /**< Passive Surround Decoding upmixing */ + uint32_t upmix; struct spa_log *log; @@ -97,6 +102,26 @@ int channelmix_init(struct channelmix *mix); +static const struct channelmix_upmix_info { + const char *label; + const char *description; + uint32_t upmix; +} channelmix_upmix_info[] = { + [CHANNELMIX_UPMIX_NONE] = { "none", "Disabled", CHANNELMIX_UPMIX_NONE }, + [CHANNELMIX_UPMIX_SIMPLE] = { "simple", "Simple upmixing", CHANNELMIX_UPMIX_SIMPLE }, + [CHANNELMIX_UPMIX_PSD] = { "psd", "Passive Surround Decoding", CHANNELMIX_UPMIX_PSD } +}; + +static inline uint32_t channelmix_upmix_from_label(const char *label) +{ + uint32_t i; + for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) { + if (spa_streq(channelmix_upmix_info[i].label, label)) + return channelmix_upmix_info[i].upmix; + } + return CHANNELMIX_UPMIX_NONE; +} + #define channelmix_process(mix,...) (mix)->process(mix, __VA_ARGS__) #define channelmix_set_volume(mix,...) (mix)->set_volume(mix, __VA_ARGS__) #define channelmix_free(mix) (mix)->free(mix)
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/channelmix.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/channelmix.c
Changed
@@ -292,7 +292,8 @@ { struct volumes *vol; - if (this->mix.set_volume == NULL) + if (this->mix.set_volume == NULL || + this->props.disabled) return; if (this->props.have_soft_volume) @@ -545,6 +546,31 @@ this->mix.hilbert_taps, 0, MAX_TAPS), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; + case 17: + { + struct spa_pod_frame f[2]; + uint32_t i; + spa_pod_builder_push_object(&b, &f[0], + SPA_TYPE_OBJECT_PropInfo, id); + spa_pod_builder_add(&b, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix-method"), + SPA_PROP_INFO_description, SPA_POD_String("Upmix Method to use"), + SPA_PROP_INFO_type, SPA_POD_String( + channelmix_upmix_info[this->mix.upmix].label), + 0); + spa_pod_builder_prop(&b, SPA_PROP_INFO_labels, 0); + spa_pod_builder_push_struct(&b, &f[1]); + for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) { + spa_pod_builder_string(&b, channelmix_upmix_info[i].label); + spa_pod_builder_string(&b, channelmix_upmix_info[i].description); + } + spa_pod_builder_pop(&b, &f[1]); + spa_pod_builder_add(&b, + SPA_PROP_INFO_params, SPA_POD_Bool(true), + 0); + param = spa_pod_builder_pop(&b, &f[0]); + break; + } default: return 0; } @@ -604,6 +630,8 @@ spa_pod_builder_float(&b, this->mix.widen); spa_pod_builder_string(&b, "channelmix.hilbert-taps"); spa_pod_builder_int(&b, this->mix.hilbert_taps); + spa_pod_builder_string(&b, "channelmix.upmix-method"); + spa_pod_builder_string(&b, channelmix_upmix_info[this->mix.upmix].label); spa_pod_builder_pop(&b, &f[1]); param = spa_pod_builder_pop(&b, &f[0]); break; @@ -647,6 +675,8 @@ spa_atof(s, &this->mix.widen); else if (spa_streq(k, "channelmix.hilbert-taps")) spa_atou32(s, &this->mix.hilbert_taps, 0); + else if (spa_streq(k, "channelmix.upmix-method")) + this->mix.upmix = channelmix_upmix_from_label(s); else return 0; return 1; @@ -665,7 +695,7 @@ while (true) { const char *name; struct spa_pod *pod; - char value[512]; + char value[512], buf[128]; if (spa_pod_parser_get_string(&prs, &name) < 0) break; @@ -676,8 +706,9 @@ if (spa_pod_is_string(pod)) { spa_pod_copy_string(pod, sizeof(value), value); } else if (spa_pod_is_float(pod)) { - snprintf(value, sizeof(value), "%f", - SPA_POD_VALUE(struct spa_pod_float, pod)); + snprintf(value, sizeof(value), "%s", + spa_json_format_float(buf, sizeof(buf), + SPA_POD_VALUE(struct spa_pod_float, pod))); } else if (spa_pod_is_int(pod)) { snprintf(value, sizeof(value), "%d", SPA_POD_VALUE(struct spa_pod_int, pod)); @@ -691,7 +722,7 @@ spa_log_info(this->log, "key:'%s' val:'%s'", name, value); changed += channelmix_set_param(this, name, value); } - if (changed) + if (changed && !this->props.disabled) channelmix_init(&this->mix); return changed; } @@ -709,9 +740,6 @@ if (param == NULL) return 0; - if (this->props.disabled) - return 0; - SPA_POD_OBJECT_FOREACH(obj, prop) { switch (prop->key) { case SPA_PROP_volume: @@ -771,6 +799,7 @@ break; } } + if (changed) { struct port *port = GET_PORT(this, this->direction, 0); if (have_soft_volume) @@ -780,6 +809,7 @@ if (port->have_format) remap_volumes(this, &port->format); + set_volume(this); } return changed; @@ -794,9 +824,6 @@ if (size < 3) return -EINVAL; - if (this->props.disabled) - return 0; - if ((val[0] & 0xf0) != 0xb0 || val[1] != 7) return 0; @@ -1627,9 +1654,13 @@ props_reset(&this->props); - this->mix.options = CHANNELMIX_OPTION_NORMALIZE; + this->mix.options = CHANNELMIX_OPTION_UPMIX; + this->mix.upmix = CHANNELMIX_UPMIX_SIMPLE; this->mix.log = this->log; + this->mix.lfe_cutoff = 120.0f; + this->mix.fc_cutoff = 6000.0f; this->mix.rear_delay = 12.0f; + this->mix.widen = 0.1f; for (i = 0; info && i < info->n_items; i++) { const char *k = info->items[i].key;
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/fmt-ops-sse2.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/fmt-ops-sse2.c
Changed
@@ -544,6 +544,354 @@ } static void +conv_interleave_32_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], + uint32_t n_channels, uint32_t n_samples) +{ + const int32_t *s0 = src[0]; + int32_t *d = dst; + uint32_t n, unrolled; + __m128i out[4]; + + if (SPA_IS_ALIGNED(s0, 16)) + unrolled = n_samples & ~3; + else + unrolled = 0; + + for(n = 0; n < unrolled; n += 4) { + out[0] = _mm_load_si128((__m128i*)&s0[n]); + out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1)); + out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2)); + out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3)); + + d[0*n_channels] = _mm_cvtsi128_si32(out[0]); + d[1*n_channels] = _mm_cvtsi128_si32(out[1]); + d[2*n_channels] = _mm_cvtsi128_si32(out[2]); + d[3*n_channels] = _mm_cvtsi128_si32(out[3]); + d += 4*n_channels; + } + for(; n < n_samples; n++) { + *d = s0[n]; + d += n_channels; + } +} +static void +conv_interleave_32_4s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], + uint32_t n_channels, uint32_t n_samples) +{ + const float *s0 = src[0], *s1 = src[1], *s2 = src[2], *s3 = src[3]; + float *d = dst; + uint32_t n, unrolled; + __m128 out[4]; + + if (SPA_IS_ALIGNED(s0, 16) && + SPA_IS_ALIGNED(s1, 16) && + SPA_IS_ALIGNED(s2, 16) && + SPA_IS_ALIGNED(s3, 16)) + unrolled = n_samples & ~3; + else + unrolled = 0; + + for(n = 0; n < unrolled; n += 4) { + out[0] = _mm_load_ps(&s0[n]); + out[1] = _mm_load_ps(&s1[n]); + out[2] = _mm_load_ps(&s2[n]); + out[3] = _mm_load_ps(&s3[n]); + + _MM_TRANSPOSE4_PS(out[0], out[1], out[2], out[3]); + + _mm_storeu_ps((d + 0*n_channels), out[0]); + _mm_storeu_ps((d + 1*n_channels), out[1]); + _mm_storeu_ps((d + 2*n_channels), out[2]); + _mm_storeu_ps((d + 3*n_channels), out[3]); + d += 4*n_channels; + } + for(; n < n_samples; n++) { + out[0] = _mm_setr_ps(s0[n], s1[n], s2[n], s3[n]); + _mm_storeu_ps(d, out[0]); + d += n_channels; + } +} + +void +conv_interleave_32_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + int32_t *d = dst[0]; + uint32_t i = 0, n_channels = conv->n_channels; + + for(; i + 3 < n_channels; i += 4) + conv_interleave_32_4s_sse2(conv, &d[i], &src[i], n_channels, n_samples); + for(; i < n_channels; i++) + conv_interleave_32_1s_sse2(conv, &d[i], &src[i], n_channels, n_samples); +} + +#define _MM_BSWAP_EPI32(x) \ +({ \ + __m128i a = _mm_or_si128( \ + _mm_slli_epi16(x, 8), \ + _mm_srli_epi16(x, 8)); \ + a = _mm_shufflelo_epi16(a, _MM_SHUFFLE(2, 3, 0, 1)); \ + a = _mm_shufflehi_epi16(a, _MM_SHUFFLE(2, 3, 0, 1)); \ +}) + +static void +conv_interleave_32s_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], + uint32_t n_channels, uint32_t n_samples) +{ + const int32_t *s0 = src[0]; + int32_t *d = dst; + uint32_t n, unrolled; + __m128i out[4]; + + if (SPA_IS_ALIGNED(s0, 16)) + unrolled = n_samples & ~3; + else + unrolled = 0; + + for(n = 0; n < unrolled; n += 4) { + out[0] = _mm_load_si128((__m128i*)&s0[n]); + out[0] = _MM_BSWAP_EPI32(out[0]); + out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1)); + out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2)); + out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3)); + + d[0*n_channels] = _mm_cvtsi128_si32(out[0]); + d[1*n_channels] = _mm_cvtsi128_si32(out[1]); + d[2*n_channels] = _mm_cvtsi128_si32(out[2]); + d[3*n_channels] = _mm_cvtsi128_si32(out[3]); + d += 4*n_channels; + } + for(; n < n_samples; n++) { + *d = bswap_32(s0[n]); + d += n_channels; + } +} +static void +conv_interleave_32s_4s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], + uint32_t n_channels, uint32_t n_samples) +{ + const float *s0 = src[0], *s1 = src[1], *s2 = src[2], *s3 = src[3]; + float *d = dst; + uint32_t n, unrolled; + __m128 out[4]; + + if (SPA_IS_ALIGNED(s0, 16) && + SPA_IS_ALIGNED(s1, 16) && + SPA_IS_ALIGNED(s2, 16) && + SPA_IS_ALIGNED(s3, 16)) + unrolled = n_samples & ~3; + else + unrolled = 0; + + for(n = 0; n < unrolled; n += 4) { + out[0] = _mm_load_ps(&s0[n]); + out[1] = _mm_load_ps(&s1[n]); + out[2] = _mm_load_ps(&s2[n]); + out[3] = _mm_load_ps(&s3[n]); + + _MM_TRANSPOSE4_PS(out[0], out[1], out[2], out[3]); + + out[0] = (__m128) _MM_BSWAP_EPI32((__m128i)out[0]); + out[1] = (__m128) _MM_BSWAP_EPI32((__m128i)out[1]); + out[2] = (__m128) _MM_BSWAP_EPI32((__m128i)out[2]); + out[3] = (__m128) _MM_BSWAP_EPI32((__m128i)out[3]); + + _mm_storeu_ps(&d[0*n_channels], out[0]); + _mm_storeu_ps(&d[1*n_channels], out[1]); + _mm_storeu_ps(&d[2*n_channels], out[2]); + _mm_storeu_ps(&d[3*n_channels], out[3]); + d += 4*n_channels; + } + for(; n < n_samples; n++) { + out[0] = _mm_setr_ps(s0[n], s1[n], s2[n], s3[n]); + out[0] = (__m128) _MM_BSWAP_EPI32((__m128i)out[0]); + _mm_storeu_ps(d, out[0]); + d += n_channels; + } +} + +void +conv_interleave_32s_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + int32_t *d = dst[0]; + uint32_t i = 0, n_channels = conv->n_channels; + + for(; i + 3 < n_channels; i += 4) + conv_interleave_32s_4s_sse2(conv, &d[i], &src[i], n_channels, n_samples); + for(; i < n_channels; i++) + conv_interleave_32s_1s_sse2(conv, &d[i], &src[i], n_channels, n_samples); +} + +static void +conv_deinterleave_32_1s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, + uint32_t n_channels, uint32_t n_samples) +{ + const float *s = src; + float *d0 = dst[0]; + uint32_t n, unrolled; + __m128 out; + + if (SPA_IS_ALIGNED(d0, 16)) + unrolled = n_samples & ~3; + else + unrolled = 0; + + for(n = 0; n < unrolled; n += 4) { + out = _mm_setr_ps(s[0*n_channels], + s[1*n_channels],
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/fmt-ops.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/fmt-ops.c
Changed
@@ -84,10 +84,22 @@ { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_copy32_c }, { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_copy32d_c }, +#if defined (HAVE_SSE2) + { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32_sse2 }, +#endif { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32_c }, +#if defined (HAVE_SSE2) + { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_interleave_32_sse2 }, +#endif { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_interleave_32_c }, +#if defined (HAVE_SSE2) + { SPA_AUDIO_FORMAT_F32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32s_sse2 }, +#endif { SPA_AUDIO_FORMAT_F32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32s_c }, +#if defined (HAVE_SSE2) + { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32_OE, 0, 0, conv_interleave_32s_sse2 }, +#endif { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32_OE, 0, 0, conv_interleave_32s_c }, { SPA_AUDIO_FORMAT_U32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u32_to_f32_c }, @@ -259,7 +271,13 @@ /* s32 */ { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32, 0, 0, conv_copy32_c }, { SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_copy32d_c }, +#if defined (HAVE_SSE2) + { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_deinterleave_32_sse2 }, +#endif { SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_deinterleave_32_c }, +#if defined (HAVE_SSE2) + { SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, 0, 0, conv_interleave_32_sse2 }, +#endif { SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, 0, 0, conv_interleave_32_c }, /* s24 */ @@ -271,7 +289,13 @@ /* s24_32 */ { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_copy32_c }, { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_copy32d_c }, +#if defined (HAVE_SSE2) + { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_deinterleave_32_sse2 }, +#endif { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_deinterleave_32_c }, +#if defined (HAVE_SSE2) + { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_interleave_32_sse2 }, +#endif { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_interleave_32_c }, /* F64 */
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/fmt-ops.h -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/fmt-ops.h
Changed
@@ -328,6 +328,10 @@ DEFINE_FUNCTION(f32d_to_s16_2, sse2); DEFINE_FUNCTION(f32d_to_s16, sse2); DEFINE_FUNCTION(f32d_to_s16d, sse2); +DEFINE_FUNCTION(deinterleave_32, sse2); +DEFINE_FUNCTION(deinterleave_32s, sse2); +DEFINE_FUNCTION(interleave_32, sse2); +DEFINE_FUNCTION(interleave_32s, sse2); #endif #if defined(HAVE_SSSE3) DEFINE_FUNCTION(s24_to_f32d, ssse3);
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/merger.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/merger.c
Changed
@@ -306,78 +306,7 @@ case SPA_PARAM_PropInfo: { - struct props *p = &this->props; - switch (result.index) { - case 0: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_volume), - SPA_PROP_INFO_name, SPA_POD_String("Volume"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0)); - break; - case 1: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_mute), - SPA_PROP_INFO_name, SPA_POD_String("Mute"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->channel.mute)); - break; - case 2: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_channelVolumes), - SPA_PROP_INFO_name, SPA_POD_String("Channel Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), - SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); - break; - case 3: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_channelMap), - SPA_PROP_INFO_name, SPA_POD_String("Channel Map"), - SPA_PROP_INFO_type, SPA_POD_Id(SPA_AUDIO_CHANNEL_UNKNOWN), - SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); - break; - case 4: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_monitorMute), - SPA_PROP_INFO_name, SPA_POD_String("Monitor Mute"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->monitor.mute)); - break; - case 5: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_monitorVolumes), - SPA_PROP_INFO_name, SPA_POD_String("Monitor Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), - SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); - break; - case 6: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_softMute), - SPA_PROP_INFO_name, SPA_POD_String("Soft Mute"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->soft.mute)); - break; - case 7: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_softVolumes), - SPA_PROP_INFO_name, SPA_POD_String("Soft Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), - SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); - break; - case 8: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_name, SPA_POD_String("monitor.channel-volumes"), - SPA_PROP_INFO_description, SPA_POD_String("Monitor channel volume"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool( - this->monitor_channel_volumes), - SPA_PROP_INFO_params, SPA_POD_Bool(true)); - break; default: return 0; } @@ -386,46 +315,7 @@ case SPA_PARAM_Props: { -#if 0 - struct props *p = &this->props; - struct spa_pod_frame f[2]; -#endif - switch (result.index) { -#if 0 - case 0: - spa_pod_builder_push_object(&b, &f[0], - SPA_TYPE_OBJECT_Props, id); - spa_pod_builder_add(&b, - SPA_PROP_volume, SPA_POD_Float(p->volume), - SPA_PROP_mute, SPA_POD_Bool(p->channel.mute), - SPA_PROP_channelVolumes, SPA_POD_Array(sizeof(float), - SPA_TYPE_Float, - p->channel.n_volumes, - p->channel.volumes), - SPA_PROP_channelMap, SPA_POD_Array(sizeof(uint32_t), - SPA_TYPE_Id, - p->n_channels, - p->channel_map), - SPA_PROP_softMute, SPA_POD_Bool(p->soft.mute), - SPA_PROP_softVolumes, SPA_POD_Array(sizeof(float), - SPA_TYPE_Float, - p->soft.n_volumes, - p->soft.volumes), - SPA_PROP_monitorMute, SPA_POD_Bool(p->monitor.mute), - SPA_PROP_monitorVolumes, SPA_POD_Array(sizeof(float), - SPA_TYPE_Float, - p->monitor.n_volumes, - p->monitor.volumes), - 0); - spa_pod_builder_prop(&b, SPA_PROP_params, 0); - spa_pod_builder_push_struct(&b, &f[1]); - spa_pod_builder_string(&b, "monitor.channel-volumes"); - spa_pod_builder_bool(&b, this->monitor_channel_volumes); - spa_pod_builder_pop(&b, &f[1]); - param = spa_pod_builder_pop(&b, &f[0]); - break; -#endif default: return 0; }
View file
pipewire-0.3.48.tar.gz/spa/plugins/audioconvert/resample.c -> pipewire-0.3.49.tar.gz/spa/plugins/audioconvert/resample.c
Changed
@@ -307,9 +307,6 @@ if (spa_pod_is_string(pod)) { spa_pod_copy_string(pod, sizeof(value), value); - } else if (spa_pod_is_float(pod)) { - snprintf(value, sizeof(value), "%f", - SPA_POD_VALUE(struct spa_pod_float, pod)); } else if (spa_pod_is_int(pod)) { snprintf(value, sizeof(value), "%d", SPA_POD_VALUE(struct spa_pod_int, pod)); @@ -395,10 +392,10 @@ static void update_rate_match(struct impl *this, bool passthrough, uint32_t out_size, uint32_t in_queued) { if (this->io_rate_match) { - uint32_t match_size; + uint32_t delay, match_size; if (passthrough) { - this->io_rate_match->delay = 0; + delay = in_queued; match_size = out_size; } else { if (SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) @@ -406,12 +403,14 @@ else resample_update_rate(&this->resample, this->rate_scale); - this->io_rate_match->delay = resample_delay(&this->resample); + delay = resample_delay(&this->resample) + in_queued; match_size = resample_in_len(&this->resample, out_size); } match_size -= SPA_MIN(match_size, in_queued); this->io_rate_match->size = match_size; - spa_log_trace_fp(this->log, "%p: next match %u", this, match_size); + this->io_rate_match->delay = delay; + spa_log_trace_fp(this->log, "%p: next match:%u queued:%u delay:%u", this, match_size, + in_queued, delay); } else { resample_update_rate(&this->resample, this->rate_scale * this->props.rate); } @@ -997,7 +996,7 @@ if (SPA_LIKELY(this->io_position)) { double r = this->rate_scale; - max = this->io_position->clock.duration; + max = this->io_position->clock.duration * sizeof(float); if (this->mode == MODE_SPLIT) { if (this->io_position->clock.rate.denom != this->resample.o_rate) r = (double) this->io_position->clock.rate.denom / this->resample.o_rate; @@ -1015,13 +1014,13 @@ } } else - max = maxsize / sizeof(float); + max = maxsize; switch (this->mode) { case MODE_SPLIT: /* in split mode we need to output exactly the size of the * duration so we don't try to flush early */ - maxsize = SPA_MIN(maxsize, max * sizeof(float)); + maxsize = SPA_MIN(maxsize, max); flush_out = false; break; case MODE_MERGE: @@ -1112,8 +1111,8 @@ spa_log_trace_fp(this->log, "%p: no output buffer", this); } - update_rate_match(this, passthrough, max - outport->offset / sizeof(float), - size - inport->offset / sizeof(float)); + update_rate_match(this, passthrough, (max - outport->offset) / sizeof(float), + (size - inport->offset) / sizeof(float)); return res; }
View file
pipewire-0.3.48.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c -> pipewire-0.3.49.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c
Changed
@@ -984,6 +984,13 @@ return 0; } +static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct impl *this = user_data; + spa_loop_remove_source(this->data_loop, &this->timer_source); + return 0; +} + static int impl_clear(struct spa_handle *handle) { struct impl *this; @@ -993,7 +1000,7 @@ this = (struct impl *) handle; if (this->data_loop) - spa_loop_remove_source(this->data_loop, &this->timer_source); + spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this); spa_system_close(this->data_system, this->timer_source.fd); return 0;
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/a2dp-codec-aptx.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/a2dp-codec-aptx.c
Changed
@@ -343,6 +343,8 @@ if (this->hd) this->max_frames = (this->mtu - sizeof(struct rtp_header)) / this->frame_length; + else if (codec_is_ll(codec)) + this->max_frames = SPA_MIN(256u, this->mtu) / this->frame_length; else this->max_frames = this->mtu / this->frame_length;
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/a2dp-codecs.h -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/a2dp-codecs.h
Changed
@@ -43,7 +43,7 @@ #define SPA_TYPE_INTERFACE_Bluez5CodecA2DP SPA_TYPE_INFO_INTERFACE_BASE "Bluez5:Codec:A2DP:Private" -#define SPA_VERSION_BLUEZ5_CODEC_A2DP 0 +#define SPA_VERSION_BLUEZ5_CODEC_A2DP 1 struct spa_bluez5_codec_a2dp { struct spa_interface iface;
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/a2dp-sink.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/a2dp-sink.c
Changed
@@ -70,6 +70,9 @@ #define FILL_FRAMES 2 #define MAX_BUFFERS 32 +#define MIN_LATENCY 128 +#define MAX_LATENCY 8192 +#define BUFFER_SIZE (MAX_LATENCY*8) struct buffer { uint32_t id; @@ -137,6 +140,8 @@ struct spa_source source; int timerfd; struct spa_source flush_source; + struct spa_source flush_timer_source; + int flush_timerfd; struct spa_io_clock *clock; struct spa_io_position *position; @@ -153,14 +158,14 @@ int need_flush; uint32_t block_size; - uint8_t buffer[4096]; + uint8_t buffer[BUFFER_SIZE]; uint32_t buffer_used; uint32_t header_size; uint32_t frame_count; uint16_t seqnum; uint32_t timestamp; uint64_t sample_count; - uint8_t tmp_buffer[4096]; + uint8_t tmp_buffer[BUFFER_SIZE]; uint32_t tmp_buffer_used; uint32_t fd_buffer_size; }; @@ -169,11 +174,7 @@ static void reset_props(struct impl *this, struct props *props) { - if (this->codec->id == SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL) { - props->min_latency = 256; - } else { - props->min_latency = MIN_LATENCY; - } + props->min_latency = MIN_LATENCY; props->max_latency = MAX_LATENCY; props->latency_offset = 0; strncpy(props->clock_name, DEFAULT_CLOCK_NAME, sizeof(props->clock_name)); @@ -481,11 +482,6 @@ return written; } -static bool want_flush(struct impl *this) -{ - return (this->frame_count * this->block_size / this->port.frame_size >= this->props.min_latency); -} - static int encode_buffer(struct impl *this, const void *data, uint32_t size) { int processed; @@ -542,7 +538,7 @@ spa_log_trace(this->log, "%p: used:%d block_size:%d", this, this->buffer_used, this->block_size); - if (this->need_flush || want_flush(this)) + if (this->need_flush) return send_buffer(this); return 0; @@ -565,12 +561,25 @@ return total; } -static void enable_flush(struct impl *this, bool enabled) +static void enable_flush(struct impl *this, bool enabled, uint64_t timeout) { - if (SPA_FLAG_IS_SET(this->flush_source.mask, SPA_IO_OUT) != enabled) { - SPA_FLAG_UPDATE(this->flush_source.mask, SPA_IO_OUT, enabled); + bool flush_enabled = enabled && (timeout == 0); + struct itimerspec ts; + + if (SPA_FLAG_IS_SET(this->flush_source.mask, SPA_IO_OUT) != flush_enabled) { + SPA_FLAG_UPDATE(this->flush_source.mask, SPA_IO_OUT, flush_enabled); spa_loop_update_source(this->data_loop, &this->flush_source); } + + if (!enabled) + timeout = 0; + + ts.it_value.tv_sec = timeout / SPA_NSEC_PER_SEC; + ts.it_value.tv_nsec = timeout % SPA_NSEC_PER_SEC; + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + spa_system_timerfd_settime(this->data_system, + this->flush_timerfd, 0, &ts, NULL); } static int flush_data(struct impl *this, uint64_t now_time) @@ -579,6 +588,11 @@ uint32_t total_frames; struct port *port = &this->port; + if (!this->flush_source.loop) { + /* I/O in error state */ + return -EIO; + } + total_frames = 0; again: written = 0; @@ -640,42 +654,80 @@ } if (written > 0 && this->buffer_used == this->header_size) { - enable_flush(this, false); + enable_flush(this, false, 0); return 0; } written = flush_buffer(this); + if (written == -EAGAIN) { - spa_log_trace(this->log, "%p: delay flush", this); + spa_log_trace(this->log, "%p: fail flush", this); if (now_time - this->last_error > SPA_NSEC_PER_SEC / 2) { + spa_log_trace(this->log, "%p: reduce bitpool", this); this->codec->reduce_bitpool(this->codec_data); this->last_error = now_time; } - this->need_flush = true; - enable_flush(this, true); + + /* + * The socket buffer is full, and the device is not processing data + * fast enough, so should just skip this packet. There will be a sound + * glitch in any case. + */ + written = this->buffer_used; + reset_buffer(this); } - else if (written < 0) { + + if (written < 0) { spa_log_trace(this->log, "%p: error flushing %s", this, spa_strerror(written)); reset_buffer(this); - enable_flush(this, false); + enable_flush(this, false, 0); return written; } else if (written > 0) { + /* + * We cannot write all data we have at once, since this can exceed + * device buffers. We'll want a limited number of "excess" + * samples. This is an issue for the "low-latency" A2DP codecs. + * + * Flushing the rest of the data (if any) is delayed after a timeout, + * selected on an average-rate basis: + * + * npackets = quantum / packet_samples + * write_end_time = npackets * timeout + * max_excess = quantum - sample_rate * write_end_time + * packet_time = packet_samples / sample_rate + * => timeout = (quantum - max_excess)/quantum * packet_time + */ + uint64_t max_excess = 2*256; + uint64_t packet_samples = this->frame_count * this->block_size / port->frame_size; + uint64_t packet_time = packet_samples * SPA_NSEC_PER_SEC / port->current_format.info.raw.rate; + uint64_t quantum = SPA_LIKELY(this->clock) ? this->clock->duration : 0; + uint64_t timeout = (quantum > max_excess) ? + (packet_time * (quantum - max_excess) / quantum) : 0; + reset_buffer(this); if (now_time - this->last_error > SPA_NSEC_PER_SEC) { - this->codec->increase_bitpool(this->codec_data); + if (get_transport_unused_size(this) == (int)this->fd_buffer_size) { + spa_log_trace(this->log, "%p: increase bitpool", this); + this->codec->increase_bitpool(this->codec_data); + } this->last_error = now_time; } - if (!spa_list_is_empty(&port->ready)) - goto again; - - enable_flush(this, false); + if (!spa_list_is_empty(&port->ready)) { + spa_log_trace(this->log, "%p: flush after %d ns", this, (int)timeout); + if (timeout == 0) + goto again; + else + enable_flush(this, true, timeout); + } else { + enable_flush(this, false, 0); + } } else { /* Don't want to flush yet, or failed to write anything */ spa_log_trace(this->log, "%p: skip flush", this); - enable_flush(this, false);
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/a2dp-source.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/a2dp-source.c
Changed
@@ -70,6 +70,8 @@ #define FILL_FRAMES 2 #define MAX_BUFFERS 32 +#define MIN_LATENCY 512 +#define MAX_LATENCY 1024 struct buffer { uint32_t id;
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/backend-ofono.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/backend-ofono.c
Changed
@@ -38,10 +38,14 @@ #include <spa/support/plugin.h> #include <spa/utils/string.h> #include <spa/utils/type.h> +#include <spa/utils/result.h> #include <spa/param/audio/raw.h> #include "defs.h" +#define INITIAL_INTERVAL_NSEC (500 * SPA_NSEC_PER_MSEC) +#define ACTION_INTERVAL_NSEC (3000 * SPA_NSEC_PER_MSEC) + static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.ofono"); #undef SPA_LOG_TOPIC_DEFAULT #define SPA_LOG_TOPIC_DEFAULT &log_topic @@ -53,17 +57,23 @@ struct spa_log *log; struct spa_loop *main_loop; + struct spa_system *main_system; struct spa_dbus *dbus; + struct spa_loop_utils *loop_utils; DBusConnection *conn; const struct spa_bt_quirks *quirks; + struct spa_source *timer; + unsigned int filters_added:1; unsigned int msbc_supported:1; }; struct transport_data { struct spa_source sco; + unsigned int broken:1; + unsigned int activated:1; }; #define OFONO_HF_AUDIO_MANAGER_INTERFACE OFONO_SERVICE ".HandsfreeAudioManager" @@ -161,6 +171,13 @@ dbus_error_init(&err); + /* + * XXX: We assume here oFono replies. It however can happen that the headset does + * XXX: not properly respond to the codec negotiation RFCOMM commands. + * XXX: oFono (1.34) fails to handle this condition, and will not send DBus reply + * XXX: in this case. The transport acquire API is synchronous, so we can't + * XXX: do better here right now. + */ r = dbus_connection_send_with_reply_and_block(backend->conn, m, -1, &err); dbus_message_unref(m); m = NULL; @@ -196,12 +213,19 @@ static int ofono_audio_acquire(void *data, bool optional) { struct spa_bt_transport *transport = data; + struct transport_data *td = transport->user_data; struct impl *backend = SPA_CONTAINER_OF(transport->backend, struct impl, this); uint8_t codec; int ret = 0; if (transport->fd >= 0) goto finish; + if (td->broken) { + ret = -EIO; + goto finish; + } + + spa_bt_device_update_last_bluez_action_time(transport->device); ret = _audio_acquire(backend, transport->path, &codec); if (ret < 0) @@ -210,27 +234,28 @@ transport->fd = ret; if (transport->codec != codec) { - struct spa_bt_transport *t = NULL; + struct timespec ts; - spa_log_warn(backend->log, "Acquired codec (%d) differs from transport one (%d)", - codec, transport->codec); + spa_log_info(backend->log, "transport %p: acquired codec (%d) differs from transport one (%d)", + transport, codec, transport->codec); /* shutdown to make sure connection is dropped immediately */ shutdown(transport->fd, SHUT_RDWR); close(transport->fd); transport->fd = -1; - /* Create a new transport which differs only for codec */ - t = _transport_create(backend, transport->path, transport->device, - transport->profile, codec, &transport->impl); - - spa_bt_transport_free(transport); - spa_bt_device_connect_profile(t->device, t->profile); - - ret = -EIO; - goto finish; + /* schedule immediate profile update, from main loop */ + transport->codec = codec; + td->broken = true; + ts.tv_sec = 0; + ts.tv_nsec = 1; + spa_loop_utils_update_timer(backend->loop_utils, backend->timer, + &ts, NULL, false); + return -EIO; } + td->broken = false; + spa_log_debug(backend->log, "transport %p: Acquire %s, fd %d codec %d", transport, transport->path, transport->fd, transport->codec); @@ -293,14 +318,74 @@ .release = ofono_audio_release, }; +bool activate_transport(struct spa_bt_transport *t, const void *data) +{ + struct impl *backend = (void *)data; + struct transport_data *td = t->user_data; + struct timespec ts; + uint64_t now, threshold; + + if (t->backend != &backend->this) + return false; + + /* Check device-specific rate limit */ + spa_system_clock_gettime(backend->main_system, CLOCK_MONOTONIC, &ts); + now = SPA_TIMESPEC_TO_NSEC(&ts); + threshold = t->device->last_bluez_action_time + ACTION_INTERVAL_NSEC; + if (now < threshold) { + ts.tv_sec = (threshold - now) / SPA_NSEC_PER_SEC; + ts.tv_nsec = (threshold - now) % SPA_NSEC_PER_SEC; + spa_loop_utils_update_timer(backend->loop_utils, backend->timer, + &ts, NULL, false); + return false; + } + + if (!td->activated) { + /* Connect profile */ + spa_log_debug(backend->log, "Transport %s activated", t->path); + td->activated = true; + spa_bt_device_connect_profile(t->device, t->profile); + } + + if (td->broken) { + /* Recreate the transport */ + struct spa_bt_transport *t_copy; + + t_copy = _transport_create(backend, t->path, t->device, + t->profile, t->codec, (struct spa_callbacks *)&ofono_transport_impl); + spa_bt_transport_free(t); + + if (t_copy) + spa_bt_device_connect_profile(t_copy->device, t_copy->profile); + + return true; + } + + return false; +} + +static void activate_transports(struct impl *backend) +{ + while (spa_bt_transport_find_full(backend->monitor, activate_transport, backend)); +} + +static void activate_timer_event(void *userdata, uint64_t expirations) +{ + struct impl *backend = userdata; + spa_loop_utils_update_timer(backend->loop_utils, backend->timer, NULL, NULL, false); + activate_transports(backend); +} + static DBusHandlerResult ofono_audio_card_found(struct impl *backend, char *path, DBusMessageIter *props_i) { const char *remote_address = NULL; const char *local_address = NULL; struct spa_bt_device *d; struct spa_bt_transport *t; + struct transport_data *td; enum spa_bt_profile profile = SPA_BT_PROFILE_HFP_AG; - uint8_t codec = HFP_AUDIO_CODEC_CVSD; + uint8_t codec = backend->msbc_supported ? + HFP_AUDIO_CODEC_MSBC : HFP_AUDIO_CODEC_CVSD; spa_assert(backend); spa_assert(path); @@ -340,24 +425,6 @@ dbus_message_iter_next(props_i); } - /* - * Acquire and close immediately to figure out the codec. - * This is necessary if we are in HF mode, because we need to emit - * nodes and the advertised sample rate of the node depends on the codec. - * For AG mode, we delay the emission of the nodes, so it is not necessary - * to know the codec in advance
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -837,7 +837,7 @@ return NULL; } -static void device_update_last_bluez_action_time(struct spa_bt_device *device) +void spa_bt_device_update_last_bluez_action_time(struct spa_bt_device *device) { struct timespec ts; spa_system_clock_gettime(device->monitor->main_system, CLOCK_MONOTONIC, &ts); @@ -867,7 +867,7 @@ spa_list_prepend(&monitor->device_list, &d->link); - device_update_last_bluez_action_time(d); + spa_bt_device_update_last_bluez_action_time(d); return d; } @@ -2595,7 +2595,7 @@ goto next; } - device_update_last_bluez_action_time(sw->device); + spa_bt_device_update_last_bluez_action_time(sw->device); spa_log_info(sw->device->monitor->log, "a2dp codec switch %p: trying codec %s for endpoint %s, local endpoint %s", sw, codec->name, ep->path, local_endpoint); @@ -2727,7 +2727,7 @@ dbus_pending_call_unref(pending); sw->pending = NULL; - device_update_last_bluez_action_time(device); + spa_bt_device_update_last_bluez_action_time(device); if (!a2dp_codec_switch_goto_active(sw)) { if (r != NULL) @@ -3030,7 +3030,7 @@ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - device_update_last_bluez_action_time(transport->device); + spa_bt_device_update_last_bluez_action_time(transport->device); if (profile & SPA_BT_PROFILE_A2DP_SOURCE) { /* PW is the rendering device so it's responsible for reporting hardware volume. */
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/codec-loader.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/codec-loader.c
Changed
@@ -103,7 +103,7 @@ spa_log_debug(impl->log, "loading codecs from %s", factory_name); if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Bluez5CodecA2DP, &iface)) < 0) { - spa_log_info(impl->log, "Bluetooth codec plugin %s has no codec interface", + spa_log_warn(impl->log, "Bluetooth codec plugin %s has no codec interface", factory_name); goto fail; } @@ -111,7 +111,7 @@ bluez5_codec_a2dp = iface; if (bluez5_codec_a2dp->iface.version != SPA_VERSION_BLUEZ5_CODEC_A2DP) { - spa_log_info(impl->log, "codec plugin %s has incompatible ABI version (%d != %d)", + spa_log_warn(impl->log, "codec plugin %s has incompatible ABI version (%d != %d)", factory_name, bluez5_codec_a2dp->iface.version, SPA_VERSION_BLUEZ5_CODEC_A2DP); res = -ENOENT; goto fail;
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/defs.h
Changed
@@ -60,9 +60,6 @@ #define PIPEWIRE_BATTERY_PROVIDER "/org/freedesktop/pipewire/battery" -#define MIN_LATENCY 512 -#define MAX_LATENCY 1024 - #define OBJECT_MANAGER_INTROSPECT_XML \ DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ "<node>\n" \ @@ -499,6 +496,7 @@ int spa_bt_device_supports_hfp_codec(struct spa_bt_device *device, unsigned int codec); int spa_bt_device_release_transports(struct spa_bt_device *device); int spa_bt_device_report_battery_level(struct spa_bt_device *device, uint8_t percentage); +void spa_bt_device_update_last_bluez_action_time(struct spa_bt_device *device); #define spa_bt_device_emit(d,m,v,...) spa_hook_list_call(&(d)->listener_list, \ struct spa_bt_device_events, \
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/quirks.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/quirks.c
Changed
@@ -262,14 +262,16 @@ } else { char path[PATH_MAX]; const char *dir = getenv("SPA_DATA_DIR"); + int res; if (dir == NULL) dir = SPADATADIR; if (spa_scnprintf(path, sizeof(path), "%s/bluez5/bluez-hardware.conf", dir) >= 0) - load_conf(this, path); + if ((res = load_conf(this, path)) < 0) + spa_log_warn(this->log, "failed to load '%s': %s", path, + spa_strerror(res)); } - if (!(this->kernel_rules && this->adapter_rules && this->device_rules)) spa_log_warn(this->log, "failed to load bluez-hardware.conf");
View file
pipewire-0.3.48.tar.gz/spa/plugins/bluez5/sco-sink.c -> pipewire-0.3.49.tar.gz/spa/plugins/bluez5/sco-sink.c
Changed
@@ -66,6 +66,8 @@ }; #define MAX_BUFFERS 32 +#define MIN_LATENCY 512 +#define MAX_LATENCY 1024 struct buffer { uint32_t id;
View file
pipewire-0.3.48.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.49.tar.gz/spa/plugins/support/loop.c
Changed
@@ -90,6 +90,7 @@ uint8_t buffer_mem[DATAS_SIZE + MAX_ALIGN]; unsigned int flushing:1; + unsigned int polling:1; }; struct source_impl { @@ -98,7 +99,6 @@ struct impl *impl; struct spa_list link; - bool close; union { spa_source_io_func_t io; spa_source_idle_func_t idle; @@ -106,8 +106,11 @@ spa_source_timer_func_t timer; spa_source_signal_func_t signal; } func; - bool enabled; + struct spa_source *fallback; + + bool close; + bool enabled; }; /** \endcond */ @@ -116,28 +119,51 @@ struct impl *impl = object; source->loop = &impl->loop; source->priv = NULL; + source->rmask = 0; return spa_system_pollfd_add(impl->system, impl->poll_fd, source->fd, source->mask, source); } static int loop_update_source(void *object, struct spa_source *source) { struct impl *impl = object; + + spa_assert(source->loop == &impl->loop); + return spa_system_pollfd_mod(impl->system, impl->poll_fd, source->fd, source->mask, source); } -static int loop_remove_source(void *object, struct spa_source *source) +static void detach_source(struct spa_source *source) { - struct impl *impl = object; struct spa_poll_event *e; + + source->loop = NULL; + source->rmask = 0; + if ((e = source->priv)) { /* active in an iteration of the loop, remove it from there */ e->data = NULL; source->priv = NULL; } - source->loop = NULL; +} + +static int remove_from_poll(struct impl *impl, struct spa_source *source) +{ + spa_assert(source->loop == &impl->loop); + return spa_system_pollfd_del(impl->system, impl->poll_fd, source->fd); } +static int loop_remove_source(void *object, struct spa_source *source) +{ + struct impl *impl = object; + spa_assert(!impl->polling); + + int res = remove_from_poll(impl, source); + detach_source(source); + + return res; +} + static void flush_items(struct impl *impl) { uint32_t index; @@ -151,7 +177,7 @@ item = SPA_PTROFF(impl->buffer_data, index & (DATAS_SIZE - 1), struct invoke_item); block = item->block; - spa_log_trace(impl->log, "%p: flush item %p", impl, item); + spa_log_trace_fp(impl->log, "%p: flush item %p", impl, item); item->res = item->func ? item->func(&impl->loop, true, item->seq, item->data, item->size, item->user_data) : 0; @@ -223,7 +249,7 @@ item->user_data = user_data; item->item_size = SPA_ROUND_UP_N(sizeof(struct invoke_item) + size, ITEM_ALIGN); - spa_log_trace(impl->log, "%p: add item %p filled:%d", impl, item, filled); + spa_log_trace_fp(impl->log, "%p: add item %p filled:%d", impl, item, filled); if (l0 >= item->item_size) { /* item + size fit in current ringbuffer idx */ @@ -322,15 +348,25 @@ spa_log_trace(impl->log, "%p: leave %lu", impl, impl->thread); - if (--impl->enter_count == 0) + if (--impl->enter_count == 0) { impl->thread = 0; + impl->polling = false; + } +} + +static inline void free_source(struct source_impl *s) +{ + detach_source(&s->source); + free(s); } 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); + free_source(source); + spa_list_init(&impl->destroy_list); } @@ -340,20 +376,22 @@ struct spa_poll_event ep[MAX_EP], *e; int i, nfds; + impl->polling = true; spa_loop_control_hook_before(&impl->hooks_list); - nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, MAX_EP, timeout); + nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout); spa_loop_control_hook_after(&impl->hooks_list); - - if (SPA_UNLIKELY(nfds < 0)) - return nfds; + impl->polling = false; /* first we set all the rmasks, then call the callbacks. The reason is that * some callback might also want to look at other sources it manages and * can then reset the rmask to suppress the callback */ for (i = 0; i < nfds; i++) { struct spa_source *s = ep[i].data; + + spa_assert(s->loop == &impl->loop); + s->rmask = ep[i].events; /* already active in another iteration of the loop, * remove it from that iteration */ @@ -361,24 +399,32 @@ e->data = NULL; s->priv = &ep[i]; } + + if (SPA_UNLIKELY(!spa_list_is_empty(&impl->destroy_list))) + process_destroy(impl); + for (i = 0; i < nfds; i++) { struct spa_source *s = ep[i].data; - if (SPA_LIKELY(s && s->rmask && s->loop)) { - s->priv = NULL; + if (SPA_LIKELY(s && s->rmask)) s->func(s); + } + + for (i = 0; i < nfds; i++) { + struct spa_source *s = ep[i].data; + if (SPA_LIKELY(s)) { + s->rmask = 0; + s->priv = NULL; } } - if (SPA_UNLIKELY(!spa_list_is_empty(&impl->destroy_list))) - process_destroy(impl); return nfds; } static void source_io_func(struct spa_source *source) { - struct source_impl *impl = SPA_CONTAINER_OF(source, struct source_impl, source); - spa_log_trace_fp(impl->impl->log, "%p: io %08x", impl, source->rmask); - impl->func.io(source->data, source->fd, source->rmask); + struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source); + spa_log_trace_fp(s->impl->log, "%p: io %08x", s, source->rmask); + s->func.io(source->data, source->fd, source->rmask); } static struct spa_source *loop_add_io(void *object, @@ -394,7 +440,6 @@ if (source == NULL) goto error_exit;
View file
pipewire-0.3.48.tar.gz/spa/plugins/support/node-driver.c -> pipewire-0.3.49.tar.gz/spa/plugins/support/node-driver.c
Changed
@@ -350,6 +350,13 @@ return 0; } +static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct impl *this = user_data; + spa_loop_remove_source(this->data_loop, &this->timer_source); + return 0; +} + static int impl_clear(struct spa_handle *handle) { struct impl *this; @@ -358,7 +365,7 @@ this = (struct impl *) handle; - spa_loop_remove_source(this->data_loop, &this->timer_source); + spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this); spa_system_close(this->data_system, this->timer_source.fd); return 0;
View file
pipewire-0.3.48.tar.gz/spa/plugins/support/null-audio-sink.c -> pipewire-0.3.49.tar.gz/spa/plugins/support/null-audio-sink.c
Changed
@@ -779,6 +779,13 @@ return 0; } +static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct impl *this = user_data; + spa_loop_remove_source(this->data_loop, &this->timer_source); + return 0; +} + static int impl_clear(struct spa_handle *handle) { struct impl *this; @@ -787,7 +794,7 @@ this = (struct impl *) handle; - spa_loop_remove_source(this->data_loop, &this->timer_source); + spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this); spa_system_close(this->data_system, this->timer_source.fd); return 0;
View file
pipewire-0.3.48.tar.gz/spa/plugins/test/fakesink.c -> pipewire-0.3.49.tar.gz/spa/plugins/test/fakesink.c
Changed
@@ -698,6 +698,13 @@ return 0; } +static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct impl *this = user_data; + spa_loop_remove_source(this->data_loop, &this->timer_source); + return 0; +} + static int impl_clear(struct spa_handle *handle) { struct impl *this; @@ -707,7 +714,7 @@ this = (struct impl *) handle; if (this->data_loop) - spa_loop_remove_source(this->data_loop, &this->timer_source); + spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this); spa_system_close(this->data_system, this->timer_source.fd); return 0;
View file
pipewire-0.3.48.tar.gz/spa/plugins/test/fakesrc.c -> pipewire-0.3.49.tar.gz/spa/plugins/test/fakesrc.c
Changed
@@ -731,6 +731,13 @@ return 0; } +static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct impl *this = user_data; + spa_loop_remove_source(this->data_loop, &this->timer_source); + return 0; +} + static int impl_clear(struct spa_handle *handle) { struct impl *this; @@ -740,7 +747,7 @@ this = (struct impl *) handle; if (this->data_loop) - spa_loop_remove_source(this->data_loop, &this->timer_source); + spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this); spa_system_close(this->data_system, this->timer_source.fd); return 0;
View file
pipewire-0.3.48.tar.gz/spa/plugins/videotestsrc/videotestsrc.c -> pipewire-0.3.49.tar.gz/spa/plugins/videotestsrc/videotestsrc.c
Changed
@@ -838,6 +838,13 @@ return 0; } +static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct impl *this = user_data; + spa_loop_remove_source(this->data_loop, &this->timer_source); + return 0; +} + static int impl_clear(struct spa_handle *handle) { struct impl *this; @@ -847,7 +854,7 @@ this = (struct impl *) handle; if (this->data_loop) - spa_loop_remove_source(this->data_loop, &this->timer_source); + spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this); spa_system_close(this->data_system, this->timer_source.fd); return 0;
View file
pipewire-0.3.48.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c -> pipewire-0.3.49.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c
Changed
@@ -854,6 +854,13 @@ return 0; } +static int do_remove_timer(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct impl *this = user_data; + spa_loop_remove_source(this->data_loop, &this->timer_source); + return 0; +} + static int impl_clear(struct spa_handle *handle) { struct impl *this; @@ -863,7 +870,7 @@ this = (struct impl *) handle; if (this->data_loop) - spa_loop_remove_source(this->data_loop, &this->timer_source); + spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this); spa_system_close(this->data_system, this->timer_source.fd); return 0;
View file
pipewire-0.3.48.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.49.tar.gz/src/daemon/client-rt.conf.in
Changed
@@ -81,12 +81,13 @@ #node.latency = 1024/48000 #node.autoconnect = true #resample.quality = 4 - #channelmix.normalize = true + #channelmix.normalize = false #channelmix.mix-lfe = true - #channelmix.upmix = false - #channelmix.lfe-cutoff = 0 - #channelmix.fc-cutoff = 0 + #channelmix.upmix = true + #channelmix.upmix-method = simple # none, psd + #channelmix.lfe-cutoff = 120 + #channelmix.fc-cutoff = 6000 #channelmix.rear-delay = 12.0 - #channelmix.stereo-widen = 0.0 + #channelmix.stereo-widen = 0.1 #channelmix.hilbert-taps = 0 }
View file
pipewire-0.3.48.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.49.tar.gz/src/daemon/client.conf.in
Changed
@@ -71,12 +71,13 @@ #node.latency = 1024/48000 #node.autoconnect = true #resample.quality = 4 - #channelmix.normalize = true + #channelmix.normalize = false #channelmix.mix-lfe = false - #channelmix.upmix = false - #channelmix.lfe-cutoff = 0 - #channelmix.fc-cutoff = 0 + #channelmix.upmix = true + #channelmix.upmix-method = simple # none, psd + #channelmix.lfe-cutoff = 120 + #channelmix.fc-cutoff = 6000 #channelmix.rear-delay = 12.0 - #channelmix.stereo-widen = 0.0 + #channelmix.stereo-widen = 0.1 #channelmix.hilbert-taps = 0 }
View file
pipewire-0.3.48.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.49.tar.gz/src/daemon/minimal.conf.in
Changed
@@ -202,13 +202,14 @@ #resample.quality = 4 resample.disable = true #monitor.channel-volumes = false - #channelmix.normalize = true + #channelmix.normalize = false #channelmix.mix-lfe = false - #channelmix.upmix = false - #channelmix.lfe-cutoff = 0 - #channelmix.fc-cutoff = 0 + #channelmix.upmix = true + #channelmix.upmix-method = simple # none, psd + #channelmix.lfe-cutoff = 120 + #channelmix.fc-cutoff = 6000 #channelmix.rear-delay = 12.0 - #channelmix.stereo-widen = 0.0 + #channelmix.stereo-widen = 0.1 #channelmix.hilbert-taps = 0 channelmix.disable = true #node.param.Props = { @@ -261,13 +262,14 @@ #audio.position = "FL,FR" #resample.quality = 4 resample.disable = true - #channelmix.normalize = true + #channelmix.normalize = false #channelmix.mix-lfe = false - #channelmix.upmix = false - #channelmix.lfe-cutoff = 0 - #channelmix.fc-cutoff = 0 + #channelmix.upmix = true + #channelmix.upmix-method = simple # none, psd + #channelmix.lfe-cutoff = 120 + #channelmix.fc-cutoff = 6000 #channelmix.rear-delay = 12.0 - #channelmix.stereo-widen = 0.0 + #channelmix.stereo-widen = 0.1 #channelmix.hilbert-taps = 0 channelmix.disable = true #node.param.Props = {
View file
pipewire-0.3.48.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.49.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
@@ -40,32 +40,8 @@ { name = libpipewire-module-protocol-pulse args = { - # the addresses this server listens on - server.address = [ - "unix:native" - #"unix:/tmp/something" # absolute paths may be used - #"tcp:4713" # IPv4 and IPv6 on all addresses - #"tcp:[::]:9999" # IPv6 on all addresses - #"tcp:127.0.0.1:8888" # IPv4 on a single address - # - #{ address = "tcp:4713" # address - # max-clients = 64 # maximum number of clients - # listen-backlog = 32 # backlog in the server listen queue - # client.access = "restricted" # permissions for clients - #} - ] - #pulse.min.req = 256/48000 # 5ms - #pulse.default.req = 960/48000 # 20 milliseconds - #pulse.min.frag = 256/48000 # 5ms - #pulse.default.frag = 96000/48000 # 2 seconds - #pulse.default.tlength = 96000/48000 # 2 seconds - #pulse.min.quantum = 256/48000 # 5ms - #pulse.default.format = F32 - #pulse.default.position = [ FL FR ] - # These overrides are only applied when running in a vm. - vm.overrides = { - pulse.min.quantum = 1024/48000 # 22ms - } + # contents of pulse.properties can also be placed here + # to have config per server. } } ] @@ -81,16 +57,46 @@ #node.latency = 1024/48000 #node.autoconnect = true #resample.quality = 4 - #channelmix.normalize = true + #channelmix.normalize = false #channelmix.mix-lfe = false - #channelmix.upmix = false - #channelmix.lfe-cutoff = 0 - #channelmix.fc-cutoff = 0 + #channelmix.upmix = true + #channelmix.upmix-method = simple # none, psd + #channelmix.lfe-cutoff = 120 + #channelmix.fc-cutoff = 6000 #channelmix.rear-delay = 12.0 - #channelmix.stereo-widen = 0.0 + #channelmix.stereo-widen = 0.1 #channelmix.hilbert-taps = 0 } +pulse.properties = { + # the addresses this server listens on + server.address = [ + "unix:native" + #"unix:/tmp/something" # absolute paths may be used + #"tcp:4713" # IPv4 and IPv6 on all addresses + #"tcp:[::]:9999" # IPv6 on all addresses + #"tcp:127.0.0.1:8888" # IPv4 on a single address + # + #{ address = "tcp:4713" # address + # max-clients = 64 # maximum number of clients + # listen-backlog = 32 # backlog in the server listen queue + # client.access = "restricted" # permissions for clients + #} + ] + #pulse.min.req = 256/48000 # 5ms + #pulse.default.req = 960/48000 # 20 milliseconds + #pulse.min.frag = 256/48000 # 5ms + #pulse.default.frag = 96000/48000 # 2 seconds + #pulse.default.tlength = 96000/48000 # 2 seconds + #pulse.min.quantum = 256/48000 # 5ms + #pulse.default.format = F32 + #pulse.default.position = [ FL FR ] + # These overrides are only applied when running in a vm. + vm.overrides = { + pulse.min.quantum = 1024/48000 # 22ms + } +} + # client/stream specific properties pulse.rules = [ {
View file
pipewire-0.3.48.tar.gz/src/daemon/pipewire.c -> pipewire-0.3.49.tar.gz/src/daemon/pipewire.c
Changed
@@ -26,6 +26,7 @@ #include <signal.h> #include <getopt.h> #include <libgen.h> +#include <locale.h> #include <spa/utils/result.h> #include <pipewire/pipewire.h> @@ -74,6 +75,7 @@ snprintf(path, sizeof(path), "%s.conf", argv[0]); config_name = basename(path); + setlocale(LC_ALL, ""); pw_init(&argc, &argv); while ((c = getopt_long(argc, argv, "hVc:v", long_options, NULL)) != -1) {
View file
pipewire-0.3.48.tar.gz/src/gst/gstpipewiredeviceprovider.c -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiredeviceprovider.c
Changed
@@ -44,6 +44,7 @@ enum { PROP_ID = 1, + PROP_SERIAL, }; static GstElement * @@ -51,12 +52,16 @@ { GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device); GstElement *elem; - gchar *str; + gchar *id_str, *serial_str; elem = gst_element_factory_make (pipewire_dev->element, name); - str = g_strdup_printf ("%u", pipewire_dev->id); - g_object_set (elem, "path", str, NULL); - g_free (str); + + /* XXX: eventually only add target-object here */ + id_str = g_strdup_printf ("%u", pipewire_dev->id); + serial_str = g_strdup_printf ("%"PRIu64, pipewire_dev->serial); + g_object_set (elem, "path", id_str, "target-object", serial_str, NULL); + g_free (id_str); + g_free (serial_str); return elem; } @@ -65,7 +70,7 @@ gst_pipewire_device_reconfigure_element (GstDevice * device, GstElement * element) { GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device); - gchar *str; + gchar *id_str, *serial_str; if (spa_streq(pipewire_dev->element, "pipewiresrc")) { if (!GST_IS_PIPEWIRE_SRC (element)) @@ -77,9 +82,12 @@ g_assert_not_reached (); } - str = g_strdup_printf ("%u", pipewire_dev->id); - g_object_set (element, "path", str, NULL); - g_free (str); + /* XXX: eventually only add target-object here */ + id_str = g_strdup_printf ("%u", pipewire_dev->id); + serial_str = g_strdup_printf ("%"PRIu64, pipewire_dev->serial); + g_object_set (element, "path", id_str, "target-object", serial_str, NULL); + g_free (id_str); + g_free (serial_str); return TRUE; } @@ -97,6 +105,9 @@ case PROP_ID: g_value_set_uint (value, device->id); break; + case PROP_SERIAL: + g_value_set_uint64 (value, device->serial); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -115,6 +126,9 @@ case PROP_ID: device->id = g_value_get_uint (value); break; + case PROP_SERIAL: + device->serial = g_value_get_uint64 (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -144,6 +158,11 @@ g_param_spec_uint ("id", "Id", "The internal id of the PipeWire device", 0, G_MAXUINT32, SPA_ID_INVALID, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, PROP_SERIAL, + g_param_spec_uint64 ("serial", "Serial", + "The internal serial of the PipeWire device", 0, G_MAXUINT64, SPA_ID_INVALID, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } static void @@ -176,6 +195,7 @@ struct pw_node *proxy; struct spa_hook proxy_listener; uint32_t id; + uint64_t serial; struct spa_hook node_listener; struct pw_node_info *info; GstCaps *caps; @@ -187,6 +207,7 @@ struct pw_port *proxy; struct spa_hook proxy_listener; uint32_t id; + uint64_t serial; struct spa_hook port_listener; }; @@ -236,9 +257,10 @@ gstdev = g_object_new (GST_TYPE_PIPEWIRE_DEVICE, "display-name", name, "caps", data->caps, "device-class", klass, - "id", data->id, "properties", props, NULL); + "id", data->id, "serial", data->serial, "properties", props, NULL); gstdev->id = data->id; + gstdev->serial = data->serial; gstdev->type = type; gstdev->element = element; if (props) @@ -476,6 +498,8 @@ nd->self = self; nd->proxy = node; nd->id = id; + if (!props || !spa_atou64(spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL), &nd->serial, 0)) + nd->serial = SPA_ID_INVALID; spa_list_append(&rd->nodes, &nd->link); pw_node_add_listener(node, &nd->node_listener, &node_events, nd); pw_proxy_add_listener((struct pw_proxy*)node, &nd->proxy_listener, &proxy_node_events, nd); @@ -500,6 +524,8 @@ pd->node_data = nd; pd->proxy = port; pd->id = id; + if (!props || !spa_atou64(spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL), &pd->serial, 0)) + pd->serial = SPA_ID_INVALID; pw_port_add_listener(port, &pd->port_listener, &port_events, pd); pw_proxy_add_listener((struct pw_proxy*)port, &pd->proxy_listener, &proxy_port_events, pd); resync(self);
View file
pipewire-0.3.48.tar.gz/src/gst/gstpipewiredeviceprovider.h -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiredeviceprovider.h
Changed
@@ -56,6 +56,7 @@ GstPipeWireDeviceType type; uint32_t id; + uint64_t serial; const gchar *element; };
View file
pipewire-0.3.48.tar.gz/src/gst/gstpipewiresink.c -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiresink.c
Changed
@@ -60,6 +60,7 @@ { PROP_0, PROP_PATH, + PROP_TARGET_OBJECT, PROP_CLIENT_NAME, PROP_STREAM_PROPERTIES, PROP_MODE, @@ -124,6 +125,7 @@ if (pwsink->properties) gst_structure_free (pwsink->properties); g_free (pwsink->path); + g_free (pwsink->target_object); g_free (pwsink->client_name); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -160,6 +162,16 @@ "The sink path to connect to (NULL = default)", NULL, G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_DEPRECATED)); + + g_object_class_install_property (gobject_class, + PROP_TARGET_OBJECT, + g_param_spec_string ("target-object", + "Target object", + "The sink name/serial to connect to (NULL = default)", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, @@ -339,6 +351,11 @@ pwsink->path = g_value_dup_string (value); break; + case PROP_TARGET_OBJECT: + g_free (pwsink->target_object); + pwsink->target_object = g_value_dup_string (value); + break; + case PROP_CLIENT_NAME: g_free (pwsink->client_name); pwsink->client_name = g_value_dup_string (value); @@ -376,6 +393,10 @@ g_value_set_string (value, pwsink->path); break; + case PROP_TARGET_OBJECT: + g_value_set_string (value, pwsink->target_object); + break; + case PROP_CLIENT_NAME: g_value_set_string (value, pwsink->client_name); break; @@ -522,15 +543,37 @@ if (state == PW_STREAM_STATE_UNCONNECTED) { enum pw_stream_flags flags = 0; + uint32_t target_id; if (pwsink->mode != GST_PIPEWIRE_SINK_MODE_PROVIDE) flags |= PW_STREAM_FLAG_AUTOCONNECT; else flags |= PW_STREAM_FLAG_DRIVER; + target_id = pwsink->path ? (uint32_t)atoi(pwsink->path) : PW_ID_ANY; + + if (pwsink->target_object) { + struct spa_dict_item items[2] = { + SPA_DICT_ITEM_INIT(PW_KEY_TARGET_OBJECT, pwsink->target_object), + SPA_DICT_ITEM_INIT(PW_KEY_NODE_TARGET, NULL), + }; + struct spa_dict dict = SPA_DICT_INIT_ARRAY(items); + uint64_t serial; + + /* If target.object is a name, set it also to node.target */ + if (spa_atou64(pwsink->target_object, &serial, 0)) { + dict.n_items = 1; + } else { + target_id = PW_ID_ANY; + items[1].value = pwsink->target_object; + } + + pw_stream_update_properties (pwsink->stream, &dict); + } + pw_stream_connect (pwsink->stream, PW_DIRECTION_OUTPUT, - pwsink->path ? (uint32_t)atoi(pwsink->path) : PW_ID_ANY, + target_id, flags, (const struct spa_pod **) possible->pdata, possible->len);
View file
pipewire-0.3.48.tar.gz/src/gst/gstpipewiresink.h -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiresink.h
Changed
@@ -78,6 +78,7 @@ /*< private >*/ gchar *path; + gchar *target_object; gchar *client_name; int fd;
View file
pipewire-0.3.48.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiresrc.c
Changed
@@ -67,6 +67,7 @@ { PROP_0, PROP_PATH, + PROP_TARGET_OBJECT, PROP_CLIENT_NAME, PROP_STREAM_PROPERTIES, PROP_ALWAYS_COPY, @@ -116,6 +117,11 @@ pwsrc->path = g_value_dup_string (value); break; + case PROP_TARGET_OBJECT: + g_free (pwsrc->target_object); + pwsrc->target_object = g_value_dup_string (value); + break; + case PROP_CLIENT_NAME: g_free (pwsrc->client_name); pwsrc->client_name = g_value_dup_string (value); @@ -169,6 +175,10 @@ g_value_set_string (value, pwsrc->path); break; + case PROP_TARGET_OBJECT: + g_value_set_string (value, pwsrc->target_object); + break; + case PROP_CLIENT_NAME: g_value_set_string (value, pwsrc->client_name); break; @@ -244,6 +254,7 @@ if (pwsrc->clock) gst_object_unref (pwsrc->clock); g_free (pwsrc->path); + g_free (pwsrc->target_object); g_free (pwsrc->client_name); g_object_unref(pwsrc->pool); @@ -274,6 +285,16 @@ "The source path to connect to (NULL = default)", NULL, G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_DEPRECATED)); + + g_object_class_install_property (gobject_class, + PROP_TARGET_OBJECT, + g_param_spec_string ("target-object", + "Target object", + "The source name/serial to connect to (NULL = default)", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, @@ -675,6 +696,7 @@ GPtrArray *possible; const char *error = NULL; struct timespec abstime; + uint32_t target_id; /* first see what is possible on our source pad */ thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL); @@ -727,11 +749,33 @@ } } - GST_DEBUG_OBJECT (basesrc, "connect capture with path %s", pwsrc->path); + target_id = pwsrc->path ? (uint32_t)atoi(pwsrc->path) : PW_ID_ANY; + + if (pwsrc->target_object) { + struct spa_dict_item items[2] = { + SPA_DICT_ITEM_INIT(PW_KEY_TARGET_OBJECT, pwsrc->target_object), + SPA_DICT_ITEM_INIT(PW_KEY_NODE_TARGET, NULL), + }; + struct spa_dict dict = SPA_DICT_INIT_ARRAY(items); + uint64_t serial; + + /* If target.object is a name, set it also to node.target */ + if (spa_atou64(pwsrc->target_object, &serial, 0)) { + dict.n_items = 1; + } else { + target_id = PW_ID_ANY; + items[1].value = pwsrc->target_object; + } + + pw_stream_update_properties (pwsrc->stream, &dict); + } + + GST_DEBUG_OBJECT (basesrc, "connect capture with path %s, target-object %s", + pwsrc->path, pwsrc->target_object); pwsrc->negotiated = FALSE; pw_stream_connect (pwsrc->stream, PW_DIRECTION_INPUT, - pwsrc->path ? (uint32_t)atoi(pwsrc->path) : PW_ID_ANY, + target_id, PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_DONT_RECONNECT, (const struct spa_pod **)possible->pdata, possible->len);
View file
pipewire-0.3.48.tar.gz/src/gst/gstpipewiresrc.h -> pipewire-0.3.49.tar.gz/src/gst/gstpipewiresrc.h
Changed
@@ -60,6 +60,7 @@ /*< private >*/ gchar *path; + gchar *target_object; gchar *client_name; gboolean always_copy; gint min_buffers;
View file
pipewire-0.3.48.tar.gz/src/modules/meson.build -> pipewire-0.3.49.tar.gz/src/modules/meson.build
Changed
@@ -131,8 +131,6 @@ dependencies : [spa_dep, mathlib, dl_lib, pipewire_dep], ) -build_module_rt = dbus_dep.found() -if build_module_rt pipewire_module_rt = shared_library('pipewire-module-rt', [ 'module-rt.c' ], include_directories : [configinc], install : true, @@ -140,6 +138,9 @@ install_rpath: modules_install_dir, dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep], ) + +build_module_rtkit = dbus_dep.found() +if build_module_rtkit # TODO: This serves as a temporary alias to prevent breaking existing setups # while `module-rtkit` is being migrated to `module-rt` pipewire_module_rtkit = shared_library('pipewire-module-rtkit', [ 'module-rt.c' ], @@ -150,7 +151,7 @@ dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep], ) endif -summary({'rt': build_module_rt}, bool_yn: true, section: 'Optional Modules') +summary({'rt': '@0@ RTKit'.format(build_module_rtkit ? 'with' : 'without')}, section: 'Optional Modules') build_module_portal = dbus_dep.found() if build_module_portal
View file
pipewire-0.3.48.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.49.tar.gz/src/modules/module-client-node/remote-node.c
Changed
@@ -843,9 +843,9 @@ { struct link *link = user_data; struct spa_system *data_system = link->data->context->data_system; - struct timespec ts; + struct timespec ts = { 0, 0 }; - pw_log_trace("link %p: signal", link); + pw_log_trace_fp("link %p: signal", link); spa_system_clock_gettime(data_system, CLOCK_MONOTONIC, &ts); link->target.activation->status = PW_NODE_ACTIVATION_TRIGGERED;
View file
pipewire-0.3.48.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.49.tar.gz/src/modules/module-echo-cancel.c
Changed
@@ -71,7 +71,7 @@ * - `source.props = {}`: properties to be passed to the source stream * - `sink.props = {}`: properties to be passed to the sink stream * - `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/libspa-aec-webrtc`. Leave unset to use the default method (`aec/libspa-aec-webrtc`). * - `aec.args = <str>`: arguments to pass to the echo cancellation method * * ## General options @@ -96,7 +96,7 @@ * context.modules = [ * { name = libpipewire-module-echo-cancel * args = { - * # library.name = aec/libspa-aec-exaudio + * # library.name = aec/libspa-aec-webrtc * # node.latency = 1024/48000 * source.props = { * node.name = "Echo Cancellation Source" @@ -139,7 +139,7 @@ "[ audio.channels=<number of channels> ] " "[ audio.position=<channel map> ] " "[ buffer.max_size=<max buffer size in ms> ] " - "[ buffer.play_delay=<play delay in ms> ] " + "[ buffer.play_delay=<delay as fraction> ] " "[ library.name =<library name> ] " "[ aec.args=<aec arguments> ] " "[ source.props=<properties> ] " @@ -731,7 +731,7 @@ return res; impl->rec_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000; - impl->play_ringsize = sizeof(float) * (impl->max_buffer_size + impl->buffer_delay) * impl->info.rate / 1000; + impl->play_ringsize = sizeof(float) * ((impl->max_buffer_size * impl->info.rate / 1000) + impl->buffer_delay); impl->out_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000; for (i = 0; i < impl->info.channels; i++) { impl->rec_buffer[i] = malloc(impl->rec_ringsize); @@ -744,9 +744,9 @@ spa_ringbuffer_init(&impl->out_ring); spa_ringbuffer_get_write_index(&impl->play_ring, &index); - spa_ringbuffer_write_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay) * impl->info.rate / 1000)); + spa_ringbuffer_write_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay))); spa_ringbuffer_get_read_index(&impl->play_ring, &index); - spa_ringbuffer_read_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay) * impl->info.rate / 1000)); + spa_ringbuffer_read_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay))); return 0; } @@ -1054,7 +1054,23 @@ copy_props(impl, props, PW_KEY_NODE_LATENCY); impl->max_buffer_size = pw_properties_get_uint32(props,"buffer.max_size", MAX_BUFSIZE_MS); - impl->buffer_delay = pw_properties_get_uint32(props,"buffer.play_delay", DELAY_MS); + + if ((str = pw_properties_get(props, "buffer.play_delay")) != NULL) { + int req_num, req_denom; + if (sscanf(str, "%u/%u", &req_num, &req_denom) == 2) { + if (req_denom != 0) { + impl->buffer_delay = (impl->info.rate*req_num)/req_denom; + } else { + impl->buffer_delay = DELAY_MS * impl->info.rate / 1000; + pw_log_warn("Sample rate for buffer.play_delay is 0 using default"); + } + } else { + impl->buffer_delay = DELAY_MS * impl->info.rate / 1000; + pw_log_warn("Wrong value/format for buffer.play_delay using default"); + } + } else { + impl->buffer_delay = DELAY_MS * impl->info.rate / 1000; + } pw_properties_free(props);
View file
pipewire-0.3.48.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.49.tar.gz/src/modules/module-filter-chain.c
Changed
@@ -408,14 +408,36 @@ SPA_PROP_INFO_name, SPA_POD_String(name), 0); spa_pod_builder_prop(b, SPA_PROP_INFO_type, 0); - if (min == max) { - spa_pod_builder_float(b, def); + if (p->hint & FC_HINT_BOOLEAN) { + if (min == max) { + spa_pod_builder_bool(b, def <= 0.0 ? false : true); + } else { + spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Enum, 0); + spa_pod_builder_bool(b, def <= 0.0 ? false : true); + spa_pod_builder_bool(b, false); + spa_pod_builder_bool(b, true); + spa_pod_builder_pop(b, &f[1]); + } + } else if (p->hint & FC_HINT_INTEGER) { + if (min == max) { + spa_pod_builder_int(b, def); + } else { + spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Range, 0); + spa_pod_builder_int(b, def); + spa_pod_builder_int(b, min); + spa_pod_builder_int(b, max); + spa_pod_builder_pop(b, &f[1]); + } } else { - spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Range, 0); - spa_pod_builder_float(b, def); - spa_pod_builder_float(b, min); - spa_pod_builder_float(b, max); - spa_pod_builder_pop(b, &f[1]); + if (min == max) { + spa_pod_builder_float(b, def); + } else { + spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Range, 0); + spa_pod_builder_float(b, def); + spa_pod_builder_float(b, min); + spa_pod_builder_float(b, max); + spa_pod_builder_pop(b, &f[1]); + } } spa_pod_builder_prop(b, SPA_PROP_INFO_params, 0); spa_pod_builder_bool(b, true); @@ -446,7 +468,13 @@ snprintf(name, sizeof(name), "%s", p->name); spa_pod_builder_string(b, name); - spa_pod_builder_float(b, port->control_data); + if (p->hint & FC_HINT_BOOLEAN) { + spa_pod_builder_bool(b, port->control_data <= 0.0 ? false : true); + } else if (p->hint & FC_HINT_INTEGER) { + spa_pod_builder_int(b, port->control_data); + } else { + spa_pod_builder_float(b, port->control_data); + } } spa_pod_builder_pop(b, &f[1]); return spa_pod_builder_pop(b, &f[0]); @@ -487,12 +515,23 @@ while (true) { const char *name; float value, *val = NULL; + bool bool_val; + int32_t int_val; if (spa_pod_parser_get_string(&prs, &name) < 0) break; - if (spa_pod_parser_get_float(&prs, &value) >= 0) + if (spa_pod_parser_get_float(&prs, &value) >= 0) { val = &value; - + } else if (spa_pod_parser_get_int(&prs, &int_val) >= 0) { + value = int_val; + val = &value; + } else if (spa_pod_parser_get_bool(&prs, &bool_val) >= 0) { + value = bool_val ? 1.0f : 0.0f; + val = &value; + } else { + struct spa_pod *pod; + spa_pod_parser_get_pod(&prs, &pod); + } changed += set_control_value(def_node, name, val); } return changed; @@ -524,13 +563,14 @@ } if (changed > 0) { uint8_t buffer[1024]; - struct spa_pod_builder b; + struct spa_pod_dynamic_builder b; const struct spa_pod *params[1]; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - params[0] = get_props_param(graph, &b); + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + params[0] = get_props_param(graph, &b.b); pw_stream_update_params(impl->capture, params, 1); + spa_pod_dynamic_builder_clean(&b); } }
View file
pipewire-0.3.48.tar.gz/src/modules/module-filter-chain/plugin.h -> pipewire-0.3.49.tar.gz/src/modules/module-filter-chain/plugin.h
Changed
@@ -47,7 +47,9 @@ #define FC_PORT_AUDIO (1ULL << 3) uint64_t flags; +#define FC_HINT_BOOLEAN (1ULL << 2) #define FC_HINT_SAMPLE_RATE (1ULL << 3) +#define FC_HINT_INTEGER (1ULL << 5) uint64_t hint; float def; float min;
View file
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/extensions/ext-stream-restore.c
Changed
@@ -235,7 +235,7 @@ FILE *f; char *ptr; size_t size; - char key[1024]; + char key[1024], buf[128]; spa_zero(map); spa_zero(vol); @@ -260,7 +260,8 @@ if (vol.channels > 0) { fprintf(f, ", \"volumes\": ["); for (i = 0; i < vol.channels; i++) - fprintf(f, "%s%f", (i == 0 ? " ":", "), vol.values[i]); + fprintf(f, "%s%s", (i == 0 ? " ":", "), + spa_json_format_float(buf, sizeof(buf), vol.values[i])); fprintf(f, " ]"); } if (map.channels > 0) {
View file
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/manager.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/manager.c
Changed
@@ -812,6 +812,8 @@ struct manager *m = SPA_CONTAINER_OF(manager, struct manager, this); struct object *o; + spa_hook_list_clean(&m->hooks); + spa_hook_remove(&m->core_listener); spa_list_consume(o, &m->this.object_list, this.link)
View file
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/module.c
Changed
@@ -67,6 +67,7 @@ if (module == NULL) return NULL; + module->index = SPA_ID_INVALID; module->impl = impl; module->methods = methods; spa_hook_list_init(&module->listener_list); @@ -102,8 +103,10 @@ if (module->index != SPA_ID_INVALID) pw_map_remove(&impl->modules, module->index & MODULE_INDEX_MASK); + if (module->unloading) + pw_work_queue_cancel(impl->work_queue, module, SPA_ID_INVALID); + spa_hook_list_clean(&module->listener_list); - pw_work_queue_cancel(impl->work_queue, module, SPA_ID_INVALID); pw_properties_free(module->props); free((char*)module->name);
View file
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c
Changed
@@ -166,8 +166,7 @@ pw_stream_queue_buffer(data->streams[i].stream, out); } - if (in != NULL) - pw_stream_queue_buffer(data->sink, in); + pw_stream_queue_buffer(data->sink, in); } static void check_initialized(struct module_combine_sink_data *data)
View file
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c
Changed
@@ -78,7 +78,7 @@ fprintf(f, "{"); pw_properties_serialize_dict(f, &data->roc_props->dict, 0); - fprintf(f, " } sink.props = {"); + fprintf(f, " sink.props = {"); pw_properties_serialize_dict(f, &data->sink_props->dict, 0); fprintf(f, " } }"); fclose(f); @@ -125,6 +125,7 @@ { PW_KEY_MODULE_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" }, { PW_KEY_MODULE_DESCRIPTION, "roc sink" }, { PW_KEY_MODULE_USAGE, "sink_name=<name for the sink> " + "sink_properties=<properties for the sink> " "local_ip=<local sender ip> " "remote_ip=<remote receiver ip> " "remote_source_port=<remote receiver port for source packets> " @@ -156,6 +157,10 @@ pw_properties_set(sink_props, PW_KEY_NODE_NAME, str); pw_properties_set(props, "sink_name", NULL); } + if ((str = pw_properties_get(props, "sink_properties")) != NULL) { + module_args_add_props(sink_props, str); + pw_properties_set(props, "sink_properties", NULL); + } if ((str = pw_properties_get(props, PW_KEY_MEDIA_CLASS)) == NULL) { pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
View file
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c
Changed
@@ -78,7 +78,7 @@ fprintf(f, "{"); pw_properties_serialize_dict(f, &data->roc_props->dict, 0); - fprintf(f, " } source.props = {"); + fprintf(f, " source.props = {"); pw_properties_serialize_dict(f, &data->source_props->dict, 0); fprintf(f, " } }"); fclose(f); @@ -125,6 +125,7 @@ { PW_KEY_MODULE_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" }, { PW_KEY_MODULE_DESCRIPTION, "roc source" }, { PW_KEY_MODULE_USAGE, "source_name=<name for the source> " + "source_properties=<properties for the source> " "resampler_profile=<empty>|disable|high|medium|low " "sess_latency_msec=<target network latency in milliseconds> " "local_ip=<local receiver ip> " @@ -158,6 +159,10 @@ pw_properties_set(source_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(source_props, str); + pw_properties_set(props, "source_properties", NULL); + } if ((str = pw_properties_get(props, PW_KEY_MEDIA_CLASS)) == NULL) { pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Source");
View file
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
@@ -1822,7 +1822,7 @@ n_valid_formats++; } } - if (n_params < MAX_FORMATS && + else if (n_params < MAX_FORMATS && (params[n_params] = format_build_param(&b, SPA_PARAM_EnumFormat, &ss, ss.channels > 0 ? &map : NULL)) != NULL) { @@ -5350,6 +5350,8 @@ support = pw_context_get_support(context, &n_support); cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); + pw_context_conf_update_props(context, "pulse.properties", props); + if ((str = pw_properties_get(props, "vm.overrides")) != NULL) { if (cpu != NULL && spa_cpu_get_vm_type(cpu) != SPA_CPU_VM_NONE) pw_properties_update_string(props, str, strlen(str));
View file
pipewire-0.3.48.tar.gz/src/modules/module-protocol-pulse/sample-play.c -> pipewire-0.3.49.tar.gz/src/modules/module-protocol-pulse/sample-play.c
Changed
@@ -211,6 +211,8 @@ if (p->stream) pw_stream_destroy(p->stream); + spa_hook_list_clean(&p->hooks); + free(p); }
View file
pipewire-0.3.48.tar.gz/src/modules/module-rt.c -> pipewire-0.3.49.tar.gz/src/modules/module-rt.c
Changed
@@ -1,6 +1,6 @@ /* PipeWire * - * Copyright © 2018 Wim Taymans + * 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"), @@ -21,6 +21,30 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +/*** + Copyright 2009 Lennart Poettering + Copyright 2010 David Henningsson <diwic@ubuntu.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 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 <stdlib.h> #include <stdbool.h> @@ -35,16 +59,21 @@ #include <unistd.h> #include <pthread.h> #include <sys/resource.h> +#include <sys/syscall.h> #include "config.h" -#include <spa/support/dbus.h> #include <spa/utils/result.h> #include <spa/utils/string.h> #include <pipewire/impl.h> #include <pipewire/thread.h> +#ifdef HAVE_DBUS +#include <spa/support/dbus.h> +#include <dbus/dbus.h> +#endif + /** \page page_module_rt PipeWire Module: RT * * The `rt` module uses the operating system's scheduler to enable realtime @@ -87,7 +116,15 @@ { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; -struct pw_rtkit_bus; +#ifdef HAVE_DBUS +#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1" +#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1" + +/** \cond */ +struct pw_rtkit_bus { + DBusConnection *bus; +}; +/** \endcond */ struct thread { struct impl *impl; @@ -97,6 +134,7 @@ void *(*start)(void*); void *arg; }; +#endif /* HAVE_DBUS */ struct impl { struct pw_context *context; @@ -110,6 +148,7 @@ struct spa_hook module_listener; +#ifdef HAVE_DBUS bool use_rtkit; struct pw_rtkit_bus *system_bus; @@ -119,52 +158,29 @@ pthread_mutex_t lock; pthread_cond_t cond; struct spa_list threads_list; +#endif }; -/*** - Copyright 2009 Lennart Poettering - Copyright 2010 David Henningsson <diwic@ubuntu.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 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 <dbus/dbus.h> - -#include "config.h" - -#include <sys/syscall.h> - -#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1" -#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1" - #ifndef RLIMIT_RTTIME #define RLIMIT_RTTIME 15 #endif -/** \cond */ -struct pw_rtkit_bus { - DBusConnection *bus; -}; -/** \endcond */ +static pid_t _gettid(void) +{ +#if defined(HAVE_GETTID) + return (pid_t) gettid(); +#elif defined(__linux__) + return syscall(SYS_gettid); +#elif defined(__FreeBSD__) + long pid; + thr_self(&pid); + return (pid_t)pid; +#else +#error "No gettid impl" +#endif +} +#ifdef HAVE_DBUS struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) { struct pw_rtkit_bus *bus; @@ -204,21 +220,6 @@ free(system_bus); } -static pid_t _gettid(void) -{ -#if defined(HAVE_GETTID) - return (pid_t) gettid(); -#elif defined(__linux__) - return syscall(SYS_gettid); -#elif defined(__FreeBSD__) - long pid; - thr_self(&pid); - return (pid_t)pid; -#else -#error "No gettid impl" -#endif -} - static int translate_error(const char *name) { pw_log_warn("RTKit error: %s", name); @@ -458,6 +459,7 @@ return ret; } +#endif /* HAVE_DBUS */ static void module_destroy(void *data) { @@ -466,8 +468,11 @@ pw_thread_utils_set(NULL); spa_hook_remove(&impl->module_listener); +#ifdef HAVE_DBUS if (impl->system_bus)
View file
pipewire-0.3.48.tar.gz/src/modules/module-zeroconf-discover/avahi-poll.c -> pipewire-0.3.49.tar.gz/src/modules/module-zeroconf-discover/avahi-poll.c
Changed
@@ -37,6 +37,7 @@ AvahiWatchEvent events; AvahiWatchCallback callback; void *userdata; + unsigned int dispatching; }; struct AvahiTimeout { @@ -65,9 +66,14 @@ { AvahiWatch *w = data; + w->dispatching += 1; + w->events = from_pw_events(mask); w->callback(w, fd, w->events, w->userdata); w->events = 0; + + if (--w->dispatching == 0 && !w->source) + free(w); } static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, @@ -103,9 +109,11 @@ static void watch_free(AvahiWatch *w) { - struct impl *impl = w->impl; - pw_loop_destroy_source(impl->loop, w->source); - free(w); + pw_loop_destroy_source(w->impl->loop, w->source); + w->source = NULL; + + if (!w->dispatching) + free(w); } static void timeout_callback(void *data, uint64_t expirations)
View file
pipewire-0.3.48.tar.gz/src/pipewire/filter.c -> pipewire-0.3.49.tar.gz/src/pipewire/filter.c
Changed
@@ -642,7 +642,7 @@ clear_params(impl, port, id); } else { for (i = 0; i < n_params; i++) { - if (!spa_pod_is_object(params[i])) + if (params[i] == NULL || !spa_pod_is_object(params[i])) continue; clear_params(impl, port, SPA_POD_OBJECT_ID(params[i])); }
View file
pipewire-0.3.48.tar.gz/src/pipewire/pipewire.c -> pipewire-0.3.49.tar.gz/src/pipewire/pipewire.c
Changed
@@ -89,7 +89,7 @@ struct spa_interface i18n_iface; struct spa_support support[MAX_SUPPORT]; uint32_t n_support; - unsigned int initialized:1; + uint32_t init_count; unsigned int in_valgrind:1; unsigned int no_color:1; unsigned int no_config:1; @@ -413,11 +413,9 @@ static void init_i18n(struct support *support) { - /* Load locale from the environment. */ - setlocale(LC_ALL, ""); - /* Set LC_NUMERIC to C so that floating point strings are consistently - * formatted and parsed across locales. */ - setlocale(LC_NUMERIC, "C"); + /* XXX: we should remove this setlocale() call, after wireplumber + * XXX: starts setting the locale */ + setlocale(LC_MESSAGES, ""); bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); pw_set_domain(GETTEXT_PACKAGE); @@ -594,7 +592,7 @@ char level[32]; pthread_mutex_lock(&init_lock); - if (support->initialized) + if (support->init_count > 0) goto done; pthread_mutex_lock(&support_lock); @@ -666,9 +664,9 @@ add_i18n(support); pw_log_info("version %s", pw_get_library_version()); - support->initialized = true; pthread_mutex_unlock(&support_lock); done: + support->init_count++; pthread_mutex_unlock(&init_lock); } @@ -680,6 +678,11 @@ struct plugin *p; pthread_mutex_lock(&init_lock); + if (support->init_count == 0) + goto done; + if (--support->init_count > 0) + goto done; + pthread_mutex_lock(&support_lock); pw_log_set(NULL); spa_list_consume(p, ®istry->plugins, link) { @@ -693,6 +696,7 @@ free(support->i18n_domain); spa_zero(global_support); pthread_mutex_unlock(&support_lock); +done: pthread_mutex_unlock(&init_lock); }
View file
pipewire-0.3.48.tar.gz/src/pipewire/stream.c -> pipewire-0.3.49.tar.gz/src/pipewire/stream.c
Changed
@@ -116,6 +116,8 @@ struct spa_io_clock *clock; struct spa_io_position *position; struct spa_io_buffers *io; + struct spa_io_rate_match *rate_match; + uint32_t rate_queued; struct { struct spa_io_position *position; } rt; @@ -295,7 +297,7 @@ clear_params(impl, id); } else { for (i = 0; i < n_params; i++) { - if (!spa_pod_is_object(params[i])) + if (params[i] == NULL || !spa_pod_is_object(params[i])) continue; clear_params(impl, SPA_POD_OBJECT_ID(params[i])); } @@ -390,14 +392,14 @@ { struct stream *impl = user_data; struct pw_stream *stream = &impl->this; - pw_log_trace("%p: do process", stream); + pw_log_trace_fp("%p: do process", stream); pw_stream_emit_process(stream); return 0; } static void call_process(struct stream *impl) { - pw_log_trace("%p: call process rt:%u", impl, impl->process_rt); + pw_log_trace_fp("%p: call process rt:%u", impl, impl->process_rt); if (impl->process_rt) spa_callbacks_call(&impl->rt_callbacks, struct pw_stream_events, process, 0); else @@ -411,7 +413,7 @@ { struct stream *impl = user_data; struct pw_stream *stream = &impl->this; - pw_log_trace("%p: drained", stream); + pw_log_trace_fp("%p: drained", stream); pw_stream_emit_drained(stream); return 0; } @@ -428,7 +430,7 @@ { struct stream *impl = user_data; struct pw_stream *stream = &impl->this; - pw_log_trace("%p: trigger_done", stream); + pw_log_trace_fp("%p: trigger_done", stream); pw_stream_emit_trigger_done(stream); return 0; } @@ -669,6 +671,12 @@ else impl->io = NULL; break; + case SPA_IO_RateMatch: + if (data && size >= sizeof(struct spa_io_rate_match)) + impl->rate_match = data; + else + impl->rate_match = NULL; + break; } pw_stream_emit_io_changed(stream, id, data, size); @@ -917,8 +925,9 @@ static inline void copy_position(struct stream *impl, int64_t queued) { struct spa_io_position *p = impl->rt.position; - if (SPA_UNLIKELY(p != NULL)) { - SEQ_WRITE(impl->seq); + + SEQ_WRITE(impl->seq); + if (SPA_LIKELY(p != NULL)) { impl->time.now = p->clock.nsec; impl->time.rate = p->clock.rate; if (SPA_UNLIKELY(impl->clock_id != p->clock.id)) { @@ -929,8 +938,10 @@ impl->time.delay = 0; impl->time.queued = queued; impl->quantum = p->clock.duration; - SEQ_WRITE(impl->seq); } + if (SPA_LIKELY(impl->rate_match != NULL)) + impl->rate_queued = impl->rate_match->delay; + SEQ_WRITE(impl->seq); } static int impl_node_process_input(void *object) @@ -940,7 +951,7 @@ struct spa_io_buffers *io = impl->io; struct buffer *b; - pw_log_trace("%p: process in status:%d id:%d ticks:%"PRIu64" delay:%"PRIi64, + pw_log_trace_fp("%p: process in status:%d id:%d ticks:%"PRIu64" delay:%"PRIi64, stream, io->status, io->buffer_id, impl->time.ticks, impl->time.delay); if (io->status == SPA_STATUS_HAVE_DATA && @@ -956,7 +967,7 @@ if (io->status != SPA_STATUS_NEED_DATA) { /* pop buffer to recycle */ if ((b = pop_queue(impl, &impl->queued))) { - pw_log_trace("%p: recycle buffer %d", stream, b->id); + pw_log_trace_fp("%p: recycle buffer %d", stream, b->id); } else if (io->status == -EPIPE) return io->status; io->buffer_id = b ? b->id : SPA_ID_INVALID; @@ -976,16 +987,19 @@ struct buffer *b; int res; uint32_t index; + bool recycled; again: - pw_log_trace("%p: process out status:%d id:%d", stream, + pw_log_trace_fp("%p: process out status:%d id:%d", stream, io->status, io->buffer_id); + recycled = false; if ((res = io->status) != SPA_STATUS_HAVE_DATA) { /* recycle old buffer */ if ((b = get_buffer(stream, io->buffer_id)) != NULL) { - pw_log_trace("%p: recycle buffer %d", stream, b->id); + pw_log_trace_fp("%p: recycle buffer %d", stream, b->id); push_queue(impl, &impl->dequeued, b); + recycled = true; } /* pop new buffer */ @@ -993,17 +1007,17 @@ impl->drained = false; io->buffer_id = b->id; res = io->status = SPA_STATUS_HAVE_DATA; - pw_log_trace("%p: pop %d %p", stream, b->id, io); + pw_log_trace_fp("%p: pop %d %p", stream, b->id, io); } else if (impl->draining || impl->drained) { impl->draining = true; impl->drained = true; io->buffer_id = SPA_ID_INVALID; res = io->status = SPA_STATUS_DRAINED; - pw_log_trace("%p: draining", stream); + pw_log_trace_fp("%p: draining", stream); } else { io->buffer_id = SPA_ID_INVALID; res = io->status = SPA_STATUS_NEED_DATA; - pw_log_trace("%p: no more buffers %p", stream, io); + pw_log_trace_fp("%p: no more buffers %p", stream, io); } } @@ -1012,12 +1026,12 @@ if (!impl->draining && !impl->driving) { /* we're not draining, not a driver check if we need to get * more buffers */ - if (!impl->process_rt) { + if (!impl->process_rt && (recycled || res == SPA_STATUS_NEED_DATA)) { /* not realtime and we have a free buffer, trigger process so that we have * data in the next round. */ if (spa_ringbuffer_get_read_index(&impl->dequeued.ring, &index) > 0) call_process(impl); - } else if (io->status == SPA_STATUS_NEED_DATA) { + } else if (res == SPA_STATUS_NEED_DATA) { /* realtime and we don't have a buffer, trigger process and try * again when there is something in the queue now */ call_process(impl); @@ -1027,7 +1041,7 @@ } } - pw_log_trace("%p: res %d", stream, res); + pw_log_trace_fp("%p: res %d", stream, res); if (impl->driving && impl->using_trigger && res != SPA_STATUS_HAVE_DATA) call_trigger_done(impl); @@ -2061,10 +2075,12 @@ { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); uintptr_t seq1, seq2; + uint32_t rate_queued; do { seq1 = SEQ_READ(impl->seq); *time = impl->time; + rate_queued = impl->rate_queued; seq2 = SEQ_READ(impl->seq); } while (!SEQ_READ_SUCCESS(seq1, seq2)); @@ -2073,11 +2089,13 @@ else time->queued = (int64_t)(impl->queued.incount - time->queued); + time->queued += rate_queued; + time->delay += ((impl->latency.min_quantum + impl->latency.max_quantum) / 2) * impl->quantum; time->delay += (impl->latency.min_rate + impl->latency.max_rate) / 2; time->delay += ((impl->latency.min_ns + impl->latency.max_ns) / 2) * time->rate.denom / SPA_NSEC_PER_SEC; - pw_log_trace("%p: %"PRIi64" %"PRIi64" %"PRIu64" %d/%d %"PRIu64" %" + pw_log_trace_fp("%p: %"PRIi64" %"PRIi64" %"PRIu64" %d/%d %"PRIu64" %"
View file
pipewire-0.3.48.tar.gz/src/pipewire/stream.h -> pipewire-0.3.49.tar.gz/src/pipewire/stream.h
Changed
@@ -193,16 +193,30 @@ /** A time structure */ struct pw_time { - int64_t now; /**< the monotonic time in nanoseconds */ - struct spa_fraction rate; /**< the rate of \a ticks and delay */ + int64_t now; /**< the monotonic time in nanoseconds. This is the time + * when this time report was updated. It is usually + * updated every graph cycle. You can use the current + * monotonic time to calculate the elapsed time between + * this report and the current state and calculate + * updated ticks and delay values. */ + struct spa_fraction rate; /**< the rate of \a ticks and delay. This is usually + * expressed in 1/<samplerate>. */ uint64_t ticks; /**< the ticks at \a now. This is the current time that * the remote end is reading/writing. */ - int64_t delay; /**< delay to device, add to ticks to get the time of the - * device. Positive for INPUT streams and - * negative for OUTPUT streams. */ + int64_t delay; /**< delay to device. This is the time it will take for + * the next sample in the stream to be presented by + * the playback device or the time a sample traveled + * from the capture device. This delay includes the + * delay introduced by all filters on the path between + * the stream and the device. The delay is normally + * constant in a graph and can change when the topology + * of the graph or the quantum changes. */ uint64_t queued; /**< data queued in the stream, this is the sum * of the size fields in the pw_buffer that are - * currently queued */ + * currently queued and, for audio streams, the extra + * data queued in the resampler. For audio streams, it + * is thus highly recommended to use the buffer size + * field as the sample count in the buffer. */ }; #include <pipewire/port.h>
View file
pipewire-0.3.48.tar.gz/src/tools/dsffile.c -> pipewire-0.3.49.tar.gz/src/tools/dsffile.c
Changed
@@ -214,33 +214,39 @@ dsf_file_read(struct dsf_file *f, void *data, size_t samples, const struct dsf_layout *layout) { uint8_t *d = data; - const uint8_t *s; - uint32_t i, j, k, total, stride, bytes; - int32_t interleave = layout->interleave; + int step = SPA_ABS(layout->interleave); bool rev = layout->lsb != f->info.lsb; - - stride = layout->channels * layout->interleave; - bytes = samples * stride; - bytes -= bytes % f->info.blocksize; - - for (total = 0; total < bytes; total += layout->channels * f->info.blocksize) { - s = f->p + f->offset; - - for (i = 0; i < f->info.blocksize; i += interleave) { - for (j = 0; j < layout->channels; j++) { - const uint8_t *c = &s[f->info.blocksize * j + i]; - if (interleave > 0) { - for (k = 0; k < (uint32_t)interleave; k++) - *d++ = rev ? bitrev[c[k]] : c[k]; - } else { - for (k = -interleave; k > 0; k--) - *d++ = rev ? bitrev[c[k-1]] : c[k-1]; - } + size_t total, block, offset, pos; + + block = f->offset / f->info.blocksize; + offset = block * f->info.blocksize * f->info.channels; + pos = f->offset % f->info.blocksize; + + for (total = 0; total < samples && offset + pos < f->info.length; total++) { + const uint8_t *s = f->p + offset + pos; + uint32_t i; + + for (i = 0; i < layout->channels; i++) { + const uint8_t *c = &s[f->info.blocksize * i]; + int j; + + if (layout->interleave > 0) { + for (j = 0; j < step; j++) + *d++ = rev ? bitrev[c[j]] : c[j]; + } else { + for (j = step-1; j >= 0; j--) + *d++ = rev ? bitrev[c[j]] : c[j]; } } - f->offset += f->info.channels * f->info.blocksize; + pos += step; + if (pos == f->info.blocksize) { + pos = 0; + offset += f->info.blocksize * f->info.channels; + } } - return total / stride; + f->offset += total * step; + + return total; } int dsf_file_close(struct dsf_file *f)
View file
pipewire-0.3.48.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.49.tar.gz/src/tools/pw-cat.c
Changed
@@ -34,6 +34,7 @@ #include <unistd.h> #include <assert.h> #include <ctype.h> +#include <locale.h> #include <sndfile.h> @@ -915,7 +916,7 @@ data->dsf.layout.channels = info.info.dsd.channels; data->dsf.layout.lsb = info.info.dsd.bitorder == SPA_PARAM_BITORDER_lsb; - data->stride = data->dsf.info.channels * SPA_ABS(data->dsf.layout.interleave); + data->stride = data->dsf.layout.channels * SPA_ABS(data->dsf.layout.interleave); if (data->verbose) { printf("DSD out: channels:%d bitorder:%s interleave:%d\n", @@ -1268,13 +1269,14 @@ } if (data->verbose) - printf("opened file \"%s\" channels:%d rate:%d bitorder:%s\n", + printf("opened file \"%s\" channels:%d rate:%d samples:%"PRIu64" bitorder:%s\n", data->filename, data->dsf.info.channels, data->dsf.info.rate, + data->dsf.info.samples, data->dsf.info.lsb ? "lsb" : "msb"); data->fill = dsf_play; -; + return 0; } @@ -1488,6 +1490,7 @@ int exit_code = EXIT_FAILURE, c, ret; enum pw_stream_flags flags = 0; + setlocale(LC_ALL, ""); pw_init(&argc, &argv); flags |= PW_STREAM_FLAG_AUTOCONNECT;
View file
pipewire-0.3.48.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.49.tar.gz/src/tools/pw-cli.c
Changed
@@ -35,6 +35,7 @@ #include <fnmatch.h> #include <readline/readline.h> #include <readline/history.h> +#include <locale.h> #if !defined(FNM_EXTMATCH) #define FNM_EXTMATCH 0 @@ -3076,6 +3077,7 @@ setlinebuf(stdout); + setlocale(LC_ALL, ""); pw_init(&argc, &argv); while ((c = getopt_long(argc, argv, "hVdr:", long_options, NULL)) != -1) {
View file
pipewire-0.3.48.tar.gz/src/tools/pw-dot.c -> pipewire-0.3.49.tar.gz/src/tools/pw-dot.c
Changed
@@ -25,9 +25,16 @@ #include <stdio.h> #include <signal.h> #include <getopt.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <locale.h> #include <spa/utils/result.h> #include <spa/utils/string.h> +#include <spa/utils/json.h> #include <spa/debug/pod.h> #include <spa/debug/format.h> #include <spa/debug/types.h> @@ -77,7 +84,6 @@ #define INTERFACE_Module 5 #define INTERFACE_Factory 6 uint32_t type; - struct pw_properties *props; void *info; pw_destroy_t info_destroy; @@ -152,9 +158,8 @@ } } -static SPA_PRINTF_FUNC(7,0) void draw_vlabel(char **str, const char *name, uint32_t id, bool detail, - const struct spa_dict *info_p, const struct spa_dict *p, - const char *fmt, va_list varargs) +static SPA_PRINTF_FUNC(6,0) void draw_vlabel(char **str, const char *name, uint32_t id, bool detail, + const struct spa_dict *props, const char *fmt, va_list varargs) { /* draw the label header */ dot_str_add(str, "%s_%u [label=\"", name, id); @@ -162,22 +167,19 @@ /* draw the label body */ dot_str_vadd(str, fmt, varargs); - if (detail) { - draw_dict(str, "info_props", info_p); - draw_dict(str, "properties", p); - } + if (detail) + draw_dict(str, "properties", props); /*draw the label footer */ dot_str_add(str, "%s", "\"];\n"); } -static SPA_PRINTF_FUNC(7,8) void draw_label(char **str, const char *name, uint32_t id, bool detail, - const struct spa_dict *info_p, const struct spa_dict *p, - const char *fmt, ...) +static SPA_PRINTF_FUNC(6,7) void draw_label(char **str, const char *name, uint32_t id, bool detail, + const struct spa_dict *props, const char *fmt, ...) { va_list varargs; va_start(varargs, fmt); - draw_vlabel(str, name, id, detail, info_p, p, fmt, varargs); + draw_vlabel(str, name, id, detail, props, fmt, varargs); va_end(varargs); } @@ -199,7 +201,7 @@ /* draw the label */ draw_label(dot_str, - "port", g->id, g->data->show_detail, info->props, &g->props->dict, + "port", g->id, g->data->show_detail, info->props, "port_id: %u\\lname: %s\\ldirection: %s\\l", g->id, spa_dict_lookup(info->props, PW_KEY_PORT_NAME), @@ -237,10 +239,9 @@ g->id, spa_dict_lookup(info->props, PW_KEY_NODE_NAME), spa_dict_lookup(info->props, PW_KEY_MEDIA_CLASS)); - if (g->data->show_detail) { - draw_dict(dot_str, "info_props", info->props); - draw_dict(dot_str, "properties", &g->props->dict); - } + + if (g->data->show_detail) + draw_dict(dot_str, "properties", info->props); /*draw the label footer */ dot_str_add(dot_str, "%s", "\"\n"); @@ -249,11 +250,13 @@ struct global *p; const char *prop_node_id; spa_list_for_each(p, &g->data->globals, link) { + struct pw_port_info *pinfo; if (p->info == NULL) continue; if (p->type != INTERFACE_Port) continue; - prop_node_id = pw_properties_get(p->props, PW_KEY_NODE_ID); + pinfo = p->info; + prop_node_id = spa_dict_lookup(pinfo->props, PW_KEY_NODE_ID); if (!prop_node_id || (uint32_t)atoi(prop_node_id) != g->id) continue; if (p->draw) @@ -290,7 +293,7 @@ /* draw the label */ draw_label(dot_str, - "link", g->id, g->data->show_detail, info->props, &g->props->dict, + "link", g->id, g->data->show_detail, info->props, "link_id: %u\\loutput_node_id: %u\\linput_node_id: %u\\loutput_port_id: %u\\linput_port_id: %u\\lstate: %s\\l", g->id, info->output_node_id, @@ -318,7 +321,7 @@ /* draw the label */ draw_label(dot_str, - "client", g->id, g->data->show_detail, info->props, &g->props->dict, + "client", g->id, g->data->show_detail, info->props, "client_id: %u\\lname: %s\\lpid: %s\\l", g->id, spa_dict_lookup(info->props, PW_KEY_APP_NAME), @@ -345,7 +348,7 @@ /* draw the label */ draw_label(dot_str, - "device", g->id, g->data->show_detail, info->props, &g->props->dict, + "device", g->id, g->data->show_detail, info->props, "device_id: %u\\lname: %s\\lmedia_class: %s\\lapi: %s\\lpath: %s\\l", g->id, spa_dict_lookup(info->props, PW_KEY_DEVICE_NAME), @@ -376,7 +379,7 @@ /* draw the label */ draw_label(dot_str, - "factory", g->id, g->data->show_detail, info->props, &g->props->dict, + "factory", g->id, g->data->show_detail, info->props, "factory_id: %u\\lname: %s\\lmodule_id: %u\\l", g->id, info->name, module_id ); @@ -399,7 +402,7 @@ /* draw the label */ draw_label(dot_str, - "module", g->id, g->data->show_detail, info->props, &g->props->dict, + "module", g->id, g->data->show_detail, info->props, "module_id: %u\\lname: %s\\l", g->id, info->name ); @@ -611,9 +614,6 @@ 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); } static const struct pw_proxy_events proxy_events = { @@ -701,20 +701,17 @@ return; } - proxy = pw_registry_bind(d->registry, id, type, - client_version, - sizeof(struct global)); + proxy = pw_registry_bind(d->registry, id, type, client_version, 0); if (proxy == NULL) return; /* set the global data */ - g = pw_proxy_get_user_data(proxy); + g = calloc(1, sizeof(struct global)); g->data = d; g->proxy = proxy; g->id = id; g->type = object_type; - g->props = props ? pw_properties_new_dict(props) : NULL; g->info = NULL; g->info_destroy = info_destroy; @@ -762,6 +759,300 @@ pw_main_loop_quit(d->loop); } +static int get_data_from_pipewire(struct data *data, const char *opt_remote) +{ + struct pw_loop *l; + struct global *g; + + data->loop = pw_main_loop_new(NULL); + if (data->loop == NULL) { + fprintf(stderr, "can't create main loop: %m\n"); + return -1; + } + + l = pw_main_loop_get_loop(data->loop); + pw_loop_add_signal(l, SIGINT, do_quit, &data); + pw_loop_add_signal(l, SIGTERM, do_quit, &data); +
View file
pipewire-0.3.48.tar.gz/src/tools/pw-dump.c -> pipewire-0.3.49.tar.gz/src/tools/pw-dump.c
Changed
@@ -31,6 +31,7 @@ #include <limits.h> #include <math.h> #include <fnmatch.h> +#include <locale.h> #if !defined(FNM_EXTMATCH) #define FNM_EXTMATCH 0 @@ -278,13 +279,15 @@ static void put_double(struct data *d, const char *key, double val) { - put_fmt(d, key, "%s%f%s", NUMBER, val, NORMAL); + char buf[128]; + put_fmt(d, key, "%s%s%s", NUMBER, + spa_json_format_float(buf, sizeof(buf), val), NORMAL); } static void put_value(struct data *d, const char *key, const char *val) { int64_t li; - double dv; + float fv; if (val == NULL) put_literal(d, key, "null"); @@ -292,8 +295,8 @@ put_literal(d, key, val); else if (spa_atoi64(val, &li, 10)) put_int(d, key, li); - else if (spa_atod(val, &dv)) - put_double(d, key, dv); + else if (spa_json_parse_float(val, strlen(val), &fv)) + put_double(d, key, fv); else put_string(d, key, val); } @@ -1487,6 +1490,7 @@ }; int c; + setlocale(LC_ALL, ""); pw_init(&argc, &argv); data.out = stdout;
View file
pipewire-0.3.48.tar.gz/src/tools/pw-link.c -> pipewire-0.3.49.tar.gz/src/tools/pw-link.c
Changed
@@ -27,6 +27,7 @@ #include <math.h> #include <getopt.h> #include <regex.h> +#include <locale.h> #include <spa/utils/result.h> #include <spa/utils/string.h> @@ -599,6 +600,7 @@ { NULL, 0, NULL, 0} }; + setlocale(LC_ALL, ""); pw_init(&argc, &argv); spa_list_init(&data.objects);
View file
pipewire-0.3.48.tar.gz/src/tools/pw-loopback.c -> pipewire-0.3.49.tar.gz/src/tools/pw-loopback.c
Changed
@@ -29,6 +29,7 @@ #include <getopt.h> #include <limits.h> #include <math.h> +#include <locale.h> #include <spa/utils/result.h> #include <spa/pod/builder.h> @@ -124,6 +125,7 @@ }; int c, res = -1; + setlocale(LC_ALL, ""); pw_init(&argc, &argv); data.channels = DEFAULT_CHANNELS;
View file
pipewire-0.3.48.tar.gz/src/tools/pw-metadata.c -> pipewire-0.3.49.tar.gz/src/tools/pw-metadata.c
Changed
@@ -26,6 +26,7 @@ #include <signal.h> #include <math.h> #include <getopt.h> +#include <locale.h> #include <spa/utils/result.h> #include <spa/utils/string.h> @@ -198,6 +199,7 @@ setlinebuf(stdout); + setlocale(LC_ALL, ""); pw_init(&argc, &argv); data.opt_name = "default";
View file
pipewire-0.3.48.tar.gz/src/tools/pw-mididump.c -> pipewire-0.3.49.tar.gz/src/tools/pw-mididump.c
Changed
@@ -26,6 +26,7 @@ #include <signal.h> #include <math.h> #include <getopt.h> +#include <locale.h> #include <spa/utils/result.h> #include <spa/utils/defs.h> @@ -195,6 +196,7 @@ { NULL, 0, NULL, 0} }; + setlocale(LC_ALL, ""); pw_init(&argc, &argv); setlinebuf(stdout);
View file
pipewire-0.3.48.tar.gz/src/tools/pw-mon.c -> pipewire-0.3.49.tar.gz/src/tools/pw-mon.c
Changed
@@ -26,6 +26,7 @@ #include <signal.h> #include <getopt.h> #include <unistd.h> +#include <locale.h> #include <spa/utils/result.h> #include <spa/utils/string.h> @@ -771,6 +772,7 @@ int c; bool colors = false; + setlocale(LC_ALL, ""); pw_init(&argc, &argv); setlinebuf(stdout);
View file
pipewire-0.3.48.tar.gz/src/tools/pw-profiler.c -> pipewire-0.3.49.tar.gz/src/tools/pw-profiler.c
Changed
@@ -25,6 +25,7 @@ #include <stdio.h> #include <signal.h> #include <getopt.h> +#include <locale.h> #include <spa/utils/result.h> #include <spa/utils/string.h> @@ -565,6 +566,7 @@ }; int c; + setlocale(LC_ALL, ""); pw_init(&argc, &argv); while ((c = getopt_long(argc, argv, "hVr:o:", long_options, NULL)) != -1) {
View file
pipewire-0.3.48.tar.gz/src/tools/pw-reserve.c -> pipewire-0.3.49.tar.gz/src/tools/pw-reserve.c
Changed
@@ -26,6 +26,7 @@ #include <getopt.h> #include <signal.h> +#include <locale.h> #include <dbus/dbus.h> @@ -121,6 +122,7 @@ setlinebuf(stdout); + setlocale(LC_ALL, ""); pw_init(&argc, &argv); while ((c = getopt_long(argc, argv, "hVn:a:p:m", long_options, NULL)) != -1) {
View file
pipewire-0.3.48.tar.gz/test/meson.build -> pipewire-0.3.49.tar.gz/test/meson.build
Changed
@@ -119,6 +119,28 @@ link_with: pwtest_lib) ) +openal_info = find_program('openal-info', required: false) +if openal_info.found() + cdata.set_quoted('OPENAL_INFO_PATH', openal_info.full_path()) +endif +summary({'openal-info': openal_info.found()}, bool_yn: true, section: 'Functional test programs') + +pactl = find_program('pactl', required: false) +if pactl.found() + cdata.set_quoted('PACTL_PATH', pactl.full_path()) +endif +summary({'pactl': pactl.found()}, bool_yn: true, section: 'Functional test programs') + +if default_sm == 'media-session' or default_sm == 'wireplumber' + test('test-functional', + executable('test-functional', + 'test-functional.c', + include_directories: pwtest_inc, + dependencies: [ spa_dep ], + link_with: pwtest_lib) + ) +endif + valgrind = find_program('valgrind', required: false) summary({'valgrind (test setup)': valgrind.found()}, bool_yn: true, section: 'Optional programs') if valgrind.found()
View file
pipewire-0.3.48.tar.gz/test/pwtest.c -> pipewire-0.3.49.tar.gz/test/pwtest.c
Changed
@@ -128,6 +128,8 @@ struct spa_list suites; unsigned int timeout; bool no_fork; + bool terminate; + struct spa_list cleanup_pids; const char *test_filter; bool has_iteration_filter; @@ -135,6 +137,11 @@ char *xdg_dir; }; +struct cleanup_pid { + struct spa_list link; + pid_t pid; +}; + struct pwtest_context *pwtest_get_context(struct pwtest_test *t) { return ctx; @@ -175,6 +182,56 @@ } } +static int add_cleanup_pid(struct pwtest_context *ctx, pid_t pid) +{ + struct cleanup_pid *cpid; + + if (pid == 0) + return -EINVAL; + + cpid = calloc(1, sizeof(struct cleanup_pid)); + if (cpid == NULL) + return -errno; + + cpid->pid = pid; + spa_list_append(&ctx->cleanup_pids, &cpid->link); + + return 0; +} + +static void remove_cleanup_pid(struct pwtest_context *ctx, pid_t pid) +{ + struct cleanup_pid *cpid, *t; + + spa_list_for_each_safe(cpid, t, &ctx->cleanup_pids, link) { + if (cpid->pid == pid) { + spa_list_remove(&cpid->link); + free(cpid); + } + } +} + +static void terminate_cleanup_pids(struct pwtest_context *ctx) +{ + struct cleanup_pid *cpid; + spa_list_for_each(cpid, &ctx->cleanup_pids, link) { + /* Don't free here, to be signal-safe */ + if (cpid->pid != 0) { + kill(cpid->pid, SIGTERM); + cpid->pid = 0; + } + } +} + +static void free_cleanup_pids(struct pwtest_context *ctx) +{ + struct cleanup_pid *cpid; + spa_list_consume(cpid, &ctx->cleanup_pids, link) { + spa_list_remove(&cpid->link); + free(cpid); + } +} + static void pwtest_backtrace(pid_t p) { #ifdef HAVE_GSTACK @@ -407,6 +464,34 @@ pwtest_error_with_msg("Unable to create temporary file: %s", strerror(errno)); } +int +pwtest_spawn(const char *file, char *const argv[]) +{ + int r; + int status = -1; + pid_t pid; + const int fail_code = 121; + + pid = fork(); + if (pid == 0) { + /* child process */ + execvp(file, (char **)argv); + exit(fail_code); + } else if (pid < 0) + pwtest_error_with_msg("Unable to fork: %s", strerror(errno)); + + add_cleanup_pid(ctx, pid); + r = waitpid(pid, &status, 0); + remove_cleanup_pid(ctx, pid); + if (r <= 0) + pwtest_error_with_msg("waitpid failed: %s", strerror(errno)); + + if (WEXITSTATUS(status) == fail_code) + pwtest_error_with_msg("exec %s failed", file); + + return status; +} + void _pwtest_add(struct pwtest_context *ctx, struct pwtest_suite *suite, const char *funcname, const void *func, ...) { @@ -461,6 +546,8 @@ pw_properties_set(t->args.env, key, value); break; case PWTEST_ARG_DAEMON: + if (RUNNING_ON_VALGRIND) + t->result = PWTEST_SKIP; t->args.pw_daemon = true; break; } @@ -568,6 +655,9 @@ { struct pwtest_suite *c, *tmp; + terminate_cleanup_pids(ctx); + free_cleanup_pids(ctx); + spa_list_for_each_safe(c, tmp, &ctx->suites, link) { free_suite(c); } @@ -585,13 +675,14 @@ sigaction(signal, &act, NULL); pwtest_backtrace(0); + terminate_cleanup_pids(ctx); raise(signal); } static inline void log_append(struct pw_array *buffer, int fd) { int r = 0; - const int sz = 1024; + const int sz = 65536; while (true) { r = pw_array_ensure_size(buffer, sz); @@ -646,6 +737,7 @@ pid_t pid; char pw_remote[64]; int status; + int r; spa_scnprintf(pw_remote, sizeof(pw_remote), "pwtest-pw-%u\n", count++); replace_env(t, "PIPEWIRE_REMOTE", pw_remote); @@ -653,15 +745,26 @@ pid = fork(); if (pid == 0) { /* child */ + setpgid(0, 0); + setenv("PIPEWIRE_CORE", pw_remote, 1); + setenv("PIPEWIRE_DEBUG", "4", 0); + setenv("WIREPLUMBER_DEBUG", "4", 0); + + r = dup2(stderr_fd, STDERR_FILENO); + spa_assert_se(r != -1); + r = dup2(stderr_fd, STDOUT_FILENO); + spa_assert_se(r != -1); - dup2(stderr_fd, STDERR_FILENO); - setlinebuf(stderr); execl(daemon, daemon, (char*)NULL); return -errno; + } else if (pid < 0) { + return pid; } + add_cleanup_pid(ctx, -pid); + /* parent */ sleep(1); /* FIXME how to wait for pw to be ready? */ if (waitpid(pid, &status, WNOHANG) > 0) { @@ -701,6 +804,7 @@ replace_env(t, "TMPDIR", xdg_runtime_dir); replace_env(t, "SPA_PLUGIN_DIR", BUILD_ROOT "/spa/plugins"); + replace_env(t, "SPA_DATA_DIR", SOURCE_ROOT "/spa/plugins"); replace_env(t, "PIPEWIRE_CONFIG_DIR", BUILD_ROOT "/src/daemon"); replace_env(t, "PIPEWIRE_MODULE_DIR", BUILD_ROOT "/src/modules"); replace_env(t, "ACP_PATHS_DIR", SOURCE_ROOT "/spa/plugins/alsa/mixer/paths"); @@ -711,7 +815,8 @@ static void close_pipes(int fds[_FD_LAST]) { for (int i = 0; i < _FD_LAST; i++) { - close(fds[i]); + if (fds[i] >= 0) + close(fds[i]);
View file
pipewire-0.3.48.tar.gz/test/pwtest.h -> pipewire-0.3.49.tar.gz/test/pwtest.h
Changed
@@ -558,6 +558,11 @@ */ void pwtest_mkstemp(char path[PATH_MAX]); +/** + * Run a command and wait for it to return. + */ +int pwtest_spawn(const char *file, char *const argv[]); + /** * \}
View file
pipewire-0.3.49.tar.gz/test/test-functional.c
Added
@@ -0,0 +1,62 @@ +/* PipeWire + * + * Copyright © 2019 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 "config.h" + +#include "pwtest.h" + +PWTEST(openal_info_test) +{ + int status; + +#ifdef OPENAL_INFO_PATH + status = pwtest_spawn(OPENAL_INFO_PATH, (char *[]){ "openal-info", NULL }); + pwtest_int_eq(WEXITSTATUS(status), 0); + return PWTEST_PASS; +#else + return PWTEST_SKIP; +#endif +} + +PWTEST(pactl_test) +{ + int status; + +#ifdef PACTL_PATH + status = pwtest_spawn(PACTL_PATH, (char *[]){ "pactl", "info", NULL }); + pwtest_int_eq(WEXITSTATUS(status), 0); + return PWTEST_PASS; +#else + return PWTEST_SKIP; +#endif +} + +PWTEST_SUITE(pw_array) +{ + pwtest_add(pactl_test, PWTEST_ARG_DAEMON); + pwtest_add(openal_info_test, PWTEST_ARG_DAEMON); + + return PWTEST_PASS; +}
View file
pipewire-0.3.48.tar.gz/test/test-lib.c -> pipewire-0.3.49.tar.gz/test/test-lib.c
Changed
@@ -49,9 +49,21 @@ return PWTEST_PASS; } +PWTEST(init_deinit) +{ + pw_init(0, NULL); + pw_deinit(); + pw_init(0, NULL); + pw_init(0, NULL); + pw_deinit(); + pw_deinit(); + return PWTEST_PASS; +} + PWTEST_SUITE(properties) { pwtest_add(library_version, PWTEST_NOARG); + pwtest_add(init_deinit, PWTEST_NOARG); return PWTEST_PASS; }
View file
pipewire-0.3.48.tar.gz/test/test-loop.c -> pipewire-0.3.49.tar.gz/test/test-loop.c
Changed
@@ -44,6 +44,22 @@ int count; }; +static inline void write_eventfd(int evfd) +{ + uint64_t value = 1; + ssize_t r = write(evfd, &value, sizeof(value)); + pwtest_errno_ok(r); + pwtest_int_eq(r, (ssize_t) sizeof(value)); +} + +static inline void read_eventfd(int evfd) +{ + uint64_t value = 0; + ssize_t r = read(evfd, &value, sizeof(value)); + pwtest_errno_ok(r); + pwtest_int_eq(r, (ssize_t) sizeof(value)); +} + static void on_event(struct spa_source *source) { struct data *d = source->data; @@ -86,8 +102,8 @@ 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)); + write_eventfd(data.a->source.fd); + write_eventfd(data.b->source.fd); pw_main_loop_run(data.ml); pw_main_loop_destroy(data.ml); @@ -102,12 +118,11 @@ { 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)); + read_eventfd(source->fd); if (first) { first = false; @@ -146,8 +161,8 @@ 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)); + write_eventfd(data.a->source.fd); + write_eventfd(data.b->source.fd); pw_main_loop_run(data.ml); pw_main_loop_destroy(data.ml); @@ -165,12 +180,11 @@ { 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)); + read_eventfd(source->fd); if (first) { first = false; @@ -216,8 +230,8 @@ 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)); + write_eventfd(data.a->source.fd); + write_eventfd(data.b->source.fd); pw_main_loop_run(data.ml); pw_main_loop_destroy(data.ml); @@ -227,33 +241,133 @@ return PWTEST_PASS; } -PWTEST(thread_loop_destroy_between_poll_and_lock) +static void +on_event_fail_if_called(void *data, int fd, uint32_t mask) +{ + pwtest_fail_if_reached(); +} + +struct dmsbd_data { + struct pw_loop *l; + struct pw_main_loop *ml; + struct spa_source *source; + struct spa_hook hook; +}; + +static void dmsbd_after(void *data) +{ + struct dmsbd_data *d = data; + + pw_loop_destroy_source(d->l, d->source); + pw_main_loop_quit(d->ml); +} + +static const struct spa_loop_control_hooks dmsbd_hooks = { + SPA_VERSION_LOOP_CONTROL_HOOKS, + .after = dmsbd_after, +}; + +PWTEST(destroy_managed_source_before_dispatch) { pw_init(NULL, NULL); - struct pw_thread_loop *thread_loop = pw_thread_loop_new("uaf", NULL); - pwtest_ptr_notnull(thread_loop); + struct dmsbd_data data = {0}; + + 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.source = pw_loop_add_io(data.l, eventfd(0, 0), SPA_IO_IN, true, on_event_fail_if_called, NULL); + pwtest_ptr_notnull(data.source); - struct pw_loop *loop = pw_thread_loop_get_loop(thread_loop); - pwtest_ptr_notnull(loop); + pw_loop_add_hook(data.l, &data.hook, &dmsbd_hooks, &data); - int evfd = eventfd(0, 0); - pwtest_errno_ok(evfd); + write_eventfd(data.source->fd); - struct spa_source *source = pw_loop_add_io(loop, evfd, SPA_IO_IN, true, NULL, NULL); - pwtest_ptr_notnull(source); + pw_main_loop_run(data.ml); + pw_main_loop_destroy(data.ml); - pw_thread_loop_start(thread_loop); + pw_deinit(); - pw_thread_loop_lock(thread_loop); - { - write(evfd, &(uint64_t){1}, sizeof(uint64_t)); - sleep(1); - pw_loop_destroy_source(loop, source); + return PWTEST_PASS; +} + +struct dmsbd_recurse_data { + struct pw_loop *l; + struct pw_main_loop *ml; + struct spa_source *a, *b; + struct spa_hook hook; + bool first; +}; + +static void dmsbd_recurse_on_event(void *data, int fd, uint32_t mask) +{ + struct dmsbd_recurse_data *d = data; + + read_eventfd(fd); + + pw_loop_enter(d->l); + pw_loop_iterate(d->l, 0); + pw_loop_leave(d->l); + + pw_main_loop_quit(d->ml); +} + +static void dmswp_recurse_before(void *data) +{ + struct dmsbd_recurse_data *d = data; + + if (d->first) { + write_eventfd(d->a->fd); + write_eventfd(d->b->fd); } - pw_thread_loop_unlock(thread_loop); +} + +static void dmsbd_recurse_after(void *data) +{ + struct dmsbd_recurse_data *d = data; + + if (d->first) { + pw_loop_destroy_source(d->l, d->b); + + d->first = false; + } +} + +static const struct spa_loop_control_hooks dmsbd_recurse_hooks = {
View file
pipewire-0.3.48.tar.gz/test/test-spa-json.c -> pipewire-0.3.49.tar.gz/test/test-spa-json.c
Changed
@@ -22,6 +22,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include <locale.h> + #include "pwtest.h" #include <spa/utils/defs.h> @@ -223,6 +225,63 @@ return PWTEST_PASS; } +PWTEST(json_float) +{ + struct { + const char *str; + double val; + } val[] = { + { "0.0", 0.0f }, + { ".0", 0.0f }, + { ".0E0", 0.0E0f }, + { "1.0", 1.0f }, + { "1.011", 1.011f }, + { "176543.123456", 176543.123456f }, + { "-176543.123456", -176543.123456f }, + { "-5678.5432E10", -5678.5432E10f }, + { "-5678.5432e10", -5678.5432e10f }, + { "-5678.5432e-10", -5678.5432e-10f }, + { "5678.5432e+10", 5678.5432e+10f }, + { "00.000100", 00.000100f }, + { "-0.000100", -0.000100f }, + }; + float v; + unsigned i; + char buf1[128], buf2[128], *b1 = buf1, *b2 = buf2; + + pwtest_int_eq(spa_json_parse_float("", 0, &v), 0); + + setlocale(LC_NUMERIC, "C"); + for (i = 0; i < SPA_N_ELEMENTS(val); i++) { + pwtest_int_gt(spa_json_parse_float(val[i].str, strlen(val[i].str), &v), 0); + pwtest_double_eq(v, val[i].val); + } + setlocale(LC_NUMERIC, "fr_FR"); + for (i = 0; i < SPA_N_ELEMENTS(val); i++) { + pwtest_int_gt(spa_json_parse_float(val[i].str, strlen(val[i].str), &v), 0); + pwtest_double_eq(v, val[i].val); + } + pwtest_ptr_eq(spa_json_format_float(buf1, sizeof(buf1), 0.0f), b1); + pwtest_str_eq(buf1, "0.000000"); + pwtest_ptr_eq(spa_json_format_float(buf1, sizeof(buf1), NAN), b1); + pwtest_str_eq(buf1, "0.000000"); + pwtest_ptr_eq(spa_json_format_float(buf1, sizeof(buf1), INFINITY), b1); + pwtest_ptr_eq(spa_json_format_float(buf2, sizeof(buf2), FLT_MAX), b2); + pwtest_str_eq(buf1, buf2); + pwtest_ptr_eq(spa_json_format_float(buf1, sizeof(buf1), -INFINITY), b1); + pwtest_ptr_eq(spa_json_format_float(buf2, sizeof(buf2), FLT_MIN), b2); + pwtest_str_eq(buf1, buf2); + + return PWTEST_PASS; +} + +PWTEST(json_int) +{ + int v; + pwtest_int_eq(spa_json_parse_int("", 0, &v), 0); + return PWTEST_PASS; +} + PWTEST_SUITE(spa_json) { pwtest_add(json_abi, PWTEST_NOARG); @@ -230,6 +289,8 @@ pwtest_add(json_encode, PWTEST_NOARG); pwtest_add(json_array, PWTEST_NOARG); pwtest_add(json_overflow, PWTEST_NOARG); + pwtest_add(json_float, PWTEST_NOARG); + pwtest_add(json_int, PWTEST_NOARG); return PWTEST_PASS; }
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
.