Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 23
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Mon Mar 13 12:30:13 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.66 + +------------------------------------------------------------------- Thu Jan 26 20:45:06 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.65
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.65 +Version: 0.3.66 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
pipewire-0.3.65.tar.gz/spa/plugins/libcamera/libcamera-client.c
Deleted
@@ -1,247 +0,0 @@ -/* Spa libcamera client - * - * Copyright (C) 2020, Collabora Ltd. - * Author: Raghavendra Rao Sidlagatta <raghavendra.rao@collabora.com> - * - * libcamera-client.c - * - * 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 <errno.h> -#include <stddef.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include <spa/support/log.h> -#include <spa/support/loop.h> -#include <spa/support/plugin.h> -#include <spa/utils/type.h> -#include <spa/utils/keys.h> -#include <spa/utils/names.h> -#include <spa/utils/string.h> -#include <spa/monitor/device.h> -#include <spa/monitor/utils.h> - -#include "libcamera.h" - -struct impl { - struct spa_handle handle; - struct spa_device device; - - struct spa_log *log; - struct spa_loop *main_loop; - - struct spa_hook_list hooks; - - uint64_t info_all; - struct spa_device_info info; - - struct spa_source source; -}; - -static int emit_object_info(struct impl *this, uint32_t id) -{ - struct spa_device_object_info info; - struct spa_dict_item items20; - uint32_t n_items = 0; - - info = SPA_DEVICE_OBJECT_INFO_INIT(); - - info.type = SPA_TYPE_INTERFACE_Device; - info.factory_name = SPA_NAME_API_LIBCAMERA_DEVICE; - info.change_mask = (SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS | - SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS); - info.flags = 0; - - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_ENUM_API,"libcamera-client"); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "libcamera"); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Video/Device"); - - info.props = &SPA_DICT_INIT(items, n_items); - spa_device_emit_object_info(&this->hooks, id, &info); - - return 1; -} - -static const struct spa_dict_item device_info_items = { - { SPA_KEY_DEVICE_API, "libcamera" }, - { SPA_KEY_DEVICE_NICK, "libcamera-client" }, - { SPA_KEY_API_UDEV_MATCH, "libcamera" }, -}; - - -static void emit_device_info(struct impl *this, bool full) -{ - uint64_t old = full ? this->info.change_mask : 0; - if (full) - this->info.change_mask = this->info_all; - if (this->info.change_mask) { - this->info.props = &SPA_DICT_INIT_ARRAY(device_info_items); - spa_device_emit_info(&this->hooks, &this->info); - this->info.change_mask = old; - } -} - -static void impl_hook_removed(struct spa_hook *hook) -{ - return; -} - -static int -impl_device_add_listener(void *object, struct spa_hook *listener, - const struct spa_device_events *events, void *data) -{ - struct impl *this = object; - struct spa_hook_list save; - - spa_return_val_if_fail(this != NULL, -EINVAL); - spa_return_val_if_fail(events != NULL, -EINVAL); - - spa_hook_list_isolate(&this->hooks, &save, listener, events, data); - - emit_device_info(this, true); - - emit_object_info(this, 0); - - spa_hook_list_join(&this->hooks, &save); - - listener->removed = impl_hook_removed; - listener->priv = this; - - return 0; -} - -static const struct spa_device_methods impl_device = { - SPA_VERSION_DEVICE_METHODS, - .add_listener = impl_device_add_listener, -}; - -static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) -{ - struct impl *this; - - spa_return_val_if_fail(handle != NULL, -EINVAL); - spa_return_val_if_fail(interface != NULL, -EINVAL); - - this = (struct impl *) handle; - - if (spa_streq(type, SPA_TYPE_INTERFACE_Device)) - *interface = &this->device; - else - return -ENOENT; - - return 0; -} - -static int impl_clear(struct spa_handle *handle) -{ - struct impl *this = (struct impl *) handle; - - if(this->dev.camera) { - deleteLibCamera(this->dev.camera); - this->dev.camera = NULL; - } - return 0; -} - -static size_t -impl_get_size(const struct spa_handle_factory *factory, - const struct spa_dict *params) -{ - return sizeof(struct impl); -} - -static int -impl_init(const struct spa_handle_factory *factory, - struct spa_handle *handle, - const struct spa_dict *info, - const struct spa_support *support, - uint32_t n_support) -{ - struct impl *this; - - spa_return_val_if_fail(factory != NULL, -EINVAL); - spa_return_val_if_fail(handle != NULL, -EINVAL); - - handle->get_interface = impl_get_interface; - handle->clear = impl_clear; - - this = (struct impl *) handle; - - this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); - libcamera_log_topic_init(this->log); - - this->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); - - if (this->main_loop == NULL) { - spa_log_error(this->log, "a main-loop is needed"); - return -EINVAL; - } - spa_hook_list_init(&this->hooks); - - this->device.iface = SPA_INTERFACE_INIT( - SPA_TYPE_INTERFACE_Device, - SPA_VERSION_DEVICE, - &impl_device, this); - - this->info = SPA_DEVICE_INFO_INIT(); - this->info_all = SPA_DEVICE_CHANGE_MASK_FLAGS | - SPA_DEVICE_CHANGE_MASK_PROPS; - this->info.flags = 0; - - if(this->dev.camera == NULL) - this->dev.camera = (LibCamera*)newLibCamera(); - if(this->dev.camera != NULL) - libcamera_set_log(this->dev.camera, this->dev.log); - - return 0; -} - -static const struct spa_interface_info impl_interfaces = { - {SPA_TYPE_INTERFACE_Device,}, -}; - -static int -impl_enum_interface_info(const struct spa_handle_factory *factory, - const struct spa_interface_info **info, - uint32_t *index) -{ - spa_return_val_if_fail(factory != NULL, -EINVAL); - spa_return_val_if_fail(info != NULL, -EINVAL); - spa_return_val_if_fail(index != NULL, -EINVAL); - - if (*index >= SPA_N_ELEMENTS(impl_interfaces)) - return 0; - - *info = &impl_interfaces(*index)++; - return 1; -} - -const struct spa_handle_factory spa_libcamera_client_factory = { - SPA_VERSION_HANDLE_FACTORY, - SPA_NAME_API_LIBCAMERA_ENUM_CLIENT, - NULL, - impl_get_size, - impl_init, - impl_enum_interface_info, -};
View file
pipewire-0.3.65.tar.gz/.gitignore -> pipewire-0.3.66.tar.gz/.gitignore
Changed
@@ -15,6 +15,11 @@ subprojects/wireplumber subprojects/media-session subprojects/packagecache +subprojects/googletest* +subprojects/gtest.wrap +subprojects/libyaml.wrap +subprojects/libyaml +subprojects/libcamera # Created by https://www.gitignore.io/api/vim
View file
pipewire-0.3.65.tar.gz/.gitlab-ci.yml -> pipewire-0.3.66.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-11-07.0' + FDO_DISTRIBUTION_TAG: '2023-01-18.0' FDO_DISTRIBUTION_VERSION: '35' FDO_DISTRIBUTION_PACKAGES: >- alsa-lib-devel @@ -46,6 +46,7 @@ jack-audio-connection-kit-devel libcanberra-devel libldac-devel + libmysofa-devel libsndfile-devel libusb-devel lilv-devel
View file
pipewire-0.3.65.tar.gz/NEWS -> pipewire-0.3.66.tar.gz/NEWS
Changed
@@ -1,3 +1,81 @@ +# PipeWire 0.3.66 (2023-02-16) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + - Fix a regression in the pulseaudio module-combine-stream because the new + module-combine-stream was not installed. + - PipeWire can now generate a limits.d config file with our recommended + settings for priorities and memlock. + + +## PipeWire + - Avoid rate switches when the graph is idle. + - The rate selection algorithm was improved. This ensures minimal performance + and quality loss when resampling. + - The default min.quantum was set to 32 again after it got erronously changed + to (the too low) 16 in version 0.3.45. + - Fix compilation issues with rust bindings because of macros in defines. + Work around it for now. (#2952) + - Invalid file mappings are now refused (#2617 #2914 #3007) + - Modules, exec and objects can now be loaded depending on conditions. One + example is the X11-bell module that can now be disabled with a custom + property override. + - Filter now also supports _trigger_process() to drive the graph. + - TID is now added to the journald log. + - PipeWire generates and installs */etc/security/limits.d/25-pw-rlimits.conf* + that by default contains project's recommended settings. Creation of the + pipewire group is left to the distro or user ( `groupadd -r pipewire` ). + See the rlimits-* Meson options for controlling this behavior. + - Additionally there is now by default disabled Meson option that will + install */etc/security/limits.d/20-pw-defaults.conf* with the current Linux + default memlock value. Distros with only kernels >=5.16 or always using + systemd v251 or newer do not need this. But all other builds should set the + `-Dpam-defaults-install=true` Meson option to ensure that the memlock value + is always large enough. Thanks to Rickie Schroeder for pointing out that + the default Linux memlock value has been somewhat recently increased. + +## modules + - Install module-combine-stream. + - RTP source now has support for custom channel names. + - RTP source will now stop when inactive. + - There is now + - Filter-chain has a new mysofa based spacializer plugin. + - The RTP modules can now use direct clock timestamps to send and receive + packets. This makes it possible to synchronize sender and receiver with + a PTP clock, for example. + - Filter-chain now has an invert plugin to invert the polarity of a + signal. (#3008) + +## SPA + - There is now an option to set the channels used for probing Pro Audio + devices. This could unlock more samplerates for some devices when they are + probed with fewer channels. (#2990) + - Support was added for other clocks than the MONOTONIC clock in the + driver nodes. This can be used to synchronize the graph to a PTP clock, + for example. + - The ALSA source has some more headroom when rate matching to avoid + stuttering when following another driver. + - libcamera controls are now mapped to standard PipeWire property values. + - The channelmixer has seen some improvements. MONO and undefined channel + layouts are now upmixed and downmixed more correctly. (#3010) + +## Bluetooth + - Many BAP support fixes. + +## GStreamer + - The gstreamer elements now support buffer video metadata so that strides + are correctly handled. + - pipewiresrc will now error out correctly in more cases. (#2935) + +## JACK + - The frame to/from time functions are improved to also work with negative + time and frame offsets. + +Older versions: + + # PipeWire 0.3.65 (2023-01-26) This is a bugfix release that is API and ABI compatible with previous @@ -109,9 +187,6 @@ this. - pipewiresrc will now always be a live source unless told otherwise. -Older versions: - - # PipeWire 0.3.64 (2023-01-12) This is a bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.65.tar.gz/meson.build -> pipewire-0.3.66.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '0.3.65', + version : '0.3.66', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.59.0', default_options : 'warning_level=3', @@ -285,6 +285,9 @@ sndfile_dep = dependency('sndfile', version : '>= 1.0.20', required : get_option('sndfile')) summary({'sndfile': sndfile_dep.found()}, bool_yn: true, section: 'pw-cat/pw-play/pw-dump/filter-chain') cdata.set('HAVE_SNDFILE', sndfile_dep.found()) +libmysofa_dep = dependency('libmysofa', required : get_option('libmysofa')) +summary({'libmysofa': libmysofa_dep.found()}, bool_yn: true, section: 'filter-chain') +cdata.set('HAVE_LIBMYSOFA', libmysofa_dep.found()) pulseaudio_dep = dependency('libpulse', required : get_option('libpulse')) summary({'libpulse': pulseaudio_dep.found()}, bool_yn: true, section: 'Streaming between daemons') avahi_dep = dependency('avahi-client', required : get_option('avahi'))
View file
pipewire-0.3.65.tar.gz/meson_options.txt -> pipewire-0.3.66.tar.gz/meson_options.txt
Changed
@@ -213,6 +213,10 @@ description: 'Enable code that depends on libsndfile', type: 'feature', value: 'auto') +option('libmysofa', + description: 'Enable code that depends on libmysofa', + type: 'feature', + value: 'auto') option('libpulse', description: 'Enable code that depends on libpulse', type: 'feature', @@ -281,3 +285,36 @@ description: 'Enable ALSA Compress-Offload support', type: 'feature', value: 'disabled') +option('pam-defaults-install', + description: 'Install limits.d file modifying defaults for all PAM users. Only for old kernels/systemd!', + type: 'boolean', + value: 'false') +option('pam-memlock-default', + description : 'The default memlock value for any PAM user in kilobytes. Multiples of 64 recommended.', + type : 'integer', + min: 640, + value: 8192) +option('rlimits-install', + description: 'Install PAM limits.d file. Voids all following rlimits-* options, if false', + type: 'boolean', + value: 'true') +option('rlimits-match', + description : 'PAM match rule for the generated limits.d file. @<name> denotes matching a group.', + type : 'string', + value: '@pipewire') +option('rlimits-rtprio', + description : 'RR and FIFO scheduler priority permitted for realtime threads of the matching user(s)', + type : 'integer', + min: 11, + max: 99, + value: 95) +option('rlimits-memlock', + description : 'kB of memory each process of the user matched by the rule can lock. Can be unlimited .', + type : 'string', + value: '4194304') +option('rlimits-nice', + description : 'Not niceness permitted for non-realtime threads of the matching user(s)', + type : 'integer', + min: -20, + max: -1, + value: -19)
View file
pipewire-0.3.65.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.66.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -5784,15 +5784,18 @@ { struct client *c = (struct client *) client; struct spa_io_position *pos; - double df; spa_return_val_if_fail(c != NULL, -EINVAL); - if (SPA_UNLIKELY((pos = c->rt.position) == NULL)) + if (SPA_UNLIKELY((pos = c->rt.position) == NULL) || c->buffer_frames == 0) return 0; - df = (frames - pos->clock.position) * (double)SPA_NSEC_PER_SEC / c->sample_rate; - return (pos->clock.nsec + (int64_t)rint(df)) / SPA_NSEC_PER_USEC; + uint32_t nf = (uint32_t)pos->clock.position; + uint64_t w = pos->clock.nsec/SPA_NSEC_PER_USEC; + uint64_t nw = pos->clock.next_nsec/SPA_NSEC_PER_USEC; + int32_t df = frames - nf; + int64_t dp = nw - w; + return w + (int64_t)rint((double) df * (double) dp / c->buffer_frames); } SPA_EXPORT @@ -5800,15 +5803,18 @@ { struct client *c = (struct client *) client; struct spa_io_position *pos; - double du; spa_return_val_if_fail(c != NULL, -EINVAL); if (SPA_UNLIKELY((pos = c->rt.position) == NULL)) return 0; - du = (usecs - pos->clock.nsec/SPA_NSEC_PER_USEC) * (double)c->sample_rate / SPA_USEC_PER_SEC; - return pos->clock.position + (int32_t)rint(du); + uint32_t nf = (uint32_t)pos->clock.position; + uint64_t w = pos->clock.nsec/SPA_NSEC_PER_USEC; + uint64_t nw = pos->clock.next_nsec/SPA_NSEC_PER_USEC; + int64_t du = usecs - w; + int64_t dp = nw - w; + return nf + (int32_t)rint((double)du / (double)dp * c->buffer_frames); } SPA_EXPORT
View file
pipewire-0.3.65.tar.gz/po/oc.po -> pipewire-0.3.66.tar.gz/po/oc.po
Changed
@@ -1,4 +1,4 @@ -# French translation of pipewire. +# Occitan translation of pipewire. # Copyright (C) 2006-2008 Lennart Poettering # This file is distributed under the same license as the pipewire package. # Robert-André Mauchin <zebob.m@pengzone.org>, 2008. @@ -8,24 +8,25 @@ # Thomas Canniot <mrtom@fedoraproject.org>, 2009, 2012. # Cédric Valmary (Tot en Òc) <cvalmary@yahoo.fr>, 2015. # Cédric Valmary (totenoc.eu) <cvalmary@yahoo.fr>, 2016. +# Quentin PAGÈS, 2023. msgid "" msgstr "" "Project-Id-Version: pipewire trunk\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/" "issues/new\n" -"POT-Creation-Date: 2021-04-18 16:54+0800\n" -"PO-Revision-Date: 2016-10-12 22:20+0200\n" -"Last-Translator: Cédric Valmary (totenoc.eu) <cvalmary@yahoo.fr>\n" +"POT-Creation-Date: 2022-06-30 12:50+0200\n" +"PO-Revision-Date: 2023-02-11 00:11+0100\n" +"Last-Translator: Quentin PAGÈS\n" "Language-Team: Tot En Òc\n" "Language: oc\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Virtaal 0.7.1\n" +"X-Generator: Poedit 3.2.2\n" "X-Launchpad-Export-Date: 2016-10-12 20:12+0000\n" -#: src/daemon/pipewire.c:43 +#: src/daemon/pipewire.c:46 #, c-format msgid "" "%s options\n" @@ -33,40 +34,56 @@ " --version Show version\n" " -c, --config Load config (Default %s)\n" msgstr "" +"%s opcions\n" +" -h, --help Afichar aquesta ajuda\n" +" --version Afichar la version\n" +" -c, --config Cargar la conf. (Defaut %s)\n" -#: src/daemon/pipewire.desktop.in:4 -msgid "PipeWire Media System" -msgstr "" - -#: src/daemon/pipewire.desktop.in:5 -msgid "Start the PipeWire Media System" -msgstr "" +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:180 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:180 +#, c-format +msgid "Tunnel to %s/%s" +msgstr "Tunèl cap a %s/%s" -#: src/examples/media-session/alsa-monitor.c:526 -#: spa/plugins/alsa/acp/compat.c:187 -msgid "Built-in Audio" -msgstr "Àudio integrat" +#: src/modules/module-fallback-sink.c:51 +msgid "Dummy Output" +msgstr "Sortida factícia" -#: src/examples/media-session/alsa-monitor.c:530 -#: spa/plugins/alsa/acp/compat.c:192 -msgid "Modem" -msgstr "Modèm" +#: src/modules/module-pulse-tunnel.c:662 +#, c-format +msgid "Tunnel for %s@%s" +msgstr "Tunèl per %s@%s" -#: src/examples/media-session/alsa-monitor.c:539 +#: src/modules/module-zeroconf-discover.c:332 msgid "Unknown device" -msgstr "" +msgstr "Periferic desconegut" + +#: src/modules/module-zeroconf-discover.c:344 +#, c-format +msgid "%s on %s@%s" +msgstr "%s sus %s@%s" -#: src/tools/pw-cat.c:991 +#: src/modules/module-zeroconf-discover.c:348 +#, c-format +msgid "%s on %s" +msgstr "%s sus %s" + +#: src/tools/pw-cat.c:784 #, c-format msgid "" -"%s options <file>\n" +"%s options <file>|-\n" " -h, --help Show this help\n" " --version Show version\n" " -v, --verbose Enable verbose operations\n" "\n" msgstr "" +"%s opcions <file>|-\n" +" -h, --help Afichar aquesta ajuda\n" +" --version Afichar la version\n" +" -v, --verbose Activar las operacions verbosas\n" +"\n" -#: src/tools/pw-cat.c:998 +#: src/tools/pw-cat.c:791 #, c-format msgid "" " -R, --remote Remote daemon name\n" @@ -80,11 +97,11 @@ " or direct samples (256)\n" " the rate is the one of the source " "file\n" -" --list-targets List available targets for --target\n" +" -P --properties Set node properties\n" "\n" msgstr "" -#: src/tools/pw-cat.c:1016 +#: src/tools/pw-cat.c:809 #, c-format msgid "" " --rate Sample rate (req. for rec) (default " @@ -104,15 +121,21 @@ "\n" msgstr "" -#: src/tools/pw-cat.c:1033 +#: src/tools/pw-cat.c:826 msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n" " -m, --midi Midi mode\n" +" -d, --dsd DSD mode\n" "\n" msgstr "" +" -p, --playback Mòde lectura\n" +" -r, --record Mòde enregistrament\n" +" -m, --midi Mòde Midi\n" +" -d, --dsd Mòde DSD\n" +"\n" -#: src/tools/pw-cli.c:2932 +#: src/tools/pw-cli.c:2250 #, c-format msgid "" "%s options command\n" @@ -122,360 +145,353 @@ " -r, --remote Remote daemon name\n" "\n" msgstr "" +"%s opcions comanda\n" +" -h, --help Afichar aquesta ajuda\n" +" --version Afichar la version\n" +" -d, --daemon Aviar coma demòni (Per defaut " +"false)\n" +" -r, --remote Remote daemon name\n" +"\n" -#: spa/plugins/alsa/acp/acp.c:290 +#: spa/plugins/alsa/acp/acp.c:321 msgid "Pro Audio" msgstr "" -#: spa/plugins/alsa/acp/acp.c:411 spa/plugins/alsa/acp/alsa-mixer.c:4704 -#: spa/plugins/bluez5/bluez5-device.c:1000 +#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648 +#: spa/plugins/bluez5/bluez5-device.c:1236 msgid "Off" msgstr "Atudat" -#: spa/plugins/alsa/acp/channelmap.h:466 -msgid "(invalid)" -msgstr "(invalid)" - -#: spa/plugins/alsa/acp/alsa-mixer.c:2709 +#: spa/plugins/alsa/acp/alsa-mixer.c:2652 msgid "Input" msgstr "Entrada" -#: spa/plugins/alsa/acp/alsa-mixer.c:2710 +#: spa/plugins/alsa/acp/alsa-mixer.c:2653 msgid "Docking Station Input" msgstr "Entrada de l'estacion d'acuèlh" -#: spa/plugins/alsa/acp/alsa-mixer.c:2711 +#: spa/plugins/alsa/acp/alsa-mixer.c:2654 msgid "Docking Station Microphone" msgstr "Microfòn de l'estacion d'acuèlh" -#: spa/plugins/alsa/acp/alsa-mixer.c:2712 +#: spa/plugins/alsa/acp/alsa-mixer.c:2655 msgid "Docking Station Line In" msgstr "Entrada linha de l'estacion d'acuèlh" -#: spa/plugins/alsa/acp/alsa-mixer.c:2713 -#: spa/plugins/alsa/acp/alsa-mixer.c:2804 +#: spa/plugins/alsa/acp/alsa-mixer.c:2656 +#: spa/plugins/alsa/acp/alsa-mixer.c:2747 msgid "Line In" msgstr "Entrada linha" -#: spa/plugins/alsa/acp/alsa-mixer.c:2714 -#: spa/plugins/alsa/acp/alsa-mixer.c:2798 -#: spa/plugins/bluez5/bluez5-device.c:1145 +#: spa/plugins/alsa/acp/alsa-mixer.c:2657 +#: spa/plugins/alsa/acp/alsa-mixer.c:2741 +#: spa/plugins/bluez5/bluez5-device.c:1454 msgid "Microphone" -msgstr "Micrò" +msgstr "Microfòn" -#: spa/plugins/alsa/acp/alsa-mixer.c:2715 -#: spa/plugins/alsa/acp/alsa-mixer.c:2799 +#: spa/plugins/alsa/acp/alsa-mixer.c:2658 +#: spa/plugins/alsa/acp/alsa-mixer.c:2742 msgid "Front Microphone" msgstr "Microfòn avant" -#: spa/plugins/alsa/acp/alsa-mixer.c:2716 -#: spa/plugins/alsa/acp/alsa-mixer.c:2800 +#: spa/plugins/alsa/acp/alsa-mixer.c:2659 +#: spa/plugins/alsa/acp/alsa-mixer.c:2743 msgid "Rear Microphone" msgstr "Microfòn arrièr" -#: spa/plugins/alsa/acp/alsa-mixer.c:2717 +#: spa/plugins/alsa/acp/alsa-mixer.c:2660 msgid "External Microphone" msgstr "Microfòn extèrne" -#: spa/plugins/alsa/acp/alsa-mixer.c:2718 -#: spa/plugins/alsa/acp/alsa-mixer.c:2802 +#: spa/plugins/alsa/acp/alsa-mixer.c:2661 +#: spa/plugins/alsa/acp/alsa-mixer.c:2745 msgid "Internal Microphone" msgstr "Microfòn intèrne" -#: spa/plugins/alsa/acp/alsa-mixer.c:2719 -#: spa/plugins/alsa/acp/alsa-mixer.c:2805 +#: spa/plugins/alsa/acp/alsa-mixer.c:2662 +#: spa/plugins/alsa/acp/alsa-mixer.c:2748 msgid "Radio" msgstr "Ràdio" -#: spa/plugins/alsa/acp/alsa-mixer.c:2720 -#: spa/plugins/alsa/acp/alsa-mixer.c:2806 +#: spa/plugins/alsa/acp/alsa-mixer.c:2663 +#: spa/plugins/alsa/acp/alsa-mixer.c:2749 msgid "Video" msgstr "Vidèo" -#: spa/plugins/alsa/acp/alsa-mixer.c:2721 +#: spa/plugins/alsa/acp/alsa-mixer.c:2664 msgid "Automatic Gain Control" msgstr "Contraròtle automatic del ganh" -#: spa/plugins/alsa/acp/alsa-mixer.c:2722 +#: spa/plugins/alsa/acp/alsa-mixer.c:2665 msgid "No Automatic Gain Control" msgstr "Pas de contraròtle automatic del ganh" -#: spa/plugins/alsa/acp/alsa-mixer.c:2723 +#: spa/plugins/alsa/acp/alsa-mixer.c:2666 msgid "Boost" msgstr "Boost" -#: spa/plugins/alsa/acp/alsa-mixer.c:2724 +#: spa/plugins/alsa/acp/alsa-mixer.c:2667 msgid "No Boost" msgstr "Sens boost" -#: spa/plugins/alsa/acp/alsa-mixer.c:2725 +#: spa/plugins/alsa/acp/alsa-mixer.c:2668 msgid "Amplifier" msgstr "Amplificador" -#: spa/plugins/alsa/acp/alsa-mixer.c:2726 +#: spa/plugins/alsa/acp/alsa-mixer.c:2669 msgid "No Amplifier" msgstr "Pas d'amplificador" -#: spa/plugins/alsa/acp/alsa-mixer.c:2727 +#: spa/plugins/alsa/acp/alsa-mixer.c:2670 msgid "Bass Boost" msgstr "Amplificacion bassas" -#: spa/plugins/alsa/acp/alsa-mixer.c:2728 +#: spa/plugins/alsa/acp/alsa-mixer.c:2671 msgid "No Bass Boost" msgstr "Pas d'amplificacion de las bassas" -#: spa/plugins/alsa/acp/alsa-mixer.c:2729 -#: spa/plugins/bluez5/bluez5-device.c:1150 +#: spa/plugins/alsa/acp/alsa-mixer.c:2672 +#: spa/plugins/bluez5/bluez5-device.c:1460 msgid "Speaker" msgstr "Nautparlaire" -#: spa/plugins/alsa/acp/alsa-mixer.c:2730 -#: spa/plugins/alsa/acp/alsa-mixer.c:2808 +#: spa/plugins/alsa/acp/alsa-mixer.c:2673 +#: spa/plugins/alsa/acp/alsa-mixer.c:2751 msgid "Headphones" msgstr "Escotadors" -#: spa/plugins/alsa/acp/alsa-mixer.c:2797 +#: spa/plugins/alsa/acp/alsa-mixer.c:2740 msgid "Analog Input" msgstr "Entrada analogica" -#: spa/plugins/alsa/acp/alsa-mixer.c:2801 +#: spa/plugins/alsa/acp/alsa-mixer.c:2744 msgid "Dock Microphone" msgstr "Microfòn de l'estacion d'acuèlh" -#: spa/plugins/alsa/acp/alsa-mixer.c:2803 +#: spa/plugins/alsa/acp/alsa-mixer.c:2746 msgid "Headset Microphone" msgstr "Micro-casc" -#: spa/plugins/alsa/acp/alsa-mixer.c:2807 +#: spa/plugins/alsa/acp/alsa-mixer.c:2750 msgid "Analog Output" msgstr "Sortida analogica" -#: spa/plugins/alsa/acp/alsa-mixer.c:2809 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:2752 msgid "Headphones 2" -msgstr "Escotadors" +msgstr "Casc àudio 2" -#: spa/plugins/alsa/acp/alsa-mixer.c:2810 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:2753 msgid "Headphones Mono Output" -msgstr "Sortida Analogica Monò" +msgstr "Sortida casc àudio analogica mono" -#: spa/plugins/alsa/acp/alsa-mixer.c:2811 +#: spa/plugins/alsa/acp/alsa-mixer.c:2754 msgid "Line Out" msgstr "Sortida linha" -#: spa/plugins/alsa/acp/alsa-mixer.c:2812 +#: spa/plugins/alsa/acp/alsa-mixer.c:2755 msgid "Analog Mono Output" -msgstr "Sortida Analogica Monò" +msgstr "Sortida analogica mono" -#: spa/plugins/alsa/acp/alsa-mixer.c:2813 +#: spa/plugins/alsa/acp/alsa-mixer.c:2756 msgid "Speakers" msgstr "Nauts parlaires" -#: spa/plugins/alsa/acp/alsa-mixer.c:2814 +#: spa/plugins/alsa/acp/alsa-mixer.c:2757 msgid "HDMI / DisplayPort" msgstr "HDMI / DisplayPort" -#: spa/plugins/alsa/acp/alsa-mixer.c:2815 +#: spa/plugins/alsa/acp/alsa-mixer.c:2758 msgid "Digital Output (S/PDIF)" msgstr "Sortida numerica (S/PDIF)" -#: spa/plugins/alsa/acp/alsa-mixer.c:2816 +#: spa/plugins/alsa/acp/alsa-mixer.c:2759 msgid "Digital Input (S/PDIF)" msgstr "Entrada numerica (S/PDIF)" -#: spa/plugins/alsa/acp/alsa-mixer.c:2817 +#: spa/plugins/alsa/acp/alsa-mixer.c:2760 msgid "Multichannel Input" -msgstr "" +msgstr "Entrada multicanal" -#: spa/plugins/alsa/acp/alsa-mixer.c:2818 +#: spa/plugins/alsa/acp/alsa-mixer.c:2761 msgid "Multichannel Output" -msgstr "" +msgstr "Sortida multicanal" -#: spa/plugins/alsa/acp/alsa-mixer.c:2819 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:2762 msgid "Game Output" -msgstr "%s Sortida" +msgstr "Sortida jòc" -#: spa/plugins/alsa/acp/alsa-mixer.c:2820 -#: spa/plugins/alsa/acp/alsa-mixer.c:2821 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:2763 +#: spa/plugins/alsa/acp/alsa-mixer.c:2764 msgid "Chat Output" -msgstr "%s Sortida" +msgstr "Sortida messatjariá" -#: spa/plugins/alsa/acp/alsa-mixer.c:2822 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:2765 msgid "Chat Input" -msgstr "%s Entrada" +msgstr "Entrada messatjariá" -#: spa/plugins/alsa/acp/alsa-mixer.c:2823 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:2766 msgid "Virtual Surround 7.1" -msgstr "Collector ambiofonic virtual" +msgstr "Surround 7.1 virtual" -#: spa/plugins/alsa/acp/alsa-mixer.c:4527 +#: spa/plugins/alsa/acp/alsa-mixer.c:4471 msgid "Analog Mono" -msgstr "Monò analogic" +msgstr "Mono analogic" -#: spa/plugins/alsa/acp/alsa-mixer.c:4528 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:4472 msgid "Analog Mono (Left)" -msgstr "Monò analogic" +msgstr "Mono analogic (esquèrra)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4529 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:4473 msgid "Analog Mono (Right)" -msgstr "Monò analogic" +msgstr "Mono analogic (drecha)" #. Note: Not translated to "Analog Stereo Input", because the source #. * name gets "Input" appended to it automatically, so adding "Input" #. * here would lead to the source name to become "Analog Stereo Input #. * Input". The same logic applies to analog-stereo-output, #. * multichannel-input and multichannel-output. -#: spa/plugins/alsa/acp/alsa-mixer.c:4530 -#: spa/plugins/alsa/acp/alsa-mixer.c:4538 -#: spa/plugins/alsa/acp/alsa-mixer.c:4539 +#: spa/plugins/alsa/acp/alsa-mixer.c:4474 +#: spa/plugins/alsa/acp/alsa-mixer.c:4482 +#: spa/plugins/alsa/acp/alsa-mixer.c:4483 msgid "Analog Stereo" -msgstr "Esterèo analogic" +msgstr "Estereo analogic" -#: spa/plugins/alsa/acp/alsa-mixer.c:4531 +#: spa/plugins/alsa/acp/alsa-mixer.c:4475 msgid "Mono" msgstr "Mono" -#: spa/plugins/alsa/acp/alsa-mixer.c:4532 +#: spa/plugins/alsa/acp/alsa-mixer.c:4476 msgid "Stereo" -msgstr "Esterèo" +msgstr "Estereo" -#: spa/plugins/alsa/acp/alsa-mixer.c:4540 -#: spa/plugins/alsa/acp/alsa-mixer.c:4698 -#: spa/plugins/bluez5/bluez5-device.c:1135 +#: spa/plugins/alsa/acp/alsa-mixer.c:4484 +#: spa/plugins/alsa/acp/alsa-mixer.c:4642 +#: spa/plugins/bluez5/bluez5-device.c:1442 msgid "Headset" msgstr "Casc àudio" -#: spa/plugins/alsa/acp/alsa-mixer.c:4541 -#: spa/plugins/alsa/acp/alsa-mixer.c:4699 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:4485 +#: spa/plugins/alsa/acp/alsa-mixer.c:4643 msgid "Speakerphone" msgstr "Nautparlaire" -#: spa/plugins/alsa/acp/alsa-mixer.c:4542 -#: spa/plugins/alsa/acp/alsa-mixer.c:4543 +#: spa/plugins/alsa/acp/alsa-mixer.c:4486 +#: spa/plugins/alsa/acp/alsa-mixer.c:4487 msgid "Multichannel" -msgstr "" +msgstr "Multicanal" -#: spa/plugins/alsa/acp/alsa-mixer.c:4544 +#: spa/plugins/alsa/acp/alsa-mixer.c:4488 msgid "Analog Surround 2.1" msgstr "Surround analogic 2.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4545 +#: spa/plugins/alsa/acp/alsa-mixer.c:4489 msgid "Analog Surround 3.0" msgstr "Surround analogic 3.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4546 +#: spa/plugins/alsa/acp/alsa-mixer.c:4490 msgid "Analog Surround 3.1" msgstr "Surround analogic 3.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4547 +#: spa/plugins/alsa/acp/alsa-mixer.c:4491 msgid "Analog Surround 4.0" msgstr "Surround analogic 4.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4548 +#: spa/plugins/alsa/acp/alsa-mixer.c:4492 msgid "Analog Surround 4.1" msgstr "Surround analogic 4.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4549 +#: spa/plugins/alsa/acp/alsa-mixer.c:4493 msgid "Analog Surround 5.0" msgstr "Surround analogic 5.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4550 +#: spa/plugins/alsa/acp/alsa-mixer.c:4494 msgid "Analog Surround 5.1" msgstr "Surround analogic 5.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4551 +#: spa/plugins/alsa/acp/alsa-mixer.c:4495 msgid "Analog Surround 6.0" msgstr "Surround analogic 6.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4552 +#: spa/plugins/alsa/acp/alsa-mixer.c:4496 msgid "Analog Surround 6.1" msgstr "Surround analogic 6.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4553 +#: spa/plugins/alsa/acp/alsa-mixer.c:4497 msgid "Analog Surround 7.0" msgstr "Surround analogic 7.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4554 +#: spa/plugins/alsa/acp/alsa-mixer.c:4498 msgid "Analog Surround 7.1" msgstr "Surround analogic 7.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4555 +#: spa/plugins/alsa/acp/alsa-mixer.c:4499 msgid "Digital Stereo (IEC958)" -msgstr "Esterèo numeric (IEC958)" +msgstr "Estereo numeric (IEC958)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4556 +#: spa/plugins/alsa/acp/alsa-mixer.c:4500 msgid "Digital Surround 4.0 (IEC958/AC3)" msgstr "Surround numeric 4.0 (IEC958/AC3)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4557 +#: spa/plugins/alsa/acp/alsa-mixer.c:4501 msgid "Digital Surround 5.1 (IEC958/AC3)" msgstr "Surround numeric 5.1 (IEC958/AC3)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4558 +#: spa/plugins/alsa/acp/alsa-mixer.c:4502 msgid "Digital Surround 5.1 (IEC958/DTS)" msgstr "Digital Surround 5.1 (IEC958/DTS)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4559 +#: spa/plugins/alsa/acp/alsa-mixer.c:4503 msgid "Digital Stereo (HDMI)" -msgstr "Esterèo numeric (HDMI)" +msgstr "Estereo numeric (HDMI)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4560 +#: spa/plugins/alsa/acp/alsa-mixer.c:4504 msgid "Digital Surround 5.1 (HDMI)" msgstr "Digital Surround 5.1 (HDMI)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4561 +#: spa/plugins/alsa/acp/alsa-mixer.c:4505 msgid "Chat" -msgstr "" +msgstr "Messatjariá instantanèa" -#: spa/plugins/alsa/acp/alsa-mixer.c:4562 +#: spa/plugins/alsa/acp/alsa-mixer.c:4506 msgid "Game" -msgstr "" +msgstr "Jòc" -#: spa/plugins/alsa/acp/alsa-mixer.c:4696 +#: spa/plugins/alsa/acp/alsa-mixer.c:4640 msgid "Analog Mono Duplex" msgstr "Duplèx Mono analogic" -#: spa/plugins/alsa/acp/alsa-mixer.c:4697 +#: spa/plugins/alsa/acp/alsa-mixer.c:4641 msgid "Analog Stereo Duplex" msgstr "Duplèx esterèo analogic" -#: spa/plugins/alsa/acp/alsa-mixer.c:4700 +#: spa/plugins/alsa/acp/alsa-mixer.c:4644 msgid "Digital Stereo Duplex (IEC958)" msgstr "Duplèx estèreo numeric (IEC958)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4701 +#: spa/plugins/alsa/acp/alsa-mixer.c:4645 msgid "Multichannel Duplex" -msgstr "" +msgstr "Duplèx multicanal" -#: spa/plugins/alsa/acp/alsa-mixer.c:4702 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:4646 msgid "Stereo Duplex" -msgstr "Duplèx esterèo analogic" +msgstr "Duplèx estereo" -#: spa/plugins/alsa/acp/alsa-mixer.c:4703 +#: spa/plugins/alsa/acp/alsa-mixer.c:4647 msgid "Mono Chat + 7.1 Surround" -msgstr "" +msgstr "Messatjariá mono + Surround 7.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4806 +#: spa/plugins/alsa/acp/alsa-mixer.c:4754 #, c-format msgid "%s Output" msgstr "%s Sortida" -#: spa/plugins/alsa/acp/alsa-mixer.c:4813 +#: spa/plugins/alsa/acp/alsa-mixer.c:4761 #, c-format msgid "%s Input" msgstr "%s Entrada" -#: spa/plugins/alsa/acp/alsa-util.c:1175 spa/plugins/alsa/acp/alsa-util.c:1269 -#, fuzzy, c-format +#: spa/plugins/alsa/acp/alsa-util.c:1187 spa/plugins/alsa/acp/alsa-util.c:1281 +#, c-format msgid "" "snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu " "ms).\n" @@ -487,18 +503,18 @@ "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgstr0 "" -"snd_pcm_avail() a tornat una valor qu'es excepcionalament larga : %lu octets " +"snd_pcm_avail() a tornat una valor qu'es excepcionalament larga : %lu octet " "(%lu ms).\n" -"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz " -"aqueste problèma als desvolopaires d'ALSA." +"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als " +"desvolopaires d’ALSA." msgstr1 "" "snd_pcm_avail() a tornat una valor qu'es excepcionalament larga : %lu octets " "(%lu ms).\n" -"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz " -"aqueste problèma als desvolopaires d'ALSA." +"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als " +"desvolopaires d’ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1241 -#, fuzzy, c-format +#: spa/plugins/alsa/acp/alsa-util.c:1253 +#, c-format msgid "" "snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s" "%lu ms).\n" @@ -510,17 +526,17 @@ "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgstr0 "" -"snd_pcm_delay() a tornat una valor qu'es excepcionalament larga : %li octets " +"snd_pcm_delay() a tornat una valor qu'es excepcionalament larga : %li octet " "%s%lu ms).\n" -"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz " -"aqueste problèma als desvolopaires d'ALSA." +"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als " +"desvolopaires d’ALSA." msgstr1 "" "snd_pcm_delay() a tornat una valor qu'es excepcionalament larga : %li octets " "%s%lu ms).\n" -"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz " -"aqueste problèma als desvolopaires d'ALSA." +"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als " +"desvolopaires d’ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1288 +#: spa/plugins/alsa/acp/alsa-util.c:1300 #, c-format msgid "" "snd_pcm_avail_delay() returned strange values: delay %lu is less than avail " @@ -530,11 +546,11 @@ msgstr "" "snd_pcm_avail_delay() a tornat de resultats anormals : lo relambi %lu es mai " "pichon que %lu.\n" -"Es fòrt probablament un bug dins lo pilòt ALSA '%s'. Senhalatz-lo als " -"desvolopaires d'ALSA." +"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als " +"desvolopaires d’ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1331 -#, fuzzy, c-format +#: spa/plugins/alsa/acp/alsa-util.c:1343 +#, c-format msgid "" "snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte " "(%lu ms).\n" @@ -547,71 +563,113 @@ "to the ALSA developers." msgstr0 "" "snd_pcm_mmap_begin() a tornat una valor qu'es excepcionalament larga : %lu " -"octets (%lu·ms)..\n" -"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz " -"aqueste problèma als desvolopaires d'ALSA." +"octet (%lu ms).\n" +"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als " +"desvolopaires d’ALSA." msgstr1 "" "snd_pcm_mmap_begin() a tornat una valor qu'es excepcionalament larga : %lu " -"octets (%lu·ms)..\n" -"S'agís fòrt probablament d'un bug dins lo pilòt ALSA « %s ». Raportatz " -"aqueste problèma als desvolopaires d'ALSA." +"octet (%lu ms).\n" +"Es fòrt probablament un bug dins lo pilòt ALSA « %s ». Senhalatz-lo als " +"desvolopaires d’ALSA." + +#: spa/plugins/alsa/acp/channelmap.h:457 +msgid "(invalid)" +msgstr "(invalid)" + +#: spa/plugins/alsa/acp/compat.c:189 +msgid "Built-in Audio" +msgstr "Àudio integrat" + +#: spa/plugins/alsa/acp/compat.c:194 +msgid "Modem" +msgstr "Modèm" -#: spa/plugins/bluez5/bluez5-device.c:1010 +#: spa/plugins/bluez5/bluez5-device.c:1247 msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" -msgstr "" +msgstr "Palanca àudio (Font A2DP & HSP/HFP AG)" -#: spa/plugins/bluez5/bluez5-device.c:1033 +#: spa/plugins/bluez5/bluez5-device.c:1272 #, c-format msgid "High Fidelity Playback (A2DP Sink, codec %s)" -msgstr "" +msgstr "Lectura nauta fidelitat (A2DP Sink, codec %s)" -#: spa/plugins/bluez5/bluez5-device.c:1035 +#: spa/plugins/bluez5/bluez5-device.c:1275 #, c-format msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" -msgstr "" +msgstr "Duplèx nauta fidelitat (A2DP Source/Sink, codec %s)" -#: spa/plugins/bluez5/bluez5-device.c:1041 +#: spa/plugins/bluez5/bluez5-device.c:1283 msgid "High Fidelity Playback (A2DP Sink)" -msgstr "" +msgstr "Lectura nauta fidelitat (A2DP Sink)" -#: spa/plugins/bluez5/bluez5-device.c:1043 +#: spa/plugins/bluez5/bluez5-device.c:1285 msgid "High Fidelity Duplex (A2DP Source/Sink)" -msgstr "" +msgstr "Duplèx nauta fidelitat (A2DP Source/Sink)" + +#: spa/plugins/bluez5/bluez5-device.c:1322 +#, c-format +msgid "High Fidelity Playback (BAP Sink, codec %s)" +msgstr "Lectura nauta fidelitat (A2DP Sink, codec %s)" -#: spa/plugins/bluez5/bluez5-device.c:1070 +#: spa/plugins/bluez5/bluez5-device.c:1326 +#, c-format +msgid "High Fidelity Input (BAP Source, codec %s)" +msgstr "Duplèx nauta fidelitat (Font BAP, codec %s)" + +#: spa/plugins/bluez5/bluez5-device.c:1330 +#, c-format +msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)" +msgstr "Duplèx nauta fidelitat (Font BAP/Sink, codec %s)" + +#: spa/plugins/bluez5/bluez5-device.c:1359 #, c-format msgid "Headset Head Unit (HSP/HFP, codec %s)" msgstr "" -#: spa/plugins/bluez5/bluez5-device.c:1074 +#: spa/plugins/bluez5/bluez5-device.c:1364 msgid "Headset Head Unit (HSP/HFP)" msgstr "" -#: spa/plugins/bluez5/bluez5-device.c:1140 +#: spa/plugins/bluez5/bluez5-device.c:1443 +#: spa/plugins/bluez5/bluez5-device.c:1448 +#: spa/plugins/bluez5/bluez5-device.c:1455 +#: spa/plugins/bluez5/bluez5-device.c:1461 +#: spa/plugins/bluez5/bluez5-device.c:1467 +#: spa/plugins/bluez5/bluez5-device.c:1473 +#: spa/plugins/bluez5/bluez5-device.c:1479 +#: spa/plugins/bluez5/bluez5-device.c:1485 +#: spa/plugins/bluez5/bluez5-device.c:1491 msgid "Handsfree" msgstr "Mans liuras" -#: spa/plugins/bluez5/bluez5-device.c:1155 +#: spa/plugins/bluez5/bluez5-device.c:1449 +msgid "Handsfree (HFP)" +msgstr "Mans liuras (HFP)" + +#: spa/plugins/bluez5/bluez5-device.c:1466 msgid "Headphone" -msgstr "Escotadors" +msgstr "Escotador" -#: spa/plugins/bluez5/bluez5-device.c:1160 +#: spa/plugins/bluez5/bluez5-device.c:1472 msgid "Portable" msgstr "Portable" -#: spa/plugins/bluez5/bluez5-device.c:1165 +#: spa/plugins/bluez5/bluez5-device.c:1478 msgid "Car" msgstr "Telefòn de veitura" -#: spa/plugins/bluez5/bluez5-device.c:1170 +#: spa/plugins/bluez5/bluez5-device.c:1484 msgid "HiFi" msgstr "HiFi" -#: spa/plugins/bluez5/bluez5-device.c:1175 +#: spa/plugins/bluez5/bluez5-device.c:1490 msgid "Phone" msgstr "Telefòn" -#: spa/plugins/bluez5/bluez5-device.c:1181 -#, fuzzy +#: spa/plugins/bluez5/bluez5-device.c:1497 msgid "Bluetooth" -msgstr "Entrada Bluetooth" +msgstr "Bluetooth" + +#: spa/plugins/bluez5/bluez5-device.c:1498 +msgid "Bluetooth (HFP)" +msgstr "Bluetooth (HFP)"
View file
pipewire-0.3.65.tar.gz/po/uk.po -> pipewire-0.3.66.tar.gz/po/uk.po
Changed
@@ -1,14 +1,14 @@ # Copyright (C) 2009 Free Software Foundation, Inc. # This file is distributed under the same license as the pipewire package. # -# Yuri Chornoivan <yurchor@ukr.net>, 2009-2021, 2022. +# Yuri Chornoivan <yurchor@ukr.net>, 2009-2021, 2022, 2023. msgid "" msgstr "" "Project-Id-Version: pipewire\n" -"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/issue" -"s\n" -"POT-Creation-Date: 2022-05-20 15:26+0000\n" -"PO-Revision-Date: 2022-06-18 13:07+0300\n" +"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/issu" +"es\n" +"POT-Creation-Date: 2023-02-06 15:27+0000\n" +"PO-Revision-Date: 2023-02-11 17:42+0200\n" "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n" "Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n" "Language: uk\n" @@ -41,8 +41,8 @@ msgid "Start the PipeWire Media System" msgstr "Запустити мультимедійну систему PipeWire" -#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:183 -#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:183 +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:179 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:179 #, c-format msgid "Tunnel to %s/%s" msgstr "Тунель до %s/%s" @@ -51,33 +51,27 @@ msgid "Dummy Output" msgstr "Фіктивний вихід" -#: src/modules/module-pulse-tunnel.c:639 +#: src/modules/module-pulse-tunnel.c:695 #, c-format msgid "Tunnel for %s@%s" msgstr "Тунель для %s@%s" -#: src/modules/module-zeroconf-discover.c:332 +#: src/modules/module-zeroconf-discover.c:335 msgid "Unknown device" msgstr "Невідомий пристрій" -#: src/modules/module-zeroconf-discover.c:344 +#: src/modules/module-zeroconf-discover.c:347 #, c-format msgid "%s on %s@%s" msgstr "%s на %s@%s" -#: src/modules/module-zeroconf-discover.c:348 +#: src/modules/module-zeroconf-discover.c:351 #, c-format msgid "%s on %s" msgstr "%s на %s" -#: src/tools/pw-cat.c:872 +#: src/tools/pw-cat.c:940 #, c-format -#| msgid "" -#| "%s options <file>\n" -#| " -h, --help Show this help\n" -#| " --version Show version\n" -#| " -v, --verbose Enable verbose operations\n" -#| "\n" msgid "" "%s options <file>|-\n" " -h, --help Show this help\n" @@ -92,7 +86,7 @@ "інформації\n" "\n" -#: src/tools/pw-cat.c:879 +#: src/tools/pw-cat.c:947 #, c-format #| msgid "" #| " -R, --remote Remote daemon name\n" @@ -106,13 +100,15 @@ #| " or direct samples (256)\n" #| " the rate is the one of the " #| "source file\n" +#| " -P --properties Set node properties\n" #| "\n" msgid "" " -R, --remote Remote daemon name\n" " --media-type Set media type (default %s)\n" " --media-category Set media category (default %s)\n" " --media-role Set media role (default %s)\n" -" --target Set node target (default %s)\n" +" --target Set node target serial or name " +"(default %s)\n" " 0 means don't link\n" " --latency Set node latency (default %s)\n" " Xunit (unit = s, ms, us, ns)\n" @@ -129,7 +125,8 @@ "(типово, %s)\n" " --media-role встановити роль мультимедіа (типово, " "%s)\n" -" --target встановити ціль вузла (типово, %s)\n" +" --target встановити назву або серійний номер" +" цілі вузла (типово, %s)\n" " 0 — не пов'язувати\n" " --latency встановити затримку вузла (типово, " "%s)\n" @@ -140,7 +137,7 @@ " -P --properties встановити властивості вузла\n" "\n" -#: src/tools/pw-cat.c:897 +#: src/tools/pw-cat.c:965 #, c-format msgid "" " --rate Sample rate (req. for rec) (default " @@ -176,28 +173,44 @@ "(типово, %d)\n" "\n" -#: src/tools/pw-cat.c:914 +#: src/tools/pw-cat.c:982 +#| msgid "" +#| " -p, --playback Playback mode\n" +#| " -r, --record Recording mode\n" +#| " -m, --midi Midi mode\n" +#| " -d, --dsd DSD mode\n" +#| "\n" msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n" " -m, --midi Midi mode\n" " -d, --dsd DSD mode\n" +" -o, --encoded\t\t\t Encoded mode\n" "\n" msgstr "" " -p, --playback режим відтворення\n" " -r, --record режим запису\n" " -m, --midi режим MIDI\n" " -d, --dsd режим DSD\n" +" -o, --encoded\t\t\t закодований режим\n" "\n" -#: src/tools/pw-cli.c:3139 +#: src/tools/pw-cli.c:2236 #, c-format +#| msgid "" +#| "%s options command\n" +#| " -h, --help Show this help\n" +#| " --version Show version\n" +#| " -d, --daemon Start as daemon (Default false)\n" +#| " -r, --remote Remote daemon name\n" +#| "\n" msgid "" "%s options command\n" " -h, --help Show this help\n" " --version Show version\n" " -d, --daemon Start as daemon (Default false)\n" " -r, --remote Remote daemon name\n" +" -m, --monitor Monitor activity\n" "\n" msgstr "" "%s параметри команда\n" @@ -206,14 +219,15 @@ " -d, --daemon запустити як фонову службу (типово, " "false)\n" " -r, --remote назва віддаленої фонової служби\n" +" -m, --monitor спостерігати за діями\n" "\n" -#: spa/plugins/alsa/acp/acp.c:321 +#: spa/plugins/alsa/acp/acp.c:323 msgid "Pro Audio" msgstr "Професійний звук" -#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648 -#: spa/plugins/bluez5/bluez5-device.c:1161 +#: spa/plugins/alsa/acp/acp.c:447 spa/plugins/alsa/acp/alsa-mixer.c:4648 +#: spa/plugins/bluez5/bluez5-device.c:1303 msgid "Off" msgstr "Вимкнено" @@ -240,7 +254,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:2657 #: spa/plugins/alsa/acp/alsa-mixer.c:2741 -#: spa/plugins/bluez5/bluez5-device.c:1330 +#: spa/plugins/bluez5/bluez5-device.c:1536 msgid "Microphone" msgstr "Мікрофон" @@ -306,7 +320,7 @@ msgstr "Без підсилення" #: spa/plugins/alsa/acp/alsa-mixer.c:2672 -#: spa/plugins/bluez5/bluez5-device.c:1335 +#: spa/plugins/bluez5/bluez5-device.c:1542 msgid "Speaker" msgstr "Динамік" @@ -421,7 +435,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4484 #: spa/plugins/alsa/acp/alsa-mixer.c:4642 -#: spa/plugins/bluez5/bluez5-device.c:1320 +#: spa/plugins/bluez5/bluez5-device.c:1524 msgid "Headset" msgstr "Гарнітура" @@ -545,7 +559,7 @@ msgid "%s Input" msgstr "%s-вхід" -#: spa/plugins/alsa/acp/alsa-util.c:1173 spa/plugins/alsa/acp/alsa-util.c:1267 +#: spa/plugins/alsa/acp/alsa-util.c:1187 spa/plugins/alsa/acp/alsa-util.c:1281 #, c-format msgid "" "snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu " @@ -573,7 +587,7 @@ "Ймовірно, ви натрапили на помилку у драйвері ALSA «%s». Будь ласка, " "повідомте про цю помилку розробникам ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1239 +#: spa/plugins/alsa/acp/alsa-util.c:1253 #, c-format msgid "" "snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s" @@ -601,7 +615,7 @@ "Ймовірно, ви натрапили на помилку у драйвері ALSA «%s». Будь ласка, " "повідомте про цю помилку розробникам ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1286 +#: spa/plugins/alsa/acp/alsa-util.c:1300 #, c-format msgid "" "snd_pcm_avail_delay() returned strange values: delay %lu is less than avail " @@ -614,7 +628,7 @@ "Ймовірно, це пов’язано з помилкою у драйвері ALSA «%s». Будь ласка, " "повідомте про цю помилку розробникам ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1329 +#: spa/plugins/alsa/acp/alsa-util.c:1343 #, c-format msgid "" "snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte " @@ -642,7 +656,7 @@ "Ймовірно, ви натрапили на помилку у драйвері ALSA «%s». Будь ласка, " "повідомте про цю помилку розробникам ALSA." -#: spa/plugins/alsa/acp/channelmap.h:464 +#: spa/plugins/alsa/acp/channelmap.h:457 msgid "(invalid)" msgstr "(некоректний)" @@ -654,61 +668,112 @@ msgid "Modem" msgstr "Модем" -#: spa/plugins/bluez5/bluez5-device.c:1172 +#: spa/plugins/bluez5/bluez5-device.c:1314 msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" msgstr "Звуковий шлюз (джерело A2DP і HSP/HFP AG)" -#: spa/plugins/bluez5/bluez5-device.c:1197 +#: spa/plugins/bluez5/bluez5-device.c:1339 #, c-format msgid "High Fidelity Playback (A2DP Sink, codec %s)" msgstr "Високоточне відтворення (приймач A2DP, кодек %s)" -#: spa/plugins/bluez5/bluez5-device.c:1200 +#: spa/plugins/bluez5/bluez5-device.c:1342 #, c-format msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" msgstr "Двобічний високоточний обмін (джерело/приймач A2DP, кодек %s)" -#: spa/plugins/bluez5/bluez5-device.c:1208 +#: spa/plugins/bluez5/bluez5-device.c:1350 msgid "High Fidelity Playback (A2DP Sink)" msgstr "Високоточне відтворення (приймач A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:1210 +#: spa/plugins/bluez5/bluez5-device.c:1352 msgid "High Fidelity Duplex (A2DP Source/Sink)" msgstr "Двобічний високоточний обмін (джерело/приймач A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:1238 +#: spa/plugins/bluez5/bluez5-device.c:1391 +#, c-format +#| msgid "High Fidelity Playback (A2DP Sink, codec %s)" +msgid "High Fidelity Playback (BAP Sink, codec %s)" +msgstr "Високоточне відтворення (приймач BAP, кодек %s)" + +#: spa/plugins/bluez5/bluez5-device.c:1395 +#, c-format +#| msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" +msgid "High Fidelity Input (BAP Source, codec %s)" +msgstr "Двобічний високоточний вхід (джерело BAP, кодек %s)" + +#: spa/plugins/bluez5/bluez5-device.c:1399 +#, c-format +#| msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" +msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)" +msgstr "Двобічний високоточний обмін (джерело/приймач BAP, кодек %s)" + +#: spa/plugins/bluez5/bluez5-device.c:1407 +#| msgid "High Fidelity Playback (A2DP Sink)" +msgid "High Fidelity Playback (BAP Sink)" +msgstr "Високоточне відтворення (приймач BAP)" + +#: spa/plugins/bluez5/bluez5-device.c:1410 +#| msgid "High Fidelity Duplex (A2DP Source/Sink)" +msgid "High Fidelity Input (BAP Source)" +msgstr "Двобічний високоточний вхід (джерело BAP)" + +#: spa/plugins/bluez5/bluez5-device.c:1413 +#| msgid "High Fidelity Duplex (A2DP Source/Sink)" +msgid "High Fidelity Duplex (BAP Source/Sink)" +msgstr "Двобічний високоточний обмін (джерело/приймач BAP)" + +#: spa/plugins/bluez5/bluez5-device.c:1441 #, c-format msgid "Headset Head Unit (HSP/HFP, codec %s)" msgstr "Головний модуль гарнітури (HSP/HFP, кодек %s)" -#: spa/plugins/bluez5/bluez5-device.c:1243 +#: spa/plugins/bluez5/bluez5-device.c:1446 msgid "Headset Head Unit (HSP/HFP)" msgstr "Головний модуль гарнітури (HSP/HFP)" -#: spa/plugins/bluez5/bluez5-device.c:1325 +#: spa/plugins/bluez5/bluez5-device.c:1525 +#: spa/plugins/bluez5/bluez5-device.c:1530 +#: spa/plugins/bluez5/bluez5-device.c:1537 +#: spa/plugins/bluez5/bluez5-device.c:1543 +#: spa/plugins/bluez5/bluez5-device.c:1549 +#: spa/plugins/bluez5/bluez5-device.c:1555 +#: spa/plugins/bluez5/bluez5-device.c:1561 +#: spa/plugins/bluez5/bluez5-device.c:1567 +#: spa/plugins/bluez5/bluez5-device.c:1573 msgid "Handsfree" msgstr "Hands-Free пристрій" -#: spa/plugins/bluez5/bluez5-device.c:1340 +#: spa/plugins/bluez5/bluez5-device.c:1531 +#| msgid "Handsfree" +msgid "Handsfree (HFP)" +msgstr "Hands-Free пристрій (HFP)" + +#: spa/plugins/bluez5/bluez5-device.c:1548 msgid "Headphone" msgstr "Навушники" -#: spa/plugins/bluez5/bluez5-device.c:1345 +#: spa/plugins/bluez5/bluez5-device.c:1554 msgid "Portable" msgstr "Портативна акустика" -#: spa/plugins/bluez5/bluez5-device.c:1350 +#: spa/plugins/bluez5/bluez5-device.c:1560 msgid "Car" msgstr "Автомобільна акустика" -#: spa/plugins/bluez5/bluez5-device.c:1355 +#: spa/plugins/bluez5/bluez5-device.c:1566 msgid "HiFi" msgstr "Hi-Fi" -#: spa/plugins/bluez5/bluez5-device.c:1360 +#: spa/plugins/bluez5/bluez5-device.c:1572 msgid "Phone" msgstr "Телефон" -#: spa/plugins/bluez5/bluez5-device.c:1366 +#: spa/plugins/bluez5/bluez5-device.c:1579 msgid "Bluetooth" msgstr "Bluetooth" + +#: spa/plugins/bluez5/bluez5-device.c:1580 +#| msgid "Bluetooth" +msgid "Bluetooth (HFP)" +msgstr "Bluetooth (HFP)"
View file
pipewire-0.3.65.tar.gz/spa/include/spa/param/port-config.h -> pipewire-0.3.66.tar.gz/spa/include/spa/param/port-config.h
Changed
@@ -48,7 +48,7 @@ /** properties for SPA_TYPE_OBJECT_ParamPortConfig */ enum spa_param_port_config { SPA_PARAM_PORT_CONFIG_START, - SPA_PARAM_PORT_CONFIG_direction, /**< direction, input/output (Id enum spa_direction) */ + SPA_PARAM_PORT_CONFIG_direction, /**< (Id enum spa_direction) direction */ SPA_PARAM_PORT_CONFIG_mode, /**< (Id enum spa_param_port_config_mode) mode */ SPA_PARAM_PORT_CONFIG_monitor, /**< (Bool) enable monitor output ports on input ports */ SPA_PARAM_PORT_CONFIG_control, /**< (Bool) enable control ports */
View file
pipewire-0.3.65.tar.gz/spa/include/spa/utils/defs.h -> pipewire-0.3.66.tar.gz/spa/include/spa/utils/defs.h
Changed
@@ -142,7 +142,7 @@ for ((ptr) = arr; (void*)(ptr) < SPA_PTROFF(arr, sizeof(arr), void); (ptr)++) #define SPA_FOR_EACH_ELEMENT_VAR(arr, var) \ - for (__typeof__((arr)0)* (var) = arr; (void*)(var) < SPA_PTROFF(arr, sizeof(arr), void); (var)++) + for (__typeof__((arr)0)* var = arr; (void*)(var) < SPA_PTROFF(arr, sizeof(arr), void); (var)++) #define SPA_ABS(a) \ ({ \
View file
pipewire-0.3.65.tar.gz/spa/meson.build -> pipewire-0.3.66.tar.gz/spa/meson.build
Changed
@@ -41,14 +41,23 @@ # plugin-specific dependencies alsa_dep = dependency('alsa', required: get_option('alsa')) summary({'ALSA': alsa_dep.found()}, bool_yn: true, section: 'Backend') + bluez_dep = dependency('bluez', version : '>= 4.101', required: get_option('bluez5')) gio_dep = dependency('gio-2.0', required : get_option('bluez5')) gio_unix_dep = dependency('gio-unix-2.0', required : get_option('bluez5')) - bluez_deps_found = bluez_dep.found() and gio_dep.found() and gio_unix_dep.found() + bluez_glib2_dep = dependency('glib-2.0', required : get_option('bluez5')) + sbc_dep = dependency('sbc', required: get_option('bluez5')) + summary({'SBC': sbc_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs') + bluez5_deps = mathlib, dbus_dep, sbc_dep, bluez_dep, bluez_glib2_dep, gio_dep, gio_unix_dep + bluez_deps_found = get_option('bluez5').allowed() + foreach dep: bluez5_deps + if get_option('bluez5').enabled() and not dep.found() + error('bluez5 enabled, but dependency not found: ' + dep.name()) + endif + bluez_deps_found = bluez_deps_found and dep.found() + endforeach summary({'Bluetooth audio': bluez_deps_found}, bool_yn: true, section: 'Backend') if bluez_deps_found - sbc_dep = dependency('sbc', required: get_option('bluez5')) - summary({'SBC': sbc_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs') ldac_dep = dependency('ldacBT-enc', required : get_option('bluez5-codec-ldac')) summary({'LDAC': ldac_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs') ldac_abr_dep = dependency('ldacBT-abr', required : get_option('bluez5-codec-ldac'))
View file
pipewire-0.3.65.tar.gz/spa/plugins/alsa/acp/acp.c -> pipewire-0.3.66.tar.gz/spa/plugins/alsa/acp/acp.c
Changed
@@ -315,7 +315,7 @@ ss.format = PA_SAMPLE_S32LE; ss.rate = impl->rate; - ss.channels = 64; + ss.channels = impl->pro_channels; ap = pa_xnew0(pa_alsa_profile, 1); ap->profile_set = ps; @@ -1564,6 +1564,7 @@ impl->auto_port = true; impl->ignore_dB = false; impl->rate = DEFAULT_RATE; + impl->pro_channels = 64; if (props) { if ((s = acp_dict_lookup(props, "api.alsa.use-ucm")) != NULL) @@ -1582,6 +1583,8 @@ impl->auto_port = spa_atob(s); if ((s = acp_dict_lookup(props, "api.acp.probe-rate")) != NULL) impl->rate = atoi(s); + if ((s = acp_dict_lookup(props, "api.acp.pro-channels")) != NULL) + impl->pro_channels = atoi(s); } impl->ucm.default_sample_spec.format = PA_SAMPLE_S16NE;
View file
pipewire-0.3.65.tar.gz/spa/plugins/alsa/acp/card.h -> pipewire-0.3.66.tar.gz/spa/plugins/alsa/acp/card.h
Changed
@@ -48,6 +48,7 @@ bool auto_port; bool ignore_dB; uint32_t rate; + uint32_t pro_channels; pa_alsa_ucm_config ucm; pa_alsa_profile_set *profile_set;
View file
pipewire-0.3.65.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.66.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -1879,6 +1879,8 @@ } else { *delay = avail; *target = SPA_MAX(*target, state->read_size); + if (state->matching) + *target += 32; } *target = SPA_CLAMP(*target, state->min_delay, state->buffer_frames); return 0;
View file
pipewire-0.3.65.tar.gz/spa/plugins/audioconvert/channelmix-ops.c -> pipewire-0.3.66.tar.gz/spa/plugins/audioconvert/channelmix-ops.c
Changed
@@ -142,18 +142,67 @@ #define MATRIX_DOLBY 1 #define MATRIX_DPLII 2 -#define _CH(ch) ((SPA_AUDIO_CHANNEL_ ## ch)-3) +#define _SH 2 +#define _CH(ch) ((SPA_AUDIO_CHANNEL_ ## ch)-_SH) #define _MASK(ch) (1ULL << _CH(ch)) #define FRONT (_MASK(FC)) #define STEREO (_MASK(FL)|_MASK(FR)) #define REAR (_MASK(RL)|_MASK(RR)) #define SIDE (_MASK(SL)|_MASK(SR)) +static uint32_t mask_to_ch(struct channelmix *mix, uint64_t mask) +{ + uint32_t ch = 0; + while (mask > 1) { + ch++; + mask >>= 1; + } + return ch; +} + +static void distribute_mix(struct channelmix *mix, + float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS, + uint64_t mask) +{ + uint32_t i, ch = mask_to_ch(mix, mask); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) + matrixich= 1.0f; +} +static void average_mix(struct channelmix *mix, + float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS, + uint64_t mask) +{ + uint32_t i, ch = mask_to_ch(mix, mask); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) + matrixchi= 1.0f; +} +static void pair_mix(float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS) +{ + uint32_t i; + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) + matrixii= 1.0f; +} +static bool match_mix(struct channelmix *mix, + float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS, + uint64_t src_mask, uint64_t dst_mask) +{ + bool matched = false; + uint32_t i; + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) { + if ((src_mask & dst_mask & (1ULL << i))) { + spa_log_info(mix->log, "matched channel %u (%f)", i, 1.0f); + matrixii = 1.0f; + matched = true; + } + } + return matched; +} + static int make_matrix(struct channelmix *mix) { float matrixSPA_AUDIO_MAX_CHANNELSSPA_AUDIO_MAX_CHANNELS = {{ 0.0f }}; - uint64_t src_mask = mix->src_mask; - uint64_t dst_mask = mix->dst_mask; + uint64_t src_mask = mix->src_mask, src_paired; + uint64_t dst_mask = mix->dst_mask, dst_paired; uint32_t src_chan = mix->src_chan; uint32_t dst_chan = mix->dst_chan; uint64_t unassigned, keep; @@ -162,89 +211,110 @@ float slev = SQRT1_2; float llev = 0.5f; float maxsum = 0.0f; - bool filter_fc = false, filter_lfe = false; + bool filter_fc = false, filter_lfe = false, matched = false, normalize; #define _MATRIX(s,d) matrix_CH(s)_CH(d) + normalize = SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_NORMALIZE); + spa_log_debug(mix->log, "src-mask:%08"PRIx64" dst-mask:%08"PRIx64 " options:%08x", src_mask, dst_mask, mix->options); - /* move the MONO mask to FRONT so that the lower bits can be shifted - * away. */ - if ((src_mask & (1Ull << SPA_AUDIO_CHANNEL_MONO)) != 0) { - if (src_chan == 1) - src_mask = 0; - else - src_mask |= (1ULL << SPA_AUDIO_CHANNEL_FC); - } - if ((dst_mask & (1Ull << SPA_AUDIO_CHANNEL_MONO)) != 0) - dst_mask |= (1ULL << SPA_AUDIO_CHANNEL_FC); + /* shift so that bit 0 is MONO */ + src_mask >>= _SH; + dst_mask >>= _SH; - /* shift so that bit 0 is FL */ - src_mask >>= 3; - dst_mask >>= 3; + if (src_chan > 1 && (src_mask & _MASK(MONO))) + src_mask = 0; + if (dst_chan > 1 && (dst_mask & _MASK(MONO))) + dst_mask = 0; - /* unknown channels or just 1 channel */ + src_paired = src_mask; + dst_paired = dst_mask; + + /* unknown channels */ if (src_mask == 0 || dst_mask == 0) { if (src_chan == 1) { - /* one FC/MONO src goes everywhere */ - spa_log_debug(mix->log, "distribute FC/MONO (%f)", 1.0f); - for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) - matrixi0= 1.0f; + /* one src channel goes everywhere */ + spa_log_info(mix->log, "distribute UNK (%f) %"PRIu64, 1.0f, src_mask); + distribute_mix(mix, matrix, src_mask); } else if (dst_chan == 1) { - /* one FC/MONO dst get average of everything */ - spa_log_debug(mix->log, "average FC/MONO (%f)", 1.0f / src_chan); - for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) - matrix0i= 1.0f / src_chan; + /* one dst channel get average of everything */ + spa_log_info(mix->log, "average UNK (%f) %"PRIu64, 1.0f / src_chan, dst_mask); + average_mix(mix, matrix, dst_mask); + normalize = true; } else { /* just pair channels */ - spa_log_debug(mix->log, "pairing channels (%f)", 1.0f); - for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) - matrixii= 1.0f; + spa_log_info(mix->log, "pairing UNK channels (%f)", 1.0f); + if (src_mask == 0) + src_paired = dst_mask; + else if (dst_mask == 0) + dst_paired = src_mask; + pair_mix(matrix); } - if (dst_mask & FRONT) - filter_fc = true; - if (dst_mask & _MASK(LFE)) - filter_lfe = true; - src_mask = dst_mask = ~0LU; goto done; } else { spa_log_debug(mix->log, "matching channels"); - for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) { - if ((src_mask & dst_mask & (1ULL << i))) { - spa_log_debug(mix->log, "matched channel %u (%f)", i, 1.0f); - matrixii= 1.0f; - } - } + matched = match_mix(mix, matrix, src_mask, dst_mask); } unassigned = src_mask & ~dst_mask; keep = dst_mask & ~src_mask; if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX)) { + /* upmix completely disabled */ keep = 0; } else { + /* some upmixing (FC and LFE) enabled. */ if (mix->upmix == CHANNELMIX_UPMIX_NONE) keep = 0; - keep |= FRONT; + if (mix->fc_cutoff > 0.0f) + keep |= FRONT; + else + keep &= ~FRONT; if (mix->lfe_cutoff > 0.0f) keep |= _MASK(LFE); else keep &= ~_MASK(LFE); } + /* if we have no channel matched, try to upmix or keep the stereo + * pair or else we might end up with silence. */ + if (dst_mask & STEREO && !matched) + keep |= STEREO; + + spa_log_info(mix->log, "unassigned downmix %08" PRIx64 " %08" PRIx64, unassigned, keep); + + if (unassigned & _MASK(MONO)) { + if ((dst_mask & STEREO) == STEREO) { + spa_log_info(mix->log, "assign MONO to STEREO (%f)", 1.0f); + _MATRIX(FL,MONO) += 1.0f; + _MATRIX(FR,MONO) += 1.0f; + keep &= ~STEREO; + } else if ((dst_mask & FRONT) == FRONT) { + spa_log_info(mix->log, "assign MONO to FRONT (%f)", 1.0f); + _MATRIX(FC,MONO) += 1.0f; + normalize = true; + } else { + spa_log_warn(mix->log, "can't assign MONO"); + } + } - spa_log_debug(mix->log, "unassigned downmix %08" PRIx64 " %08" PRIx64, unassigned, keep); - - if (unassigned & FRONT){ + if (unassigned & FRONT) { if ((dst_mask & STEREO) == STEREO){ - if(src_mask & STEREO) { - spa_log_debug(mix->log, "assign FC to STEREO (%f)", clev); + if (src_mask & STEREO) { + spa_log_info(mix->log, "assign FC to STEREO (%f)", clev); _MATRIX(FL,FC) += clev; _MATRIX(FR,FC) += clev; } else { - spa_log_debug(mix->log, "assign FC to STEREO (%f)", SQRT1_2); + spa_log_info(mix->log, "assign FC to STEREO (%f)", SQRT1_2); _MATRIX(FL,FC) += SQRT1_2; _MATRIX(FR,FC) += SQRT1_2; } + keep &= ~STEREO; + } else if (dst_mask & _MASK(MONO)){ + spa_log_info(mix->log, "assign FC to MONO (%f)", 1.0f); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) + matrixi_CH(FC)= 1.0f; + normalize = true; } else { spa_log_warn(mix->log, "can't assign FC"); } @@ -252,14 +322,21 @@ if (unassigned & STEREO){ if (dst_mask & FRONT) { - spa_log_debug(mix->log, "assign STEREO to FC (%f)", SQRT1_2); + spa_log_info(mix->log, "assign STEREO to FC (%f)", SQRT1_2); _MATRIX(FC,FL) += SQRT1_2; _MATRIX(FC,FR) += SQRT1_2; if (src_mask & FRONT) { - spa_log_debug(mix->log, "assign FC to FC (%f)", clev * SQRT2); + spa_log_info(mix->log, "assign FC to FC (%f)", clev * SQRT2); _MATRIX(FC,FC) = clev * SQRT2; } keep &= ~FRONT; + } else if ((dst_mask & _MASK(MONO))){ + spa_log_info(mix->log, "assign STEREO to MONO (%f)", 1.0f); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) { + matrixi_CH(FL)= 1.0f; + matrixi_CH(FR)= 1.0f; + } + normalize = true; } else { spa_log_warn(mix->log, "can't assign STEREO"); } @@ -267,15 +344,15 @@ if (unassigned & _MASK(RC)) { if (dst_mask & REAR){ - spa_log_debug(mix->log, "assign RC to RL+RR (%f)", SQRT1_2); + spa_log_info(mix->log, "assign RC to RL+RR (%f)", SQRT1_2); _MATRIX(RL,RC) += SQRT1_2; _MATRIX(RR,RC) += SQRT1_2; } else if (dst_mask & SIDE) { - spa_log_debug(mix->log, "assign RC to SL+SR (%f)", SQRT1_2); + spa_log_info(mix->log, "assign RC to SL+SR (%f)", SQRT1_2); _MATRIX(SL,RC) += SQRT1_2; _MATRIX(SR,RC) += SQRT1_2; } else if(dst_mask & STEREO) { - spa_log_debug(mix->log, "assign RC to FL+FR"); + spa_log_info(mix->log, "assign RC to FL+FR"); if (matrix_encoding == MATRIX_DOLBY || matrix_encoding == MATRIX_DPLII) { if (unassigned & (_MASK(RL)|_MASK(RR))) { @@ -290,8 +367,13 @@ _MATRIX(FR,RC) += slev * SQRT1_2; } } else if (dst_mask & FRONT) { - spa_log_debug(mix->log, "assign RC to FC (%f)", slev * SQRT1_2); + spa_log_info(mix->log, "assign RC to FC (%f)", slev * SQRT1_2); _MATRIX(FC,RC) += slev * SQRT1_2; + } else if (dst_mask & _MASK(MONO)){ + spa_log_info(mix->log, "assign RC to MONO (%f)", 1.0f); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) + matrixi_CH(RC)= 1.0f; + normalize = true; } else { spa_log_warn(mix->log, "can't assign RC"); } @@ -299,11 +381,11 @@ if (unassigned & REAR) { if (dst_mask & _MASK(RC)) { - spa_log_debug(mix->log, "assign RL+RR to RC"); + spa_log_info(mix->log, "assign RL+RR to RC"); _MATRIX(RC,RL) += SQRT1_2; _MATRIX(RC,RR) += SQRT1_2; } else if (dst_mask & SIDE) { - spa_log_debug(mix->log, "assign RL+RR to SL+SR"); + spa_log_info(mix->log, "assign RL+RR to SL+SR"); if (src_mask & SIDE) { _MATRIX(SL,RL) += SQRT1_2; _MATRIX(SR,RR) += SQRT1_2; @@ -313,7 +395,7 @@ } keep &= ~SIDE; } else if (dst_mask & STEREO) { - spa_log_debug(mix->log, "assign RL+RR to FL+FR (%f)", slev); + spa_log_info(mix->log, "assign RL+RR to FL+FR (%f)", slev); if (matrix_encoding == MATRIX_DOLBY) { _MATRIX(FL,RL) -= slev * SQRT1_2; _MATRIX(FL,RR) -= slev * SQRT1_2; @@ -329,10 +411,17 @@ _MATRIX(FR,RR) += slev; } } else if (dst_mask & FRONT) { - spa_log_debug(mix->log, "assign RL+RR to FC (%f)", + spa_log_info(mix->log, "assign RL+RR to FC (%f)", slev * SQRT1_2); _MATRIX(FC,RL)+= slev * SQRT1_2; _MATRIX(FC,RR)+= slev * SQRT1_2; + } else if (dst_mask & _MASK(MONO)){ + spa_log_info(mix->log, "assign RL+RR to MONO (%f)", 1.0f); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) { + matrixi_CH(RL)= 1.0f; + matrixi_CH(RR)= 1.0f; + } + normalize = true; } else { spa_log_warn(mix->log, "can't assign RL"); } @@ -341,43 +430,50 @@ if (unassigned & SIDE) { if (dst_mask & REAR) { if (src_mask & _MASK(RL)) { - spa_log_debug(mix->log, "assign SL+SR to RL+RR (%f)", SQRT1_2); + spa_log_info(mix->log, "assign SL+SR to RL+RR (%f)", SQRT1_2); _MATRIX(RL,SL) += SQRT1_2; _MATRIX(RR,SR) += SQRT1_2; } else { - spa_log_debug(mix->log, "assign SL+SR to RL+RR (%f)", 1.0f); + spa_log_info(mix->log, "assign SL+SR to RL+RR (%f)", 1.0f); _MATRIX(RL,SL) += 1.0f; _MATRIX(RR,SR) += 1.0f; } keep &= ~REAR; } else if (dst_mask & _MASK(RC)) { - spa_log_debug(mix->log, "assign SL+SR to RC (%f)", SQRT1_2); + spa_log_info(mix->log, "assign SL+SR to RC (%f)", SQRT1_2); _MATRIX(RC,SL)+= SQRT1_2; _MATRIX(RC,SR)+= SQRT1_2; } else if (dst_mask & STEREO) { if (matrix_encoding == MATRIX_DOLBY) { - spa_log_debug(mix->log, "assign SL+SR to FL+FR (%f)", + spa_log_info(mix->log, "assign SL+SR to FL+FR (%f)", slev * SQRT1_2); _MATRIX(FL,SL) -= slev * SQRT1_2; _MATRIX(FL,SR) -= slev * SQRT1_2; _MATRIX(FR,SL) += slev * SQRT1_2; _MATRIX(FR,SR) += slev * SQRT1_2; } else if (matrix_encoding == MATRIX_DPLII) { - spa_log_debug(mix->log, "assign SL+SR to FL+FR (%f / %f)", + spa_log_info(mix->log, "assign SL+SR to FL+FR (%f / %f)", slev * SQRT3_2, slev * SQRT1_2); _MATRIX(FL,SL) -= slev * SQRT3_2; _MATRIX(FL,SR) -= slev * SQRT1_2; _MATRIX(FR,SL) += slev * SQRT1_2; _MATRIX(FR,SR) += slev * SQRT3_2; } else { - spa_log_debug(mix->log, "assign SL+SR to FL+FR (%f)", slev); + spa_log_info(mix->log, "assign SL+SR to FL+FR (%f)", slev); _MATRIX(FL,SL) += slev; _MATRIX(FR,SR) += slev; } } else if (dst_mask & FRONT) { - spa_log_debug(mix->log, "assign SL+SR to FC (%f)", slev * SQRT1_2); + spa_log_info(mix->log, "assign SL+SR to FC (%f)", slev * SQRT1_2); _MATRIX(FC,SL) += slev * SQRT1_2; _MATRIX(FC,SR) += slev * SQRT1_2; + } else if (dst_mask & _MASK(MONO)){ + spa_log_info(mix->log, "assign SL+SR to MONO (%f)", 1.0f); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) { + matrixi_CH(SL)= 1.0f; + matrixi_CH(SR)= 1.0f; + } + normalize = true; } else { spa_log_warn(mix->log, "can't assign SL"); } @@ -385,13 +481,20 @@ if (unassigned & _MASK(FLC)) { if (dst_mask & STEREO) { - spa_log_debug(mix->log, "assign FLC+FRC to FL+FR (%f)", 1.0f); + spa_log_info(mix->log, "assign FLC+FRC to FL+FR (%f)", 1.0f); _MATRIX(FL,FLC)+= 1.0f; _MATRIX(FR,FRC)+= 1.0f; } else if(dst_mask & FRONT) { - spa_log_debug(mix->log, "assign FLC+FRC to FC (%f)", SQRT1_2); + spa_log_info(mix->log, "assign FLC+FRC to FC (%f)", SQRT1_2); _MATRIX(FC,FLC)+= SQRT1_2; _MATRIX(FC,FRC)+= SQRT1_2; + } else if (dst_mask & _MASK(MONO)){ + spa_log_info(mix->log, "assign FLC+FRC to MONO (%f)", 1.0f); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) { + matrixi_CH(FLC)= 1.0f; + matrixi_CH(FRC)= 1.0f; + } + normalize = true; } else { spa_log_warn(mix->log, "can't assign FLC"); } @@ -399,13 +502,18 @@ if (unassigned & _MASK(LFE) && SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_MIX_LFE)) { if (dst_mask & FRONT) { - spa_log_debug(mix->log, "assign LFE to FC (%f)", llev); + spa_log_info(mix->log, "assign LFE to FC (%f)", llev); _MATRIX(FC,LFE) += llev; } else if (dst_mask & STEREO) { - spa_log_debug(mix->log, "assign LFE to FL+FR (%f)", + spa_log_info(mix->log, "assign LFE to FL+FR (%f)", llev * SQRT1_2); _MATRIX(FL,LFE) += llev * SQRT1_2; _MATRIX(FR,LFE) += llev * SQRT1_2; + } else if ((dst_mask & _MASK(MONO))){ + spa_log_info(mix->log, "assign LFE to MONO (%f)", 1.0f); + for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) + matrixi_CH(LFE)= 1.0f; + normalize = true; } else { spa_log_warn(mix->log, "can't assign LFE"); } @@ -413,117 +521,148 @@ unassigned = dst_mask & ~src_mask & keep; - spa_log_debug(mix->log, "unassigned upmix %08"PRIx64" lfe:%f", + spa_log_info(mix->log, "unassigned upmix %08"PRIx64" lfe:%f", unassigned, mix->lfe_cutoff); if (unassigned & STEREO) { if ((src_mask & FRONT) == FRONT) { - spa_log_debug(mix->log, "produce STEREO from FC (%f)", clev); + spa_log_info(mix->log, "produce STEREO from FC (%f)", clev); _MATRIX(FL,FC) += clev; _MATRIX(FR,FC) += clev; + } else if (src_mask & _MASK(MONO)) { + spa_log_info(mix->log, "produce STEREO from MONO (%f)", 1.0f); + _MATRIX(FL,MONO) += 1.0f; + _MATRIX(FR,MONO) += 1.0f; } else { spa_log_warn(mix->log, "can't produce STEREO"); } } if (unassigned & FRONT) { if ((src_mask & STEREO) == STEREO) { - spa_log_debug(mix->log, "produce FC from STEREO (%f)", clev); + spa_log_info(mix->log, "produce FC from STEREO (%f)", clev); _MATRIX(FC,FL) += clev; _MATRIX(FC,FR) += clev; filter_fc = true; + } else if (src_mask & _MASK(MONO)) { + spa_log_info(mix->log, "produce FC from MONO (%f)", 1.0f); + _MATRIX(FC,MONO) += 1.0f; + filter_fc = true; } else { spa_log_warn(mix->log, "can't produce FC"); } } if (unassigned & _MASK(LFE)) { if ((src_mask & STEREO) == STEREO) { - spa_log_debug(mix->log, "produce LFE from STEREO (%f)", llev); + spa_log_info(mix->log, "produce LFE from STEREO (%f)", llev); _MATRIX(LFE,FL) += llev; _MATRIX(LFE,FR) += llev; filter_lfe = true; } else if ((src_mask & FRONT) == FRONT) { - spa_log_debug(mix->log, "produce LFE from FC (%f)", llev); + spa_log_info(mix->log, "produce LFE from FC (%f)", llev); _MATRIX(LFE,FC) += llev; filter_lfe = true; + } else if (src_mask & _MASK(MONO)) { + spa_log_info(mix->log, "produce LFE from MONO (%f)", 1.0f); + _MATRIX(LFE,MONO) += 1.0f; + filter_lfe = true; } else { spa_log_warn(mix->log, "can't produce LFE"); } } if (unassigned & SIDE) { if ((src_mask & REAR) == REAR) { - spa_log_debug(mix->log, "produce SIDE from REAR (%f)", 1.0f); + spa_log_info(mix->log, "produce SIDE from REAR (%f)", 1.0f); _MATRIX(SL,RL) += 1.0f; _MATRIX(SR,RR) += 1.0f; } else if ((src_mask & STEREO) == STEREO) { - spa_log_debug(mix->log, "produce SIDE from STEREO (%f)", slev); + spa_log_info(mix->log, "produce SIDE from STEREO (%f)", slev); _MATRIX(SL,FL) += slev; _MATRIX(SR,FR) += slev; } else if ((src_mask & FRONT) == FRONT && mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { - spa_log_debug(mix->log, "produce SIDE from FC (%f)", clev); + spa_log_info(mix->log, "produce SIDE from FC (%f)", clev); _MATRIX(SL,FC) += clev; _MATRIX(SR,FC) += clev; + } else if (src_mask & _MASK(MONO) && + mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { + spa_log_info(mix->log, "produce SIDE from MONO (%f)", 1.0f); + _MATRIX(SL,MONO) += 1.0f; + _MATRIX(SR,MONO) += 1.0f; } else { - spa_log_debug(mix->log, "won't produce SIDE"); + spa_log_info(mix->log, "won't produce SIDE"); } } if (unassigned & REAR) { if ((src_mask & SIDE) == SIDE) { - spa_log_debug(mix->log, "produce REAR from SIDE (%f)", 1.0f); + spa_log_info(mix->log, "produce REAR from SIDE (%f)", 1.0f); _MATRIX(RL,SL) += 1.0f; _MATRIX(RR,SR) += 1.0f; } else if ((src_mask & STEREO) == STEREO) { - spa_log_debug(mix->log, "produce REAR from STEREO (%f)", slev); + spa_log_info(mix->log, "produce REAR from STEREO (%f)", slev); _MATRIX(RL,FL) += slev; _MATRIX(RR,FR) += slev; } else if ((src_mask & FRONT) == FRONT && mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { - spa_log_debug(mix->log, "produce REAR from FC (%f)", clev); + spa_log_info(mix->log, "produce REAR from FC (%f)", clev); _MATRIX(RL,FC) += clev; _MATRIX(RR,FC) += clev; + } else if (src_mask & _MASK(MONO) && + mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { + spa_log_info(mix->log, "produce REAR from MONO (%f)", 1.0f); + _MATRIX(RL,MONO) += 1.0f; + _MATRIX(RR,MONO) += 1.0f; } else { - spa_log_debug(mix->log, "won't produce SIDE"); + spa_log_info(mix->log, "won't produce SIDE"); } } if (unassigned & _MASK(RC)) { if ((src_mask & REAR) == REAR) { - spa_log_debug(mix->log, "produce RC from REAR (%f)", 0.5f); + spa_log_info(mix->log, "produce RC from REAR (%f)", 0.5f); _MATRIX(RC,RL) += 0.5f; _MATRIX(RC,RR) += 0.5f; } else if ((src_mask & SIDE) == SIDE) { - spa_log_debug(mix->log, "produce RC from SIDE (%f)", 0.5f); + spa_log_info(mix->log, "produce RC from SIDE (%f)", 0.5f); _MATRIX(RC,SL) += 0.5f; _MATRIX(RC,SR) += 0.5f; } else if ((src_mask & STEREO) == STEREO) { - spa_log_debug(mix->log, "produce RC from STEREO (%f)", 0.5f); + spa_log_info(mix->log, "produce RC from STEREO (%f)", 0.5f); _MATRIX(RC,FL) += 0.5f; _MATRIX(RC,FR) += 0.5f; } else if ((src_mask & FRONT) == FRONT && mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { - spa_log_debug(mix->log, "produce RC from FC (%f)", slev); + spa_log_info(mix->log, "produce RC from FC (%f)", slev); _MATRIX(RC,FC) += slev; + } else if (src_mask & _MASK(MONO) && + mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { + spa_log_info(mix->log, "produce RC from MONO (%f)", 1.0f); + _MATRIX(RC,MONO) += 1.0f; } else { - spa_log_debug(mix->log, "won't produce RC"); + spa_log_info(mix->log, "won't produce RC"); } } done: + if (dst_paired == 0) + dst_paired = ~0LU; + if (src_paired == 0) + src_paired = ~0LU; + for (jc = 0, ic = 0, i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) { float sum = 0.0f; char str1024, str21024; int idx = 0, idx2 = 0; - if ((dst_mask & (1UL << i)) == 0) + if ((dst_paired & (1UL << i)) == 0) continue; for (jc = 0, j = 0; j < SPA_AUDIO_MAX_CHANNELS; j++) { - if ((src_mask & (1UL << j)) == 0) + if ((src_paired & (1UL << j)) == 0) continue; if (ic >= dst_chan || jc >= src_chan) continue; if (ic == 0) idx2 += snprintf(str2 + idx2, sizeof(str2) - idx2, "%-4.4s ", - src_mask == ~0LU ? "MONO" : - spa_debug_type_find_short_name(spa_type_audio_channel, j + 3)); + src_mask == 0 ? "UNK" : + spa_debug_type_find_short_name(spa_type_audio_channel, j + _SH)); mix->matrix_origicjc++ = matrixij; sum += fabs(matrixij); @@ -537,8 +676,8 @@ spa_log_info(mix->log, " %s", str2); if (idx > 0) { spa_log_info(mix->log, "%-4.4s %s %f", - dst_mask == ~0LU ? "MONO" : - spa_debug_type_find_short_name(spa_type_audio_channel, i + 3), + dst_mask == 0 ? "UNK" : + spa_debug_type_find_short_name(spa_type_audio_channel, i + _SH), str, sum); } @@ -554,9 +693,8 @@ } ic++; } - if (SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_NORMALIZE) && - maxsum > 1.0f) { - spa_log_debug(mix->log, "normalize %f", maxsum); + if (normalize && maxsum > 1.0f) { + spa_log_info(mix->log, "normalize %f", maxsum); for (i = 0; i < dst_chan; i++) for (j = 0; j < src_chan; j++) mix->matrix_origij /= maxsum;
View file
pipewire-0.3.65.tar.gz/spa/plugins/audioconvert/test-audioconvert.c -> pipewire-0.3.66.tar.gz/spa/plugins/audioconvert/test-audioconvert.c
Changed
@@ -38,6 +38,7 @@ #include <spa/node/node.h> #include <spa/node/io.h> #include <spa/debug/mem.h> +#include <spa/debug/log.h> #include <spa/support/log-impl.h> SPA_LOG_IMPL(logger); @@ -682,8 +683,10 @@ res = memcmp(b->datasj.data, out_data->datak, out_data->size); if (res != 0) { fprintf(stderr, "error port %d plane %d\n", i, j); - spa_debug_mem(0, b->datasj.data, out_data->size); - spa_debug_mem(0, out_data->datak, out_data->size); + spa_debug_log_mem(&logger.log, SPA_LOG_LEVEL_WARN, + 0, b->datasj.data, out_data->size); + spa_debug_log_mem(&logger.log, SPA_LOG_LEVEL_WARN, + 2, out_data->datak, out_data->size); } spa_assert_se(res == 0);
View file
pipewire-0.3.65.tar.gz/spa/plugins/audioconvert/test-channelmix.c -> pipewire-0.3.66.tar.gz/spa/plugins/audioconvert/test-channelmix.c
Changed
@@ -72,6 +72,8 @@ mix.src_mask = src_mask; mix.dst_mask = dst_mask; mix.log = &logger.log; + mix.fc_cutoff = 120.0f; + mix.lfe_cutoff = 12000.0f; spa_assert_se(channelmix_init(&mix) == 0); channelmix_set_volume(&mix, 1.0f, false, 0, NULL); @@ -83,11 +85,17 @@ test_mix(1, _M(MONO), 2, _M(FL)|_M(FR), 0, MATRIX(1.0, 1.0)); test_mix(1, _M(MONO), 3, _M(FL)|_M(FR)|_M(LFE), 0, + MATRIX(1.0, 1.0, 0.0)); + test_mix(1, _M(MONO), 3, _M(FL)|_M(FR)|_M(LFE), CHANNELMIX_OPTION_UPMIX, MATRIX(1.0, 1.0, 1.0)); test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 0, + MATRIX(1.0, 1.0, 0.0, 0.0)); + test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), CHANNELMIX_OPTION_UPMIX, MATRIX(1.0, 1.0, 1.0, 1.0)); test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 0, - MATRIX(1.0, 1.0, 1.0, 1.0)); + MATRIX(1.0, 1.0, 0.0, 0.0)); + test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR), CHANNELMIX_OPTION_UPMIX, + MATRIX(1.0, 1.0, 0.0, 0.0)); test_mix(1, _M(MONO), 12, 0, 0, MATRIX(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)); @@ -119,16 +127,49 @@ test_mix(1, _M(FC), 1, _M(FC), 0, MATRIX(1.0)); test_mix(2, _M(FL)|_M(FR), 1, _M(MONO), 0, - MATRIX(0.707107, 0.707107)); + MATRIX(0.5, 0.5)); test_mix(12, 0, 1, _M(MONO), 0, MATRIX(0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.0833333)); } +static void test_2_N(void) +{ + test_mix(2, _M(FL)|_M(FR), 1, _M(MONO), 0, MATRIX(0.5, 0.5)); + test_mix(2, _M(FL)|_M(FR), 1, 0, 0, MATRIX(0.5, 0.5)); + test_mix(2, _M(FL)|_M(FR), 2, 0, 0, MATRIX(1.0, 0.0, 0.0, 1.0)); + test_mix(2, _M(FL)|_M(FR), 2, _M(MONO), 0, MATRIX(1.0, 0.0, 0.0, 1.0)); + test_mix(2, _M(FL)|_M(FR), 2, _M(FL)|_M(FR), 0, MATRIX(1.0, 0.0, 0.0, 1.0)); + test_mix(2, _M(FL)|_M(FR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 0, + MATRIX(1.0, 0.0, + 0.0, 1.0, + 0.0, 0.0, + 0.0, 0.0)); + test_mix(2, _M(FL)|_M(FR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), CHANNELMIX_OPTION_UPMIX, + MATRIX(1.0, 0.0, + 0.0, 1.0, + 0.707107, 0.707107, + 0.5, 0.5)); + test_mix(2, _M(FL)|_M(FR), 6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 0, + MATRIX(1.0, 0.0, + 0.0, 1.0, + 0.0, 0.0, + 0.0, 0.0, + 0.0, 0.0, + 0.0, 0.0)); + test_mix(2, _M(FL)|_M(FR), 6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), CHANNELMIX_OPTION_UPMIX, + MATRIX(1.0, 0.0, + 0.0, 1.0, + 0.707107, 0.707107, + 0.5, 0.5, + 0.0, 0.0, + 0.0, 0.0)); +} + static void test_3p1_N(void) { test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 1, _M(MONO), 0, - MATRIX(0.707107, 0.707107, 1.0, 0.0)); + MATRIX(0.333333, 0.333333, 0.333333, 0.0)); test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 2, _M(FL)|_M(FR), 0, MATRIX(1.0, 0.0, 0.707107, 0.0, 0.0, 1.0, 0.707107, 0.0 )); @@ -151,9 +192,9 @@ static void test_4_N(void) { test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 1, _M(MONO), 0, - MATRIX(0.707107, 0.707107, 0.5, 0.5)); + MATRIX(0.25, 0.25, 0.25, 0.25)); test_mix(4, _M(FL)|_M(FR)|_M(SL)|_M(SR), 1, _M(MONO), 0, - MATRIX(0.707107, 0.707107, 0.5, 0.5)); + MATRIX(0.25, 0.25, 0.25, 0.25)); test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR), 0, MATRIX(1.0, 0.0, 0.707107, 0.0, 0.0, 1.0, 0.0, 0.707107)); @@ -178,13 +219,13 @@ MATRIX(1.0, 0.0, 0.707107, 0.0, 0.0, 1.0, 0.0, 0.707107, 0.707107, 0.707107, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0)); + 0.5, 0.5, 0.0, 0.0)); } static void test_5p1_N(void) { test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 1, _M(MONO), 0, - MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5)); + MATRIX(0.20, 0.20, 0.20, 0.0, 0.20, 0.20)); test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 2, _M(FL)|_M(FR), 0, MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0, 0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107)); @@ -223,7 +264,7 @@ static void test_6p1_N(void) { test_mix(7, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(RC)|_M(SL)|_M(SR), 1, _M(MONO), 0, - MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5, 0.5)); + MATRIX(0.166667, 0.166667, 0.166667, 0.0, 0.166667, 0.166667, 0.166667)); test_mix(7, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RC), 6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 0, MATRIX(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, @@ -263,7 +304,7 @@ static void test_7p1_N(void) { test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 1, _M(MONO), 0, - MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5, 0.5, 0.5)); + MATRIX(0.142857, 0.142857, 0.142857, 0.0, 0.142857, 0.142857, 0.142857, 0.142857)); test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR), 0, MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0, 0.707107, 0.0, 0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107, 0.0, 0.707107)); @@ -362,6 +403,7 @@ test_1_N_MONO(); test_1_N_FC(); test_N_1(); + test_2_N(); test_3p1_N(); test_4_N(); test_5p1_N();
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.66.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -134,8 +134,6 @@ /* A reference audio info for A2DP codec configuration. */ struct media_codec_audio_info default_audio_info; - - bool le_audio_supported; }; /* Stream endpoints owned by BlueZ for each device */ @@ -1008,6 +1006,52 @@ return 0; } +static int adapter_media_update_props(struct spa_bt_adapter *adapter, + DBusMessageIter *props_iter, + DBusMessageIter *invalidated_iter) +{ + /* Handle org.bluez.Media1 interface properties of .Adapter1 objects */ + struct spa_bt_monitor *monitor = adapter->monitor; + + while (dbus_message_iter_get_arg_type(props_iter) != DBUS_TYPE_INVALID) { + DBusMessageIter it2; + const char *key; + + dbus_message_iter_recurse(props_iter, &it0); + dbus_message_iter_get_basic(&it0, &key); + dbus_message_iter_next(&it0); + dbus_message_iter_recurse(&it0, &it1); + + if (spa_streq(key, "SupportedUUIDs")) { + DBusMessageIter iter; + + if (!check_iter_signature(&it1, "as")) + goto next; + + dbus_message_iter_recurse(&it1, &iter); + + while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) { + const char *uuid; + + dbus_message_iter_get_basic(&iter, &uuid); + + if (spa_streq(uuid, SPA_BT_UUID_BAP_SINK)) { + adapter->le_audio_supported = true; + spa_log_info(monitor->log, "Adapter %s: LE Audio supported", + adapter->path); + } + dbus_message_iter_next(&iter); + } + } + else + spa_log_debug(monitor->log, "media: unhandled key %s", key); + +next: + dbus_message_iter_next(props_iter); + } + return 0; +} + static void adapter_update_devices(struct spa_bt_adapter *adapter) { struct spa_bt_monitor *monitor = adapter->monitor; @@ -1875,6 +1919,8 @@ { struct spa_bt_monitor *monitor = device->monitor; struct spa_bt_remote_endpoint *ep; + enum spa_bt_profile codec_profile; + struct spa_bt_transport *t; const struct { enum spa_bluetooth_audio_codec codec; uint32_t mask; } quirks = { { SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ, SPA_BT_FEATURE_SBC_XQ }, { SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM, SPA_BT_FEATURE_FASTSTREAM }, @@ -1887,10 +1933,13 @@ if (!is_media_codec_enabled(device->monitor, codec)) return false; - if (!device->adapter->application_registered) { + if (!device->adapter->a2dp_application_registered && !codec->bap) { /* Codec switching not supported: only plain SBC allowed */ - return (codec->codec_id == A2DP_CODEC_SBC && spa_streq(codec->name, "sbc")); + return (codec->codec_id == A2DP_CODEC_SBC && spa_streq(codec->name, "sbc") && + device->adapter->legacy_endpoints_registered); } + if (!device->adapter->bap_application_registered && codec->bap) + return false; /* Check codec quirks */ for (i = 0; i < SPA_N_ELEMENTS(quirks); ++i) { @@ -1906,16 +1955,15 @@ return false; } + if (codec->bap) + codec_profile = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE; + else + codec_profile = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE; + spa_list_for_each(ep, &device->remote_endpoint_list, device_link) { const enum spa_bt_profile profile = spa_bt_profile_from_uuid(ep->uuid); - enum spa_bt_profile expected; - if (codec->bap) - expected = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE; - else - expected = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE; - - if (profile != expected) + if (profile != codec_profile) continue; if (media_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len, @@ -1923,6 +1971,21 @@ return true; } + /* Codecs on configured transports are always supported. + * + * Remote BAP endpoints correspond to capabilities of the remote + * BAP Server, not to remote BAP Client, and need not be the same. + * BAP Clients may not have any remote endpoints. In this case we + * can only know that the currently configured codec is supported. + */ + spa_list_for_each(t, &device->transport_list, device_link) { + if (t->profile != codec_profile) + continue; + + if (codec == t->media_codec) + return true; + } + return false; } @@ -3355,7 +3418,8 @@ const struct media_codec *preferred_codec = NULL; size_t i, j, num_codecs, num_eps; - if (!device->adapter->application_registered) { + if (!device->adapter->a2dp_application_registered && + !device->adapter->bap_application_registered) { /* Codec switching not supported */ return -ENOTSUP; } @@ -3690,9 +3754,10 @@ return res; } -static void bluez_register_endpoint_reply(DBusPendingCall *pending, void *user_data) +static void bluez_register_endpoint_legacy_reply(DBusPendingCall *pending, void *user_data) { - struct spa_bt_monitor *monitor = user_data; + struct spa_bt_adapter *adapter = user_data; + struct spa_bt_monitor *monitor = adapter->monitor; DBusMessage *r; r = dbus_pending_call_steal_reply(pending); @@ -3711,6 +3776,8 @@ goto finish; } + adapter->legacy_endpoints_registered = true; + finish: dbus_message_unref(r); } @@ -3739,10 +3806,12 @@ dbus_message_iter_close_container(dict, &dict_entry_it); } -static int bluez_register_endpoint(struct spa_bt_monitor *monitor, - const char *path, enum spa_bt_media_direction direction, +static int bluez_register_endpoint_legacy(struct spa_bt_adapter *adapter, + enum spa_bt_media_direction direction, const char *uuid, const struct media_codec *codec) { + struct spa_bt_monitor *monitor = adapter->monitor; + const char *path = adapter->path; char *object_path = NULL; DBusMessage *m; DBusMessageIter object_it, dict_it; @@ -3783,7 +3852,7 @@ dbus_message_iter_close_container(&object_it, &dict_it); dbus_connection_send_with_reply(monitor->conn, m, &call, -1); - dbus_pending_call_set_notify(call, bluez_register_endpoint_reply, monitor, NULL); + dbus_pending_call_set_notify(call, bluez_register_endpoint_legacy_reply, adapter, NULL); dbus_message_unref(m); free(object_path); @@ -3795,14 +3864,15 @@ return ret; } -static int adapter_register_endpoints(struct spa_bt_adapter *a) +static int adapter_register_endpoints_legacy(struct spa_bt_adapter *a) { struct spa_bt_monitor *monitor = a->monitor; const struct media_codec * const * const media_codecs = monitor->media_codecs; int i; int err = 0; + bool registered = false; - if (a->endpoints_registered) + if (a->legacy_endpoints_registered) return err; /* The legacy bluez5 api doesn't support codec switching @@ -3813,9 +3883,7 @@ * */ spa_log_warn(monitor->log, "Using legacy bluez5 API for A2DP - only SBC will be supported. " - "No LE Audio. Please upgrade bluez5."); - - monitor->le_audio_supported = false; + "Please upgrade bluez5."); for (i = 0; media_codecsi; i++) { const struct media_codec *codec = media_codecsi; @@ -3824,26 +3892,24 @@ continue; if (endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SOURCE)) { - if ((err = bluez_register_endpoint(monitor, a->path, - SPA_BT_MEDIA_SOURCE, + if ((err = bluez_register_endpoint_legacy(a, SPA_BT_MEDIA_SOURCE, SPA_BT_UUID_A2DP_SOURCE, codec))) goto out; } if (endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SINK)) { - if ((err = bluez_register_endpoint(monitor, a->path, - SPA_BT_MEDIA_SINK, + if ((err = bluez_register_endpoint_legacy(a, SPA_BT_MEDIA_SINK, SPA_BT_UUID_A2DP_SINK, codec))) goto out; } - a->endpoints_registered = true; + registered = true; break; } - if (!a->endpoints_registered) { + if (!registered) { /* Should never happen as SBC support is always enabled */ spa_log_error(monitor->log, "Broken PipeWire build - unable to locate SBC codec"); err = -ENOSYS; @@ -3887,7 +3953,7 @@ dbus_message_iter_close_container(iter, &object); } -static DBusHandlerResult object_manager_handler(DBusConnection *c, DBusMessage *m, void *user_data) +static DBusHandlerResult object_manager_handler(DBusConnection *c, DBusMessage *m, void *user_data, bool is_bap) { struct spa_bt_monitor *monitor = user_data; const struct media_codec * const * const media_codecs = monitor->media_codecs; @@ -3930,20 +3996,11 @@ int caps_size, ret; uint16_t codec_id = codec->codec_id; - if (!is_media_codec_enabled(monitor, codec)) + if (codec->bap != is_bap) continue; - if (codec->bap && !monitor->le_audio_supported) { - /* The legacy bluez5 api doesn't support LE Audio - * It doesn't make sense to register unsupported codecs as it prevents - * registration of A2DP codecs - * let's incentivize users to upgrade their bluez5 daemon - * if they want proper media codec support - * */ - spa_log_warn(monitor->log, "Trying to use legacy bluez5 API for LE Audio - only A2DP will be supported. " - "Please upgrade bluez5."); + if (!is_media_codec_enabled(monitor, codec)) continue; - } if (endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SINK)) { caps_size = codec->fill_caps(codec, MEDIA_CODEC_FLAG_SINK, caps); @@ -3987,7 +4044,17 @@ return res; } -static void bluez_register_application_reply(DBusPendingCall *pending, void *user_data) +static DBusHandlerResult object_manager_handler_a2dp(DBusConnection *c, DBusMessage *m, void *user_data) +{ + return object_manager_handler(c, m, user_data, false); +} + +static DBusHandlerResult object_manager_handler_bap(DBusConnection *c, DBusMessage *m, void *user_data) +{ + return object_manager_handler(c, m, user_data, true); +} + +static void bluez_register_application_a2dp_reply(DBusPendingCall *pending, void *user_data) { struct spa_bt_adapter *adapter = user_data; struct spa_bt_monitor *monitor = adapter->monitor; @@ -4012,13 +4079,37 @@ } fallback = false; - adapter->application_registered = true; + adapter->a2dp_application_registered = true; finish: dbus_message_unref(r); if (fallback) - adapter_register_endpoints(adapter); + adapter_register_endpoints_legacy(adapter); +} + +static void bluez_register_application_bap_reply(DBusPendingCall *pending, void *user_data) +{ + struct spa_bt_adapter *adapter = user_data; + struct spa_bt_monitor *monitor = adapter->monitor; + DBusMessage *r; + + r = dbus_pending_call_steal_reply(pending); + dbus_pending_call_unref(pending); + + if (r == NULL) + return; + + if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { + spa_log_error(monitor->log, "RegisterApplication() failed: %s", + dbus_message_get_error_name(r)); + goto finish; + } + + adapter->bap_application_registered = true; + +finish: + dbus_message_unref(r); } static int register_media_endpoint(struct spa_bt_monitor *monitor, @@ -4037,7 +4128,7 @@ if (ret < 0) return ret; - spa_log_info(monitor->log, "registering endpoint: %s", object_path); + spa_log_info(monitor->log, "Registering DBus media endpoint: %s", object_path); if (!dbus_connection_register_object_path(monitor->conn, object_path, @@ -4053,15 +4144,27 @@ static int register_media_application(struct spa_bt_monitor * monitor) { const struct media_codec * const * const media_codecs = monitor->media_codecs; - const DBusObjectPathVTable vtable_object_manager = { - .message_function = object_manager_handler, + const DBusObjectPathVTable vtable_object_manager_a2dp = { + .message_function = object_manager_handler_a2dp, }; + const DBusObjectPathVTable vtable_object_manager_bap = { + .message_function = object_manager_handler_bap, + }; + + spa_log_info(monitor->log, "Registering DBus media object manager: %s", + A2DP_OBJECT_MANAGER_PATH); - spa_log_info(monitor->log, "Registering media application object: " MEDIA_OBJECT_MANAGER_PATH); + if (!dbus_connection_register_object_path(monitor->conn, + A2DP_OBJECT_MANAGER_PATH, + &vtable_object_manager_a2dp, monitor)) + return -EIO; + + spa_log_info(monitor->log, "Registering DBus media object manager: %s", + BAP_OBJECT_MANAGER_PATH); if (!dbus_connection_register_object_path(monitor->conn, - MEDIA_OBJECT_MANAGER_PATH, - &vtable_object_manager, monitor)) + BAP_OBJECT_MANAGER_PATH, + &vtable_object_manager_bap, monitor)) return -EIO; for (int i = 0; media_codecsi; i++) { @@ -4105,20 +4208,31 @@ unregister_media_endpoint(monitor, codec, SPA_BT_MEDIA_SINK); } - dbus_connection_unregister_object_path(monitor->conn, MEDIA_OBJECT_MANAGER_PATH); + dbus_connection_unregister_object_path(monitor->conn, BAP_OBJECT_MANAGER_PATH); + dbus_connection_unregister_object_path(monitor->conn, A2DP_OBJECT_MANAGER_PATH); } -static int adapter_register_application(struct spa_bt_adapter *a) { - const char *object_manager_path = MEDIA_OBJECT_MANAGER_PATH; +static int adapter_register_application(struct spa_bt_adapter *a, bool bap) +{ + const char *object_manager_path = bap ? BAP_OBJECT_MANAGER_PATH : A2DP_OBJECT_MANAGER_PATH; struct spa_bt_monitor *monitor = a->monitor; DBusMessage *m; DBusMessageIter i, d; DBusPendingCall *call; - if (a->application_registered) + if (bap && a->bap_application_registered) + return 0; + if (!bap && a->a2dp_application_registered) return 0; - spa_log_debug(monitor->log, "Registering bluez5 media application on adapter %s", a->path); + if (bap && !a->le_audio_supported) { + spa_log_info(monitor->log, "Adapter %s indicates LE Audio unsupported: not registering application", + a->path); + return -ENOTSUP; + } + + spa_log_debug(monitor->log, "Registering bluez5 %s media application on adapter %s", + (bap ? "LE Audio" : "A2DP"), a->path); m = dbus_message_new_method_call(BLUEZ_SERVICE, a->path, @@ -4133,7 +4247,9 @@ dbus_message_iter_close_container(&i, &d); dbus_connection_send_with_reply(monitor->conn, m, &call, -1); - dbus_pending_call_set_notify(call, bluez_register_application_reply, a, NULL); + dbus_pending_call_set_notify(call, + bap ? bluez_register_application_bap_reply : bluez_register_application_a2dp_reply, + a, NULL); dbus_message_unref(m); return 0; @@ -4205,48 +4321,6 @@ backend ? backend->name : "none"); } -static int media_update_props(struct spa_bt_monitor *monitor, - DBusMessageIter *props_iter, - DBusMessageIter *invalidated_iter) -{ - while (dbus_message_iter_get_arg_type(props_iter) != DBUS_TYPE_INVALID) { - DBusMessageIter it2; - const char *key; - - dbus_message_iter_recurse(props_iter, &it0); - dbus_message_iter_get_basic(&it0, &key); - dbus_message_iter_next(&it0); - dbus_message_iter_recurse(&it0, &it1); - - if (spa_streq(key, "SupportedUUIDs")) { - DBusMessageIter iter; - - if (!check_iter_signature(&it1, "as")) - goto next; - - dbus_message_iter_recurse(&it1, &iter); - - while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) { - const char *uuid; - - dbus_message_iter_get_basic(&iter, &uuid); - - if (spa_streq(uuid, SPA_BT_UUID_BAP_SINK)) { - monitor->le_audio_supported = true; - spa_log_info(monitor->log, "LE Audio supported"); - } - dbus_message_iter_next(&iter); - } - } - else - spa_log_debug(monitor->log, "media: unhandled key %s", key); - -next: - dbus_message_iter_next(props_iter); - } - return 0; -} - static void interface_added(struct spa_bt_monitor *monitor, DBusConnection *conn, const char *object_path, @@ -4255,7 +4329,8 @@ { spa_log_debug(monitor->log, "Found object %s, interface %s", object_path, interface_name); - if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE)) { + if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE) || + spa_streq(interface_name, BLUEZ_MEDIA_INTERFACE)) { struct spa_bt_adapter *a; a = adapter_find(monitor, object_path); @@ -4266,10 +4341,21 @@ return; } } - adapter_update_props(a, props_iter, NULL); - adapter_register_application(a); - adapter_register_player(a); - adapter_update_devices(a); + + if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE)) { + adapter_update_props(a, props_iter, NULL); + a->has_adapter1_interface = true; + } else { + adapter_media_update_props(a, props_iter, NULL); + a->has_media1_interface = true; + } + + if (a->has_adapter1_interface && a->has_media1_interface) { + adapter_register_application(a, false); + adapter_register_application(a, true); + adapter_register_player(a); + adapter_update_devices(a); + } } else if (spa_streq(interface_name, BLUEZ_PROFILE_MANAGER_INTERFACE)) { if (monitor->backendsBACKEND_NATIVE) @@ -4320,9 +4406,6 @@ if (d) spa_bt_device_emit_profiles_changed(d, d->profiles, d->connected_profiles); } - else if (spa_streq(interface_name, BLUEZ_MEDIA_INTERFACE)) { - media_update_props(monitor, props_iter, NULL); - } } static void interfaces_added(struct spa_bt_monitor *monitor, DBusMessageIter *arg_iter) @@ -4371,7 +4454,8 @@ d = spa_bt_device_find(monitor, object_path); if (d != NULL) device_free(d); - } else if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE)) { + } else if (spa_streq(interface_name, BLUEZ_ADAPTER_INTERFACE) || + spa_streq(interface_name, BLUEZ_MEDIA_INTERFACE)) { struct spa_bt_adapter *a; a = adapter_find(monitor, object_path); if (a != NULL) @@ -4575,7 +4659,8 @@ dbus_message_iter_next(&it0); dbus_message_iter_recurse(&it0, &it1); - if (spa_streq(iface, BLUEZ_ADAPTER_INTERFACE)) { + if (spa_streq(iface, BLUEZ_ADAPTER_INTERFACE) || + spa_streq(iface, BLUEZ_MEDIA_INTERFACE)) { struct spa_bt_adapter *a; a = adapter_find(monitor, path); @@ -4586,7 +4671,10 @@ } spa_log_debug(monitor->log, "Properties changed in adapter %s", path); - adapter_update_props(a, &it1, NULL); + if (spa_streq(iface, BLUEZ_ADAPTER_INTERFACE)) + adapter_update_props(a, &it1, NULL); + else + adapter_media_update_props(a, &it1, NULL); } else if (spa_streq(iface, BLUEZ_DEVICE_INTERFACE)) { struct spa_bt_device *d; @@ -4691,6 +4779,10 @@ dbus_bus_add_match(this->conn, "type='signal',sender='" BLUEZ_SERVICE "'," "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'," + "arg0='" BLUEZ_MEDIA_INTERFACE "'", &err); + dbus_bus_add_match(this->conn, + "type='signal',sender='" BLUEZ_SERVICE "'," + "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'," "arg0='" BLUEZ_DEVICE_INTERFACE "'", &err); dbus_bus_add_match(this->conn, "type='signal',sender='" BLUEZ_SERVICE "',"
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.66.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
@@ -204,6 +204,33 @@ return media_codec; } +static bool is_bap_client(struct impl *this) +{ + struct spa_bt_device *device = this->bt_dev; + struct spa_bt_transport *t; + + spa_list_for_each(t, &device->transport_list, device_link) { + if (t->bap_initiator) + return true; + } + + return false; +} + +static bool can_bap_codec_switch(struct impl *this) +{ + if (!is_bap_client(this)) + return false; + + /* XXX: codec switching for source/duplex is not currently + * XXX: implemented properly. TODO: fix this + */ + if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_BAP_SOURCE) + return false; + + return true; +} + static unsigned int get_hfp_codec(enum spa_bluetooth_audio_codec id) { switch (id) { @@ -873,9 +900,15 @@ * A2DP/BAP: ensure there's a transport with the selected codec (0 means any). * Don't try to switch codecs when the device is in the A2DP source role, since * devices do not appear to like that. + * + * For BAP, only BAP client can configure the codec. + * + * XXX: codec switching also currently does not work in the duplex or + * XXX: source-only case, as it will only switch the sink, and we only + * XXX: list the sink codecs here. TODO: fix this */ - if ((profile == DEVICE_PROFILE_A2DP || profile == DEVICE_PROFILE_BAP) - && !(this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE)) { + if ((profile == DEVICE_PROFILE_A2DP || (profile == DEVICE_PROFILE_BAP && can_bap_codec_switch(this))) + && !(this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE)) { int ret; const struct media_codec *codecs64; @@ -1332,11 +1365,6 @@ if (profile == 0) return NULL; - if (!codec) { - errno = EINVAL; - return NULL; - } - if (profile & (SPA_BT_PROFILE_BAP_SINK)) n_sink++; if (profile & (SPA_BT_PROFILE_BAP_SOURCE)) @@ -1344,28 +1372,51 @@ name = spa_bt_profile_name(profile); - media_codec = get_supported_media_codec(this, codec, &idx); - if (media_codec == NULL) { - errno = EINVAL; + /* If we can't codec switch, emit codecless profile */ + if (current && !can_bap_codec_switch(this)) { + codec = 0; + index = get_index_from_profile(this, profile_index, codec); + } else if ((codec != 0) != can_bap_codec_switch(this)) { + errno = -EINVAL; return NULL; } - name_and_codec = spa_aprintf("%s-%s", name, media_codec->name); - name = name_and_codec; - switch (profile) { - case SPA_BT_PROFILE_BAP_SINK: - desc_and_codec = spa_aprintf(_("High Fidelity Playback (BAP Sink, codec %s)"), - media_codec->description); - break; - case SPA_BT_PROFILE_BAP_SOURCE: - desc_and_codec = spa_aprintf(_("High Fidelity Input (BAP Source, codec %s)"), - media_codec->description); - break; - default: - desc_and_codec = spa_aprintf(_("High Fidelity Duplex (BAP Source/Sink, codec %s)"), - media_codec->description); + + if (codec) { + media_codec = get_supported_media_codec(this, codec, &idx); + if (media_codec == NULL) { + errno = EINVAL; + return NULL; + } + name_and_codec = spa_aprintf("%s-%s", name, media_codec->name); + name = name_and_codec; + switch (profile) { + case SPA_BT_PROFILE_BAP_SINK: + desc_and_codec = spa_aprintf(_("High Fidelity Playback (BAP Sink, codec %s)"), + media_codec->description); + break; + case SPA_BT_PROFILE_BAP_SOURCE: + desc_and_codec = spa_aprintf(_("High Fidelity Input (BAP Source, codec %s)"), + media_codec->description); + break; + default: + desc_and_codec = spa_aprintf(_("High Fidelity Duplex (BAP Source/Sink, codec %s)"), + media_codec->description); + } + desc = desc_and_codec; + priority = 128 + this->supported_codec_count - idx; /* order as in codec list */ + } else { + switch (profile) { + case SPA_BT_PROFILE_BAP_SINK: + desc = _("High Fidelity Playback (BAP Sink)"); + break; + case SPA_BT_PROFILE_BAP_SOURCE: + desc = _("High Fidelity Input (BAP Source)"); + break; + default: + desc = _("High Fidelity Duplex (BAP Source/Sink)"); + } + priority = 128; } - desc = desc_and_codec; - priority = 128 + this->supported_codec_count - idx; /* order as in codec list */ break; } case DEVICE_PROFILE_HSP_HFP:
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.66.tar.gz/spa/plugins/bluez5/defs.h
Changed
@@ -161,12 +161,13 @@ #define HFP_AUDIO_CODEC_CVSD 0x01 #define HFP_AUDIO_CODEC_MSBC 0x02 -#define MEDIA_OBJECT_MANAGER_PATH "/MediaEndpoint" -#define A2DP_SINK_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/A2DPSink" -#define A2DP_SOURCE_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/A2DPSource" +#define A2DP_OBJECT_MANAGER_PATH "/MediaEndpoint" +#define A2DP_SINK_ENDPOINT A2DP_OBJECT_MANAGER_PATH "/A2DPSink" +#define A2DP_SOURCE_ENDPOINT A2DP_OBJECT_MANAGER_PATH "/A2DPSource" -#define BAP_SINK_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/BAPSink" -#define BAP_SOURCE_ENDPOINT MEDIA_OBJECT_MANAGER_PATH "/BAPSource" +#define BAP_OBJECT_MANAGER_PATH "/MediaEndpointLE" +#define BAP_SINK_ENDPOINT BAP_OBJECT_MANAGER_PATH "/BAPSink" +#define BAP_SOURCE_ENDPOINT BAP_OBJECT_MANAGER_PATH "/BAPSource" #define SPA_BT_UNKNOWN_DELAY 0 @@ -358,11 +359,15 @@ int powered; unsigned int has_msbc:1; unsigned int msbc_probed:1; - unsigned int endpoints_registered:1; - unsigned int application_registered:1; + unsigned int legacy_endpoints_registered:1; + unsigned int a2dp_application_registered:1; + unsigned int bap_application_registered:1; unsigned int player_registered:1; unsigned int has_battery_provider:1; unsigned int battery_provider_unavailable:1; + unsigned int le_audio_supported:1; + unsigned int has_adapter1_interface:1; + unsigned int has_media1_interface:1; }; enum spa_bt_form_factor {
View file
pipewire-0.3.65.tar.gz/spa/plugins/bluez5/meson.build -> pipewire-0.3.66.tar.gz/spa/plugins/bluez5/meson.build
Changed
@@ -1,12 +1,5 @@ gnome = import('gnome') -bluez5_deps = mathlib, dbus_dep, glib2_dep, sbc_dep, bluez_dep, gio_dep, gio_unix_dep -foreach dep: bluez5_deps - if not dep.found() - subdir_done() - endif -endforeach - cdata.set('HAVE_BLUEZ_5_BACKEND_NATIVE', get_option('bluez5-backend-hsp-native').allowed() or get_option('bluez5-backend-hfp-native').allowed())
View file
pipewire-0.3.65.tar.gz/spa/plugins/libcamera/libcamera-utils.cpp -> pipewire-0.3.66.tar.gz/spa/plugins/libcamera/libcamera-utils.cpp
Changed
@@ -35,6 +35,7 @@ #include <limits.h> #include <linux/media.h> +#include <libcamera/control_ids.h> int spa_libcamera_open(struct impl *impl) { @@ -458,6 +459,38 @@ } +static struct { + uint32_t id; + uint32_t spa_id; +} control_map = { + { libcamera::controls::BRIGHTNESS, SPA_PROP_brightness }, + { libcamera::controls::CONTRAST, SPA_PROP_contrast }, + { libcamera::controls::SATURATION, SPA_PROP_saturation }, + { libcamera::controls::EXPOSURE_TIME, SPA_PROP_exposure }, + { libcamera::controls::ANALOGUE_GAIN, SPA_PROP_gain }, + { libcamera::controls::SHARPNESS, SPA_PROP_sharpness }, +}; + +static uint32_t control_to_prop_id(struct impl *impl, uint32_t control_id) +{ + SPA_FOR_EACH_ELEMENT_VAR(control_map, c) { + if (c->id == control_id) + return c->spa_id; + } + return SPA_PROP_START_CUSTOM + control_id; +} + +static uint32_t prop_id_to_control(struct impl *impl, uint32_t prop_id) +{ + SPA_FOR_EACH_ELEMENT_VAR(control_map, c) { + if (c->spa_id == prop_id) + return c->id; + } + if (prop_id >= SPA_PROP_START_CUSTOM) + return prop_id - SPA_PROP_START_CUSTOM; + return SPA_ID_INVALID; +} + static int spa_libcamera_enum_controls(struct impl *impl, struct port *port, int seq, uint32_t start, uint32_t num, @@ -469,7 +502,7 @@ struct spa_pod_frame f2; struct spa_result_node_params result; struct spa_pod *ctrl; - uint32_t count = 0, skip; + uint32_t count = 0, skip, id; int res; const ControlId *ctrl_id; ControlInfo ctrl_info; @@ -492,10 +525,12 @@ ctrl_id = it->first; ctrl_info = it->second; + id = control_to_prop_id(impl, ctrl_id->id()); + spa_pod_builder_init(&b, buffer, sizeof(buffer)); spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo); spa_pod_builder_add(&b, - SPA_PROP_INFO_id, SPA_POD_Id(ctrl_id->id()), + SPA_PROP_INFO_id, SPA_POD_Id(id), SPA_PROP_INFO_description, SPA_POD_String(ctrl_id->name().c_str()), 0); @@ -601,8 +636,13 @@ const ControlId *ctrl_id; int res; struct val d; + uint32_t control_id; + + control_id = prop_id_to_control(impl, prop->key); + if (control_id == SPA_ID_INVALID) + return -ENOENT; - auto v = info.idmap().find(prop->key); + auto v = info.idmap().find(control_id); if (v == info.idmap().end()) return -ENOENT;
View file
pipewire-0.3.65.tar.gz/spa/plugins/libcamera/meson.build -> pipewire-0.3.66.tar.gz/spa/plugins/libcamera/meson.build
Changed
@@ -5,13 +5,8 @@ 'libcamera-source.cpp' -libdrm_dep = dependency('libdrm', version : '>= 2.4.98', - required : get_option('libcamera')) -summary({'libdrm': libdrm_dep.found()}, bool_yn: true, section: 'Backend') -if libdrm_dep.found() - libcameralib = shared_library('spa-libcamera', - libcamera_sources, - dependencies : spa_dep, libudev_dep, libcamera_dep, pthread_lib, libdrm_dep , - install : true, - install_dir : spa_plugindir / 'libcamera') -endif +libcameralib = shared_library('spa-libcamera', + libcamera_sources, + dependencies : spa_dep, libudev_dep, libcamera_dep, pthread_lib , + install : true, + install_dir : spa_plugindir / 'libcamera')
View file
pipewire-0.3.65.tar.gz/spa/plugins/support/journal.c -> pipewire-0.3.66.tar.gz/spa/plugins/support/journal.c
Changed
@@ -22,6 +22,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include "config.h" + #include <stddef.h> #include <unistd.h> #include <string.h> @@ -114,6 +116,9 @@ sd_journal_send_with_location(file_buffer, line_buffer, func, "MESSAGE=%s", message_buffer, "PRIORITY=%i", priority, +#ifdef HAVE_GETTID + "TID=%jd", (intmax_t) gettid(), +#endif NULL); }
View file
pipewire-0.3.65.tar.gz/spa/plugins/support/meson.build -> pipewire-0.3.66.tar.gz/spa/plugins/support/meson.build
Changed
@@ -18,7 +18,7 @@ spa_support_lib = shared_library('spa-support', spa_support_sources, c_args : simd_cargs , - dependencies : spa_dep, pthread_lib, epoll_shim_dep , + dependencies : spa_dep, pthread_lib, epoll_shim_dep, mathlib , install : true, install_dir : spa_plugindir / 'support') spa_support_dep = declare_dependency(link_with: spa_support_lib) @@ -61,6 +61,7 @@ spa_journal_lib = shared_library('spa-journal', spa_journal_sources, + include_directories : configinc , dependencies : spa_dep, systemd_dep , install : true, install_dir : spa_plugindir / 'support')
View file
pipewire-0.3.65.tar.gz/spa/plugins/support/node-driver.c -> pipewire-0.3.66.tar.gz/spa/plugins/support/node-driver.c
Changed
@@ -27,6 +27,7 @@ #include <unistd.h> #include <string.h> #include <stdio.h> +#include <fcntl.h> #include <spa/support/plugin.h> #include <spa/support/log.h> @@ -34,6 +35,7 @@ #include <spa/utils/names.h> #include <spa/utils/result.h> #include <spa/utils/string.h> +#include <spa/utils/dll.h> #include <spa/node/node.h> #include <spa/node/keys.h> #include <spa/node/io.h> @@ -43,11 +45,20 @@ #define NAME "driver" #define DEFAULT_FREEWHEEL false -#define DEFAULT_CLOCK_NAME "clock.system.monotonic" +#define DEFAULT_CLOCK_PREFIX "clock.system" +#define DEFAULT_CLOCK_ID CLOCK_MONOTONIC + +#define CLOCKFD 3 +#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) +#define CLOCKID_TO_FD(clk) ((unsigned int) ~((clk) >> 3)) + +#define BW_PERIOD (3 * SPA_NSEC_PER_SEC) +#define MAX_ERROR_MS 1 struct props { bool freewheel; char clock_name64; + clockid_t clock_id; }; struct impl { @@ -72,19 +83,62 @@ struct spa_source timer_source; struct itimerspec timerspec; + int clock_fd; bool started; bool following; + bool tracking; + clockid_t timer_clockid; uint64_t next_time; + uint64_t last_time; + uint64_t base_time; + struct spa_dll dll; + double max_error; }; static void reset_props(struct props *props) { props->freewheel = DEFAULT_FREEWHEEL; - spa_scnprintf(props->clock_name, sizeof(props->clock_name), - "%s", DEFAULT_CLOCK_NAME); + spa_zero(props->clock_name); + props->clock_id = CLOCK_MONOTONIC; } +static const struct clock_info { + const char *name; + clockid_t id; +} clock_info = { + { "realtime", CLOCK_REALTIME }, + { "tai", CLOCK_TAI }, + { "monotonic", CLOCK_MONOTONIC }, + { "monotonic-raw", CLOCK_MONOTONIC_RAW }, + { "boottime", CLOCK_BOOTTIME }, +}; + +static bool clock_for_timerfd(clockid_t id) +{ + return id == CLOCK_REALTIME || + id == CLOCK_MONOTONIC || + id == CLOCK_BOOTTIME; +} + +static clockid_t clock_name_to_id(const char *name) +{ + SPA_FOR_EACH_ELEMENT_VAR(clock_info, i) { + if (spa_streq(i->name, name)) + return i->id; + } + return -1; +} +static const char *clock_id_to_name(clockid_t id) +{ + SPA_FOR_EACH_ELEMENT_VAR(clock_info, i) { + if (i->id == id) + return i->name; + } + return "custom"; +} + + static void set_timeout(struct impl *this, uint64_t next_time) { spa_log_trace(this->log, "set timeout %"PRIu64, next_time); @@ -94,14 +148,22 @@ this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &this->timerspec, NULL); } +static inline uint64_t gettime_nsec(struct impl *this, clockid_t clock_id) +{ + struct timespec now = { 0 }; + uint64_t nsec; + if (spa_system_clock_gettime(this->data_system, clock_id, &now) < 0) + return 0; + nsec = SPA_TIMESPEC_TO_NSEC(&now); + spa_log_trace(this->log, "%p now:%"PRIu64, this, nsec); + return nsec; +} + static int set_timers(struct impl *this) { - struct timespec now; - int res; + this->next_time = gettime_nsec(this, this->timer_clockid); - if ((res = spa_system_clock_gettime(this->data_system, CLOCK_MONOTONIC, &now)) < 0) - return res; - this->next_time = SPA_TIMESPEC_TO_NSEC(&now); + spa_log_debug(this->log, "%p now:%"PRIu64, this, this->next_time); if (this->following) { set_timeout(this, 0); @@ -176,15 +238,23 @@ return 0; } +static inline uint64_t scale_u64(uint64_t val, uint32_t num, uint32_t denom) +{ +#if 0 + return ((__uint128_t)val * num) / denom; +#else + return (double)val / denom * num; +#endif +} + static void on_timeout(struct spa_source *source) { struct impl *this = source->data; - uint64_t expirations, nsec, duration; + uint64_t expirations, nsec, duration, current_time, current_position, position; uint32_t rate; + double corr = 1.0, err = 0.0; int res; - spa_log_trace(this->log, "timeout"); - if ((res = spa_system_timerfd_read(this->data_system, this->timer_source.fd, &expirations)) < 0) { if (res != EAGAIN) @@ -192,9 +262,6 @@ this, spa_strerror(res)); return; } - - nsec = this->next_time; - if (SPA_LIKELY(this->position)) { duration = this->position->clock.duration; rate = this->position->clock.rate.denom; @@ -202,15 +269,61 @@ duration = 1024; rate = 48000; } + nsec = this->next_time; + + if (this->tracking) + /* we are actually following another clock */ + current_time = gettime_nsec(this, this->props.clock_id); + else + current_time = nsec; + + current_position = scale_u64(current_time, rate, SPA_NSEC_PER_SEC); + + if (SPA_LIKELY(this->clock)) + position = this->clock->position; + else + position = current_position; + + if (this->last_time == 0) { + spa_dll_set_bw(&this->dll, SPA_DLL_BW_MIN, duration, rate); + this->max_error = rate * MAX_ERROR_MS / 1000; + position = current_position; + } - this->next_time = nsec + duration * SPA_NSEC_PER_SEC / rate; + /* check the elapsed time of the other clock against + * the graph clock elapsed time, feed this error into the + * dll and adjust the timeout of our MONOTONIC clock. */ + err = (double)position - (double)current_position; + if (err > this->max_error) + err = this->max_error; + else if (err < -this->max_error) + err = -this->max_error; + + position += duration; + this->last_time = current_time; + + if (this->tracking) { + corr = spa_dll_update(&this->dll, err); + this->next_time = nsec + duration / corr * 1e9 / rate; + } else { + corr = 1.0; + this->next_time = scale_u64(position, SPA_NSEC_PER_SEC, rate); + } + + if (SPA_UNLIKELY((this->next_time - this->base_time) > BW_PERIOD)) { + this->base_time = this->next_time; + spa_log_debug(this->log, "%p: rate:%f " + "bw:%f dur:%"PRIu64" max:%f drift:%f", + this, corr, this->dll.bw, duration, + this->max_error, err); + } if (SPA_LIKELY(this->clock)) { this->clock->nsec = nsec; - this->clock->position += duration; + this->clock->position = position; this->clock->duration = duration; this->clock->delay = 0; - this->clock->rate_diff = 1.0; + this->clock->rate_diff = corr; this->clock->next_nsec = this->next_time; } @@ -228,6 +341,7 @@ this->following = is_following(this); set_timers(this); this->started = true; + this->last_time = 0; return 0; } @@ -262,17 +376,19 @@ return 0; } -static const struct spa_dict_item node_info_items = { - { SPA_KEY_NODE_DRIVER, "true" }, -}; - static void emit_node_info(struct impl *this, bool full) { uint64_t old = full ? this->info.change_mask : 0; if (full) this->info.change_mask = this->info_all; if (this->info.change_mask) { - this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items); + struct spa_dict_item items3; + + items0 = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true"); + items1 = SPA_DICT_ITEM_INIT("clock.id", clock_id_to_name(this->props.clock_id)); + items2 = SPA_DICT_ITEM_INIT("clock.name", this->props.clock_name); + + this->info.props = &SPA_DICT_INIT(items, 3); spa_node_emit_info(&this->hooks, &this->info); this->info.change_mask = old; } @@ -314,14 +430,12 @@ static int impl_node_process(void *object) { struct impl *this = object; - struct timespec now; spa_return_val_if_fail(this != NULL, -EINVAL); spa_log_trace(this->log, "process %d", this->props.freewheel); if (this->props.freewheel) { - clock_gettime(CLOCK_MONOTONIC, &now); - this->next_time = SPA_TIMESPEC_TO_NSEC(&now); + this->next_time = gettime_nsec(this, this->timer_clockid); set_timeout(this, this->next_time); } return SPA_STATUS_HAVE_DATA | SPA_STATUS_NEED_DATA; @@ -371,6 +485,9 @@ spa_loop_invoke(this->data_loop, do_remove_timer, 0, NULL, 0, true, this); spa_system_close(this->data_system, this->timer_source.fd); + if (this->clock_fd != -1) + close(this->clock_fd); + return 0; } @@ -402,6 +519,8 @@ this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); this->data_system = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataSystem); + this->clock_fd = -1; + spa_dll_init(&this->dll); if (this->data_loop == NULL) { spa_log_error(this->log, "a data_loop is needed"); @@ -430,17 +549,6 @@ this->info.params = this->params; this->info.n_params = 0; - this->timer_source.func = on_timeout; - this->timer_source.data = this; - this->timer_source.fd = spa_system_timerfd_create(this->data_system, CLOCK_MONOTONIC, - SPA_FD_CLOEXEC | SPA_FD_NONBLOCK); - this->timer_source.mask = SPA_IO_IN; - this->timer_source.rmask = 0; - this->timerspec.it_value.tv_sec = 0; - this->timerspec.it_value.tv_nsec = 0; - this->timerspec.it_interval.tv_sec = 0; - this->timerspec.it_interval.tv_nsec = 0; - reset_props(&this->props); for (i = 0; info && i < info->n_items; i++) { @@ -451,8 +559,43 @@ } else if (spa_streq(k, "clock.name")) { spa_scnprintf(this->props.clock_name, sizeof(this->props.clock_name), "%s", s); + } else if (spa_streq(k, "clock.id")) { + this->props.clock_id = clock_name_to_id(s); + if (this->props.clock_id == -1) { + spa_log_warn(this->log, "unknown clock id '%s'", s); + this->props.clock_id = DEFAULT_CLOCK_ID; + } + } else if (spa_streq(k, "clock.device")) { + this->clock_fd = open(s, O_RDWR); + if (this->clock_fd == -1) { + spa_log_warn(this->log, "failed to open clock device '%s'", s); + } else { + this->props.clock_id = FD_TO_CLOCKID(this->clock_fd); + } } } + if (this->props.clock_name0 == '\0') { + spa_scnprintf(this->props.clock_name, sizeof(this->props.clock_name), + "%s.%s", DEFAULT_CLOCK_PREFIX, + clock_id_to_name(this->props.clock_id)); + } + + this->tracking = !clock_for_timerfd(this->props.clock_id); + this->timer_clockid = this->tracking ? CLOCK_MONOTONIC : this->props.clock_id; + this->max_error = 128; + + this->timer_source.func = on_timeout; + this->timer_source.data = this; + this->timer_source.fd = spa_system_timerfd_create(this->data_system, + this->timer_clockid, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK); + + this->timer_source.mask = SPA_IO_IN; + this->timer_source.rmask = 0; + this->timerspec.it_value.tv_sec = 0; + this->timerspec.it_value.tv_nsec = 0; + this->timerspec.it_interval.tv_sec = 0; + this->timerspec.it_interval.tv_nsec = 0; + spa_loop_add_source(this->data_loop, &this->timer_source); return 0;
View file
pipewire-0.3.65.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/client-rt.conf.in
Changed
@@ -31,8 +31,9 @@ context.modules = #{ name = <module-name> - # args = { <key> = <value> ... } - # flags = ifexists nofail + # ( args = { <key> = <value> ... } ) + # ( flags = ( ifexists ) ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) #} # # Loads a module with the given parameters.
View file
pipewire-0.3.65.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/client.conf.in
Changed
@@ -31,8 +31,9 @@ context.modules = #{ name = <module-name> - # args = { <key> = <value> ... } - # flags = ifexists nofail + # ( args = { <key> = <value> ... } ) + # ( flags = ( ifexists ) ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) #} # # Loads a module with the given parameters.
View file
pipewire-0.3.65.tar.gz/src/daemon/filter-chain.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/filter-chain.conf.in
Changed
@@ -30,8 +30,9 @@ context.modules = #{ name = <module-name> - # args = { <key> = <value> ... } - # flags = ifexists nofail + # ( args = { <key> = <value> ... } ) + # ( flags = ( ifexists ) ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) #} # # Loads a module with the given parameters.
View file
pipewire-0.3.66.tar.gz/src/daemon/filter-chain/spatializer-7.1.conf
Added
@@ -0,0 +1,157 @@ +# Headphone surround sink +# +# Copy this file into a conf.d/ directory such as +# ~/.config/pipewire/filter-chain.conf.d/ +# +context.modules = + { name = libpipewire-module-filter-chain + args = { + node.description = "Spatial Sink" + media.name = "Spatial Sink" + filter.graph = { + nodes = + { + type = sofa + label = spatializer + name = spFL + config = { + filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + } + control = { + "Azimuth" = 30.0 + "Elevation" = 0.0 + "Radius" = 3.0 + } + } + { + type = sofa + label = spatializer + name = spFR + config = { + filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + } + control = { + "Azimuth" = 330.0 + "Elevation" = 0.0 + "Radius" = 3.0 + } + } + { + type = sofa + label = spatializer + name = spFC + config = { + filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + } + control = { + "Azimuth" = 0.0 + "Elevation" = 0.0 + "Radius" = 3.0 + } + } + { + type = sofa + label = spatializer + name = spRL + config = { + filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + } + control = { + "Azimuth" = 150.0 + "Elevation" = 0.0 + "Radius" = 3.0 + } + } + { + type = sofa + label = spatializer + name = spRR + config = { + filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + } + control = { + "Azimuth" = 210.0 + "Elevation" = 0.0 + "Radius" = 3.0 + } + } + { + type = sofa + label = spatializer + name = spSL + config = { + filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + } + control = { + "Azimuth" = 90.0 + "Elevation" = 0.0 + "Radius" = 3.0 + } + } + { + type = sofa + label = spatializer + name = spSR + config = { + filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + } + control = { + "Azimuth" = 270.0 + "Elevation" = 0.0 + "Radius" = 3.0 + } + } + { + type = sofa + label = spatializer + name = spLFE + config = { + filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + } + control = { + "Azimuth" = 0.0 + "Elevation" = -60.0 + "Radius" = 3.0 + } + } + + { type = builtin label = mixer name = mixL } + { type = builtin label = mixer name = mixR } + + links = + # output + { output = "spFL:Out L" input="mixL:In 1" } + { output = "spFL:Out R" input="mixR:In 1" } + { output = "spFR:Out L" input="mixL:In 2" } + { output = "spFR:Out R" input="mixR:In 2" } + { output = "spFC:Out L" input="mixL:In 3" } + { output = "spFC:Out R" input="mixR:In 3" } + { output = "spRL:Out L" input="mixL:In 4" } + { output = "spRL:Out R" input="mixR:In 4" } + { output = "spRR:Out L" input="mixL:In 5" } + { output = "spRR:Out R" input="mixR:In 5" } + { output = "spSL:Out L" input="mixL:In 6" } + { output = "spSL:Out R" input="mixR:In 6" } + { output = "spSR:Out L" input="mixL:In 7" } + { output = "spSR:Out R" input="mixR:In 7" } + { output = "spLFE:Out L" input="mixL:In 8" } + { output = "spLFE:Out R" input="mixR:In 8" } + + inputs = "spFL:In" "spFR:In" "spFC:In" "spLFE:In" "spRL:In" "spRR:In", "spSL:In", "spSR:In" + outputs = "mixL:Out" "mixR:Out" + } + capture.props = { + node.name = "effect_input.spatializer" + media.class = Audio/Sink + audio.channels = 8 + audio.position = FL FR FC LFE RL RR SL SR + } + playback.props = { + node.name = "effect_output.spatializer" + node.passive = true + audio.channels = 2 + audio.position = FL FR + } + } + } +
View file
pipewire-0.3.66.tar.gz/src/daemon/filter-chain/spatializer-single.conf
Added
@@ -0,0 +1,45 @@ +# A virtual sound source sink +# Useful for testing spatial effects by moving it around with controls +# +# Copy this file into a conf.d/ directory such as +# ~/.config/pipewire/filter-chain.conf.d/ +# +context.modules = + { name = libpipewire-module-filter-chain + args = { + node.description = "3D Sink" + media.name = "3D Sink" + filter.graph = { + nodes = + { + type = sofa + label = spatializer + name = sp + config = { + filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + } + control = { + "Azimuth" = 220.0 + "Elevation" = 0.0 + "Radius" = 3.0 + } + } + + inputs = "sp:In" + outputs = "sp:Out L" "sp:Out R" + } + capture.props = { + node.name = "effect_input.3d" + media.class = Audio/Sink + audio.channels = 1 + audio.position = FC + } + playback.props = { + node.name = "effect_output.3d" + node.passive = true + audio.channels = 2 + audio.position = FL FR + } + } + } +
View file
pipewire-0.3.65.tar.gz/src/daemon/jack.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/jack.conf.in
Changed
@@ -30,8 +30,9 @@ context.modules = #{ name = <module-name> - # args = { <key> = <value> ... } - # flags = ifexists nofail + # ( args = { <key> = <value> ... } ) + # ( flags = ( ifexists ) ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) #} # # Loads a module with the given parameters.
View file
pipewire-0.3.65.tar.gz/src/daemon/meson.build -> pipewire-0.3.66.tar.gz/src/daemon/meson.build
Changed
@@ -72,6 +72,7 @@ 'minimal.conf', 'pipewire-pulse.conf', 'pipewire-avb.conf', + 'pipewire-aes67.conf', foreach c : conf_files @@ -109,6 +110,14 @@ dependencies : spa_dep, pipewire_dep, , ) +executable('pipewire-aes67', + pipewire_daemon_sources, + install: true, + c_args : pipewire_c_args, + include_directories : configinc , + dependencies : spa_dep, pipewire_dep, , +) + ln = find_program('ln') custom_target('pipewire-uninstalled',
View file
pipewire-0.3.65.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/minimal.conf.in
Changed
@@ -60,8 +60,9 @@ context.modules = #{ name = <module-name> - # args = { <key> = <value> ... } - # flags = ifexists nofail + # ( args = { <key> = <value> ... } ) + # ( flags = ( ifexists ) ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) #} # # Loads a module with the given parameters. @@ -135,8 +136,9 @@ context.objects = #{ factory = <factory-name> - # args = { <key> = <value> ... } - # flags = nofail + # ( args = { <key> = <value> ... } ) + # ( flags = ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) #} # # Creates an object from a PipeWire factory with the given parameters. @@ -339,7 +341,10 @@ context.exec = - #{ path = <program-name> args = "<arguments>" } + #{ path = <program-name> + # ( args = "<arguments>" ) + # ( condition = { <key> = <value> ... } ... ) + #} # # Execute the given program with arguments. #
View file
pipewire-0.3.66.tar.gz/src/daemon/pipewire-aes67.conf.in
Added
@@ -0,0 +1,52 @@ +# AES67 config file for PipeWire version @VERSION@ # +# +# Copy and edit this file in @PIPEWIRE_CONFIG_DIR@ for system-wide changes +# or in ~/.config/pipewire for local changes. +# +# It is also possible to place a file with an updated section in +# @PIPEWIRE_CONFIG_DIR@/pipewire-aes67.conf.d/ for system-wide changes or in +# ~/.config/pipewire/pipewire-aes67.conf.d/ for local changes. +# + +context.properties = { + ## Configure properties in the system. + #mem.warn-mlock = false + #mem.allow-mlock = true + #mem.mlock-all = false + #log.level = 2 + + #default.clock.quantum-limit = 8192 +} + +#context.spa-libs = { +# audio.convert.* = audioconvert/libspa-audioconvert +# support.* = support/libspa-support +#} + +context.modules = + { name = libpipewire-module-rt + args = { + nice.level = -11 + #rt.prio = 88 + #rt.time.soft = -1 + #rt.time.hard = -1 + } + flags = ifexists nofail + } + { name = libpipewire-module-protocol-native } + { name = libpipewire-module-client-node } + { name = libpipewire-module-adapter } + { name = libpipewire-module-rtp-source + args = { + sap.ip = 239.255.255.255 + sap.port = 9875 + sess.latency.msec = 10 + local.ifname = eth0 + stream.props = { + media.class = "Audio/Source" + node.virtual = false + device.api = aes67 + } + } + } +
View file
pipewire-0.3.65.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
@@ -57,11 +57,11 @@ # Extra commands can be executed here. # load-module : loads a module with args and flags # args = "<module-name> <module-args>" -# flags = "no-fail" +# ( flags = nofail ) pulse.cmd = { cmd = "load-module" args = "module-always-sink" flags = } #{ cmd = "load-module" args = "module-switch-on-connect" } - #{ cmd = "load-module" args = "module-gsettings" flags = "nofail" } + #{ cmd = "load-module" args = "module-gsettings" flags = nofail } stream.properties = {
View file
pipewire-0.3.65.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.66.tar.gz/src/daemon/pipewire.conf.in
Changed
@@ -29,7 +29,7 @@ #default.clock.rate = 48000 #default.clock.allowed-rates = 48000 #default.clock.quantum = 1024 - default.clock.min-quantum = 16 + #default.clock.min-quantum = 32 #default.clock.max-quantum = 2048 #default.clock.quantum-limit = 8192 #default.video.width = 640 @@ -44,6 +44,9 @@ vm.overrides = { default.clock.min-quantum = 1024 } + + # keys checked below to disable module loading + module.x11.bell = true } context.spa-libs = { @@ -68,13 +71,16 @@ context.modules = #{ name = <module-name> - # args = { <key> = <value> ... } - # flags = ifexists nofail + # ( args = { <key> = <value> ... } ) + # ( flags = ( ifexists ) ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) #} # # Loads a module with the given parameters. # If ifexists is given, the module is ignored when it is not found. # If nofail is given, module initialization failures are ignored. + # If condition is given, the module is loaded only when the context + # properties all match the match rules. # # Uses realtime scheduling to boost the audio thread priorities. This uses @@ -167,17 +173,21 @@ #x11.xauthority = null } flags = ifexists nofail + condition = { module.x11.bell = true } } context.objects = #{ factory = <factory-name> - # args = { <key> = <value> ... } - # flags = nofail + # ( args = { <key> = <value> ... } ) + # ( flags = ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) #} # # Creates an object from a PipeWire factory with the given parameters. # If nofail is given, errors are ignored (and no object is created). + # If condition is given, the object is created only when the context properties + # all match the match rules. # #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } } #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = nofail } @@ -194,6 +204,8 @@ node.name = Dummy-Driver node.group = pipewire.dummy priority.driver = 20000 + #clock.id = monotonic # realtime | tai | monotonic-raw | boottime + #clock.name = "clock.system.monotonic" } } { factory = spa-node-factory @@ -205,6 +217,20 @@ node.freewheel = true } } + # An example clock reading from /dev/ptp0. Another option is to sync the + # ptp clock to CLOCK_TAI and then set clock.id = tai. + #{ factory = spa-node-factory + # args = { + # factory.name = support.node.driver + # node.name = PTP0-Driver + # node.group = pipewire.ptp0 + # priority.driver = 30000 + # clock.name = "clock.system.ptp0" + # #clock.id = tai + # clock.device = "/dev/ptp0" + # } + #} + # This creates a new Source node. It will have input ports # that you can link, to provide audio for this source. #{ factory = adapter @@ -240,9 +266,14 @@ context.exec = - #{ path = <program-name> args = "<arguments>" } + #{ path = <program-name> + # ( args = "<arguments>" ) + # ( condition = { <key> = <value> ... } ... ) + #} # # Execute the given program with arguments. + # If condition is given, the program is executed only when the context + # properties all match the match rules. # # You can optionally start the session manager here, # but it is better to start it as a systemd service.
View file
pipewire-0.3.65.tar.gz/src/gst/gstpipewirepool.c -> pipewire-0.3.66.tar.gz/src/gst/gstpipewirepool.c
Changed
@@ -109,6 +109,16 @@ gst_buffer_insert_memory (buf, i, gmem); } + if (pool->add_metavideo) { + gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, + GST_VIDEO_INFO_FORMAT (&pool->video_info), + GST_VIDEO_INFO_WIDTH (&pool->video_info), + GST_VIDEO_INFO_HEIGHT (&pool->video_info), + GST_VIDEO_INFO_N_PLANES (&pool->video_info), + pool->video_info.offset, + pool->video_info.stride); + } + data->pool = gst_object_ref (pool); data->owner = NULL; data->header = spa_buffer_find_meta_data (b->buffer, SPA_META_Header, sizeof(*data->header)); @@ -208,6 +218,41 @@ } } +static const gchar ** +get_options (GstBufferPool * pool) +{ + static const gchar *options = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL }; + return options; +} + +static gboolean +set_config (GstBufferPool * pool, GstStructure * config) +{ + GstPipeWirePool *p = GST_PIPEWIRE_POOL (pool); + GstCaps *caps; + guint size, min_buffers, max_buffers; + gboolean has_video; + + if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, &max_buffers)) { + GST_WARNING_OBJECT (pool, "invalid config"); + return FALSE; + } + + if (caps == NULL) { + GST_WARNING_OBJECT (pool, "no caps in config"); + return FALSE; + } + + has_video = gst_video_info_from_caps (&p->video_info, caps); + + p->add_metavideo = has_video && gst_buffer_pool_config_has_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_META); + + gst_buffer_pool_config_set_params (config, caps, p->video_info.size, min_buffers, max_buffers); + + return GST_BUFFER_POOL_CLASS (gst_pipewire_pool_parent_class)->set_config (pool, config); +} + static void flush_start (GstBufferPool * pool) { @@ -252,6 +297,8 @@ gobject_class->finalize = gst_pipewire_pool_finalize; + bufferpool_class->get_options = get_options; + bufferpool_class->set_config = set_config; bufferpool_class->start = do_start; bufferpool_class->flush_start = flush_start; bufferpool_class->acquire_buffer = acquire_buffer;
View file
pipewire-0.3.65.tar.gz/src/gst/gstpipewirepool.h -> pipewire-0.3.66.tar.gz/src/gst/gstpipewirepool.h
Changed
@@ -27,6 +27,8 @@ #include <gst/gst.h> +#include <gst/video/video.h> + #include <pipewire/pipewire.h> G_BEGIN_DECLS @@ -66,6 +68,9 @@ struct pw_stream *stream; struct pw_type *t; + gboolean add_metavideo; + GstVideoInfo video_info; + GstAllocator *fd_allocator; GstAllocator *dmabuf_allocator;
View file
pipewire-0.3.65.tar.gz/src/gst/gstpipewiresink.c -> pipewire-0.3.66.tar.gz/src/gst/gstpipewiresink.c
Changed
@@ -142,6 +142,7 @@ GstPipeWireSink *pwsink = GST_PIPEWIRE_SINK (bsink); gst_query_add_allocation_pool (query, GST_BUFFER_POOL_CAST (pwsink->pool), 0, 0, 0); + gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); return TRUE; } @@ -504,6 +505,22 @@ d->chunk->stride = 0; } + GstVideoMeta *meta = gst_buffer_get_video_meta (buffer); + if (meta) { + if (meta->n_planes == b->n_datas) { + gsize video_size = 0; + for (i = 0; i < meta->n_planes; i++) { + struct spa_data *d = &b->datasi; + d->chunk->offset += meta->offseti - video_size; + d->chunk->stride = meta->stridei; + + video_size += d->chunk->size; + } + } else { + GST_ERROR ("plane num not matching, meta:%u buffer:%u", meta->n_planes, b->n_datas); + } + } + if ((res = pw_stream_queue_buffer (pwsink->stream, data->b)) < 0) { g_warning ("can't send buffer %s", spa_strerror(res)); }
View file
pipewire-0.3.65.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.66.tar.gz/src/gst/gstpipewiresrc.c
Changed
@@ -615,6 +615,27 @@ } } + if (pwsrc->is_video) { + gsize video_size = 0; + GstVideoInfo *info = &pwsrc->video_info; + GstVideoMeta *meta = gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, + GST_VIDEO_INFO_FORMAT (info), + GST_VIDEO_INFO_WIDTH (info), + GST_VIDEO_INFO_HEIGHT (info), + GST_VIDEO_INFO_N_PLANES (info), + info->offset, + info->stride); + + meta->n_planes = MIN(meta->n_planes, b->buffer->n_datas); + for (i = 0; i < meta->n_planes; i++) { + struct spa_data *d = &b->buffer->datasi; + meta->offseti = video_size; + meta->stridei = d->chunk->stride; + + video_size += d->chunk->size; + } + } + for (i = 0; i < b->buffer->n_datas; i++) { struct spa_data *d = &b->buffer->datasi; GstMemory *pmem = gst_buffer_peek_memory (data->buf, i); @@ -658,6 +679,7 @@ case PW_STREAM_STATE_STREAMING: break; case PW_STREAM_STATE_ERROR: + pw_stream_set_error (pwsrc->stream, -EPIPE, "%s", error); GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED, ("stream error: %s", error), (NULL)); break; @@ -958,6 +980,10 @@ gst_caps_unref(pwsrc->caps); pwsrc->caps = gst_caps_from_format (param); + pwsrc->is_video = pwsrc->caps != NULL + ? gst_video_info_from_caps (&pwsrc->video_info, pwsrc->caps) + : FALSE; + pwsrc->negotiated = pwsrc->caps != NULL; if (pwsrc->negotiated) {
View file
pipewire-0.3.65.tar.gz/src/gst/gstpipewiresrc.h -> pipewire-0.3.66.tar.gz/src/gst/gstpipewiresrc.h
Changed
@@ -28,6 +28,8 @@ #include <gst/gst.h> #include <gst/base/gstpushsrc.h> +#include <gst/video/video.h> + #include <pipewire/pipewire.h> #include <gst/gstpipewirepool.h> #include <gst/gstpipewirecore.h> @@ -71,6 +73,9 @@ GstCaps *caps; + gboolean is_video; + GstVideoInfo video_info; + gboolean negotiated; gboolean flushing; gboolean started;
View file
pipewire-0.3.65.tar.gz/src/modules/meson.build -> pipewire-0.3.66.tar.gz/src/modules/meson.build
Changed
@@ -1,3 +1,4 @@ +subdir('module-rt') subdir('spa') # The list of "main" source files for modules, the ones that have the @@ -108,10 +109,11 @@ 'module-filter-chain/biquad.c', 'module-filter-chain/ladspa_plugin.c', 'module-filter-chain/builtin_plugin.c', + 'module-filter-chain/sofa_plugin.c', 'module-filter-chain/convolver.c' filter_chain_dependencies = - mathlib, dl_lib, pipewire_dep, sndfile_dep, audioconvert_dep + mathlib, dl_lib, pipewire_dep, sndfile_dep, audioconvert_dep, libmysofa_dep if lilv_lib.found() @@ -139,7 +141,7 @@ pipewire_module_combine_stream = shared_library('pipewire-module-combine-stream', 'module-combine-stream.c' , include_directories : configinc, - install : false, + install : true, install_dir : modules_install_dir, install_rpath: modules_install_dir, dependencies : spa_dep, dl_lib, pipewire_dep, @@ -174,27 +176,25 @@ build_module_rtkit = dbus_dep.found() and (get_option('legacy-rtkit') == true) 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' , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : dbus_dep, mathlib, dl_lib, pipewire_dep, -) + pipewire_module_rtkit = shared_library('pipewire-module-rtkit', 'module-rt.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : dbus_dep, mathlib, dl_lib, pipewire_dep, + ) endif summary({'rt': '@0@ RTKit'.format(build_module_rtkit ? 'with' : 'without')}, section: 'Optional Modules') build_module_portal = dbus_dep.found() if build_module_portal -pipewire_module_portal = shared_library('pipewire-module-portal', 'module-portal.c' , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : dbus_dep, mathlib, dl_lib, pipewire_dep, -) + pipewire_module_portal = shared_library('pipewire-module-portal', 'module-portal.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : dbus_dep, mathlib, dl_lib, pipewire_dep, + ) endif summary({'portal': build_module_portal}, bool_yn: true, section: 'Optional Modules') @@ -332,16 +332,16 @@ ) build_module_pulse_tunnel = pulseaudio_dep.found() -if build_module_pulse_tunnel - pipewire_module_pulse_tunnel = shared_library('pipewire-module-pulse-tunnel', - 'module-pulse-tunnel.c', - 'module-protocol-pulse/format.c' , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : mathlib, dl_lib, pipewire_dep, pulseaudio_dep, -) + if build_module_pulse_tunnel + pipewire_module_pulse_tunnel = shared_library('pipewire-module-pulse-tunnel', + 'module-pulse-tunnel.c', + 'module-protocol-pulse/format.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : mathlib, dl_lib, pipewire_dep, pulseaudio_dep, + ) endif summary({'pulse-tunnel': build_module_pulse_tunnel}, bool_yn: true, section: 'Optional Modules') @@ -474,44 +474,44 @@ build_module_zeroconf_discover = avahi_dep.found() if build_module_zeroconf_discover -pipewire_module_zeroconf_discover = shared_library('pipewire-module-zeroconf-discover', - 'module-zeroconf-discover.c', - 'module-protocol-pulse/format.c', - 'module-zeroconf-discover/avahi-poll.c' , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep, -) + pipewire_module_zeroconf_discover = shared_library('pipewire-module-zeroconf-discover', + 'module-zeroconf-discover.c', + 'module-protocol-pulse/format.c', + 'module-zeroconf-discover/avahi-poll.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep, + ) endif summary({'zeroconf-discover': build_module_zeroconf_discover}, bool_yn: true, section: 'Optional Modules') build_module_raop_discover = avahi_dep.found() if build_module_raop_discover -pipewire_module_raop_discover = shared_library('pipewire-module-raop-discover', - 'module-raop-discover.c', - 'module-zeroconf-discover/avahi-poll.c' , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep, -) + pipewire_module_raop_discover = shared_library('pipewire-module-raop-discover', + 'module-raop-discover.c', + 'module-zeroconf-discover/avahi-poll.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep, + ) endif summary({'raop-discover (needs Avahi)': build_module_raop_discover}, bool_yn: true, section: 'Optional Modules') build_module_raop = openssl_lib.found() if build_module_raop -pipewire_module_raop_sink = shared_library('pipewire-module-raop-sink', - 'module-raop-sink.c', - 'module-raop/rtsp-client.c' , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, openssl_lib, -) + pipewire_module_raop_sink = shared_library('pipewire-module-raop-sink', + 'module-raop-sink.c', + 'module-raop/rtsp-client.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, openssl_lib, + ) endif summary({'raop-sink (requires OpenSSL)': build_module_raop}, bool_yn: true, section: 'Optional Modules') @@ -538,37 +538,37 @@ build_module_roc = roc_dep.found() if build_module_roc -pipewire_module_roc_sink = shared_library('pipewire-module-roc-sink', - 'module-roc-sink.c' , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep, -) + pipewire_module_roc_sink = shared_library('pipewire-module-roc-sink', + 'module-roc-sink.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep, + ) -pipewire_module_roc_source = shared_library('pipewire-module-roc-source', - 'module-roc-source.c' , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep, -) + pipewire_module_roc_source = shared_library('pipewire-module-roc-source', + 'module-roc-source.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, roc_dep, + ) endif summary({'roc-sink': build_module_roc}, bool_yn: true, section: 'Optional Modules') summary({'roc-source': build_module_roc}, bool_yn: true, section: 'Optional Modules') build_module_x11_bell = x11_dep.found() and canberra_dep.found() if build_module_x11_bell -pipewire_module_x11_bell = shared_library('pipewire-module-x11-bell', - 'module-x11-bell.c' , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, x11_dep, xfixes_dep, canberra_dep, -) + pipewire_module_x11_bell = shared_library('pipewire-module-x11-bell', + 'module-x11-bell.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, x11_dep, xfixes_dep, canberra_dep, + ) endif summary({'x11-bell': build_module_x11_bell}, bool_yn: true, section: 'Optional Modules') @@ -583,27 +583,27 @@ build_module_avb = get_option('avb').require(host_machine.system() == 'linux', error_message: 'AVB support is only available on Linux').allowed() if build_module_avb -pipewire_module_avb = shared_library('pipewire-module-avb', - 'module-avb.c', - 'module-avb/avb.c', - 'module-avb/adp.c', - 'module-avb/acmp.c', - 'module-avb/aecp.c', - 'module-avb/aecp-aem.c', - 'module-avb/avdecc.c', - 'module-avb/maap.c', - 'module-avb/mmrp.c', - 'module-avb/mrp.c', - 'module-avb/msrp.c', - 'module-avb/mvrp.c', - 'module-avb/srp.c', - 'module-avb/stream.c' - , - include_directories : configinc, - install : true, - install_dir : modules_install_dir, - install_rpath: modules_install_dir, - dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, -) + pipewire_module_avb = shared_library('pipewire-module-avb', + 'module-avb.c', + 'module-avb/avb.c', + 'module-avb/adp.c', + 'module-avb/acmp.c', + 'module-avb/aecp.c', + 'module-avb/aecp-aem.c', + 'module-avb/avdecc.c', + 'module-avb/maap.c', + 'module-avb/mmrp.c', + 'module-avb/mrp.c', + 'module-avb/msrp.c', + 'module-avb/mvrp.c', + 'module-avb/srp.c', + 'module-avb/stream.c' + , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, + ) endif summary({'avb': build_module_avb}, bool_yn: true, section: 'Optional Modules')
View file
pipewire-0.3.65.tar.gz/src/modules/module-combine-stream.c -> pipewire-0.3.66.tar.gz/src/modules/module-combine-stream.c
Changed
@@ -847,6 +847,7 @@ } static const struct pw_proxy_events core_proxy_events = { + PW_VERSION_PROXY_EVENTS, .removed = core_removed, };
View file
pipewire-0.3.65.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.66.tar.gz/src/modules/module-filter-chain.c
Changed
@@ -273,6 +273,12 @@ * - `max-delay` the maximum delay in seconds. The "Delay (s)" parameter will * be clamped to this value. * + * ### Invert + * + * The invert plugin can be used to invert the phase of the signal. + * + * It has an input port "In" and an output port "Out". + * * ## General options * * Options with well-known behavior. Most options can be added to the global @@ -445,7 +451,7 @@ struct plugin { struct spa_list link; int ref; - char type64; + char type256; char pathPATH_MAX; struct fc_plugin *plugin; @@ -506,6 +512,7 @@ unsigned int n_deps; unsigned int visited:1; unsigned int disabled:1; + unsigned int control_changed:1; }; struct link { @@ -878,7 +885,8 @@ old = port->control_data; port->control_data = value ? *value : desc->default_controlport->idx; pw_log_info("control %d ('%s') from %f to %f", port->idx, name, old, port->control_data); - return old == port->control_data ? 0 : 1; + node->control_changed = old != port->control_data; + return node->control_changed ? 1 : 0; } static int parse_params(struct graph *graph, const struct spa_pod *pod) @@ -938,6 +946,24 @@ d->activate(*hndl->hndl); } } + +static void node_control_changed(struct node *node) +{ + const struct fc_descriptor *d = node->desc->desc; + uint32_t i; + + if (!node->control_changed) + return; + + for (i = 0; i < node->n_hndl; i++) { + if (node->hndli == NULL) + continue; + if (d->control_changed) + d->control_changed(node->hndli); + } + node->control_changed = false; +} + static void param_props_changed(struct impl *impl, const struct spa_pod *param) { struct spa_pod_object *obj = (struct spa_pod_object *) param; @@ -953,6 +979,10 @@ uint8_t buffer1024; struct spa_pod_dynamic_builder b; const struct spa_pod *params1; + struct node *node; + + spa_list_for_each(node, &graph->node_list, link) + node_control_changed(node); spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); params0 = get_props_param(graph, &b.b); @@ -1205,6 +1235,9 @@ if (spa_streq(type, "builtin")) { pl = load_builtin_plugin(support, n_support, &impl->dsp, path, NULL); } + else if (spa_streq(type, "sofa")) { + pl = load_sofa_plugin(support, n_support, &impl->dsp, path, NULL); + } else if (spa_streq(type, "ladspa")) { pl = load_ladspa_plugin(support, n_support, &impl->dsp, path, NULL); } @@ -1696,6 +1729,7 @@ free(node->output_port); free(node->control_port); free(node->notify_port); + free(node->config); free(node); } @@ -1767,6 +1801,8 @@ } if (d->activate) d->activate(node->hndli); + if (node->control_changed && d->control_changed) + d->control_changed(node->hndli); } } return 0; @@ -1902,6 +1938,8 @@ pw_log_error("input port %s not found", v); goto error; } else { + bool disabled = false; + desc = port->node->desc; d = desc->desc; if (i == 0 && port->external != SPA_ID_INVALID) { @@ -1936,12 +1974,14 @@ gp->hndl = &peer->node->hndli; gp->port = peer->p; gp->next = true; + disabled = true; } if (gp != NULL) gp->next = false; } - port->node->disabled = true; - } else { + port->node->disabled = disabled; + } + if (!disabled) { pw_log_info("input port %s%d:%s", port->node->name, i, d->portsport->p.name); port->external = graph->n_input;
View file
pipewire-0.3.65.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.66.tar.gz/src/modules/module-filter-chain/builtin_plugin.c
Changed
@@ -978,6 +978,38 @@ .cleanup = delay_cleanup, }; +static void invert_run(void * Instance, unsigned long SampleCount) +{ + struct builtin *impl = Instance; + float *in = impl->port1, *out = impl->port0; + unsigned long n; + for (n = 0; n < SampleCount; n++) + outn = -inn; +} + +static struct fc_port invert_ports = { + { .index = 0, + .name = "Out", + .flags = FC_PORT_OUTPUT | FC_PORT_AUDIO, + }, + { .index = 1, + .name = "In", + .flags = FC_PORT_INPUT | FC_PORT_AUDIO, + }, +}; + +static const struct fc_descriptor invert_desc = { + .name = "invert", + + .n_ports = 2, + .ports = invert_ports, + + .instantiate = builtin_instantiate, + .connect_port = builtin_connect_port, + .run = invert_run, + .cleanup = builtin_cleanup, +}; + static const struct fc_descriptor * builtin_descriptor(unsigned long Index) { switch(Index) { @@ -1005,6 +1037,8 @@ return &convolve_desc; case 11: return &delay_desc; + case 12: + return &invert_desc; } return NULL; }
View file
pipewire-0.3.65.tar.gz/src/modules/module-filter-chain/plugin.h -> pipewire-0.3.66.tar.gz/src/modules/module-filter-chain/plugin.h
Changed
@@ -83,6 +83,7 @@ void (*cleanup) (void *instance); void (*connect_port) (void *instance, unsigned long port, float *data); + void (*control_changed) (void *instance); void (*activate) (void *instance); void (*deactivate) (void *instance); @@ -108,5 +109,7 @@ struct dsp_ops *dsp, const char *path, const char *config); struct fc_plugin *load_builtin_plugin(const struct spa_support *support, uint32_t n_support, struct dsp_ops *dsp, const char *path, const char *config); +struct fc_plugin *load_sofa_plugin(const struct spa_support *support, uint32_t n_support, + struct dsp_ops *dsp, const char *path, const char *config); #endif /* PLUGIN_H */
View file
pipewire-0.3.66.tar.gz/src/modules/module-filter-chain/sofa_plugin.c
Added
@@ -0,0 +1,375 @@ +#include "config.h" + +#include <spa/utils/json.h> +#include <spa/support/loop.h> + +#include <pipewire/log.h> +#include "plugin.h" +#include "convolver.h" +#include "dsp-ops.h" +#include "pffft.h" + +#ifdef HAVE_LIBMYSOFA +#include <mysofa.h> + +#define MAX_SAMPLES 8192u +#endif + +static struct dsp_ops *dsp_ops; +static struct spa_loop *data_loop; +static struct spa_loop *main_loop; + +struct spatializer_impl { + unsigned long rate; + float *port6; + int n_samples, blocksize, tailsize; + float *tmp2; + +#ifdef HAVE_LIBMYSOFA + struct MYSOFA_EASY *sofa; +#endif + unsigned int interpolate:1; + struct convolver *l_conv3; + struct convolver *r_conv3; +}; + +static void * spatializer_instantiate(const struct fc_descriptor * Descriptor, + unsigned long SampleRate, int index, const char *config) +{ +#ifdef HAVE_LIBMYSOFA + struct spatializer_impl *impl; + struct spa_json it2; + const char *val; + char key256; + char filenamePATH_MAX = ""; + + errno = EINVAL; + if (config == NULL) + return NULL; + + spa_json_init(&it0, config, strlen(config)); + if (spa_json_enter_object(&it0, &it1) <= 0) + return NULL; + + impl = calloc(1, sizeof(*impl)); + if (impl == NULL) { + errno = ENOMEM; + return NULL; + } + + while (spa_json_get_string(&it1, key, sizeof(key)) > 0) { + if (spa_streq(key, "blocksize")) { + if (spa_json_get_int(&it1, &impl->blocksize) <= 0) { + pw_log_error("spatializer:blocksize requires a number"); + errno = EINVAL; + goto error; + } + } + else if (spa_streq(key, "tailsize")) { + if (spa_json_get_int(&it1, &impl->tailsize) <= 0) { + pw_log_error("spatializer:tailsize requires a number"); + errno = EINVAL; + goto error; + } + } + else if (spa_streq(key, "filename")) { + if (spa_json_get_string(&it1, filename, sizeof(filename)) <= 0) { + pw_log_error("spatializer:filename requires a string"); + errno = EINVAL; + goto error; + } + } + else if (spa_json_next(&it1, &val) < 0) + break; + } + if (!filename0) { + pw_log_error("spatializer:filename was not given"); + errno = EINVAL; + goto error; + } + + int ret = MYSOFA_OK; + + impl->sofa = mysofa_open_cached(filename, SampleRate, &impl->n_samples, &ret); + + if (ret != MYSOFA_OK) { + pw_log_error("Unable to load HRTF from %s: %d", filename, ret); + errno = ENOENT; + goto error; + } + + if (impl->blocksize <= 0) + impl->blocksize = SPA_CLAMP(impl->n_samples, 64, 256); + if (impl->tailsize <= 0) + impl->tailsize = SPA_CLAMP(4096, impl->blocksize, 32768); + + pw_log_info("using n_samples:%u %d:%d blocksize sofa:%s", impl->n_samples, + impl->blocksize, impl->tailsize, filename); + + impl->tmp0 = calloc(MAX_SAMPLES, sizeof(float)); + impl->tmp1 = calloc(MAX_SAMPLES, sizeof(float)); + impl->rate = SampleRate; + return impl; +error: + if (impl->sofa) + mysofa_close_cached(impl->sofa); + free(impl); + return NULL; +#else + pw_log_error("libmysofa is required for spatializer, but disabled at compile time"); + errno = EINVAL; + return NULL; +#endif +} + +#ifdef HAVE_LIBMYSOFA +static int +do_switch(struct spa_loop *loop, bool async, uint32_t seq, const void *data, + size_t size, void *user_data) +{ + struct spatializer_impl *impl = user_data; + + if (impl->l_conv0 == NULL) { + SPA_SWAP(impl->l_conv0, impl->l_conv2); + SPA_SWAP(impl->r_conv0, impl->r_conv2); + } else { + SPA_SWAP(impl->l_conv1, impl->l_conv2); + SPA_SWAP(impl->r_conv1, impl->r_conv2); + } + impl->interpolate = impl->l_conv0 && impl->l_conv1; + + return 0; +} + +static void spatializer_reload(void * Instance) +{ + struct spatializer_impl *impl = Instance; + float *left_ir = calloc(impl->n_samples, sizeof(float)); + float *right_ir = calloc(impl->n_samples, sizeof(float)); + float left_delay; + float right_delay; + float coords3; + + for (uint8_t i = 0; i < 3; i++) + coordsi = impl->port3 + i0; + + mysofa_s2c(coords); + mysofa_getfilter_float( + impl->sofa, + coords0, + coords1, + coords2, + left_ir, + right_ir, + &left_delay, + &right_delay + ); + + // TODO: make use of delay + if ((left_delay || right_delay) && (!isnan(left_delay) || !isnan(right_delay))) { + pw_log_warn("delay dropped l: %f, r: %f", left_delay, right_delay); + } + + if (impl->l_conv2) + convolver_free(impl->l_conv2); + if (impl->r_conv2) + convolver_free(impl->r_conv2); + + impl->l_conv2 = convolver_new(dsp_ops, impl->blocksize, impl->tailsize, + left_ir, impl->n_samples); + impl->r_conv2 = convolver_new(dsp_ops, impl->blocksize, impl->tailsize, + right_ir, impl->n_samples); + + free(left_ir); + free(right_ir); + + if (impl->l_conv2 == NULL || impl->r_conv2 == NULL) { + pw_log_error("reloading left or right convolver failed"); + return; + } + spa_loop_invoke(data_loop, do_switch, 1, NULL, 0, true, impl); +} + +struct free_data { + void *item2; +}; + +static int +do_free(struct spa_loop *loop, bool async, uint32_t seq, const void *data, + size_t size, void *user_data) +{ + const struct free_data *fd = data; + if (fd->item0) + convolver_free(fd->item0); + if (fd->item1) + convolver_free(fd->item1); + return 0; +} +#endif + +static void spatializer_run(void * Instance, unsigned long SampleCount) +{ +#ifdef HAVE_LIBMYSOFA + struct spatializer_impl *impl = Instance; + + if (impl->interpolate) { + uint32_t len = SPA_MIN(SampleCount, MAX_SAMPLES); + struct free_data free_data; + float *l = impl->tmp0, *r = impl->tmp1; + + convolver_run(impl->l_conv0, impl->port2, impl->port0, len); + convolver_run(impl->l_conv1, impl->port2, l, len); + convolver_run(impl->r_conv0, impl->port2, impl->port1, len); + convolver_run(impl->r_conv1, impl->port2, r, len); + + for (uint32_t i = 0; i < SampleCount; i++) { + float t = (float)i / SampleCount; + impl->port0i = impl->port0i * (1.0f - t) + li * t; + impl->port1i = impl->port1i * (1.0f - t) + ri * t; + } + free_data.item0 = impl->l_conv0; + free_data.item1 = impl->r_conv0; + impl->l_conv0 = impl->l_conv1; + impl->r_conv0 = impl->r_conv1; + impl->l_conv1 = impl->r_conv1 = NULL; + impl->interpolate = false; + + spa_loop_invoke(main_loop, do_free, 1, &free_data, sizeof(free_data), false, impl); + } else if (impl->l_conv0 && impl->r_conv0) { + convolver_run(impl->l_conv0, impl->port2, impl->port0, SampleCount); + convolver_run(impl->r_conv0, impl->port2, impl->port1, SampleCount); + } +#endif +} + +static void spatializer_connect_port(void * Instance, unsigned long Port, + float * DataLocation) +{ + struct spatializer_impl *impl = Instance; + if (Port > 5) + return; + impl->portPort = DataLocation; +} + +static void spatializer_cleanup(void * Instance) +{ + struct spatializer_impl *impl = Instance; + + for (uint8_t i = 0; i < 3; i++) { + if (impl->l_convi) + convolver_free(impl->l_convi); + if (impl->r_convi) + convolver_free(impl->r_convi); + } +#ifdef HAVE_LIBMYSOFA + if (impl->sofa) + mysofa_close_cached(impl->sofa); +#endif + free(impl->tmp0); + free(impl->tmp1); + + free(impl); +} + +static void spatializer_control_changed(void * Instance) +{ +#ifdef HAVE_LIBMYSOFA + pw_log_info("control changed"); + spatializer_reload(Instance); +#endif +} + +static void spatializer_deactivate(void * Instance) +{ + struct spatializer_impl *impl = Instance; + if (impl->l_conv0) + convolver_reset(impl->l_conv0); + if (impl->r_conv0) + convolver_reset(impl->r_conv0); + impl->interpolate = false; +} + +static struct fc_port spatializer_ports = { + { .index = 0, + .name = "Out L", + .flags = FC_PORT_OUTPUT | FC_PORT_AUDIO, + }, + { .index = 1, + .name = "Out R", + .flags = FC_PORT_OUTPUT | FC_PORT_AUDIO, + }, + { .index = 2, + .name = "In", + .flags = FC_PORT_INPUT | FC_PORT_AUDIO, + }, + + { .index = 3, + .name = "Azimuth", + .flags = FC_PORT_INPUT | FC_PORT_CONTROL, + .def = 0.0f, .min = 0.0f, .max = 360.0f + }, + { .index = 4, + .name = "Elevation", + .flags = FC_PORT_INPUT | FC_PORT_CONTROL, + .def = 0.0f, .min = -90.0f, .max = 90.0f + }, + { .index = 5, + .name = "Radius", + .flags = FC_PORT_INPUT | FC_PORT_CONTROL, + .def = 1.0f, .min = 0.0f, .max = 100.0f + }, +}; + +static const struct fc_descriptor spatializer_desc = { + .name = "spatializer", + + .n_ports = 6, + .ports = spatializer_ports, + + .instantiate = spatializer_instantiate, + .connect_port = spatializer_connect_port, + .control_changed = spatializer_control_changed, + .deactivate = spatializer_deactivate, + .run = spatializer_run, + .cleanup = spatializer_cleanup, +}; + +static const struct fc_descriptor * sofa_descriptor(unsigned long Index) +{ + switch(Index) { + case 0: + return &spatializer_desc; + } + return NULL; +} + + +static const struct fc_descriptor *sofa_make_desc(struct fc_plugin *plugin, const char *name) +{ + unsigned long i; + for (i = 0; ;i++) { + const struct fc_descriptor *d = sofa_descriptor(i); + if (d == NULL) + break; + if (spa_streq(d->name, name)) + return d; + } + return NULL; +} + +static struct fc_plugin builtin_plugin = { + .make_desc = sofa_make_desc +}; + +struct fc_plugin *load_sofa_plugin(const struct spa_support *support, uint32_t n_support, + struct dsp_ops *dsp, const char *plugin, const char *config) +{ + dsp_ops = dsp; + pffft_select_cpu(dsp->cpu_flags); + + data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); + main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); + + return &builtin_plugin; +} +
View file
pipewire-0.3.65.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.66.tar.gz/src/modules/module-loopback.c
Changed
@@ -111,6 +111,32 @@ * *\endcode * + * ## Example configuration of a virtual source + * + * This Virtual source routes the front-left channel of a multi-channel input to a mono channel. + * This is useful for splitting up multi-channel inputs from USB audio interfaces that are not yet fully supported by alsa. + * + *\code{.unparsed} + * context.modules = + * { name = libpipewire-module-loopback + * args = { + * node.description = "Scarlett Focusrite Line 1" + * capture.props = { + * audio.position = FL + * stream.dont-remix = true + * node.target = "alsa_input.usb-Focusrite_Scarlett_Solo_USB_Y7ZD17C24495BC-00.analog-stereo" + * node.passive = true + * } + * playback.props = { + * node.name = "SF_mono_in_1" + * media.class = "Audio/Source" + * audio.position = MONO + * } + * } + * } + * + *\endcode + * * ## See also * * `pw-loopback` : a tool that loads the loopback module with given parameters.
View file
pipewire-0.3.65.tar.gz/src/modules/module-protocol-pulse/cmd.c -> pipewire-0.3.66.tar.gz/src/modules/module-protocol-pulse/cmd.c
Changed
@@ -76,7 +76,10 @@ /* * pulse.cmd = - * { cmd = <command> args = "<arguments>" } + * { cmd = <command> + * ( args = "<arguments>" ) + * ( flags = ( nofail ) ) + * } * ... * */
View file
pipewire-0.3.66.tar.gz/src/modules/module-rt
Added
+(directory)
View file
pipewire-0.3.66.tar.gz/src/modules/module-rt/20-pw-defaults.conf.in
Added
@@ -0,0 +1,20 @@ +# This file was installed by PipeWire project for buffer locking to always work + +# Required to memlock audio buffers for all client types +# +# This will match all PAM users i.e. those going through the login procedure but +# it should not get applied to system daemons, since they are run bypassing PAM. +# +# While at first glance this might appear very relevant, in fact abusing this +# can at most allow for either more rapid OOM or enhance malicious system memory +# thrashing while evading systemd-oomd limits that are based on the requirement +# that swap utilization must be high before issues arise. As such it's perfectly +# reasonable to just set a limit where each client can lock a few megabytes with +# nearly no impact on regular systems. Meanwhile malicious attackers can OOM +# just as they could. And instead tooling for OOM and resource abuse should be +# improved, if such denial of service attacks are a serious consideration at all. +# +# Starting with Linux 5.16 or systemd v253 the default is 8192 which is plenty +# good enough and this file should not be installed on such systems. +# +* - memlock @PAM_MEMLOCK@
View file
pipewire-0.3.66.tar.gz/src/modules/module-rt/25-pw-rlimits.conf.in
Added
@@ -0,0 +1,8 @@ +# This file was installed by PipeWire project for its libpipewire-module-rt.so + +# It's believed to be acceptable to have match rules that will never be true +# i.e. a group that does not exist. +# +@MATCH@ - rtprio @RTPRIO@ +@MATCH@ - nice @NICE@ +@MATCH@ - memlock @MEMLOCK@
View file
pipewire-0.3.66.tar.gz/src/modules/module-rt/meson.build
Added
@@ -0,0 +1,23 @@ +rlimits_install = get_option('rlimits-install') +rlimits_data = configuration_data() +rlimits_data.set('MATCH', get_option('rlimits-match')) +rlimits_data.set('RTPRIO', get_option('rlimits-rtprio')) +rlimits_data.set('NICE', get_option('rlimits-nice')) +rlimits_data.set('MEMLOCK', get_option('rlimits-memlock')) +configure_file(input: '25-pw-rlimits.conf.in', + output: '25-pw-rlimits.conf', + install: rlimits_install, + install_dir: get_option('sysconfdir') / 'security' / 'limits.d', + configuration: rlimits_data) +summary({'RLIMITs': '@0@ limits.d file affecting matching PAM users'.format(rlimits_install ? 'with' : 'without')}) + +# The pam-defaults-install related code can be removed once all Linux <5.16 kernels are EOL (projected Dec, 2026) +pam_defaults_install = get_option('pam-defaults-install') +pam_defaults_data = configuration_data() +pam_defaults_data.set('PAM_MEMLOCK', get_option('pam-memlock-default')) +configure_file(input: '20-pw-defaults.conf.in', + output: '20-pw-defaults.conf', + install: pam_defaults_install, + install_dir: get_option('sysconfdir') / 'security' / 'limits.d', + configuration: pam_defaults_data) +summary({'PAM defaults': '@0@ limits.d file affecting all PAM users (not needed with modern systemd or kernel)'.format(pam_defaults_install ? 'with' : 'without')})
View file
pipewire-0.3.65.tar.gz/src/modules/module-rtp-sink.c -> pipewire-0.3.66.tar.gz/src/modules/module-rtp-sink.c
Changed
@@ -70,6 +70,8 @@ * - `sess.min-ptime = <int>`: minimum packet time in milliseconds, default 2 * - `sess.max-ptime = <int>`: maximum packet time in milliseconds, default 20 * - `sess.name = <str>`: a session name + * - `sess.ts-offset = <int>`: an offset to apply to the timestamp, default -1 = random offset + * - `sess.ts-refclk = <string>`: the name of a reference clock * - `stream.props = {}`: properties to be passed to the stream * * ## General options @@ -149,6 +151,7 @@ #define DEFAULT_MIN_PTIME 2 #define DEFAULT_MAX_PTIME 20 +#define DEFAULT_TS_OFFSET -1 #define USAGE "sap.ip=<SAP IP address to send announce, default:"DEFAULT_SAP_IP"> " \ "sap.port=<SAP port to send on, default:"SPA_STRINGIFY(DEFAULT_SAP_PORT)"> " \ @@ -212,6 +215,8 @@ struct pw_stream *stream; struct spa_hook stream_listener; + struct spa_io_position *io_position; + unsigned int do_disconnect:1; char *ifname; @@ -220,9 +225,9 @@ int mtu; bool ttl; bool mcast_loop; - uint32_t min_ptime; - uint32_t max_ptime; - uint32_t pbytes; + float min_ptime; + float max_ptime; + uint32_t psamples; struct sockaddr_storage src_addr; socklen_t src_len; @@ -240,17 +245,20 @@ struct spa_audio_info_raw info; const struct format_info *format_info; - uint32_t frame_size; + uint32_t stride; int payload; uint16_t seq; - uint32_t timestamp; uint32_t ssrc; + uint32_t ts_offset; + char ts_refclk64; struct spa_ringbuffer ring; uint8_t bufferBUFFER_SIZE; int rtp_fd; int sap_fd; + + unsigned sync:1; }; @@ -274,20 +282,21 @@ static void flush_packets(struct impl *impl) { int32_t avail; - uint32_t index; + uint32_t stride, timestamp; struct iovec iov3; struct msghdr msg; ssize_t n; struct rtp_header header; int32_t tosend; - avail = spa_ringbuffer_get_read_index(&impl->ring, &index); - - tosend = impl->pbytes; + avail = spa_ringbuffer_get_read_index(&impl->ring, ×tamp); + tosend = impl->psamples; if (avail < tosend) return; + stride = impl->stride; + spa_zero(header); header.v = 2; header.pt = impl->payload; @@ -306,13 +315,14 @@ while (avail >= tosend) { header.sequence_number = htons(impl->seq); - header.timestamp = htonl(impl->timestamp); + header.timestamp = htonl(impl->ts_offset + timestamp); set_iovec(&impl->ring, impl->buffer, BUFFER_SIZE, - index & BUFFER_MASK, - &iov1, tosend); + (timestamp * stride) & BUFFER_MASK, + &iov1, tosend * stride); + pw_log_trace("sending %d timestamp:%d", tosend, timestamp); n = sendmsg(impl->rtp_fd, &msg, MSG_NOSIGNAL); if (n < 0) { switch (errno) { @@ -321,18 +331,18 @@ pw_log_debug("remote end not listening"); break; default: - pw_log_warn("sendmsg() failed: %m"); + pw_log_warn("sendmsg() failed, seq:%u dropped: %m", + impl->seq); break; } } impl->seq++; - impl->timestamp += tosend / impl->frame_size; - index += tosend; + timestamp += tosend; avail -= tosend; } - spa_ringbuffer_read_update(&impl->ring, index); + spa_ringbuffer_read_update(&impl->ring, timestamp); } static void stream_process(void *data) @@ -340,8 +350,8 @@ struct impl *impl = data; struct pw_buffer *buf; struct spa_data *d; - uint32_t index; - int32_t filled, wanted; + uint32_t offs, size, timestamp, expected_timestamp, stride; + int32_t filled, wanted; if ((buf = pw_stream_dequeue_buffer(impl->stream)) == NULL) { pw_log_debug("Out of stream buffers: %m"); @@ -349,27 +359,56 @@ } d = buf->buffer->datas; - wanted = d0.chunk->size; + offs = SPA_MIN(d0.chunk->offset, d0.maxsize); + size = SPA_MIN(d0.chunk->size, d0.maxsize - offs); + stride = impl->stride; + wanted = size / stride; + + filled = spa_ringbuffer_get_write_index(&impl->ring, &expected_timestamp); + if (SPA_LIKELY(impl->io_position)) + timestamp = impl->io_position->clock.position; + else + timestamp = expected_timestamp; + + if (impl->sync) { + if (expected_timestamp != timestamp) { + pw_log_warn("expected %u != timestamp %u", expected_timestamp, timestamp); + impl->sync = false; + } else if (filled + wanted > (int32_t)(BUFFER_SIZE / stride)) { + pw_log_warn("overrun %u + %u > %u", filled, wanted, BUFFER_SIZE / stride); + impl->sync = false; + } + } + if (!impl->sync) { + pw_log_info("sync to timestamp %u", timestamp); + impl->ring.readindex = impl->ring.writeindex = timestamp; + memset(impl->buffer, 0, BUFFER_SIZE); + impl->sync = true; + } - filled = spa_ringbuffer_get_write_index(&impl->ring, &index); + spa_ringbuffer_write_data(&impl->ring, + impl->buffer, + BUFFER_SIZE, + (timestamp * stride) & BUFFER_MASK, + SPA_PTROFF(d0.data, offs, void), wanted * stride); + timestamp += wanted; + spa_ringbuffer_write_update(&impl->ring, timestamp); - if (filled + wanted > (int32_t)BUFFER_SIZE) { - pw_log_warn("overrun %u + %u > %u", filled, wanted, BUFFER_SIZE); - } else { - spa_ringbuffer_write_data(&impl->ring, - impl->buffer, - BUFFER_SIZE, - index & BUFFER_MASK, - d0.data, wanted); - - index += wanted; - spa_ringbuffer_write_update(&impl->ring, index); - } pw_stream_queue_buffer(impl->stream, buf); flush_packets(impl); } +static void stream_io_changed(void *data, uint32_t id, void *area, uint32_t size) +{ + struct impl *impl = data; + switch (id) { + case SPA_IO_Position: + impl->io_position = area; + break; + } +} + static void on_stream_state_changed(void *d, enum pw_stream_state old, enum pw_stream_state state, const char *error) { @@ -383,6 +422,9 @@ case PW_STREAM_STATE_ERROR: pw_log_error("stream error: %s", error); break; + case PW_STREAM_STATE_PAUSED: + impl->sync = false; + break; default: break; } @@ -391,6 +433,7 @@ static const struct pw_stream_events in_stream_events = { PW_VERSION_STREAM_EVENTS, .destroy = stream_destroy, + .io_changed = stream_io_changed, .state_changed = on_stream_state_changed, .process = stream_process }; @@ -463,6 +506,7 @@ if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &val, sizeof(val)) < 0) pw_log_warn("setsockopt(SO_PRIORITY) failed: %m"); #endif + /* FIXME AES67 wants IPTOS_DSCP_AF41 */ val = IPTOS_LOWDELAY; if (setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) pw_log_warn("setsockopt(IP_TOS) failed: %m"); @@ -489,8 +533,7 @@ if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL) { pw_properties_setf(props, PW_KEY_NODE_LATENCY, - "%d/%d", impl->pbytes / impl->frame_size, - impl->info.rate); + "%d/%d", impl->psamples, impl->info.rate); } pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", impl->info.rate); @@ -548,6 +591,7 @@ struct sap_header header; struct iovec iov4; struct msghdr msg; + struct spa_strbuf buf; spa_zero(header); header.v = 1; @@ -580,7 +624,8 @@ if (is_multicast((struct sockaddr*)&impl->dst_addr, impl->dst_len)) snprintf(dst_ttl, sizeof(dst_ttl), "/%d", impl->ttl); - snprintf(buffer, sizeof(buffer), + spa_strbuf_init(&buf, buffer, sizeof(buffer)); + spa_strbuf_append(&buf, "v=0\n" "o=%s %u 0 IN %s %s\n" "s=%s\n" @@ -600,7 +645,17 @@ impl->port, impl->payload, impl->payload, impl->format_info->mime, impl->info.rate, impl->info.channels, - (impl->pbytes / impl->frame_size) * 1000 / impl->info.rate); + impl->psamples * 1000 / impl->info.rate); + + if (impl->ts_refclk0 != '\0') { + spa_strbuf_append(&buf, + "a=ts-refclk:%s\n" + "a=mediaclk:direct=%u\n", + impl->ts_refclk, + impl->ts_offset); + } else { + spa_strbuf_append(&buf, "a=mediaclk:sender\n"); + } iov3.iov_base = buffer; iov3.iov_len = strlen(buffer); @@ -793,7 +848,8 @@ struct impl *impl; struct pw_properties *props = NULL, *stream_props = NULL; uint32_t id = pw_global_get_id(pw_impl_module_get_global(module)); - uint32_t pid = getpid(), port, min_bytes, max_bytes; + uint32_t pid = getpid(), port, min_samples, max_samples; + int64_t ts_offset; char addr64; const char *str; int res = 0; @@ -867,13 +923,12 @@ res = -EINVAL; goto out; } - impl->frame_size = impl->format_info->size * impl->info.channels; + impl->stride = impl->format_info->size * impl->info.channels; impl->msg_id_hash = rand(); impl->ntp = (uint32_t) time(NULL) + 2208988800U; impl->payload = 127; impl->seq = rand(); - impl->timestamp = rand(); impl->ssrc = rand(); str = pw_properties_get(props, "local.ifname"); @@ -907,14 +962,25 @@ impl->ttl = pw_properties_get_uint32(props, "net.ttl", DEFAULT_TTL); impl->mcast_loop = pw_properties_get_bool(props, "net.loop", DEFAULT_LOOP); - impl->min_ptime = pw_properties_get_uint32(props, "sess.min-ptime", DEFAULT_MIN_PTIME); - impl->max_ptime = pw_properties_get_uint32(props, "sess.max-ptime", DEFAULT_MAX_PTIME); + ts_offset = pw_properties_get_int64(props, "sess.ts-offset", DEFAULT_TS_OFFSET); + impl->ts_offset = ts_offset < 0 ? rand() : ts_offset; + + str = pw_properties_get(props, "sess.ts-refclk"); + if (str != NULL) + snprintf(impl->ts_refclk, sizeof(impl->ts_refclk), "%s", str); + + str = pw_properties_get(props, "sess.min-ptime"); + if (!spa_atof(str, &impl->min_ptime)) + impl->min_ptime = DEFAULT_MIN_PTIME; + str = pw_properties_get(props, "sess.max-ptime"); + if (!spa_atof(str, &impl->max_ptime)) + impl->max_ptime = DEFAULT_MAX_PTIME; - min_bytes = (impl->min_ptime * impl->info.rate / 1000) * impl->frame_size; - max_bytes = (impl->max_ptime * impl->info.rate / 1000) * impl->frame_size; + min_samples = impl->min_ptime * impl->info.rate / 1000; + max_samples = impl->max_ptime * impl->info.rate / 1000; - impl->pbytes = SPA_ROUND_DOWN(impl->mtu, impl->frame_size); - impl->pbytes = SPA_CLAMP(impl->pbytes, min_bytes, max_bytes); + impl->psamples = impl->mtu / impl->stride; + impl->psamples = SPA_CLAMP(impl->psamples, min_samples, max_samples); if ((str = pw_properties_get(props, "sess.name")) == NULL) pw_properties_setf(props, "sess.name", "PipeWire RTP Stream on %s", @@ -931,7 +997,7 @@ pw_properties_setf(stream_props, "rtp.mtu", "%u", impl->mtu); pw_properties_setf(stream_props, "rtp.ttl", "%u", impl->ttl); pw_properties_setf(stream_props, "rtp.ptime", "%u", - (impl->pbytes / impl->frame_size) * 1000 / impl->info.rate); + impl->psamples * 1000 / impl->info.rate); impl->core = pw_context_get_object(impl->module_context, PW_TYPE_INTERFACE_Core); if (impl->core == NULL) {
View file
pipewire-0.3.65.tar.gz/src/modules/module-rtp-source.c -> pipewire-0.3.66.tar.gz/src/modules/module-rtp-source.c
Changed
@@ -25,6 +25,7 @@ #include "config.h" #include <limits.h> +#include <string.h> #include <unistd.h> #include <sys/stat.h> #include <sys/socket.h> @@ -84,6 +85,7 @@ * #sap.port = 9875 * #local.ifname = eth0 * sess.latency.msec = 100 + * #node.always-process = false # true to receive even when not running * stream.props = { * #media.class = "Audio/Source" * #node.name = "rtp-source" @@ -97,11 +99,14 @@ * #rtp.payload = "127" * #rtp.fmt = "L16/48000/2" * #rtp.session = "PipeWire RTP Stream on fedora" + * #rtp.ts-offset = 0 + * #rtp.ts-refclk = "private" * } * * actions = { * create-stream = { * #sess.latency.msec = 100 + * #sess.ts-direct = false * #target.object = "" * } * } @@ -169,6 +174,7 @@ char *ifname; char *sap_ip; + bool always_process; int sap_port; int sess_latency_msec; uint32_t cleanup_interval; @@ -202,6 +208,7 @@ char origin128; char session256; + char channelmap512; struct sockaddr_storage sa; socklen_t salen; @@ -212,6 +219,9 @@ const struct format_info *format_info; struct spa_audio_info_raw info; uint32_t stride; + + uint32_t ts_offset; + char refclk64; }; struct session { @@ -237,12 +247,13 @@ uint8_t bufferBUFFER_SIZE; struct spa_io_rate_match *rate_match; + struct spa_io_position *position; struct spa_dll dll; uint32_t target_buffer; - uint32_t last_packet_size; float max_error; - unsigned buffering:1; unsigned first:1; + unsigned receiving:1; + unsigned direct_timestamp:1; }; static void stream_destroy(void *d) @@ -257,8 +268,8 @@ struct session *sess = data; struct pw_buffer *buf; struct spa_data *d; - uint32_t index, target_buffer; - int32_t avail, wanted; + uint32_t wanted, timestamp, target_buffer, stride, maxsize; + int32_t avail; if ((buf = pw_stream_dequeue_buffer(sess->stream)) == NULL) { pw_log_debug("Out of stream buffers: %m"); @@ -266,38 +277,53 @@ } d = buf->buffer->datas; - wanted = buf->requested ? - SPA_MIN(buf->requested * sess->info.stride, d0.maxsize) - : d0.maxsize; + stride = sess->info.stride; - avail = spa_ringbuffer_get_read_index(&sess->ring, &index); + maxsize = d0.maxsize / stride; + wanted = buf->requested ? SPA_MIN(buf->requested, maxsize) : maxsize; - target_buffer = sess->target_buffer + sess->last_packet_size / 2; + if (sess->position && sess->direct_timestamp) { + /* in direct mode, read directly from the timestamp index, + * because sender and receiver are in sync, this would keep + * target_buffer of bytes available. */ + spa_ringbuffer_read_update(&sess->ring, + sess->position->clock.position); + } + avail = spa_ringbuffer_get_read_index(&sess->ring, ×tamp); - if (avail < wanted || sess->buffering) { - memset(d0.data, 0, wanted); - if (!sess->buffering && sess->have_sync) { - pw_log_debug("underrun %u/%u < %u, buffering...", - avail, target_buffer, wanted); - sess->buffering = true; + target_buffer = sess->target_buffer; + + if (avail < (int32_t)wanted) { + enum spa_log_level level; + memset(d0.data, 0, wanted * stride); + if (sess->have_sync) { + sess->have_sync = false; + level = SPA_LOG_LEVEL_WARN; + } else { + level = SPA_LOG_LEVEL_DEBUG; } + pw_log(level, "underrun %d/%u < %u", + avail, target_buffer, wanted); } else { float error, corr; - if (avail > (int32_t)SPA_MIN(target_buffer * 8, BUFFER_SIZE)) { + if (avail > (int32_t)SPA_MIN(target_buffer * 8, BUFFER_SIZE / stride)) { pw_log_warn("overrun %u > %u", avail, target_buffer * 8); - index += avail - target_buffer; + timestamp += avail - target_buffer; avail = target_buffer; - } else { - if (sess->first) { - if ((uint32_t)avail > target_buffer) { - uint32_t skip = avail - target_buffer; - pw_log_debug("first: avail:%d skip:%u target:%u", + } else if (sess->first) { + if ((uint32_t)avail > target_buffer) { + uint32_t skip = avail - target_buffer; + pw_log_debug("first: avail:%d skip:%u target:%u", avail, skip, target_buffer); - index += skip; - avail = target_buffer; - } - sess->first = false; + timestamp += skip; + avail = target_buffer; } + sess->first = false; + } + if (!sess->direct_timestamp) { + /* when not using direct timestamp and clocks are not + * in sync, try to adjust our playback rate to keep the + * requested target_buffer bytes in the ringbuffer */ error = (float)target_buffer - (float)avail; error = SPA_CLAMP(error, -sess->max_error, sess->max_error); @@ -307,46 +333,28 @@ target_buffer, error, corr); if (sess->rate_match) { - SPA_FLAG_SET(sess->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE); + SPA_FLAG_SET(sess->rate_match->flags, + SPA_IO_RATE_MATCH_FLAG_ACTIVE); sess->rate_match->rate = 1.0f / corr; } } spa_ringbuffer_read_data(&sess->ring, sess->buffer, BUFFER_SIZE, - index & BUFFER_MASK, - d0.data, wanted); + (timestamp * stride) & BUFFER_MASK, + d0.data, wanted * stride); - index += wanted; - spa_ringbuffer_read_update(&sess->ring, index); + timestamp += wanted; + spa_ringbuffer_read_update(&sess->ring, timestamp); } - d0.chunk->size = wanted; - d0.chunk->stride = sess->info.stride; + d0.chunk->size = wanted * stride; + d0.chunk->stride = stride; d0.chunk->offset = 0; - buf->size = wanted / sess->info.stride; + buf->size = wanted; pw_stream_queue_buffer(sess->stream, buf); } -static void on_stream_state_changed(void *d, enum pw_stream_state old, - enum pw_stream_state state, const char *error) -{ - struct session *sess = d; - struct impl *impl = sess->impl; - - switch (state) { - case PW_STREAM_STATE_UNCONNECTED: - pw_log_info("stream disconnected, unloading"); - pw_impl_module_schedule_destroy(impl->module); - break; - case PW_STREAM_STATE_ERROR: - pw_log_error("stream error: %s", error); - break; - default: - break; - } -} - static void stream_io_changed(void *data, uint32_t id, void *area, uint32_t size) { struct session *sess = data; @@ -354,16 +362,18 @@ case SPA_IO_RateMatch: sess->rate_match = area; break; + case SPA_IO_Position: + sess->position = area; + break; } } -static const struct pw_stream_events out_stream_events = { - PW_VERSION_STREAM_EVENTS, - .destroy = stream_destroy, - .state_changed = on_stream_state_changed, - .io_changed = stream_io_changed, - .process = stream_process -}; +static void session_touch(struct session *sess) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + sess->timestamp = SPA_TIMESPEC_TO_NSEC(&ts); +} static void on_rtp_io(void *data, int fd, uint32_t mask) @@ -374,7 +384,7 @@ uint8_t buffer2048, *payload; if (mask & SPA_IO_IN) { - uint32_t index, expected_index, timestamp; + uint32_t stride, read, timestamp, expected_timestamp, samples; uint16_t seq; int32_t filled; @@ -399,65 +409,54 @@ seq = ntohs(hdr->sequence_number); if (sess->have_seq && sess->expected_seq != seq) { - pw_log_warn("unexpected seq (%d != %d)", seq, sess->expected_seq); + pw_log_info("unexpected seq (%d != %d)", seq, sess->expected_seq); + sess->have_sync = false; } sess->expected_seq = seq + 1; sess->have_seq = true; - len = SPA_ROUND_DOWN(len - hlen, sess->info.stride); + stride = sess->info.stride; + samples = (len - hlen) / stride; payload = &bufferhlen; - filled = spa_ringbuffer_get_write_index(&sess->ring, &index); + filled = spa_ringbuffer_get_write_index(&sess->ring, &expected_timestamp); - timestamp = ntohl(hdr->timestamp); - expected_index = timestamp * sess->info.stride; + read = ntohl(hdr->timestamp) - sess->info.ts_offset; + /* we always write to timestamp + delay */ + timestamp = read + sess->target_buffer; if (!sess->have_sync) { - pw_log_trace("got rtp, no sync"); - sess->ring.readindex = sess->ring.writeindex = - index = expected_index; - filled = 0; - sess->have_sync = true; - sess->buffering = true; - pw_log_debug("sync to timestamp %u", index); + pw_log_info("sync to timestamp %u", read); + /* we read from timestamp, keeping target_buffer of data + * in the ringbuffer. */ + sess->ring.readindex = read; + sess->ring.writeindex = timestamp; + filled = sess->target_buffer; spa_dll_init(&sess->dll); spa_dll_set_bw(&sess->dll, SPA_DLL_BW_MIN, 128, sess->info.info.rate); - - } else if (expected_index != index) { - pw_log_trace("got rtp, wrong timestamp"); + memset(sess->buffer, 0, BUFFER_SIZE); + sess->have_sync = true; + } else if (expected_timestamp != timestamp) { pw_log_debug("unexpected timestamp (%u != %u)", - index / sess->info.stride, - expected_index / sess->info.stride); - index = expected_index; - filled = 0; + timestamp, expected_timestamp); } - if (filled + len > BUFFER_SIZE) { - pw_log_debug("got rtp, capture overrun %u %zd", filled, len); + if (filled + samples > BUFFER_SIZE / stride) { + pw_log_debug("capture overrun %u + %u > %u", filled, samples, + BUFFER_SIZE / stride); sess->have_sync = false; } else { - uint32_t target_buffer; - - pw_log_trace("got rtp packet len:%zd", len); + pw_log_trace("got samples:%u", samples); spa_ringbuffer_write_data(&sess->ring, sess->buffer, BUFFER_SIZE, - index & BUFFER_MASK, - payload, len); - index += len; - filled += len; - spa_ringbuffer_write_update(&sess->ring, index); - - sess->last_packet_size = len; - target_buffer = sess->target_buffer + len/2; - - if (sess->buffering && (uint32_t)filled > target_buffer) { - sess->buffering = false; - pw_log_debug("buffering done %u > %u", - filled, target_buffer); - } + (timestamp * stride) & BUFFER_MASK, + payload, (samples * stride)); + timestamp += samples; + spa_ringbuffer_write_update(&sess->ring, timestamp); } + sess->receiving = true; } return; @@ -556,16 +555,9 @@ return res; } -static uint32_t msec_to_bytes(struct sdp_info *info, uint32_t msec) -{ - return msec * info->stride * info->info.rate / 1000; -} - -static void session_touch(struct session *sess) +static uint32_t msec_to_samples(struct sdp_info *info, uint32_t msec) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - sess->timestamp = SPA_TIMESPEC_TO_NSEC(&ts); + return msec * info->info.rate / 1000; } static void session_free(struct session *sess) @@ -601,6 +593,78 @@ return res; } +static int session_start(struct impl *impl, struct session *session) { + int fd; + if (session->source) + return 0; + + pw_log_info("starting RTP listener"); + + if ((fd = make_socket((const struct sockaddr *)&session->info.sa, + session->info.salen, impl->ifname)) < 0) { + pw_log_error("failed to create socket: %m"); + return fd; + } + + session->source = pw_loop_add_io(impl->data_loop, fd, + SPA_IO_IN, true, on_rtp_io, session); + if (session->source == NULL) { + pw_log_error("can't create io source: %m"); + close(fd); + return -errno; + } + return 0; +} + +static void session_stop(struct impl *impl, struct session *session) { + if (!session->source) + return; + + pw_log_info("stopping RTP listener"); + + pw_loop_destroy_source( + session->impl->data_loop, + session->source + ); + + session->source = NULL; +} + +static void on_stream_state_changed(void *d, enum pw_stream_state old, + enum pw_stream_state state, const char *error) +{ + struct session *sess = d; + struct impl *impl = sess->impl; + + switch (state) { + case PW_STREAM_STATE_UNCONNECTED: + pw_log_info("stream disconnected, unloading"); + pw_impl_module_schedule_destroy(impl->module); + break; + case PW_STREAM_STATE_ERROR: + pw_log_error("stream error: %s", error); + break; + case PW_STREAM_STATE_STREAMING: + if ((errno = -session_start(impl, sess)) < 0) + pw_log_error("failed to start RTP stream: %m"); + break; + case PW_STREAM_STATE_PAUSED: + if (!impl->always_process) + session_stop(impl, sess); + break; + default: + break; + } +} + +static const struct pw_stream_events out_stream_events = { + PW_VERSION_STREAM_EVENTS, + .destroy = stream_destroy, + .state_changed = on_stream_state_changed, + .io_changed = stream_io_changed, + .process = stream_process +}; + static int session_new(struct impl *impl, struct sdp_info *info) { struct session *session; @@ -609,7 +673,7 @@ uint32_t n_params; uint8_t buffer1024; struct pw_properties *props; - int res, fd, sess_latency_msec; + int res, sess_latency_msec; const char *str; if (impl->n_sessions >= MAX_SESSIONS) { @@ -643,6 +707,8 @@ } else { pw_properties_set(props, PW_KEY_MEDIA_NAME, "RTP Stream"); } + pw_properties_setf(props, "rtp.ts-offset", "%u", info->ts_offset); + pw_properties_set(props, "rtp.ts-refclk", info->refclk); if ((str = pw_properties_get(impl->props, "stream.rules")) != NULL) { struct session_info sinfo = { @@ -658,22 +724,29 @@ goto error; } } + session->direct_timestamp = pw_properties_get_bool(props, "sess.ts-direct", false); - pw_log_info("new session %s %s", info->origin, info->session); + pw_log_info("new session %s %s direct:%d", info->origin, info->session, + session->direct_timestamp); sess_latency_msec = pw_properties_get_uint32(props, "sess.latency.msec", impl->sess_latency_msec); - session->target_buffer = msec_to_bytes(info, sess_latency_msec); - session->max_error = msec_to_bytes(info, ERROR_MSEC); + session->target_buffer = msec_to_samples(info, sess_latency_msec); + session->max_error = msec_to_samples(info, ERROR_MSEC); pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%d", info->info.rate); pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%d/%d", - session->target_buffer / (2 * info->stride), info->info.rate); + session->target_buffer / 2, info->info.rate); spa_dll_init(&session->dll); spa_dll_set_bw(&session->dll, SPA_DLL_BW_MIN, 128, session->info.info.rate); + if (info->channelmap0) { + pw_properties_set(props, PW_KEY_NODE_CHANNELNAMES, info->channelmap); + pw_log_info("channelmap: %s", info->channelmap); + } + session->stream = pw_stream_new(impl->core, "rtp-source playback", props); if (session->stream == NULL) { @@ -702,21 +775,10 @@ goto error; } - if ((fd = make_socket((const struct sockaddr *)&info->sa, - info->salen, impl->ifname)) < 0) { - res = fd; + if (impl->always_process && + (res = session_start(impl, session)) < 0) goto error; - } - session->source = pw_loop_add_io(impl->data_loop, fd, - SPA_IO_IN, true, on_rtp_io, session); - if (session->source == NULL) { - res = -errno; - pw_log_error("can't create io source: %m"); - goto error; - } - - pw_log_info("starting RTP listener"); session_touch(session); session->impl = impl; @@ -801,7 +863,32 @@ return 0; } -static int parse_sdp_a(struct impl *impl, char *c, struct sdp_info *info) +// some AES67 devices have channelmap encoded in i=* +// if `i` record is found, it matches the template +// and channel count matches, name the channels respectively +// `i=2 channels: 01, 08` is the format +static int parse_sdp_i(struct impl *impl, char *c, struct sdp_info *info) +{ + if (!strstr(c, " channels: ")) { + return 0; + } + + c += strlen("i="); + cstrcspn(c, " ") = '\0'; + + uint32_t channels; + if (sscanf(c, "%u", &channels) != 1 || channels <= 0 || channels > SPA_AUDIO_MAX_CHANNELS) + return 0; + + c += strcspn(c, "\0"); + c += strlen(" channels: "); + + strncpy(info->channelmap, c, sizeof(info->channelmap) - 1); + + return 0; +} + +static int parse_sdp_a_rtpmap(struct impl *impl, char *c, struct sdp_info *info) { int payload, len, rate, channels; @@ -833,6 +920,7 @@ if (sscanf(c, "%u/%u", &rate, &channels) == 2) { info->info.rate = rate; info->info.channels = channels; + pw_log_debug("rate: %d, ch: %d", rate, channels); if (channels == 2) { info->info.position0 = SPA_AUDIO_CHANNEL_FL; info->info.position1 = SPA_AUDIO_CHANNEL_FR; @@ -848,6 +936,35 @@ return 0; } +static int parse_sdp_a_mediaclk(struct impl *impl, char *c, struct sdp_info *info) +{ + if (!spa_strstartswith(c, "a=mediaclk:")) + return 0; + + c += strlen("a=mediaclk:"); + + if (spa_strstartswith(c, "direct=")) { + int offset; + c += strlen("direct="); + if (sscanf(c, "%i", &offset) != 1) + return -EINVAL; + info->ts_offset = offset; + } else if (spa_strstartswith(c, "sender")) { + info->ts_offset = 0; + } + return 0; +} + +static int parse_sdp_a_ts_refclk(struct impl *impl, char *c, struct sdp_info *info) +{ + if (!spa_strstartswith(c, "a=ts-refclk:")) + return 0; + + c += strlen("a=ts-refclk:"); + snprintf(info->refclk, sizeof(info->refclk), "%s", c); + return 0; +} + static int parse_sdp(struct impl *impl, char *sdp, struct sdp_info *info) { char *s = sdp; @@ -872,8 +989,14 @@ res = parse_sdp_c(impl, s, info); else if (spa_strstartswith(s, "m=")) res = parse_sdp_m(impl, s, info); - else if (spa_strstartswith(s, "a=")) - res = parse_sdp_a(impl, s, info); + else if (spa_strstartswith(s, "a=rtpmap:")) + res = parse_sdp_a_rtpmap(impl, s, info); + else if (spa_strstartswith(s, "a=mediaclk:")) + res = parse_sdp_a_mediaclk(impl, s, info); + else if (spa_strstartswith(s, "a=ts-refclk:")) + res = parse_sdp_a_ts_refclk(impl, s, info); + else if (spa_strstartswith(s, "i=")) + res = parse_sdp_i(impl, s, info); if (res < 0) goto error; @@ -1027,10 +1150,16 @@ spa_list_for_each_safe(sess, tmp, &impl->sessions, link) { if (sess->timestamp + interval < timestamp) { - pw_log_debug("More than %lu elapsed from last advertisement at %lu", interval, sess->timestamp); - pw_log_info("No advertisement packets found for timeout, closing RTP source"); - session_free(sess); + pw_log_debug("More than %lu elapsed from last advertisement at %lu", + interval, sess->timestamp); + if (!sess->receiving) { + pw_log_info("SAP timeout, closing inactive RTP source"); + session_free(sess); + } else { + pw_log_info("SAP timeout, keeping active RTP source"); + } } + sess->receiving = false; } } @@ -1140,6 +1269,8 @@ str = pw_properties_get(impl->props, "local.ifname"); impl->ifname = str ? strdup(str) : NULL; + impl->always_process = pw_properties_get_bool(impl->props, PW_KEY_NODE_ALWAYS_PROCESS, false); + str = pw_properties_get(impl->props, "sap.ip"); impl->sap_ip = strdup(str ? str : DEFAULT_SAP_IP); impl->sap_port = pw_properties_get_uint32(impl->props,
View file
pipewire-0.3.65.tar.gz/src/pipewire/conf.c -> pipewire-0.3.66.tar.gz/src/pipewire/conf.c
Changed
@@ -605,10 +605,70 @@ } /* + * { + * # all keys must match the value. ~ in value starts regex. + * <key> = <value> + * ... + * } + */ +static bool find_match(struct spa_json *arr, const struct spa_dict *props) +{ + struct spa_json it1; + + while (spa_json_enter_object(arr, &it0) > 0) { + char key256, val1024; + const char *str, *value; + int match = 0, fail = 0; + int len; + + while (spa_json_get_string(&it0, key, sizeof(key)) > 0) { + bool success = false; + + if ((len = spa_json_next(&it0, &value)) <= 0) + break; + + str = spa_dict_lookup(props, key); + + if (spa_json_is_null(value, len)) { + success = str == NULL; + } else { + if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0) + continue; + value = val; + len = strlen(val); + } + if (str != NULL) { + if (value0 == '~') { + regex_t preg; + if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) { + if (regexec(&preg, str, 0, NULL, 0) == 0) + success = true; + regfree(&preg); + } + } else if (strncmp(str, value, len) == 0 && + strlen(str) == (size_t)len) { + success = true; + } + } + if (success) { + match++; + pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value); + } + else + fail++; + } + if (match > 0 && fail == 0) + return true; + } + return false; +} + +/* * context.modules = * { name = <module-name> - * args = { <key> = <value> ... } - * flags = ifexists nofail + * ( args = { <key> = <value> ... } ) + * ( flags = ( ifexists ) ( nofail ) + * ( condition = { key = value, .. } .. ) * } * */ @@ -617,7 +677,7 @@ { struct data *d = user_data; struct pw_context *context = d->context; - struct spa_json it3; + struct spa_json it4; char key512, *s; int res = 0; @@ -631,6 +691,7 @@ while (spa_json_enter_object(&it1, &it2) > 0) { char *name = NULL, *args = NULL, *flags = NULL; + bool have_match = true; while (spa_json_get_string(&it2, key, sizeof(key)) > 0) { const char *val; @@ -653,8 +714,16 @@ len = spa_json_container_len(&it2, val, len); flags = (char*)val; spa_json_parse_stringn(val, len, flags, len+1); + } else if (spa_streq(key, "condition")) { + if (!spa_json_is_array(val, len)) + break; + spa_json_enter(&it2, &it3); + have_match = find_match(&it3, &context->properties->dict); } } + if (!have_match) + continue; + if (name != NULL) res = load_module(context, name, args, flags); @@ -698,8 +767,9 @@ /* * context.objects = * { factory = <factory-name> - * args = { <key> = <value> ... } - * flags = nofail + * ( args = { <key> = <value> ... } ) + * ( flags = ( nofail ) ) + * ( condition = { key = value, .. } .. ) * } * */ @@ -708,7 +778,7 @@ { struct data *d = user_data; struct pw_context *context = d->context; - struct spa_json it3; + struct spa_json it4; char key512, *s; int res = 0; @@ -722,6 +792,7 @@ while (spa_json_enter_object(&it1, &it2) > 0) { char *factory = NULL, *args = NULL, *flags = NULL; + bool have_match = true; while (spa_json_get_string(&it2, key, sizeof(key)) > 0) { const char *val; @@ -745,8 +816,16 @@ flags = (char*)val; spa_json_parse_stringn(val, len, flags, len+1); + } else if (spa_streq(key, "condition")) { + if (!spa_json_is_array(val, len)) + break; + spa_json_enter(&it2, &it3); + have_match = find_match(&it3, &context->properties->dict); } } + if (!have_match) + continue; + if (factory != NULL) res = create_object(context, factory, args, flags); @@ -807,8 +886,9 @@ /* * context.exec = - * { path = <program-name> - * args = "<arguments>" + * { path = <program-name> + * ( args = "<arguments>" ) + * ( condition = { key = value, .. } .. ) * } * */ @@ -817,7 +897,7 @@ { struct data *d = user_data; struct pw_context *context = d->context; - struct spa_json it3; + struct spa_json it4; char key512, *s; int res = 0; @@ -831,6 +911,7 @@ while (spa_json_enter_object(&it1, &it2) > 0) { char *path = NULL, *args = NULL; + bool have_match = true; while (spa_json_get_string(&it2, key, sizeof(key)) > 0) { const char *val; @@ -845,8 +926,16 @@ } else if (spa_streq(key, "args")) { args = (char*)val; spa_json_parse_stringn(val, len, args, len+1); + } else if (spa_streq(key, "condition")) { + if (!spa_json_is_array(val, len)) + break; + spa_json_enter(&it2, &it3); + have_match = find_match(&it3, &context->properties->dict); } } + if (!have_match) + continue; + if (path != NULL) res = do_exec(context, path, args); @@ -1014,65 +1103,6 @@ } -/* - * { - * # all keys must match the value. ~ in value starts regex. - * <key> = <value> - * ... - * } - */ -static bool find_match(struct spa_json *arr, const struct spa_dict *props) -{ - struct spa_json it1; - - while (spa_json_enter_object(arr, &it0) > 0) { - char key256, val1024; - const char *str, *value; - int match = 0, fail = 0; - int len; - - while (spa_json_get_string(&it0, key, sizeof(key)) > 0) { - bool success = false; - - if ((len = spa_json_next(&it0, &value)) <= 0) - break; - - str = spa_dict_lookup(props, key); - - if (spa_json_is_null(value, len)) { - success = str == NULL; - } else { - if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0) - continue; - value = val; - len = strlen(val); - } - if (str != NULL) { - if (value0 == '~') { - regex_t preg; - if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) { - if (regexec(&preg, str, 0, NULL, 0) == 0) - success = true; - regfree(&preg); - } - } else if (strncmp(str, value, len) == 0 && - strlen(str) == (size_t)len) { - success = true; - } - } - if (success) { - match++; - pw_log_debug("'%s' match '%s' < > '%.*s'", key, str, len, value); - } - else - fail++; - } - if (match > 0 && fail == 0) - return true; - } - return false; -} - /** * * {
View file
pipewire-0.3.65.tar.gz/src/pipewire/context.c -> pipewire-0.3.66.tar.gz/src/pipewire/context.c
Changed
@@ -970,15 +970,114 @@ return fa < fb ? -1 : (fa > fb ? 1 : 0); } -static uint32_t find_best_rate(const uint32_t *rates, uint32_t n_rates, uint32_t rate, uint32_t best) +static inline uint32_t calc_gcd(uint32_t a, uint32_t b) { - uint32_t i; + while (b != 0) { + uint32_t temp = a; + a = b; + b = temp % b; + } + return a; +} + +struct rate_info { + uint32_t rate; + uint32_t gcd; + uint32_t diff; +}; + +static inline void update_highest_rate(struct rate_info *best, struct rate_info *current) +{ + /* find highest rate */ + if (best->rate == 0 || best->rate < current->rate) + *best = *current; +} + +static inline void update_nearest_gcd(struct rate_info *best, struct rate_info *current) +{ + /* find nearest GCD */ + if (best->rate == 0 || + (best->gcd < current->gcd) || + (best->gcd == current->gcd && best->diff > current->diff)) + *best = *current; +} +static inline void update_nearest_rate(struct rate_info *best, struct rate_info *current) +{ + /* find nearest rate */ + if (best->rate == 0 || best->diff > current->diff) + *best = *current; +} + +static uint32_t find_best_rate(const uint32_t *rates, uint32_t n_rates, uint32_t rate, uint32_t def) +{ + uint32_t i, limit; + struct rate_info best; + struct rate_info infon_rates; + + for (i = 0; i < n_rates; i++) { + infoi.rate = ratesi; + infoi.gcd = calc_gcd(rate, ratesi); + infoi.diff = SPA_ABS((int32_t)rate - (int32_t)ratesi); + } + + /* first find higher nearest GCD. This tries to find next bigest rate that + * requires the least amount of resample filter banks. Usually these are + * rates that are multiples of eachother or multiples of a common rate. + * + * 44100 and 32000 56000 88200 96000 -> 88200 + * 48000 and 32000 56000 88200 96000 -> 96000 + * 88200 and 44100 48000 96000 192000 -> 96000 + * 32000 and 44100 192000 -> 44100 + * 8000 and 44100 48000 -> 48000 + * 8000 and 44100 192000 -> 44100 + * 11025 and 44100 48000 -> 44100 + * 44100 and 48000 176400 -> 48000 + */ + spa_zero(best); + /* Don't try to do excessive upsampling by limiting the max rate + * for desired < default to default*2. For other rates allow + * a x3 upsample rate max */ + limit = rate < def ? def*2 : rate*3; + for (i = 0; i < n_rates; i++) { + if (infoi.rate >= rate && infoi.rate <= limit) + update_nearest_gcd(&best, &infoi); + } + if (best.rate != 0) + return best.rate; + + /* we would need excessive upsampling, pick a nearest higher rate */ + spa_zero(best); + for (i = 0; i < n_rates; i++) { + if (infoi.rate >= rate) + update_nearest_rate(&best, &infoi); + } + if (best.rate != 0) + return best.rate; + + /* There is nothing above the rate, we need to downsample. Try to downsample + * but only to something that is from a common rate family. Also don't + * try to downsample to something that will sound worse (< 44100). + * + * 88200 and 22050 44100 48000 -> 44100 + * 88200 and 22050 48000 -> 48000 + */ + spa_zero(best); for (i = 0; i < n_rates; i++) { - if (SPA_ABS((int32_t)rate - (int32_t)ratesi) < - SPA_ABS((int32_t)rate - (int32_t)best)) - best = ratesi; + if (infoi.rate >= 44100) + update_nearest_gcd(&best, &infoi); } - return best; + if (best.rate != 0) + return best.rate; + + /* There is nothing to downsample above our threshold. Downsample to whatever + * is the highest rate then. */ + spa_zero(best); + for (i = 0; i < n_rates; i++) + update_highest_rate(&best, &infoi); + if (best.rate != 0) + return best.rate; + + return def; } /* here we evaluate the complete state of the graph. @@ -1201,10 +1300,12 @@ running = true; current_rate = n->current_rate.denom; - if (lock_rate || n->reconfigure || + if (lock_rate || n->reconfigure || !running || (!force_rate && (n->info.state > PW_NODE_STATE_IDLE))) /* when someone wants us to lock the rate of this driver or + * when we are in the process of reconfiguring the driver or + * when we are not running any followers or * when the driver is busy and we don't need to force a rate, * keep the current rate */ target_rate = current_rate;
View file
pipewire-0.3.65.tar.gz/src/pipewire/filter.c -> pipewire-0.3.66.tar.gz/src/pipewire/filter.c
Changed
@@ -95,15 +95,15 @@ struct pw_properties *props; - uint32_t change_mask_all; + uint64_t change_mask_all; struct spa_port_info info; struct spa_list param_list; -#define IDX_EnumFormat 0 -#define IDX_Meta 1 -#define IDX_IO 2 -#define IDX_Format 3 -#define IDX_Buffers 4 -#define IDX_Latency 5 +#define PORT_EnumFormat 0 +#define PORT_Meta 1 +#define PORT_IO 2 +#define PORT_Format 3 +#define PORT_Buffers 4 +#define PORT_Latency 5 #define N_PORT_PARAMS 6 struct spa_param_info paramsN_PORT_PARAMS; @@ -133,6 +133,7 @@ struct spa_node impl_node; struct spa_hook_list hooks; struct spa_callbacks callbacks; + struct spa_io_clock *clock; struct spa_io_position *position; struct { @@ -142,12 +143,12 @@ struct spa_list port_list; struct pw_map ports2; - uint32_t change_mask_all; + uint64_t change_mask_all; struct spa_node_info info; struct spa_list param_list; -#define IDX_PropInfo 0 -#define IDX_Props 1 -#define IDX_ProcessLatency 2 +#define NODE_PropInfo 0 +#define NODE_Props 1 +#define NODE_ProcessLatency 2 #define N_NODE_PARAMS 3 struct spa_param_info paramsN_NODE_PARAMS; @@ -168,17 +169,18 @@ unsigned int allow_mlock:1; unsigned int warn_mlock:1; unsigned int process_rt:1; + unsigned int driving:1; }; static int get_param_index(uint32_t id) { switch (id) { case SPA_PARAM_PropInfo: - return IDX_PropInfo; + return NODE_PropInfo; case SPA_PARAM_Props: - return IDX_Props; + return NODE_Props; case SPA_PARAM_ProcessLatency: - return IDX_ProcessLatency; + return NODE_ProcessLatency; default: return -1; } @@ -188,17 +190,17 @@ { switch (id) { case SPA_PARAM_EnumFormat: - return IDX_EnumFormat; + return PORT_EnumFormat; case SPA_PARAM_Meta: - return IDX_Meta; + return PORT_Meta; case SPA_PARAM_IO: - return IDX_IO; + return PORT_IO; case SPA_PARAM_Format: - return IDX_Format; + return PORT_Format; case SPA_PARAM_Buffers: - return IDX_Buffers; + return PORT_Buffers; case SPA_PARAM_Latency: - return IDX_Latency; + return PORT_Latency; default: return -1; } @@ -475,6 +477,12 @@ pw_log_debug("%p: io %d %p/%zd", impl, id, data, size); switch(id) { + case SPA_IO_Clock: + if (data && size >= sizeof(struct spa_io_clock)) + impl->clock = data; + else + impl->clock = NULL; + break; case SPA_IO_Position: if (data && size >= sizeof(struct spa_io_position)) impl->position = data; @@ -484,6 +492,7 @@ do_set_position, 1, NULL, 0, true, impl); break; } + impl->driving = impl->clock && impl->position && impl->position->clock.id == impl->clock->id; pw_filter_emit_io_changed(&impl->this, NULL, id, data, size); return 0; @@ -1530,9 +1539,9 @@ impl->info.max_output_ports = UINT32_MAX; impl->info.flags = impl->process_rt ? SPA_NODE_FLAG_RT : 0; impl->info.props = &filter->properties->dict; - impl->paramsIDX_PropInfo = SPA_PARAM_INFO(SPA_PARAM_PropInfo, 0); - impl->paramsIDX_Props = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_WRITE); - impl->paramsIDX_ProcessLatency = SPA_PARAM_INFO(SPA_PARAM_ProcessLatency, 0); + impl->paramsNODE_PropInfo = SPA_PARAM_INFO(SPA_PARAM_PropInfo, 0); + impl->paramsNODE_Props = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_WRITE); + impl->paramsNODE_ProcessLatency = SPA_PARAM_INFO(SPA_PARAM_ProcessLatency, 0); impl->info.params = impl->params; impl->info.n_params = N_NODE_PARAMS; impl->info.change_mask = impl->change_mask_all; @@ -1712,12 +1721,12 @@ p->info.flags |= SPA_PORT_FLAG_CAN_ALLOC_BUFFERS; p->info.props = &p->props->dict; p->change_mask_all |= SPA_PORT_CHANGE_MASK_PARAMS; - p->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, 0); - p->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, 0); - p->paramsIDX_IO = SPA_PARAM_INFO(SPA_PARAM_IO, 0); - p->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); - p->paramsIDX_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); - p->paramsIDX_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_WRITE); + p->paramsPORT_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, 0); + p->paramsPORT_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, 0); + p->paramsPORT_IO = SPA_PARAM_INFO(SPA_PARAM_IO, 0); + p->paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); + p->paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); + p->paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_WRITE); p->info.params = p->params; p->info.n_params = N_PORT_PARAMS; @@ -1749,22 +1758,23 @@ return NULL; } -SPA_EXPORT -int pw_filter_remove_port(void *port_data) +static inline void free_port(struct filter *impl, struct port *port) { - struct port *port = SPA_CONTAINER_OF(port_data, struct port, user_data); - struct filter *impl = port->filter; - - spa_node_emit_port_info(&impl->hooks, port->direction, port->id, NULL); - spa_list_remove(&port->link); + spa_node_emit_port_info(&impl->hooks, port->direction, port->id, NULL); pw_map_remove(&impl->portsport->direction, port->id); - clear_buffers(port); clear_params(impl, port, SPA_ID_INVALID); pw_properties_free(port->props); free(port); +} +SPA_EXPORT +int pw_filter_remove_port(void *port_data) +{ + struct port *port = SPA_CONTAINER_OF(port_data, struct port, user_data); + struct filter *impl = port->filter; + free_port(impl, port); return 0; } @@ -1844,25 +1854,6 @@ return 0; } -static int -do_process(struct spa_loop *loop, - bool async, uint32_t seq, const void *data, size_t size, void *user_data) -{ - struct filter *impl = user_data; - int res = impl_node_process(impl); - return spa_node_call_ready(&impl->callbacks, res); -} - -static inline int call_trigger(struct filter *impl) -{ - int res = 0; - if (SPA_FLAG_IS_SET(impl->flags, PW_FILTER_FLAG_DRIVER)) { - res = pw_loop_invoke(impl->context->data_loop, - do_process, 1, NULL, 0, false, impl); - } - return res; -} - SPA_EXPORT struct pw_buffer *pw_filter_dequeue_buffer(void *port_data) { @@ -1894,7 +1885,7 @@ if ((res = push_queue(p, &p->queued, b)) < 0) return res; - return call_trigger(impl); + return res; } SPA_EXPORT @@ -1960,3 +1951,48 @@ drain ? do_drain : do_flush, 1, NULL, 0, true, impl); return 0; } + +SPA_EXPORT +bool pw_filter_is_driving(struct pw_filter *filter) +{ + struct filter *impl = SPA_CONTAINER_OF(filter, struct filter, this); + return impl->driving; +} + +static int +do_trigger_process(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct filter *impl = user_data; + int res = impl_node_process(impl); + return spa_node_call_ready(&impl->callbacks, res); +} + +static int trigger_request_process(struct filter *impl) +{ + uint8_t buffer1024; + struct spa_pod_builder b = { 0 }; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + spa_node_emit_event(&impl->hooks, + spa_pod_builder_add_object(&b, + SPA_TYPE_EVENT_Node, SPA_NODE_EVENT_RequestProcess)); + return 0; +} + +SPA_EXPORT +int pw_filter_trigger_process(struct pw_filter *filter) +{ + struct filter *impl = SPA_CONTAINER_OF(filter, struct filter, this); + int res = 0; + + pw_log_trace_fp("%p", impl); + + if (!impl->driving) { + res = trigger_request_process(impl); + } else { + res = pw_loop_invoke(impl->context->data_loop, + do_trigger_process, 1, NULL, 0, false, impl); + } + return res; +}
View file
pipewire-0.3.65.tar.gz/src/pipewire/filter.h -> pipewire-0.3.66.tar.gz/src/pipewire/filter.h
Changed
@@ -239,6 +239,16 @@ * be called when all data is played or recorded */ int pw_filter_flush(struct pw_filter *filter, bool drain); +/** Check if the filter is driving. The filter needs to have the + * PW_FILTER_FLAG_DRIVER set. When the filter is driving, + * pw_filter_trigger_process() needs to be called when data is + * available (output) or needed (input). Since 0.3.66 */ +bool pw_filter_is_driving(struct pw_filter *filter); + +/** Trigger a push/pull on the filter. One iteration of the graph will + * be scheduled and process() will be called. Since 0.3.66 */ +int pw_filter_trigger_process(struct pw_filter *filter); + /** * \} */
View file
pipewire-0.3.65.tar.gz/src/pipewire/impl-core.c -> pipewire-0.3.66.tar.gz/src/pipewire/impl-core.c
Changed
@@ -351,7 +351,7 @@ if (obj == NULL) goto error_create_failed; - return 0; + return obj; error_no_factory: res = -ENOENT;
View file
pipewire-0.3.65.tar.gz/src/pipewire/keys.h -> pipewire-0.3.66.tar.gz/src/pipewire/keys.h
Changed
@@ -342,8 +342,13 @@ * and object name or object.serial */ #ifndef PW_REMOVE_DEPRECATED -#define PW_KEY_PRIORITY_MASTER PW_DEPRECATED("priority.master") /**< deprecated, use priority.driver */ -#define PW_KEY_NODE_TARGET PW_DEPRECATED("node.target") /**< deprecated since 0.3.64, use target.object. */ +# ifdef PW_ENABLE_DEPRECATED +# define PW_KEY_PRIORITY_MASTER "priority.master" /**< deprecated, use priority.driver */ +# define PW_KEY_NODE_TARGET "node.target" /**< deprecated since 0.3.64, use target.object. */ +# else +# define PW_KEY_PRIORITY_MASTER PW_DEPRECATED("priority.master") +# define PW_KEY_NODE_TARGET PW_DEPRECATED("node.target") +# endif /* PW_ENABLE_DEPRECATED */ #endif /* PW_REMOVE_DEPRECATED */ /** \}
View file
pipewire-0.3.65.tar.gz/src/pipewire/log.c -> pipewire-0.3.66.tar.gz/src/pipewire/log.c
Changed
@@ -29,6 +29,7 @@ #include <spa/pod/pod.h> #include <spa/debug/types.h> +#include <spa/debug/format.h> #include <spa/pod/iter.h> #include <spa/utils/list.h> @@ -241,13 +242,14 @@ { struct spa_debug_log_ctx ctx = SPA_LOGF_DEBUG_INIT(global_log, level, topic, file, line, func ); - if (flags & PW_LOG_OBJECT_POD) { + if (object == NULL) { + pw_log_logt(level, topic, file, line, func, "NULL"); + } else { const struct spa_pod *pod = object; - if (pod == NULL) { - pw_log_logt(level, topic, file, line, func, "NULL"); - } else { + if (flags & PW_LOG_OBJECT_POD) spa_debugc_pod(&ctx.ctx, 0, SPA_TYPE_ROOT, pod); - } + else if (flags & PW_LOG_OBJECT_FORMAT) + spa_debugc_format(&ctx.ctx, 0, NULL, pod); } }
View file
pipewire-0.3.65.tar.gz/src/pipewire/mem.c -> pipewire-0.3.66.tar.gz/src/pipewire/mem.c
Changed
@@ -33,6 +33,7 @@ #include <unistd.h> #include <stdlib.h> #include <sys/syscall.h> +#include <sys/stat.h> #include <spa/utils/list.h> #include <spa/buffer/buffer.h> @@ -363,6 +364,23 @@ struct mapping *m; struct memmap *mm; struct pw_map_range range; + struct stat sb; + + if (fstat(b->this.fd, &sb) != 0) + return NULL; + + const bool valid = (int64_t) offset + size <= (int64_t) sb.st_size; + pw_log(valid ? SPA_LOG_LEVEL_DEBUG : SPA_LOG_LEVEL_ERROR, + "%p: block %p%u mapping %" PRIu32 "+%" PRIu32 " of file=%d/%" PRIu64 ":%" PRIu64 " with size=%" PRId64, + block->pool, block, block->id, + offset, size, + block->fd, (uint64_t) sb.st_dev, (uint64_t) sb.st_ino, + (int64_t) sb.st_size); + + if (!valid) { + errno = -EINVAL; + return NULL; + } pw_map_range_init(&range, offset, size, p->pagesize);
View file
pipewire-0.3.65.tar.gz/src/pipewire/private.h -> pipewire-0.3.66.tar.gz/src/pipewire/private.h
Changed
@@ -1276,6 +1276,7 @@ void pw_impl_client_unref(struct pw_impl_client *client); #define PW_LOG_OBJECT_POD (1<<0) +#define PW_LOG_OBJECT_FORMAT (1<<1) void pw_log_log_object(enum spa_log_level level, const struct spa_log_topic *topic, const char *file, int line, const char *func, uint32_t flags, const void *object); @@ -1288,7 +1289,7 @@ }) #define pw_log_pod(lev,pod) pw_log_object(lev,PW_LOG_TOPIC_DEFAULT,PW_LOG_OBJECT_POD,pod) -#define pw_log_format(lev,pod) pw_log_object(lev,PW_LOG_TOPIC_DEFAULT,PW_LOG_OBJECT_POD,pod) +#define pw_log_format(lev,pod) pw_log_object(lev,PW_LOG_TOPIC_DEFAULT,PW_LOG_OBJECT_FORMAT,pod) bool pw_log_is_default(void);
View file
pipewire-0.3.65.tar.gz/src/pipewire/stream.c -> pipewire-0.3.66.tar.gz/src/pipewire/stream.c
Changed
@@ -123,7 +123,7 @@ struct spa_io_position *position; } rt; - uint32_t port_change_mask_all; + uint64_t port_change_mask_all; struct spa_port_info port_info; struct pw_properties *port_props; #define PORT_EnumFormat 0 @@ -137,7 +137,7 @@ struct spa_list param_list; - uint32_t change_mask_all; + uint64_t change_mask_all; struct spa_node_info info; #define NODE_PropInfo 0 #define NODE_Props 1
View file
pipewire-0.3.65.tar.gz/src/pipewire/thread-loop.c -> pipewire-0.3.66.tar.gz/src/pipewire/thread-loop.c
Changed
@@ -435,7 +435,7 @@ * */ SPA_EXPORT -int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, struct timespec *abstime) +int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, const struct timespec *abstime) { int ret; loop->n_waiting++;
View file
pipewire-0.3.65.tar.gz/src/pipewire/thread-loop.h -> pipewire-0.3.66.tar.gz/src/pipewire/thread-loop.h
Changed
@@ -153,7 +153,7 @@ /** Release the lock and wait up to \a abstime until some thread calls * \ref pw_thread_loop_signal. Use \ref pw_thread_loop_get_time to make a timeout. * Since: 0.3.7 */ -int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, struct timespec *abstime); +int pw_thread_loop_timed_wait_full(struct pw_thread_loop *loop, const struct timespec *abstime); /** Signal all threads waiting with \ref pw_thread_loop_wait */ void pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept);
View file
pipewire-0.3.65.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.66.tar.gz/src/tools/pw-cat.c
Changed
@@ -255,14 +255,13 @@ static int encoded_playback_fill(struct data *d, void *dest, unsigned int n_frames) { int ret, size = 0; - uint8_t buffer16384 = { 0 }; + uint8_t buffer16384; - ret = fread(buffer, 1, 16384, d->encoded_file); + ret = fread(buffer, 1, SPA_MIN(n_frames, sizeof(buffer)), d->encoded_file); if (ret > 0) { memcpy(dest, buffer, ret); size = ret; } - return (int)size; } @@ -786,31 +785,6 @@ n_frames = d->maxsize / data->stride; n_frames = SPA_MIN(n_frames, (int)b->requested); -#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION - n_fill_frames = data->fill(data, p, n_frames); - - if (n_fill_frames > 0 || n_frames == 0) { - d->chunk->offset = 0; - if (data->data_type == TYPE_ENCODED) { - d->chunk->stride = 0; - // encoded_playback_fill returns number of bytes - // read and not number of frames like other - // functions for raw audio. - d->chunk->size = n_fill_frames; - b->size = n_fill_frames; - } else { - d->chunk->stride = data->stride; - d->chunk->size = n_fill_frames * data->stride; - b->size = n_frames; - } - have_data = true; - } else if (n_fill_frames < 0) { - fprintf(stderr, "fill error %d\n", n_fill_frames); - } else { - if (data->verbose) - printf("drain start\n"); - } -#else n_fill_frames = data->fill(data, p, n_frames); if (n_fill_frames > 0 || n_frames == 0) { @@ -825,7 +799,6 @@ if (data->verbose) printf("drain start\n"); } -#endif } else { offset = SPA_MIN(d->chunk->offset, d->maxsize); size = SPA_MIN(d->chunk->size, d->maxsize - offset);
View file
pipewire-0.3.66.tar.gz/subprojects/libcamera.wrap
Added
@@ -0,0 +1,3 @@ +wrap-git +url = https://git.libcamera.org/libcamera/libcamera.git +revision = head
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
.