Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 2
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Sun Jan 30 16:36:30 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.44 + +------------------------------------------------------------------- Wed Jan 5 16:20:56 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.43
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.43 +Version: 0.3.44 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
pipewire-0.3.43.tar.gz/doc/pipewire-tools.dox
Deleted
@@ -1,4 +0,0 @@ -/** \page page_tools PipeWire Tools - -*/ -
View file
pipewire-0.3.43.tar.gz/spa/plugins/alsa/mixer/profile-sets/behringer-umc22.conf
Deleted
@@ -1,68 +0,0 @@ -# This file is part of PulseAudio. -# -# PulseAudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 2.1 of the -# License, or (at your option) any later version. -# -# PulseAudio is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. - -; Behringer U-Phoria UMC22 -; -; Default mapping only allows to use stereo input and sound card has two -; physical input channels. -; -; However in case of only using a single input channel (like condenser -; microphone) only one channel will have any sound, which is often -; inconvenient for casual use. -; -; This config includes mono input options which makes it much more -; friendly in single input configuration. -; -; This config also removes default digital input/output mappings that do -; not physically exist on this card. -; -; Added by Nazar Mokrynskyi <nazar@mokrynskyi.com> - -[General] -auto-profiles = yes - -[Mapping analog-stereo-input] -device-strings = hw:%f -channel-map = left,right -paths-input = analog-input-mic -direction = input -priority = 4 - -[Mapping analog-mono] -device-strings = hw:%f -channel-map = mono,mono -paths-input = analog-input-mic -direction = input -priority = 3 - -[Mapping analog-mono-left] -device-strings = hw:%f -channel-map = mono,aux1 -paths-input = analog-input-mic -direction = input -priority = 2 - -[Mapping analog-mono-right] -device-strings = hw:%f -channel-map = aux1,mono -paths-input = analog-input-mic -direction = input -priority = 1 - -[Mapping analog-stereo-output] -device-strings = front:%f -channel-map = left,right -paths-output = analog-output -direction = output
View file
pipewire-0.3.43.tar.gz/src/modules/module-rtkit.c
Deleted
@@ -1,730 +0,0 @@ -/* PipeWire - * - * Copyright © 2018 Wim Taymans - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <sys/stat.h> -#ifdef __FreeBSD__ -#include <sys/thr.h> -#endif -#include <fcntl.h> -#include <unistd.h> -#include <pthread.h> -#include <sys/resource.h> - -#include "config.h" - -#include <spa/support/dbus.h> -#include <spa/utils/result.h> -#include <spa/utils/string.h> - -#include <pipewire/impl.h> -#include <pipewire/thread.h> - -/** \page page_module_rtkit PipeWire Module: RTKit - */ - -#define NAME "rtkit" - -PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); -#define PW_LOG_TOPIC_DEFAULT mod_topic - -#define DEFAULT_NICE_LEVEL -11 -#define DEFAULT_RT_PRIO 88 -#define DEFAULT_RT_TIME_SOFT 2000000 -#define DEFAULT_RT_TIME_HARD 2000000 - -#define MODULE_USAGE "[nice.level=<priority: default "SPA_STRINGIFY(DEFAULT_NICE_LEVEL) ">] " \ - "[rt.prio=<priority: default "SPA_STRINGIFY(DEFAULT_RT_PRIO) ">] " \ - "[rt.time.soft=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_SOFT)"] " \ - "[rt.time.hard=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_HARD)"] " - -static const struct spa_dict_item module_props[] = { - { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, - { PW_KEY_MODULE_DESCRIPTION, "Use RTKit to raise thread priorities" }, - { PW_KEY_MODULE_USAGE, MODULE_USAGE }, - { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, -}; - -struct pw_rtkit_bus; - -struct thread { - struct impl *impl; - struct spa_list link; - pthread_t thread; - pid_t pid; - void *(*start)(void*); - void *arg; -}; - -struct impl { - struct pw_context *context; - - struct pw_properties *props; - - struct pw_rtkit_bus *system_bus; - - pthread_mutex_t lock; - pthread_cond_t cond; - - struct spa_list threads_list; - struct spa_thread_utils thread_utils; - - int nice_level; - int rt_prio; - rlim_t rt_time_soft; - rlim_t rt_time_hard; - - struct spa_hook module_listener; -}; - -/*** - Copyright 2009 Lennart Poettering - Copyright 2010 David Henningsson <diwic@ubuntu.com> - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -***/ - -#include <dbus/dbus.h> - -#include "config.h" - -#include <sys/syscall.h> - -#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1" -#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1" - -#ifndef RLIMIT_RTTIME -#define RLIMIT_RTTIME 15 -#endif - -/** \cond */ -struct pw_rtkit_bus { - DBusConnection *bus; -}; -/** \endcond */ - -struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) -{ - struct pw_rtkit_bus *bus; - DBusError error; - - if (getenv("DISABLE_RTKIT")) { - errno = ENOTSUP; - return NULL; - } - - dbus_error_init(&error); - - bus = calloc(1, sizeof(struct pw_rtkit_bus)); - if (bus == NULL) - return NULL; - - bus->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); - if (bus->bus == NULL) - goto error; - - dbus_connection_set_exit_on_disconnect(bus->bus, false); - - return bus; - -error: - free(bus); - pw_log_error("Failed to connect to system bus: %s", error.message); - dbus_error_free(&error); - errno = ECONNREFUSED; - return NULL; -} - -void pw_rtkit_bus_free(struct pw_rtkit_bus *system_bus) -{ - dbus_connection_close(system_bus->bus); - dbus_connection_unref(system_bus->bus); - free(system_bus); -} - -static pid_t _gettid(void) -{ -#if defined(HAVE_GETTID) - return (pid_t) gettid(); -#elif defined(__linux__) - return syscall(SYS_gettid); -#elif defined(__FreeBSD__) - long pid; - thr_self(&pid); - return (pid_t)pid; -#else -#error "No gettid impl" -#endif -} - -static int translate_error(const char *name) -{ - pw_log_warn("RTKit error: %s", name); - - if (spa_streq(name, DBUS_ERROR_NO_MEMORY)) - return -ENOMEM; - if (spa_streq(name, DBUS_ERROR_SERVICE_UNKNOWN) || - spa_streq(name, DBUS_ERROR_NAME_HAS_NO_OWNER)) - return -ENOENT; - if (spa_streq(name, DBUS_ERROR_ACCESS_DENIED) || - spa_streq(name, DBUS_ERROR_AUTH_FAILED)) - return -EACCES; - - return -EIO; -} - -static long long rtkit_get_int_property(struct pw_rtkit_bus *connection, const char *propname, - long long *propval) -{ - DBusMessage *m = NULL, *r = NULL; - DBusMessageIter iter, subiter; - dbus_int64_t i64; - dbus_int32_t i32; - DBusError error; - int current_type; - long long ret; - const char *interfacestr = "org.freedesktop.RealtimeKit1"; - - dbus_error_init(&error); - - if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, - RTKIT_OBJECT_PATH, - "org.freedesktop.DBus.Properties", "Get"))) { - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interfacestr, - DBUS_TYPE_STRING, &propname, DBUS_TYPE_INVALID)) { - ret = -ENOMEM; - goto finish; - } - - if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) { - ret = translate_error(error.name); - goto finish; - } - - if (dbus_set_error_from_message(&error, r)) { - ret = translate_error(error.name); - goto finish; - } - - ret = -EBADMSG; - dbus_message_iter_init(r, &iter); - while ((current_type = dbus_message_iter_get_arg_type(&iter)) != DBUS_TYPE_INVALID) { - - if (current_type == DBUS_TYPE_VARIANT) { - dbus_message_iter_recurse(&iter, &subiter); - - while ((current_type = - dbus_message_iter_get_arg_type(&subiter)) != DBUS_TYPE_INVALID) { - - if (current_type == DBUS_TYPE_INT32) { - dbus_message_iter_get_basic(&subiter, &i32); - *propval = i32; - ret = 0; - } - - if (current_type == DBUS_TYPE_INT64) { - dbus_message_iter_get_basic(&subiter, &i64); - *propval = i64; - ret = 0; - } - - dbus_message_iter_next(&subiter); - } - } - dbus_message_iter_next(&iter); - } - -finish: - - if (m) - dbus_message_unref(m); - - if (r) - dbus_message_unref(r); - - dbus_error_free(&error); - - return ret; -} - -int pw_rtkit_get_max_realtime_priority(struct pw_rtkit_bus *connection) -{ - long long retval; - int err; - - err = rtkit_get_int_property(connection, "MaxRealtimePriority", &retval); - return err < 0 ? err : retval; -} - -int pw_rtkit_get_min_nice_level(struct pw_rtkit_bus *connection, int *min_nice_level) -{ - long long retval; - int err; - - err = rtkit_get_int_property(connection, "MinNiceLevel", &retval); - if (err >= 0) - *min_nice_level = retval; - return err; -} - -long long pw_rtkit_get_rttime_usec_max(struct pw_rtkit_bus *connection) -{ - long long retval; - int err; - - err = rtkit_get_int_property(connection, "RTTimeUSecMax", &retval); - return err < 0 ? err : retval; -} - -int pw_rtkit_make_realtime(struct pw_rtkit_bus *connection, pid_t thread, int priority) -{ - DBusMessage *m = NULL, *r = NULL; - dbus_uint64_t u64; - dbus_uint32_t u32; - DBusError error; - int ret; - - dbus_error_init(&error); - - if (thread == 0) - thread = _gettid(); - - if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, - RTKIT_OBJECT_PATH, - "org.freedesktop.RealtimeKit1", - "MakeThreadRealtime"))) { - ret = -ENOMEM; - goto finish; - } - - u64 = (dbus_uint64_t) thread; - u32 = (dbus_uint32_t) priority; - - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT64, &u64, - DBUS_TYPE_UINT32, &u32, DBUS_TYPE_INVALID)) { - ret = -ENOMEM; - goto finish; - } - - if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) { - ret = translate_error(error.name); - goto finish; - } - - - if (dbus_set_error_from_message(&error, r)) { - ret = translate_error(error.name); - goto finish; - } - - ret = 0; - -finish: - - if (m) - dbus_message_unref(m); - - if (r) - dbus_message_unref(r); - - dbus_error_free(&error); - - return ret; -} - -int pw_rtkit_make_high_priority(struct pw_rtkit_bus *connection, pid_t thread, int nice_level) -{ - DBusMessage *m = NULL, *r = NULL; - dbus_uint64_t u64; - dbus_int32_t s32; - DBusError error; - int ret; - - dbus_error_init(&error); - - if (thread == 0) - thread = _gettid(); - - if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, - RTKIT_OBJECT_PATH, - "org.freedesktop.RealtimeKit1", - "MakeThreadHighPriority"))) { - ret = -ENOMEM; - goto finish; - } - - u64 = (dbus_uint64_t) thread; - s32 = (dbus_int32_t) nice_level; - - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT64, &u64, - DBUS_TYPE_INT32, &s32, DBUS_TYPE_INVALID)) { - ret = -ENOMEM; - goto finish; - } - - - - if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) { - ret = translate_error(error.name); - goto finish; - } - - - if (dbus_set_error_from_message(&error, r)) { - ret = translate_error(error.name); - goto finish; - } - - ret = 0; - -finish: - - if (m) - dbus_message_unref(m); - - if (r) - dbus_message_unref(r); - - dbus_error_free(&error); - - return ret; -} - -static void module_destroy(void *data) -{ - struct impl *impl = data; - - pw_thread_utils_set(NULL); - spa_hook_remove(&impl->module_listener); - - pw_properties_free(impl->props); - if (impl->system_bus) - pw_rtkit_bus_free(impl->system_bus); - free(impl); -} - -static const struct pw_impl_module_events module_events = { - PW_VERSION_IMPL_MODULE_EVENTS, - .destroy = module_destroy, -}; - -static int set_nice(struct impl *impl, int nice_level) -{ - int res; - if ((res = pw_rtkit_make_high_priority(impl->system_bus, 0, nice_level)) < 0) { - pw_log_warn("could not set nice-level to %d: %s", - nice_level, spa_strerror(res)); - } else { - pw_log_info("main thread nice level set to %d", nice_level); - } - return 0; -} - -static int set_rlimit(struct impl *impl) -{ - struct rlimit rl; - long long rttime; - int res = 0; - - rl.rlim_cur = impl->rt_time_soft; - rl.rlim_max = impl->rt_time_hard; - - rttime = pw_rtkit_get_rttime_usec_max(impl->system_bus); - if (rttime >= 0) { - rl.rlim_cur = SPA_MIN(rl.rlim_cur, (rlim_t)rttime); - rl.rlim_max = SPA_MIN(rl.rlim_max, (rlim_t)rttime); - } - - if (setrlimit(RLIMIT_RTTIME, &rl) < 0) - res = -errno; - - if (res < 0) - pw_log_debug("setrlimit() failed: %s", spa_strerror(res)); - else - pw_log_debug("rt.time.soft:%"PRIi64" rt.time.hard:%"PRIi64, - (int64_t)rl.rlim_cur, (int64_t)rl.rlim_max); - - return res; -} - -static struct thread *find_thread_by_pt(struct impl *impl, pthread_t pt) -{ - struct thread *t; - - spa_list_for_each(t, &impl->threads_list, link) { - if (pthread_equal(t->thread, pt)) - return t; - } - return NULL; -} - -static void *custom_start(void *data) -{ - struct thread *this = data; - struct impl *impl = this->impl; - - pthread_mutex_lock(&impl->lock); - this->pid = _gettid(); - pthread_cond_broadcast(&impl->cond); - pthread_mutex_unlock(&impl->lock); - - return this->start(this->arg); -} - -static struct spa_thread *impl_create(void *data, const struct spa_dict *props, - void *(*start_routine)(void*), void *arg) -{ - struct impl *impl = data; - struct thread *this; - int err; - - this = calloc(1, sizeof(*this)); - this->impl = impl; - this->start = start_routine; - this->arg = arg; - - pthread_mutex_lock(&impl->lock); - err = pthread_create(&this->thread, NULL, custom_start, this); - if (err != 0) - goto exit; - - pthread_cond_wait(&impl->cond, &impl->lock); - - spa_list_append(&impl->threads_list, &this->link); -exit: - pthread_mutex_unlock(&impl->lock); - - if (err != 0) { - errno = err; - free(this); - return NULL; - } - return (struct spa_thread*)this->thread; -} - -static int impl_join(void *data, struct spa_thread *thread, void **retval) -{ - struct impl *impl = data; - pthread_t pt = (pthread_t)thread; - struct thread *thr; - - pthread_mutex_lock(&impl->lock); - if ((thr = find_thread_by_pt(impl, pt)) != NULL) { - spa_list_remove(&thr->link); - free(thr); - } - pthread_mutex_unlock(&impl->lock); - - return pthread_join(pt, retval); -} - -static int impl_get_rt_range(void *data, const struct spa_dict *props, - int *min, int *max) -{ - struct impl *impl = data; - if (min) - *min = 1; - if (max) - *max = pw_rtkit_get_max_realtime_priority(impl->system_bus); - return 0; -} - -static pid_t impl_gettid(struct impl *impl, pthread_t pt) -{ - struct thread *thr; - pid_t pid; - - pthread_mutex_lock(&impl->lock); - if ((thr = find_thread_by_pt(impl, pt)) != NULL) - pid = thr->pid; - else - pid = _gettid(); - pthread_mutex_unlock(&impl->lock); - - return pid; -} - -static int impl_acquire_rt(void *data, struct spa_thread *thread, int priority) -{ - struct impl *impl = data; - struct sched_param sp; - int r, rtprio; - pthread_t pt = (pthread_t)thread; - pid_t pid; - - priority = impl->rt_prio; - - rtprio = pw_rtkit_get_max_realtime_priority(impl->system_bus); - if (rtprio >= 0) - rtprio = SPA_MIN(rtprio, priority); - else - rtprio = priority; - - spa_zero(sp); - sp.sched_priority = rtprio; - -#ifndef __FreeBSD__ - if (pthread_setschedparam(pt, SCHED_OTHER | SCHED_RESET_ON_FORK, &sp) == 0) { - pw_log_debug("SCHED_OTHER|SCHED_RESET_ON_FORK worked."); - } -#endif - - pid = impl_gettid(impl, pt); - - if ((r = pw_rtkit_make_realtime(impl->system_bus, pid, rtprio)) < 0) { - pw_log_warn("could not make thread realtime: %s", spa_strerror(r)); - } else { - pw_log_info("acquired realtime prio:%d", rtprio); - } - return 0; -} - -static int impl_drop_rt(void *data, struct spa_thread *thread) -{ - struct sched_param sp; - pthread_t pt = (pthread_t)thread; - int err; - - spa_zero(sp); -#ifndef __FreeBSD__ - if ((err = pthread_setschedparam(pt, - SCHED_OTHER | SCHED_RESET_ON_FORK, &sp)) != 0) { - pw_log_debug("thread %p: SCHED_OTHER|SCHED_RESET_ON_FORK failed: %s", - thread, strerror(err)); - return -err; - } -#endif - pw_log_info("thread %p dropped realtime priority", thread); - return 0; -} - -static const struct spa_thread_utils_methods impl_thread_utils = { - SPA_VERSION_THREAD_UTILS_METHODS, - .create = impl_create, - .join = impl_join, - .get_rt_range = impl_get_rt_range, - .acquire_rt = impl_acquire_rt, - .drop_rt = impl_drop_rt, -}; - - -SPA_EXPORT -int pipewire__module_init(struct pw_impl_module *module, const char *args) -{ - struct pw_context *context = pw_impl_module_get_context(module); - struct impl *impl; - const struct pw_properties *props; - const char *str; - int res; - - PW_LOG_TOPIC_INIT(mod_topic); - - if ((props = pw_context_get_properties(context)) != NULL && - (str = pw_properties_get(props, "support.dbus")) != NULL && - !pw_properties_parse_bool(str)) - return -ENOTSUP; - - impl = calloc(1, sizeof(struct impl)); - if (impl == NULL) - return -ENOMEM; - - spa_list_init(&impl->threads_list); - pthread_mutex_init(&impl->lock, NULL); - pthread_cond_init(&impl->cond, NULL); - - pw_log_debug("module %p: new", impl); - - impl->context = context; - impl->props = args ? pw_properties_new_string(args) : pw_properties_new(NULL, NULL); - if (impl->props == NULL) { - res = -errno; - goto error; - } - - impl->system_bus = pw_rtkit_bus_get_system(); - if (impl->system_bus == NULL) { - res = -errno; - pw_log_warn("could not get system bus: %m"); - goto error; - } - impl->nice_level = pw_properties_get_int32(impl->props, "nice.level", DEFAULT_NICE_LEVEL); - - set_nice(impl, impl->nice_level); - - impl->rt_prio = pw_properties_get_int32(impl->props, "rt.prio", DEFAULT_RT_PRIO); - impl->rt_time_soft = pw_properties_get_int32(impl->props, "rt.time.soft", DEFAULT_RT_TIME_SOFT); - impl->rt_time_hard = pw_properties_get_int32(impl->props, "rt.time.hard", DEFAULT_RT_TIME_HARD); - - set_rlimit(impl); - - impl->thread_utils.iface = SPA_INTERFACE_INIT( - SPA_TYPE_INTERFACE_ThreadUtils, - SPA_VERSION_THREAD_UTILS, - &impl_thread_utils, impl); - - pw_thread_utils_set(&impl->thread_utils); - - pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl); - - pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props)); - pw_impl_module_update_properties(module, &impl->props->dict); - - return 0; - -error: - pw_properties_free(impl->props); - if (impl->system_bus) - pw_rtkit_bus_free(impl->system_bus); - free(impl); - return res; -}
View file
pipewire-0.3.43.tar.gz/.cirrus.yml -> pipewire-0.3.44.tar.gz/.cirrus.yml
Changed
@@ -17,7 +17,7 @@ build_script: - mkdir build - cd build - - meson setup -Dalsa=enabled -Draop=enabled -Dv4l2=enabled -Dpipewire-alsa=enabled -Dbluez5=disabled -Djack=disabled -Dpipewire-jack=disabled -Dpw-cat=enabled -Dpipewire-v4l2=disabled -Dsdl2=enabled -Dsystemd=disabled -Dsession-managers=media-session .. + - meson setup -Dalsa=enabled -Draop=enabled -Dv4l2=enabled -Dpipewire-alsa=enabled -Dbluez5=disabled -Djack=disabled -Dpipewire-jack=enabled -Dpw-cat=enabled -Dpipewire-v4l2=disabled -Dsdl2=enabled -Dsystemd=disabled -Dsession-managers=media-session .. - ninja test_script: - cd build
View file
pipewire-0.3.43.tar.gz/.gitlab-ci.yml -> pipewire-0.3.44.tar.gz/.gitlab-ci.yml
Changed
@@ -8,8 +8,8 @@ variables: FDO_UPSTREAM_REPO: 'pipewire/pipewire' -# ci-templates as of March 19th 2021 -.templates_sha: &templates_sha 290b79e0e78eab67a83766f4e9691be554fc4afd +# ci-templates as of Jan 27th 2022 +.templates_sha: &templates_sha 0c312d9c7255f46e741d43bcd1930f09cd12efe7 include: - project: 'freedesktop/ci-templates' @@ -22,8 +22,8 @@ .fedora: variables: # Update this tag when you want to trigger a rebuild - FDO_DISTRIBUTION_TAG: '2021-10-12.1' - FDO_DISTRIBUTION_VERSION: '34' + FDO_DISTRIBUTION_TAG: '2022-01-27.1' + FDO_DISTRIBUTION_VERSION: '35' FDO_DISTRIBUTION_PACKAGES: >- alsa-lib-devel bluez-libs-devel @@ -62,7 +62,7 @@ .ubuntu: variables: # Update this tag when you want to trigger a rebuild - FDO_DISTRIBUTION_TAG: '2021-10-15.0' + FDO_DISTRIBUTION_TAG: '2022-01-27.0' FDO_DISTRIBUTION_VERSION: '20.04' FDO_DISTRIBUTION_PACKAGES: >- debhelper-compat
View file
pipewire-0.3.43.tar.gz/NEWS -> pipewire-0.3.44.tar.gz/NEWS
Changed
@@ -1,4 +1,142 @@ -# PipeWire 0.3.43 (2021-01-05) +# PipeWire 0.3.44 (2022-01-27) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + - It is now possible to run a minimal PipeWire server without a session + manager, enough to run JACK clients. + - The maximum buffer size is now configurable and can be larger than + the previously hardcoded limit of 8192 samples. When using high sample + rates, the larger buffer size can avoid xruns. + - The default maximum latency was reduced from 170ms to 42ms. This should + improve overall latency for application that ask for a large latency, + such as notifications. + - Better JACK compatibility. Patchbays should now get less confused about + ports appearing and disappearing. + - Fix some bluetooth crashes. + - Fix some races in ALSA device detection. + - Many bug fixes and improvements all over the place. + +## PipeWire + - Bump the meson requirement to 0.59.0. + - pw-top now reports correct times for filter-chain and loopback. + - max-quantum is now also scaled with the rate. A new quantum-limit + property was added as a hard limit for the quantum. This makes it + possible to configure for larger than 8192 buffer sizes. Note + than many JACK applications have a hardcoded 8192 limit. (#1931) + - The max-quantum was reduced to 2048, This gives a 42ms default + latency. (#1908) + - pw-filter can now return a NULL buffer from _get_dsp_buffer(). + - Add a PIPEWIRE_RATE and PIPEWIRE_QUANTUM env variable to set the + graph rate and the graph quantum and rate respectively. + - Fix a potential file descriptor leak in the connection. + - A new minimal.conf file was added to demonstrate a static setup + of a daemon that doesn't require a session manager and is able to + run JACK applicaions. + - Nice levels are now only changed on the servers, not the clients. + - Add an option to suspend nodes when idle. + - Make it possible to avoid quantum and rate changes with + pw-metadata. This is essential in a locked down system. + - Handle mixer port errors better and fail to create the link instead + of silently not working. + - Nodes that are moved to a driver now have all the linked nodes moved + as well. This makes it possible to run some graphs without a + driver, such as paplay -> zita-j2n. + - pw-cli and pw-dump can now also list objects by name, serial and + object.path using glob style pattern matching. + + +## modules + - filter-chain can now also configure parameters by index. + - Fix the client name of module-protocol-simple. (#2017) + - module-rtkit was merged into module-rt. This makes it easier to + ship a default config that works on more systems by default. + - module-adapter can now configure the adapter node from the config. + Previously, this was a task only performed by the session manager. + - module-metadata can now also create metadata object from the + config file. + - The ROC module should now work again. (#2045) + - An X11-bell module was added to handle X11 bell events. (#1668) + - filter-chain and loopback modules now have better unique default + names for the streams, which makes it possible to save and restore + their volumes independently. (#1983) + - module-echo-cancel now has properties to control the delay and + buffer size. + +## ALSA + - The monitor names are now correctly parsed. + - The default period size for batch devices is limited now to avoid + large latency. + - The unused min/max-latency properties were removed. + - Internal latency is now also configurable with params at runtime. + - The udev rule for TI2902 was removed because it causes problems. + - Fix a race where some devices would sometimes be missing. (#2046) + - Add some more timeouts to work around a race in udev device + permission changes when switching VTs. + +## SPA + - Fix potential infinite loop in audioconvert. + - The spa-resample tools can now also use optimized implementations. + - Fix a potential crash in resampler. (#1994) + - audioconvert can now also handle F64 formats. (#1990) + - The channelmixer now does normalization by default to avoid clipping + when downmixing is active. + - The channelmixer will now generate LFE channels when the lfe_cutoff + frequency is set, even when upmix is disabled. + - The channelmixer will now always generate FC when the target has it. + - Adapter now reports latency correctly, even after linking the monitor + ports. + - Reduce memory usage and preallocated memory in some of the + audioconvert nodes. + - Many properties are now exposed in adapter, such as the resample + quality. + - The resampler and channelmixer can now be disabled. + +## V4L2 + - pw-v4l2 now also works for ffplay. (#2029) + - Take product names from udev now that the kernel returns a generic + name. + +## JACK + - The jack pkgconfig file now has the `jack_implementation=pipewire` + variable to be able to distinguish jack implementations. (#1666) + - jconvolver now starts correctly again. (#1989) + - The object.serial is now used for the port_id. This makes it easier + to track old objects in the cache. + - Add a dummy jacknet implementation. (#2043) + - A bug in the port allocation was fixed that would make it impossible + to allocate ports at some point. (#1714) + +## Bluetooth + - Bluetooth profiles are now saved properly by the session manager. + - Improved profile detections, increased timeouts for slow devices. + - Implement HFP call indicator for improved compatibility. + - Handle the case where bluez does not set the adapter or address + properties on the device instead of crashing. + - Improved support for setting the profile from the session manager. + +## pulse-server + - Monitor sources now have the device.class=monitor for better + compatibility. + - Behaviour after seeking is improved. The algorithm for requesting + bytes from the client was simplified and improved. (#1981) + - module-ladspa-sink implements the control argument now. (#1987) + - A potential memory leak in the message queue was fixed. (#1840) + - Use the object.serial for the pulseaudio object index. The index is + not supposed to be reused and this would cause problems with some + clients. + - Servers should now again be able to listen in IPv4. (#2047) + - module-x11-bell was added. (#1668) + - There is now support for per-application quirks and properties in + the pipewire-pulse.conf file. Per-application latency and buffering + properties can also be configured. + - Fix a regression in telegram sounds not playing. + + +Older versions: + +# PipeWire 0.3.43 (2022-01-05) This is a bugfix release that is API and ABI compatible with previous 0.3.x releases. @@ -81,10 +219,6 @@ - Add command access control. This avoids execution of commands without proper authentication. - -Older versions: - - # PipeWire 0.3.42 (2021-12-16) This is a bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.43.tar.gz/README.md -> pipewire-0.3.44.tar.gz/README.md
Changed
@@ -48,6 +48,13 @@ expressed as a fraction of the samplerate, like 256/48000, which uses 256 samples at a samplerate of 48KHz for a latency of 5.33ms. + This function does not attempt to configure + the samplerate. +* `PIPEWIRE_RATE=<num/denom>` to configure a rate for the graph. +* `PIPEWIRE_QUANTUM=<num/denom>` to configure latency as a fraction and a + samplerate. This function will attempt to change + the graph samplerate to `denom` and use the + specified `num` as the buffer size. * `PIPEWIRE_NODE=<id>` to request a link to the specified node ### Using tools
View file
pipewire-0.3.44.tar.gz/doc/manpage.dox.in
Added
@@ -0,0 +1,5 @@ +/** \page @pagename@ @title@ + +\verbinclude @filename@ + +*/
View file
pipewire-0.3.43.tar.gz/doc/meson.build -> pipewire-0.3.44.tar.gz/doc/meson.build
Changed
@@ -26,7 +26,6 @@ 'pipewire-daemon.dox', 'pipewire-library.dox', 'pipewire-modules.dox', - 'pipewire-tools.dox', 'pipewire-session-manager.dox', 'pipewire-objects-design.dox', 'pipewire-audio.dox', @@ -115,6 +114,30 @@ input_dirs += [ 'doc/examples.dox' ] +man_doxygen = [] +man_subpages = [] +foreach m : manpages + manconf = configuration_data() + pagename = 'page_man_' + m.split('.rst.in').get(0).replace('.', '_').replace('-', '_') + filename = m.split('.rst.in').get(0) + '.dox' + manconf.set('pagename', pagename) + manconf.set('title', m.split('.rst.in').get(0).replace('.1','').replace('.5','')) + manconf.set('filename', meson.project_source_root() / 'man' / m) + manfile = configure_file(input: 'manpage.dox.in', + output: filename, + configuration: manconf) + man_doxygen += [manfile] + man_subpages += ['- \subpage ' + pagename] + input_dirs += [ 'doc/' + filename ] +endforeach + +pw_tools_dox_conf = configuration_data() +pw_tools_dox_conf.set('man_subpages', '\n'.join(man_subpages)) +pw_tools_dox = configure_file(input: 'pipewire-tools.dox.in', + output: 'pipewire-tools.dox', + configuration: pw_tools_dox_conf) +input_dirs += [ 'doc/pipewire-tools.dox' ] + doxyfile_conf.set('inputs', ' '.join(inputs + input_dirs)) doxyfile_conf.set('cssfiles', ' '.join(cssfiles)) doxyfile_conf.set('path_prefixes', ' '.join(path_prefixes)) @@ -131,7 +154,7 @@ endif html_target = custom_target('pipewire-docs', - input: [ doxyfile, examples_dox ] + inputs + cssfiles, + input: [ doxyfile, examples_dox, pw_tools_dox ] + inputs + cssfiles + man_doxygen, output: [ 'html' ], command: [ doxygen, doxyfile ], install: true,
View file
pipewire-0.3.43.tar.gz/doc/pipewire-modules.dox -> pipewire-0.3.44.tar.gz/doc/pipewire-modules.dox
Changed
@@ -74,8 +74,8 @@ - \subpage page_module_roc_sink - \subpage page_module_roc_source - \subpage page_module_rt -- \subpage page_module_rtkit - \subpage page_module_session_manager +- \subpage page_module_x11_bell - \subpage page_module_zeroconf_discover
View file
pipewire-0.3.44.tar.gz/doc/pipewire-tools.dox.in
Added
@@ -0,0 +1,7 @@ +/** \page page_tools PipeWire Tools + +Manual pages: + +@man_subpages@ + +*/
View file
pipewire-0.3.43.tar.gz/man/meson.build -> pipewire-0.3.44.tar.gz/man/meson.build
Changed
@@ -23,6 +23,10 @@ manpages += 'pw-jack.1.rst.in' endif +if not generate_manpages + subdir_done() +endif + foreach m : manpages file = m.split('.rst.in').get(0) rst = configure_file(input : m,
View file
pipewire-0.3.43.tar.gz/man/pipewire-pulse.1.rst.in -> pipewire-0.3.44.tar.gz/man/pipewire-pulse.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pipewire-pulse ##############
View file
pipewire-0.3.43.tar.gz/man/pipewire.1.rst.in -> pipewire-0.3.44.tar.gz/man/pipewire.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pipewire ########
View file
pipewire-0.3.43.tar.gz/man/pipewire.conf.5.rst.in -> pipewire-0.3.44.tar.gz/man/pipewire.conf.5.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pipewire.conf #############
View file
pipewire-0.3.43.tar.gz/man/pw-cat.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-cat.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pw-cat ###### @@ -44,13 +42,16 @@ a connection is made to the default PipeWire instance. -p | --playback - Playback mode. Read data from the specified file, and play it back. If the tool is called under the name **pw-play** or **pw-midiplay** this is the default. + Playback mode. Read data from the specified file, and play it back. If the tool + is called under the name **pw-play** or **pw-midiplay** this is the default. -r | --record - Recording mode. Capture data and write it to the specified file. If the tool is called under the name **pw-record** or **pw-midirecord** this is the default. + Recording mode. Capture data and write it to the specified file. If the tool is + called under the name **pw-record** or **pw-midirecord** this is the default. -m | --midi - MIDI mode. *FILE* is a MIDI file. If the tool is called under the name **pw-midiplay** or **pw-midirecord** this is the default. + MIDI mode. *FILE* is a MIDI file. If the tool is called under the name + **pw-midiplay** or **pw-midirecord** this is the default. --media-type=VALUE Set the media type property (default Audio/Midi depending on mode).
View file
pipewire-0.3.43.tar.gz/man/pw-cli.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-cli.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pw-cli ###### @@ -45,7 +43,8 @@ MODULE MANAGEMENT ================= -| Modules are loaded and unloaded in the local instance and can add functionality or objects to the local instance. +| Modules are loaded and unloaded in the local instance and can add +| functionality or objects to the local instance. load-module *name* [*arguments...*] Load a module specified by its name and arguments. For most
View file
pipewire-0.3.43.tar.gz/man/pw-dot.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-dot.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pw-dot ######
View file
pipewire-0.3.43.tar.gz/man/pw-jack.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-jack.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pw-jack #######
View file
pipewire-0.3.43.tar.gz/man/pw-metadata.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-metadata.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pw-metadata ###########
View file
pipewire-0.3.43.tar.gz/man/pw-mididump.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-mididump.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pw-mididump ###########
View file
pipewire-0.3.43.tar.gz/man/pw-mon.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-mon.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pw-mon ######
View file
pipewire-0.3.43.tar.gz/man/pw-profiler.1.rst.in -> pipewire-0.3.44.tar.gz/man/pw-profiler.1.rst.in
Changed
@@ -1,5 +1,3 @@ -.. This file is part of PipeWire. - pw-profiler ###########
View file
pipewire-0.3.43.tar.gz/meson.build -> pipewire-0.3.44.tar.gz/meson.build
Changed
@@ -1,7 +1,7 @@ project('pipewire', ['c' ], - version : '0.3.43', + version : '0.3.44', license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ], - meson_version : '>= 0.56.0', + meson_version : '>= 0.59.0', default_options : [ 'warning_level=3', 'c_std=gnu99', 'cpp_std=c++17', @@ -323,12 +323,12 @@ dl_lib = cc.find_library('dl', required : false) pthread_lib = dependency('threads') dbus_dep = dependency('dbus-1', required : get_option('dbus')) -summary({'dbus (Bluetooth, rtkit, portal, pw-reserve)': dbus_dep.found()}, bool_yn: true, section: 'Misc dependencies') +summary({'dbus (Bluetooth, rt, portal, pw-reserve)': dbus_dep.found()}, bool_yn: true, section: 'Misc dependencies') if dbus_dep.found() cdata.set('HAVE_DBUS', 1) endif sdl_dep = dependency('sdl2', required : get_option('sdl2')) -summary({'SDL 2': sdl_dep.found()}, bool_yn: true, section: 'Misc dependencies') +summary({'SDL2 (video examples)': sdl_dep.found()}, bool_yn: true, section: 'Misc dependencies') drm_dep = dependency('libdrm', required : false) readline_dep = dependency('readline', required : false) @@ -349,6 +349,14 @@ summary({'Avahi DNS-SD (Zeroconf)': avahi_dep.found()}, bool_yn: true, section: 'Streaming between daemons') +x11_dep = dependency('x11-xcb', required : get_option('x11')) +summary({'X11 (x11-bell)': x11_dep.found()}, bool_yn: true, + section: 'Misc dependencies') + +canberra_dep = dependency('libcanberra', required : get_option('libcanberra')) +summary({'libcanberra (x11-bell)': canberra_dep.found()}, bool_yn: true, + section: 'Misc dependencies') + libusb_dep = dependency('libusb-1.0', required : get_option('libusb')) summary({'libusb (Bluetooth quirks)': libusb_dep.found()}, bool_yn: true, section: 'Backend') if libusb_dep.found() @@ -479,22 +487,25 @@ subdir('pipewire-alsa/tests') endif -doxygen = find_program('doxygen', required : get_option('docs')) -if doxygen.found() - subdir('doc') -endif - +generate_manpages = false if not get_option('man').disabled() rst2man = find_program('rst2man', required: false) if not rst2man.found() rst2man = find_program('rst2man.py', required: get_option('man')) endif - summary({'Manpage generation': rst2man.found()}, bool_yn: true) if rst2man.found() - subdir('man') + generate_manpages = true endif endif +summary({'Manpage generation': generate_manpages}, bool_yn: true) +subdir('man') + +doxygen = find_program('doxygen', required : get_option('docs')) +if doxygen.found() + subdir('doc') +endif + setenv = find_program('pw-uninstalled.sh') run_target('pw-uninstalled', command : [setenv, @@ -502,27 +513,25 @@ '-v@0@'.format(pipewire_version)] ) -if meson.version().version_compare('>=0.58.0') - devenv = environment() +devenv = environment() - builddir = meson.project_build_root() - srcdir = meson.project_source_root() +builddir = meson.project_build_root() +srcdir = meson.project_source_root() - devenv.set('PIPEWIRE_CONFIG_DIR', pipewire_dep.get_variable(internal: 'confdatadir')) - devenv.set('PIPEWIRE_MODULE_DIR', pipewire_dep.get_variable(internal: 'moduledir')) +devenv.set('PIPEWIRE_CONFIG_DIR', pipewire_dep.get_variable('confdatadir')) +devenv.set('PIPEWIRE_MODULE_DIR', pipewire_dep.get_variable('moduledir')) - devenv.set('SPA_PLUGIN_DIR', spa_dep.get_variable(internal: 'plugindir')) - devenv.set('SPA_DATA_DIR', spa_dep.get_variable(internal: 'datadir')) +devenv.set('SPA_PLUGIN_DIR', spa_dep.get_variable('plugindir')) +devenv.set('SPA_DATA_DIR', spa_dep.get_variable('datadir')) - devenv.set('GST_PLUGIN_PATH', builddir / 'src'/ 'gst') +devenv.set('GST_PLUGIN_PATH', builddir / 'src'/ 'gst') - devenv.set('ALSA_PLUGIN_DIR', builddir / 'pipewire-alsa' / 'alsa-plugins') - devenv.set('ACP_PATHS_DIR', srcdir / 'spa' / 'plugins' / 'alsa' / 'mixer' / 'paths') - devenv.set('ACP_PROFILES_DIR', srcdir / 'spa' / 'plugins' / 'alsa' / 'mixer' / 'profile-sets') +devenv.set('ALSA_PLUGIN_DIR', builddir / 'pipewire-alsa' / 'alsa-plugins') +devenv.set('ACP_PATHS_DIR', srcdir / 'spa' / 'plugins' / 'alsa' / 'mixer' / 'paths') +devenv.set('ACP_PROFILES_DIR', srcdir / 'spa' / 'plugins' / 'alsa' / 'mixer' / 'profile-sets') - devenv.set('LD_LIBRARY_PATH', builddir / 'pipewire-jack' / 'src') +devenv.set('LD_LIBRARY_PATH', builddir / 'pipewire-jack' / 'src') - devenv.set('PW_UNINSTALLED', '1') +devenv.set('PW_UNINSTALLED', '1') - meson.add_devenv(devenv) -endif +meson.add_devenv(devenv)
View file
pipewire-0.3.43.tar.gz/meson_options.txt -> pipewire-0.3.44.tar.gz/meson_options.txt
Changed
@@ -179,6 +179,9 @@ option('udevrulesdir', type : 'string', description : 'Directory for udev rules (defaults to /lib/udev/rules.d)') +option('systemd-system-unit-dir', + type : 'string', + description : 'Directory for system systemd units (defaults to /usr/lib/systemd/system)') option('systemd-user-unit-dir', type : 'string', description : 'Directory for user systemd units (defaults to /usr/lib/systemd/user)') @@ -222,3 +225,11 @@ description: 'Enable loading of LV2 plugins', type: 'feature', value: 'auto') +option('x11', + description: 'Enable code that depends on X11', + type: 'feature', + value: 'auto') +option('libcanberra', + description: 'Enable code that depends on libcanberra', + type: 'feature', + value: 'auto')
View file
pipewire-0.3.43.tar.gz/pipewire-jack/src/meson.build -> pipewire-0.3.44.tar.gz/pipewire-jack/src/meson.build
Changed
@@ -11,10 +11,9 @@ 'control.c', ] -pipewire_dummy_sources = [ - 'dummy.c', +pipewire_net_sources = [ + 'net.c', ] - pipewire_jack_c_args = [ '-DPIC', ] @@ -57,8 +56,8 @@ install_dir : libjack_path, ) -pipewire_jackserver = shared_library('jacknet', - pipewire_dummy_sources, +pipewire_jacknet = shared_library('jacknet', + pipewire_net_sources, soversion : soversion, version : libversion, c_args : pipewire_jack_c_args, @@ -85,7 +84,7 @@ description : 'PipeWire JACK API', version : '1.9.17', extra_cflags : '-D_REENTRANT', - unescaped_variables: ['server_libs=-L${libdir} -ljackserver']) + unescaped_variables: ['server_libs=-L${libdir} -ljackserver', 'jack_implementation=pipewire']) endif if sdl_dep.found()
View file
pipewire-0.3.43.tar.gz/pipewire-jack/src/metadata.c -> pipewire-0.3.44.tar.gz/pipewire-jack/src/metadata.c
Changed
@@ -213,7 +213,8 @@ const char* type) { struct client *c = (struct client *) client; - uint32_t id; + struct object *o; + uint32_t serial; int res = -1; spa_return_val_if_fail(c != NULL, -EINVAL); @@ -227,14 +228,16 @@ if (subject & (1<<30)) goto done; - id = jack_uuid_to_index(subject); + serial = jack_uuid_to_index(subject); + if ((o = find_by_serial(c, serial)) == NULL) + goto done; if (type == NULL) type = ""; - pw_log_info("set id:%u (%"PRIu64") '%s' to '%s@%s'", id, subject, key, value, type); + pw_log_info("set id:%u (%"PRIu64") '%s' to '%s@%s'", o->id, subject, key, value, type); if (update_property(c, subject, key, type, value)) - pw_metadata_set_property(c->metadata->proxy, id, key, type, value); + pw_metadata_set_property(c->metadata->proxy, o->id, key, type, value); res = 0; done: pw_thread_loop_unlock(c->context.loop);
View file
pipewire-0.3.44.tar.gz/pipewire-jack/src/net.c
Added
@@ -0,0 +1,169 @@ +/* PipeWire + * + * Copyright © 2022 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> + +#include <jack/net.h> + +#include <pipewire/pipewire.h> + +SPA_EXPORT +jack_net_slave_t* jack_net_slave_open(const char* ip, int port, const char* name, + jack_slave_t* request, jack_master_t* result) +{ + return NULL; +} + +SPA_EXPORT +int jack_net_slave_close(jack_net_slave_t* net) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_set_net_slave_process_callback(jack_net_slave_t * net, JackNetSlaveProcessCallback net_callback, void *arg) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_net_slave_activate(jack_net_slave_t* net) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_net_slave_deactivate(jack_net_slave_t* net) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_net_slave_is_active(jack_net_slave_t* net) +{ + return false; +} + +SPA_EXPORT +int jack_set_net_slave_buffer_size_callback(jack_net_slave_t *net, JackNetSlaveBufferSizeCallback bufsize_callback, void *arg) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_set_net_slave_sample_rate_callback(jack_net_slave_t *net, JackNetSlaveSampleRateCallback samplerate_callback, void *arg) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_set_net_slave_shutdown_callback(jack_net_slave_t *net, JackNetSlaveShutdownCallback shutdown_callback, void *arg) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_set_net_slave_restart_callback(jack_net_slave_t *net, JackNetSlaveRestartCallback restart_callback, void *arg) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_set_net_slave_error_callback(jack_net_slave_t *net, JackNetSlaveErrorCallback error_callback, void *arg) +{ + return ENOTSUP; +} + +SPA_EXPORT +jack_net_master_t* jack_net_master_open(const char* ip, int port, jack_master_t* request, jack_slave_t* result) +{ + return NULL; +} + +SPA_EXPORT +int jack_net_master_close(jack_net_master_t* net) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_net_master_recv(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_net_master_recv_slice(jack_net_master_t* net, int audio_input, float** audio_input_buffer, int midi_input, void** midi_input_buffer, int frames) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_net_master_send(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_net_master_send_slice(jack_net_master_t* net, int audio_output, float** audio_output_buffer, int midi_output, void** midi_output_buffer, int frames) +{ + return ENOTSUP; +} + +SPA_EXPORT +jack_adapter_t* jack_create_adapter(int input, int output, + jack_nframes_t host_buffer_size, + jack_nframes_t host_sample_rate, + jack_nframes_t adapted_buffer_size, + jack_nframes_t adapted_sample_rate) +{ + return NULL; +} + +SPA_EXPORT +int jack_destroy_adapter(jack_adapter_t* adapter) +{ + return ENOTSUP; +} + +SPA_EXPORT +void jack_flush_adapter(jack_adapter_t* adapter) +{ +} + +SPA_EXPORT +int jack_adapter_push_and_pull(jack_adapter_t* adapter, float** input, float** output, unsigned int frames) +{ + return ENOTSUP; +} + +SPA_EXPORT +int jack_adapter_pull_and_push(jack_adapter_t* adapter, float** input, float** output, unsigned int frames) +{ + return ENOTSUP; +}
View file
pipewire-0.3.43.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.44.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -99,14 +99,14 @@ jack_thread_creator_t creator; pthread_mutex_t lock; struct pw_array descriptions; - struct spa_list free_objects[3]; - struct pw_map cache; + struct spa_list free_objects; }; static struct globals globals; static bool mlock_warned = false; -#define OBJECT_CHUNK 8 +#define OBJECT_CHUNK 8 +#define RECYCLE_THRESHOLD 128 typedef void (*mix2_func) (float *dst, float *src1, float *src2, int n_samples); @@ -122,7 +122,7 @@ #define INTERFACE_Link 2 uint32_t type; uint32_t id; - uint32_t idx; + uint32_t serial; union { struct { @@ -134,11 +134,11 @@ struct { uint32_t src; uint32_t dst; + uint32_t src_serial; + uint32_t dst_serial; bool src_ours; bool dst_ours; bool is_complete; - uint32_t src_idx; - uint32_t dst_idx; struct port *our_input; struct port *our_output; } port_link; @@ -151,7 +151,6 @@ uint32_t system_id; uint32_t type_id; uint32_t node_id; - uint32_t port_id; uint32_t monitor_requests; int32_t priority; struct port *port; @@ -164,6 +163,7 @@ struct spa_hook proxy_listener; struct spa_hook object_listener; unsigned int removing:1; + unsigned int removed:1; }; struct midi_buffer { @@ -223,7 +223,7 @@ struct client *client; enum spa_direction direction; - uint32_t id; + uint32_t port_id; struct object *object; struct pw_properties *props; struct spa_port_info info; @@ -264,15 +264,13 @@ struct pw_context *context; pthread_mutex_t lock; /* protects map and lists below, in addition to thread_lock */ - struct pw_map globals; - struct spa_list ports; - struct spa_list nodes; - struct spa_list links; + struct spa_list objects; + uint32_t free_count; }; #define GET_DIRECTION(f) ((f) & JackPortIsInput ? SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT) -#define GET_PORT(c,d,p) ((d >= 0 && d <=1 && p < c->n_port_pool[d]) ? c->port_pool[d][p] : NULL) +#define GET_PORT(c,d,p) (pw_map_lookup(&c->ports[d], p)) struct metadata { struct pw_metadata *proxy; @@ -315,6 +313,7 @@ struct metadata *metadata; uint32_t node_id; + uint32_t serial; struct spa_source *socket_source; JackThreadCallback thread_callback; @@ -362,10 +361,8 @@ struct spa_list mix; struct spa_list free_mix; - uint32_t n_port_pool[2]; - struct port *port_pool[2][MAX_PORTS]; - struct spa_list ports[2]; - struct spa_list free_ports[2]; + struct spa_list free_ports; + struct pw_map ports[2]; struct spa_list links; uint32_t driver_id; @@ -406,6 +403,7 @@ }; static int do_sync(struct client *client); +static struct object *find_by_serial(struct client *c, uint32_t serial); #include "metadata.c" @@ -413,64 +411,66 @@ int (*matched) (void *data, const char *action, const char *val, int len), void *data); -static void init_port_pool(struct client *c, enum spa_direction direction) -{ - spa_list_init(&c->ports[direction]); - spa_list_init(&c->free_ports[direction]); - c->n_port_pool[direction] = 0; -} - -static struct object * find_cache(uint32_t type, uint32_t idx) -{ - struct object *o; - pthread_mutex_lock(&globals.lock); - o = pw_map_lookup(&globals.cache, idx); - if (o != NULL && o->type != type) - o = NULL; - pthread_mutex_unlock(&globals.lock); - return o; -} - static struct object * alloc_object(struct client *c, int type) { struct object *o; int i; pthread_mutex_lock(&globals.lock); - if (spa_list_is_empty(&globals.free_objects[type])) { + if (spa_list_is_empty(&globals.free_objects)) { o = calloc(OBJECT_CHUNK, sizeof(struct object)); if (o == NULL) { pthread_mutex_unlock(&globals.lock); return NULL; } - for (i = 0; i < OBJECT_CHUNK; i++) { - o[i].idx = pw_map_insert_new(&globals.cache, &o[i]); - spa_list_append(&globals.free_objects[type], &o[i].link); - } + for (i = 0; i < OBJECT_CHUNK; i++) + spa_list_append(&globals.free_objects, &o[i].link); } - o = spa_list_first(&globals.free_objects[type], struct object, link); + o = spa_list_first(&globals.free_objects, struct object, link); spa_list_remove(&o->link); pthread_mutex_unlock(&globals.lock); o->client = c; + o->removed = false; o->type = type; pw_log_debug("%p: object:%p type:%d", c, o, type); return o; } +static void recycle_objects(struct client *c, uint32_t remain) +{ + struct object *o, *t; + pthread_mutex_lock(&globals.lock); + spa_list_for_each_safe(o, t, &c->context.objects, link) { + if (o->removed) { + pw_log_info("%p: recycle object:%p type:%d id:%u/%u", + c, o, o->type, o->id, o->serial); + spa_list_remove(&o->link); + memset(o, 0, sizeof(struct object)); + spa_list_append(&globals.free_objects, &o->link); + if (--c->context.free_count == remain) + break; + } + } + pthread_mutex_unlock(&globals.lock); +} + +/* JACK clients expect the objects to hang around after + * they are unregistered and freed. We mark the object removed and + * move it to the end of the queue. */ static void free_object(struct client *c, struct object *o) { + pw_log_debug("%p: object:%p type:%d", c, o, o->type); pthread_mutex_lock(&c->context.lock); spa_list_remove(&o->link); + o->removed = true; + o->id = SPA_ID_INVALID; + spa_list_append(&c->context.objects, &o->link); + if (++c->context.free_count > RECYCLE_THRESHOLD) + recycle_objects(c, RECYCLE_THRESHOLD / 2); pthread_mutex_unlock(&c->context.lock); - pw_log_debug("%p: object:%p type:%d", c, o, o->type); - - pthread_mutex_lock(&globals.lock); - spa_list_append(&globals.free_objects[o->type], &o->link); - o->client = NULL; - pthread_mutex_unlock(&globals.lock); } static void init_mix(struct mix *mix, uint32_t mix_id, struct port *port) @@ -565,30 +565,21 @@ { struct port *p; struct object *o; - uint32_t i, n; + uint32_t i; - if (spa_list_is_empty(&c->free_ports[direction])) { + if (spa_list_is_empty(&c->free_ports)) { p = calloc(OBJECT_CHUNK, sizeof(struct port)); if (p == NULL) return NULL; - n = c->n_port_pool[direction]; - for (i = 0; i < OBJECT_CHUNK; i++, n++) { - p[i].direction = direction; - p[i].id = n; - p[i].emptyptr = SPA_PTR_ALIGN(p[i].empty, MAX_ALIGN, float); - c->port_pool[direction][n] = &p[i]; - spa_list_append(&c->free_ports[direction], &p[i].link); - } - c->n_port_pool[direction] = n; - + for (i = 0; i < OBJECT_CHUNK; i++) + spa_list_append(&c->free_ports, &p[i].link); } - p = spa_list_first(&c->free_ports[direction], struct port, link); + p = spa_list_first(&c->free_ports, struct port, link); spa_list_remove(&p->link); o = alloc_object(c, INTERFACE_Port); o->id = SPA_ID_INVALID; o->port.node_id = c->node_id; - o->port.port_id = p->id; o->port.port = p; o->port.latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); o->port.latency[SPA_DIRECTION_OUTPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); @@ -600,10 +591,12 @@ spa_list_init(&p->mix); p->props = pw_properties_new(NULL, NULL); - spa_list_append(&c->ports[direction], &p->link); + p->direction = direction; + p->emptyptr = SPA_PTR_ALIGN(p->empty, MAX_ALIGN, float); + p->port_id = pw_map_insert_new(&c->ports[direction], p); pthread_mutex_lock(&c->context.lock); - spa_list_append(&c->context.ports, &o->link); + spa_list_append(&c->context.objects, &o->link); pthread_mutex_unlock(&c->context.lock); return p; @@ -619,19 +612,21 @@ spa_list_consume(m, &p->mix, port_link) free_mix(c, m); - spa_list_remove(&p->link); p->valid = false; + pw_map_remove(&c->ports[p->direction], p->port_id); free_object(c, p->object); pw_properties_free(p->props); - spa_list_append(&c->free_ports[p->direction], &p->link); + spa_list_append(&c->free_ports, &p->link); } static struct object *find_node(struct client *c, const char *name) { struct object *o; - spa_list_for_each(o, &c->context.nodes, link) { - if (!o->removing && spa_streq(o->node.name, name)) + spa_list_for_each(o, &c->context.objects, link) { + if (o->removing || o->removed || o->type != INTERFACE_Node) + continue; + if (spa_streq(o->node.name, name)) return o; } return NULL; @@ -652,11 +647,13 @@ return false; } -static struct object *find_port(struct client *c, const char *name) +static struct object *find_port_by_name(struct client *c, const char *name) { struct object *o; - spa_list_for_each(o, &c->context.ports, link) { + spa_list_for_each(o, &c->context.objects, link) { + if (o->type != INTERFACE_Port || o->removed) + continue; if (spa_streq(o->port.name, name) || spa_streq(o->port.alias1, name) || spa_streq(o->port.alias2, name)) @@ -667,9 +664,29 @@ return NULL; } +static struct object *find_by_id(struct client *c, uint32_t id) +{ + struct object *o; + spa_list_for_each(o, &c->context.objects, link) { + if (o->id == id) + return o; + } + return NULL; +} + +static struct object *find_by_serial(struct client *c, uint32_t serial) +{ + struct object *o; + spa_list_for_each(o, &c->context.objects, link) { + if (o->serial == serial) + return o; + } + return NULL; +} + static struct object *find_id(struct client *c, uint32_t id, bool valid) { - struct object *o = pw_map_lookup(&c->context.globals, id); + struct object *o = find_by_id(c, id); if (o != NULL && (!valid || o->client == c)) return o; return NULL; @@ -687,7 +704,9 @@ { struct object *l; - spa_list_for_each(l, &c->context.links, link) { + spa_list_for_each(l, &c->context.objects, link) { + if (l->type != INTERFACE_Link || l->removed) + continue; if (l->port_link.src == src && l->port_link.dst == dst) { return l; @@ -1002,7 +1021,7 @@ return NULL; pw_log_trace_fp("%p: port %s %d get buffer %d n_buffers:%d", - c, p->object->port.name, p->id, frames, mix->n_buffers); + c, p->object->port.name, p->port_id, frames, mix->n_buffers); if (SPA_UNLIKELY(mix->n_buffers == 0)) return NULL; @@ -1077,14 +1096,21 @@ { struct port *p; struct mix *mix; + union pw_map_item *item; - spa_list_for_each(p, &c->ports[SPA_DIRECTION_INPUT], link) { + pw_array_for_each(item, &c->ports[SPA_DIRECTION_INPUT].items) { + if (pw_map_item_is_free(item)) + continue; + p = item->data; spa_list_for_each(mix, &p->mix, port_link) { if (SPA_LIKELY(mix->io != NULL)) mix->io->status = SPA_STATUS_NEED_DATA; } - } - spa_list_for_each(p, &c->ports[SPA_DIRECTION_OUTPUT], link) { + } + pw_array_for_each(item, &c->ports[SPA_DIRECTION_OUTPUT].items) { + if (pw_map_item_is_free(item)) + continue; + p = item->data; prepare_output(p, frames); p->io.status = SPA_STATUS_NEED_DATA; } @@ -1227,7 +1253,8 @@ { uint32_t buffer_frames = *((uint32_t*)data); struct client *c = user_data; - do_callback_expr(c, c->buffer_frames = buffer_frames, bufsize_callback, buffer_frames, c->bufsize_arg); + if (c->buffer_frames != buffer_frames) + do_callback_expr(c, c->buffer_frames = buffer_frames, bufsize_callback, buffer_frames, c->bufsize_arg); recompute_latencies(c); return 0; } @@ -1771,7 +1798,7 @@ SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_STEP_Int( MAX_BUFFER_FRAMES * sizeof(float), sizeof(float), - MAX_BUFFER_FRAMES * sizeof(float), + INT32_MAX, sizeof(float)), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(p->object->port.type_id == TYPE_ID_AUDIO ? sizeof(float) : 1)); @@ -1889,7 +1916,7 @@ pw_client_node_port_update(c->node, p->direction, - p->id, + p->port_id, PW_CLIENT_NODE_PORT_UPDATE_PARAMS | PW_CLIENT_NODE_PORT_UPDATE_INFO, SPA_N_ELEMENTS(params), @@ -1921,7 +1948,7 @@ pw_client_node_port_update(c->node, p->direction, - p->id, + p->port_id, PW_CLIENT_NODE_PORT_UPDATE_PARAMS | PW_CLIENT_NODE_PORT_UPDATE_INFO, SPA_N_ELEMENTS(params), @@ -1935,14 +1962,19 @@ struct spa_latency_info *latency) { enum spa_direction other; + union pw_map_item *item; struct port *p; other = SPA_DIRECTION_REVERSE(direction); spa_latency_info_combine_start(latency, direction); - spa_list_for_each(p, &c->ports[other], link) + pw_array_for_each(item, &c->ports[other].items) { + if (pw_map_item_is_free(item)) + continue; + p = item->data; spa_latency_info_combine(latency, &p->object->port.latency[direction]); + } spa_latency_info_combine_finish(latency); } @@ -1952,6 +1984,7 @@ { struct spa_latency_info latency, *current; enum spa_direction direction; + union pw_map_item *item; struct port *p; if (mode == JackPlaybackLatency) @@ -1967,7 +2000,10 @@ latency.min_rate, latency.max_rate, latency.min_ns, latency.max_ns); - spa_list_for_each(p, &c->ports[direction], link) { + pw_array_for_each(item, &c->ports[direction].items) { + if (pw_map_item_is_free(item)) + continue; + p = item->data; current = &p->object->port.latency[direction]; if (spa_latency_info_compare(current, &latency) == 0) continue; @@ -2407,11 +2443,11 @@ if (!l->port_link.is_complete) { l->port_link.is_complete = true; - pw_log_info("%p: our link %d/%u -> %d/%u completed", c, - l->port_link.src, l->port_link.src_idx, - l->port_link.dst, l->port_link.dst_idx); + pw_log_info("%p: our link %u/%u -> %u/%u completed", c, + l->port_link.src, l->port_link.src_serial, + l->port_link.dst, l->port_link.dst_serial); do_callback(c, connect_callback, - l->port_link.src_idx, l->port_link.dst_idx, 1, c->connect_arg); + l->port_link.src_serial, l->port_link.dst_serial, 1, c->connect_arg); recompute_latencies(c); do_callback(c, graph_callback, c->graph_arg); } @@ -2538,10 +2574,10 @@ switch (o->type) { case INTERFACE_Node: - uuid = client_make_uuid(id, false); + uuid = client_make_uuid(o->serial, false); break; case INTERFACE_Port: - uuid = jack_port_uuid_generate(id); + uuid = jack_port_uuid_generate(o->serial); break; default: return -EINVAL; @@ -2621,12 +2657,18 @@ struct client *c = (struct client *) data; struct object *o, *ot, *op; const char *str; - size_t size; bool is_first = false, graph_changed = false; + uint32_t serial; if (props == NULL) return; + str = spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL); + if (!spa_atou32(str, &serial, 0)) + serial = SPA_ID_INVALID; + + pw_log_debug("new %s id:%u serial:%u", type, id, serial); + if (spa_streq(type, PW_TYPE_INTERFACE_Node)) { const char *app, *node_name; char tmp[JACK_CLIENT_NAME_SIZE+1]; @@ -2642,6 +2684,7 @@ pw_log_debug("%p: add our node %d", c, id); if (node_name != NULL) snprintf(c->name, sizeof(c->name), "%s", node_name); + c->serial = serial; } snprintf(o->node.node_name, sizeof(o->node.node_name), "%s", node_name); @@ -2685,7 +2728,7 @@ pw_log_debug("%p: add node %d", c, id); pthread_mutex_lock(&c->context.lock); - spa_list_append(&c->context.nodes, &o->link); + spa_list_append(&c->context.objects, &o->link); pthread_mutex_unlock(&c->context.lock); } else if (spa_streq(type, PW_TYPE_INTERFACE_Port)) { @@ -2742,34 +2785,19 @@ o = NULL; if (node_id == c->node_id) { snprintf(tmp, sizeof(tmp), "%s:%s", c->name, str); - o = find_port(c, tmp); + o = find_port_by_name(c, tmp); if (o != NULL) - pw_log_debug("%p: %s found our port %p", c, tmp, o); + pw_log_info("%p: %s found our port %p", c, tmp, o); } if (o == NULL) { + if ((ot = find_type(c, node_id, INTERFACE_Node, true)) == NULL) + goto exit; + o = alloc_object(c, INTERFACE_Port); if (o == NULL) goto exit; - pthread_mutex_lock(&c->context.lock); - spa_list_append(&c->context.ports, &o->link); - pthread_mutex_unlock(&c->context.lock); - - if ((ot = find_type(c, node_id, INTERFACE_Node, true)) == NULL) - goto exit_free; - - if (is_monitor && !c->merge_monitor) - snprintf(tmp, sizeof(tmp), "%.*s%s:%s", - (int)(JACK_CLIENT_NAME_SIZE-(sizeof(MONITOR_EXT)-1)), - ot->node.name, MONITOR_EXT, str); - else - snprintf(tmp, sizeof(tmp), "%s:%s", ot->node.name, str); - - if (c->filter_name) - filter_name(tmp, FILTER_PORT); - o->port.system_id = 0; - o->port.port_id = SPA_ID_INVALID; o->port.priority = ot->node.priority; o->port.node = ot; o->port.latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); @@ -2788,6 +2816,26 @@ pw_port_subscribe_params((struct pw_port*)o->proxy, ids, 1); } + pthread_mutex_lock(&c->context.lock); + spa_list_append(&c->context.objects, &o->link); + pthread_mutex_unlock(&c->context.lock); + + if (is_monitor && !c->merge_monitor) + snprintf(tmp, sizeof(tmp), "%.*s%s:%s", + (int)(JACK_CLIENT_NAME_SIZE-(sizeof(MONITOR_EXT)-1)), + ot->node.name, MONITOR_EXT, str); + else + snprintf(tmp, sizeof(tmp), "%s:%s", ot->node.name, str); + + if (c->filter_name) + filter_name(tmp, FILTER_PORT); + + op = find_port_by_name(c, tmp); + if (op != NULL) + snprintf(o->port.name, sizeof(o->port.name), "%.*s-%u", + (int)(sizeof(tmp)-11), tmp, serial); + else + snprintf(o->port.name, sizeof(o->port.name), "%s", tmp); } if ((str = spa_dict_lookup(props, PW_KEY_OBJECT_PATH)) != NULL) @@ -2809,14 +2857,7 @@ o->port.node_id = node_id; o->port.is_monitor = is_monitor; - op = find_port(c, tmp); - if (op != NULL && op != o) - snprintf(o->port.name, sizeof(o->port.name), "%.*s-%d", - (int)(sizeof(tmp)-11), tmp, id); - else - snprintf(o->port.name, sizeof(o->port.name), "%s", tmp); - - pw_log_debug("%p: add port %d name:%s %d", c, id, + pw_log_debug("%p: %p add port %d name:%s %d", c, o, id, o->port.name, type_id); } else if (spa_streq(type, PW_TYPE_INTERFACE_Link)) { @@ -2825,7 +2866,7 @@ o = alloc_object(c, INTERFACE_Link); pthread_mutex_lock(&c->context.lock); - spa_list_append(&c->context.links, &o->link); + spa_list_append(&c->context.objects, &o->link); pthread_mutex_unlock(&c->context.lock); if ((str = spa_dict_lookup(props, PW_KEY_LINK_OUTPUT_PORT)) == NULL) @@ -2834,7 +2875,7 @@ if ((p = find_type(c, o->port_link.src, INTERFACE_Port, true)) == NULL) goto exit_free; - o->port_link.src_idx = p->idx; + o->port_link.src_serial = p->serial; o->port_link.src_ours = p->port.port != NULL && p->port.port->client == c; @@ -2847,16 +2888,17 @@ if ((p = find_type(c, o->port_link.dst, INTERFACE_Port, true)) == NULL) goto exit_free; + o->port_link.dst_serial = p->serial; - o->port_link.dst_idx = p->idx; o->port_link.dst_ours = p->port.port != NULL && p->port.port->client == c; if (o->port_link.dst_ours) o->port_link.our_input = p->port.port; o->port_link.is_complete = !o->port_link.src_ours && !o->port_link.dst_ours; - pw_log_debug("%p: add link %d %d->%d", c, id, - o->port_link.src, o->port_link.dst); + pw_log_debug("%p: add link %d %u/%u->%u/%u", c, id, + o->port_link.src, o->port_link.src_serial, + o->port_link.dst, o->port_link.dst_serial); } else if (spa_streq(type, PW_TYPE_INTERFACE_Metadata)) { struct pw_proxy *proxy; @@ -2885,13 +2927,7 @@ } o->id = id; - - pthread_mutex_lock(&c->context.lock); - size = pw_map_get_size(&c->context.globals); - while (id > size) - pw_map_insert_at(&c->context.globals, size++, NULL); - pw_map_insert_at(&c->context.globals, id, o); - pthread_mutex_unlock(&c->context.lock); + o->serial = serial; switch (o->type) { case INTERFACE_Node: @@ -2904,20 +2940,21 @@ break; case INTERFACE_Port: - pw_log_info("%p: port added %d/%d \"%s\"", c, o->id, o->idx, o->port.name); + pw_log_info("%p: port added %u/%u \"%s\"", c, o->id, o->serial, o->port.name); do_callback(c, portregistration_callback, - o->idx, 1, c->portregistration_arg); + o->serial, 1, c->portregistration_arg); graph_changed = true; break; case INTERFACE_Link: - pw_log_info("%p: link %u/%u %d/%d -> %d/%d added complete:%d", c, o->id, o->idx, - o->port_link.src, o->port_link.src_idx, - o->port_link.dst, o->port_link.dst_idx, + pw_log_info("%p: link %u %u/%u -> %u/%u added complete:%d", c, + o->id, o->port_link.src, o->port_link.src_serial, + o->port_link.dst, o->port_link.dst_serial, o->port_link.is_complete); if (o->port_link.is_complete) { do_callback(c, connect_callback, - o->port_link.src_idx, o->port_link.dst_idx, 1, c->connect_arg); + o->port_link.src_serial, + o->port_link.dst_serial, 1, c->connect_arg); graph_changed = true; } break; @@ -2967,21 +3004,21 @@ } break; case INTERFACE_Port: - pw_log_info("%p: port %u/%u removed \"%s\"", c, o->id, o->idx, o->port.name); + pw_log_info("%p: port %u/%u removed \"%s\"", c, o->id, o->serial, o->port.name); do_callback(c, portregistration_callback, - o->idx, 0, c->portregistration_arg); + o->serial, 0, c->portregistration_arg); graph_changed = true; break; case INTERFACE_Link: if (o->port_link.is_complete && find_type(c, o->port_link.src, INTERFACE_Port, true) != NULL && find_type(c, o->port_link.dst, INTERFACE_Port, true) != NULL) { - pw_log_info("%p: link %u/%u %d/%u -> %d/%u removed", c, o->id, o->idx, - o->port_link.src, o->port_link.src_idx, - o->port_link.dst, o->port_link.dst_idx); + pw_log_info("%p: link %u %u/%u -> %u/%u removed", c, o->id, + o->port_link.src, o->port_link.src_serial, + o->port_link.dst, o->port_link.dst_serial); o->port_link.is_complete = false; do_callback(c, connect_callback, - o->port_link.src_idx, o->port_link.dst_idx, 0, c->connect_arg); + o->port_link.src_serial, o->port_link.dst_serial, 0, c->connect_arg); graph_changed = true; } else pw_log_warn("unlink between unknown ports %d and %d", @@ -2993,16 +3030,8 @@ do_callback(c, graph_callback, c->graph_arg); } - /* JACK clients expect the objects to hang around after - * they are unregistered. We keep the memory around for that - * reason but reuse it when we can. */ o->removing = false; free_object(c, o); - /* we keep the object available with the id because jack clients - * tend to access the objects with it later. - * - * pw_map_insert_at(&c->context.globals, id, NULL); - */ return; } @@ -3135,9 +3164,7 @@ pthread_mutex_init(&client->context.lock, NULL); pthread_mutex_init(&client->rt_lock, NULL); - spa_list_init(&client->context.nodes); - spa_list_init(&client->context.ports); - spa_list_init(&client->context.links); + spa_list_init(&client->context.objects); support = pw_context_get_support(client->context.context, &n_support); @@ -3162,10 +3189,9 @@ spa_list_init(&client->mix); spa_list_init(&client->free_mix); - init_port_pool(client, SPA_DIRECTION_INPUT); - init_port_pool(client, SPA_DIRECTION_OUTPUT); - - pw_map_init(&client->context.globals, 64, 64); + pw_map_init(&client->ports[SPA_DIRECTION_INPUT], MAX_PORTS, 32); + pw_map_init(&client->ports[SPA_DIRECTION_OUTPUT], MAX_PORTS, 32); + spa_list_init(&client->free_ports); pw_thread_loop_start(client->context.loop); @@ -3189,6 +3215,19 @@ if ((str = getenv("PIPEWIRE_LATENCY")) != NULL) pw_properties_set(client->props, PW_KEY_NODE_LATENCY, str); + if ((str = getenv("PIPEWIRE_RATE")) != NULL) + pw_properties_set(client->props, PW_KEY_NODE_RATE, str); + if ((str = getenv("PIPEWIRE_QUANTUM")) != NULL) { + struct spa_fraction q; + if (sscanf(str, "%u/%u", &q.num, &q.denom) == 2 && q.denom != 0) { + pw_properties_setf(client->props, PW_KEY_NODE_RATE, + "1/%u", q.denom); + pw_properties_setf(client->props, PW_KEY_NODE_LATENCY, + "%u/%u", q.num, q.denom); + } else { + pw_log_warn("invalid PIPEWIRE_QUANTUM: %s", str); + } + } if ((str = pw_properties_get(client->props, PW_KEY_NODE_LATENCY)) != NULL) { uint32_t num, denom; if (sscanf(str, "%u/%u", &num, &denom) == 2 && denom != 0) { @@ -3207,7 +3246,7 @@ pw_properties_set(client->props, PW_KEY_MEDIA_ROLE, "DSP"); if (pw_properties_get(client->props, PW_KEY_NODE_ALWAYS_PROCESS) == NULL) pw_properties_set(client->props, PW_KEY_NODE_ALWAYS_PROCESS, "true"); - pw_properties_set(client->props, "node.transport.sync", "true"); + pw_properties_set(client->props, PW_KEY_NODE_TRANSPORT_SYNC, "true"); client->node = pw_core_create_object(client->core, "client-node", @@ -3324,14 +3363,13 @@ pw_log_debug("%p: free", client); - spa_list_consume(o, &c->context.nodes, link) - free_object(c, o); - spa_list_consume(o, &c->context.ports, link) - free_object(c, o); - spa_list_consume(o, &c->context.links, link) + spa_list_consume(o, &c->context.objects, link) free_object(c, o); + recycle_objects(c, 0); + + pw_map_clear(&c->ports[SPA_DIRECTION_INPUT]); + pw_map_clear(&c->ports[SPA_DIRECTION_OUTPUT]); - pw_map_clear(&c->context.globals); pthread_mutex_destroy(&c->context.lock); pthread_mutex_destroy(&c->rt_lock); pw_properties_free(c->props); @@ -3412,11 +3450,13 @@ pthread_mutex_lock(&c->context.lock); - spa_list_for_each(o, &c->context.nodes, link) { + spa_list_for_each(o, &c->context.objects, link) { + if (o->type != INTERFACE_Node) + continue; if (spa_streq(o->node.name, client_name) || (monitor && spa_strneq(o->node.name, client_name, strlen(client_name) - strlen(MONITOR_EXT)))) { - uuid = spa_aprintf( "%" PRIu64, client_make_uuid(o->id, monitor)); + uuid = spa_aprintf( "%" PRIu64, client_make_uuid(o->serial, monitor)); break; } } @@ -3444,8 +3484,10 @@ monitor = uuid & (1 << 30); pthread_mutex_lock(&c->context.lock); - spa_list_for_each(o, &c->context.nodes, link) { - if (client_make_uuid(o->id, monitor) == uuid) { + spa_list_for_each(o, &c->context.objects, link) { + if (o->type != INTERFACE_Node) + continue; + if (client_make_uuid(o->serial, monitor) == uuid) { pw_log_debug("%p: uuid %s (%"PRIu64")-> %s", client, client_uuid, uuid, o->node.name); name = spa_aprintf("%s%s", o->node.name, monitor ? MONITOR_EXT : ""); @@ -3533,10 +3575,11 @@ c->activation->pending_new_pos = false; c->activation->pending_sync = false; - spa_list_for_each(l, &c->context.links, link) { - if (l->port_link.src_ours || l->port_link.dst_ours) { + spa_list_for_each(l, &c->context.objects, link) { + if (l->type != INTERFACE_Link || l->removed) + continue; + if (l->port_link.src_ours || l->port_link.dst_ours) pw_registry_destroy(c->registry, l->id); - } } res = do_sync(c); @@ -3985,6 +4028,7 @@ res = c->position->clock.duration; } } + c->buffer_frames = res; pw_log_debug("buffer_frames: %u", res); return res; } @@ -4042,21 +4086,27 @@ spa_return_val_if_fail(port_name != NULL, NULL); spa_return_val_if_fail(port_type != NULL, NULL); - pw_log_info("%p: port register \"%s\" \"%s\" %08lx %ld", - c, port_name, port_type, flags, buffer_frames); + pw_log_info("%p: port register \"%s:%s\" \"%s\" %08lx %ld", + c, c->name, port_name, port_type, flags, buffer_frames); if (flags & JackPortIsInput) direction = PW_DIRECTION_INPUT; else if (flags & JackPortIsOutput) direction = PW_DIRECTION_OUTPUT; - else + else { + pw_log_warn("invalid port flags %lu for %s", flags, port_name); return NULL; + } - if ((type_id = string_to_type(port_type)) == SPA_ID_INVALID) + if ((type_id = string_to_type(port_type)) == SPA_ID_INVALID) { + pw_log_warn("unknown port type %s", port_type); return NULL; + } - if ((p = alloc_port(c, direction)) == NULL) + if ((p = alloc_port(c, direction)) == NULL) { + pw_log_warn("can't allocate port %s: %m", port_name); return NULL; + } o = p->object; o->port.flags = flags; @@ -4132,7 +4182,7 @@ pw_client_node_port_update(c->node, direction, - p->id, + p->port_id, PW_CLIENT_NODE_PORT_UPDATE_PARAMS | PW_CLIENT_NODE_PORT_UPDATE_INFO, n_params, @@ -4145,8 +4195,11 @@ pw_thread_loop_unlock(c->context.loop); - if (res < 0) + if (res < 0) { + pw_log_warn("can't create port %s: %s", port_name, + spa_strerror(res)); return NULL; + } return (jack_port_t *) o; } @@ -4162,30 +4215,28 @@ spa_return_val_if_fail(c != NULL, -EINVAL); spa_return_val_if_fail(o != NULL, -EINVAL); - if (o->type != INTERFACE_Port || o->port.port_id == SPA_ID_INVALID || - o->client != c) { - pw_log_error("%p: invalid port %p", client, port); - return -EINVAL; - } - pw_log_info("%p: port %p unregister \"%s\"", client, port, o->port.name); - pw_thread_loop_lock(c->context.loop); - p = GET_PORT(c, GET_DIRECTION(o->port.flags), o->port.port_id); - if (p == NULL || !p->valid) { + p = o->port.port; + if (o->type != INTERFACE_Port || p == NULL || !p->valid || + o->client != c) { + pw_log_error("%p: invalid port %p", client, port); res = -EINVAL; goto done; } + pw_log_info("%p: port %p unregister \"%s\"", client, port, o->port.name); pw_client_node_port_update(c->node, p->direction, - p->id, + p->port_id, 0, 0, NULL, NULL); res = do_sync(c); - + if (res < 0) { + pw_log_warn("can't unregister port %s: %s", o->port.name, + spa_strerror(res)); + } free_port(c, p); - done: pw_thread_loop_unlock(c->context.loop); @@ -4221,7 +4272,7 @@ void *np; pw_log_trace_fp("%p: port %s mix %d.%d get buffer %d", - p->client, p->object->port.name, p->id, mix->id, frames); + p->client, p->object->port.name, p->port_id, mix->id, frames); if ((b = get_mix_buffer(mix, frames)) == NULL) continue; @@ -4261,7 +4312,7 @@ void *pod; pw_log_trace_fp("%p: port %p mix %d.%d get buffer %d", - p->client, p, p->id, mix->id, frames); + p->client, p, p->port_id, mix->id, frames); if ((b = get_mix_buffer(mix, frames)) == NULL) continue; @@ -4352,7 +4403,7 @@ { struct object *o = (struct object *) port; spa_return_val_if_fail(o != NULL, 0); - return jack_port_uuid_generate(o->id); + return jack_port_uuid_generate(o->serial); } SPA_EXPORT @@ -4420,16 +4471,18 @@ c = o->client; pthread_mutex_lock(&c->context.lock); - spa_list_for_each(l, &c->context.links, link) { + spa_list_for_each(l, &c->context.objects, link) { + if (l->type != INTERFACE_Link || l->removed) + continue; if (!l->port_link.is_complete) continue; - if (l->port_link.src == o->id || - l->port_link.dst == o->id) + if (l->port_link.src_serial == o->serial || + l->port_link.dst_serial == o->serial) res++; } pthread_mutex_unlock(&c->context.lock); - pw_log_debug("%p: id:%d res:%d", port, o->id, res); + pw_log_debug("%p: id:%u/%u res:%d", port, o->id, o->serial, res); return res; } @@ -4452,7 +4505,7 @@ pthread_mutex_lock(&c->context.lock); - p = find_port(c, port_name); + p = find_port_by_name(c, port_name); if (p == NULL) goto exit; @@ -4470,7 +4523,8 @@ exit: pthread_mutex_unlock(&c->context.lock); - pw_log_debug("%p: id:%d name:%s res:%d", port, o->id, port_name, res); + pw_log_debug("%p: id:%u/%u name:%s res:%d", port, o->id, + o->serial, port_name, res); return res; } @@ -4503,10 +4557,12 @@ res = malloc(sizeof(char*) * (CONNECTION_NUM_FOR_PORT + 1)); pthread_mutex_lock(&c->context.lock); - spa_list_for_each(l, &c->context.links, link) { - if (l->port_link.src == o->id) + spa_list_for_each(l, &c->context.objects, link) { + if (l->type != INTERFACE_Link || l->removed) + continue; + if (l->port_link.src_serial == o->serial) p = find_type(c, l->port_link.dst, INTERFACE_Port, true); - else if (l->port_link.dst == o->id) + else if (l->port_link.dst_serial == o->serial) p = find_type(c, l->port_link.src, INTERFACE_Port, true); else continue; @@ -4567,13 +4623,12 @@ pw_log_info("%p: port rename %p %s -> %s:%s", client, port, o->port.name, c->name, port_name); - p = GET_PORT(c, GET_DIRECTION(o->port.flags), o->port.port_id); + p = o->port.port; if (p == NULL || !p->valid) { res = -EINVAL; goto done; } - pw_properties_set(p->props, PW_KEY_PORT_NAME, port_name); snprintf(o->port.name, sizeof(o->port.name), "%s:%s", c->name, port_name); @@ -4582,7 +4637,7 @@ pw_client_node_port_update(c->node, p->direction, - p->id, + p->port_id, PW_CLIENT_NODE_PORT_UPDATE_INFO, 0, NULL, &p->info); @@ -4605,14 +4660,14 @@ spa_return_val_if_fail(o != NULL, -EINVAL); spa_return_val_if_fail(alias != NULL, -EINVAL); - if (o->type != INTERFACE_Port || o->client == NULL) - return -EINVAL; c = o->client; + if (o->type != INTERFACE_Port || c == NULL) + return -EINVAL; pw_thread_loop_lock(c->context.loop); - p = GET_PORT(c, GET_DIRECTION(o->port.flags), o->port.port_id); + p = o->port.port; if (p == NULL || !p->valid) { res = -EINVAL; goto done; @@ -4638,7 +4693,7 @@ pw_client_node_port_update(c->node, p->direction, - p->id, + p->port_id, PW_CLIENT_NODE_PORT_UPDATE_INFO, 0, NULL, &p->info); @@ -4661,14 +4716,13 @@ spa_return_val_if_fail(o != NULL, -EINVAL); spa_return_val_if_fail(alias != NULL, -EINVAL); - if (o->type != INTERFACE_Port || o->client == NULL) - return -EINVAL; c = o->client; + if (o->type != INTERFACE_Port || c == NULL) + return -EINVAL; pw_thread_loop_lock(c->context.loop); - - p = GET_PORT(c, GET_DIRECTION(o->port.flags), o->port.port_id); + p = o->port.port; if (p == NULL || !p->valid) { res = -EINVAL; goto done; @@ -4690,7 +4744,7 @@ pw_client_node_port_update(c->node, p->direction, - p->id, + p->port_id, PW_CLIENT_NODE_PORT_UPDATE_INFO, 0, NULL, &p->info); @@ -4750,7 +4804,7 @@ spa_return_val_if_fail(port_name != NULL, -EINVAL); pthread_mutex_lock(&c->context.lock); - p = find_port(c, port_name); + p = find_port_by_name(c, port_name); pthread_mutex_unlock(&c->context.lock); if (p == NULL) { @@ -4849,8 +4903,8 @@ pw_thread_loop_lock(c->context.loop); - src = find_port(c, source_port); - dst = find_port(c, destination_port); + src = find_port_by_name(c, source_port); + dst = find_port_by_name(c, destination_port); if (src == NULL || dst == NULL || !(src->port.flags & JackPortIsOutput) || @@ -4923,8 +4977,8 @@ pw_thread_loop_lock(c->context.loop); - src = find_port(c, source_port); - dst = find_port(c, destination_port); + src = find_port_by_name(c, source_port); + dst = find_port_by_name(c, destination_port); pw_log_debug("%p: %d %d", client, src->id, dst->id); @@ -4968,9 +5022,11 @@ pw_thread_loop_lock(c->context.loop); - spa_list_for_each(l, &c->context.links, link) { - if (l->port_link.src == o->id || - l->port_link.dst == o->id) { + spa_list_for_each(l, &c->context.objects, link) { + if (l->type != INTERFACE_Link || l->removed) + continue; + if (l->port_link.src_serial == o->serial || + l->port_link.dst_serial == o->serial) { pw_registry_destroy(c->registry, l->id); } } @@ -5229,7 +5285,7 @@ if (res == 0) res = (*o1)->port.system_id - (*o2)->port.system_id; if (res == 0) - res = (*o1)->id - (*o2)->id; + res = (*o1)->serial - (*o2)->serial; } @@ -5238,7 +5294,7 @@ (*o1)->port.type_id, (*o2)->port.type_id, is_def1, is_def2, (*o1)->port.priority, (*o2)->port.priority, - (*o1)->id, (*o2)->id, res); + (*o1)->serial, (*o2)->serial, res); return res; } @@ -5282,7 +5338,9 @@ pthread_mutex_lock(&c->context.lock); count = 0; - spa_list_for_each(o, &c->context.ports, link) { + spa_list_for_each(o, &c->context.objects, link) { + if (o->type != INTERFACE_Port || o->removed) + continue; pw_log_debug("%p: check port type:%d flags:%08lx name:\"%s\"", c, o->port.type_id, o->port.flags, o->port.name); if (count == JACK_PORT_MAX) @@ -5342,7 +5400,7 @@ spa_return_val_if_fail(c != NULL, NULL); pthread_mutex_lock(&c->context.lock); - res = find_port(c, port_name); + res = find_port_by_name(c, port_name); pthread_mutex_unlock(&c->context.lock); if (res == NULL) @@ -5360,9 +5418,12 @@ spa_return_val_if_fail(c != NULL, NULL); - res = find_cache(INTERFACE_Port, port_id); - + pthread_mutex_lock(&c->context.lock); + res = find_by_serial(c, port_id); + if (res && res->type != INTERFACE_Port) + res = NULL; pw_log_debug("%p: port %d -> %p", c, port_id, res); + pthread_mutex_unlock(&c->context.lock); if (res == NULL) pw_log_info("%p: port %d not found", c, port_id); @@ -5790,7 +5851,7 @@ spa_return_val_if_fail(c != NULL, NULL); - return spa_aprintf("%"PRIu64, client_make_uuid(c->node_id, false)); + return spa_aprintf("%"PRIu64, client_make_uuid(c->serial, false)); } SPA_EXPORT @@ -6167,8 +6228,5 @@ PW_LOG_TOPIC_INIT(jack_log_topic); pthread_mutex_init(&globals.lock, NULL); pw_array_init(&globals.descriptions, 16); - spa_list_init(&globals.free_objects[INTERFACE_Port]); - spa_list_init(&globals.free_objects[INTERFACE_Node]); - spa_list_init(&globals.free_objects[INTERFACE_Link]); - pw_map_init(&globals.cache, 64, 64); + spa_list_init(&globals.free_objects); }
View file
pipewire-0.3.43.tar.gz/pipewire-jack/src/pw-jack.in -> pipewire-0.3.44.tar.gz/pipewire-jack/src/pw-jack.in
Changed
@@ -24,7 +24,7 @@ # DEALINGS IN THE SOFTWARE. # -SAMPLERATE=48000 +DEFAULT_SAMPLERATE=48000 while getopts 'hr:vs:p:' param ; do case $param in @@ -55,7 +55,7 @@ echo " -h show brief help" echo " -r <remote> remote daemon name" echo " -v verbose debug info" - echo " -s samplerate (default \"$SAMPLERATE\")" + echo " -s samplerate (default \"$DEFAULT_SAMPLERATE\")" echo " -p period in samples" exit 0 ;; @@ -65,8 +65,12 @@ shift $(( OPTIND - 1 )) if [ -n "$PERIOD" ]; then - PIPEWIRE_LATENCY="$PERIOD/$SAMPLERATE" - export PIPEWIRE_LATENCY + if [ -n "$SAMPLERATE" ]; then + PIPEWIRE_QUANTUM="$PERIOD/$SAMPLERATE" + else + PIPEWIRE_QUANTUM="$PERIOD/$DEFAULT_SAMPLERATE" + fi + export PIPEWIRE_QUANTUM fi LD_LIBRARY_PATH='@LIBJACK_PATH@'"${LD_LIBRARY_PATH+":$LD_LIBRARY_PATH"}" export LD_LIBRARY_PATH
View file
pipewire-0.3.43.tar.gz/pipewire-v4l2/src/pipewire-v4l2.c -> pipewire-0.3.44.tar.gz/pipewire-v4l2/src/pipewire-v4l2.c
Changed
@@ -1119,12 +1119,13 @@ file->v4l2_format = fmt; - buffers = file->reqbufs; + buffers = SPA_CLAMP(file->reqbufs, 2u, MAX_BUFFERS); size = 0; params[n_params++] = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, - SPA_PARAM_BUFFERS_buffers, SPA_POD_Int(buffers), + SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(buffers, + 2, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int(size, 0, INT_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_CHOICE_RANGE_Int(0, 0, INT_MAX),
View file
pipewire-0.3.43.tar.gz/spa/include/spa/buffer/meta.h -> pipewire-0.3.44.tar.gz/spa/include/spa/buffer/meta.h
Changed
@@ -81,7 +81,7 @@ #define SPA_META_HEADER_FLAG_DELTA_UNIT (1 << 5) /**< cannot be decoded independently */ uint32_t flags; /**< flags */ uint32_t offset; /**< offset in current cycle */ - int64_t pts; /**< presentation timestamp */ + int64_t pts; /**< presentation timestamp in nanoseconds */ int64_t dts_offset; /**< decoding timestamp as a difference with pts */ uint64_t seq; /**< sequence number, increments with a * media specific frequency */
View file
pipewire-0.3.43.tar.gz/spa/include/spa/debug/types.h -> pipewire-0.3.44.tar.gz/spa/include/spa/debug/types.h
Changed
@@ -96,6 +96,26 @@ return SPA_ID_INVALID; } +static inline const struct spa_type_info *spa_debug_type_find_short(const struct spa_type_info *info, const char *name) +{ + while (info && info->name) { + if (strcmp(spa_debug_type_short_name(info->name), name) == 0) + return info; + if (strcmp(info->name, name) == 0) + return info; + if (info->type != 0 && info->type == (uint32_t)atoi(name)) + return info; + info++; + } + return NULL; +} + +static inline uint32_t spa_debug_type_find_type_short(const struct spa_type_info *info, const char *name) +{ + if ((info = spa_debug_type_find_short(info, name)) == NULL) + return SPA_ID_INVALID; + return info->type; +} /** * \} */
View file
pipewire-0.3.43.tar.gz/spa/include/spa/support/thread.h -> pipewire-0.3.44.tar.gz/spa/include/spa/support/thread.h
Changed
@@ -68,7 +68,9 @@ /** get realtime priority range for threads created with \a props */ int (*get_rt_range) (void *data, const struct spa_dict *props, int *min, int *max); - /** acquire realtime priority */ + /** acquire realtime priority, a priority of -1 refers to the priority + * configured in the realtime module + */ int (*acquire_rt) (void *data, struct spa_thread *thread, int priority); /** drop realtime priority */ int (*drop_rt) (void *data, struct spa_thread *thread);
View file
pipewire-0.3.43.tar.gz/spa/include/spa/utils/dict.h -> pipewire-0.3.44.tar.gz/spa/include/spa/utils/dict.h
Changed
@@ -74,8 +74,9 @@ static inline void spa_dict_qsort(struct spa_dict *dict) { - qsort((void*)dict->items, dict->n_items, sizeof(struct spa_dict_item), - spa_dict_item_compare); + if (dict->n_items > 0) + qsort((void*)dict->items, dict->n_items, sizeof(struct spa_dict_item), + spa_dict_item_compare); SPA_FLAG_SET(dict->flags, SPA_DICT_FLAG_SORTED); } @@ -84,7 +85,8 @@ { const struct spa_dict_item *item; - if (SPA_FLAG_IS_SET(dict->flags, SPA_DICT_FLAG_SORTED)) { + if (SPA_FLAG_IS_SET(dict->flags, SPA_DICT_FLAG_SORTED) && + dict->n_items > 0) { struct spa_dict_item k = SPA_DICT_ITEM_INIT(key, NULL); item = (const struct spa_dict_item *)bsearch(&k, (const void *) dict->items, dict->n_items,
View file
pipewire-0.3.44.tar.gz/spa/include/spa/utils/json-pod.h
Added
@@ -0,0 +1,177 @@ +/* Simple Plugin API + * + * Copyright © 2022 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SPA_UTILS_JSON_POD_H +#define SPA_UTILS_JSON_POD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <spa/utils/string.h> +#include <spa/utils/json.h> +#include <spa/pod/pod.h> +#include <spa/pod/builder.h> +#include <spa/debug/types.h> + +/** \defgroup spa_json_pod JSON to POD + * JSON to POD conversion + */ + +/** + * \addtogroup spa_json_pod + * \{ + */ + +static inline int spa_json_to_pod_part(struct spa_pod_builder *b, uint32_t flags, uint32_t id, + const struct spa_type_info *info, struct spa_json *iter, const char *value, int len) +{ + const struct spa_type_info *ti; + char key[256]; + struct spa_pod_frame f[1]; + struct spa_json it[1]; + int l, res; + const char *v; + uint32_t type; + + if (spa_json_is_object(value, len) && info != NULL) { + if ((ti = spa_debug_type_find(NULL, info->parent)) == NULL) + return -EINVAL; + + spa_pod_builder_push_object(b, &f[0], info->parent, id); + + spa_json_enter(iter, &it[0]); + while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { + const struct spa_type_info *pi; + if ((l = spa_json_next(&it[0], &v)) <= 0) + break; + if ((pi = spa_debug_type_find_short(ti->values, key)) != NULL) + type = pi->type; + else if (!spa_atou32(key, &type, 0)) + continue; + spa_pod_builder_prop(b, type, 0); + if ((res = spa_json_to_pod_part(b, flags, id, pi, &it[0], v, l)) < 0) + return res; + } + spa_pod_builder_pop(b, &f[0]); + } + else if (spa_json_is_array(value, len)) { + if (info == NULL || info->parent == SPA_TYPE_Struct) { + spa_pod_builder_push_struct(b, &f[0]); + } else { + spa_pod_builder_push_array(b, &f[0]); + info = info->values; + } + spa_json_enter(iter, &it[0]); + while ((l = spa_json_next(&it[0], &v)) > 0) + if ((res = spa_json_to_pod_part(b, flags, id, info, &it[0], v, l)) < 0) + return res; + spa_pod_builder_pop(b, &f[0]); + } + else if (spa_json_is_float(value, len)) { + float val = 0.0f; + spa_json_parse_float(value, len, &val); + switch (info ? info->parent : (uint32_t)SPA_TYPE_Struct) { + case SPA_TYPE_Bool: + spa_pod_builder_bool(b, val >= 0.5f); + break; + case SPA_TYPE_Id: + spa_pod_builder_id(b, val); + break; + case SPA_TYPE_Int: + spa_pod_builder_int(b, val); + break; + case SPA_TYPE_Long: + spa_pod_builder_long(b, val); + break; + case SPA_TYPE_Struct: + if (spa_json_is_int(value, len)) + spa_pod_builder_int(b, val); + else + spa_pod_builder_float(b, val); + break; + case SPA_TYPE_Float: + spa_pod_builder_float(b, val); + break; + case SPA_TYPE_Double: + spa_pod_builder_double(b, val); + break; + default: + spa_pod_builder_none(b); + break; + } + } + else if (spa_json_is_bool(value, len)) { + bool val = false; + spa_json_parse_bool(value, len, &val); + spa_pod_builder_bool(b, val); + } + else if (spa_json_is_null(value, len)) { + spa_pod_builder_none(b); + } + else { + char *val = (char*)alloca(len+1); + spa_json_parse_stringn(value, len, val, len+1); + switch (info ? info->parent : (uint32_t)SPA_TYPE_Struct) { + case SPA_TYPE_Id: + if ((ti = spa_debug_type_find_short(info->values, val)) != NULL) + type = ti->type; + else if (!spa_atou32(val, &type, 0)) + return -EINVAL; + spa_pod_builder_id(b, type); + break; + case SPA_TYPE_Struct: + case SPA_TYPE_String: + spa_pod_builder_string(b, val); + break; + default: + spa_pod_builder_none(b); + break; + } + } + return 0; +} + +static inline int spa_json_to_pod(struct spa_pod_builder *b, uint32_t flags, + const struct spa_type_info *info, const char *value, int len) +{ + struct spa_json iter; + const char *val; + + spa_json_init(&iter, value, len); + if ((len = spa_json_next(&iter, &val)) <= 0) + return -EINVAL; + + return spa_json_to_pod_part(b, flags, info->type, info, &iter, val, len); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_UTILS_JSON_POD_H */
View file
pipewire-0.3.43.tar.gz/spa/meson.build -> pipewire-0.3.44.tar.gz/spa/meson.build
Changed
@@ -9,6 +9,7 @@ include_directories : [ include_directories('include'), ], + dependencies : [atomic_dep], version : spaversion, variables : { 'plugindir' : meson.current_build_dir() / 'plugins',
View file
pipewire-0.3.43.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules
Changed
@@ -113,8 +113,7 @@ ATTRS{idVendor}=="041e", ATTRS{idProduct}=="322c", ENV{ACP_PROFILE_SET}="sb-omni-surround-5.1.conf" ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="4014", ENV{ACP_PROFILE_SET}="dell-dock-tb16-usb-audio.conf" ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="402e", ENV{ACP_PROFILE_SET}="dell-dock-tb16-usb-audio.conf" -ATTRS{idVendor}=="1397", ATTRS{idProduct}=="0507", ENV{ACP_PROFILE_SET}="behringer-umc22.conf" -ATTRS{idVendor}=="08bb", ATTRS{idProduct}=="2902", ENV{ACP_PROFILE_SET}="texas-instruments-pcm2902.conf" +#ATTRS{idVendor}=="08bb", ATTRS{idProduct}=="2902", ENV{ACP_PROFILE_SET}="texas-instruments-pcm2902.conf" ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0269", ENV{ACP_PROFILE_SET}="hp-tbt-dock-120w-g2.conf" ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0567", ENV{ACP_PROFILE_SET}="hp-tbt-dock-audio-module.conf"
View file
pipewire-0.3.43.tar.gz/spa/plugins/alsa/acp/compat.h -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/acp/compat.h
Changed
@@ -34,6 +34,9 @@ #include <inttypes.h> #include <stdlib.h> #include <unistd.h> +#include <math.h> + +#include <spa/utils/string.h> typedef struct pa_core pa_core; @@ -545,25 +548,35 @@ static inline int pa_atod(const char *s, double *ret_d) { - char *x; - *ret_d = strtod(s, &x); - return 0; + if (spa_atod(s, ret_d) && !isnan(*ret_d)) + return 0; + errno = EINVAL; + return -1; } static inline int pa_atoi(const char *s, int32_t *ret_i) { - *ret_i = (int32_t) atoi(s); - return 0; + if (spa_atoi32(s, ret_i, 0)) + return 0; + errno = EINVAL; + return -1; } static inline int pa_atou(const char *s, uint32_t *ret_u) { - *ret_u = (uint32_t) atoi(s); - return 0; + if (spa_atou32(s, ret_u, 0)) + return 0; + errno = EINVAL; + return -1; } static inline int pa_atol(const char *s, long *ret_l) { - char *x; - *ret_l = strtol(s, &x, 0); - return 0; + int64_t res; + if (spa_atoi64(s, &res, 0)) { + *ret_l = res; + if (*ret_l == res) + return 0; + } + errno = EINVAL; + return -1; } static inline int pa_parse_boolean(const char *v)
View file
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
@@ -42,14 +42,10 @@ #define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) == 0) static const char default_device[] = "hw:0"; -static const uint32_t default_min_latency = MIN_LATENCY; -static const uint32_t default_max_latency = MAX_LATENCY; static void reset_props(struct props *props) { strncpy(props->device, default_device, 64); - props->min_latency = default_min_latency; - props->max_latency = default_max_latency; props->use_chmap = DEFAULT_USE_CHMAP; } @@ -68,7 +64,7 @@ items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Sink"); items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true"); if (this->have_format) { - snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 4, this->rate); + snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 2, this->rate); items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency); } this->info.props = &SPA_DICT_INIT(items, n_items); @@ -162,25 +158,11 @@ case 3: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_minLatency), - SPA_PROP_INFO_description, SPA_POD_String("The minimum latency"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->min_latency, 1, INT32_MAX)); - break; - case 4: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_maxLatency), - SPA_PROP_INFO_description, SPA_POD_String("The maximum latency"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->max_latency, 1, INT32_MAX)); - break; - case 5: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_latencyOffsetNsec), SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"), SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, INT64_MAX)); break; - case 6: + case 4: if (!this->is_iec958 && !this->is_hdmi) goto next; param = spa_pod_builder_add_object(&b, @@ -193,7 +175,7 @@ SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); break; default: - param = spa_alsa_enum_propinfo(this, result.index - 7, &b); + param = spa_alsa_enum_propinfo(this, result.index - 5, &b); if (param == NULL) return 0; } @@ -213,8 +195,6 @@ SPA_PROP_device, SPA_POD_Stringn(p->device, sizeof(p->device)), SPA_PROP_deviceName, SPA_POD_Stringn(p->device_name, sizeof(p->device_name)), SPA_PROP_cardName, SPA_POD_Stringn(p->card_name, sizeof(p->card_name)), - SPA_PROP_minLatency, SPA_POD_Int(p->min_latency), - SPA_PROP_maxLatency, SPA_POD_Int(p->max_latency), SPA_PROP_latencyOffsetNsec, SPA_POD_Long(this->process_latency.ns), 0); @@ -343,8 +323,6 @@ spa_pod_parse_object(param, SPA_TYPE_OBJECT_Props, NULL, SPA_PROP_device, SPA_POD_OPT_Stringn(p->device, sizeof(p->device)), - SPA_PROP_minLatency, SPA_POD_OPT_Int(&p->min_latency), - SPA_PROP_maxLatency, SPA_POD_OPT_Int(&p->max_latency), SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&info.ns), SPA_PROP_iec958Codecs, SPA_POD_OPT_Pod(&iec958_codecs), SPA_PROP_params, SPA_POD_OPT_Pod(¶ms)); @@ -363,8 +341,8 @@ this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; this->port_params[PORT_EnumFormat].user++; } - handle_process_latency(this, &info); spa_alsa_parse_prop_params(this, params); + handle_process_latency(this, &info); emit_node_info(this, false); emit_port_info(this, false); @@ -551,8 +529,8 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(this->blocks), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - this->props.max_latency * this->frame_size, - this->props.min_latency * this->frame_size, + this->quantum_limit * this->frame_size, + 16 * this->frame_size, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->frame_size)); break;
View file
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-pcm-source.c
Changed
@@ -44,14 +44,10 @@ #define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) == 0) static const char default_device[] = "hw:0"; -static const uint32_t default_min_latency = MIN_LATENCY; -static const uint32_t default_max_latency = MAX_LATENCY; static void reset_props(struct props *props) { strncpy(props->device, default_device, 64); - props->min_latency = default_min_latency; - props->max_latency = default_max_latency; props->use_chmap = DEFAULT_USE_CHMAP; } @@ -69,7 +65,7 @@ items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Source"); items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true"); if (this->have_format) { - snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 4, this->rate); + snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 2, this->rate); items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency); } this->info.props = &SPA_DICT_INIT(items, n_items); @@ -162,26 +158,12 @@ case 3: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_minLatency), - SPA_PROP_INFO_description, SPA_POD_String("The minimum latency"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->min_latency, 1, INT32_MAX)); - break; - case 4: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, - SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_maxLatency), - SPA_PROP_INFO_description, SPA_POD_String("The maximum latency"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->max_latency, 1, INT32_MAX)); - break; - case 5: - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_latencyOffsetNsec), SPA_PROP_INFO_description, SPA_POD_String("Latency offset (ns)"), SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0LL, 0LL, INT64_MAX)); break; default: - param = spa_alsa_enum_propinfo(this, result.index - 6, &b); + param = spa_alsa_enum_propinfo(this, result.index - 4, &b); if (param == NULL) return 0; } @@ -199,8 +181,6 @@ SPA_PROP_device, SPA_POD_Stringn(p->device, sizeof(p->device)), SPA_PROP_deviceName, SPA_POD_Stringn(p->device_name, sizeof(p->device_name)), SPA_PROP_cardName, SPA_POD_Stringn(p->card_name, sizeof(p->card_name)), - SPA_PROP_minLatency, SPA_POD_Int(p->min_latency), - SPA_PROP_maxLatency, SPA_POD_Int(p->max_latency), SPA_PROP_latencyOffsetNsec, SPA_POD_Long(this->process_latency.ns), 0); spa_alsa_add_prop_params(this, &b); @@ -323,13 +303,11 @@ spa_pod_parse_object(param, SPA_TYPE_OBJECT_Props, NULL, SPA_PROP_device, SPA_POD_OPT_Stringn(p->device, sizeof(p->device)), - SPA_PROP_minLatency, SPA_POD_OPT_Int(&p->min_latency), - SPA_PROP_maxLatency, SPA_POD_OPT_Int(&p->max_latency), SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&info.ns), SPA_PROP_params, SPA_POD_OPT_Pod(¶ms)); - handle_process_latency(this, &info); spa_alsa_parse_prop_params(this, params); + handle_process_latency(this, &info); emit_node_info(this, false); emit_port_info(this, false); @@ -500,8 +478,8 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(this->blocks), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - this->props.max_latency * this->frame_size, - this->props.min_latency * this->frame_size, + this->quantum_limit * this->frame_size, + 16 * this->frame_size, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->frame_size)); break;
View file
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -125,6 +125,10 @@ state->props.use_chmap = spa_atob(s); } else if (spa_streq(k, "api.alsa.multi-rate")) { state->multi_rate = spa_atob(s); + } else if (spa_streq(k, "latency.internal.rate")) { + state->process_latency.rate = atoi(s); + } else if (spa_streq(k, "latency.internal.ns")) { + state->process_latency.ns = atoi(s); } else if (spa_streq(k, "clock.name")) { spa_scnprintf(state->clock_name, sizeof(state->clock_name), "%s", s); @@ -295,6 +299,22 @@ case 13: param = spa_pod_builder_add_object(b, SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, + SPA_PROP_INFO_name, SPA_POD_String("latency.internal.rate"), + SPA_PROP_INFO_description, SPA_POD_String("Internal latency in samples"), + SPA_PROP_INFO_type, SPA_POD_Int(state->process_latency.rate), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 14: + param = spa_pod_builder_add_object(b, + SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, + SPA_PROP_INFO_name, SPA_POD_String("latency.internal.ns"), + SPA_PROP_INFO_description, SPA_POD_String("Internal latency in nanoseconds"), + SPA_PROP_INFO_type, SPA_POD_Long(state->process_latency.ns), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 15: + param = spa_pod_builder_add_object(b, + SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_PROP_INFO_name, SPA_POD_String("clock.name"), SPA_PROP_INFO_description, SPA_POD_String("The name of the clock"), SPA_PROP_INFO_type, SPA_POD_String(state->clock_name), @@ -358,6 +378,12 @@ spa_pod_builder_string(b, "api.alsa.multi-rate"); spa_pod_builder_bool(b, state->multi_rate); + spa_pod_builder_string(b, "latency.internal.rate"); + spa_pod_builder_int(b, state->process_latency.rate); + + spa_pod_builder_string(b, "latency.internal.ns"); + spa_pod_builder_long(b, state->process_latency.ns); + spa_pod_builder_string(b, "clock.name"); spa_pod_builder_string(b, state->clock_name); @@ -391,8 +417,11 @@ if (spa_pod_is_string(pod)) { spa_pod_copy_string(pod, sizeof(value), value); } else if (spa_pod_is_int(pod)) { - snprintf(value, sizeof(value), "%u", + snprintf(value, sizeof(value), "%d", SPA_POD_VALUE(struct spa_pod_int, pod)); + } else if (spa_pod_is_long(pod)) { + snprintf(value, sizeof(value), "%"PRIi64, + SPA_POD_VALUE(struct spa_pod_long, pod)); } else if (spa_pod_is_bool(pod)) { snprintf(value, sizeof(value), "%s", SPA_POD_VALUE(struct spa_pod_bool, pod) ? @@ -427,10 +456,8 @@ state->card_index = atoi(s); } else if (spa_streq(k, SPA_KEY_API_ALSA_OPEN_UCM)) { state->open_ucm = spa_atob(s); - } else if (spa_streq(k, "latency.internal.rate")) { - state->process_latency.rate = atoi(s); - } else if (spa_streq(k, "latency.internal.ns")) { - state->process_latency.ns = atoi(s); + } else if (spa_streq(k, "clock.quantum-limit")) { + spa_atou32(s, &state->quantum_limit, 0); } else { alsa_set_param(state, k, s); } @@ -732,31 +759,32 @@ CHECK(snd_pcm_hw_params_get_rate_min(params, &min, &dir), "get_rate_min"); CHECK(snd_pcm_hw_params_get_rate_max(params, &max, &dir), "get_rate_max"); - rate = state->default_rate; if (!state->multi_rate && state->card->format_ref > 0) rate = state->card->rate; + else + rate = state->default_rate; - if (rate != 0 && !all) { - if (min < rate) - min = rate; - if (max > rate) - max = rate; - } + if (rate < min || rate > max) + rate = 0; + + if (rate != 0 && !all) + min = max = rate; + + if (rate == 0) + rate = state->position ? state->position->clock.rate.denom : DEFAULT_RATE; + + rate = SPA_CLAMP(rate, min, max); spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0); spa_pod_builder_push_choice(b, &f[0], SPA_CHOICE_None, 0); choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[0]); - if (rate == 0) - rate = state->position ? state->position->clock.rate.denom : DEFAULT_RATE; - if (state->n_allowed_rates > 0) { uint32_t i, v, last = 0, count = 0; - v = SPA_CLAMP(rate, min, max); - if (uint32_array_contains(state->allowed_rates, state->n_allowed_rates, v)) { - spa_pod_builder_int(b, v * scale); + if (uint32_array_contains(state->allowed_rates, state->n_allowed_rates, rate)) { + spa_pod_builder_int(b, rate * scale); count++; } for (i = 0; i < state->n_allowed_rates; i++) { @@ -773,7 +801,7 @@ if (count > 1) choice->body.type = SPA_CHOICE_Enum; } else { - spa_pod_builder_int(b, SPA_CLAMP(rate, min, max) * scale); + spa_pod_builder_int(b, rate * scale); if (min != max) { spa_pod_builder_int(b, min * scale); @@ -1419,9 +1447,13 @@ if (is_batch) { if (period_size == 0) period_size = state->position ? state->position->clock.duration : DEFAULT_PERIOD; + if (period_size == 0) + period_size = DEFAULT_PERIOD; /* batch devices get their hw pointers updated every period. Make - * the period smaller and add one period of headroom */ - period_size /= 2; + * the period smaller and add one period of headroom. Limit the + * period size to our default so that we don't create too much + * headroom. */ + period_size = SPA_MIN(period_size, DEFAULT_PERIOD) / 2; spa_log_info(state->log, "%s: batch mode, period_size:%ld", state->props.device, period_size); } else { @@ -2306,7 +2338,7 @@ else { spa_log_warn(state->log, "%s: no position set, using defaults", state->props.device); - state->duration = state->props.min_latency; + state->duration = 1024; state->rate_denom = state->rate; }
View file
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-pcm.h
Changed
@@ -52,9 +52,6 @@ #include "dll.h" -#define MIN_LATENCY 16 -#define MAX_LATENCY 8192 - #define MAX_RATES 16 #define DEFAULT_PERIOD 1024u @@ -66,8 +63,6 @@ char device[64]; char device_name[128]; char card_name[128]; - uint32_t min_latency; - uint32_t max_latency; bool use_chmap; }; @@ -148,6 +143,7 @@ unsigned int disable_mmap; unsigned int disable_batch; char clock_name[64]; + uint32_t quantum_limit; snd_pcm_uframes_t buffer_frames; snd_pcm_uframes_t period_frames;
View file
pipewire-0.3.43.tar.gz/spa/plugins/alsa/alsa-udev.c -> pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-udev.c
Changed
@@ -47,6 +47,9 @@ #define MAX_DEVICES 64 +#define RETRY_COUNT 1 +#define RETRY_MSEC 2000 + #define ACTION_ADD 0 #define ACTION_REMOVE 1 #define ACTION_DISABLE 2 @@ -54,6 +57,7 @@ struct device { uint32_t id; struct udev_device *dev; + uint8_t retry; unsigned int accessible:1; unsigned int ignored:1; unsigned int emitted:1; @@ -65,6 +69,7 @@ struct spa_log *log; struct spa_loop *main_loop; + struct spa_system *main_system; struct spa_hook_list hooks; @@ -79,6 +84,7 @@ struct spa_source source; struct spa_source notify; + struct spa_source retry_timer; unsigned int use_acp:1; }; @@ -243,6 +249,39 @@ *d = 0; } +static int check_device_busy(struct impl *this, struct device *device, snd_ctl_t *ctl_hndl) +{ + int dev; + + /* Check if some pcm devices of the card cannot be opened because they are busy */ + + for (dev = -1; snd_ctl_pcm_next_device(ctl_hndl, &dev) >= 0 && dev >= 0;) { + char devpath[64]; + int i; + + snprintf(devpath, sizeof(devpath), "hw:%u,%u", device->id, dev); + + for (i = 0; i < 2; ++i) { + snd_pcm_t *handle; + int res; + + res = snd_pcm_open(&handle, devpath, + (i == 0) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, + SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_RESAMPLE | + SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT); + if (res == -EBUSY) { + spa_log_debug(this->log, "pcm device %s busy", devpath); + return -EBUSY; + } else if (res >= 0) { + snd_pcm_close(handle); + } + } + spa_log_debug(this->log, "pcm device %s free", devpath); + } + + return 0; +} + static int emit_object_info(struct impl *this, struct device *device) { struct spa_device_object_info info; @@ -267,20 +306,24 @@ pcm = -1; res = snd_ctl_pcm_next_device(ctl_hndl, &pcm); - spa_log_debug(this->log, "close card %s", path); - snd_ctl_close(ctl_hndl); - if (res < 0) { spa_log_error(this->log, "error iterating devices: %s", snd_strerror(res)); device->ignored = true; - return res; - } - if (pcm < 0) { + } else if (pcm < 0) { spa_log_debug(this->log, "no pcm devices for %s", path); device->ignored = true; - return 0; + res = 0; + } else if (device->retry > 0) { + /* Check if we can open all PCM devices (retry later if not) */ + res = check_device_busy(this, device, ctl_hndl); } + spa_log_debug(this->log, "close card %s", path); + snd_ctl_close(ctl_hndl); + + if (res < 0 || device->ignored) + return res; + info = SPA_DEVICE_OBJECT_INFO_INIT(); info.type = SPA_TYPE_INTERFACE_Device; @@ -393,6 +436,82 @@ return 1; } +static void start_retry(struct impl *this); + +static void stop_retry(struct impl *this); + +static void retry_timer_event(struct spa_source *source) +{ + struct impl *this = source->data; + bool have_retry = false; + size_t i; + + stop_retry(this); + + for (i = 0; i < this->n_devices; ++i) { + struct device *device = &this->devices[i]; + if (device->ignored) + device->retry = 0; + if (device->retry > 0) { + --device->retry; + + spa_log_debug(this->log, "retrying device %u", device->id); + + if (emit_object_info(this, device) == -EBUSY) { + spa_log_debug(this->log, "device %u busy (remaining retries %u)", + device->id, device->retry); + } else { + device->retry = 0; + } + } + if (device->retry > 0) + have_retry = true; + } + + if (have_retry) + start_retry(this); +} + +static void start_retry(struct impl *this) +{ + struct itimerspec ts; + + spa_log_debug(this->log, "start retry"); + + if (this->retry_timer.data == NULL) { + this->retry_timer.data = this; + this->retry_timer.func = retry_timer_event; + this->retry_timer.mask = SPA_IO_IN; + this->retry_timer.rmask = 0; + spa_loop_add_source(this->main_loop, &this->retry_timer); + } + + ts.it_value.tv_sec = ((uint64_t)RETRY_MSEC * SPA_NSEC_PER_MSEC) / SPA_NSEC_PER_SEC; + ts.it_value.tv_nsec = ((uint64_t)RETRY_MSEC * SPA_NSEC_PER_MSEC) % SPA_NSEC_PER_SEC; + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + spa_system_timerfd_settime(this->main_system, this->retry_timer.fd, 0, &ts, NULL); +} + +static void stop_retry(struct impl *this) +{ + struct itimerspec ts; + + if (this->retry_timer.data == NULL) + return; + + spa_log_debug(this->log, "stop retry"); + + spa_loop_remove_source(this->main_loop, &this->retry_timer); + this->retry_timer.data = NULL; + + ts.it_value.tv_sec = 0; + ts.it_value.tv_nsec = 0; + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + spa_system_timerfd_settime(this->main_system, this->retry_timer.fd, 0, &ts, NULL); +} + static bool check_access(struct impl *this, struct device *device) { char path[128]; @@ -425,7 +544,14 @@ return; if (!check_access(this, device)) return; - emit_object_info(this, device); + device->retry = RETRY_COUNT; + if (emit_object_info(this, device) == -EBUSY) { + spa_log_debug(this->log, "device %u busy (remaining retries %u)", + device->id, device->retry); + start_retry(this); + } else { + device->retry = 0; + } break; case ACTION_REMOVE: @@ -440,6 +566,7 @@ case ACTION_DISABLE: if (device == NULL) return; + device->retry = 0; if (device->emitted) { device->emitted = false; spa_device_emit_object_info(&this->hooks, id, NULL); @@ -687,10 +814,10 @@ emit_device_info(this, true); - if ((res = enum_devices(this)) < 0) + if ((res = start_monitor(this)) < 0) return res; - if ((res = start_monitor(this)) < 0) + if ((res = enum_devices(this)) < 0) return res; spa_hook_list_join(&this->hooks, &save); @@ -728,6 +855,10 @@ struct impl *this = (struct impl *) handle; stop_monitor(this); impl_udev_close(this); + stop_retry(this); + if (this->retry_timer.fd >= 0) + spa_system_close(this->main_system, this->retry_timer.fd); + this->retry_timer.fd = -1; return 0; } @@ -756,15 +887,21 @@ this = (struct impl *) handle; this->notify.fd = -1; + this->retry_timer.fd = -1; this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); alsa_log_topic_init(this->log); this->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop); + this->main_system = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_System); if (this->main_loop == NULL) { spa_log_error(this->log, "a main-loop is needed"); return -EINVAL; } + if (this->main_system == NULL) { + spa_log_error(this->log, "a main-system is needed"); + return -EINVAL; + } spa_hook_list_init(&this->hooks); this->device.iface = SPA_INTERFACE_INIT( @@ -782,6 +919,9 @@ this->use_acp = spa_atob(str); } + this->retry_timer.fd = spa_system_timerfd_create(this->main_system, + CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK); + return 0; }
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
@@ -118,19 +118,20 @@ struct spa_pod_builder *builder) { int res; - if (result->next < 0x10000) { + if (result->next < 0x100000) { if ((res = spa_node_enum_params_sync(this->convert, id, &result->next, filter, &result->param, builder)) == 1) return res; - result->next = 0x10000; + result->next = 0x100000; } - if (result->next >= 0x10000 && this->follower_params_flags[idx] & SPA_PARAM_INFO_READ) { - result->next &= 0xffff; + if (result->next < 0x200000 && this->follower_params_flags[idx] & SPA_PARAM_INFO_READ) { + result->next &= 0xfffff; if ((res = spa_node_enum_params_sync(this->follower, id, &result->next, filter, &result->param, builder)) == 1) { - result->next |= 0x10000; + result->next |= 0x100000; return res; } + result->next = 0x200000; } return 0; }
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -472,13 +472,22 @@ } result->next = 0x1000; } - if (result->next >= 0x1000) { + if (result->next < 0x2000) { result->next &= 0xfff; if ((res = spa_node_enum_params_sync(this->channelmix, id, &result->next, filter, &result->param, builder)) == 1) { result->next |= 0x1000; return res; } + result->next = 0x2000; + } + if (result->next >= 0x2000) { + result->next &= 0xfff; + if ((res = spa_node_enum_params_sync(this->resample, + id, &result->next, filter, &result->param, builder)) == 1) { + result->next |= 0x2000; + return res; + } } return 0; } @@ -881,6 +890,7 @@ if (this->fmt[SPA_DIRECTION_INPUT] == this->merger) res = spa_node_set_param(this->merger, id, flags, param); res = spa_node_set_param(this->channelmix, id, flags, param); + res = spa_node_set_param(this->resample, id, flags, param); break; } default: @@ -1112,11 +1122,12 @@ switch (id) { case SPA_PARAM_Latency: - target = this->fmt[SPA_DIRECTION_REVERSE(direction)]; - port_id = 0; - if ((res = spa_node_port_set_param(target, - direction, port_id, id, flags, param)) < 0) - return res; + if (port_id == 0) { + target = this->fmt[SPA_DIRECTION_REVERSE(direction)]; + if ((res = spa_node_port_set_param(target, + direction, port_id, id, flags, param)) < 0) + return res; + } break; }
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/channelmix-ops.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/channelmix-ops.c
Changed
@@ -149,17 +149,16 @@ float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS] = {{ 0.0f }}; uint64_t src_mask = mix->src_mask; uint64_t dst_mask = mix->dst_mask; - uint64_t unassigned; + uint64_t unassigned, keep; uint32_t i, j, ic, jc, matrix_encoding = MATRIX_NORMAL; float clev = SQRT1_2; float slev = SQRT1_2; float llev = 0.5f; float maxsum = 0.0f; - bool do_upmix = SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX); #define _MATRIX(s,d) matrix[_CH(s)][_CH(d)] - spa_log_debug(mix->log, "src-mask:%08"PRIx64" dst-mask:%08"PRIx64, - src_mask, dst_mask); + 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. */ @@ -207,6 +206,14 @@ } unassigned = src_mask & ~dst_mask; + keep = dst_mask & ~src_mask; + + if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX)) + keep = 0; + + keep |= FRONT; + if (mix->lfe_cutoff > 0.0f) + keep |= _MASK(LFE); spa_log_debug(mix->log, "unassigned downmix %08" PRIx64, unassigned); @@ -232,6 +239,7 @@ _MATRIX(FC,FR) += SQRT1_2; if (src_mask & FRONT) _MATRIX(FC,FC) = clev * SQRT2; + keep &= ~FRONT; } else { spa_log_warn(mix->log, "can't assign STEREO"); } @@ -374,12 +382,10 @@ } } - if (!do_upmix) - goto done; - - unassigned = dst_mask & ~src_mask; + unassigned = dst_mask & ~src_mask & keep; - spa_log_debug(mix->log, "unassigned upmix %08" PRIx64, unassigned); + spa_log_debug(mix->log, "unassigned upmix %08"PRIx64" lfe:%f", + unassigned, mix->lfe_cutoff); if (unassigned & FRONT) { if ((src_mask & STEREO) == STEREO) { @@ -390,7 +396,7 @@ spa_log_warn(mix->log, "can't produce FC"); } } - if (unassigned & _MASK(LFE) && mix->lfe_cutoff > 0.0f) { + if (unassigned & _MASK(LFE)) { if ((src_mask & STEREO) == STEREO) { spa_log_debug(mix->log, "produce LFE from STEREO"); _MATRIX(LFE,FL) += llev; @@ -445,7 +451,7 @@ sum += fabs(matrix[i][j]); } maxsum = SPA_MAX(maxsum, sum); - if (i == _CH(LFE) && do_upmix && mix->lfe_cutoff > 0.0f) { + if (i == _CH(LFE) && mix->lfe_cutoff > 0.0f) { spa_log_debug(mix->log, "channel %d is LFE", ic); lr4_set(&mix->lr4[ic], BQ_LOWPASS, mix->lfe_cutoff / mix->freq); mix->lr4_info[ic] = 1; @@ -456,6 +462,7 @@ } if (SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_NORMALIZE) && maxsum > 1.0f) { + spa_log_debug(mix->log, "normalize %f", maxsum); for (i = 0; i < ic; i++) for (j = 0; j < jc; j++) mix->matrix_orig[i][j] /= maxsum;
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/channelmix.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/channelmix.c
Changed
@@ -48,7 +48,6 @@ #define DEFAULT_RATE 48000 #define DEFAULT_CHANNELS 2 -#define DEFAULT_SAMPLES 8192 #define MAX_BUFFERS 32 #define MAX_DATAS SPA_AUDIO_MAX_CHANNELS @@ -82,6 +81,7 @@ struct volumes soft; struct volumes monitor; unsigned int have_soft_volume:1; + unsigned int disabled:1; }; static void props_reset(struct props *props) @@ -142,6 +142,7 @@ struct spa_log *log; struct spa_cpu *cpu; + uint32_t quantum_limit; struct spa_io_position *io_position; @@ -363,6 +364,8 @@ emit_props_changed(this); this->is_passthrough = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY); + if (!this->is_passthrough && this->props.disabled) + return -EINVAL; spa_log_debug(this->log, "%p: got channelmix features %08x:%08x flags:%08x passthrough:%d", this, this->cpu_flags, this->mix.cpu_flags, @@ -495,6 +498,14 @@ this->mix.lfe_cutoff, 0.0, 1000.0), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; + case 12: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.disable"), + SPA_PROP_INFO_description, SPA_POD_String("Disable Channel mixing"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->disabled), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; default: return 0; } @@ -544,6 +555,8 @@ CHANNELMIX_OPTION_UPMIX)); spa_pod_builder_string(&b, "channelmix.lfe-cutoff"); spa_pod_builder_float(&b, this->mix.lfe_cutoff); + spa_pod_builder_string(&b, "channelmix.disable"); + spa_pod_builder_bool(&b, this->props.disabled); spa_pod_builder_pop(&b, &f[1]); param = spa_pod_builder_pop(&b, &f[0]); break; @@ -577,6 +590,8 @@ SPA_FLAG_UPDATE(this->mix.options, CHANNELMIX_OPTION_UPMIX, spa_atob(s)); else if (spa_streq(k, "channelmix.lfe-cutoff")) this->mix.lfe_cutoff = atoi(s); + else if (spa_streq(k, "channelmix.disable")) + this->props.disabled = spa_atob(s); return 0; } @@ -634,6 +649,9 @@ if (param == NULL) return 0; + if (this->props.disabled) + return 0; + SPA_POD_OBJECT_FOREACH(obj, prop) { switch (prop->key) { case SPA_PROP_volume: @@ -716,6 +734,9 @@ if (size < 3) return -EINVAL; + if (this->props.disabled) + return 0; + if ((val[0] & 0xf0) != 0xb0 || val[1] != 7) return 0; @@ -863,6 +884,7 @@ } else { struct spa_pod_frame f; struct port *other; + int32_t channels, min = 1, max = INT32_MAX; other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), 0); @@ -875,19 +897,24 @@ 0); if (other->have_format) { + channels = other->format.info.raw.channels; + if (this->props.disabled) + min = max = channels; + spa_pod_builder_add(builder, SPA_FORMAT_AUDIO_rate, SPA_POD_Int(other->format.info.raw.rate), SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int( - other->format.info.raw.channels, 1, INT32_MAX), + channels, min, max), 0); } else { uint32_t rate = this->io_position ? this->io_position->clock.rate.denom : DEFAULT_RATE; + channels = DEFAULT_CHANNELS; spa_pod_builder_add(builder, SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(rate, 0, INT32_MAX), SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int( - DEFAULT_CHANNELS, 1, INT32_MAX), + channels, min, max), 0); } *param = spa_pod_builder_pop(builder, &f); @@ -978,7 +1005,7 @@ size = other->size / other->stride; } else { buffers = 1; - size = DEFAULT_SAMPLES; + size = this->quantum_limit; } param = spa_pod_builder_add_object(&b, @@ -1539,11 +1566,15 @@ props_reset(&this->props); + this->mix.options = CHANNELMIX_OPTION_NORMALIZE; + for (i = 0; info && i < info->n_items; i++) { const char *k = info->items[i].key; const char *s = info->items[i].value; if (spa_streq(k, SPA_KEY_AUDIO_POSITION)) this->props.n_channels = parse_position(this->props.channel_map, s, strlen(s)); + else if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); else channelmix_set_param(this, k, s);
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/fmt-ops-c.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmt-ops-c.c
Changed
@@ -99,6 +99,22 @@ } void +conv_copy64d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + uint32_t i, n_channels = conv->n_channels; + for (i = 0; i < n_channels; i++) + spa_memcpy(dst[i], src[i], n_samples * sizeof(int64_t)); +} + +void +conv_copy64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + spa_memcpy(dst[0], src[0], n_samples * sizeof(int64_t) * conv->n_channels); +} + +void conv_u8d_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_samples) { @@ -650,6 +666,77 @@ } void +conv_f64d_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + uint32_t i, j, n_channels = conv->n_channels; + + for (i = 0; i < n_channels; i++) { + const double *s = src[i]; + float *d = dst[i]; + + for (j = 0; j < n_samples; j++) + d[j] = s[j]; + } +} + +void +conv_f64_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + uint32_t i, n_channels = conv->n_channels; + const double *s = src[0]; + float *d = dst[0]; + + n_samples *= n_channels; + + for (i = 0; i < n_samples; i++) + d[i] = s[i]; +} + +void +conv_f64_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + const double *s = src[0]; + float **d = (float **) dst; + uint32_t i, j, n_channels = conv->n_channels; + + for (j = 0; j < n_samples; j++) { + for (i = 0; i < n_channels; i++) + d[i][j] = *s++; + } +} + +void +conv_f64s_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + const double *s = src[0]; + float **d = (float **) dst; + uint32_t i, j, n_channels = conv->n_channels; + + for (j = 0; j < n_samples; j++) { + for (i = 0; i < n_channels; i++) + d[i][j] = bswap_64(*s++); + } +} + +void +conv_f64d_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + const double **s = (const double **) src; + float *d = dst[0]; + uint32_t i, j, n_channels = conv->n_channels; + + for (j = 0; j < n_samples; j++) { + for (i = 0; i < n_channels; i++) + *d++ = s[i][j]; + } +} + +void conv_f32d_to_u8d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_samples) { @@ -989,6 +1076,77 @@ } void +conv_f32d_to_f64d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + uint32_t i, j, n_channels = conv->n_channels; + + for (i = 0; i < n_channels; i++) { + const float *s = src[i]; + double *d = dst[i]; + + for (j = 0; j < n_samples; j++) + d[j] = s[j]; + } +} + +void +conv_f32_to_f64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + uint32_t i, n_channels = conv->n_channels; + const float *s = src[0]; + double *d = dst[0]; + + n_samples *= n_channels; + + for (i = 0; i < n_samples; i++) + d[i] = s[i]; +} + +void +conv_f32_to_f64d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + const float *s = src[0]; + double **d = (double **) dst; + uint32_t i, j, n_channels = conv->n_channels; + + for (j = 0; j < n_samples; j++) { + for (i = 0; i < n_channels; i++) + d[i][j] = *s++; + } +} + +void +conv_f32d_to_f64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + const float **s = (const float **) src; + double *d = dst[0]; + uint32_t i, j, n_channels = conv->n_channels; + + for (j = 0; j < n_samples; j++) { + for (i = 0; i < n_channels; i++) + *d++ = s[i][j]; + } +} + +void +conv_f32d_to_f64s_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + const float **s = (const float **) src; + double *d = dst[0]; + uint32_t i, j, n_channels = conv->n_channels; + + for (j = 0; j < n_samples; j++) { + for (i = 0; i < n_channels; i++) + *d++ = bswap_32(s[i][j]); + } +} + +void conv_f32_to_u24_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_samples) { @@ -1273,6 +1431,20 @@ } void +conv_deinterleave_64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + const uint64_t *s = src[0]; + uint64_t **d = (uint64_t **) dst; + uint32_t i, j, n_channels = conv->n_channels; + + for (j = 0; j < n_samples; j++) { + for (i = 0; i < n_channels; i++) + d[i][j] = *s++; + } +} + +void conv_interleave_8_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_samples) { @@ -1343,3 +1515,17 @@ *d++ = bswap_32(s[i][j]); } } + +void +conv_interleave_64_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], + uint32_t n_samples) +{ + const int64_t **s = (const int64_t **) src; + uint64_t *d = dst[0]; + uint32_t i, j, n_channels = conv->n_channels; + + for (j = 0; j < n_samples; j++) { + for (i = 0; i < n_channels; i++) + *d++ = s[i][j]; + } +}
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/fmt-ops.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmt-ops.c
Changed
@@ -138,6 +138,13 @@ { SPA_AUDIO_FORMAT_S24_32_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24_32s_to_f32d_c }, + { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F32, 0, 0, conv_f64_to_f32_c }, + { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_f64d_to_f32d_c }, + { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_f64_to_f32d_c }, + { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_f64d_to_f32_c }, + + { SPA_AUDIO_FORMAT_F64_OE, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_f64s_to_f32d_c }, + /* from f32 */ { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U8, 0, 0, conv_f32_to_u8_c }, { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_f32d_to_u8d_c }, @@ -219,6 +226,13 @@ { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_32_OE, 0, 0, conv_f32d_to_s24_32s_c }, + { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F64, 0, 0, conv_f32_to_f64_c }, + { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_f32d_to_f64d_c }, + { SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_f32_to_f64d_c }, + { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F64, 0, 0, conv_f32d_to_f64_c }, + + { SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F64_OE, 0, 0, conv_f32d_to_f64s_c }, + /* u8 */ { SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_U8, 0, 0, conv_copy8_c }, { SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_copy8d_c }, @@ -259,6 +273,12 @@ { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_copy32d_c }, { SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_deinterleave_32_c }, { SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_interleave_32_c }, + + /* F64 */ + { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F64, 0, 0, conv_copy64_c }, + { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_copy64d_c }, + { SPA_AUDIO_FORMAT_F64, SPA_AUDIO_FORMAT_F64P, 0, 0, conv_deinterleave_64_c }, + { SPA_AUDIO_FORMAT_F64P, SPA_AUDIO_FORMAT_F64, 0, 0, conv_interleave_64_c }, }; #define MATCH_CHAN(a,b) ((a) == 0 || (a) == (b))
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/fmt-ops.h -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmt-ops.h
Changed
@@ -27,6 +27,7 @@ #include <sys/endian.h> #define bswap_16 bswap16 #define bswap_32 bswap32 +#define bswap_64 bswap64 #else #include <byteswap.h> #endif @@ -207,6 +208,8 @@ DEFINE_FUNCTION(copy24, c); DEFINE_FUNCTION(copy32d, c); DEFINE_FUNCTION(copy32, c); +DEFINE_FUNCTION(copy64d, c); +DEFINE_FUNCTION(copy64, c); DEFINE_FUNCTION(u8d_to_f32d, c); DEFINE_FUNCTION(u8_to_f32, c); DEFINE_FUNCTION(u8_to_f32d, c); @@ -245,6 +248,11 @@ DEFINE_FUNCTION(s24_32_to_f32d, c); DEFINE_FUNCTION(s24_32s_to_f32d, c); DEFINE_FUNCTION(s24_32d_to_f32, c); +DEFINE_FUNCTION(f64d_to_f32d, c); +DEFINE_FUNCTION(f64_to_f32, c); +DEFINE_FUNCTION(f64_to_f32d, c); +DEFINE_FUNCTION(f64s_to_f32d, c); +DEFINE_FUNCTION(f64d_to_f32, c); DEFINE_FUNCTION(f32d_to_u8d, c); DEFINE_FUNCTION(f32_to_u8, c); DEFINE_FUNCTION(f32_to_u8d, c); @@ -283,16 +291,25 @@ DEFINE_FUNCTION(f32_to_s24_32d, c); DEFINE_FUNCTION(f32d_to_s24_32, c); DEFINE_FUNCTION(f32d_to_s24_32s, c); +DEFINE_FUNCTION(f32d_to_f64d, c); +DEFINE_FUNCTION(f32_to_f64, c); +DEFINE_FUNCTION(f32_to_f64d, c); +DEFINE_FUNCTION(f32d_to_f64, c); +DEFINE_FUNCTION(f32d_to_f64s, c); DEFINE_FUNCTION(deinterleave_8, c); DEFINE_FUNCTION(deinterleave_16, c); DEFINE_FUNCTION(deinterleave_24, c); DEFINE_FUNCTION(deinterleave_32, c); DEFINE_FUNCTION(deinterleave_32s, c); +DEFINE_FUNCTION(deinterleave_64, c); +DEFINE_FUNCTION(deinterleave_64s, c); DEFINE_FUNCTION(interleave_8, c); DEFINE_FUNCTION(interleave_16, c); DEFINE_FUNCTION(interleave_24, c); DEFINE_FUNCTION(interleave_32, c); DEFINE_FUNCTION(interleave_32s, c); +DEFINE_FUNCTION(interleave_64, c); +DEFINE_FUNCTION(interleave_64s, c); #if defined(HAVE_NEON) DEFINE_FUNCTION(s16_to_f32d_2, neon);
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/fmtconvert.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmtconvert.c
Changed
@@ -52,7 +52,6 @@ #define DEFAULT_RATE 48000 #define DEFAULT_CHANNELS 2 -#define MAX_SAMPLES 8192 #define MAX_BUFFERS 32 #define MAX_ALIGN 16 #define MAX_DATAS SPA_AUDIO_MAX_CHANNELS @@ -118,6 +117,8 @@ struct spa_log *log; struct spa_cpu *cpu; + uint32_t cpu_flags; + uint32_t quantum_limit; struct spa_io_position *io_position; @@ -136,7 +137,6 @@ struct spa_latency_info latency[2]; - uint32_t cpu_flags; struct convert conv; unsigned int started:1; unsigned int is_passthrough:1; @@ -400,11 +400,14 @@ info.info.raw.format == SPA_AUDIO_FORMAT_F32P || info.info.raw.format == SPA_AUDIO_FORMAT_F32) { spa_pod_builder_add(builder, - SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(26, + SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(29, info.info.raw.format, SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32_OE, + SPA_AUDIO_FORMAT_F64P, + SPA_AUDIO_FORMAT_F64, + SPA_AUDIO_FORMAT_F64_OE, SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32_OE, @@ -542,7 +545,7 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - MAX_SAMPLES * 2 * port->stride, + this->quantum_limit * 2 * port->stride, 16 * port->stride, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); @@ -619,6 +622,10 @@ case SPA_AUDIO_FORMAT_S24_OE: case SPA_AUDIO_FORMAT_U24: return 3; + case SPA_AUDIO_FORMAT_F64P: + case SPA_AUDIO_FORMAT_F64: + case SPA_AUDIO_FORMAT_F64_OE: + return 8; default: return 4; } @@ -1070,6 +1077,7 @@ uint32_t n_support) { struct impl *this; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -1086,6 +1094,13 @@ if (this->cpu) this->cpu_flags = spa_cpu_get_flags(this->cpu); + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); + } + this->node.iface = SPA_INTERFACE_INIT( SPA_TYPE_INTERFACE_Node, SPA_VERSION_NODE,
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/merger.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/merger.c
Changed
@@ -55,7 +55,6 @@ #define DEFAULT_RATE 48000 #define DEFAULT_CHANNELS 2 -#define MAX_SAMPLES 8192 #define MAX_ALIGN 16 #define MAX_BUFFERS 32 #define MAX_DATAS SPA_AUDIO_MAX_CHANNELS @@ -146,6 +145,9 @@ struct spa_log *log; struct spa_cpu *cpu; + uint32_t cpu_flags; + uint32_t quantum_limit; + struct spa_io_position *io_position; uint64_t info_all; @@ -167,7 +169,6 @@ unsigned int have_profile:1; struct convert conv; - uint32_t cpu_flags; unsigned int is_passthrough:1; unsigned int started:1; unsigned int monitor:1; @@ -181,7 +182,8 @@ struct spa_latency_info latency[2]; - float empty[MAX_SAMPLES + MAX_ALIGN]; + uint32_t empty_size; + float *empty; }; #define CHECK_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < this->port_count) @@ -622,7 +624,9 @@ info.info.raw.rate = 0; - if (this->have_profile && memcmp(&this->format, &info, sizeof(info)) == 0) + if (this->have_profile && + memcmp(&this->format, &info, sizeof(info)) == 0 && + this->monitor == monitor) return 0; spa_log_debug(this->log, "%p: port config %d/%d %d", this, @@ -775,11 +779,14 @@ SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(22, + SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(25, SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32_OE, + SPA_AUDIO_FORMAT_F64P, + SPA_AUDIO_FORMAT_F64, + SPA_AUDIO_FORMAT_F64_OE, SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32_OE, @@ -869,7 +876,7 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - MAX_SAMPLES * port->stride, + this->quantum_limit * port->stride, 16 * port->stride, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); @@ -1008,6 +1015,10 @@ case SPA_AUDIO_FORMAT_S24: case SPA_AUDIO_FORMAT_S24_OE: return 3; + case SPA_AUDIO_FORMAT_F64P: + case SPA_AUDIO_FORMAT_F64: + case SPA_AUDIO_FORMAT_F64_OE: + return 8; default: return 4; } @@ -1024,7 +1035,11 @@ enum spa_direction other = SPA_DIRECTION_REVERSE(direction); uint32_t i; - spa_log_debug(this->log, "%p: set latency direction:%d", this, direction); + spa_log_debug(this->log, "%p: set latency direction:%d id:%d", + this, direction, port_id); + + if (direction == SPA_DIRECTION_OUTPUT && port_id != 0) + return 0; if (latency == NULL) { this->latency[other] = SPA_LATENCY_INFO(other); @@ -1212,7 +1227,7 @@ { struct impl *this = object; struct port *port; - uint32_t i, j; + uint32_t i, j, maxsize; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -1227,6 +1242,7 @@ clear_buffers(this, port); + maxsize = 0; for (i = 0; i < n_buffers; i++) { struct buffer *b; uint32_t n_datas = buffers[i]->n_datas; @@ -1257,11 +1273,19 @@ if (direction == SPA_DIRECTION_OUTPUT && !SPA_FLAG_IS_SET(d[j].flags, SPA_DATA_FLAG_DYNAMIC)) this->is_passthrough = false; - } + maxsize = SPA_MAX(maxsize, d[j].maxsize); + } if (direction == SPA_DIRECTION_OUTPUT) queue_buffer(this, port, i); } + if (maxsize > this->empty_size) { + this->empty = realloc(this->empty, maxsize + MAX_ALIGN); + if (this->empty == NULL) + return -errno; + memset(this->empty, 0, maxsize + MAX_ALIGN); + this->empty_size = maxsize; + } port->n_buffers = n_buffers; return 0; @@ -1519,6 +1543,7 @@ free(this->in_ports[i]); for (i = 0; i < MAX_PORTS+1; i++) free(this->out_ports[i]); + free(this->empty); return 0; } @@ -1557,7 +1582,10 @@ for (i = 0; info && i < info->n_items; i++) { const char *k = info->items[i].key; const char *s = info->items[i].value; - merger_set_param(this, k, s); + if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); + else + merger_set_param(this, k, s); } this->latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/meson.build -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/meson.build
Changed
@@ -140,7 +140,7 @@ install : installed_tests_enabled, install_dir : installed_tests_execdir / 'audioconvert'), env : [ - 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')), + 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')), ]) if installed_tests_enabled @@ -170,7 +170,7 @@ install : installed_tests_enabled, install_dir : installed_tests_execdir / 'audioconvert'), env : [ - 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')), + 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')), ]) if installed_tests_enabled @@ -191,7 +191,6 @@ ] executable('spa-resample', sparesample_sources, - c_args : [ simd_cargs ], link_with : [ test_lib ], dependencies : [ spa_dep, sndfile_dep, mathlib, audioconvert_dep ], install : true,
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/resample-peaks-impl.h -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/resample-peaks-impl.h
Changed
@@ -31,7 +31,7 @@ struct peaks_data { uint32_t o_count; uint32_t i_count; - float max_f[0]; + float max_f[]; }; #if defined (HAVE_SSE)
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/resample-peaks.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/resample-peaks.c
Changed
@@ -146,7 +146,7 @@ r->delay = impl_peaks_delay; r->in_len = impl_peaks_in_len; - d = r->data = calloc(1, sizeof(struct peaks_data) * sizeof(float) * r->channels); + d = r->data = calloc(1, sizeof(struct peaks_data) + sizeof(float) * r->channels); if (r->data == NULL) return -errno;
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/resample.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/resample.c
Changed
@@ -48,7 +48,6 @@ #define DEFAULT_RATE 48000 #define DEFAULT_CHANNELS 2 -#define MAX_SAMPLES 8192u #define MAX_ALIGN 16 #define MAX_BUFFERS 32 @@ -57,12 +56,14 @@ struct props { double rate; int quality; + bool disabled; }; static void props_reset(struct props *props) { props->rate = 1.0; props->quality = RESAMPLE_DEFAULT_QUALITY; + props->disabled = false; } struct buffer { @@ -104,6 +105,8 @@ struct spa_log *log; struct spa_cpu *cpu; + uint32_t quantum_limit; + struct spa_io_position *io_position; struct spa_io_rate_match *io_rate_match; @@ -127,8 +130,6 @@ struct resample resample; double rate_scale; - - float empty[MAX_SAMPLES + MAX_ALIGN]; }; #define CHECK_PORT(this,d,id) (id == 0) @@ -183,7 +184,147 @@ uint32_t id, uint32_t start, uint32_t num, const struct spa_pod *filter) { - return -ENOTSUP; + struct impl *this = object; + struct spa_pod *param; + struct spa_pod_builder b = { 0 }; + uint8_t buffer[4096]; + struct spa_result_node_params result; + uint32_t count = 0; + + spa_return_val_if_fail(this != NULL, -EINVAL); + spa_return_val_if_fail(num != 0, -EINVAL); + + result.id = id; + result.next = start; + next: + result.index = result.next++; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + + switch (id) { + case SPA_PARAM_PropInfo: + { + struct props *p = &this->props; + + switch (result.index) { + case 0: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_rate), + SPA_PROP_INFO_description, SPA_POD_String("Rate scaler"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Double(p->rate, 0.0, 10.0)); + break; + case 1: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_quality), + SPA_PROP_INFO_name, SPA_POD_String("resample.quality"), + SPA_PROP_INFO_description, SPA_POD_String("Resample Quality"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->quality, 0, 14), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 2: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("resample.disable"), + SPA_PROP_INFO_description, SPA_POD_String("Disable Resampling"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->disabled), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + default: + return 0; + } + break; + } + case SPA_PARAM_Props: + { + struct props *p = &this->props; + struct spa_pod_frame f[2]; + + switch (result.index) { + case 0: + spa_pod_builder_push_object(&b, &f[0], SPA_TYPE_OBJECT_Props, id); + spa_pod_builder_add(&b, + SPA_PROP_rate, SPA_POD_Double(p->rate), + SPA_PROP_quality, SPA_POD_Int(p->quality), + 0); + spa_pod_builder_prop(&b, SPA_PROP_params, 0); + spa_pod_builder_push_struct(&b, &f[1]); + spa_pod_builder_string(&b, "resample.quality"); + spa_pod_builder_int(&b, p->quality); + spa_pod_builder_string(&b, "resample.disable"); + spa_pod_builder_bool(&b, p->disabled); + spa_pod_builder_pop(&b, &f[1]); + param = spa_pod_builder_pop(&b, &f[0]); + break; + default: + return 0; + } + break; + } + default: + return -ENOENT; + } + + if (spa_pod_filter(&b, &result.param, param, filter) < 0) + goto next; + + spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result); + + if (++count != num) + goto next; + + return 0; +} + +static int resample_set_param(struct impl *this, const char *k, const char *s) +{ + if (spa_streq(k, "resample.quality")) + this->props.quality = atoi(s); + else if (spa_streq(k, "resample.disable")) + this->props.disabled = spa_atob(s); + return 0; +} + +static int parse_prop_params(struct impl *this, struct spa_pod *params) +{ + struct spa_pod_parser prs; + struct spa_pod_frame f; + + spa_pod_parser_pod(&prs, params); + if (spa_pod_parser_push_struct(&prs, &f) < 0) + return 0; + + while (true) { + const char *name; + struct spa_pod *pod; + char value[512]; + + if (spa_pod_parser_get_string(&prs, &name) < 0) + break; + + if (spa_pod_parser_get_pod(&prs, &pod) < 0) + break; + + if (spa_pod_is_string(pod)) { + spa_pod_copy_string(pod, sizeof(value), value); + } else if (spa_pod_is_float(pod)) { + snprintf(value, sizeof(value), "%f", + SPA_POD_VALUE(struct spa_pod_float, pod)); + } else if (spa_pod_is_int(pod)) { + snprintf(value, sizeof(value), "%d", + SPA_POD_VALUE(struct spa_pod_int, pod)); + } else if (spa_pod_is_bool(pod)) { + snprintf(value, sizeof(value), "%s", + SPA_POD_VALUE(struct spa_pod_bool, pod) ? + "true" : "false"); + } else + continue; + + spa_log_info(this->log, "key:'%s' val:'%s'", name, value); + resample_set_param(this, name, value); + } + return 0; } static int apply_props(struct impl *this, const struct spa_pod *param) @@ -191,22 +332,28 @@ struct spa_pod_prop *prop; struct spa_pod_object *obj = (struct spa_pod_object *) param; struct props *p = &this->props; + int changed = 0; SPA_POD_OBJECT_FOREACH(obj, prop) { switch (prop->key) { case SPA_PROP_rate: if (spa_pod_get_double(&prop->value, &p->rate) == 0) { resample_update_rate(&this->resample, p->rate); + changed++; } break; case SPA_PROP_quality: - spa_pod_get_int(&prop->value, &p->quality); + if (spa_pod_get_int(&prop->value, &p->quality) == 0) + changed++; + break; + case SPA_PROP_params: + changed += parse_prop_params(this, &prop->value); break; default: break; } } - return 0; + return changed; } static int impl_node_set_param(void *object, uint32_t id, uint32_t flags, @@ -270,12 +417,16 @@ resample_update_rate(&this->resample, this->rate_scale * this->props.rate); } } +static inline bool is_passthrough(struct impl *this) +{ + return this->resample.i_rate == this->resample.o_rate && this->rate_scale == 1.0 && + (this->io_rate_match == NULL || this->props.disabled || + !SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)); +} static void recalc_rate_match(struct impl *this) { - bool passthrough = this->resample.i_rate == this->resample.o_rate && - (this->io_rate_match == NULL || - !SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)); + bool passthrough = is_passthrough(this); uint32_t out_size = this->io_position ? this->io_position->clock.duration : 1024; update_rate_match(this, passthrough, out_size, 0); } @@ -391,20 +542,24 @@ struct impl *this = object; struct port *other; struct spa_pod_frame f; + uint32_t rate, min = 1, max = INT32_MAX; other = GET_PORT(this, SPA_DIRECTION_REVERSE(direction), 0); switch (index) { case 0: if (other->have_format) { + rate = other->format.info.raw.rate; + if (this->props.disabled) + min = max = rate; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); spa_pod_builder_add(builder, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_F32P), - SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int( - other->format.info.raw.rate, 1, INT32_MAX), + SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(rate, min, max), SPA_FORMAT_AUDIO_channels, SPA_POD_Int(other->format.info.raw.channels), 0); spa_pod_builder_prop(builder, SPA_FORMAT_AUDIO_position, 0); @@ -412,15 +567,17 @@ other->format.info.raw.channels, other->format.info.raw.position); *param = spa_pod_builder_pop(builder, &f); } else { - uint32_t rate = this->io_position ? + rate = this->io_position ? this->io_position->clock.rate.denom : DEFAULT_RATE; + if (this->props.disabled) + min = max = rate; *param = spa_pod_builder_add_object(builder, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_F32P), - SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(rate, 1, INT32_MAX), + SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_RANGE_Int(rate, min, max), SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(DEFAULT_CHANNELS, 1, INT32_MAX)); } break; @@ -497,9 +654,9 @@ size = (other->size / other->stride) * rate; } else { buffers = 1; - size = MAX_SAMPLES * rate; + size = this->quantum_limit * rate; } - size = SPA_MAX(size, MAX_SAMPLES) * 2; + size = SPA_MAX(size, this->quantum_limit) * 2; param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_ParamBuffers, id, @@ -878,10 +1035,16 @@ src_datas = alloca(sizeof(void*) * this->resample.channels); dst_datas = alloca(sizeof(void*) * this->resample.channels); + if (inport->offset > size) + inport->offset = size; + if (outport->offset > maxsize) + outport->offset = maxsize; + if (size == 0) { - size = MAX_SAMPLES * sizeof(float); + size = sb->datas[0].maxsize; + memset(sb->datas[0].data, 0, size); for (i = 0; i < sb->n_datas; i++) - src_datas[i] = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void); + src_datas[i] = sb->datas[0].data; inport->offset = 0; flush_in = draining = true; } else { @@ -899,9 +1062,7 @@ pin_len = in_len; pout_len = out_len; #endif - passthrough = this->resample.i_rate == this->resample.o_rate && this->rate_scale == 1.0 && - (this->io_rate_match == NULL || - !SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)); + passthrough = is_passthrough(this); if (passthrough) { uint32_t len = SPA_MIN(in_len, out_len); @@ -1021,7 +1182,7 @@ { struct impl *this; struct port *port; - const char *str; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -1040,20 +1201,25 @@ props_reset(&this->props); - if (info != NULL) { - if ((str = spa_dict_lookup(info, "resample.quality")) != NULL) - this->props.quality = atoi(str); - if ((str = spa_dict_lookup(info, "resample.peaks")) != NULL) - this->peaks = spa_atob(str); - if ((str = spa_dict_lookup(info, "factory.mode")) != NULL) { - if (spa_streq(str, "split")) + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); + else if (spa_streq(k, "resample.peaks")) + this->peaks = spa_atob(s); + else if (spa_streq(k, "factory.mode")) { + if (spa_streq(s, "split")) this->mode = MODE_SPLIT; - else if (spa_streq(str, "merge")) + else if (spa_streq(s, "merge")) this->mode = MODE_MERGE; else this->mode = MODE_CONVERT; - } + } else + resample_set_param(this, k, s); + } + spa_log_debug(this->log, "mode:%d", this->mode); this->node.iface = SPA_INTERFACE_INIT(
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/spa-resample.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/spa-resample.c
Changed
@@ -49,6 +49,7 @@ int rate; int format; int quality; + int cpu_flags; const char *iname; SF_INFO iinfo; @@ -61,7 +62,7 @@ #define STR_FMTS "(s8|s16|s32|f32|f64)" -#define OPTIONS "hvr:f:q:" +#define OPTIONS "hvr:f:q:c:" static const struct option long_options[] = { { "help", no_argument, NULL, 'h'}, { "verbose", no_argument, NULL, 'v'}, @@ -69,6 +70,7 @@ { "rate", required_argument, NULL, 'r' }, { "format", required_argument, NULL, 'f' }, { "quality", required_argument, NULL, 'q' }, + { "cpuflags", required_argument, NULL, 'c' }, { NULL, 0, NULL, 0 } }; @@ -88,6 +90,7 @@ " -r --rate Output sample rate (default as input)\n" " -f --format Output sample format %s (default as input)\n" " -q --quality Resampler quality (default %u)\n" + " -c --cpuflags CPU flags (default 0)\n" "\n", STR_FMTS, DEFAULT_QUALITY); } @@ -191,6 +194,7 @@ bool flushing = false; spa_zero(r); + r.cpu_flags = d->cpu_flags; r.log = &logger.log; r.channels = channels; r.i_rate = d->iinfo.samplerate; @@ -297,6 +301,9 @@ } data.quality = ret; break; + case 'c': + data.cpu_flags = strtol(optarg, NULL, 0); + break; default: fprintf(stderr, "error: unknown option '%c'\n", c); goto error_usage;
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/splitter.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/splitter.c
Changed
@@ -53,7 +53,6 @@ #define DEFAULT_CHANNELS 2 #define DEFAULT_MASK (1LL << SPA_AUDIO_CHANNEL_FL) | (1LL << SPA_AUDIO_CHANNEL_FR) -#define MAX_SAMPLES 8192 #define MAX_ALIGN 16 #define MAX_BUFFERS 32 #define MAX_DATAS SPA_AUDIO_MAX_CHANNELS @@ -107,6 +106,9 @@ struct spa_log *log; struct spa_cpu *cpu; + uint32_t cpu_flags; + uint32_t quantum_limit; + struct spa_io_position *io_position; uint64_t info_all; @@ -124,7 +126,6 @@ struct spa_audio_info format; unsigned int have_profile:1; - uint32_t cpu_flags; struct convert conv; unsigned int is_passthrough:1; unsigned int started:1; @@ -134,7 +135,8 @@ uint32_t src_remap[SPA_AUDIO_MAX_CHANNELS]; uint32_t dst_remap[SPA_AUDIO_MAX_CHANNELS]; - float empty[MAX_SAMPLES + MAX_ALIGN]; + uint32_t empty_size; + float *empty; }; #define CHECK_OUT_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < this->port_count) @@ -456,11 +458,14 @@ SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(22, + SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(25, SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32_OE, + SPA_AUDIO_FORMAT_F64P, + SPA_AUDIO_FORMAT_F64, + SPA_AUDIO_FORMAT_F64_OE, SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32_OE, @@ -550,9 +555,9 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - MAX_SAMPLES * port->stride, + this->quantum_limit * port->stride, 16 * port->stride, - MAX_SAMPLES * port->stride), + INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); break; @@ -690,6 +695,10 @@ case SPA_AUDIO_FORMAT_S24: case SPA_AUDIO_FORMAT_S24_OE: return 3; + case SPA_AUDIO_FORMAT_F64P: + case SPA_AUDIO_FORMAT_F64: + case SPA_AUDIO_FORMAT_F64_OE: + return 8; default: return 4; } @@ -877,7 +886,7 @@ { struct impl *this = object; struct port *port; - uint32_t i, j; + uint32_t i, j, maxsize; spa_return_val_if_fail(this != NULL, -EINVAL); spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); @@ -890,6 +899,7 @@ clear_buffers(this, port); + maxsize = 0; for (i = 0; i < n_buffers; i++) { struct buffer *b; uint32_t n_datas = buffers[i]->n_datas; @@ -917,11 +927,19 @@ spa_log_debug(this->log, "%p: buffer %d data %d flags:%08x %p", this, i, j, d[j].flags, b->datas[j]); - } + maxsize = SPA_MAX(maxsize, d[j].maxsize); + } if (direction == SPA_DIRECTION_OUTPUT) queue_buffer(this, port, i); } + if (maxsize > this->empty_size) { + this->empty = realloc(this->empty, maxsize + MAX_ALIGN); + if (this->empty == NULL) + return -errno; + memset(this->empty, 0, maxsize + MAX_ALIGN); + this->empty_size = maxsize; + } port->n_buffers = n_buffers; return 0; @@ -975,7 +993,6 @@ uint32_t n_src_datas, n_dst_datas; const void **src_datas; void **dst_datas; - int res = 0; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -1063,10 +1080,8 @@ convert_process(&this->conv, dst_datas, src_datas, n_samples); inio->status = SPA_STATUS_NEED_DATA; - res |= SPA_STATUS_NEED_DATA; - res |= SPA_STATUS_HAVE_DATA; - return res; + return SPA_STATUS_NEED_DATA | SPA_STATUS_HAVE_DATA; } static const struct spa_node_methods impl_node = { @@ -1115,6 +1130,7 @@ for (i = 0; i < MAX_PORTS; i++) free(this->out_ports[i]); + free(this->empty); return 0; } @@ -1134,6 +1150,7 @@ { struct impl *this; struct port *port; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -1150,6 +1167,13 @@ if (this->cpu) this->cpu_flags = spa_cpu_get_flags(this->cpu); + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); + } + spa_hook_list_init(&this->hooks); this->latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/test-channelmix.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/test-channelmix.c
Changed
@@ -162,7 +162,7 @@ test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), MATRIX(1.0, 0.0, 0.707107, 0.0, 0.0, 1.0, 0.0, 0.707107, - 0.0, 0.0, 0.0, 0.0, + 0.707107, 0.707107, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); }
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/test-fmt-ops.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/test-fmt-ops.c
Changed
@@ -41,10 +41,10 @@ static uint32_t cpu_flags; -static uint8_t samp_in[N_SAMPLES * 4]; -static uint8_t samp_out[N_SAMPLES * 4]; -static uint8_t temp_in[N_SAMPLES * N_CHANNELS * 4]; -static uint8_t temp_out[N_SAMPLES * N_CHANNELS * 4]; +static uint8_t samp_in[N_SAMPLES * 8]; +static uint8_t samp_out[N_SAMPLES * 8]; +static uint8_t temp_in[N_SAMPLES * N_CHANNELS * 8]; +static uint8_t temp_out[N_SAMPLES * N_CHANNELS * 8]; static void compare_mem(int i, int j, const void *m1, const void *m2, size_t size) { @@ -92,6 +92,9 @@ case 4: conv_interleave_32_c(&conv, tp, ip, N_SAMPLES); break; + case 8: + conv_interleave_64_c(&conv, tp, ip, N_SAMPLES); + break; default: fprintf(stderr, "unknown size %zd\n", in_size); return; @@ -430,6 +433,35 @@ false, false, conv_s24_32d_to_f32d_c); } +static void test_f64_f32(void) +{ + static const double in[] = { 0.0, 1.0, -1.0, 0.4999999404, -0.4999999404, }; + static const float out[] = { 0.0f, 1.0f, -1.0f, 0.4999999404f, -0.4999999404f, }; + + run_test("test_f64_f32d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + true, false, conv_f64_to_f32d_c); + run_test("test_f64d_f32", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + false, true, conv_f64d_to_f32_c); + run_test("test_f64_f32", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + true, true, conv_f64_to_f32_c); + run_test("test_f64d_f32d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + false, false, conv_f64d_to_f32d_c); +} + +static void test_f32_f64(void) +{ + static const float in[] = { 0.0f, 1.0f, -1.0f, 0.5f, -0.5f, 1.1f, -1.1f }; + static const double out[] = { 0.0, 1.0, -1.0, 0.5, -0.5, 1.1, -1.1 }; + + run_test("test_f32_f64", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + true, true, conv_f32_to_f64_c); + run_test("test_f32d_f64", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + false, true, conv_f32d_to_f64_c); + run_test("test_f32_f64d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + true, false, conv_f32_to_f64d_c); + run_test("test_f32d_f64d", in, sizeof(in[0]), out, sizeof(out[0]), SPA_N_ELEMENTS(out), + false, false, conv_f32d_to_f64d_c); +} int main(int argc, char *argv[]) { cpu_flags = get_cpu_flags(); @@ -453,5 +485,7 @@ test_u24_32_f32(); test_f32_s24_32(); test_s24_32_f32(); + test_f32_f64(); + test_f64_f32(); return 0; }
View file
pipewire-0.3.43.tar.gz/spa/plugins/audioconvert/test-source.c -> pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/test-source.c
Changed
@@ -45,7 +45,6 @@ #define DEFAULT_RATE 44100 #define DEFAULT_CHANNELS 2 -#define MAX_SAMPLES 8192 #define MAX_BUFFERS 32 struct impl; @@ -101,6 +100,8 @@ struct spa_log *log; + uint32_t quantum_limit; + struct spa_hook_list hooks; uint64_t info_all; @@ -458,7 +459,7 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - MAX_SAMPLES * port->stride, + this->quantum_limit * port->stride, 16 * port->stride, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); @@ -830,6 +831,7 @@ { struct impl *this; struct port *port; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -841,6 +843,13 @@ this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); + } + spa_log_debug(this->log, NAME " %p: init", this); spa_hook_list_init(&this->hooks);
View file
pipewire-0.3.43.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.44.tar.gz/spa/plugins/audiomixer/audiomixer.c
Changed
@@ -45,11 +45,9 @@ #define SPA_LOG_TOPIC_DEFAULT log_topic static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.audiomixer"); -#define MAX_SAMPLES 8192 #define MAX_BUFFERS 64 #define MAX_PORTS 128 #define MAX_CHANNELS 64 -#define MAX_BUFFER_SIZE (MAX_SAMPLES * MAX_CHANNELS * 8) #define PORT_DEFAULT_VOLUME 1.0 #define PORT_DEFAULT_MUTE false @@ -74,8 +72,6 @@ struct spa_buffer *buffer; struct spa_meta_header *h; struct spa_buffer buf; - struct spa_data datas[1]; - struct spa_chunk chunk[1]; }; struct port { @@ -107,6 +103,7 @@ struct spa_log *log; struct spa_cpu *cpu; uint32_t cpu_flags; + uint32_t quantum_limit; struct mix_ops ops; @@ -128,9 +125,6 @@ unsigned int started:1; uint32_t stride; uint32_t blocks; - - uint8_t empty[MAX_BUFFER_SIZE]; - }; #define PORT_VALID(p) ((p) != NULL && (p)->valid) @@ -421,7 +415,7 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(this->blocks), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - MAX_SAMPLES * this->stride, + this->quantum_limit * this->stride, 16 * this->stride, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->stride)); @@ -520,6 +514,10 @@ case SPA_AUDIO_FORMAT_S24_OE: case SPA_AUDIO_FORMAT_U24: return 3; + case SPA_AUDIO_FORMAT_F64P: + case SPA_AUDIO_FORMAT_F64: + case SPA_AUDIO_FORMAT_F64_OE: + return 8; default: return 4; } @@ -653,6 +651,7 @@ b->flags = 0; b->id = i; b->h = spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h)); + b->buf = *buffers[i]; if (d[0].data == NULL) { spa_log_error(this->log, "%p: invalid memory on buffer %p", this, @@ -721,9 +720,9 @@ struct impl *this = object; struct port *outport; struct spa_io_buffers *outio; - uint32_t n_samples, n_buffers, i, maxsize; + uint32_t n_buffers, i, maxsize; struct buffer **buffers; - struct buffer *outb; + struct buffer *outb; const void **datas; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -748,7 +747,7 @@ datas = alloca(MAX_PORTS * sizeof(void *)); n_buffers = 0; - maxsize = MAX_SAMPLES * this->stride; + maxsize = UINT32_MAX; for (i = 0; i < this->last_port; i++) { struct port *inport = GET_IN_PORT(this, i); @@ -785,22 +784,22 @@ return -EPIPE; } - n_samples = maxsize / this->stride; - if (n_buffers == 1) { *outb->buffer = *buffers[0]->buffer; } else { - outb->buffer->n_datas = 1; - outb->buffer->datas = outb->datas; - outb->datas[0].data = this->empty; - outb->datas[0].chunk = outb->chunk; - outb->datas[0].chunk->offset = 0; - outb->datas[0].chunk->size = n_samples * this->stride; - outb->datas[0].chunk->stride = this->stride; - outb->datas[0].maxsize = maxsize; - - mix_ops_process(&this->ops, outb->datas[0].data, datas, n_buffers, n_samples); + struct spa_data *d = outb->buf.datas; + + *outb->buffer = outb->buf; + + maxsize = SPA_MIN(maxsize, d[0].maxsize); + + d[0].chunk->offset = 0; + d[0].chunk->size = maxsize; + d[0].chunk->stride = this->stride; + + mix_ops_process(&this->ops, d[0].data, + datas, n_buffers, maxsize / this->stride); } outio->buffer_id = outb->id; @@ -875,6 +874,7 @@ { struct impl *this; struct port *port; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -891,6 +891,13 @@ if (this->cpu) this->cpu_flags = spa_cpu_get_flags(this->cpu); + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); + } + spa_hook_list_init(&this->hooks); this->node.iface = SPA_INTERFACE_INIT(
View file
pipewire-0.3.43.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.44.tar.gz/spa/plugins/audiomixer/mixer-dsp.c
Changed
@@ -47,7 +47,6 @@ #define MAX_BUFFERS 64 #define MAX_PORTS 128 -#define MAX_SAMPLES 8192 #define MAX_ALIGN 64 #define PORT_DEFAULT_VOLUME 1.0 @@ -73,8 +72,6 @@ struct spa_buffer *buffer; struct spa_meta_header *h; struct spa_buffer buf; - struct spa_data datas[1]; - struct spa_chunk chunk[1]; }; struct port { @@ -107,6 +104,8 @@ struct spa_cpu *cpu; uint32_t cpu_flags; + uint32_t quantum_limit; + struct mix_ops ops; uint64_t info_all; @@ -126,8 +125,6 @@ unsigned int have_format:1; unsigned int started:1; - - float empty[MAX_SAMPLES + MAX_ALIGN]; }; #define PORT_VALID(p) ((p) != NULL && (p)->valid) @@ -400,7 +397,7 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - MAX_SAMPLES * this->stride, + this->quantum_limit * this->stride, 16 * this->stride, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->stride)); @@ -601,12 +598,13 @@ b->flags = 0; b->id = i; b->h = spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h)); + b->buf = *buffers[i]; if (d[0].data == NULL) { spa_log_error(this->log, "%p: invalid memory on buffer %d", this, i); return -EINVAL; } - if (!SPA_IS_ALIGNED(d[0].data, 16)) { + if (!SPA_IS_ALIGNED(d[0].data, 32)) { spa_log_warn(this->log, "%p: memory on buffer %d not aligned", this, i); } if (direction == SPA_DIRECTION_OUTPUT) @@ -668,9 +666,9 @@ struct impl *this = object; struct port *outport; struct spa_io_buffers *outio; - uint32_t n_samples, n_buffers, i, maxsize; - struct buffer **buffers; - struct buffer *outb; + uint32_t n_buffers, i, maxsize; + struct buffer **buffers; + struct buffer *outb; const void **datas; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -695,7 +693,7 @@ datas = alloca(MAX_PORTS * sizeof(void *)); n_buffers = 0; - maxsize = MAX_SAMPLES * sizeof(float); + maxsize = UINT32_MAX; for (i = 0; i < this->last_port; i++) { struct port *inport = GET_IN_PORT(this, i); @@ -732,21 +730,20 @@ return -EPIPE; } - n_samples = maxsize / sizeof(float); - if (n_buffers == 1) { *outb->buffer = *buffers[0]->buffer; - } - else { - outb->buffer->n_datas = 1; - outb->buffer->datas = outb->datas; - outb->datas[0].data = SPA_PTR_ALIGN(this->empty, MAX_ALIGN, void); - outb->datas[0].chunk = outb->chunk; - outb->datas[0].chunk->offset = 0; - outb->datas[0].chunk->size = n_samples * sizeof(float); - outb->datas[0].chunk->stride = sizeof(float); - - mix_ops_process(&this->ops, outb->datas[0].data, datas, n_buffers, n_samples); + } else { + struct spa_data *d = outb->buf.datas; + *outb->buffer = outb->buf; + + maxsize = SPA_MIN(maxsize, d[0].maxsize); + + d[0].chunk->offset = 0; + d[0].chunk->size = maxsize; + d[0].chunk->stride = sizeof(float); + + mix_ops_process(&this->ops, d[0].data, + datas, n_buffers, maxsize / sizeof(float)); } outio->buffer_id = outb->id; @@ -820,6 +817,7 @@ { struct impl *this; struct port *port; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -836,6 +834,13 @@ if (this->cpu) this->cpu_flags = spa_cpu_get_flags(this->cpu); + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); + } + spa_hook_list_init(&this->hooks); this->node.iface = SPA_INTERFACE_INIT(
View file
pipewire-0.3.43.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c -> pipewire-0.3.44.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c
Changed
@@ -75,7 +75,6 @@ props->volume = DEFAULT_VOLUME; } -#define MAX_SAMPLES 8192 #define MAX_BUFFERS 16 #define MAX_PORTS 1 @@ -119,6 +118,8 @@ struct spa_loop *data_loop; struct spa_system *data_system; + uint32_t quantum_limit; + uint64_t info_all; struct spa_node_info info; struct spa_param_info params[2]; @@ -646,7 +647,7 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - MAX_SAMPLES * port->bpf, + this->quantum_limit * port->bpf, 16 * port->bpf, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->bpf)); @@ -1014,6 +1015,7 @@ { struct impl *this; struct port *port; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -1027,6 +1029,12 @@ 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); + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); + } spa_hook_list_init(&this->hooks); this->node.iface = SPA_INTERFACE_INIT(
View file
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/backend-hsphfpd.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/backend-hsphfpd.c
Changed
@@ -1088,7 +1088,7 @@ } d = spa_bt_device_find_by_address(backend->monitor, endpoint->remote_address, endpoint->local_address); - if (!d) { + if (!d || !d->adapter) { spa_log_debug(backend->log, "No device for %s", endpoint->path); return DBUS_HANDLER_RESULT_HANDLED; }
View file
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/backend-native.c
Changed
@@ -137,6 +137,8 @@ unsigned int msbc_supported_by_hfp:1; unsigned int hfp_ag_switching_codec:1; unsigned int hfp_ag_initial_codec_setup:2; + unsigned int cind_call_active:1; + unsigned int cind_call_notify:1; enum hfp_hf_state hf_state; enum hsp_hs_state hs_state; unsigned int codec; @@ -676,6 +678,22 @@ } } +static void rfcomm_hfp_ag_set_cind(struct rfcomm *rfcomm, bool call_active) +{ + if (rfcomm->profile != SPA_BT_PROFILE_HFP_HF) + return; + + if (call_active == rfcomm->cind_call_active) + return; + + rfcomm->cind_call_active = call_active; + + if (!rfcomm->cind_call_notify) + return; + + rfcomm_send_reply(rfcomm, "+CIEV: 2,%d", rfcomm->cind_call_active); +} + static bool rfcomm_hfp_ag(struct rfcomm *rfcomm, char* buf) { struct impl *backend = rfcomm->backend; @@ -762,12 +780,20 @@ rfcomm_send_reply(rfcomm, "+CIND:(\"service\",(0-1)),(\"call\",(0-1)),(\"callsetup\",(0-3)),(\"callheld\",(0-2))"); rfcomm_send_reply(rfcomm, "OK"); } else if (spa_strstartswith(buf, "AT+CIND?")) { - rfcomm_send_reply(rfcomm, "+CIND: 0,0,0,0"); + rfcomm_send_reply(rfcomm, "+CIND: 0,%d,0,0", rfcomm->cind_call_active); rfcomm_send_reply(rfcomm, "OK"); } else if (spa_strstartswith(buf, "AT+CMER")) { + int mode, keyp, disp, ind; + rfcomm->slc_configured = true; rfcomm_send_reply(rfcomm, "OK"); + rfcomm->cind_call_active = false; + if (sscanf(buf, "AT+CMER= %d , %d , %d , %d", &mode, &keyp, &disp, &ind) == 4) + rfcomm->cind_call_notify = ind ? true : false; + else + rfcomm->cind_call_notify = false; + /* switch codec to mSBC by sending unsolicited +BCS message */ if (rfcomm->codec_negotiation_supported && rfcomm->msbc_supported_by_hfp) { spa_log_debug(backend->log, "RFCOMM initial codec setup"); @@ -785,7 +811,6 @@ rfcomm_emit_volume_changed(rfcomm, -1, SPA_BT_VOLUME_INVALID); } } - } else if (!rfcomm->slc_configured) { spa_log_warn(backend->log, "RFCOMM receive command before SLC completed: %s", buf); rfcomm_send_reply(rfcomm, "ERROR"); @@ -829,6 +854,11 @@ rfcomm_send_reply(rfcomm, "OK"); if (was_switching_codec) spa_bt_device_emit_codec_switched(rfcomm->device, 0); + } else if (spa_strstartswith(buf, "AT+BIA=")) { + /* We only support 'call' indicator, which HFP 4.35.1 defines as + always active (assuming CMER enabled it), so we don't need to + parse anything here. */ + rfcomm_send_reply(rfcomm, "OK"); } else if (sscanf(buf, "AT+VGM=%u", &gain) == 1) { if (gain <= SPA_BT_VOLUME_HS_MAX) { if (!rfcomm->broken_mic_hw_volume) @@ -1172,12 +1202,17 @@ static int sco_acquire_cb(void *data, bool optional) { struct spa_bt_transport *t = data; + struct transport_data *td = t->user_data; struct impl *backend = SPA_CONTAINER_OF(t->backend, struct impl, this); int sock; socklen_t len; spa_log_debug(backend->log, "transport %p: enter sco_acquire_cb", t); +#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE + rfcomm_hfp_ag_set_cind(td->rfcomm, true); +#endif + if (optional || t->fd > 0) sock = t->fd; else @@ -1217,10 +1252,15 @@ static int sco_release_cb(void *data) { struct spa_bt_transport *t = data; + struct transport_data *td = t->user_data; struct impl *backend = SPA_CONTAINER_OF(t->backend, struct impl, this); spa_log_info(backend->log, "Transport %s released", t->path); +#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE + rfcomm_hfp_ag_set_cind(td->rfcomm, false); +#endif + if (t->sco_io) { spa_bt_sco_io_destroy(t->sco_io); t->sco_io = NULL; @@ -1689,7 +1729,7 @@ dbus_message_iter_get_basic(&it[0], &path); d = spa_bt_device_find(backend->monitor, path); - if (d == NULL) { + if (d == NULL || d->adapter == NULL) { spa_log_warn(backend->log, "unknown device for path %s", path); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1816,7 +1856,7 @@ dbus_message_iter_get_basic(&it[0], &path); d = spa_bt_device_find(backend->monitor, path); - if (d == NULL) { + if (d == NULL || d->adapter == NULL) { spa_log_warn(backend->log, "unknown device for path %s", path); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
View file
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/backend-ofono.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/backend-ofono.c
Changed
@@ -364,7 +364,7 @@ } d = spa_bt_device_find_by_address(backend->monitor, remote_address, local_address); - if (!d) { + if (!d || !d->adapter) { spa_log_error(backend->log, "Device doesn’t exist for %s", path); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
View file
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -229,7 +229,7 @@ device->battery_pending_call = NULL; } - if (!device->adapter->has_battery_provider || !device->has_battery) + if (!device->adapter || !device->adapter->has_battery_provider || !device->has_battery) return; spa_log_debug(device->monitor->log, "Removing virtual battery: %s", device->battery_path); @@ -694,6 +694,22 @@ return 0; } +static void adapter_update_devices(struct spa_bt_adapter *adapter) +{ + struct spa_bt_monitor *monitor = adapter->monitor; + struct spa_bt_device *device; + + /* + * Update devices when new adapter appears. + * Devices may appear on DBus before or after the adapter does. + */ + + spa_list_for_each(device, &monitor->device_list, link) { + if (device->adapter == NULL && spa_streq(device->adapter_path, adapter->path)) + device->adapter = adapter; + } +} + static void adapter_register_player(struct spa_bt_adapter *adapter) { if (adapter->player_registered || !adapter->monitor->dummy_avrcp_player) @@ -785,11 +801,20 @@ return d; } +static void device_free(struct spa_bt_device *device); + static void adapter_free(struct spa_bt_adapter *adapter) { struct spa_bt_monitor *monitor = adapter->monitor; + struct spa_bt_device *d, *td; + spa_log_debug(monitor->log, "%p", adapter); + /* Devices should be destroyed before their assigned adapter */ + spa_list_for_each_safe(d, td, &monitor->device_list, link) + if (d->adapter == adapter) + device_free(d); + spa_bt_player_destroy(adapter->dummy_player); spa_list_remove(&adapter->link); @@ -1159,7 +1184,7 @@ } #define DEVICE_RECONNECT_TIMEOUT_SEC 2 -#define DEVICE_PROFILE_TIMEOUT_SEC 3 +#define DEVICE_PROFILE_TIMEOUT_SEC 6 static void device_timer_event(struct spa_source *source) { @@ -1238,19 +1263,34 @@ { struct spa_bt_monitor *monitor = device->monitor; uint32_t connected_profiles = device->connected_profiles; + uint32_t direction_masks[2] = { + SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_HEADSET_AUDIO, + SPA_BT_PROFILE_A2DP_SOURCE | SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY, + }; + bool direction_connected = false; + bool all_connected; + size_t i; if (connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT) connected_profiles |= SPA_BT_PROFILE_HEADSET_HEAD_UNIT; if (connected_profiles & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY) connected_profiles |= SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY; + for (i = 0; i < SPA_N_ELEMENTS(direction_masks); ++i) { + uint32_t mask = direction_masks[i] & device->profiles; + if (mask && (connected_profiles & mask) == mask) + direction_connected = true; + } + + all_connected = (device->profiles & connected_profiles) == device->profiles; + spa_log_debug(monitor->log, "device %p: profiles %08x %08x %d", device, device->profiles, connected_profiles, device->added); if (connected_profiles == 0 && spa_list_is_empty(&device->codec_switch_list)) { device_stop_timer(device); device_connected(monitor, device, BT_DEVICE_DISCONNECTED); - } else if (force || (device->profiles & connected_profiles) == device->profiles) { + } else if (force || direction_connected || all_connected) { device_stop_timer(device); device_connected(monitor, device, BT_DEVICE_CONNECTED); } else { @@ -1349,7 +1389,7 @@ device->adapter = adapter_find(monitor, value); if (device->adapter == NULL) { - spa_log_warn(monitor->log, "unknown adapter %s", value); + spa_log_info(monitor->log, "unknown adapter %s", value); } } else if (spa_streq(key, "Icon")) { @@ -1455,6 +1495,15 @@ return 0; } +static bool device_props_ready(struct spa_bt_device *device) +{ + /* + * In some cases, BlueZ device props may be missing part of + * the information required when the interface first appears. + */ + return device->adapter && device->address; +} + bool spa_bt_device_supports_a2dp_codec(struct spa_bt_device *device, const struct a2dp_codec *codec) { struct spa_bt_monitor *monitor = device->monitor; @@ -2091,9 +2140,16 @@ spa_bt_transport_set_state(transport, spa_bt_transport_state_from_string(value)); } else if (spa_streq(key, "Device")) { - transport->device = spa_bt_device_find(monitor, value); - if (transport->device == NULL) - spa_log_warn(monitor->log, "could not find device %s", value); + struct spa_bt_device *device = spa_bt_device_find(monitor, value); + if (transport->device != device) { + if (transport->device != NULL) + spa_list_remove(&transport->device_link); + transport->device = device; + if (device != NULL) + spa_list_append(&device->transport_list, &transport->device_link); + else + spa_log_warn(monitor->log, "could not find device %s", value); + } } } else if (spa_streq(key, "Codec")) { @@ -2874,7 +2930,6 @@ DBusMessageIter it[2]; DBusMessage *r; struct spa_bt_transport *transport; - bool is_new = false; const struct a2dp_codec *codec; int profile; @@ -2897,9 +2952,8 @@ dbus_message_iter_recurse(&it[0], &it[1]); transport = spa_bt_transport_find(monitor, transport_path); - is_new = transport == NULL; - if (is_new) { + if (transport == NULL) { char *tpath = strdup(transport_path); transport = spa_bt_transport_create(monitor, tpath, 0); @@ -2928,14 +2982,10 @@ transport->a2dp_codec = codec; transport_update_props(transport, &it[1], NULL); - if (transport->device == NULL) { + if (transport->device == NULL || transport->device->adapter == NULL) { spa_log_warn(monitor->log, "no device found for transport"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - spa_bt_device_add_profile(transport->device, transport->profile); - - if (is_new) - spa_list_append(&transport->device->transport_list, &transport->device_link); device_update_last_bluez_action_time(transport->device); @@ -2966,6 +3016,8 @@ spa_log_info(monitor->log, "%p: %s validate conf channels:%d", monitor, path, transport->n_channels); + spa_bt_device_add_profile(transport->device, transport->profile); + spa_bt_device_connect_profile(transport->device, transport->profile); /* Sync initial volumes */ @@ -3585,6 +3637,7 @@ adapter_update_props(a, props_iter, NULL); adapter_register_application(a); adapter_register_player(a); + adapter_update_devices(a); } else if (spa_streq(interface_name, BLUEZ_PROFILE_MANAGER_INTERFACE)) { if (monitor->backends[BACKEND_NATIVE]) @@ -3607,6 +3660,9 @@ device_update_props(d, props_iter, NULL); d->reconnect_state = BT_DEVICE_RECONNECT_INIT; + if (!device_props_ready(d)) + return; + device_update_hw_volume_profiles(d); /* Trigger bluez device creation before bluez profile negotiation started so that @@ -3963,6 +4019,12 @@ spa_log_debug(monitor->log, "Properties changed in device %s", path); device_update_props(d, &it[1], NULL); + + if (!device_props_ready(d)) + goto finish; + + device_update_hw_volume_profiles(d); + spa_bt_device_add_profile(d, SPA_BT_PROFILE_NULL); } else if (spa_streq(iface, BLUEZ_MEDIA_ENDPOINT_INTERFACE)) {
View file
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
@@ -137,6 +137,7 @@ uint32_t profile; unsigned int switching_codec:1; + unsigned int save_profile:1; uint32_t prev_bt_connected_profiles; const struct a2dp_codec **supported_codecs; @@ -757,7 +758,7 @@ static bool validate_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_audio_codec codec); -static int set_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_audio_codec codec) +static int set_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_audio_codec codec, bool save) { if (!validate_profile(this, profile, codec)) { spa_log_warn(this->log, "trying to set invalid profile %d, codec %d, %08x %08x", @@ -766,6 +767,8 @@ return -EINVAL; } + this->save_profile = save; + if (this->profile == profile && (this->profile != DEVICE_PROFILE_A2DP || codec == this->props.codec) && (this->profile != DEVICE_PROFILE_HSP_HFP || codec == this->props.codec)) @@ -1104,6 +1107,8 @@ /* If default profile is set to HSP/HFP, first try those and exit if found. */ if (this->bt_dev->settings != NULL) { const char *str = spa_dict_lookup(this->bt_dev->settings, "bluez5.profile"); + if (spa_streq(str, "off")) + goto off; if (spa_streq(str, "headset-head-unit") && set_initial_hsp_hfp_profile(this)) return; } @@ -1126,6 +1131,7 @@ if (set_initial_hsp_hfp_profile(this)) return; +off: spa_log_debug(this->log, "initial profile off"); this->profile = DEVICE_PROFILE_OFF; @@ -1133,7 +1139,8 @@ } static struct spa_pod *build_profile(struct impl *this, struct spa_pod_builder *b, - uint32_t id, uint32_t index, uint32_t profile_index, enum spa_bluetooth_audio_codec codec) + uint32_t id, uint32_t index, uint32_t profile_index, enum spa_bluetooth_audio_codec codec, + bool current) { struct spa_bt_device *device = this->bt_dev; struct spa_pod_frame f[2]; @@ -1266,6 +1273,10 @@ } spa_pod_builder_pop(b, &f[1]); } + if (current) { + spa_pod_builder_prop(b, SPA_PARAM_PROFILE_save, 0); + spa_pod_builder_bool(b, this->save_profile); + } if (name_and_codec) free(name_and_codec); @@ -1282,7 +1293,7 @@ uint8_t buffer[1024]; spa_pod_builder_init(&b, buffer, sizeof(buffer)); - return (build_profile(this, &b, 0, 0, profile, codec) != NULL); + return (build_profile(this, &b, 0, 0, profile, codec, false) != NULL); } static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b, @@ -1597,7 +1608,7 @@ case DEVICE_PROFILE_AG: case DEVICE_PROFILE_A2DP: case DEVICE_PROFILE_HSP_HFP: - param = build_profile(this, &b, id, result.index, profile, codec); + param = build_profile(this, &b, id, result.index, profile, codec, false); if (param == NULL) goto next; break; @@ -1613,7 +1624,7 @@ switch (result.index) { case 0: index = get_index_from_profile(this, this->profile, this->props.codec); - param = build_profile(this, &b, id, index, this->profile, this->props.codec); + param = build_profile(this, &b, id, index, this->profile, this->props.codec, true); if (param == NULL) return 0; break; @@ -1858,13 +1869,15 @@ uint32_t idx, next; uint32_t profile; enum spa_bluetooth_audio_codec codec; + bool save = false; if (param == NULL) return -EINVAL; if ((res = spa_pod_parse_object(param, SPA_TYPE_OBJECT_ParamProfile, NULL, - SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx))) < 0) { + SPA_PARAM_PROFILE_index, SPA_POD_Int(&idx), + SPA_PARAM_PROFILE_save, SPA_POD_OPT_Bool(&save))) < 0) { spa_log_warn(this->log, "can't parse profile"); spa_debug_pod(0, NULL, param); return res; @@ -1874,8 +1887,8 @@ if (profile == SPA_ID_INVALID) return -EINVAL; - spa_log_debug(this->log, "setting profile %d codec:%d", profile, codec); - return set_profile(this, profile, codec); + spa_log_debug(this->log, "setting profile %d codec:%d save:%d", profile, codec, (int)save); + return set_profile(this, profile, codec, save); } case SPA_PARAM_Route: { @@ -1927,6 +1940,8 @@ return res; } + spa_log_debug(this->log, "setting props codec:%d", codec_id); + if (codec_id == SPA_ID_INVALID) return 0; @@ -1934,16 +1949,16 @@ size_t j; for (j = 0; j < this->supported_codec_count; ++j) { if (this->supported_codecs[j]->id == codec_id) { - return set_profile(this, this->profile, codec_id); + return set_profile(this, this->profile, codec_id, true); } } } else if (this->profile == DEVICE_PROFILE_HSP_HFP) { if (codec_id == SPA_BLUETOOTH_AUDIO_CODEC_CVSD && spa_bt_device_supports_hfp_codec(this->bt_dev, HFP_AUDIO_CODEC_CVSD) == 1) { - return set_profile(this, this->profile, codec_id); + return set_profile(this, this->profile, codec_id, true); } else if (codec_id == SPA_BLUETOOTH_AUDIO_CODEC_MSBC && spa_bt_device_supports_hfp_codec(this->bt_dev, HFP_AUDIO_CODEC_MSBC) == 1) { - return set_profile(this, this->profile, codec_id); + return set_profile(this, this->profile, codec_id, true); } } return -EINVAL;
View file
pipewire-0.3.43.tar.gz/spa/plugins/bluez5/quirks.c -> pipewire-0.3.44.tar.gz/spa/plugins/bluez5/quirks.c
Changed
@@ -332,7 +332,7 @@ } /* Adapter */ - if (this->adapter_rules) { + if (this->adapter_rules && adapter) { uint32_t no_features = 0; int nitems = 0; char vendor_id[64], product_id[64], address[64]; @@ -357,7 +357,7 @@ } /* Device */ - if (this->device_rules) { + if (this->device_rules && device) { uint32_t no_features = 0; int nitems = 0; char vendor_id[64], product_id[64], version_id[64], address[64];
View file
pipewire-0.3.43.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.44.tar.gz/spa/plugins/support/loop.c
Changed
@@ -187,7 +187,7 @@ int32_t filled; uint32_t avail, idx, offset, l0; - if (pthread_equal(impl->thread, pthread_self())) + if (impl->thread == 0 || pthread_equal(impl->thread, pthread_self())) return loop_invoke_inthread(impl, func, seq, data, size, block, user_data); filled = spa_ringbuffer_get_write_index(&impl->buffer, &idx);
View file
pipewire-0.3.43.tar.gz/spa/plugins/support/null-audio-sink.c -> pipewire-0.3.44.tar.gz/spa/plugins/support/null-audio-sink.c
Changed
@@ -70,7 +70,6 @@ #define DEFAULT_CHANNELS 2 #define DEFAULT_RATE 44100 -#define MAX_SAMPLES 8192 #define MAX_BUFFERS 16 #define MAX_PORTS 1 @@ -107,6 +106,8 @@ struct spa_loop *data_loop; struct spa_system *data_system; + uint32_t quantum_limit; + struct props props; uint64_t info_all; @@ -538,7 +539,7 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(1, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - MAX_SAMPLES * port->bpf, + this->quantum_limit * port->bpf, 16 * port->bpf, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->bpf)); @@ -856,7 +857,6 @@ spa_log_error(this->log, "a data_system is needed"); return -EINVAL; } - spa_hook_list_init(&this->hooks); this->node.iface = SPA_INTERFACE_INIT( @@ -904,7 +904,9 @@ for (i = 0; info && i < info->n_items; i++) { const char *k = info->items[i].key; const char *s = info->items[i].value; - if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) { + if (spa_streq(k, "clock.quantum-limit")) { + spa_atou32(s, &this->quantum_limit, 0); + } else if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) { this->props.channels = atoi(s); } else if (spa_streq(k, SPA_KEY_AUDIO_RATE)) { this->props.rate = atoi(s);
View file
pipewire-0.3.43.tar.gz/spa/plugins/v4l2/v4l2-udev.c -> pipewire-0.3.44.tar.gz/spa/plugins/v4l2/v4l2-udev.c
Changed
@@ -311,18 +311,17 @@ } } - str = udev_device_get_property_value(dev, "ID_V4L_PRODUCT"); + str = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE"); if (!(str && *str)) { - str = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE"); + str = udev_device_get_property_value(dev, "ID_MODEL_ENC"); if (!(str && *str)) { - str = udev_device_get_property_value(dev, "ID_MODEL_ENC"); - if (!(str && *str)) { - str = udev_device_get_property_value(dev, "ID_MODEL"); - } else { - char *t = alloca(strlen(str) + 1); - unescape(str, t); - str = t; - } + str = udev_device_get_property_value(dev, "ID_MODEL"); + if (!(str && *str)) + str = udev_device_get_property_value(dev, "ID_V4L_PRODUCT"); + } else { + char *t = alloca(strlen(str) + 1); + unescape(str, t); + str = t; } } if (str && *str)
View file
pipewire-0.3.43.tar.gz/spa/plugins/volume/volume.c -> pipewire-0.3.44.tar.gz/spa/plugins/volume/volume.c
Changed
@@ -53,7 +53,6 @@ props->mute = DEFAULT_MUTE; } -#define MAX_SAMPLES 8192 #define MAX_BUFFERS 16 struct buffer { @@ -90,6 +89,7 @@ struct spa_node node; struct spa_log *log; + uint32_t quantum_limit; uint64_t info_all; struct spa_node_info info; @@ -386,7 +386,7 @@ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - MAX_SAMPLES * this->bpf, + this->quantum_limit * this->bpf, 16 * this->bpf, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->bpf)); @@ -777,6 +777,7 @@ { struct impl *this; struct port *port; + uint32_t i; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -788,6 +789,13 @@ this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + for (i = 0; info && i < info->n_items; i++) { + const char *k = info->items[i].key; + const char *s = info->items[i].value; + if (spa_streq(k, "clock.quantum-limit")) + spa_atou32(s, &this->quantum_limit, 0); + } + spa_hook_list_init(&this->hooks); this->node.iface = SPA_INTERFACE_INIT(
View file
pipewire-0.3.43.tar.gz/spa/tests/meson.build -> pipewire-0.3.44.tar.gz/spa/tests/meson.build
Changed
@@ -9,15 +9,16 @@ '-name', '*.h', '-not', '-name', 'type-info.h', '-type', 'f', - '-printf', '%P\n') + '-printf', '%P\n', + check: false) foreach spa_header : spa_headers.stdout().split('\n') if spa_header.endswith('.h') # skip empty lines ext = have_cpp ? 'cpp' : 'c' - c = configuration_data() - c.set('INCLUDE', spa_header) src = configure_file(input: 'spa-include-test-template.c', - output: 'spa-include-test-@0@.@1@'.format(spa_header.underscorify(), ext), - configuration: c) + output: 'spa-include-test-@0@.@1@'.format(spa_header.underscorify(), ext), + configuration: { + 'INCLUDE': spa_header, + }) executable('spa-include-test-@0@'.format(spa_header.underscorify()), src, dependencies: [ spa_dep ], @@ -40,7 +41,7 @@ install_dir : installed_tests_execdir, ), env : [ - 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')), + 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')), ] )
View file
pipewire-0.3.43.tar.gz/spa/tests/stress-ringbuffer.c -> pipewire-0.3.44.tar.gz/spa/tests/stress-ringbuffer.c
Changed
@@ -13,7 +13,8 @@ #ifdef __FreeBSD__ #include <sys/param.h> -#if __FreeBSD_version < 1400043 +#if (__FreeBSD_version >= 1400000 && __FreeBSD_version < 1400043) \ + || (__FreeBSD_version < 1300523) static int sched_getcpu(void) { return -1; }; #endif #endif
View file
pipewire-0.3.43.tar.gz/src/daemon/client-rt.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/client-rt.conf.in
Changed
@@ -9,6 +9,8 @@ #mem.allow-mlock = true #mem.mlock-all = false log.level = 0 + + #default.clock.quantum-limit = 8192 } context.spa-libs = { @@ -32,13 +34,12 @@ # If ifexists is given, the module is ignored when it is not found. # If nofail is given, module initialization failures are ignored. # - # Uses RTKit to boost the data thread priority. - { name = libpipewire-module-rtkit + # Uses realtime scheduling to boost the audio thread priorities + { name = libpipewire-module-rt args = { - #nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] } @@ -75,7 +76,7 @@ #node.latency = 1024/48000 #node.autoconnect = true #resample.quality = 4 - #channelmix.normalize = false + #channelmix.normalize = true #channelmix.mix-lfe = true #channelmix.upmix = false #channelmix.lfe-cutoff = 0
View file
pipewire-0.3.43.tar.gz/src/daemon/client.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/client.conf.in
Changed
@@ -9,6 +9,8 @@ #mem.allow-mlock = true #mem.mlock-all = false log.level = 0 + + #default.clock.quantum-limit = 8192 } context.spa-libs = { @@ -65,7 +67,7 @@ #node.latency = 1024/48000 #node.autoconnect = true #resample.quality = 4 - #channelmix.normalize = false + #channelmix.normalize = true #channelmix.mix-lfe = false #channelmix.upmix = false #channelmix.lfe-cutoff = 0
View file
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/demonic.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/demonic.conf
Changed
@@ -19,13 +19,12 @@ } context.modules = [ - # Uses RTKit to boost the data thread priority. - { name = libpipewire-module-rtkit + # Uses realtime scheduling to boost the audio thread priorities + { name = libpipewire-module-rt args = { - #nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] }
View file
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-dolby-surround.conf
Changed
@@ -12,12 +12,11 @@ } context.modules = [ - { name = libpipewire-module-rtkit + { name = libpipewire-module-rt args = { - #nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] }
View file
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-eq6.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-eq6.conf
Changed
@@ -12,12 +12,11 @@ } context.modules = [ - { name = libpipewire-module-rtkit + { name = libpipewire-module-rt args = { - #nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] }
View file
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-matrix-spatialiser.conf
Changed
@@ -13,12 +13,11 @@ } context.modules = [ - { name = libpipewire-module-rtkit + { name = libpipewire-module-rt args = { - #nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] }
View file
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-virtual-surround-5.1-kemar.conf
Changed
@@ -12,12 +12,11 @@ } context.modules = [ - { name = libpipewire-module-rtkit + { name = libpipewire-module-rt args = { - #nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] }
View file
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf
Changed
@@ -12,12 +12,11 @@ } context.modules = [ - { name = libpipewire-module-rtkit + { name = libpipewire-module-rt args = { - #nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] }
View file
pipewire-0.3.43.tar.gz/src/daemon/filter-chain/source-rnnoise.conf -> pipewire-0.3.44.tar.gz/src/daemon/filter-chain/source-rnnoise.conf
Changed
@@ -12,12 +12,11 @@ } context.modules = [ - { name = libpipewire-module-rtkit + { name = libpipewire-module-rt args = { - #nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] }
View file
pipewire-0.3.43.tar.gz/src/daemon/jack.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/jack.conf.in
Changed
@@ -9,6 +9,8 @@ #mem.allow-mlock = true #mem.mlock-all = false log.level = 0 + + #default.clock.quantum-limit = 8192 } context.spa-libs = { @@ -35,10 +37,9 @@ # Boost the data thread priority. { name = libpipewire-module-rt args = { - #nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] }
View file
pipewire-0.3.43.tar.gz/src/daemon/meson.build -> pipewire-0.3.44.tar.gz/src/daemon/meson.build
Changed
@@ -68,6 +68,7 @@ 'client.conf', 'client-rt.conf', 'jack.conf', + 'minimal.conf', 'pipewire-pulse.conf', ]
View file
pipewire-0.3.44.tar.gz/src/daemon/minimal.conf.in
Added
@@ -0,0 +1,297 @@ +# Simple daemon 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. + +context.properties = { + ## Configure properties in the system. + #library.name.system = support/libspa-support + #context.data-loop.library.name.system = support/libspa-support + #support.dbus = true + #link.max-buffers = 64 + link.max-buffers = 16 # version < 3 clients can't handle more + #mem.warn-mlock = false + #mem.allow-mlock = true + #mem.mlock-all = false + #clock.power-of-two-quantum = true + #log.level = 2 + #cpu.zero.denormals = true + + core.daemon = true # listening for socket connections + core.name = pipewire-0 # core name and socket name + + ## Properties for the DSP configuration. + #default.clock.rate = 48000 + #default.clock.allowed-rates = [ 48000 ] + #default.clock.quantum = 1024 + #default.clock.min-quantum = 32 + #default.clock.max-quantum = 2048 + #default.clock.quantum-limit = 8192 + #default.video.width = 640 + #default.video.height = 480 + #default.video.rate.num = 25 + #default.video.rate.denom = 1 + # + settings.check-quantum = true + settings.check-rate = true + # + # These overrides are only applied when running in a vm. + vm.overrides = { + default.clock.min-quantum = 1024 + } +} + +context.spa-libs = { + #<factory-name regex> = <library-name> + # + # Used to find spa factory names. It maps an spa factory name + # regular expression to a library name that should contain + # that factory. + # + audio.convert.* = audioconvert/libspa-audioconvert + api.alsa.* = alsa/libspa-alsa + support.* = support/libspa-support +} + +context.modules = [ + #{ name = <module-name> + # [ args = { <key> = <value> ... } ] + # [ flags = [ [ ifexists ] [ nofail ] ] + #} + # + # 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. + # + + # Uses realtime scheduling to boost the audio thread priorities. This uses + # RTKit if the user doesn't have permission to use regular realtime + # scheduling. + { name = libpipewire-module-rt + args = { + nice.level = -11 + #rt.prio = 88 + #rt.time.soft = -1 + #rt.time.hard = -1 + } + flags = [ ifexists nofail ] + } + + # The native communication protocol. + { name = libpipewire-module-protocol-native } + + # The profile module. Allows application to access profiler + # and performance data. It provides an interface that is used + # by pw-top and pw-profiler. + { name = libpipewire-module-profiler } + + # Allows applications to create metadata objects. It creates + # a factory for Metadata objects. + { name = libpipewire-module-metadata } + + # Creates a factory for making nodes that run in the + # context of the PipeWire server. + { name = libpipewire-module-spa-node-factory } + + # Allows creating nodes that run in the context of the + # client. Is used by all clients that want to provide + # data to PipeWire. + { name = libpipewire-module-client-node } + + # The access module can perform access checks and block + # new clients. + { name = libpipewire-module-access + args = { + # access.allowed to list an array of paths of allowed + # apps. + #access.allowed = [ + # @session_manager_path@ + #] + + # An array of rejected paths. + #access.rejected = [ ] + + # An array of paths with restricted access. + #access.restricted = [ ] + + # Anything not in the above lists gets assigned the + # access.force permission. + #access.force = flatpak + } + } + + # Makes a factory for wrapping nodes in an adapter with a + # converter and resampler. + { name = libpipewire-module-adapter } + + # Makes a factory for creating links between ports. + { name = libpipewire-module-link-factory } +] + +context.objects = [ + #{ factory = <factory-name> + # [ args = { <key> = <value> ... } ] + # [ flags = [ [ nofail ] ] + #} + # + # Creates an object from a PipeWire factory with the given parameters. + # If nofail is given, errors are ignored (and no object is created). + # + #{ 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 ] } + #{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } } + #{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } } + #{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test } } + #{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } } + + # Make a default metadata store + { factory = metadata args = { metadata.name = default } } + + # A default dummy driver. This handles nodes marked with the "node.always-driver" + # property when no other driver is currently active. JACK clients need this. + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = Dummy-Driver + node.group = pipewire.dummy + priority.driver = 20000 + } + } + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = Freewheel-Driver + priority.driver = 19000 + node.group = pipewire.freewheel + node.freewheel = true + } + } + + # This creates a single PCM source device for the given + # alsa device path hw:0. You can change source to sink + # to make a sink in the same way. + { factory = adapter + args = { + factory.name = api.alsa.pcm.source + node.name = "system" + node.description = "system" + media.class = "Audio/Source" + api.alsa.path = "hw:0" + #api.alsa.period-size = 0 + #api.alsa.period-num = 0 + #api.alsa.headroom = 0 + #api.alsa.start-delay = 0 + #api.alsa.disable-mmap = false + #api.alsa.disable-batch = false + #api.alsa.use-chmap = false + #api.alsa.multirate = true + #latency.internal.rate = 0 + #latency.internal.ns = 0 + #clock.name = api.alsa.0 + node.suspend-on-idle = true + #audio.format = "S32" + #audio.rate = 48000 + #audio.allowed-rates = [ ] + #audio.channels = 4 + #audio.position = [ FL FR RL RR ] + #resample.quality = 4 + resample.disable = true + #monitor.channel-volumes = false + #channelmix.normalize = true + #channelmix.mix-lfe = false + #channelmix.upmix = false + #channelmix.lfe-cutoff = 0 + channelmix.disable = true + #node.param.Props = { + # params = [ + # audio.channels 6 + # ] + #} + adapter.auto-port-config = { + mode = dsp + monitor = false + position = unknown # aux, preserve + } + #node.param.PortConfig = { + # direction = Output + # mode = dsp + # format = { + # mediaType = audio + # mediaSubtype = raw + # format = F32 + # rate = 48000 + # channels = 4 + # position = [ FL FR RL RR ] + # } + #} + } + } + { factory = adapter + args = { + factory.name = api.alsa.pcm.sink + node.name = "system" + node.description = "system" + media.class = "Audio/Sink" + api.alsa.path = "hw:0" + #api.alsa.period-size = 0 + #api.alsa.period-num = 0 + #api.alsa.headroom = 0 + #api.alsa.start-delay = 0 + #api.alsa.disable-mmap = false + #api.alsa.disable-batch = false + #api.alsa.use-chmap = false + #api.alsa.multirate = true + #latency.internal.rate = 0 + #latency.internal.ns = 0 + #clock.name = api.alsa.0 + node.suspend-on-idle = true + #audio.format = "S32" + #audio.rate = 48000 + #audio.allowed-rates = [ ] + #audio.channels = 2 + #audio.position = "FL,FR" + #resample.quality = 4 + resample.disable = true + #channelmix.normalize = true + #channelmix.mix-lfe = false + #channelmix.upmix = false + #channelmix.lfe-cutoff = 0 + channelmix.disable = true + #node.param.Props = { + # params = [ + # audio.format S16 + # ] + #} + adapter.auto-port-config = { + mode = dsp + monitor = false + position = unknown # aux, preserve + } + #node.param.PortConfig = { + # direction = Input + # mode = dsp + # monitor = true + # format = { + # mediaType = audio + # mediaSubtype = raw + # format = F32 + # rate = 48000 + # channels = 4 + # } + #} + } + } +] + +context.exec = [ + #{ path = <program-name> [ args = "<arguments>" ] } + # + # Execute the given program with arguments. + # + # You can optionally start the pulseaudio-server here as well + # but it is better to start it as a systemd service. + # It can be interesting to start another daemon here that listens + # on another address with the -a option (eg. -a tcp:4713). + # + #@pulse_comment@{ path = "@pipewire_path@" args = "-c pipewire-pulse.conf" } +]
View file
pipewire-0.3.43.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
@@ -9,6 +9,8 @@ #mem.allow-mlock = true #mem.mlock-all = false #log.level = 2 + + #default.clock.quantum-limit = 8192 } context.spa-libs = { @@ -17,12 +19,12 @@ } context.modules = [ - { name = libpipewire-module-rtkit + { name = libpipewire-module-rt args = { - #nice.level = -11 + nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] } @@ -42,7 +44,7 @@ #"tcp:127.0.0.1:8888" # IPv4 on a single address # #{ address = "tcp:4713" # address - # max-clients = 64 # maximume number of clients + # max-clients = 64 # maximum number of clients # listen-backlog = 32 # backlog in the server listen queue # client.access = "restricted" # permissions for clients #} @@ -73,8 +75,55 @@ #node.latency = 1024/48000 #node.autoconnect = true #resample.quality = 4 - #channelmix.normalize = false + #channelmix.normalize = true #channelmix.mix-lfe = false #channelmix.upmix = false #channelmix.lfe-cutoff = 0 } + +# client/stream specific properties +pulse.rules = [ + { + matches = [ + { + # all keys must match the value. ~ starts regex. + #client.name = "Firefox" + #application.process.binary = "teams" + #application.name = "~speech-dispatcher.*" + } + ] + actions = { + update-props = { + #node.latency = 512/48000 + } + # Possible quirks:" + # force-s16-info forces sink and source info as S16 format + # remove-capture-dont-move removes the capture DONT_MOVE flag + #quirks = [ ] + } + } + { + # skype does not want to use devices that don't have an S16 sample format. + matches = [ + { application.process.binary = "teams" } + { application.process.binary = "skypeforlinux" } + ] + actions = { quirks = [ force-s16-info ] } + } + { + # firefox marks the capture streams as don't move and then they + # can't be moved with pavucontrol or other tools. + matches = [ { application.process.binary = "firefox" } ] + actions = { quirks = [ remove-capture-dont-move ] } + } + { + # speech dispatcher asks for too small latency and then underruns. + matches = [ { application.name = "~speech-dispatcher*" } ] + actions = { + update-props = { + pulse.min.req = 1024/48000 # 21ms + pulse.min.quantum = 1024/48000 # 21ms + } + } + } +]
View file
pipewire-0.3.43.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.44.tar.gz/src/daemon/pipewire.conf.in
Changed
@@ -25,12 +25,16 @@ #default.clock.allowed-rates = [ 48000 ] #default.clock.quantum = 1024 #default.clock.min-quantum = 32 - #default.clock.max-quantum = 8192 + #default.clock.max-quantum = 2048 + #default.clock.quantum-limit = 8192 #default.video.width = 640 #default.video.height = 480 #default.video.rate.num = 25 #default.video.rate.denom = 1 # + #settings.check-quantum = false + #settings.check-rate = false + # # These overrides are only applied when running in a vm. vm.overrides = { default.clock.min-quantum = 1024 @@ -67,28 +71,19 @@ # If nofail is given, module initialization failures are ignored. # - # Uses RTKit to boost the data thread priority. - { name = libpipewire-module-rtkit + # Uses realtime scheduling to boost the audio thread priorities. This uses + # RTKit if the user doesn't have permission to use regular realtime + # scheduling. + { name = libpipewire-module-rt args = { - #nice.level = -11 + nice.level = -11 #rt.prio = 88 - #rt.time.soft = 2000000 - #rt.time.hard = 2000000 + #rt.time.soft = -1 + #rt.time.hard = -1 } flags = [ ifexists nofail ] } - # Set thread priorities without using RTKit. - #{ name = libpipewire-module-rt - # args = { - # nice.level = -11 - # rt.prio = 88 - # rt.time.soft = 2000000 - # rt.time.hard = 2000000 - # } - # flags = [ ifexists nofail ] - #} - # The native communication protocol. { name = libpipewire-module-protocol-native } @@ -156,6 +151,16 @@ # Provides factories to make session manager objects. { name = libpipewire-module-session-manager } + + # Use libcanberra to play X11 Bell + #{ name = libpipewire-module-x11-bell + # args = { + # #sink.name = "@DEFAULT_SINK@" + # #sample.name = "bell-window-system" + # #x11.display = null + # #x11.xauthority = null + # } + #} ] context.objects = [
View file
pipewire-0.3.43.tar.gz/src/daemon/systemd/system/meson.build -> pipewire-0.3.44.tar.gz/src/daemon/systemd/system/meson.build
Changed
@@ -1,4 +1,7 @@ -systemd_system_services_dir = systemd.get_variable(pkgconfig: 'systemdsystemunitdir', pkgconfig_define : [ 'rootprefix', prefix]) +systemd_system_services_dir = systemd.get_variable('systemdsystemunitdir', pkgconfig_define : [ 'rootprefix', prefix]) +if get_option('systemd-system-unit-dir') != '' + systemd_system_services_dir = get_option('systemd-system-unit-dir') +endif install_data(sources : 'pipewire.socket', install_dir : systemd_system_services_dir)
View file
pipewire-0.3.43.tar.gz/src/daemon/systemd/user/meson.build -> pipewire-0.3.44.tar.gz/src/daemon/systemd/user/meson.build
Changed
@@ -1,4 +1,4 @@ -systemd_user_services_dir = systemd.get_variable(pkgconfig: 'systemduserunitdir', pkgconfig_define : [ 'prefix', prefix]) +systemd_user_services_dir = systemd.get_variable('systemduserunitdir', pkgconfig_define : [ 'prefix', prefix]) if get_option('systemd-user-unit-dir') != '' systemd_user_services_dir = get_option('systemd-user-unit-dir') endif
View file
pipewire-0.3.43.tar.gz/src/modules/meson.build -> pipewire-0.3.44.tar.gz/src/modules/meson.build
Changed
@@ -21,12 +21,12 @@ 'module-protocol-simple.c', 'module-pulse-tunnel.c', 'module-rt.c', - 'module-rtkit.c', 'module-raop-discover.c', 'module-session-manager.c', 'module-zeroconf-discover.c', 'module-roc-source.c', 'module-roc-sink.c', + 'module-x11-bell.c', ] pipewire_module_access = shared_library('pipewire-module-access', [ 'module-access.c' ], @@ -137,21 +137,18 @@ dependencies : [spa_dep, mathlib, dl_lib, pipewire_dep], ) -build_module_rt = build_machine.system() == 'linux' +build_module_rt = dbus_dep.found() if build_module_rt pipewire_module_rt = shared_library('pipewire-module-rt', [ 'module-rt.c' ], include_directories : [configinc], install : true, install_dir : modules_install_dir, install_rpath: modules_install_dir, - dependencies : [dl_lib, pipewire_dep], + dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep], ) -endif -summary({'rt': build_module_rt}, bool_yn: true, section: 'Optional Modules') - -build_module_rtkit = dbus_dep.found() -if build_module_rtkit -pipewire_module_rtkit = shared_library('pipewire-module-rtkit', [ 'module-rtkit.c' ], +# 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, @@ -159,7 +156,7 @@ dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep], ) endif -summary({'rtkit': build_module_rtkit}, bool_yn: true, section: 'Optional Modules') +summary({'rt': build_module_rt}, bool_yn: true, section: 'Optional Modules') build_module_portal = dbus_dep.found() if build_module_portal @@ -259,6 +256,7 @@ 'module-protocol-pulse/modules/module-switch-on-connect.c', 'module-protocol-pulse/modules/module-tunnel-sink.c', 'module-protocol-pulse/modules/module-tunnel-source.c', + 'module-protocol-pulse/modules/module-x11-bell.c', 'module-protocol-pulse/modules/module-zeroconf-discover.c', ] @@ -370,9 +368,9 @@ install_dir : installed_tests_execdir, ), env : [ - 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')), - 'PIPEWIRE_CONFIG_DIR=@0@'.format(pipewire_dep.get_variable(internal: 'confdatadir')), - 'PIPEWIRE_MODULE_DIR=@0@'.format(pipewire_dep.get_variable(internal: 'moduledir')), + 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')), + 'PIPEWIRE_CONFIG_DIR=@0@'.format(pipewire_dep.get_variable('confdatadir')), + 'PIPEWIRE_MODULE_DIR=@0@'.format(pipewire_dep.get_variable('moduledir')), ] ) @@ -488,3 +486,16 @@ 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, canberra_dep], +) +endif +summary({'x11-bell': build_module_x11_bell}, bool_yn: true, section: 'Optional Modules')
View file
pipewire-0.3.43.tar.gz/src/modules/module-adapter/adapter.c -> pipewire-0.3.44.tar.gz/src/modules/module-adapter/adapter.c
Changed
@@ -38,10 +38,15 @@ #include <spa/utils/string.h> #include <spa/utils/type-info.h> #include <spa/param/format.h> +#include <spa/param/audio/format.h> +#include <spa/param/audio/format-utils.h> #include <spa/param/format-utils.h> #include <spa/debug/types.h> +#include <spa/debug/pod.h> +#include <spa/utils/json-pod.h> #include "pipewire/pipewire.h" +#include "pipewire/private.h" #include "modules/spa/spa-node.h" @@ -170,6 +175,29 @@ .port_init = node_port_init, }; +static int handle_node_param(struct pw_impl_node *node, const char *key, const char *value) +{ + const struct spa_type_info *ti; + uint8_t buffer[1024]; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + struct spa_pod *pod; + int res; + + ti = spa_debug_type_find_short(spa_type_param, key); + if (ti == NULL) + return -ENOENT; + + if ((res = spa_json_to_pod(&b, 0, ti, value, strlen(value))) < 0) + return res; + + if ((pod = spa_pod_builder_deref(&b, 0)) == NULL) + return -ENOSPC; + + if ((res = pw_impl_node_set_param(node, ti->type, 0, pod)) < 0) + return res; + + return 0; +} static int find_format(struct pw_impl_node *node, enum pw_direction direction, uint32_t *media_type, uint32_t *media_subtype) @@ -201,6 +229,113 @@ return 0; } +static int do_auto_port_config(struct node *n, const char *str) +{ + uint32_t state = 0, i; + uint8_t buffer[4096]; + struct spa_pod_builder b; +#define POSITION_PRESERVE 0 +#define POSITION_AUX 1 +#define POSITION_UNKNOWN 2 + int res, position = POSITION_PRESERVE; + struct spa_pod *param; + uint32_t media_type, media_subtype; + bool have_format = false, monitor = false; + struct spa_audio_info format = { 0, }; + enum spa_param_port_config_mode mode = SPA_PARAM_PORT_CONFIG_MODE_none; + struct spa_json it[2]; + char key[1024], val[256]; + + spa_json_init(&it[0], str, strlen(str)); + if (spa_json_enter_object(&it[0], &it[1]) <= 0) + return -EINVAL; + + while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { + if (spa_json_get_string(&it[1], val, sizeof(val)) <= 0) + break; + + if (spa_streq(key, "mode")) { + mode = spa_debug_type_find_type_short(spa_type_param_port_config_mode, val); + if (mode == SPA_ID_INVALID) + mode = SPA_PARAM_PORT_CONFIG_MODE_none; + } else if (spa_streq(key, "monitor")) { + monitor = spa_atob(val); + } else if (spa_streq(key, "position")) { + if (spa_streq(val, "unknown")) + position = POSITION_UNKNOWN; + else if (spa_streq(val, "aux")) + position = POSITION_AUX; + else + position = POSITION_PRESERVE; + } + } + + while (true) { + struct spa_audio_info info = { 0, }; + struct spa_pod *position = NULL; + uint32_t n_position = 0; + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + if ((res = spa_node_port_enum_params_sync(pw_impl_node_get_implementation(n->follower), + n->direction == PW_DIRECTION_INPUT ? + SPA_DIRECTION_INPUT : + SPA_DIRECTION_OUTPUT, 0, + SPA_PARAM_EnumFormat, &state, + NULL, ¶m, &b)) != 1) + break; + + if ((res = spa_format_parse(param, &media_type, &media_subtype)) < 0) + continue; + + if (media_type != SPA_MEDIA_TYPE_audio || + media_subtype != SPA_MEDIA_SUBTYPE_raw) + continue; + + spa_pod_object_fixate((struct spa_pod_object*)param); + + if (spa_pod_parse_object(param, + SPA_TYPE_OBJECT_Format, NULL, + SPA_FORMAT_AUDIO_format, SPA_POD_Id(&info.info.raw.format), + SPA_FORMAT_AUDIO_rate, SPA_POD_Int(&info.info.raw.rate), + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(&info.info.raw.channels), + SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position)) < 0) + continue; + + if (position != NULL) + n_position = spa_pod_copy_array(position, SPA_TYPE_Id, + info.info.raw.position, SPA_AUDIO_MAX_CHANNELS); + if (n_position == 0 || n_position != info.info.raw.channels) + SPA_FLAG_SET(info.info.raw.flags, SPA_AUDIO_FLAG_UNPOSITIONED); + + if (format.info.raw.channels >= info.info.raw.channels) + continue; + + format = info; + have_format = true; + } + if (!have_format) + return -ENOENT; + + if (position == POSITION_AUX) { + for (i = 0; i < format.info.raw.channels; i++) + format.info.raw.position[i] = SPA_AUDIO_CHANNEL_START_Aux + i; + } else if (position == POSITION_UNKNOWN) { + for (i = 0; i < format.info.raw.channels; i++) + format.info.raw.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN; + } + + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + param = spa_format_audio_raw_build(&b, SPA_PARAM_Format, &format.info.raw); + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, + SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(n->direction), + SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(mode), + SPA_PARAM_PORT_CONFIG_monitor, SPA_POD_Bool(monitor), + SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param)); + pw_impl_node_set_param(n->node, SPA_PARAM_PortConfig, 0, param); + + return 0; +} struct pw_impl_node *pw_adapter_new(struct pw_context *context, struct pw_impl_node *follower, @@ -214,6 +349,8 @@ enum pw_direction direction; int res; uint32_t media_type, media_subtype; + const struct spa_dict_item *it; + struct pw_properties *copy; info = pw_impl_node_get_info(follower); if (info == NULL) { @@ -272,11 +409,16 @@ goto error; } + copy = pw_properties_new(NULL, NULL); + spa_dict_for_each(it, &props->dict) { + if (!spa_strstartswith(it->key, "node.param.") && + !spa_strstartswith(it->key, "port.param.")) + pw_properties_set(copy, it->key, it->value); + } node = pw_spa_node_load(context, factory_name, PW_SPA_NODE_FLAG_ACTIVATE | PW_SPA_NODE_FLAG_NO_REGISTER, - pw_properties_copy(props), - sizeof(struct node) + user_data_size); + copy, sizeof(struct node) + user_data_size); if (node == NULL) { res = -errno; pw_log_error("can't load spa node: %m"); @@ -298,6 +440,15 @@ pw_impl_node_add_listener(node, &n->node_listener, &node_events, n); + if ((str = pw_properties_get(props, "adapter.auto-port-config")) != NULL) + do_auto_port_config(n, str); + + spa_dict_for_each(it, &props->dict) { + if (spa_strstartswith(it->key, "node.param.")) { + if ((res = handle_node_param(node, &it->key[11], it->value)) < 0) + pw_log_warn("can't set node param: %s", spa_strerror(res)); + } + } return node; error:
View file
pipewire-0.3.43.tar.gz/src/modules/module-client-node/client-node.c -> pipewire-0.3.44.tar.gz/src/modules/module-client-node/client-node.c
Changed
@@ -219,6 +219,8 @@ if (mix_id >= len) { size_t need = sizeof(struct mix) * (mix_id + 1 - len); void *ptr = pw_array_add(&p->mix, need); + if (ptr == NULL) + return NULL; memset(ptr, 0, need); } mix = pw_array_get_unchecked(&p->mix, mix_id, struct mix); @@ -1388,8 +1390,15 @@ return -ENOMEM; mix->id = pw_map_insert_new(&impl->io_map, NULL); - if (mix->id == SPA_ID_INVALID) + if (mix->id == SPA_ID_INVALID) { + m->valid = false; return -errno; + } + if (mix->id > MAX_AREAS) { + pw_map_remove(&impl->io_map, mix->id); + m->valid = false; + return -ENOMEM; + } mix->io = SPA_PTROFF(impl->io_areas->map->ptr, mix->id * sizeof(struct spa_io_buffers), void);
View file
pipewire-0.3.43.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.44.tar.gz/src/modules/module-echo-cancel.c
Changed
@@ -109,6 +109,15 @@ * */ +/** + * .--------. .---------. .--------. .----------. .-------. + * | source | --> | capture | --> | | --> | source | --> | app | + * '--------' '---------' | echo | '----------' '-------' + * | cancel | + * .--------. .---------. | | .----------. .--------. + * | app | --> | sink | --> | | --> | playback | --> | sink | + * '--------' '---------' '--------' '----------' '--------' + */ #define NAME "echo-cancel" PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); @@ -117,6 +126,7 @@ /* Hopefully this is enough for any combination of AEC engine and resampler * input requirement for rate matching */ #define MAX_BUFSIZE_MS 100 +#define DELAY_MS 0 static const struct spa_dict_item module_props[] = { { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, @@ -126,6 +136,8 @@ "[ audio.rate=<sample rate> ] " "[ audio.channels=<number of channels> ] " "[ audio.position=<channel map> ] " + "[ buffer.max_size=<max buffer size in ms> ] " + "[ buffer.play_delay=<play delay in ms> ] " "[ aec.method=<aec method> ] " "[ aec.args=<aec arguments> ] " "[ source.props=<properties> ] " @@ -166,6 +178,7 @@ void *play_buffer[SPA_AUDIO_MAX_CHANNELS]; uint32_t play_ringsize; struct spa_ringbuffer play_ring; + struct spa_ringbuffer play_delayed_ring; struct spa_io_rate_match *play_rate_match; void *out_buffer[SPA_AUDIO_MAX_CHANNELS]; @@ -181,6 +194,9 @@ unsigned int do_disconnect:1; unsigned int unloading:1; + + uint32_t max_buffer_size; + uint32_t buffer_delay; }; static void do_unload_module(void *obj, void *data, int res, uint32_t id) @@ -202,13 +218,15 @@ struct pw_buffer *pout; float rec_buf[impl->info.channels][impl->aec_blocksize / sizeof(float)]; float play_buf[impl->info.channels][impl->aec_blocksize / sizeof(float)]; + float play_delayed_buf[impl->info.channels][impl->aec_blocksize / sizeof(float)]; float out_buf[impl->info.channels][impl->aec_blocksize / sizeof(float)]; const float *rec[impl->info.channels]; const float *play[impl->info.channels]; + const float *play_delayed[impl->info.channels]; float *out[impl->info.channels]; struct spa_data *dd; uint32_t i, size; - uint32_t rindex, pindex, oindex, avail; + uint32_t rindex, pindex, oindex, pdindex, avail; int32_t stride = 0; if ((pout = pw_stream_dequeue_buffer(impl->playback)) == NULL) { @@ -222,12 +240,15 @@ spa_ringbuffer_get_read_index(&impl->rec_ring, &rindex); spa_ringbuffer_get_read_index(&impl->play_ring, &pindex); + spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex); for (i = 0; i < impl->info.channels; i++) { /* captured samples, with echo from sink */ rec[i] = &rec_buf[i][0]; /* echo from sink */ play[i] = &play_buf[i][0]; + /* echo from sink delayed */ + play_delayed[i] = &play_delayed_buf[i][0]; /* filtered samples, without echo from sink */ out[i] = &out_buf[i][0]; @@ -241,6 +262,11 @@ impl->play_ringsize, pindex % impl->play_ringsize, (void *)play[i], size); + stride = 0; + spa_ringbuffer_read_data(&impl->play_delayed_ring, impl->play_buffer[i], + impl->play_ringsize, pdindex % impl->play_ringsize, + (void *)play_delayed[i], size); + /* output to sink, just copy */ dd = &pout->buffer->datas[i]; memcpy(dd->data, play[i], size); @@ -252,11 +278,12 @@ spa_ringbuffer_read_update(&impl->rec_ring, rindex + size); spa_ringbuffer_read_update(&impl->play_ring, pindex + size); + spa_ringbuffer_read_update(&impl->play_delayed_ring, pdindex + size); pw_stream_queue_buffer(impl->playback, pout); /* Now run the canceller */ - echo_cancel_run(impl->aec_info, impl->aec, rec, play, out, size / sizeof(float)); + echo_cancel_run(impl->aec_info, impl->aec, rec, play_delayed, out, size / sizeof(float)); /* Next, copy over the output to the output ringbuffer */ avail = spa_ringbuffer_get_write_index(&impl->out_ring, &oindex); @@ -544,6 +571,9 @@ spa_ringbuffer_get_read_index(&impl->play_ring, &rindex); spa_ringbuffer_read_update(&impl->play_ring, rindex + drop); + spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &rindex); + spa_ringbuffer_read_update(&impl->play_delayed_ring, rindex + drop); + avail += drop; } @@ -604,6 +634,7 @@ struct spa_pod_builder b; struct pw_properties *props; const char *str; + uint32_t index; props = pw_properties_new( PW_KEY_NODE_NAME, "echo-cancel-capture", @@ -710,9 +741,9 @@ params, n_params)) < 0) return res; - impl->rec_ringsize = sizeof(float) * MAX_BUFSIZE_MS * impl->info.rate / 1000; - impl->play_ringsize = sizeof(float) * MAX_BUFSIZE_MS * impl->info.rate / 1000; - impl->out_ringsize = sizeof(float) * MAX_BUFSIZE_MS * impl->info.rate / 1000; + impl->rec_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000; + impl->play_ringsize = sizeof(float) * (impl->max_buffer_size + impl->buffer_delay) * impl->info.rate / 1000; + impl->out_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000; for (i = 0; i < impl->info.channels; i++) { impl->rec_buffer[i] = malloc(impl->rec_ringsize); impl->play_buffer[i] = malloc(impl->play_ringsize); @@ -720,8 +751,14 @@ } spa_ringbuffer_init(&impl->rec_ring); spa_ringbuffer_init(&impl->play_ring); + spa_ringbuffer_init(&impl->play_delayed_ring); spa_ringbuffer_init(&impl->out_ring); + spa_ringbuffer_get_write_index(&impl->play_ring, &index); + spa_ringbuffer_write_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay) * impl->info.rate / 1000)); + spa_ringbuffer_get_read_index(&impl->play_ring, &index); + spa_ringbuffer_read_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay) * impl->info.rate / 1000)); + return 0; } @@ -997,6 +1034,9 @@ copy_props(impl, props, PW_KEY_NODE_VIRTUAL); copy_props(impl, props, PW_KEY_NODE_LATENCY); + impl->max_buffer_size = pw_properties_get_uint32(props,"buffer.max_size", MAX_BUFSIZE_MS); + impl->buffer_delay = pw_properties_get_uint32(props,"buffer.play_delay", DELAY_MS); + pw_properties_free(props); pw_proxy_add_listener((struct pw_proxy*)impl->core,
View file
pipewire-0.3.43.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.44.tar.gz/src/modules/module-filter-chain.c
Changed
@@ -343,7 +343,7 @@ char *col, *node_name, *port_name, *str; struct port *ports; const struct fc_descriptor *d; - uint32_t i, n_ports; + uint32_t i, n_ports, port_id = SPA_ID_INVALID; str = strdupa(name); col = strchr(str, ':'); @@ -359,6 +359,9 @@ if (node == NULL) return NULL; + if (!spa_atou32(port_name, &port_id, 0)) + port_id = SPA_ID_INVALID; + if (FC_IS_PORT_INPUT(descriptor)) { if (FC_IS_PORT_CONTROL(descriptor)) { ports = node->control_port; @@ -381,7 +384,8 @@ d = node->desc->desc; for (i = 0; i < n_ports; i++) { struct port *port = &ports[i]; - if (spa_streq(d->ports[port->p].name, port_name)) + if (i == port_id || + spa_streq(d->ports[port->p].name, port_name)) return port; } return NULL; @@ -1701,11 +1705,8 @@ if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL) pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); - if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL) - pw_properties_setf(props, PW_KEY_NODE_NAME, "filter-chain-%u", id); if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL) - pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, - pw_properties_get(props, PW_KEY_NODE_NAME)); + pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "filter-chain-%u", id); if ((str = pw_properties_get(props, "capture.props")) != NULL) pw_properties_update_string(impl->capture_props, str, strlen(str)); @@ -1715,7 +1716,6 @@ copy_props(impl, props, PW_KEY_AUDIO_RATE); copy_props(impl, props, PW_KEY_AUDIO_CHANNELS); copy_props(impl, props, SPA_KEY_AUDIO_POSITION); - copy_props(impl, props, PW_KEY_NODE_NAME); copy_props(impl, props, PW_KEY_NODE_DESCRIPTION); copy_props(impl, props, PW_KEY_NODE_GROUP); copy_props(impl, props, PW_KEY_NODE_LINK_GROUP); @@ -1726,18 +1726,25 @@ parse_audio_info(impl->capture_props, &impl->capture_info); parse_audio_info(impl->playback_props, &impl->playback_info); + if (pw_properties_get(impl->capture_props, PW_KEY_NODE_NAME) == NULL) + pw_properties_setf(impl->capture_props, PW_KEY_NODE_NAME, + "input.filter-chain-%u", id); + if (pw_properties_get(impl->playback_props, PW_KEY_NODE_NAME) == NULL) + pw_properties_setf(impl->playback_props, PW_KEY_NODE_NAME, + "output.filter-chain-%u", id); + + if (pw_properties_get(impl->capture_props, PW_KEY_MEDIA_NAME) == NULL) + pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME, "%s input", + pw_properties_get(impl->capture_props, PW_KEY_NODE_DESCRIPTION)); + if (pw_properties_get(impl->playback_props, PW_KEY_MEDIA_NAME) == NULL) + pw_properties_setf(impl->playback_props, PW_KEY_MEDIA_NAME, "%s output", + pw_properties_get(impl->playback_props, PW_KEY_NODE_DESCRIPTION)); + if ((res = load_graph(&impl->graph, props)) < 0) { pw_log_error("can't load graph: %s", spa_strerror(res)); goto error; } - if (pw_properties_get(impl->capture_props, PW_KEY_MEDIA_NAME) == NULL) - pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME, "filter input %s", - pw_properties_get(impl->capture_props, PW_KEY_NODE_NAME)); - if (pw_properties_get(impl->playback_props, PW_KEY_MEDIA_NAME) == NULL) - pw_properties_setf(impl->playback_props, PW_KEY_MEDIA_NAME, "filter output %s", - pw_properties_get(impl->playback_props, PW_KEY_NODE_NAME)); - impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core); if (impl->core == NULL) { str = pw_properties_get(props, PW_KEY_REMOTE_NAME);
View file
pipewire-0.3.43.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.44.tar.gz/src/modules/module-loopback.c
Changed
@@ -461,11 +461,9 @@ if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL) pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); - if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL) - pw_properties_setf(props, PW_KEY_NODE_NAME, "loopback-%u", id); if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL) - pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, - pw_properties_get(props, PW_KEY_NODE_NAME)); + pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, + "loopback-%u", id); if ((str = pw_properties_get(props, "capture.props")) != NULL) pw_properties_update_string(impl->capture_props, str, strlen(str)); @@ -475,25 +473,29 @@ copy_props(impl, props, PW_KEY_AUDIO_RATE); copy_props(impl, props, PW_KEY_AUDIO_CHANNELS); copy_props(impl, props, SPA_KEY_AUDIO_POSITION); - copy_props(impl, props, PW_KEY_NODE_NAME); copy_props(impl, props, PW_KEY_NODE_DESCRIPTION); copy_props(impl, props, PW_KEY_NODE_GROUP); copy_props(impl, props, PW_KEY_NODE_LINK_GROUP); copy_props(impl, props, PW_KEY_NODE_LATENCY); copy_props(impl, props, PW_KEY_NODE_VIRTUAL); + copy_props(impl, props, PW_KEY_MEDIA_NAME); + + if (pw_properties_get(impl->capture_props, PW_KEY_NODE_NAME) == NULL) + pw_properties_setf(impl->capture_props, PW_KEY_NODE_NAME, + "input.loopback-%u", id); + if (pw_properties_get(impl->playback_props, PW_KEY_NODE_NAME) == NULL) + pw_properties_setf(impl->playback_props, PW_KEY_NODE_NAME, + "output.loopback-%u", id); parse_audio_info(impl->capture_props, &impl->capture_info); parse_audio_info(impl->playback_props, &impl->playback_info); if (pw_properties_get(impl->capture_props, PW_KEY_MEDIA_NAME) == NULL) - pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME, - "loopback input %s", - pw_properties_get(impl->capture_props, PW_KEY_NODE_NAME)); - + pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME, "%s input", + pw_properties_get(impl->capture_props, PW_KEY_NODE_DESCRIPTION)); if (pw_properties_get(impl->playback_props, PW_KEY_MEDIA_NAME) == NULL) - pw_properties_setf(impl->playback_props, PW_KEY_MEDIA_NAME, - "loopback output %s", - pw_properties_get(impl->playback_props, PW_KEY_NODE_NAME)); + pw_properties_setf(impl->playback_props, PW_KEY_MEDIA_NAME, "%s output", + pw_properties_get(impl->playback_props, PW_KEY_NODE_DESCRIPTION)); impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core); if (impl->core == NULL) {
View file
pipewire-0.3.43.tar.gz/src/modules/module-metadata.c -> pipewire-0.3.44.tar.gz/src/modules/module-metadata.c
Changed
@@ -74,43 +74,70 @@ uint32_t new_id) { struct factory_data *data = _data; + struct pw_context *context = pw_impl_module_get_context(data->module); void *result; - struct pw_resource *metadata_resource; - struct pw_impl_client *client = pw_resource_get_client(resource); + struct pw_resource *metadata_resource = NULL; + struct pw_impl_client *client = resource ? pw_resource_get_client(resource) : NULL; int res; - metadata_resource = pw_resource_new(client, new_id, PW_PERM_ALL, type, version, 0); - if (metadata_resource == NULL) { - res = -errno; - goto error_resource; - } + if (properties == NULL) + properties = pw_properties_new(NULL, NULL); + if (properties == NULL) + return NULL; + + pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d", + pw_impl_factory_get_info(data->this)->id); + pw_properties_setf(properties, PW_KEY_MODULE_ID, "%d", + pw_impl_module_get_info(data->module)->id); + + if (pw_properties_get(properties, PW_KEY_METADATA_NAME) == NULL) + pw_properties_set(properties, PW_KEY_METADATA_NAME, "default"); + + if (client) { + metadata_resource = pw_resource_new(client, new_id, PW_PERM_ALL, type, version, 0); + if (metadata_resource == NULL) { + res = -errno; + goto error_resource; + } - if (properties) { - pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d", - pw_impl_factory_get_info(data->this)->id); pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d", pw_impl_client_get_info(client)->id); - } - result = pw_metadata_new(pw_impl_client_get_context(client), metadata_resource, properties); - if (result == NULL) { - res = -errno; - goto error_node; + result = pw_metadata_new(context, metadata_resource, properties); + if (result == NULL) { + properties = NULL; + res = -errno; + goto error_node; + } + } else { + result = pw_context_create_metadata(context, NULL, properties, 0); + if (result == NULL) { + properties = NULL; + res = -errno; + goto error_node; + } + pw_impl_metadata_register(result, NULL); } return result; error_resource: pw_log_error("can't create resource: %s", spa_strerror(res)); - pw_resource_errorf_id(resource, new_id, res, "can't create resource: %s", spa_strerror(res)); + if (resource) + pw_resource_errorf_id(resource, new_id, res, + "can't create resource: %s", spa_strerror(res)); goto error_exit; error_node: pw_log_error("can't create metadata: %s", spa_strerror(res)); - pw_resource_errorf_id(resource, new_id, res, "can't create metadata: %s", spa_strerror(res)); + if (resource) + pw_resource_errorf_id(resource, new_id, res, + "can't create metadata: %s", spa_strerror(res)); goto error_exit_free; error_exit_free: - pw_resource_remove(metadata_resource); + if (metadata_resource) + pw_resource_remove(metadata_resource); error_exit: + pw_properties_free(properties); errno = -res; return NULL; }
View file
pipewire-0.3.43.tar.gz/src/modules/module-metadata/metadata.c -> pipewire-0.3.44.tar.gz/src/modules/module-metadata/metadata.c
Changed
@@ -271,9 +271,6 @@ return NULL; } - if (pw_properties_get(properties, PW_KEY_METADATA_NAME) == NULL) - pw_properties_set(properties, PW_KEY_METADATA_NAME, "default"); - pw_resource_install_marshal(resource, true); impl->global = pw_global_new(context,
View file
pipewire-0.3.43.tar.gz/src/modules/module-profiler.c -> pipewire-0.3.44.tar.gz/src/modules/module-profiler.c
Changed
@@ -379,6 +379,10 @@ struct pw_properties *props; struct impl *impl; struct pw_loop *main_loop = pw_context_get_main_loop(context); + static const char * const keys[] = { + PW_KEY_OBJECT_SERIAL, + NULL + }; PW_LOG_TOPIC_INIT(mod_topic); @@ -409,9 +413,14 @@ free(impl); return -errno; } + pw_properties_setf(impl->properties, PW_KEY_OBJECT_ID, "%d", impl->global->id); + pw_properties_setf(impl->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64, + pw_global_get_serial(impl->global)); impl->flush_timeout = pw_loop_add_timer(main_loop, flush_timeout, impl); + pw_global_update_keys(impl->global, &impl->properties->dict, keys); + pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl); pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-native/connection.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-native/connection.c
Changed
@@ -175,10 +175,37 @@ pw_log_error("connection %p: could not recvmsg on fd:%d: %s", conn, conn->fd, strerror(res)); } +static size_t cmsg_data_length(const struct cmsghdr *cmsg) +{ + const void *begin = CMSG_DATA(cmsg); + const void *end = SPA_PTROFF(cmsg, cmsg->cmsg_len, void); + + spa_assert(begin <= end); + + return SPA_PTRDIFF(end, begin); +} + +static void close_all_fds(struct msghdr *msg, struct cmsghdr *from) +{ + for (; from != NULL; from = CMSG_NXTHDR(msg, from)) { + if (from->cmsg_level != SOL_SOCKET || from->cmsg_type != SCM_RIGHTS) + continue; + + size_t n_fds = cmsg_data_length(from) / sizeof(int); + for (size_t i = 0; i < n_fds; i++) { + const void *p = SPA_PTROFF(CMSG_DATA(from), sizeof(int) * i, void); + int fd; + + memcpy(&fd, p, sizeof(fd)); + close(fd); + } + } +} + static int refill_buffer(struct pw_protocol_native_connection *conn, struct buffer *buf) { ssize_t len; - struct cmsghdr *cmsg; + struct cmsghdr *cmsg = NULL; struct msghdr msg = { 0 }; struct iovec iov[1]; char cmsgbuf[CMSG_SPACE(MAX_FDS_MSG * sizeof(int))]; @@ -198,7 +225,7 @@ while (true) { len = recvmsg(conn->fd, &msg, msg.msg_flags); if (msg.msg_flags & MSG_CTRUNC) - return -EPROTO; + goto cmsgs_truncated; if (len == 0 && avail != 0) return -EPIPE; else if (len < 0) { @@ -218,10 +245,9 @@ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) continue; - n_fds = - (cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg)) / sizeof(int); + n_fds = cmsg_data_length(cmsg) / sizeof(int); if (n_fds + buf->n_fds > MAX_FDS) - return -EPROTO; + goto too_many_fds; memcpy(&buf->fds[buf->n_fds], CMSG_DATA(cmsg), n_fds * sizeof(int)); buf->n_fds += n_fds; } @@ -234,6 +260,14 @@ recv_error: handle_connection_error(conn, errno); return -errno; + +cmsgs_truncated: + close_all_fds(&msg, CMSG_FIRSTHDR(&msg)); + return -EPROTO; + +too_many_fds: + close_all_fds(&msg, cmsg); + return -EPROTO; } static void clear_buffer(struct buffer *buf, bool fds)
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/client.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/client.c
Changed
@@ -295,23 +295,34 @@ return 0; } -/* returns true if an event with the (mask, event, id) triplet should be dropped because it is redundant */ -static bool client_prune_subscribe_events(struct client *client, uint32_t mask, uint32_t event, uint32_t id) +static bool drop_from_out_queue(struct client *client, struct message *m) { - struct impl *impl = client->impl; - struct message *m, *t, *first; + spa_assert(!spa_list_is_empty(&client->out_messages)); - if ((event & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_NEW) + struct message *first = spa_list_first(&client->out_messages, struct message, link); + if (m == first && client->out_index > 0) return false; - first = spa_list_first(&client->out_messages, struct message, link); + message_free(client->impl, m, true, false); + + return true; +} + +/* returns true if an event with the (mask, event, index) triplet should be dropped because it is redundant */ +static bool client_prune_subscribe_events(struct client *client, uint32_t mask, uint32_t event, uint32_t index) +{ + struct message *m, *t; + + if ((event & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_NEW) + return false; + /* NOTE: reverse iteration */ spa_list_for_each_safe_reverse(m, t, &client->out_messages, link) { if (m->extra[0] != COMMAND_SUBSCRIBE_EVENT) continue; if ((m->extra[1] ^ event) & SUBSCRIPTION_EVENT_FACILITY_MASK) continue; - if (m->extra[2] != id) + if (m->extra[2] != index) continue; if ((event & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_REMOVE) { @@ -319,25 +330,39 @@ * point in keeping the old events regarding * entry in the queue. */ - /* if the first message has already been partially sent, do not drop it */ - if (m != first || client->out_index == 0) { - message_free(impl, m, true, false); - pw_log_debug("client %p: dropped redundant event due to remove event", client); + bool is_new = (m->extra[1] & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_NEW; + + if (drop_from_out_queue(client, m)) { + pw_log_debug("client %p: dropped redundant event due to remove event for object %u", + client, index); + + /* if the NEW event for the current object could successfully be dropped, + there is no need to deliver the REMOVE event */ + if (is_new) + goto drop; } + + /* stop if the NEW event for the current object is reached */ + if (is_new) + break; } if ((event & SUBSCRIPTION_EVENT_TYPE_MASK) == SUBSCRIPTION_EVENT_CHANGE) { /* This object has changed. If a "new" or "change" event for * this object is still in the queue we can exit. */ - pw_log_debug("client %p: dropped redundant event due to change event", client); - return true; + goto drop; } } return false; + +drop: + pw_log_debug("client %p: dropped redundant event for object %u", client, index); + + return true; } -int client_queue_subscribe_event(struct client *client, uint32_t mask, uint32_t event, uint32_t id) +int client_queue_subscribe_event(struct client *client, uint32_t mask, uint32_t event, uint32_t index) { if (client->disconnect) return -ENOTCONN; @@ -345,21 +370,21 @@ if (!(client->subscribed & mask)) return 0; - pw_log_debug("client %p: SUBSCRIBE event:%08x id:%u", client, event, id); + pw_log_debug("client %p: SUBSCRIBE event:%08x index:%u", client, event, index); - if (client_prune_subscribe_events(client, mask, event, id)) + if (client_prune_subscribe_events(client, mask, event, index)) return 0; struct message *reply = message_alloc(client->impl, -1, 0); reply->extra[0] = COMMAND_SUBSCRIBE_EVENT; reply->extra[1] = event; - reply->extra[2] = id; + reply->extra[2] = index; message_put(reply, TAG_U32, COMMAND_SUBSCRIBE_EVENT, TAG_U32, -1, TAG_U32, event, - TAG_U32, id, + TAG_U32, index, TAG_INVALID); return client_queue_message(client, reply);
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/collect.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/collect.c
Changed
@@ -58,19 +58,41 @@ continue; if (o->id == s->id) return o; + if (o->index == s->index) + return o; if (s->accumulate) s->accumulate(s, o); if (o->props && s->key != NULL && s->value != NULL && (str = pw_properties_get(o->props, s->key)) != NULL && spa_streq(str, s->value)) return o; - if (s->value != NULL && (uint32_t)atoi(s->value) == o->id) + if (s->value != NULL && (uint32_t)atoi(s->value) == o->index) return o; } return s->best; } -bool collect_is_linked(struct pw_manager *m, uint32_t obj_id, enum pw_direction direction) +uint32_t id_to_index(struct pw_manager *m, uint32_t id) +{ + struct pw_manager_object *o; + spa_list_for_each(o, &m->object_list, link) { + if (o->id == id) + return o->index; + } + return SPA_ID_INVALID; +} + +uint32_t index_to_id(struct pw_manager *m, uint32_t index) +{ + struct pw_manager_object *o; + spa_list_for_each(o, &m->object_list, link) { + if (o->index == index) + return o->id; + } + return SPA_ID_INVALID; +} + +bool collect_is_linked(struct pw_manager *m, uint32_t id, enum pw_direction direction) { struct pw_manager_object *o; uint32_t in_node, out_node; @@ -83,14 +105,14 @@ pw_properties_fetch_uint32(o->props, PW_KEY_LINK_INPUT_NODE, &in_node) != 0) continue; - if ((direction == PW_DIRECTION_OUTPUT && obj_id == out_node) || - (direction == PW_DIRECTION_INPUT && obj_id == in_node)) + if ((direction == PW_DIRECTION_OUTPUT && id == out_node) || + (direction == PW_DIRECTION_INPUT && id == in_node)) return true; } return false; } -struct pw_manager_object *find_linked(struct pw_manager *m, uint32_t obj_id, enum pw_direction direction) +struct pw_manager_object *find_linked(struct pw_manager *m, uint32_t id, enum pw_direction direction) { struct pw_manager_object *o, *p; uint32_t in_node, out_node; @@ -103,12 +125,12 @@ pw_properties_fetch_uint32(o->props, PW_KEY_LINK_INPUT_NODE, &in_node) != 0) continue; - if (direction == PW_DIRECTION_OUTPUT && obj_id == out_node) { + if (direction == PW_DIRECTION_OUTPUT && id == out_node) { struct selector sel = { .id = in_node, .type = pw_manager_object_is_sink, }; if ((p = select_object(m, &sel)) != NULL) return p; } - if (direction == PW_DIRECTION_INPUT && obj_id == in_node) { + if (direction == PW_DIRECTION_INPUT && id == in_node) { struct selector sel = { .id = out_node, .type = pw_manager_object_is_recordable, }; if ((p = select_object(m, &sel)) != NULL) return p; @@ -157,7 +179,7 @@ if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_ParamProfile, NULL, - SPA_PARAM_PROFILE_index, SPA_POD_Int(&pi->id), + SPA_PARAM_PROFILE_index, SPA_POD_Int(&pi->index), SPA_PARAM_PROFILE_name, SPA_POD_String(&pi->name), SPA_PARAM_PROFILE_description, SPA_POD_OPT_String(&pi->description), SPA_PARAM_PROFILE_priority, SPA_POD_OPT_Int(&pi->priority), @@ -167,7 +189,7 @@ } if (pi->description == NULL) pi->description = pi->name; - if (pi->id == card_info->active_profile) + if (pi->index == card_info->active_profile) card_info->active_profile_name = pi->name; if (classes != NULL) { @@ -198,12 +220,12 @@ return n; } -uint32_t find_profile_id(struct pw_manager_object *card, const char *name) +uint32_t find_profile_index(struct pw_manager_object *card, const char *name) { struct pw_manager_param *p; spa_list_for_each(p, &card->param_list, link) { - uint32_t id; + uint32_t index; const char *test_name; if (p->id != SPA_PARAM_EnumProfile) @@ -211,12 +233,12 @@ if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_ParamProfile, NULL, - SPA_PARAM_PROFILE_index, SPA_POD_Int(&id), + SPA_PARAM_PROFILE_index, SPA_POD_Int(&index), SPA_PARAM_PROFILE_name, SPA_POD_String(&test_name)) < 0) continue; if (spa_streq(test_name, name)) - return id; + return index; } return SPA_ID_INVALID; @@ -229,7 +251,7 @@ if (card && !monitor) { spa_list_for_each(p, &card->param_list, link) { - uint32_t id, dev; + uint32_t index, dev; struct spa_pod *props; if (p->id != SPA_PARAM_Route) @@ -237,13 +259,13 @@ if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_ParamRoute, NULL, - SPA_PARAM_ROUTE_index, SPA_POD_Int(&id), + SPA_PARAM_ROUTE_index, SPA_POD_Int(&index), SPA_PARAM_ROUTE_device, SPA_POD_Int(&dev), SPA_PARAM_ROUTE_props, SPA_POD_OPT_Pod(&props)) < 0) continue; if (dev != dev_info->device) continue; - dev_info->active_port = id; + dev_info->active_port = index; if (props) { volume_parse_param(props, &dev_info->volume_info, monitor); dev_info->have_volume = true; @@ -316,7 +338,7 @@ if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_ParamRoute, NULL, - SPA_PARAM_ROUTE_index, SPA_POD_Int(&pi->id), + SPA_PARAM_ROUTE_index, SPA_POD_Int(&pi->index), SPA_PARAM_ROUTE_direction, SPA_POD_Id(&pi->direction), SPA_PARAM_ROUTE_name, SPA_POD_String(&pi->name), SPA_PARAM_ROUTE_description, SPA_POD_OPT_String(&pi->description), @@ -341,7 +363,7 @@ continue; if (!array_contains(pi->devices, pi->n_devices, dev_info->device)) continue; - if (pi->id == dev_info->active_port) + if (pi->index == dev_info->active_port) dev_info->active_port_name = pi->name; } @@ -377,12 +399,12 @@ return n; } -uint32_t find_port_id(struct pw_manager_object *card, uint32_t direction, const char *port_name) +uint32_t find_port_index(struct pw_manager_object *card, uint32_t direction, const char *port_name) { struct pw_manager_param *p; spa_list_for_each(p, &card->param_list, link) { - uint32_t id, dir; + uint32_t index, dir; const char *name; if (p->id != SPA_PARAM_EnumRoute) @@ -390,14 +412,14 @@ if (spa_pod_parse_object(p->param, SPA_TYPE_OBJECT_ParamRoute, NULL, - SPA_PARAM_ROUTE_index, SPA_POD_Int(&id), + SPA_PARAM_ROUTE_index, SPA_POD_Int(&index), SPA_PARAM_ROUTE_direction, SPA_POD_Id(&dir), SPA_PARAM_ROUTE_name, SPA_POD_String(&name)) < 0) continue; if (dir != direction) continue; if (spa_streq(name, port_name)) - return id; + return index; } return SPA_ID_INVALID;
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/collect.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/collect.h
Changed
@@ -44,6 +44,7 @@ struct selector { bool (*type) (struct pw_manager_object *o); uint32_t id; + uint32_t index; const char *key; const char *value; void (*accumulate) (struct selector *sel, struct pw_manager_object *o); @@ -52,6 +53,8 @@ }; struct pw_manager_object *select_object(struct pw_manager *m, struct selector *s); +uint32_t id_to_index(struct pw_manager *m, uint32_t id); +uint32_t index_to_id(struct pw_manager *m, uint32_t index); void select_best(struct selector *s, struct pw_manager_object *o); /* ========================================================================== */ @@ -103,7 +106,7 @@ /* ========================================================================== */ struct profile_info { - uint32_t id; + uint32_t index; const char *name; const char *description; uint32_t priority; @@ -118,7 +121,7 @@ /* ========================================================================== */ struct port_info { - uint32_t id; + uint32_t index; uint32_t direction; const char *name; const char *description; @@ -154,9 +157,9 @@ /* ========================================================================== */ struct spa_dict *collect_props(struct spa_pod *info, struct spa_dict *dict); -uint32_t find_profile_id(struct pw_manager_object *card, const char *name); -uint32_t find_port_id(struct pw_manager_object *card, uint32_t direction, const char *port_name); -struct pw_manager_object *find_linked(struct pw_manager *m, uint32_t obj_id, enum pw_direction direction); -bool collect_is_linked(struct pw_manager *m, uint32_t obj_id, enum pw_direction direction); +uint32_t find_profile_index(struct pw_manager_object *card, const char *name); +uint32_t find_port_index(struct pw_manager_object *card, uint32_t direction, const char *port_name); +struct pw_manager_object *find_linked(struct pw_manager *m, uint32_t id, enum pw_direction direction); +bool collect_is_linked(struct pw_manager *m, uint32_t id, enum pw_direction direction); #endif
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/defs.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/defs.h
Changed
@@ -56,10 +56,9 @@ #define SCACHE_ENTRY_SIZE_MAX (1024*1024*16) -#define INDEX_MASK 0xffffu -#define MONITOR_FLAG (1u << 16) -#define EXTENSION_FLAG (1u << 17) -#define MODULE_FLAG (1u << 18) +#define MODULE_INDEX_MASK 0xfffffffu +#define MODULE_EXTENSION_FLAG (1u << 28) +#define MODULE_FLAG (1u << 29) #define DEFAULT_SINK "@DEFAULT_SINK@" #define DEFAULT_SOURCE "@DEFAULT_SOURCE@"
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/extension.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/extension.c
Changed
@@ -30,17 +30,17 @@ #include "extensions/registry.h" static const struct extension extensions[] = { - { "module-stream-restore", 0 | EXTENSION_FLAG, do_extension_stream_restore, }, - { "module-device-restore", 1 | EXTENSION_FLAG, do_extension_device_restore, }, - { "module-device-manager", 2 | EXTENSION_FLAG, do_extension_device_manager, }, + { "module-stream-restore", 0 | MODULE_EXTENSION_FLAG, do_extension_stream_restore, }, + { "module-device-restore", 1 | MODULE_EXTENSION_FLAG, do_extension_device_restore, }, + { "module-device-manager", 2 | MODULE_EXTENSION_FLAG, do_extension_device_manager, }, }; -const struct extension *extension_find(uint32_t idx, const char *name) +const struct extension *extension_find(uint32_t index, const char *name) { const struct extension *ext; SPA_FOR_EACH_ELEMENT(extensions, ext) { - if (idx == ext->idx || spa_streq(name, ext->name)) + if (index == ext->index || spa_streq(name, ext->name)) return ext; }
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/extension.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/extension.h
Changed
@@ -38,10 +38,10 @@ struct extension { const char *name; - uint32_t idx; + uint32_t index; int (*process)(struct client *client, uint32_t tag, struct message *m); }; -const struct extension *extension_find(uint32_t idx, const char *name); +const struct extension *extension_find(uint32_t index, const char *name); #endif /* PULSE_SERVER_EXTENSION_H */
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c
Changed
@@ -108,7 +108,7 @@ } message_put(d->reply, TAG_U32, DEVICE_TYPE_SINK, - TAG_U32, o->id, + TAG_U32, o->index, /* sink index */ TAG_U8, n_info, /* n_formats */ TAG_INVALID); for (i = 0; i < n_info; i++) { @@ -157,7 +157,7 @@ } spa_zero(sel); - sel.id = sink_index; + sel.index = sink_index; sel.type = pw_manager_object_is_sink; o = select_object(manager, &sel); @@ -173,7 +173,7 @@ return client_queue_message(client, data.reply); } -static int set_card_codecs(struct pw_manager_object *o, uint32_t id, +static int set_card_codecs(struct pw_manager_object *o, uint32_t port_index, uint32_t device_id, uint32_t n_codecs, uint32_t *codecs) { char buf[1024]; @@ -190,7 +190,7 @@ spa_pod_builder_push_object(&b, &f[0], SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route); spa_pod_builder_add(&b, - SPA_PARAM_ROUTE_index, SPA_POD_Int(id), + SPA_PARAM_ROUTE_index, SPA_POD_Int(port_index), SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id), 0); spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_props, 0); @@ -279,7 +279,7 @@ return -ENOTSUP; spa_zero(sel); - sel.id = sink_index; + sel.index = sink_index; sel.type = pw_manager_object_is_sink; o = select_object(manager, &sel);
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/internal.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/internal.h
Changed
@@ -51,7 +51,7 @@ struct spa_fraction min_quantum; struct sample_spec sample_spec; struct channel_map channel_map; - uint32_t max_quantum; + uint32_t quantum_limit; }; struct stats {
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/manager.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/manager.c
Changed
@@ -64,7 +64,7 @@ struct object_data { struct spa_list link; - const char *id; + const char *key; size_t size; }; @@ -163,7 +163,7 @@ } -static struct object *find_object(struct manager *m, uint32_t id) +static struct object *find_object_by_id(struct manager *m, uint32_t id) { struct object *o; spa_list_for_each(o, &m->this.object_list, this.link) { @@ -586,6 +586,7 @@ struct manager *m = data; struct object *o; const struct object_info *info; + const char *str; struct pw_proxy *proxy; info = find_info(type, version); @@ -603,10 +604,15 @@ pw_proxy_destroy(proxy); return; } + str = props ? spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL) : NULL; + if (!spa_atou64(str, &o->this.serial, 0)) + o->this.serial = SPA_ID_INVALID; + o->this.id = id; o->this.permissions = permissions; o->this.type = info->type; o->this.version = version; + o->this.index = o->this.serial < (1ULL<<32) ? o->this.serial : SPA_ID_INVALID; o->this.props = props ? pw_properties_new_dict(props) : NULL; o->this.proxy = proxy; o->this.creating = true; @@ -638,7 +644,7 @@ struct manager *m = object; struct object *o; - if ((o = find_object(m, id)) == NULL) + if ((o = find_object_by_id(m, id)) == NULL) return; o->this.removing = true; @@ -757,7 +763,7 @@ char buf[1024]; char *value; - if ((s = find_object(m, subject)) == NULL) + if ((s = find_object_by_id(m, subject)) == NULL) return -ENOENT; if (!SPA_FLAG_IS_SET(s->this.permissions, PW_PERM_M)) return -EACCES; @@ -793,7 +799,7 @@ int res; spa_list_for_each(o, &m->this.object_list, this.link) { - if (o->this.creating) + if (o->this.creating || o->this.removing) continue; if ((res = callback(data, &o->this)) != 0) return res; @@ -820,22 +826,22 @@ free(m); } -static struct object_data *object_find_data(struct object *o, const char *id) +static struct object_data *object_find_data(struct object *o, const char *key) { struct object_data *d; spa_list_for_each(d, &o->data_list, link) { - if (spa_streq(d->id, id)) + if (spa_streq(d->key, key)) return d; } return NULL; } -void *pw_manager_object_add_data(struct pw_manager_object *obj, const char *id, size_t size) +void *pw_manager_object_add_data(struct pw_manager_object *obj, const char *key, size_t size) { struct object *o = SPA_CONTAINER_OF(obj, struct object, this); struct object_data *d; - d = object_find_data(o, id); + d = object_find_data(o, key); if (d != NULL) { if (d->size == size) goto done; @@ -844,7 +850,7 @@ } d = calloc(1, sizeof(struct object_data) + size); - d->id = id; + d->key = key; d->size = size; spa_list_append(&o->data_list, &d->link);
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/manager.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/manager.h
Changed
@@ -75,10 +75,12 @@ struct pw_manager_object { struct spa_list link; /**< link in manager object_list */ + uint64_t serial; uint32_t id; uint32_t permissions; const char *type; uint32_t version; + uint32_t index; struct pw_properties *props; struct pw_proxy *proxy; char *message_object_path; @@ -111,8 +113,8 @@ int (*callback) (void *data, struct pw_manager_object *object), void *data); -void *pw_manager_object_add_data(struct pw_manager_object *o, const char *id, size_t size); -void *pw_manager_object_get_data(struct pw_manager_object *obj, const char *id); +void *pw_manager_object_add_data(struct pw_manager_object *o, const char *key, size_t size); +void *pw_manager_object_get_data(struct pw_manager_object *obj, const char *key); bool pw_manager_object_is_client(struct pw_manager_object *o); bool pw_manager_object_is_module(struct pw_manager_object *o);
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/message-handler.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/message-handler.c
Changed
@@ -122,7 +122,7 @@ { const char *str; - if (o->id == 0) { + if (o->id == PW_ID_CORE) { free(o->message_object_path); o->message_object_path = strdup("/core"); o->message_handler = core_object_message_handler;
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/module.c
Changed
@@ -42,7 +42,7 @@ #include "log.h" #include "module.h" -static void on_module_unload(void *obj, void *data, int res, uint32_t id) +static void on_module_unload(void *obj, void *data, int res, uint32_t index) { struct module *module = obj; module_unload(NULL, module); @@ -83,7 +83,7 @@ int module_load(struct client *client, struct module *module) { - pw_log_info("load module id:%u name:%s", module->idx, module->name); + pw_log_info("load module index:%u name:%s", module->index, module->name); if (module->methods->load == NULL) return -ENOTSUP; /* subscription event is sent when the module does a @@ -97,8 +97,8 @@ module_emit_destroy(module); - if (module->idx != SPA_ID_INVALID) - pw_map_remove(&impl->modules, module->idx & INDEX_MASK); + if (module->index != SPA_ID_INVALID) + pw_map_remove(&impl->modules, module->index & MODULE_INDEX_MASK); spa_hook_list_clean(&module->listener_list); pw_work_queue_cancel(impl->work_queue, module, SPA_ID_INVALID); @@ -118,7 +118,7 @@ /* Note that client can be NULL (when the module is being unloaded * internally and not by a client request */ - pw_log_info("unload module id:%u name:%s", module->idx, module->name); + pw_log_info("unload module index:%u name:%s", module->index, module->name); if (module->methods->unload) res = module->methods->unload(client, module); @@ -127,7 +127,7 @@ broadcast_subscribe_event(impl, SUBSCRIPTION_MASK_MODULE, SUBSCRIPTION_EVENT_REMOVE | SUBSCRIPTION_EVENT_MODULE, - module->idx); + module->index); module_free(module); @@ -270,6 +270,7 @@ #endif { "module-roc-sink", create_module_roc_sink, }, { "module-roc-source", create_module_roc_source, }, + { "module-x11-bell", create_module_x11_bell, }, }; static const struct module_info *find_module_info(const char *name) @@ -299,13 +300,13 @@ if (module == NULL) return NULL; - module->idx = pw_map_insert_new(&impl->modules, module); - if (module->idx == SPA_ID_INVALID) { + module->index = pw_map_insert_new(&impl->modules, module); + if (module->index == SPA_ID_INVALID) { module_unload(client, module); return NULL; } module->name = strdup(name); module->args = args ? strdup(args) : NULL; - module->idx |= MODULE_FLAG; + module->index |= MODULE_FLAG; return module; }
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/module.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/module.h
Changed
@@ -57,7 +57,7 @@ }; struct module { - uint32_t idx; + uint32_t index; const char *name; const char *args; struct pw_properties *props;
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c
Changed
@@ -262,11 +262,11 @@ props = pw_properties_new(NULL, NULL); pw_properties_setf(props, PW_KEY_NODE_NAME, - "combine_output.sink-%u.%s", data->module->idx, sink_name); + "combine_output.sink-%u.%s", data->module->index, sink_name); pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, data->sink_name); pw_properties_set(props, PW_KEY_NODE_TARGET, sink_name); - pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->idx); - pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->idx); + pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->index); + pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->index); pw_properties_set(props, PW_KEY_NODE_DONT_RECONNECT, "true"); pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); pw_properties_set(props, PW_KEY_NODE_PASSIVE, "true"); @@ -351,8 +351,8 @@ pw_properties_set(props, PW_KEY_NODE_NAME, data->sink_name); pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, data->sink_name); pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink"); - pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->idx); - pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->idx); + pw_properties_setf(props, PW_KEY_NODE_GROUP, "combine_sink-%u", data->module->index); + pw_properties_setf(props, PW_KEY_NODE_LINK_GROUP, "combine_sink-%u", data->module->index); pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); if ((str = pw_properties_get(module->props, "sink_properties")) != NULL)
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c
Changed
@@ -73,8 +73,8 @@ if ((label = pw_properties_get(module->props, "label")) == NULL) return -EINVAL; - pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->idx); - pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->idx); + pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->index); + pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-sink-%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{"); @@ -84,11 +84,24 @@ fprintf(f, " type = ladspa "); fprintf(f, " plugin = \"%s\" ", plugin); fprintf(f, " label = \"%s\" ", label); + if ((str = pw_properties_get(module->props, "control")) != NULL) { + size_t len; + const char *s, *state = NULL; + int count = 0; + + fprintf(f, " control = {"); + while ((s = pw_split_walk(str, ", ", &len, &state))) { + fprintf(f, " \"%d\" = %.*s", count, (int)len, s); + count++; + } + fprintf(f, " }"); + } + fprintf(f, " } ]"); if ((str = pw_properties_get(module->props, "inputs")) != NULL) fprintf(f, " inputs = [ %s ] ", str); if ((str = pw_properties_get(module->props, "outputs")) != NULL) fprintf(f, " outputs = [ %s ] ", str); - fprintf(f, " } ] }"); + fprintf(f, " }"); fprintf(f, " capture.props = {"); pw_properties_serialize_dict(f, &data->capture_props->dict, 0); fprintf(f, " } playback.props = {"); @@ -190,7 +203,7 @@ module_args_add_props(props, argument); if ((str = pw_properties_get(props, "sink_name")) != NULL) { - pw_properties_set(props, PW_KEY_NODE_NAME, str); + pw_properties_set(capture_props, PW_KEY_NODE_NAME, str); pw_properties_set(props, "sink_name", NULL); } if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c
Changed
@@ -73,8 +73,8 @@ if ((label = pw_properties_get(module->props, "label")) == NULL) return -EINVAL; - pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->idx); - pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->idx); + pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->index); + pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "ladspa-source-%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{"); @@ -84,11 +84,24 @@ fprintf(f, " type = ladspa "); fprintf(f, " plugin = \"%s\" ", plugin); fprintf(f, " label = \"%s\" ", label); + if ((str = pw_properties_get(module->props, "control")) != NULL) { + size_t len; + const char *s, *state = NULL; + int count = 0; + + fprintf(f, " control = {"); + while ((s = pw_split_walk(str, ", ", &len, &state))) { + fprintf(f, " \"%d\" = %.*s", count, (int)len, s); + count++; + } + fprintf(f, " }"); + } + fprintf(f, " } ]"); if ((str = pw_properties_get(module->props, "inputs")) != NULL) fprintf(f, " inputs = [ %s ] ", str); if ((str = pw_properties_get(module->props, "outputs")) != NULL) fprintf(f, " outputs = [ %s ] ", str); - fprintf(f, " } ] }"); + fprintf(f, " }"); fprintf(f, " capture.props = {"); pw_properties_serialize_dict(f, &data->capture_props->dict, 0); fprintf(f, " } playback.props = {"); @@ -190,8 +203,7 @@ module_args_add_props(props, argument); if ((str = pw_properties_get(props, "source_name")) != NULL) { - pw_properties_set(props, PW_KEY_NODE_NAME, str); - pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str); + pw_properties_set(capture_props, PW_KEY_NODE_NAME, str); pw_properties_set(props, "source_name", NULL); } if ((str = pw_properties_get(props, "source_properties")) != NULL) {
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c
Changed
@@ -70,8 +70,8 @@ char *args; size_t size, i; - pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "loopback-%u", module->idx); - pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "loopback-%u", module->idx); + pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index); + pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "loopback-%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{");
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c
Changed
@@ -67,8 +67,8 @@ char *args; size_t size; - pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->idx); - pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->idx); + pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index); + pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-sink-%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{"); @@ -169,7 +169,7 @@ module_args_add_props(props, argument); if ((str = pw_properties_get(props, "sink_name")) != NULL) { - pw_properties_set(props, PW_KEY_NODE_NAME, str); + pw_properties_set(capture_props, PW_KEY_NODE_NAME, str); pw_properties_set(props, "sink_name", NULL); } if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c
Changed
@@ -67,8 +67,8 @@ char *args; size_t size; - pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->idx); - pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->idx); + pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index); + pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "remap-source-%u", module->index); f = open_memstream(&args, &size); fprintf(f, "{"); @@ -169,7 +169,7 @@ module_args_add_props(props, argument); if ((str = pw_properties_get(props, "source_name")) != NULL) { - pw_properties_set(props, PW_KEY_NODE_NAME, str); + pw_properties_set(playback_props, PW_KEY_NODE_NAME, str); pw_properties_set(props, "source_name", NULL); } if ((str = pw_properties_get(props, "source_properties")) != NULL) {
View file
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-x11-bell.c
Added
@@ -0,0 +1,145 @@ +/* PipeWire + * + * Copyright © 2022 Wim Taymans <wim.taymans@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <pipewire/pipewire.h> + +#include "../module.h" + +#define NAME "x11-bell" + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +struct module_x11_bell_data { + struct module *module; + + struct pw_impl_module *mod; + struct spa_hook mod_listener; +}; + +static void module_destroy(void *data) +{ + struct module_x11_bell_data *d = data; + spa_hook_remove(&d->mod_listener); + d->mod = NULL; + module_schedule_unload(d->module); +} + +static const struct pw_impl_module_events module_events = { + PW_VERSION_IMPL_MODULE_EVENTS, + .destroy = module_destroy +}; + +static int module_x11_bell_load(struct client *client, struct module *module) +{ + struct module_x11_bell_data *data = module->user_data; + FILE *f; + char *args; + const char *str; + size_t size; + + f = open_memstream(&args, &size); + fprintf(f, "{"); + if ((str = pw_properties_get(module->props, "sink")) != NULL) + fprintf(f, " sink.name = \"%s\"", str); + if ((str = pw_properties_get(module->props, "sample")) != NULL) + fprintf(f, " sample.name = \"%s\"", str); + if ((str = pw_properties_get(module->props, "display")) != NULL) + fprintf(f, " x11.display = \"%s\"", str); + if ((str = pw_properties_get(module->props, "xauthority")) != NULL) + fprintf(f, " x11.xauthority = \"%s\"", str); + fprintf(f, " }"); + fclose(f); + + data->mod = pw_context_load_module(module->impl->context, + "libpipewire-module-x11-bell", + args, NULL); + free(args); + + if (data->mod == NULL) + return -errno; + + pw_impl_module_add_listener(data->mod, + &data->mod_listener, + &module_events, data); + return 0; +} + +static int module_x11_bell_unload(struct client *client, struct module *module) +{ + struct module_x11_bell_data *d = module->user_data; + + if (d->mod) { + spa_hook_remove(&d->mod_listener); + pw_impl_module_destroy(d->mod); + d->mod = NULL; + } + return 0; +} + +static const struct module_methods module_x11_bell_methods = { + VERSION_MODULE_METHODS, + .load = module_x11_bell_load, + .unload = module_x11_bell_unload, +}; + +static const struct spa_dict_item module_x11_bell_info[] = { + { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, + { PW_KEY_MODULE_DESCRIPTION, "X11 bell interceptor" }, + { PW_KEY_MODULE_USAGE, "sink=<sink to connect to> " + "sample=<the sample to play> " + "display=<X11 display> " + "xauthority=<X11 Authority>" }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; + +struct module *create_module_x11_bell(struct impl *impl, const char *argument) +{ + struct module *module; + struct pw_properties *props = NULL; + int res; + + PW_LOG_TOPIC_INIT(mod_topic); + + props = pw_properties_new_dict(&SPA_DICT_INIT_ARRAY(module_x11_bell_info)); + if (props == NULL) { + res = -EINVAL; + goto out; + } + if (argument) + module_args_add_props(props, argument); + + module = module_new(impl, &module_x11_bell_methods, sizeof(struct module_x11_bell_data)); + if (module == NULL) { + res = -errno; + goto out; + } + module->props = props; + + return module; +out: + pw_properties_free(props); + errno = -res; + return NULL; +}
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/modules/registry.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/registry.h
Changed
@@ -48,5 +48,6 @@ struct module *create_module_zeroconf_publish(struct impl *impl, const char *argument); struct module *create_module_roc_sink(struct impl *impl, const char *argument); struct module *create_module_roc_source(struct impl *impl, const char *argument); +struct module *create_module_x11_bell(struct impl *impl, const char *argument); #endif
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
@@ -97,12 +97,12 @@ unsigned int initialized:1; }; -static struct sample *find_sample(struct impl *impl, uint32_t idx, const char *name) +static struct sample *find_sample(struct impl *impl, uint32_t index, const char *name) { union pw_map_item *item; - if (idx != SPA_ID_INVALID) - return pw_map_lookup(&impl->samples, idx); + if (index != SPA_ID_INVALID) + return pw_map_lookup(&impl->samples, index); pw_array_for_each(item, &impl->samples.items) { struct sample *s = item->data; @@ -113,13 +113,13 @@ return NULL; } -void broadcast_subscribe_event(struct impl *impl, uint32_t mask, uint32_t event, uint32_t id) +void broadcast_subscribe_event(struct impl *impl, uint32_t mask, uint32_t event, uint32_t index) { struct server *s; spa_list_for_each(s, &impl->servers, link) { struct client *c; spa_list_for_each(c, &s->clients, link) - client_queue_subscribe_event(c, mask, event, id); + client_queue_subscribe_event(c, mask, event, index); } } @@ -159,23 +159,25 @@ static int reply_set_client_name(struct client *client, uint32_t tag) { + struct pw_manager *manager = client->manager; struct message *reply; struct pw_client *c; - uint32_t id; + uint32_t id, index; c = pw_core_get_client(client->core); if (c == NULL) return -ENOENT; id = pw_proxy_get_bound_id((struct pw_proxy*)c); + index = id_to_index(manager, id); - pw_log_info("[%s] reply tag:%u id:%u", client->name, tag, id); + pw_log_info("[%s] reply tag:%u id:%u index:%u", client->name, tag, id, index); reply = reply_new(client, tag); if (client->version >= 13) { message_put(reply, - TAG_U32, id, /* client index */ + TAG_U32, index, /* client index */ TAG_INVALID); } return client_queue_message(client, reply); @@ -196,13 +198,13 @@ operation_complete(o); } -static struct stream *find_stream(struct client *client, uint32_t id) +static struct stream *find_stream(struct client *client, uint32_t index) { union pw_map_item *item; pw_array_for_each(item, &client->streams.items) { struct stream *s = item->data; if (!pw_map_item_is_free(item) && - s->id == id) + s->index == index) return s; } return NULL; @@ -211,17 +213,15 @@ static int send_object_event(struct client *client, struct pw_manager_object *o, uint32_t facility) { - uint32_t event = 0, mask = 0, res_id = o->id; + uint32_t event = 0, mask = 0, res_index = o->index; if (pw_manager_object_is_sink(o)) { client_queue_subscribe_event(client, SUBSCRIPTION_MASK_SINK, SUBSCRIPTION_EVENT_SINK | facility, - res_id); + res_index); } if (pw_manager_object_is_source_or_monitor(o)) { - if (!pw_manager_object_is_source(o)) - res_id |= MONITOR_FLAG; mask = SUBSCRIPTION_MASK_SOURCE; event = SUBSCRIPTION_EVENT_SOURCE; } @@ -251,12 +251,12 @@ client_queue_subscribe_event(client, mask, event | facility, - res_id); + res_index); return 0; } static struct pw_manager_object *find_device(struct client *client, - uint32_t id, const char *name, bool sink, bool *is_monitor); + uint32_t index, const char *name, bool sink, bool *is_monitor); static int64_t get_node_latency_offset(struct pw_manager_object *o) { @@ -276,6 +276,7 @@ static void send_latency_offset_subscribe_event(struct client *client, struct pw_manager_object *o) { + struct pw_manager *manager = client->manager; struct latency_offset_data *d; struct pw_node_info *info; const char *str; @@ -310,7 +311,7 @@ client_queue_subscribe_event(client, SUBSCRIPTION_MASK_CARD, SUBSCRIPTION_EVENT_CARD | SUBSCRIPTION_EVENT_CHANGE, - card_id); + id_to_index(manager, card_id)); } static void send_default_change_subscribe_event(struct client *client, bool sink, bool source) @@ -370,8 +371,8 @@ struct defs *defs = &s->impl->defs; frame_size = s->frame_size; - minreq = frac_to_bytes_round_up(defs->min_req, &s->ss); - max_latency = defs->max_quantum * frame_size; + minreq = frac_to_bytes_round_up(s->min_req, &s->ss); + max_latency = defs->quantum_limit * frame_size; if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH) attr->maxlength = MAXLENGTH; @@ -379,7 +380,7 @@ attr->maxlength = SPA_MAX(attr->maxlength, frame_size); if (attr->tlength == (uint32_t) -1) - attr->tlength = frac_to_bytes_round_up(defs->default_tlength, &s->ss); + attr->tlength = frac_to_bytes_round_up(s->default_tlength, &s->ss); if (attr->tlength > attr->maxlength) attr->tlength = attr->maxlength; attr->tlength -= attr->tlength % frame_size; @@ -387,7 +388,7 @@ attr->tlength = SPA_MAX(attr->tlength, minreq); if (attr->minreq == (uint32_t) -1) { - uint32_t process = frac_to_bytes_round_up(defs->default_req, &s->ss); + uint32_t process = frac_to_bytes_round_up(s->default_req, &s->ss); /* With low-latency, tlength/4 gives a decent default in all of traditional, * adjust latency and early request modes. */ uint32_t m = attr->tlength / 4; @@ -434,7 +435,6 @@ attr->prebuf = max_prebuf; attr->prebuf -= attr->prebuf % frame_size; - s->missing = attr->tlength; attr->fragsize = 0; pw_log_info("[%s] maxlength:%u tlength:%u minreq:%u/%u prebuf:%u latency:%u %u", @@ -447,8 +447,9 @@ static int reply_create_playback_stream(struct stream *stream, struct pw_manager_object *peer) { struct client *client = stream->client; + struct pw_manager *manager = client->manager; struct message *reply; - uint32_t missing, peer_id; + uint32_t missing, peer_index; struct spa_dict_item items[5]; char latency[32]; char attr_maxlength[32]; @@ -458,7 +459,6 @@ const char *peer_name; struct spa_fraction lat; uint64_t lat_usec; - struct defs *defs = &stream->impl->defs; lat.denom = stream->ss.rate; lat.num = fix_playback_buffer_attr(stream, &stream->attr); @@ -467,9 +467,9 @@ if (stream->buffer == NULL) return -errno; - if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num) - lat.num = (defs->min_quantum.num * lat.denom + - (defs->min_quantum.denom -1)) / defs->min_quantum.denom; + if (lat.num * stream->min_quantum.denom / lat.denom < stream->min_quantum.num) + lat.num = (stream->min_quantum.num * lat.denom + + (stream->min_quantum.denom -1)) / stream->min_quantum.denom; lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom; snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom); @@ -489,22 +489,23 @@ stream->in_prebuf = true; missing = stream_pop_missing(stream); + stream->index = id_to_index(manager, stream->id); - pw_log_info("[%s] reply CREATE_PLAYBACK_STREAM tag:%u missing:%u latency:%s", - client->name, stream->create_tag, missing, latency); + pw_log_info("[%s] reply CREATE_PLAYBACK_STREAM tag:%u index:%u missing:%u latency:%s", + client->name, stream->create_tag, stream->index, missing, latency); reply = reply_new(client, stream->create_tag); message_put(reply, TAG_U32, stream->channel, /* stream index/channel */ - TAG_U32, stream->id, /* sink_input/stream index */ + TAG_U32, stream->index, /* sink_input/stream index */ TAG_U32, missing, /* missing/requested bytes */ TAG_INVALID); if (peer && pw_manager_object_is_sink(peer)) { - peer_id = peer->id; + peer_index = peer->index; peer_name = pw_properties_get(peer->props, PW_KEY_NODE_NAME); } else { - peer_id = SPA_ID_INVALID; + peer_index = SPA_ID_INVALID; peer_name = NULL; } @@ -520,7 +521,7 @@ message_put(reply, TAG_SAMPLE_SPEC, &stream->ss, TAG_CHANNEL_MAP, &stream->map, - TAG_U32, peer_id, /* sink index */ + TAG_U32, peer_index, /* sink index */ TAG_STRING, peer_name, /* sink name */ TAG_BOOLEAN, false, /* sink suspended state */ TAG_INVALID); @@ -547,7 +548,6 @@ static uint32_t fix_record_buffer_attr(struct stream *s, struct buffer_attr *attr) { uint32_t frame_size, minfrag, latency; - struct defs *defs = &s->impl->defs; frame_size = s->frame_size; @@ -556,10 +556,10 @@ attr->maxlength -= attr->maxlength % frame_size; attr->maxlength = SPA_MAX(attr->maxlength, frame_size); - minfrag = frac_to_bytes_round_up(defs->min_frag, &s->ss); + minfrag = frac_to_bytes_round_up(s->min_frag, &s->ss); if (attr->fragsize == (uint32_t) -1 || attr->fragsize == 0) - attr->fragsize = frac_to_bytes_round_up(defs->default_frag, &s->ss); + attr->fragsize = frac_to_bytes_round_up(s->default_frag, &s->ss); attr->fragsize -= attr->fragsize % frame_size; attr->fragsize = SPA_MAX(attr->fragsize, minfrag); attr->fragsize = SPA_MAX(attr->fragsize, frame_size); @@ -594,10 +594,9 @@ char attr_maxlength[32]; char attr_fragsize[32]; const char *peer_name, *name; - uint32_t peer_id; + uint32_t peer_index; struct spa_fraction lat; uint64_t lat_usec; - struct defs *defs = &stream->impl->defs; lat.denom = stream->ss.rate; lat.num = fix_record_buffer_attr(stream, &stream->attr); @@ -606,9 +605,9 @@ if (stream->buffer == NULL) return -errno; - if (lat.num * defs->min_quantum.denom / lat.denom < defs->min_quantum.num) - lat.num = (defs->min_quantum.num * lat.denom + - (defs->min_quantum.denom -1)) / defs->min_quantum.denom; + if (lat.num * stream->min_quantum.denom / lat.denom < stream->min_quantum.num) + lat.num = (stream->min_quantum.num * lat.denom + + (stream->min_quantum.denom -1)) / stream->min_quantum.denom; lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom; snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom); @@ -622,13 +621,15 @@ pw_stream_update_properties(stream->stream, &SPA_DICT_INIT(items, 3)); - pw_log_info("[%s] reply CREATE_RECORD_STREAM tag:%u latency:%s", - client->name, stream->create_tag, latency); + stream->index = id_to_index(manager, stream->id); + + pw_log_info("[%s] reply CREATE_RECORD_STREAM tag:%u index:%u latency:%s", + client->name, stream->create_tag, stream->index, latency); reply = reply_new(client, stream->create_tag); message_put(reply, TAG_U32, stream->channel, /* stream index/channel */ - TAG_U32, stream->id, /* source_output/stream index */ + TAG_U32, stream->index, /* source_output/stream index */ TAG_INVALID); if (peer && pw_manager_object_is_sink_input(peer)) @@ -637,15 +638,15 @@ name = pw_properties_get(peer->props, PW_KEY_NODE_NAME); if (!pw_manager_object_is_source(peer)) { size_t len = (name ? strlen(name) : 5) + 10; - peer_id = peer->id | MONITOR_FLAG; + peer_index = peer->index; peer_name = tmp = alloca(len); snprintf(tmp, len, "%s.monitor", name ? name : "sink"); } else { - peer_id = peer->id; + peer_index = peer->index; peer_name = name; } } else { - peer_id = SPA_ID_INVALID; + peer_index = SPA_ID_INVALID; peer_name = NULL; } @@ -659,7 +660,7 @@ message_put(reply, TAG_SAMPLE_SPEC, &stream->ss, TAG_CHANNEL_MAP, &stream->map, - TAG_U32, peer_id, /* source index */ + TAG_U32, peer_index, /* source index */ TAG_STRING, peer_name, /* source name */ TAG_BOOLEAN, false, /* source suspended state */ TAG_INVALID); @@ -703,8 +704,8 @@ if (info->props) { if ((str = spa_dict_lookup(info->props, "default.clock.rate")) != NULL) client->impl->defs.sample_spec.rate = atoi(str); - if ((str = spa_dict_lookup(info->props, "default.clock.max-quantum")) != NULL) - client->impl->defs.max_quantum = atoi(str); + if ((str = spa_dict_lookup(info->props, "default.clock.quantum-limit")) != NULL) + client->impl->defs.quantum_limit = atoi(str); } } @@ -884,6 +885,8 @@ pw_log_info("[%s] %s tag:%d", client->name, commands[command].name, tag); + client_update_quirks(client); + if (client->core == NULL) { client->core = pw_context_connect(impl->context, pw_properties_copy(client->props), 0); @@ -907,8 +910,6 @@ res = reply_set_client_name(client, tag); } - client_update_quirks(client); - return res; error: pw_log_error("%p: failed to connect client: %s", impl, spa_strerror(res)); @@ -995,11 +996,12 @@ { const struct spa_pod *param; uint32_t blocks, buffers, size, maxsize, stride; + struct defs *defs = &s->impl->defs; blocks = 1; stride = s->frame_size; - maxsize = 8192 * 32 * s->frame_size; + maxsize = defs->quantum_limit * 32 * s->frame_size; if (s->direction == PW_DIRECTION_OUTPUT) { size = attr->minreq; } else { @@ -1098,7 +1100,6 @@ uint32_t write_inc; uint32_t underrun_for; uint32_t playing_for; - uint32_t missing; uint32_t minreq; uint32_t quantum; unsigned int underrun:1; @@ -1138,12 +1139,10 @@ stream->underrun_for = 0; stream->playing_for = 0; if (pd->underrun) - stream_send_underflow(stream, stream->read_index, pd->underrun_for); + stream_send_underflow(stream, stream->read_index); else stream_send_started(stream); } - stream->missing += pd->missing; - stream->missing = SPA_MIN(stream->missing, (int64_t)stream->attr.tlength); stream->playing_for += pd->playing_for; if (stream->underrun_for != (uint64_t)-1) stream->underrun_for += pd->underrun_for; @@ -1246,7 +1245,7 @@ size = SPA_MIN(buf->datas[0].maxsize, minreq); memset(p, 0, size); - if (stream->draining) { + if (stream->draining && !stream->corked) { stream->draining = false; do_flush = true; } else { @@ -1254,16 +1253,15 @@ pd.underrun = true; } if ((stream->attr.prebuf == 0 || do_flush) && !stream->corked) { - pd.missing = size; - pd.playing_for = size; if (avail > 0) { spa_ringbuffer_read_data(&stream->ring, stream->buffer, stream->attr.maxlength, index % stream->attr.maxlength, p, avail); - index += avail; - pd.read_inc = avail; } + pd.playing_for = size; + pd.read_inc = size; + index += size; spa_ringbuffer_read_update(&stream->ring, index); } pw_log_debug("%p: [%s] underrun read:%u avail:%d max:%u", @@ -1293,7 +1291,6 @@ spa_ringbuffer_read_update(&stream->ring, index); pd.playing_for = size; - pd.missing = size; pd.underrun = false; } buf->datas[0].chunk->offset = 0; @@ -1376,6 +1373,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, uint32_t tag, struct message *m) { struct impl *impl = client->impl; + struct pw_manager *manager = client->manager; const char *name = NULL; int res; struct sample_spec ss; @@ -1436,7 +1434,7 @@ TAG_INVALID) < 0) goto error_protocol; - pw_log_info("[%s] CREATE_PLAYBACK_STREAM tag:%u corked:%u sink-name:%s sink-idx:%u", + pw_log_info("[%s] CREATE_PLAYBACK_STREAM tag:%u corked:%u sink-name:%s sink-index:%u", client->name, tag, corked, sink_name, sink_index); if (sink_index != SPA_ID_INVALID && sink_name != NULL) @@ -1580,12 +1578,18 @@ if (no_move) flags |= PW_STREAM_FLAG_DONT_RECONNECT; - if (sink_name != NULL) + if (sink_name != NULL) { pw_properties_set(props, PW_KEY_NODE_TARGET, sink_name); - else if (sink_index != SPA_ID_INVALID && sink_index != 0) + pw_properties_set(props, + PW_KEY_TARGET_OBJECT, sink_name); + } else if (sink_index != SPA_ID_INVALID && sink_index != 0) { + pw_properties_setf(props, + PW_KEY_NODE_TARGET, "%u", + index_to_id(manager, sink_index)); pw_properties_setf(props, - PW_KEY_NODE_TARGET, "%u", sink_index); + PW_KEY_TARGET_OBJECT, "%u", sink_index); + } stream->stream = pw_stream_new(client->core, name, props); props = NULL; @@ -1632,6 +1636,7 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint32_t tag, struct message *m) { struct impl *impl = client->impl; + struct pw_manager *manager = client->manager; const char *name = NULL; int res; struct sample_spec ss; @@ -1840,20 +1845,26 @@ source_index = id; } if (source_index != SPA_ID_INVALID && source_index != 0) { - if (source_index & MONITOR_FLAG) - source_index &= INDEX_MASK; pw_properties_setf(props, - PW_KEY_NODE_TARGET, "%u", source_index); + PW_KEY_NODE_TARGET, "%u", + index_to_id(manager, source_index)); + pw_properties_setf(props, + PW_KEY_TARGET_OBJECT, "%u", source_index); } else if (source_name != NULL) { if (spa_strendswith(source_name, ".monitor")) { pw_properties_setf(props, PW_KEY_NODE_TARGET, "%.*s", (int)strlen(source_name)-8, source_name); + pw_properties_setf(props, + PW_KEY_TARGET_OBJECT, + "%.*s", (int)strlen(source_name)-8, source_name); pw_properties_set(props, PW_KEY_STREAM_CAPTURE_SINK, "true"); } else { pw_properties_set(props, PW_KEY_NODE_TARGET, source_name); + pw_properties_set(props, + PW_KEY_TARGET_OBJECT, source_name); } } @@ -2233,10 +2244,11 @@ } static struct pw_manager_object *find_device(struct client *client, - uint32_t id, const char *name, bool sink, bool *is_monitor) + uint32_t index, const char *name, bool sink, bool *is_monitor) { struct selector sel; bool monitor = false, find_default = false; + struct pw_manager_object *o; if (name != NULL) { if (spa_streq(name, DEFAULT_MONITOR)) { @@ -2252,45 +2264,44 @@ if (!sink) return NULL; find_default = true; - } else if (spa_atou32(name, &id, 0)) { + } else if (spa_atou32(name, &index, 0)) { name = NULL; } } - if (name == NULL && (id == SPA_ID_INVALID || id == 0)) + if (name == NULL && (index == SPA_ID_INVALID || index == 0)) find_default = true; if (find_default) { name = get_default(client, sink); - id = SPA_ID_INVALID; + index = SPA_ID_INVALID; } - if (id != SPA_ID_INVALID) { - if (id & MONITOR_FLAG) { - if (sink) - return NULL; - monitor = true; - id &= ~MONITOR_FLAG; - } - } else if (name != NULL) { + if (name != NULL) { if (spa_strendswith(name, ".monitor")) { name = strndupa(name, strlen(name)-8); monitor = true; } - } else + } else if (index == SPA_ID_INVALID) return NULL; - if (is_monitor) - *is_monitor = monitor; spa_zero(sel); sel.type = sink ? pw_manager_object_is_sink : pw_manager_object_is_source_or_monitor; - sel.id = id; + sel.index = index; sel.key = PW_KEY_NODE_NAME; sel.value = name; - return select_object(client->manager, &sel); + o = select_object(client->manager, &sel); + if (o != NULL) { + if (!sink && pw_manager_object_is_monitor(o)) + monitor = true; + } + if (is_monitor) + *is_monitor = monitor; + + return o; } static void sample_play_ready(void *data, uint32_t index) @@ -2390,6 +2401,7 @@ goto error_noent; pw_properties_setf(props, PW_KEY_NODE_TARGET, "%u", o->id); + pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%"PRIu64, o->serial); play = sample_play_new(client->core, sample, props, sizeof(struct pending_sample)); props = NULL; @@ -2485,6 +2497,7 @@ } else { stream->playing_for = 0; stream->underrun_for = -1; + stream_send_request(stream); } return reply_simple_ack(client, tag); @@ -2563,7 +2576,7 @@ return 0; } -static int set_card_volume_mute_delay(struct pw_manager_object *o, uint32_t id, +static int set_card_volume_mute_delay(struct pw_manager_object *o, uint32_t port_index, uint32_t device_id, struct volume *vol, bool *mute, int64_t *latency_offset) { char buf[1024]; @@ -2580,7 +2593,7 @@ spa_pod_builder_push_object(&b, &f[0], SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route); spa_pod_builder_add(&b, - SPA_PARAM_ROUTE_index, SPA_POD_Int(id), + SPA_PARAM_ROUTE_index, SPA_POD_Int(port_index), SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id), 0); spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_props, 0); @@ -2609,7 +2622,7 @@ } static int set_card_port(struct pw_manager_object *o, uint32_t device_id, - uint32_t port_id) + uint32_t port_index) { char buf[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); @@ -2624,7 +2637,7 @@ SPA_PARAM_Route, 0, spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route, - SPA_PARAM_ROUTE_index, SPA_POD_Int(port_id), + SPA_PARAM_ROUTE_index, SPA_POD_Int(port_index), SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id), SPA_PARAM_ROUTE_save, SPA_POD_Bool(true))); @@ -2634,21 +2647,21 @@ static int do_set_stream_volume(struct client *client, uint32_t command, uint32_t tag, struct message *m) { struct pw_manager *manager = client->manager; - uint32_t id; + uint32_t index; struct stream *stream; struct volume volume; int res; if ((res = message_get(m, - TAG_U32, &id, + TAG_U32, &index, TAG_CVOLUME, &volume, TAG_INVALID)) < 0) return -EPROTO; pw_log_info("[%s] %s tag:%u index:%u", - client->name, commands[command].name, tag, id); + client->name, commands[command].name, tag, index); - stream = find_stream(client, id); + stream = find_stream(client, index); if (stream != NULL) { if (volume_compare(&stream->volume, &volume) == 0) @@ -2662,7 +2675,7 @@ struct pw_manager_object *o; spa_zero(sel); - sel.id = id; + sel.index = index; if (command == COMMAND_SET_SINK_INPUT_VOLUME) sel.type = pw_manager_object_is_sink_input; else @@ -2682,21 +2695,21 @@ static int do_set_stream_mute(struct client *client, uint32_t command, uint32_t tag, struct message *m) { struct pw_manager *manager = client->manager; - uint32_t id; + uint32_t index; struct stream *stream; int res; bool mute; if ((res = message_get(m, - TAG_U32, &id, + TAG_U32, &index, TAG_BOOLEAN, &mute, TAG_INVALID)) < 0) return -EPROTO; - pw_log_info("[%s] DO_SET_STREAM_MUTE tag:%u id:%u mute:%u", - client->name, tag, id, mute); + pw_log_info("[%s] DO_SET_STREAM_MUTE tag:%u index:%u mute:%u", + client->name, tag, index, mute); - stream = find_stream(client, id); + stream = find_stream(client, index); if (stream != NULL) { float val; @@ -2712,7 +2725,7 @@ struct pw_manager_object *o; spa_zero(sel); - sel.id = id; + sel.index = index; if (command == COMMAND_SET_SINK_INPUT_MUTE) sel.type = pw_manager_object_is_sink_input; else @@ -2734,7 +2747,7 @@ struct impl *impl = client->impl; struct pw_manager *manager = client->manager; struct pw_node_info *info; - uint32_t id, card_id = SPA_ID_INVALID; + uint32_t index, card_id = SPA_ID_INVALID; const char *name, *str; struct volume volume; struct pw_manager_object *o, *card = NULL; @@ -2744,17 +2757,17 @@ bool is_monitor; if ((res = message_get(m, - TAG_U32, &id, + TAG_U32, &index, TAG_STRING, &name, TAG_CVOLUME, &volume, TAG_INVALID)) < 0) return -EPROTO; pw_log_info("[%s] %s tag:%u index:%u name:%s", - client->name, commands[command].name, tag, id, name); + client->name, commands[command].name, tag, index, name); - if ((id == SPA_ID_INVALID && name == NULL) || - (id != SPA_ID_INVALID && name != NULL)) + if ((index == SPA_ID_INVALID && name == NULL) || + (index != SPA_ID_INVALID && name != NULL)) return -EINVAL; if (command == COMMAND_SET_SINK_VOLUME) @@ -2762,7 +2775,7 @@ else direction = PW_DIRECTION_INPUT; - o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT, &is_monitor); + o = find_device(client, index, name, direction == PW_DIRECTION_OUTPUT, &is_monitor); if (o == NULL || (info = o->info) == NULL || info->props == NULL) return -ENOENT; @@ -2800,7 +2813,7 @@ struct impl *impl = client->impl; struct pw_manager *manager = client->manager; struct pw_node_info *info; - uint32_t id, card_id = SPA_ID_INVALID; + uint32_t index, card_id = SPA_ID_INVALID; const char *name, *str; bool mute; struct pw_manager_object *o, *card = NULL; @@ -2810,17 +2823,17 @@ bool is_monitor; if ((res = message_get(m, - TAG_U32, &id, + TAG_U32, &index, TAG_STRING, &name, TAG_BOOLEAN, &mute, TAG_INVALID)) < 0) return -EPROTO; pw_log_info("[%s] %s tag:%u index:%u name:%s mute:%d", - client->name, commands[command].name, tag, id, name, mute); + client->name, commands[command].name, tag, index, name, mute); - if ((id == SPA_ID_INVALID && name == NULL) || - (id != SPA_ID_INVALID && name != NULL)) + if ((index == SPA_ID_INVALID && name == NULL) || + (index != SPA_ID_INVALID && name != NULL)) return -EINVAL; if (command == COMMAND_SET_SINK_MUTE) @@ -2828,7 +2841,7 @@ else direction = PW_DIRECTION_INPUT; - o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT, &is_monitor); + o = find_device(client, index, name, direction == PW_DIRECTION_OUTPUT, &is_monitor); if (o == NULL || (info = o->info) == NULL || info->props == NULL) return -ENOENT; @@ -2864,25 +2877,25 @@ { struct pw_manager *manager = client->manager; struct pw_node_info *info; - uint32_t id, card_id = SPA_ID_INVALID, device_id = SPA_ID_INVALID; - uint32_t port_id = SPA_ID_INVALID; + uint32_t index, card_id = SPA_ID_INVALID, device_id = SPA_ID_INVALID; + uint32_t port_index = SPA_ID_INVALID; const char *name, *str, *port_name; struct pw_manager_object *o, *card = NULL; int res; enum pw_direction direction; if ((res = message_get(m, - TAG_U32, &id, + TAG_U32, &index, TAG_STRING, &name, TAG_STRING, &port_name, TAG_INVALID)) < 0) return -EPROTO; pw_log_info("[%s] %s tag:%u index:%u name:%s port:%s", - client->name, commands[command].name, tag, id, name, port_name); + client->name, commands[command].name, tag, index, name, port_name); - if ((id == SPA_ID_INVALID && name == NULL) || - (id != SPA_ID_INVALID && name != NULL)) + if ((index == SPA_ID_INVALID && name == NULL) || + (index != SPA_ID_INVALID && name != NULL)) return -EINVAL; if (command == COMMAND_SET_SINK_PORT) @@ -2890,7 +2903,7 @@ else direction = PW_DIRECTION_INPUT; - o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT, NULL); + o = find_device(client, index, name, direction == PW_DIRECTION_OUTPUT, NULL); if (o == NULL || (info = o->info) == NULL || info->props == NULL) return -ENOENT; @@ -2905,11 +2918,11 @@ if (card == NULL || device_id == SPA_ID_INVALID) return -ENOENT; - port_id = find_port_id(card, direction, port_name); - if (port_id == SPA_ID_INVALID) + port_index = find_port_index(card, direction, port_name); + if (port_index == SPA_ID_INVALID) return -ENOENT; - if ((res = set_card_port(card, device_id, port_id)) < 0) + if ((res = set_card_port(card, device_id, port_index)) < 0) return res; return operation_new(client, tag); @@ -2934,7 +2947,7 @@ sel.type = pw_manager_object_is_card; if ((res = message_get(m, - TAG_U32, &sel.id, + TAG_U32, &sel.index, TAG_STRING, &sel.value, TAG_STRING, &port_name, TAG_S64, &offset, @@ -2942,10 +2955,10 @@ return -EPROTO; pw_log_info("[%s] %s tag:%u index:%u card_name:%s port_name:%s offset:%"PRIi64, - client->name, commands[command].name, tag, sel.id, sel.value, port_name, offset); + client->name, commands[command].name, tag, sel.index, sel.value, port_name, offset); - if ((sel.id == SPA_ID_INVALID && sel.value == NULL) || - (sel.id != SPA_ID_INVALID && sel.value != NULL)) + if ((sel.index == SPA_ID_INVALID && sel.value == NULL) || + (sel.index != SPA_ID_INVALID && sel.value != NULL)) return -EINVAL; if (port_name == NULL) return -EINVAL; @@ -2971,7 +2984,7 @@ res = 0; for (j = 0; j < pi->n_devices; ++j) { - res = set_card_volume_mute_delay(card, pi->id, pi->devices[j], NULL, NULL, &value); + res = set_card_volume_mute_delay(card, pi->index, pi->devices[j], NULL, NULL, &value); if (res < 0) break; } @@ -3208,7 +3221,7 @@ reply = reply_new(client, tag); message_put(reply, - TAG_U32, is_monitor ? o->id | MONITOR_FLAG : o->id, + TAG_U32, o->index, TAG_INVALID); return client_queue_message(client, reply); @@ -3240,6 +3253,7 @@ struct pw_manager_object *o) { struct pw_client_info *info = o->info; + struct pw_manager *manager = client->manager; const char *str; uint32_t module_id = SPA_ID_INVALID; @@ -3250,10 +3264,10 @@ module_id = (uint32_t)atoi(str); message_put(m, - TAG_U32, o->id, /* client index */ + TAG_U32, o->index, /* client index */ TAG_STRING, pw_properties_get(o->props, PW_KEY_APP_NAME), - TAG_U32, module_id, /* module */ - TAG_STRING, "PipeWire", /* driver */ + TAG_U32, id_to_index(manager, module_id), /* module index */ + TAG_STRING, "PipeWire", /* driver */ TAG_INVALID); if (client->version >= 13) { message_put(m, @@ -3272,7 +3286,7 @@ return -ENOENT; message_put(m, - TAG_U32, o->id, /* module index */ + TAG_U32, o->index, /* module index */ TAG_STRING, info->name, TAG_STRING, info->args, TAG_U32, -1, /* n_used */ @@ -3295,7 +3309,7 @@ struct module *module) { message_put(m, - TAG_U32, module->idx, /* module index */ + TAG_U32, module->index, /* module index */ TAG_STRING, module->name, TAG_STRING, module->args, TAG_U32, -1, /* n_used */ @@ -3360,6 +3374,7 @@ static int fill_card_info(struct client *client, struct message *m, struct pw_manager_object *o) { + struct pw_manager *manager = client->manager; struct pw_device_info *info = o->info; const char *str, *drv_name; uint32_t module_id = SPA_ID_INVALID, n_profiles, n; @@ -3377,9 +3392,9 @@ drv_name = "module-bluez5-device.c"; /* blueman needs this */ message_put(m, - TAG_U32, o->id, /* card index */ + TAG_U32, o->index, /* card index */ TAG_STRING, spa_dict_lookup(info->props, PW_KEY_DEVICE_NAME), - TAG_U32, module_id, + TAG_U32, id_to_index(manager, module_id), TAG_STRING, drv_name, TAG_INVALID); @@ -3464,7 +3479,7 @@ const char *name = "off"; for (j = 0; j < n_profiles; ++j) { - if (profile_info[j].id == pi->profiles[i]) { + if (profile_info[j].index == pi->profiles[i]) { name = profile_info[j].name; break; } @@ -3564,15 +3579,15 @@ dev_info.ss.format = SPA_AUDIO_FORMAT_S16; message_put(m, - TAG_U32, o->id, /* sink index */ + TAG_U32, o->index, /* sink index */ TAG_STRING, name, TAG_STRING, desc, TAG_SAMPLE_SPEC, &dev_info.ss, TAG_CHANNEL_MAP, &dev_info.map, - TAG_U32, module_id, /* module index */ + TAG_U32, id_to_index(manager, module_id), /* module index */ TAG_CVOLUME, &dev_info.volume_info.volume, TAG_BOOLEAN, dev_info.volume_info.mute, - TAG_U32, o->id | MONITOR_FLAG, /* monitor source */ + TAG_U32, o->index, /* monitor source index */ TAG_STRING, monitor_name, /* monitor source name */ TAG_USEC, 0LL, /* latency */ TAG_STRING, "PipeWire", /* driver */ @@ -3598,7 +3613,7 @@ TAG_VOLUME, dev_info.volume_info.base, /* base volume */ TAG_U32, state, /* state */ TAG_U32, dev_info.volume_info.steps, /* n_volume_steps */ - TAG_U32, card_id, /* card index */ + TAG_U32, card ? card->index : SPA_ID_INVALID, /* card index */ TAG_INVALID); } if (client->version >= 16) { @@ -3670,6 +3685,27 @@ return 0; } +static int fill_source_info_proplist(struct message *m, struct pw_manager_object *o, + struct pw_node_info *info) +{ + struct pw_properties *props = NULL; + struct spa_dict *props_dict = info->props; + + if (pw_manager_object_is_monitor(o)) { + props = pw_properties_new_dict(info->props); + if (props == NULL) + return -ENOMEM; + + pw_properties_set(props, PW_KEY_DEVICE_CLASS, "monitor"); + props_dict = &props->dict; + } + + message_put(m, TAG_PROPLIST, props_dict, TAG_INVALID); + pw_properties_free(props); + + return 0; +} + static int fill_source_info(struct client *client, struct message *m, struct pw_manager_object *o) { @@ -3746,15 +3782,15 @@ dev_info.ss.format = SPA_AUDIO_FORMAT_S16; message_put(m, - TAG_U32, is_monitor ? o->id | MONITOR_FLAG: o->id, /* source index */ + TAG_U32, o->index, /* source index */ TAG_STRING, is_monitor ? monitor_name : name, TAG_STRING, is_monitor ? monitor_desc : desc, TAG_SAMPLE_SPEC, &dev_info.ss, TAG_CHANNEL_MAP, &dev_info.map, - TAG_U32, module_id, /* module index */ + TAG_U32, id_to_index(manager, module_id), /* module index */ TAG_CVOLUME, &dev_info.volume_info.volume, TAG_BOOLEAN, dev_info.volume_info.mute, - TAG_U32, is_monitor ? o->id : SPA_ID_INVALID, /* monitor of sink */ + TAG_U32, is_monitor ? o->index : SPA_ID_INVALID,/* monitor of sink */ TAG_STRING, is_monitor ? name : NULL, /* monitor of sink name */ TAG_USEC, 0LL, /* latency */ TAG_STRING, "PipeWire", /* driver */ @@ -3762,8 +3798,10 @@ TAG_INVALID); if (client->version >= 13) { + int res; + if ((res = fill_source_info_proplist(m, o, info)) < 0) + return res; message_put(m, - TAG_PROPLIST, info->props, TAG_USEC, 0LL, /* requested latency */ TAG_INVALID); } @@ -3780,7 +3818,7 @@ TAG_VOLUME, dev_info.volume_info.base, /* base volume */ TAG_U32, state, /* state */ TAG_U32, dev_info.volume_info.steps, /* n_volume_steps */ - TAG_U32, card_id, /* card index */ + TAG_U32, card ? card->index : SPA_ID_INVALID, /* card index */ TAG_INVALID); } if (client->version >= 16) { @@ -3846,6 +3884,7 @@ struct pw_manager_object *peer; const char *str; uint32_t module_id = SPA_ID_INVALID, client_id = SPA_ID_INVALID; + uint32_t peer_index; struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT); if (!pw_manager_object_is_sink_input(o) || info == NULL || info->props == NULL) @@ -3865,13 +3904,17 @@ return -ENOENT; peer = find_linked(manager, o->id, PW_DIRECTION_OUTPUT); + if (peer && pw_manager_object_is_sink(peer)) + peer_index = peer->index; + else + peer_index = SPA_ID_INVALID; message_put(m, - TAG_U32, o->id, /* sink_input index */ + TAG_U32, o->index, /* sink_input index */ TAG_STRING, get_media_name(info), - TAG_U32, module_id, /* module index */ - TAG_U32, client_id, /* client index */ - TAG_U32, peer ? peer->id : SPA_ID_INVALID, /* sink index */ + TAG_U32, id_to_index(manager, module_id), /* module index */ + TAG_U32, id_to_index(manager, client_id), /* client index */ + TAG_U32, peer_index, /* sink index */ TAG_SAMPLE_SPEC, &dev_info.ss, TAG_CHANNEL_MAP, &dev_info.map, TAG_CVOLUME, &dev_info.volume_info.volume, @@ -3917,7 +3960,7 @@ struct pw_manager_object *peer; const char *str; uint32_t module_id = SPA_ID_INVALID, client_id = SPA_ID_INVALID; - uint32_t peer_id; + uint32_t peer_index; struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_INPUT); if (!pw_manager_object_is_source_output(o) || info == NULL || info->props == NULL) @@ -3937,20 +3980,17 @@ return -ENOENT; peer = find_linked(manager, o->id, PW_DIRECTION_INPUT); - if (peer && pw_manager_object_is_source_or_monitor(peer)) { - peer_id = peer->id; - if (!pw_manager_object_is_source(peer)) - peer_id |= MONITOR_FLAG; - } else { - peer_id = SPA_ID_INVALID; - } + if (peer && pw_manager_object_is_source_or_monitor(peer)) + peer_index = peer->index; + else + peer_index = SPA_ID_INVALID; message_put(m, - TAG_U32, o->id, /* source_output index */ + TAG_U32, o->index, /* source_output index */ TAG_STRING, get_media_name(info), - TAG_U32, module_id, /* module index */ - TAG_U32, client_id, /* client index */ - TAG_U32, peer_id, /* source index */ + TAG_U32, id_to_index(manager, module_id), /* module index */ + TAG_U32, id_to_index(manager, client_id), /* client index */ + TAG_U32, peer_index, /* source index */ TAG_SAMPLE_SPEC, &dev_info.ss, TAG_CHANNEL_MAP, &dev_info.map, TAG_USEC, 0LL, /* latency */ @@ -3994,15 +4034,15 @@ spa_zero(sel); if (message_get(m, - TAG_U32, &sel.id, + TAG_U32, &sel.index, TAG_INVALID) < 0) goto error_protocol; reply = reply_new(client, tag); - if (command == COMMAND_GET_MODULE_INFO && (sel.id & MODULE_FLAG) != 0) { + if (command == COMMAND_GET_MODULE_INFO && (sel.index & MODULE_FLAG) != 0) { struct module *module; - module = pw_map_lookup(&impl->modules, sel.id & INDEX_MASK); + module = pw_map_lookup(&impl->modules, sel.index & MODULE_INDEX_MASK); if (module == NULL) goto error_noentity; fill_ext_module_info(client, reply, module); @@ -4051,17 +4091,17 @@ if (fill_func == NULL) goto error_invalid; - if (sel.id != SPA_ID_INVALID && sel.value != NULL) + if (sel.index != SPA_ID_INVALID && sel.value != NULL) goto error_invalid; - pw_log_info("[%s] %s tag:%u idx:%u name:%s", client->name, - commands[command].name, tag, sel.id, sel.value); + pw_log_info("[%s] %s tag:%u index:%u name:%s", client->name, + commands[command].name, tag, sel.index, sel.value); if (command == COMMAND_GET_SINK_INFO || command == COMMAND_GET_SOURCE_INFO) { - o = find_device(client, sel.id, sel.value, + o = find_device(client, sel.index, sel.value, command == COMMAND_GET_SINK_INFO, NULL); } else { - if (sel.value == NULL && sel.id == SPA_ID_INVALID) + if (sel.value == NULL && sel.index == SPA_ID_INVALID) goto error_invalid; o = select_object(manager, &sel); } @@ -4131,25 +4171,25 @@ { struct impl *impl = client->impl; struct message *reply = NULL; - uint32_t id; + uint32_t index; const char *name; struct sample *sample; int res; if (message_get(m, - TAG_U32, &id, + TAG_U32, &index, TAG_STRING, &name, TAG_INVALID) < 0) return -EPROTO; - if ((id == SPA_ID_INVALID && name == NULL) || - (id != SPA_ID_INVALID && name != NULL)) + if ((index == SPA_ID_INVALID && name == NULL) || + (index != SPA_ID_INVALID && name != NULL)) return -EINVAL; - pw_log_info("[%s] %s tag:%u idx:%u name:%s", client->name, - commands[command].name, tag, id, name); + pw_log_info("[%s] %s tag:%u index:%u name:%s", client->name, + commands[command].name, tag, index, name); - if ((sample = find_sample(impl, id, name)) == NULL) + if ((sample = find_sample(impl, index, name)) == NULL) return -ENOENT; reply = reply_new(client, tag); @@ -4368,24 +4408,24 @@ static int do_extension(struct client *client, uint32_t command, uint32_t tag, struct message *m) { - uint32_t idx; + uint32_t index; const char *name; const struct extension *ext; if (message_get(m, - TAG_U32, &idx, + TAG_U32, &index, TAG_STRING, &name, TAG_INVALID) < 0) return -EPROTO; - pw_log_info("[%s] %s tag:%u id:%u name:%s", client->name, - commands[command].name, tag, idx, name); + pw_log_info("[%s] %s tag:%u index:%u name:%s", client->name, + commands[command].name, tag, index, name); - if ((idx == SPA_ID_INVALID && name == NULL) || - (idx != SPA_ID_INVALID && name != NULL)) + if ((index == SPA_ID_INVALID && name == NULL) || + (index != SPA_ID_INVALID && name != NULL)) return -EINVAL; - ext = extension_find(idx, name); + ext = extension_find(index, name); if (ext == NULL) return -ENOENT; @@ -4397,7 +4437,7 @@ struct pw_manager *manager = client->manager; struct pw_manager_object *o; const char *profile_name; - uint32_t profile_id = SPA_ID_INVALID; + uint32_t profile_index = SPA_ID_INVALID; struct selector sel; char buf[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); @@ -4407,17 +4447,17 @@ sel.type = pw_manager_object_is_card; if (message_get(m, - TAG_U32, &sel.id, + TAG_U32, &sel.index, TAG_STRING, &sel.value, TAG_STRING, &profile_name, TAG_INVALID) < 0) return -EPROTO; - pw_log_info("[%s] %s tag:%u id:%u name:%s profile:%s", client->name, - commands[command].name, tag, sel.id, sel.value, profile_name); + pw_log_info("[%s] %s tag:%u index:%u name:%s profile:%s", client->name, + commands[command].name, tag, sel.index, sel.value, profile_name); - if ((sel.id == SPA_ID_INVALID && sel.value == NULL) || - (sel.id != SPA_ID_INVALID && sel.value != NULL)) + if ((sel.index == SPA_ID_INVALID && sel.value == NULL) || + (sel.index != SPA_ID_INVALID && sel.value != NULL)) return -EINVAL; if (profile_name == NULL) return -EINVAL; @@ -4425,7 +4465,7 @@ if ((o = select_object(manager, &sel)) == NULL) return -ENOENT; - if ((profile_id = find_profile_id(o, profile_name)) == SPA_ID_INVALID) + if ((profile_index = find_profile_index(o, profile_name)) == SPA_ID_INVALID) return -ENOENT; if (!SPA_FLAG_IS_SET(o->permissions, PW_PERM_W | PW_PERM_X)) @@ -4438,7 +4478,7 @@ SPA_PARAM_Profile, 0, spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile, - SPA_PARAM_PROFILE_index, SPA_POD_Int(profile_id), + SPA_PARAM_PROFILE_index, SPA_POD_Int(profile_index), SPA_PARAM_PROFILE_save, SPA_POD_Bool(true))); return operation_new(client, tag); @@ -4489,20 +4529,20 @@ { struct pw_manager_object *o; const char *name; - uint32_t id, cmd; + uint32_t index, cmd; bool sink = command == COMMAND_SUSPEND_SINK, suspend; if (message_get(m, - TAG_U32, &id, + TAG_U32, &index, TAG_STRING, &name, TAG_BOOLEAN, &suspend, TAG_INVALID) < 0) return -EPROTO; - pw_log_info("[%s] %s tag:%u id:%u name:%s", client->name, - commands[command].name, tag, id, name); + pw_log_info("[%s] %s tag:%u index:%u name:%s", client->name, + commands[command].name, tag, index, name); - if ((o = find_device(client, id, name, sink, NULL)) == NULL) + if ((o = find_device(client, index, name, sink, NULL)) == NULL) return -ENOENT; if (o->proxy == NULL) @@ -4519,7 +4559,7 @@ { struct pw_manager *manager = client->manager; struct pw_manager_object *o, *dev, *dev_default; - uint32_t id, id_device; + uint32_t index, index_device; int target_id; const char *name_device; struct selector sel; @@ -4527,28 +4567,28 @@ bool sink = command == COMMAND_MOVE_SINK_INPUT; if (message_get(m, - TAG_U32, &id, - TAG_U32, &id_device, + TAG_U32, &index, + TAG_U32, &index_device, TAG_STRING, &name_device, TAG_INVALID) < 0) return -EPROTO; - if ((id_device == SPA_ID_INVALID && name_device == NULL) || - (id_device != SPA_ID_INVALID && name_device != NULL)) + if ((index_device == SPA_ID_INVALID && name_device == NULL) || + (index_device != SPA_ID_INVALID && name_device != NULL)) return -EINVAL; - pw_log_info("[%s] %s tag:%u idx:%u device:%d name:%s", client->name, - commands[command].name, tag, id, id_device, name_device); + pw_log_info("[%s] %s tag:%u index:%u device:%d name:%s", client->name, + commands[command].name, tag, index, index_device, name_device); spa_zero(sel); - sel.id = id; + sel.index = index; sel.type = sink ? pw_manager_object_is_sink_input: pw_manager_object_is_source_output; o = select_object(manager, &sel); if (o == NULL) return -ENOENT; - if ((dev = find_device(client, id_device, name_device, sink, NULL)) == NULL) + if ((dev = find_device(client, index_device, name_device, sink, NULL)) == NULL) return -ENOENT; dev_default = find_device(client, SPA_ID_INVALID, NULL, sink, NULL); @@ -4576,19 +4616,19 @@ { struct pw_manager *manager = client->manager; struct pw_manager_object *o; - uint32_t id; + uint32_t index; struct selector sel; if (message_get(m, - TAG_U32, &id, + TAG_U32, &index, TAG_INVALID) < 0) return -EPROTO; - pw_log_info("[%s] %s tag:%u id:%u", client->name, - commands[command].name, tag, id); + pw_log_info("[%s] %s tag:%u index:%u", client->name, + commands[command].name, tag, index); spa_zero(sel); - sel.id = id; + sel.index = index; switch (command) { case COMMAND_KILL_CLIENT: sel.type = pw_manager_object_is_client; @@ -4619,29 +4659,29 @@ spa_assert(!SPA_RESULT_IS_ASYNC(result)); if (SPA_RESULT_IS_OK(result)) { - pw_log_info("[%s] loaded module id:%u name:%s", - client_name, module->idx, module->name); + pw_log_info("[%s] loaded module index:%u name:%s", + client_name, module->index, module->name); module->loaded = true; broadcast_subscribe_event(impl, SUBSCRIPTION_MASK_MODULE, SUBSCRIPTION_EVENT_NEW | SUBSCRIPTION_EVENT_MODULE, - module->idx); + module->index); if (client != NULL) { struct message *reply = reply_new(client, tag); message_put(reply, - TAG_U32, module->idx, + TAG_U32, module->index, TAG_INVALID); client_queue_message(client, reply); } } else { - pw_log_warn("%p: [%s] failed to load module id:%u name:%s result:%d (%s)", + pw_log_warn("%p: [%s] failed to load module index:%u name:%s result:%d (%s)", impl, client_name, - module->idx, module->name, + module->index, module->name, result, spa_strerror(result)); module_schedule_unload(module); @@ -4744,22 +4784,22 @@ { struct impl *impl = client->impl; struct module *module; - uint32_t module_idx; + uint32_t module_index; if (message_get(m, - TAG_U32, &module_idx, + TAG_U32, &module_index, TAG_INVALID) < 0) return -EPROTO; - pw_log_info("[%s] %s tag:%u id:%u", client->name, - commands[command].name, tag, module_idx); + pw_log_info("[%s] %s tag:%u index:%u", client->name, + commands[command].name, tag, module_index); - if (module_idx == SPA_ID_INVALID) + if (module_index == SPA_ID_INVALID) return -EINVAL; - if ((module_idx & MODULE_FLAG) == 0) + if ((module_index & MODULE_FLAG) == 0) return -EPERM; - module = pw_map_lookup(&impl->modules, module_idx & INDEX_MASK); + module = pw_map_lookup(&impl->modules, module_index & MODULE_INDEX_MASK); if (module == NULL) return -ENOENT; @@ -5124,7 +5164,7 @@ parse_format(props, "pulse.default.format", DEFAULT_FORMAT, &def->sample_spec); parse_position(props, "pulse.default.position", DEFAULT_POSITION, &def->channel_map); def->sample_spec.channels = def->channel_map.channels; - def->max_quantum = 8192; + def->quantum_limit = 8192; } struct pw_protocol_pulse *pw_protocol_pulse_new(struct pw_context *context,
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/quirks.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/quirks.c
Changed
@@ -30,23 +30,7 @@ #include "log.h" #include "quirks.h" - -#define QUOTE(...) #__VA_ARGS__ - -static const char quirks_rules[] = -"# List of quirks" -"#" -"# All key/value pairs need to match before the quirks are applied." -"#" -"# Possible quirks:" -"# force-s16-info forces sink and source info as S16 format" -"# remove-capture-dont-move removes the capture DONT_MOVE flag" -"#\n" -"[" -" { application.process.binary = teams, quirks = [ force-s16-info ] }," -" { application.process.binary = skypeforlinux, quirks = [ force-s16-info ] }," -" { application.process.binary = firefox, quirks = [ remove-capture-dont-move ] }," -"]"; +#include "internal.h" static uint64_t parse_quirks(const char *str) { @@ -62,72 +46,139 @@ return 0; } -static int match(const char *rules, struct spa_dict *dict, uint64_t *quirks) +static bool find_match(struct spa_json *arr, const struct spa_dict *props) { - struct spa_json rules_json = SPA_JSON_INIT(rules, strlen(rules)); - struct spa_json rules_arr, it[2]; - - if (spa_json_enter_array(&rules_json, &rules_arr) <= 0) - return -EINVAL; + struct spa_json it[1]; - while (spa_json_enter_object(&rules_arr, &it[0]) > 0) { - char key[256]; - int match = true; - uint64_t quirks_cur = 0; + while (spa_json_enter_object(arr, &it[0]) > 0) { + char key[256], val[1024]; + const char *str, *value; + int match = 0, fail = 0; + int len; while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { - char val[4096]; - const char *str, *value; - int len; bool success = false; - if (spa_streq(key, "quirks")) { - if (spa_json_enter_array(&it[0], &it[1]) > 0) { - while (spa_json_get_string(&it[1], val, sizeof(val)) > 0) - quirks_cur |= parse_quirks(val); - } - continue; - } if ((len = spa_json_next(&it[0], &value)) <= 0) break; + str = spa_dict_lookup(props, key); + if (spa_json_is_null(value, len)) { - value = NULL; + success = str == NULL; } else { if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0) continue; value = val; + len = strlen(val); } - str = spa_dict_lookup(dict, key); - if (value == NULL) { - success = str == NULL; - } else if (str != NULL) { + if (str != NULL) { if (value[0] == '~') { - regex_t r; - if (regcomp(&r, value+1, REG_EXTENDED | REG_NOSUB) == 0) { - if (regexec(&r, str, 0, NULL, 0) == 0) + regex_t preg; + if (regcomp(&preg, value+1, REG_EXTENDED | REG_NOSUB) == 0) { + if (regexec(&preg, str, 0, NULL, 0) == 0) success = true; - regfree(&r); + regfree(&preg); } - } else if (spa_streq(str, value)) { + } 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; +} - if (!success) { - match = false; - break; +static int pw_conf_match_rules(const char *rules, size_t size, const struct spa_dict *props, + int (*matched) (void *data, const char *action, const char *val, int len), + void *data) +{ + const char *val; + struct spa_json it[4], actions; + int count = 0; + + spa_json_init(&it[0], rules, size); + if (spa_json_enter_array(&it[0], &it[1]) < 0) + return 0; + + while (spa_json_enter_object(&it[1], &it[2]) > 0) { + char key[64]; + bool have_match = false, have_actions = false; + + while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) { + if (spa_streq(key, "matches")) { + if (spa_json_enter_array(&it[2], &it[3]) < 0) + break; + + have_match = find_match(&it[3], props); } - } - if (match) { - *quirks = quirks_cur; - return 1; + else if (spa_streq(key, "actions")) { + if (spa_json_enter_object(&it[2], &actions) > 0) + have_actions = true; + } + else if (spa_json_next(&it[2], &val) <= 0) + break; + } + if (!have_match || !have_actions) + continue; + + while (spa_json_get_string(&actions, key, sizeof(key)) > 0) { + int res, len; + pw_log_debug("action %s", key); + + if ((len = spa_json_next(&actions, &val)) <= 0) + break; + + if (spa_json_is_container(val, len)) + len = spa_json_container_len(&actions, val, len); + + if ((res = matched(data, key, val, len)) < 0) + return res; + + count += res; + } + } + return count; +} + +static int client_rule_matched(void *data, const char *action, const char *val, int len) +{ + struct client *client = data; + + if (spa_streq(action, "update-props")) { + pw_properties_update_string(client->props, val, len); + } else if (spa_streq(action, "quirks")) { + struct spa_json quirks = SPA_JSON_INIT(val, len), it[1]; + uint64_t quirks_cur = 0; + char v[128]; + + if (spa_json_enter_array(&quirks, &it[0]) > 0) { + while (spa_json_get_string(&it[0], v, sizeof(v)) > 0) + quirks_cur |= parse_quirks(v); } + client->quirks = quirks_cur; } return 0; } int client_update_quirks(struct client *client) { - return match(quirks_rules, &client->props->dict, &client->quirks); + struct impl *impl = client->impl; + struct pw_context *context = impl->context; + const char *rules; + + if ((rules = pw_context_get_conf_section(context, "pulse.rules")) == NULL) + return 0; + + return pw_conf_match_rules(rules, strlen(rules), &client->props->dict, + client_rule_matched, client); }
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/server.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/server.c
Changed
@@ -167,7 +167,6 @@ index += diff; filled += diff; stream->write_index += diff; - stream->missing -= diff; if (filled < 0) { /* underrun, reported on reader side */ @@ -188,6 +187,8 @@ spa_ringbuffer_write_update(&stream->ring, index); stream->requested -= SPA_MIN(msg->length, stream->requested); + stream_send_request(stream); + finish: message_free(impl, msg, false, false); return res; @@ -378,7 +379,7 @@ goto error; } - if (server->n_clients >= MAX_CLIENTS) { + if (server->n_clients >= server->max_clients) { close(client_fd); errno = ECONNREFUSED; goto error; @@ -943,7 +944,7 @@ while ((len = spa_json_next(&it[1], &v)) > 0) { char addr_str[FORMATTED_SOCKET_ADDR_STRLEN] = { 0 }; char key[128], client_access[64] = { 0 }; - struct sockaddr_storage addr[2]; + struct sockaddr_storage addrs[2]; int i, max_clients = MAX_CLIENTS, listen_backlog = LISTEN_BACKLOG, n_addr; if (spa_json_is_object(v, len)) { @@ -966,7 +967,7 @@ spa_json_parse_stringn(v, len, addr_str, sizeof(addr_str)); } - n_addr = parse_address(addr_str, addr, 2); + n_addr = parse_address(addr_str, addrs, SPA_N_ELEMENTS(addrs)); if (n_addr < 0) { pw_log_warn("pulse-server %p: failed to parse address '%s': %s", impl, addr_str, spa_strerror(n_addr)); @@ -976,7 +977,9 @@ /* try to create sockets for each address in the list */ for (i = 0; i < n_addr; i++) { + const struct sockaddr_storage *addr = &addrs[i]; struct server * const server = server_new(impl); + if (server == NULL) { UPDATE_ERR(-errno); continue;
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/stream.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/stream.c
Changed
@@ -44,11 +44,25 @@ #include "reply.h" #include "stream.h" +static int parse_frac(struct pw_properties *props, const char *key, + const struct spa_fraction *def, struct spa_fraction *res) +{ + const char *str; + if (props == NULL || + (str = pw_properties_get(props, key)) == NULL || + sscanf(str, "%u/%u", &res->num, &res->denom) != 2 || + res->denom == 0) { + *res = *def; + } + return 0; +} + struct stream *stream_new(struct client *client, enum stream_type type, uint32_t create_tag, const struct sample_spec *ss, const struct channel_map *map, const struct buffer_attr *attr) { int res; + struct defs *defs = &client->impl->defs; struct stream *stream = calloc(1, sizeof(*stream)); if (stream == NULL) @@ -67,6 +81,13 @@ stream->attr = *attr; spa_ringbuffer_init(&stream->ring); + parse_frac(client->props, "pulse.min.req", &defs->min_req, &stream->min_req); + parse_frac(client->props, "pulse.min.frag", &defs->min_frag, &stream->min_frag); + parse_frac(client->props, "pulse.min.quantum", &defs->min_quantum, &stream->min_quantum); + parse_frac(client->props, "pulse.default.req", &defs->default_req, &stream->default_req); + parse_frac(client->props, "pulse.default.frag", &defs->default_frag, &stream->default_frag); + parse_frac(client->props, "pulse.default.tlength", &defs->default_tlength, &stream->default_tlength); + switch (type) { case STREAM_TYPE_RECORD: stream->direction = PW_DIRECTION_INPUT; @@ -136,9 +157,6 @@ stream->ring.writeindex = stream->ring.readindex; stream->write_index = stream->read_index; - stream->missing = stream->attr.tlength - - SPA_MIN(stream->requested, stream->attr.tlength); - if (stream->attr.prebuf > 0) stream->in_prebuf = true; @@ -153,13 +171,8 @@ } } -static bool stream_prebuf_active(struct stream *stream) +static bool stream_prebuf_active(struct stream *stream, int32_t avail) { - uint32_t index; - int32_t avail; - - avail = spa_ringbuffer_get_write_index(&stream->ring, &index); - if (stream->in_prebuf) { if (avail >= (int32_t) stream->attr.prebuf) stream->in_prebuf = false; @@ -172,30 +185,34 @@ uint32_t stream_pop_missing(struct stream *stream) { - uint32_t missing; + int64_t missing, avail; + + avail = stream->write_index - stream->read_index; + + missing = stream->attr.tlength; + missing -= stream->requested; + missing -= avail; - if (stream->missing <= 0) + if (missing <= 0) return 0; - if (stream->missing < stream->attr.minreq && !stream_prebuf_active(stream)) + if (missing < stream->attr.minreq && !stream_prebuf_active(stream, avail)) return 0; - missing = stream->missing; stream->requested += missing; - stream->missing = 0; return missing; } -int stream_send_underflow(struct stream *stream, int64_t offset, uint32_t underrun_for) +int stream_send_underflow(struct stream *stream, int64_t offset) { struct client *client = stream->client; struct impl *impl = client->impl; struct message *reply; if (ratelimit_test(&impl->rate_limit, stream->timestamp, SPA_LOG_LEVEL_INFO)) { - pw_log_info("[%s]: UNDERFLOW channel:%u offset:%" PRIi64 " underrun:%u", - client->name, stream->channel, offset, underrun_for); + pw_log_info("[%s]: UNDERFLOW channel:%u offset:%" PRIi64, + client->name, stream->channel, offset); } reply = message_alloc(impl, -1, 0); @@ -314,7 +331,6 @@ if (new_tlength <= old_tlength) return 0; - stream->missing += new_tlength - old_tlength; stream->attr.tlength = new_tlength; if (client->version >= 15) {
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-pulse/stream.h -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/stream.h
Changed
@@ -58,6 +58,7 @@ uint32_t create_tag; uint32_t channel; /* index in map */ uint32_t id; /* id of global */ + uint32_t index; /* index */ struct impl *impl; struct client *client; @@ -83,9 +84,15 @@ int64_t delay; uint32_t last_quantum; - int64_t missing; int64_t requested; + struct spa_fraction min_req; + struct spa_fraction default_req; + struct spa_fraction min_frag; + struct spa_fraction default_frag; + struct spa_fraction default_tlength; + struct spa_fraction min_quantum; + struct sample_spec ss; struct channel_map map; struct buffer_attr attr; @@ -116,7 +123,7 @@ void stream_flush(struct stream *stream); uint32_t stream_pop_missing(struct stream *stream); -int stream_send_underflow(struct stream *stream, int64_t offset, uint32_t underrun_for); +int stream_send_underflow(struct stream *stream, int64_t offset); int stream_send_overflow(struct stream *stream); int stream_send_killed(struct stream *stream); int stream_send_started(struct stream *stream);
View file
pipewire-0.3.43.tar.gz/src/modules/module-protocol-simple.c -> pipewire-0.3.44.tar.gz/src/modules/module-protocol-simple.c
Changed
@@ -111,7 +111,7 @@ struct spa_hook core_proxy_listener; struct spa_source *source; - char name[512]; + char name[128]; struct pw_stream *capture; struct spa_hook capture_listener; @@ -477,7 +477,7 @@ { struct server *server = data; struct impl *impl = server->impl; - struct sockaddr addr; + struct sockaddr_in addr; socklen_t addrlen; int client_fd, val; struct client *client = NULL; @@ -503,7 +503,7 @@ spa_list_append(&server->client_list, &client->link); server->n_clients++; - if (inet_ntop(addr.sa_family, addr.sa_data, client->name, sizeof(client->name)) == NULL) + if (inet_ntop(addr.sin_family, &addr.sin_addr.s_addr, client->name, sizeof(client->name)) == NULL) snprintf(client->name, sizeof(client->name), "client %d", client_fd); client->source = pw_loop_add_io(impl->loop,
View file
pipewire-0.3.43.tar.gz/src/modules/module-raop/rtsp-client.c -> pipewire-0.3.44.tar.gz/src/modules/module-raop/rtsp-client.c
Changed
@@ -203,9 +203,12 @@ if (res == 0) return -EPIPE; if (res < 0) { - if (res == EAGAIN) - return 0; - return -errno; + res = -errno; + if (res == -EINTR) + continue; + if (res != -EAGAIN && res != -EWOULDBLOCK) + return res; + return 0; } if (c == '\n') { client->line_buf[client->line_pos] = '\0'; @@ -435,9 +438,10 @@ true, on_source_io, client); if (client->source == NULL) { + res = -errno; pw_log_error("%p: source create failed: %m", client); close(fd); - return -errno; + return res; } client->connecting = true; free(client->session_id);
View file
pipewire-0.3.43.tar.gz/src/modules/module-roc-sink.c -> pipewire-0.3.44.tar.gz/src/modules/module-roc-sink.c
Changed
@@ -441,8 +441,6 @@ pw_properties_set(capture_props, PW_KEY_NODE_VIRTUAL, "true"); if (pw_properties_get(capture_props, PW_KEY_NODE_NETWORK) == NULL) pw_properties_set(capture_props, PW_KEY_NODE_NETWORK, "true"); - if (pw_properties_get(capture_props, PW_KEY_NODE_PASSIVE) == NULL) - pw_properties_set(capture_props, PW_KEY_NODE_PASSIVE, "true"); if ((str = pw_properties_get(capture_props, PW_KEY_MEDIA_CLASS)) == NULL) pw_properties_set(capture_props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
View file
pipewire-0.3.43.tar.gz/src/modules/module-roc-source.c -> pipewire-0.3.44.tar.gz/src/modules/module-roc-source.c
Changed
@@ -486,8 +486,6 @@ pw_properties_set(playback_props, PW_KEY_NODE_VIRTUAL, "true"); if (pw_properties_get(playback_props, PW_KEY_NODE_NETWORK) == NULL) pw_properties_set(playback_props, PW_KEY_NODE_NETWORK, "true"); - if (pw_properties_get(playback_props, PW_KEY_NODE_PASSIVE) == NULL) - pw_properties_set(playback_props, PW_KEY_NODE_PASSIVE, "true"); if ((str = pw_properties_get(playback_props, PW_KEY_MEDIA_CLASS)) == NULL) pw_properties_set(playback_props, PW_KEY_MEDIA_CLASS, "Audio/Source");
View file
pipewire-0.3.43.tar.gz/src/modules/module-rt.c -> pipewire-0.3.44.tar.gz/src/modules/module-rt.c
Changed
@@ -1,6 +1,6 @@ /* PipeWire * - * Copyright © 2021 Axis Communications AB + * Copyright © 2018 Wim Taymans * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -22,76 +22,452 @@ * DEALINGS IN THE SOFTWARE. */ -#include <errno.h> -#include <sched.h> -#include <stdbool.h> #include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> +#include <stdbool.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> #include <sys/stat.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <sys/resource.h> +#ifdef __FreeBSD__ +#include <sys/thr.h> +#endif +#include <fcntl.h> +#include <unistd.h> #include <pthread.h> +#include <sys/resource.h> -#include <spa/utils/dict.h> +#include "config.h" + +#include <spa/support/dbus.h> #include <spa/utils/result.h> +#include <spa/utils/string.h> #include <pipewire/impl.h> #include <pipewire/thread.h> -#include "config.h" - /** \page page_module_rt PipeWire Module: RT + * + * The `rt` module uses the operating system's scheduler to enable realtime + * scheduling for certain threads to assist with low latency audio processing. + * This requires `RLIMIT_RTPRIO` to be set to a value that's equal to this + * module's `rt.prio` parameter or higher. Most distros will come with some + * package that configures this for certain groups or users. If this is not set + * up and DBus is available, then this module will fall back to using RTKit. */ - #define NAME "rt" PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic -#define DEFAULT_POLICY SCHED_FIFO +#define REALTIME_POLICY SCHED_FIFO +#ifdef SCHED_RESET_ON_FORK +#define PW_SCHED_RESET_ON_FORK SCHED_RESET_ON_FORK +#else +/* FreeBSD compat */ +#define PW_SCHED_RESET_ON_FORK 0 +#endif -#define DEFAULT_NICE_LEVEL -11 -#define DEFAULT_RT_PRIO 88 -#define DEFAULT_RT_TIME_SOFT 2000000 -#define DEFAULT_RT_TIME_HARD 2000000 +#define IS_VALID_NICE_LEVEL(l) ((l)>=-20 && (l)<=19) -#define MODULE_USAGE \ - "[nice.level=<priority: default " SPA_STRINGIFY(DEFAULT_NICE_LEVEL) ">] " \ - "[rt.prio=<priority: default " SPA_STRINGIFY(DEFAULT_RT_PRIO) ">] " \ - "[rt.time.soft=<in usec: default " SPA_STRINGIFY(DEFAULT_RT_TIME_SOFT)"] " \ - "[rt.time.hard=<in usec: default " SPA_STRINGIFY(DEFAULT_RT_TIME_HARD)"] " +#define DEFAULT_NICE_LEVEL 20 +#define DEFAULT_RT_PRIO 88 +#define DEFAULT_RT_TIME_SOFT -1 +#define DEFAULT_RT_TIME_HARD -1 -#ifndef RLIMIT_RTTIME -#define RLIMIT_RTTIME 15 -#endif +#define MODULE_USAGE "[nice.level=<priority: default "SPA_STRINGIFY(DEFAULT_NICE_LEVEL)"(don't change)>] " \ + "[rt.prio=<priority: default "SPA_STRINGIFY(DEFAULT_RT_PRIO)">] " \ + "[rt.time.soft=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_SOFT)"] " \ + "[rt.time.hard=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_HARD)"] " static const struct spa_dict_item module_props[] = { - { PW_KEY_MODULE_AUTHOR, "Jonas Holmberg <jonashg@axis.com>" }, - { PW_KEY_MODULE_DESCRIPTION, "Set thread priorities" }, + { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, + { PW_KEY_MODULE_DESCRIPTION, "Use realtime thread scheduling, falling back to RTKit" }, { PW_KEY_MODULE_USAGE, MODULE_USAGE }, { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; +struct pw_rtkit_bus; + +struct thread { + struct impl *impl; + struct spa_list link; + pthread_t thread; + pid_t pid; + void *(*start)(void*); + void *arg; +}; + struct impl { struct pw_context *context; struct spa_thread_utils thread_utils; + int nice_level; int rt_prio; rlim_t rt_time_soft; rlim_t rt_time_hard; struct spa_hook module_listener; + + bool use_rtkit; + struct pw_rtkit_bus *system_bus; + + /* These are only for the RTKit implementation to fill in the `thread` + * struct. Since there's barely any overhead here we'll do this + * regardless of which backend is used. */ + pthread_mutex_t lock; + pthread_cond_t cond; + struct spa_list threads_list; }; +/*** + Copyright 2009 Lennart Poettering + Copyright 2010 David Henningsson <diwic@ubuntu.com> + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +***/ + +#include <dbus/dbus.h> + +#include "config.h" + +#include <sys/syscall.h> + +#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1" +#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1" + +#ifndef RLIMIT_RTTIME +#define RLIMIT_RTTIME 15 +#endif + +/** \cond */ +struct pw_rtkit_bus { + DBusConnection *bus; +}; +/** \endcond */ + +struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) +{ + struct pw_rtkit_bus *bus; + DBusError error; + + if (getenv("DISABLE_RTKIT")) { + errno = ENOTSUP; + return NULL; + } + + dbus_error_init(&error); + + bus = calloc(1, sizeof(struct pw_rtkit_bus)); + if (bus == NULL) + return NULL; + + bus->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); + if (bus->bus == NULL) + goto error; + + dbus_connection_set_exit_on_disconnect(bus->bus, false); + + return bus; + +error: + free(bus); + pw_log_error("Failed to connect to system bus: %s", error.message); + dbus_error_free(&error); + errno = ECONNREFUSED; + return NULL; +} + +void pw_rtkit_bus_free(struct pw_rtkit_bus *system_bus) +{ + dbus_connection_close(system_bus->bus); + dbus_connection_unref(system_bus->bus); + free(system_bus); +} + +static pid_t _gettid(void) +{ +#if defined(HAVE_GETTID) + return (pid_t) gettid(); +#elif defined(__linux__) + return syscall(SYS_gettid); +#elif defined(__FreeBSD__) + long pid; + thr_self(&pid); + return (pid_t)pid; +#else +#error "No gettid impl" +#endif +} + +static int translate_error(const char *name) +{ + pw_log_warn("RTKit error: %s", name); + + if (spa_streq(name, DBUS_ERROR_NO_MEMORY)) + return -ENOMEM; + if (spa_streq(name, DBUS_ERROR_SERVICE_UNKNOWN) || + spa_streq(name, DBUS_ERROR_NAME_HAS_NO_OWNER)) + return -ENOENT; + if (spa_streq(name, DBUS_ERROR_ACCESS_DENIED) || + spa_streq(name, DBUS_ERROR_AUTH_FAILED)) + return -EACCES; + + return -EIO; +} + +static long long rtkit_get_int_property(struct pw_rtkit_bus *connection, const char *propname, + long long *propval) +{ + DBusMessage *m = NULL, *r = NULL; + DBusMessageIter iter, subiter; + dbus_int64_t i64; + dbus_int32_t i32; + DBusError error; + int current_type; + long long ret; + const char *interfacestr = "org.freedesktop.RealtimeKit1"; + + dbus_error_init(&error); + + if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, + RTKIT_OBJECT_PATH, + "org.freedesktop.DBus.Properties", "Get"))) { + ret = -ENOMEM; + goto finish; + } + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &interfacestr, + DBUS_TYPE_STRING, &propname, DBUS_TYPE_INVALID)) { + ret = -ENOMEM; + goto finish; + } + + if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) { + ret = translate_error(error.name); + goto finish; + } + + if (dbus_set_error_from_message(&error, r)) { + ret = translate_error(error.name); + goto finish; + } + + ret = -EBADMSG; + dbus_message_iter_init(r, &iter); + while ((current_type = dbus_message_iter_get_arg_type(&iter)) != DBUS_TYPE_INVALID) { + + if (current_type == DBUS_TYPE_VARIANT) { + dbus_message_iter_recurse(&iter, &subiter); + + while ((current_type = + dbus_message_iter_get_arg_type(&subiter)) != DBUS_TYPE_INVALID) { + + if (current_type == DBUS_TYPE_INT32) { + dbus_message_iter_get_basic(&subiter, &i32); + *propval = i32; + ret = 0; + } + + if (current_type == DBUS_TYPE_INT64) { + dbus_message_iter_get_basic(&subiter, &i64); + *propval = i64; + ret = 0; + } + + dbus_message_iter_next(&subiter); + } + } + dbus_message_iter_next(&iter); + } + +finish: + + if (m) + dbus_message_unref(m); + + if (r) + dbus_message_unref(r); + + dbus_error_free(&error); + + return ret; +} + +int pw_rtkit_get_max_realtime_priority(struct pw_rtkit_bus *connection) +{ + long long retval; + int err; + + err = rtkit_get_int_property(connection, "MaxRealtimePriority", &retval); + return err < 0 ? err : retval; +} + +int pw_rtkit_get_min_nice_level(struct pw_rtkit_bus *connection, int *min_nice_level) +{ + long long retval; + int err; + + err = rtkit_get_int_property(connection, "MinNiceLevel", &retval); + if (err >= 0) + *min_nice_level = retval; + return err; +} + +long long pw_rtkit_get_rttime_usec_max(struct pw_rtkit_bus *connection) +{ + long long retval; + int err; + + err = rtkit_get_int_property(connection, "RTTimeUSecMax", &retval); + return err < 0 ? err : retval; +} + +int pw_rtkit_make_realtime(struct pw_rtkit_bus *connection, pid_t thread, int priority) +{ + DBusMessage *m = NULL, *r = NULL; + dbus_uint64_t u64; + dbus_uint32_t u32; + DBusError error; + int ret; + + dbus_error_init(&error); + + if (thread == 0) + thread = _gettid(); + + if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, + RTKIT_OBJECT_PATH, + "org.freedesktop.RealtimeKit1", + "MakeThreadRealtime"))) { + ret = -ENOMEM; + goto finish; + } + + u64 = (dbus_uint64_t) thread; + u32 = (dbus_uint32_t) priority; + + if (!dbus_message_append_args(m, + DBUS_TYPE_UINT64, &u64, + DBUS_TYPE_UINT32, &u32, DBUS_TYPE_INVALID)) { + ret = -ENOMEM; + goto finish; + } + + if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) { + ret = translate_error(error.name); + goto finish; + } + + + if (dbus_set_error_from_message(&error, r)) { + ret = translate_error(error.name); + goto finish; + } + + ret = 0; + +finish: + + if (m) + dbus_message_unref(m); + + if (r) + dbus_message_unref(r); + + dbus_error_free(&error); + + return ret; +} + +int pw_rtkit_make_high_priority(struct pw_rtkit_bus *connection, pid_t thread, int nice_level) +{ + DBusMessage *m = NULL, *r = NULL; + dbus_uint64_t u64; + dbus_int32_t s32; + DBusError error; + int ret; + + dbus_error_init(&error); + + if (thread == 0) + thread = _gettid(); + + if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, + RTKIT_OBJECT_PATH, + "org.freedesktop.RealtimeKit1", + "MakeThreadHighPriority"))) { + ret = -ENOMEM; + goto finish; + } + + u64 = (dbus_uint64_t) thread; + s32 = (dbus_int32_t) nice_level; + + if (!dbus_message_append_args(m, + DBUS_TYPE_UINT64, &u64, + DBUS_TYPE_INT32, &s32, DBUS_TYPE_INVALID)) { + ret = -ENOMEM; + goto finish; + } + + + + if (!(r = dbus_connection_send_with_reply_and_block(connection->bus, m, -1, &error))) { + ret = translate_error(error.name); + goto finish; + } + + + if (dbus_set_error_from_message(&error, r)) { + ret = translate_error(error.name); + goto finish; + } + + ret = 0; + +finish: + + if (m) + dbus_message_unref(m); + + if (r) + dbus_message_unref(r); + + dbus_error_free(&error); + + return ret; +} + static void module_destroy(void *data) { struct impl *impl = data; + pw_thread_utils_set(NULL); spa_hook_remove(&impl->module_listener); + + if (impl->system_bus) + pw_rtkit_bus_free(impl->system_bus); free(impl); } @@ -100,25 +476,69 @@ .destroy = module_destroy, }; -static int set_nice(struct impl *impl, int nice_level) +/** + * Check if the current user has permissions to use realtime scheduling at the + * specified priority. + */ +static bool check_realtime_priviliges(rlim_t priority) { - long tid; - int res = 0; + int old_policy; + struct sched_param old_sched_params; + int new_policy = REALTIME_POLICY; + struct sched_param new_sched_params; + + /* We could check `RLIMIT_RTPRIO`, but the BSDs generally don't have + * that available, and there are also other ways to use realtime + * scheduling without that rlimit being set such as `CAP_SYS_NICE` or + * running as root. Instead of checking a bunch of preconditions, we + * just try if setting realtime scheduling works or not. */ + if ((old_policy = sched_getscheduler(0)) < 0 || + sched_getparam(0, &old_sched_params) != 0) { + return false; + } - tid = syscall(SYS_gettid); - if (tid < 0) { - pw_log_warn("could not get main thread id: %m"); - tid = 0; /* means current thread in setpriority() on linux */ + /* If the current scheduling policy has `SCHED_RESET_ON_FORK` set, then + * this also needs to be set here or `sched_setscheduler()` will return + * an error code. Similarly, if it is not set, then we don't want to set + * it here as it would irreversible change the current thread's + * scheduling policy. */ + spa_zero(new_sched_params); + new_sched_params.sched_priority = priority; + if ((old_policy & PW_SCHED_RESET_ON_FORK) != 0) { + new_policy |= PW_SCHED_RESET_ON_FORK; } - if (setpriority(PRIO_PROCESS, (id_t)tid, nice_level) < 0) - res = -errno; - if (res < 0) - pw_log_warn("could not set nice-level to %d: %s", - nice_level, spa_strerror(res)); - else - pw_log_info("main thread nice level set to %d", - nice_level); + if (sched_setscheduler(0, new_policy, &new_sched_params) == 0) { + sched_setscheduler(0, old_policy, &old_sched_params); + return true; + } else { + return false; + } +} + +static int set_nice(struct impl *impl, int nice_level) +{ + int res = 0; + pid_t tid; + + if (impl->use_rtkit) { + if ((res = pw_rtkit_make_high_priority(impl->system_bus, 0, nice_level)) < 0) { + pw_log_warn("could not set nice-level to %d: %s", + nice_level, spa_strerror(res)); + } else { + pw_log_info("main thread nice level set to %d", nice_level); + } + } else { + tid = _gettid(); + if (setpriority(PRIO_PROCESS, tid, nice_level) == 0) { + pw_log_info("main thread nice level set to %d", + nice_level); + } else { + res = -errno; + pw_log_warn("could not set nice-level to %d: %s", + nice_level, spa_strerror(res)); + } + } return res; } @@ -126,74 +546,193 @@ static int set_rlimit(struct impl *impl) { struct rlimit rl; + long long rttime; int res = 0; + spa_zero(rl); rl.rlim_cur = impl->rt_time_soft; rl.rlim_max = impl->rt_time_hard; + if (impl->use_rtkit) { + rttime = pw_rtkit_get_rttime_usec_max(impl->system_bus); + if (rttime >= 0) { + if ((rlim_t)rttime < rl.rlim_cur) { + pw_log_debug("clamping rt.time.soft from %ld to %lld because of RTKit", + rl.rlim_cur, rttime); + } + + rl.rlim_cur = SPA_MIN(rl.rlim_cur, (rlim_t)rttime); + rl.rlim_max = SPA_MIN(rl.rlim_max, (rlim_t)rttime); + } + } + if (setrlimit(RLIMIT_RTTIME, &rl) < 0) res = -errno; if (res < 0) - pw_log_warn("could not set rlimit: %s", spa_strerror(res)); + pw_log_debug("setrlimit() failed: %s", spa_strerror(res)); else - pw_log_debug("rt.time.soft %"PRIi64", rt.time.hard %"PRIi64, + pw_log_debug("rt.time.soft:%"PRIi64" rt.time.hard:%"PRIi64, (int64_t)rl.rlim_cur, (int64_t)rl.rlim_max); return res; } -static struct spa_thread *impl_create(void *data, - const struct spa_dict *props, - void *(*start)(void*), void *arg) +static struct thread *find_thread_by_pt(struct impl *impl, pthread_t pt) +{ + struct thread *t; + + spa_list_for_each(t, &impl->threads_list, link) { + if (pthread_equal(t->thread, pt)) + return t; + } + return NULL; +} + +static void *custom_start(void *data) +{ + struct thread *this = data; + struct impl *impl = this->impl; + + pthread_mutex_lock(&impl->lock); + this->pid = _gettid(); + pthread_cond_broadcast(&impl->cond); + pthread_mutex_unlock(&impl->lock); + + return this->start(this->arg); +} + +static struct spa_thread *impl_create(void *data, const struct spa_dict *props, + void *(*start_routine)(void*), void *arg) { - pthread_t pt; + struct impl *impl = data; + struct thread *this; int err; - if ((err = pthread_create(&pt, NULL, start, arg)) != 0) { + + this = calloc(1, sizeof(*this)); + this->impl = impl; + this->start = start_routine; + this->arg = arg; + + /* This thread list is only used for the RTKit implementation */ + pthread_mutex_lock(&impl->lock); + err = pthread_create(&this->thread, NULL, custom_start, this); + if (err != 0) + goto exit; + + pthread_cond_wait(&impl->cond, &impl->lock); + + spa_list_append(&impl->threads_list, &this->link); +exit: + pthread_mutex_unlock(&impl->lock); + + if (err != 0) { errno = err; + free(this); return NULL; } - return (struct spa_thread*)pt; + return (struct spa_thread*)this->thread; } static int impl_join(void *data, struct spa_thread *thread, void **retval) { + struct impl *impl = data; pthread_t pt = (pthread_t)thread; + struct thread *thr; + + pthread_mutex_lock(&impl->lock); + if ((thr = find_thread_by_pt(impl, pt)) != NULL) { + spa_list_remove(&thr->link); + free(thr); + } + pthread_mutex_unlock(&impl->lock); + return pthread_join(pt, retval); } static int impl_get_rt_range(void *data, const struct spa_dict *props, int *min, int *max) { - int policy = DEFAULT_POLICY; - if (min) - *min = sched_get_priority_min(policy); - if (max) - *max = sched_get_priority_max(policy); + struct impl *impl = data; + if (impl->use_rtkit) { + if (min) + *min = 1; + if (max) + *max = pw_rtkit_get_max_realtime_priority(impl->system_bus); + } else { + if (min) + *min = sched_get_priority_min(REALTIME_POLICY); + if (max) + *max = sched_get_priority_max(REALTIME_POLICY); + } + return 0; } +static pid_t impl_gettid(struct impl *impl, pthread_t pt) +{ + struct thread *thr; + pid_t pid; + + pthread_mutex_lock(&impl->lock); + if ((thr = find_thread_by_pt(impl, pt)) != NULL) + pid = thr->pid; + else + pid = _gettid(); + pthread_mutex_unlock(&impl->lock); + + return pid; +} + static int impl_acquire_rt(void *data, struct spa_thread *thread, int priority) { - int err, policy = DEFAULT_POLICY; - int rtprio = priority; + struct impl *impl = data; struct sched_param sp; + int err, rtprio_limit; pthread_t pt = (pthread_t)thread; + pid_t pid; - if (rtprio < sched_get_priority_min(policy) || - rtprio > sched_get_priority_max(policy)) { - pw_log_warn("invalid priority %d for policy %d", rtprio, policy); - return -EINVAL; + /* See the docstring on `spa_thread_utils_methods::acquire_rt` */ + if (priority == -1) { + priority = impl->rt_prio; + } + + if (impl->use_rtkit) { + pid = impl_gettid(impl, pt); + rtprio_limit = pw_rtkit_get_max_realtime_priority(impl->system_bus); + if (rtprio_limit >= 0 && rtprio_limit < priority) { + pw_log_info("dropping requested priority %d for thread %d down to %d because of RTKit limits", priority, pid, rtprio_limit); + priority = rtprio_limit; + } + + spa_zero(sp); + sp.sched_priority = priority; + + if (pthread_setschedparam(pt, SCHED_OTHER | PW_SCHED_RESET_ON_FORK, &sp) == 0) { + pw_log_debug("SCHED_OTHER|SCHED_RESET_ON_FORK worked."); + } + + if ((err = pw_rtkit_make_realtime(impl->system_bus, pid, priority)) < 0) { + pw_log_warn("could not make thread %d realtime using RTKit: %s", pid, spa_strerror(err)); + } else { + pw_log_info("acquired realtime priority %d for thread %d using RTKit", priority, pid); + } + } else { + if (priority < sched_get_priority_min(REALTIME_POLICY) || + priority > sched_get_priority_max(REALTIME_POLICY)) { + pw_log_warn("invalid priority %d for policy %d", priority, REALTIME_POLICY); + return -EINVAL; + } + + spa_zero(sp); + sp.sched_priority = priority; + if ((err = pthread_setschedparam(pt, REALTIME_POLICY | PW_SCHED_RESET_ON_FORK, &sp)) != 0) { + pw_log_warn("could not make thread %p realtime: %s", thread, strerror(err)); + return -err; + } + pw_log_info("acquired realtime priority %d for thread %p", priority, thread); } - spa_zero(sp); - sp.sched_priority = rtprio; - if ((err = pthread_setschedparam(pt, policy | SCHED_RESET_ON_FORK, - &sp)) != 0) { - pw_log_warn("%p: could not make thread realtime: %s", thread, strerror(err)); - return -err; - } - pw_log_info("thread %p has realtime priority %d", thread, rtprio); return 0; } @@ -204,11 +743,11 @@ int err; spa_zero(sp); - if ((err = pthread_setschedparam(pt, - SCHED_OTHER | SCHED_RESET_ON_FORK, &sp)) != 0) { - pw_log_warn("%p: could not drop realtime: %s", thread, strerror(err)); + if ((err = pthread_setschedparam(pt, SCHED_OTHER | PW_SCHED_RESET_ON_FORK, &sp)) != 0) { + pw_log_debug("thread %p: SCHED_OTHER|SCHED_RESET_ON_FORK failed: %s", + thread, strerror(err)); return -err; - } + } pw_log_info("thread %p dropped realtime priority", thread); return 0; } @@ -222,56 +761,100 @@ .drop_rt = impl_drop_rt, }; + SPA_EXPORT int pipewire__module_init(struct pw_impl_module *module, const char *args) { struct pw_context *context = pw_impl_module_get_context(module); struct impl *impl; + const struct pw_properties *context_props; struct pw_properties *props; - int nice_level; - int res; + const char *str; + bool use_rtkit = true; + int res = 0; PW_LOG_TOPIC_INIT(mod_topic); + if ((context_props = pw_context_get_properties(context)) != NULL && + (str = pw_properties_get(context_props, "support.dbus")) != NULL && + !pw_properties_parse_bool(str)) + use_rtkit = false; + impl = calloc(1, sizeof(struct impl)); if (impl == NULL) return -ENOMEM; - pw_log_debug("module %p: new %s", impl, args); + spa_list_init(&impl->threads_list); + pthread_mutex_init(&impl->lock, NULL); + pthread_cond_init(&impl->cond, NULL); + + pw_log_debug("module %p: new", impl); - impl->context = context; props = args ? pw_properties_new_string(args) : pw_properties_new(NULL, NULL); - if (props == NULL) { + if (!props) { res = -errno; goto error; } - nice_level = pw_properties_get_int32(props, "nice.level", DEFAULT_NICE_LEVEL); - set_nice(impl, nice_level); - + impl->context = context; + impl->nice_level = pw_properties_get_int32(props, "nice.level", DEFAULT_NICE_LEVEL); impl->rt_prio = pw_properties_get_int32(props, "rt.prio", DEFAULT_RT_PRIO); impl->rt_time_soft = pw_properties_get_int32(props, "rt.time.soft", DEFAULT_RT_TIME_SOFT); impl->rt_time_hard = pw_properties_get_int32(props, "rt.time.hard", DEFAULT_RT_TIME_HARD); + /* If the user has permissions to use regular realtime scheduling, then + * we'll use that instead of RTKit */ + if (check_realtime_priviliges(impl->rt_prio)) { + use_rtkit = false; + } else { + if (!use_rtkit) { + res = -ENOTSUP; + pw_log_warn("neither regular realtime scheduling nor RTKit are available"); + goto error; + } + + /* TODO: Should this be pw_log_warn or pw_log_debug instead? */ + pw_log_info("could not use realtime scheduling, falling back to using RTKit instead"); + } + + impl->use_rtkit = use_rtkit; + if (impl->use_rtkit) { + impl->system_bus = pw_rtkit_bus_get_system(); + if (impl->system_bus == NULL) { + res = -errno; + pw_log_warn("could not get system bus: %m"); + goto error; + } + } + + if (IS_VALID_NICE_LEVEL(impl->nice_level)) + set_nice(impl, impl->nice_level); set_rlimit(impl); impl->thread_utils.iface = SPA_INTERFACE_INIT( SPA_TYPE_INTERFACE_ThreadUtils, SPA_VERSION_THREAD_UTILS, &impl_thread_utils, impl); - pw_thread_utils_set(&impl->thread_utils); pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl); pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props)); pw_impl_module_update_properties(module, &props->dict); - pw_properties_free(props); - return 0; + if (impl->use_rtkit) { + pw_log_debug("initialized using RTKit"); + } else { + pw_log_debug("initialized using regular realtime scheduling"); + } + goto done; error: - pw_properties_free(props); + if (impl->system_bus) + pw_rtkit_bus_free(impl->system_bus); free(impl); +done: + pw_properties_free(props); + return res; }
View file
pipewire-0.3.44.tar.gz/src/modules/module-x11-bell.c
Added
@@ -0,0 +1,291 @@ +/* PipeWire + * + * Copyright © 2022 Wim Taymans <wim.taymans@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "config.h" + +#include <spa/utils/string.h> + +#include <X11/Xlib.h> +#include <X11/Xlib-xcb.h> +#include <X11/XKBlib.h> + +#include <canberra.h> + +#include "pipewire/pipewire.h" +#include "pipewire/impl.h" + +/** \page page_module_x11_bell PipeWire Module: X11 Bell + * + * The `x11-bell` module intercept the X11 bell events and uses libcanberra to + * play a sound. + * + * ## Module Options + * + * - `sink.name = <str>`: node.name of the sink to connect to + * - `sample.name = <str>`: the name of the sample to play, default 'bell-window-system' + * - `x11.display = <str>`: the X11 display to use + * - `x11.xauthority = <str>`: the X11 XAuthority string placed in XAUTHORITY env + * + * ## General options + * + * There are no general options for this module. + * + * ## Example configuration + *\code{.unparsed} + * context.modules = [ + * { name = libpipewire-x11-bell } + * args = { + * #sink.name = @DEFAULT_SINK@ + * sample.name = "bell-window-system" + * #x11.display = ":1" + * #x11.xauthority = "test" + * ] + *\endcode + * + */ + +#define NAME "x11-bell" + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +struct impl { + struct pw_context *context; + struct pw_thread_loop *thread_loop; + struct pw_loop *loop; + struct spa_source *source; + + struct pw_properties *properties; + + struct spa_hook module_listener; + + Display *display; + int xkb_event_base; +}; + +static int play_sample(struct impl *impl, const char *sample) +{ + int res; + ca_context *ca; + + if ((res = ca_context_create(&ca)) < 0) { + pw_log_error("canberra context create error: %s", ca_strerror(res)); + res = -EIO; + goto exit; + } + if ((res = ca_context_open(ca)) < 0) { + pw_log_error("canberra context open error: %s", ca_strerror(res)); + res = -EIO; + goto exit_destroy; + } + if ((res = ca_context_play(ca, 0, + CA_PROP_EVENT_ID, sample, + CA_PROP_MEDIA_NAME, "X11 bell event", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + NULL)) < 0) { + pw_log_warn("can't play sample (%s): %s", sample, ca_strerror(res)); + } + +exit_destroy: + ca_context_destroy(ca); +exit: + return res; +} +static void display_io(void *data, int fd, uint32_t mask) +{ + struct impl *impl = data; + XEvent e; + const char *sample = NULL; + + while (XPending(impl->display)) { + XNextEvent(impl->display, &e); + + if (((XkbEvent*) &e)->any.xkb_type != XkbBellNotify) + continue; + + if (impl->properties) + sample = pw_properties_get(impl->properties, "sample.name"); + if (sample == NULL) + sample = "bell-window-system"; + + pw_log_debug("play sample %s", sample); + play_sample(impl, sample); + } +} + +static void x11_close(struct impl *impl) +{ + if (impl->source) { + pw_loop_destroy_source(impl->loop, impl->source); + impl->source = NULL; + } + if (impl->display) { + XCloseDisplay(impl->display); + impl->display = NULL; + } +} + +static int x11_connect(struct impl *impl, const char *name) +{ + int res, major, minor; + unsigned int auto_ctrls, auto_values; + + if (!(impl->display = XOpenDisplay(name))) { + pw_log_warn("XOpenDisplay() failed"); + res = -EIO; + goto error; + } + + impl->source = pw_loop_add_io(impl->loop, + ConnectionNumber(impl->display), + SPA_IO_IN, false, display_io, impl); + + major = XkbMajorVersion; + minor = XkbMinorVersion; + + if (!XkbLibraryVersion(&major, &minor)) { + pw_log_warn("XkbLibraryVersion() failed"); + res = -EIO; + goto error; + } + + major = XkbMajorVersion; + minor = XkbMinorVersion; + + if (!XkbQueryExtension(impl->display, NULL, &impl->xkb_event_base, + NULL, &major, &minor)) { + res = -EIO; + pw_log_warn("XkbQueryExtension() failed"); + goto error; + } + + XkbSelectEvents(impl->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask); + auto_ctrls = auto_values = XkbAudibleBellMask; + XkbSetAutoResetControls(impl->display, XkbAudibleBellMask, &auto_ctrls, &auto_values); + XkbChangeEnabledControls(impl->display, XkbUseCoreKbd, XkbAudibleBellMask, 0); + + res = 0; +error: + if (res < 0) + x11_close(impl); + return res; +} + +static void module_destroy(void *data) +{ + struct impl *impl = data; + + spa_hook_remove(&impl->module_listener); + + if (impl->thread_loop) + pw_thread_loop_lock(impl->thread_loop); + + x11_close(impl); + + if (impl->thread_loop) { + pw_thread_loop_unlock(impl->thread_loop); + pw_thread_loop_destroy(impl->thread_loop); + } + + pw_properties_free(impl->properties); + + free(impl); +} + +static const struct pw_impl_module_events module_events = { + PW_VERSION_IMPL_MODULE_EVENTS, + .destroy = module_destroy, +}; + +static const struct spa_dict_item module_x11_bell_info[] = { + { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, + { PW_KEY_MODULE_DESCRIPTION, "X11 Bell interceptor" }, + { PW_KEY_MODULE_USAGE, "sink.name=<name for the sink> " + "sample.name=<the sample name> " + "x11.display=<the X11 display> " + "x11.xauthority=<the X11 XAuthority> " }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; +SPA_EXPORT +int pipewire__module_init(struct pw_impl_module *module, const char *args) +{ + struct pw_context *context = pw_impl_module_get_context(module); + struct impl *impl; + const char *name = NULL, *str; + int res; + + PW_LOG_TOPIC_INIT(mod_topic); + + impl = calloc(1, sizeof(struct impl)); + if (impl == NULL) + return -ENOMEM; + + pw_log_debug("module %p: new", impl); + + impl->context = context; + impl->thread_loop = pw_thread_loop_new("X11 Bell", NULL); + if (impl->thread_loop == NULL) { + res = -errno; + pw_log_error("can't create thread loop: %m"); + goto error; + } + impl->loop = pw_thread_loop_get_loop(impl->thread_loop); + impl->properties = args ? pw_properties_new_string(args) : NULL; + + pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl); + pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_x11_bell_info)); + + if (impl->properties) { + if ((str = pw_properties_get(impl->properties, "x11.xauthority")) != NULL) { + if (setenv("XAUTHORITY", str, 1)) { + res = -errno; + pw_log_error("XAUTHORITY setenv failed: %m"); + goto error; + } + } + name = pw_properties_get(impl->properties, "x11.display"); + } + + /* we need to use a thread loop because this module will connect + * to pipewire eventually and will then block the mainloop. */ + pw_thread_loop_start(impl->thread_loop); + + pw_thread_loop_lock(impl->thread_loop); + x11_connect(impl, name); + pw_thread_loop_unlock(impl->thread_loop); + + return 0; +error: + module_destroy(impl); + return res; + +}
View file
pipewire-0.3.43.tar.gz/src/modules/spa/spa-node.c -> pipewire-0.3.44.tar.gz/src/modules/spa/spa-node.c
Changed
@@ -242,6 +242,13 @@ int res; struct spa_handle *handle; void *iface; + const struct pw_properties *p; + + if (properties) { + p = pw_context_get_properties(context); + pw_properties_set(properties, "clock.quantum-limit", + pw_properties_get(p, "default.clock.quantum-limit")); + } handle = pw_context_load_spa_handle(context, factory_name,
View file
pipewire-0.3.43.tar.gz/src/pipewire/conf.c -> pipewire-0.3.44.tar.gz/src/pipewire/conf.c
Changed
@@ -49,7 +49,7 @@ PW_LOG_TOPIC_EXTERN(log_conf); #define PW_LOG_TOPIC_DEFAULT log_conf -static int make_path(char *path, int size, const char *paths[]) +static int make_path(char *path, size_t size, const char *paths[]) { int i, len; char *p = path; @@ -57,7 +57,7 @@ len = snprintf(p, size, "%s%s", i == 0 ? "" : "/", paths[i]); if (len < 0) return -errno; - if (len >= size) + if ((size_t)len >= size) return -ENOSPC; p += len; size -= len;
View file
pipewire-0.3.43.tar.gz/src/pipewire/context.c -> pipewire-0.3.44.tar.gz/src/pipewire/context.c
Changed
@@ -134,7 +134,8 @@ res = pw_thread_utils_drop_rt(thr); } else { pw_log_info("%p: exit freewheel", context); - res = pw_thread_utils_acquire_rt(thr, 88); + // Use the priority as configured within the realtime module + res = pw_thread_utils_acquire_rt(thr, -1); } if (res < 0) pw_log_info("%p: freewheel error:%s", context, spa_strerror(res)); @@ -893,24 +894,31 @@ return pw_impl_node_set_state(node, state); } -static int collect_nodes(struct pw_context *context, struct pw_impl_node *driver) +static int collect_nodes(struct pw_context *context, struct pw_impl_node *node) { struct spa_list queue; - struct pw_impl_node *n, *t; + struct pw_impl_node *n, *t, *driver; struct pw_impl_port *p; struct pw_impl_link *l; - spa_list_consume(t, &driver->follower_list, follower_link) { - spa_list_remove(&t->follower_link); - spa_list_init(&t->follower_link); - } + pw_log_debug("node %p: '%s'", node, node->name); - pw_log_debug("driver %p: '%s'", driver, driver->name); + if (node->driver) { + driver = node; + spa_list_consume(t, &driver->follower_list, follower_link) { + spa_list_remove(&t->follower_link); + spa_list_init(&t->follower_link); + } + } else { + driver = node->driver_node; + if (driver == NULL) + return -EINVAL; + } - /* start with driver in the queue */ + /* start with node in the queue */ spa_list_init(&queue); - spa_list_append(&queue, &driver->sort_link); - driver->visited = true; + spa_list_append(&queue, &node->sort_link); + node->visited = true; /* now follow all the links from the nodes in the queue * and add the peers to the queue. */ @@ -980,26 +988,32 @@ } static inline void get_quantums(struct pw_context *context, uint32_t *def, - uint32_t *min, uint32_t *max, uint32_t *rate) + uint32_t *min, uint32_t *max, uint32_t *limit, uint32_t *rate) { struct settings *s = &context->settings; - *def = s->clock_force_quantum == 0 ? s->clock_quantum : s->clock_force_quantum; - *min = s->clock_force_quantum == 0 ? s->clock_min_quantum : s->clock_force_quantum; - *max = s->clock_force_quantum == 0 ? s->clock_max_quantum : s->clock_force_quantum; - *rate = s->clock_force_quantum == 0 ? s->clock_rate : s->clock_force_rate; + if (s->clock_force_quantum != 0) { + *def = *min = *max = s->clock_force_quantum; + *rate = 0; + } else { + *def = s->clock_quantum; + *min = s->clock_min_quantum; + *max = s->clock_max_quantum; + *rate = s->clock_rate; + } + *limit = s->clock_quantum_limit; } static inline uint32_t *get_rates(struct pw_context *context, uint32_t *def, uint32_t *n_rates, - bool *force_rate) + bool *force) { struct settings *s = &context->settings; if (s->clock_force_rate != 0) { - *force_rate = true; + *force = true; *n_rates = 1; *def = s->clock_force_rate; return &s->clock_force_rate; } else { - *force_rate = false; + *force = false; *n_rates = s->n_clock_rates; *def = s->clock_rate; return s->clock_rates; @@ -1053,7 +1067,7 @@ { struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this); struct pw_impl_node *n, *s, *target, *fallback; - uint32_t max_quantum, min_quantum, def_quantum, rate_quantum; + uint32_t max_quantum, min_quantum, def_quantum, lim_quantum, rate_quantum; uint32_t *rates, n_rates, def_rate; bool freewheel = false, force_rate; @@ -1067,7 +1081,7 @@ again: impl->recalc = true; - get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &rate_quantum); + get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &lim_quantum, &rate_quantum); rates = get_rates(context, &def_rate, &n_rates, &force_rate); /* start from all drivers and group all nodes that are linked @@ -1135,8 +1149,10 @@ pw_impl_node_set_driver(n, t); if (t == NULL) ensure_state(n, false); - else + else { t->passive = false; + collect_nodes(context, n); + } } n->visited = false; } @@ -1221,6 +1237,7 @@ if (rate_quantum != 0 && current_rate != rate_quantum) { def_quantum = def_quantum * current_rate / rate_quantum; min_quantum = min_quantum * current_rate / rate_quantum; + max_quantum = max_quantum * current_rate / rate_quantum; } /* calculate desired quantum */ @@ -1234,6 +1251,7 @@ if (latency.denom != 0) quantum = (latency.num * current_rate / latency.denom); quantum = SPA_CLAMP(quantum, min_quantum, max_quantum); + quantum = SPA_MIN(quantum, lim_quantum); if (context->settings.clock_power_of_two_quantum) quantum = flp2(quantum);
View file
pipewire-0.3.43.tar.gz/src/pipewire/filter.c -> pipewire-0.3.44.tar.gz/src/pipewire/filter.c
Changed
@@ -52,7 +52,6 @@ #define MASK_BUFFERS (MAX_BUFFERS-1) #define MAX_PORTS 1024 -static float empty[MAX_SAMPLES]; static bool mlock_warned = false; static uint32_t mappable_dataTypes = (1<<SPA_DATA_MemFd); @@ -1223,6 +1222,17 @@ } if ((str = getenv("PIPEWIRE_LATENCY")) != NULL) pw_properties_set(props, PW_KEY_NODE_LATENCY, str); + if ((str = getenv("PIPEWIRE_RATE")) != NULL) + pw_properties_set(props, PW_KEY_NODE_RATE, str); + if ((str = getenv("PIPEWIRE_QUANTUM")) != NULL) { + struct spa_fraction q; + if (sscanf(str, "%u/%u", &q.num, &q.denom) == 2 && q.denom != 0) { + pw_properties_setf(props, PW_KEY_NODE_RATE, + "1/%u", q.denom); + pw_properties_setf(props, PW_KEY_NODE_LATENCY, + "%u/%u", q.num, q.denom); + } + } spa_hook_list_init(&impl->hooks); this->properties = props; @@ -1860,7 +1870,7 @@ struct spa_data *d; if ((buf = pw_filter_dequeue_buffer(port_data)) == NULL) - return empty; + return NULL; d = &buf->buffer->datas[0];
View file
pipewire-0.3.43.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-link.c
Changed
@@ -451,7 +451,7 @@ return res; } -static int select_io(struct pw_impl_link *this) +static void select_io(struct pw_impl_link *this) { struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this); struct spa_io_buffers *io; @@ -461,13 +461,9 @@ io = this->rt.out_mix.io; if (io == NULL) io = &impl->io; - if (io == NULL) - return -EIO; this->io = io; *this->io = SPA_IO_BUFFERS_INIT; - - return 0; } static int do_allocation(struct pw_impl_link *this) @@ -1133,7 +1129,7 @@ if (check_permission(this->context, this->output, this->input, this->properties) < 0) { pw_impl_link_destroy(this); - } else { + } else if (this->global != NULL) { pw_global_update_permissions(this->global, client, old, new); } } @@ -1229,6 +1225,16 @@ spa_hook_list_init(&this->listener_list); impl->format_filter = format_filter; + this->info.format = NULL; + this->info.props = &this->properties->dict; + + this->rt.out_mix.peer_id = input->global->id; + this->rt.in_mix.peer_id = output->global->id; + + if ((res = pw_impl_port_init_mix(output, &this->rt.out_mix)) < 0) + goto error_output_mix; + if ((res = pw_impl_port_init_mix(input, &this->rt.in_mix)) < 0) + goto error_input_mix; pw_impl_port_add_listener(input, &impl->input_port_listener, &input_port_events, impl); pw_impl_node_add_listener(input_node, &impl->input_node_listener, &input_node_events, impl); @@ -1245,19 +1251,9 @@ spa_list_append(&output->links, &this->output_link); spa_list_append(&input->links, &this->input_link); - this->info.format = NULL; - this->info.props = &this->properties->dict; - impl->io = SPA_IO_BUFFERS_INIT; - this->rt.out_mix.peer_id = input->global->id; - this->rt.in_mix.peer_id = output->global->id; - - pw_impl_port_init_mix(output, &this->rt.out_mix); - pw_impl_port_init_mix(input, &this->rt.in_mix); - - if ((res = select_io(this)) < 0) - goto error_no_io; + select_io(this); if (this->feedback) { impl->inode = output_node; @@ -1317,8 +1313,12 @@ res = -errno; pw_log_debug("work queue failed: %m"); goto error_free; -error_no_io: - pw_log_debug("%p: can't set io %d (%s)", this, res, spa_strerror(res)); +error_output_mix: + pw_log_error("%p: can't get output mix %d (%s)", this, res, spa_strerror(res)); + goto error_free; +error_input_mix: + pw_log_error("%p: can't get input mix %d (%s)", this, res, spa_strerror(res)); + pw_impl_port_release_mix(output, &this->rt.out_mix); goto error_free; error_free: free(impl);
View file
pipewire-0.3.43.tar.gz/src/pipewire/impl-metadata.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-metadata.c
Changed
@@ -523,14 +523,15 @@ int pw_impl_metadata_register(struct pw_impl_metadata *metadata, struct pw_properties *properties) { + struct pw_context *context = metadata->context; static const char * const keys[] = { + PW_KEY_OBJECT_SERIAL, PW_KEY_MODULE_ID, + PW_KEY_FACTORY_ID, PW_KEY_METADATA_NAME, NULL }; - struct pw_context *context = metadata->context; - if (metadata->registered) goto error_existed;
View file
pipewire-0.3.43.tar.gz/src/pipewire/impl-module.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-module.c
Changed
@@ -171,6 +171,11 @@ const char *state = NULL, *p; size_t len; char path_part[PATH_MAX]; + static const char * const keys[] = { + PW_KEY_OBJECT_SERIAL, + PW_KEY_MODULE_NAME, + NULL + }; module_dir = getenv("PIPEWIRE_MODULE_DIR"); if (module_dir == NULL) { @@ -234,9 +239,7 @@ this->global = pw_global_new(context, PW_TYPE_INTERFACE_Module, PW_VERSION_MODULE, - pw_properties_new( - PW_KEY_MODULE_NAME, name, - NULL), + NULL, global_bind, this); @@ -251,6 +254,8 @@ pw_global_get_serial(this->global)); this->info.props = &this->properties->dict; + pw_global_update_keys(this->global, &this->properties->dict, keys); + pw_impl_module_emit_initialized(this); pw_global_add_listener(this->global, &this->global_listener, &global_events, this);
View file
pipewire-0.3.43.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-node.c
Changed
@@ -59,6 +59,7 @@ struct spa_list pending_list; unsigned int pause_on_idle:1; + unsigned int suspend_on_idle:1; unsigned int cache_params:1; unsigned int pending_play:1; }; @@ -387,6 +388,10 @@ spa_list_for_each(resource, &node->global->resource_list, link) pw_resource_error(resource, res, error); } + if (old == PW_NODE_STATE_RUNNING && + state == PW_NODE_STATE_IDLE && + impl->suspend_on_idle) + pw_impl_node_set_state(node, PW_NODE_STATE_SUSPENDED); } static int suspend_node(struct pw_impl_node *this) @@ -867,8 +872,9 @@ } impl->pause_on_idle = pw_properties_get_bool(node->properties, PW_KEY_NODE_PAUSE_ON_IDLE, true); + impl->suspend_on_idle = pw_properties_get_bool(node->properties, PW_KEY_NODE_SUSPEND_ON_IDLE, false); impl->cache_params = pw_properties_get_bool(node->properties, PW_KEY_NODE_CACHE_PARAMS, true); - node->transport_sync = pw_properties_get_bool(node->properties, "node.transport.sync", false); + node->transport_sync = pw_properties_get_bool(node->properties, PW_KEY_NODE_TRANSPORT_SYNC, false); driver = pw_properties_get_bool(node->properties, PW_KEY_NODE_DRIVER, false); if (node->driver != driver) { @@ -1654,6 +1660,16 @@ if (SPA_UNLIKELY(node->driver && !node->driving)) return 0; + if (!node->driver) { + struct timespec ts; + struct pw_node_activation *a = node->rt.activation; + struct spa_system *data_system = node->context->data_system; + + spa_system_clock_gettime(data_system, CLOCK_MONOTONIC, &ts); + a->status = PW_NODE_ACTIVATION_AWAKE; + a->signal_time = a->awake_time = SPA_TIMESPEC_TO_NSEC(&ts); + } + if (status & SPA_STATUS_HAVE_DATA) { spa_list_for_each(p, &node->rt.output_mix, rt.node_link) spa_node_process(p->mix);
View file
pipewire-0.3.43.tar.gz/src/pipewire/impl-port.c -> pipewire-0.3.44.tar.gz/src/pipewire/impl-port.c
Changed
@@ -214,16 +214,16 @@ if (port_id == SPA_ID_INVALID) return -errno; + if ((res = spa_node_add_port(port->mix, port->direction, port_id, NULL)) < 0 && + res != -ENOTSUP) + goto error_remove_map; + mix->port.direction = port->direction; mix->port.port_id = port_id; - - spa_list_append(&port->mix_list, &mix->link); - port->n_mix++; mix->p = port; - spa_node_add_port(port->mix, port->direction, port_id, NULL); - - res = pw_impl_port_call_init_mix(port, mix); + if ((res = pw_impl_port_call_init_mix(port, mix)) < 0) + goto error_remove_port; /* set the same format on the mixer as on the port if any */ { @@ -242,11 +242,20 @@ } } + spa_list_append(&port->mix_list, &mix->link); + port->n_mix++; + pw_log_debug("%p: init mix n_mix:%d %d.%d io:%p: (%s)", port, port->n_mix, port->port_id, mix->port.port_id, mix->io, spa_strerror(res)); return res; + +error_remove_port: + spa_node_remove_port(port->mix, port->direction, port_id); +error_remove_map: + pw_map_remove(&port->mix_port_map, port_id); + return res; } SPA_EXPORT @@ -261,7 +270,9 @@ res = pw_impl_port_call_release_mix(port, mix); - spa_node_remove_port(port->mix, port->direction, port_id); + if ((res = spa_node_remove_port(port->mix, port->direction, port_id)) < 0 && + res != -ENOTSUP) + pw_log_warn("can't remove mix port %d: %s", port_id, spa_strerror(res)); pw_log_debug("%p: release mix %d %d.%d", port, port->n_mix, port->port_id, mix->port.port_id); @@ -583,8 +594,10 @@ int res; const char *fallback_lib, *factory_name; struct spa_handle *handle; - struct spa_dict_item items[1]; + struct spa_dict_item items[2]; + char quantum_limit[16]; void *iface; + struct pw_context *context = port->node->context; if ((res = spa_format_parse(param, &media_type, &media_subtype)) < 0) return res; @@ -634,7 +647,11 @@ } items[0] = SPA_DICT_ITEM_INIT(SPA_KEY_LIBRARY_NAME, fallback_lib); - handle = pw_context_load_spa_handle(port->node->context, factory_name, + spa_scnprintf(quantum_limit, sizeof(quantum_limit), "%u", + context->settings.clock_quantum_limit); + items[1] = SPA_DICT_ITEM_INIT("clock.quantum-limit", quantum_limit); + + handle = pw_context_load_spa_handle(context, factory_name, &SPA_DICT_INIT_ARRAY(items)); if (handle == NULL) return -errno; @@ -1070,10 +1087,12 @@ } if (port->direction == PW_DIRECTION_INPUT) { - pw_map_insert_at(&node->input_port_map, port->port_id, NULL); + if ((res = pw_map_insert_at(&node->input_port_map, port->port_id, NULL)) < 0) + pw_log_warn("%p: can't remove input port: %s", port, spa_strerror(res)); node->info.n_input_ports--; } else { - pw_map_insert_at(&node->output_port_map, port->port_id, NULL); + if ((res = pw_map_insert_at(&node->output_port_map, port->port_id, NULL)) < 0) + pw_log_warn("%p: can't remove output port: %s", port, spa_strerror(res)); node->info.n_output_ports--; }
View file
pipewire-0.3.43.tar.gz/src/pipewire/keys.h -> pipewire-0.3.44.tar.gz/src/pipewire/keys.h
Changed
@@ -171,7 +171,9 @@ #define PW_KEY_NODE_WANT_DRIVER "node.want-driver" /**< the node wants to be grouped with a driver * node in order to schedule the graph. */ #define PW_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< pause the node when idle */ +#define PW_KEY_NODE_SUSPEND_ON_IDLE "node.suspend-on-idle" /**< suspend the node when idle */ #define PW_KEY_NODE_CACHE_PARAMS "node.cache-params" /**< cache the node params */ +#define PW_KEY_NODE_TRANSPORT_SYNC "node.transport.sync" /**< the node handles transport sync */ #define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph */ #define PW_KEY_NODE_STREAM "node.stream" /**< node is a stream, the server side should * add a converter */ @@ -326,6 +328,8 @@ #define PW_KEY_PRIORITY_MASTER "priority.master" /**< deprecated */ #endif /* PW_ENABLE_DEPRECATED */ +#define PW_KEY_TARGET_OBJECT "target.object" /**< a target object to link to */ + /** \} */
View file
pipewire-0.3.43.tar.gz/src/pipewire/private.h -> pipewire-0.3.44.tar.gz/src/pipewire/private.h
Changed
@@ -51,7 +51,7 @@ #define MAX_RATES 16u #define CLOCK_MIN_QUANTUM 4u -#define CLOCK_MAX_QUANTUM 8192u +#define CLOCK_MAX_QUANTUM 65536u struct settings { uint32_t log_level; @@ -61,12 +61,15 @@ uint32_t clock_quantum; /* default quantum */ uint32_t clock_min_quantum; /* min quantum */ uint32_t clock_max_quantum; /* max quantum */ + uint32_t clock_quantum_limit; /* quantum limit */ struct spa_rectangle video_size; struct spa_fraction video_rate; uint32_t link_max_buffers; unsigned int mem_warn_mlock:1; unsigned int mem_allow_mlock:1; unsigned int clock_power_of_two_quantum:1; + unsigned int check_quantum:1; + unsigned int check_rate:1; #define CLOCK_RATE_UPDATE_MODE_HARD 0 #define CLOCK_RATE_UPDATE_MODE_SOFT 1 int clock_rate_update_mode;
View file
pipewire-0.3.43.tar.gz/src/pipewire/settings.c -> pipewire-0.3.44.tar.gz/src/pipewire/settings.c
Changed
@@ -43,7 +43,8 @@ #define DEFAULT_CLOCK_RATE 48000u #define DEFAULT_CLOCK_QUANTUM 1024u #define DEFAULT_CLOCK_MIN_QUANTUM 32u -#define DEFAULT_CLOCK_MAX_QUANTUM 8192u +#define DEFAULT_CLOCK_MAX_QUANTUM 2048u +#define DEFAULT_CLOCK_QUANTUM_LIMIT 8192u #define DEFAULT_CLOCK_POWER_OF_TWO_QUANTUM true #define DEFAULT_VIDEO_WIDTH 640 #define DEFAULT_VIDEO_HEIGHT 480 @@ -52,6 +53,8 @@ #define DEFAULT_LINK_MAX_BUFFERS 64u #define DEFAULT_MEM_WARN_MLOCK false #define DEFAULT_MEM_ALLOW_MLOCK true +#define DEFAULT_CHECK_QUANTUM false +#define DEFAULT_CHECK_RATE false struct impl { struct pw_context *context; @@ -184,12 +187,23 @@ recalc = true; } else if (spa_streq(key, "clock.force-rate")) { v = value ? atoi(value) : 0; - s->clock_force_rate = v; - recalc = true; + if (v != 0 && s->check_rate && + !uint32_array_contains(s->clock_rates, s->n_clock_rates, v)) { + pw_log_info("invalid %s: %d not in allowed rates", key, v); + } else { + s->clock_force_rate = v; + recalc = true; + } } else if (spa_streq(key, "clock.force-quantum")) { v = value ? atoi(value) : 0; - s->clock_force_quantum = SPA_MIN(v, 8192u); - recalc = true; + if (v != 0 && s->check_quantum && + (v < s->clock_min_quantum || v > s->clock_max_quantum)) { + pw_log_info("invalid %s: %d not in (%d-%d)", key, v, + s->clock_min_quantum, s->clock_max_quantum); + } else { + s->clock_force_quantum = v; + recalc = true; + } } if (recalc) pw_context_recalc_graph(context, "settings changed"); @@ -213,6 +227,7 @@ d->clock_quantum = get_default_int(p, "default.clock.quantum", DEFAULT_CLOCK_QUANTUM); d->clock_min_quantum = get_default_int(p, "default.clock.min-quantum", DEFAULT_CLOCK_MIN_QUANTUM); d->clock_max_quantum = get_default_int(p, "default.clock.max-quantum", DEFAULT_CLOCK_MAX_QUANTUM); + d->clock_quantum_limit = get_default_int(p, "default.clock.quantum-limit", DEFAULT_CLOCK_QUANTUM_LIMIT); d->video_size.width = get_default_int(p, "default.video.width", DEFAULT_VIDEO_WIDTH); d->video_size.height = get_default_int(p, "default.video.height", DEFAULT_VIDEO_HEIGHT); d->video_rate.num = get_default_int(p, "default.video.rate.num", DEFAULT_VIDEO_RATE_NUM); @@ -225,8 +240,13 @@ d->mem_warn_mlock = get_default_bool(p, "mem.warn-mlock", DEFAULT_MEM_WARN_MLOCK); d->mem_allow_mlock = get_default_bool(p, "mem.allow-mlock", DEFAULT_MEM_ALLOW_MLOCK); - d->clock_max_quantum = SPA_CLAMP(d->clock_max_quantum, + d->check_quantum = get_default_bool(p, "settings.check-quantum", DEFAULT_CHECK_QUANTUM); + d->check_rate = get_default_bool(p, "settings.check-rate", DEFAULT_CHECK_RATE); + + d->clock_quantum_limit = SPA_CLAMP(d->clock_quantum_limit, CLOCK_MIN_QUANTUM, CLOCK_MAX_QUANTUM); + d->clock_max_quantum = SPA_CLAMP(d->clock_max_quantum, + CLOCK_MIN_QUANTUM, d->clock_quantum_limit); d->clock_min_quantum = SPA_CLAMP(d->clock_min_quantum, CLOCK_MIN_QUANTUM, d->clock_max_quantum); d->clock_quantum = SPA_CLAMP(d->clock_quantum,
View file
pipewire-0.3.43.tar.gz/src/pipewire/stream.c -> pipewire-0.3.44.tar.gz/src/pipewire/stream.c
Changed
@@ -1358,6 +1358,17 @@ } if ((str = getenv("PIPEWIRE_LATENCY")) != NULL) pw_properties_set(props, PW_KEY_NODE_LATENCY, str); + if ((str = getenv("PIPEWIRE_RATE")) != NULL) + pw_properties_set(props, PW_KEY_NODE_RATE, str); + if ((str = getenv("PIPEWIRE_QUANTUM")) != NULL) { + struct spa_fraction q; + if (sscanf(str, "%u/%u", &q.num, &q.denom) == 2 && q.denom != 0) { + pw_properties_setf(props, PW_KEY_NODE_RATE, + "1/%u", q.denom); + pw_properties_setf(props, PW_KEY_NODE_LATENCY, + "%u/%u", q.num, q.denom); + } + } spa_hook_list_init(&impl->hooks); this->properties = props;
View file
pipewire-0.3.43.tar.gz/src/tests/meson.build -> pipewire-0.3.44.tar.gz/src/tests/meson.build
Changed
@@ -13,9 +13,9 @@ install : installed_tests_enabled, install_dir : installed_tests_execdir), env : [ - 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable(internal: 'plugindir')), - 'PIPEWIRE_CONFIG_DIR=@0@'.format(pipewire_dep.get_variable(internal: 'confdatadir')), - 'PIPEWIRE_MODULE_DIR=@0@'.format(pipewire_dep.get_variable(internal: 'moduledir')), + 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')), + 'PIPEWIRE_CONFIG_DIR=@0@'.format(pipewire_dep.get_variable('confdatadir')), + 'PIPEWIRE_MODULE_DIR=@0@'.format(pipewire_dep.get_variable('moduledir')), ]) if installed_tests_enabled
View file
pipewire-0.3.43.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.44.tar.gz/src/tools/pw-cat.c
Changed
@@ -1906,9 +1906,10 @@ spa_list_for_each(target, &data.targets, link) { if (target->type != TARGET_TYPE_SINK) continue; - printf("%s\t%"PRIu32": sink description=\"%s\" prio=%d\n", - target == target_default ? "*" : "", - target->id, target->desc, target->prio); + printf("%s\t%"PRIu32": %s description=\"%s\" prio=%d\n", + target == target_default ? "*" : "", + target->id, data.mode == mode_record ? "monitor" : "sink", + target->desc, target->prio); } spa_list_for_each(target, &data.targets, link) { if (target->type != TARGET_TYPE_STREAM)
View file
pipewire-0.3.43.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.44.tar.gz/src/tools/pw-cli.c
Changed
@@ -32,6 +32,7 @@ #include <alloca.h> #endif #include <getopt.h> +#include <fnmatch.h> #include <readline/readline.h> #include <readline/history.h> @@ -41,7 +42,7 @@ #include <spa/utils/string.h> #include <spa/debug/pod.h> #include <spa/utils/keys.h> -#include <spa/utils/json.h> +#include <spa/utils/json-pod.h> #include <spa/pod/builder.h> #include <pipewire/impl.h> @@ -53,6 +54,18 @@ static char prompt[64]; struct remote_data; +struct proxy_data; + +typedef void (*info_func_t) (struct proxy_data *pd); + +struct class { + const char *type; + uint32_t version; + const void *events; + pw_destroy_t destroy; + info_func_t info; + const char *name_key; +}; struct data { struct pw_main_loop *loop; @@ -73,6 +86,7 @@ uint32_t permissions; uint32_t version; char *type; + const struct class *class; struct pw_proxy *proxy; bool info_pending; struct pw_properties *properties; @@ -96,19 +110,15 @@ struct pw_map globals; }; -struct proxy_data; - -typedef void (*info_func_t) (struct proxy_data *pd); struct proxy_data { struct remote_data *rd; struct global *global; struct pw_proxy *proxy; - void *info; - info_func_t info_func; - pw_destroy_t destroy; - struct spa_hook proxy_listener; - struct spa_hook object_listener; + void *info; + const struct class *class; + struct spa_hook proxy_listener; + struct spa_hook object_listener; }; struct command { @@ -303,6 +313,29 @@ } } +static bool global_matches(struct global *g, const char *pattern) +{ + const char *str; + + if (g->properties == NULL) + return false; + + if (strstr(g->type, pattern) != NULL) + return true; + if ((str = pw_properties_get(g->properties, PW_KEY_OBJECT_PATH)) != NULL && + fnmatch(pattern, str, FNM_EXTMATCH) == 0) + return true; + if ((str = pw_properties_get(g->properties, PW_KEY_OBJECT_SERIAL)) != NULL && + spa_streq(pattern, str)) + return true; + if (g->class != NULL && g->class->name_key != NULL && + (str = pw_properties_get(g->properties, g->class->name_key)) != NULL && + fnmatch(pattern, str, FNM_EXTMATCH) == 0) + return true; + + return false; +} + static int print_global(void *obj, void *data) { struct global *global = obj; @@ -311,7 +344,7 @@ if (global == NULL) return 0; - if (filter && !strstr(global->type, filter)) + if (filter && !global_matches(global, filter)) return 0; fprintf(stdout, "\tid %d, type %s/%d\n", global->id, @@ -403,6 +436,24 @@ .global_remove = registry_event_global_remove, }; +static struct global *find_global(struct remote_data *rd, const char *pattern) +{ + uint32_t id; + union pw_map_item *item; + + if (spa_atou32(pattern, &id, 0)) + return pw_map_lookup(&rd->globals, id); + + pw_array_for_each(item, &rd->globals.items) { + struct global *g = item->data; + if (pw_map_item_is_free(item) || g == NULL) + continue; + if (global_matches(g, pattern)) + return g; + } + return NULL; +} + static void on_core_error(void *_data, uint32_t id, int seq, int res, const char *message) { struct remote_data *rd = _data; @@ -1106,14 +1157,14 @@ spa_hook_remove(&pd->proxy_listener); spa_hook_remove(&pd->object_listener); - if (pd->info == NULL) - return; - if (pd->global) pd->global->proxy = NULL; - if (pd->destroy) - pd->destroy(pd->info); + if (pd->info == NULL) + return; + + if (pd->class->destroy) + pd->class->destroy(pd->info); pd->info = NULL; } @@ -1130,88 +1181,150 @@ return true; } +static const struct class core_class = { + .type = PW_TYPE_INTERFACE_Core, + .version = PW_VERSION_CORE, + .events = &core_events, + .destroy = (pw_destroy_t) pw_core_info_free, + .info = info_core, + .name_key = PW_KEY_CORE_NAME, +}; +static const struct class module_class = { + .type = PW_TYPE_INTERFACE_Module, + .version = PW_VERSION_MODULE, + .events = &module_events, + .destroy = (pw_destroy_t) pw_module_info_free, + .info = info_module, + .name_key = PW_KEY_MODULE_NAME, +}; + +static const struct class factory_class = { + .type = PW_TYPE_INTERFACE_Factory, + .version = PW_VERSION_FACTORY, + .events = &factory_events, + .destroy = (pw_destroy_t) pw_factory_info_free, + .info = info_factory, + .name_key = PW_KEY_FACTORY_NAME, +}; + +static const struct class client_class = { + .type = PW_TYPE_INTERFACE_Client, + .version = PW_VERSION_CLIENT, + .events = &client_events, + .destroy = (pw_destroy_t) pw_client_info_free, + .info = info_client, + .name_key = PW_KEY_APP_NAME, +}; +static const struct class device_class = { + .type = PW_TYPE_INTERFACE_Device, + .version = PW_VERSION_DEVICE, + .events = &device_events, + .destroy = (pw_destroy_t) pw_device_info_free, + .info = info_device, + .name_key = PW_KEY_DEVICE_NAME, +}; +static const struct class node_class = { + .type = PW_TYPE_INTERFACE_Node, + .version = PW_VERSION_NODE, + .events = &node_events, + .destroy = (pw_destroy_t) pw_node_info_free, + .info = info_node, + .name_key = PW_KEY_NODE_NAME, +}; +static const struct class port_class = { + .type = PW_TYPE_INTERFACE_Port, + .version = PW_VERSION_PORT, + .events = &port_events, + .destroy = (pw_destroy_t) pw_port_info_free, + .info = info_port, + .name_key = PW_KEY_PORT_NAME, +}; +static const struct class link_class = { + .type = PW_TYPE_INTERFACE_Link, + .version = PW_VERSION_LINK, + .events = &link_events, + .destroy = (pw_destroy_t) pw_link_info_free, + .info = info_link, +}; +static const struct class session_class = { + .type = PW_TYPE_INTERFACE_Session, + .version = PW_VERSION_SESSION, + .events = &session_events, + .destroy = (pw_destroy_t) session_info_free, + .info = info_session, +}; +static const struct class endpoint_class = { + .type = PW_TYPE_INTERFACE_Endpoint, + .version = PW_VERSION_ENDPOINT, + .events = &endpoint_events, + .destroy = (pw_destroy_t) endpoint_info_free, + .info = info_endpoint, +}; +static const struct class endpoint_stream_class = { + .type = PW_TYPE_INTERFACE_EndpointStream, + .version = PW_VERSION_ENDPOINT_STREAM, + .events = &endpoint_stream_events, + .destroy = (pw_destroy_t) endpoint_stream_info_free, + .info = info_endpoint_stream, +}; +static const struct class metadata_class = { + .type = PW_TYPE_INTERFACE_Metadata, + .version = PW_VERSION_METADATA, + .name_key = PW_KEY_METADATA_NAME, +}; + +static const struct class *classes[] = +{ + &core_class, + &module_class, + &factory_class, + &client_class, + &device_class, + &node_class, + &port_class, + &link_class, + &session_class, + &endpoint_class, + &endpoint_stream_class, + &metadata_class, +}; + +static const struct class *find_class(const char *type, uint32_t version) +{ + size_t i; + for (i = 0; i < SPA_N_ELEMENTS(classes); i++) { + if (spa_streq(classes[i]->type, type) && + classes[i]->version <= version) + return classes[i]; + } + return NULL; +} + static bool bind_global(struct remote_data *rd, struct global *global, char **error) { - const void *events; - uint32_t client_version; - info_func_t info_func; - pw_destroy_t destroy; + const struct class *class; struct proxy_data *pd; struct pw_proxy *proxy; - if (spa_streq(global->type, PW_TYPE_INTERFACE_Core)) { - events = &core_events; - client_version = PW_VERSION_CORE; - destroy = (pw_destroy_t) pw_core_info_free; - info_func = info_core; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Module)) { - events = &module_events; - client_version = PW_VERSION_MODULE; - destroy = (pw_destroy_t) pw_module_info_free; - info_func = info_module; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Device)) { - events = &device_events; - client_version = PW_VERSION_DEVICE; - destroy = (pw_destroy_t) pw_device_info_free; - info_func = info_device; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Node)) { - events = &node_events; - client_version = PW_VERSION_NODE; - destroy = (pw_destroy_t) pw_node_info_free; - info_func = info_node; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Port)) { - events = &port_events; - client_version = PW_VERSION_PORT; - destroy = (pw_destroy_t) pw_port_info_free; - info_func = info_port; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Factory)) { - events = &factory_events; - client_version = PW_VERSION_FACTORY; - destroy = (pw_destroy_t) pw_factory_info_free; - info_func = info_factory; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Client)) { - events = &client_events; - client_version = PW_VERSION_CLIENT; - destroy = (pw_destroy_t) pw_client_info_free; - info_func = info_client; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Link)) { - events = &link_events; - client_version = PW_VERSION_LINK; - destroy = (pw_destroy_t) pw_link_info_free; - info_func = info_link; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Session)) { - events = &session_events; - client_version = PW_VERSION_SESSION; - destroy = (pw_destroy_t) session_info_free; - info_func = info_session; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Endpoint)) { - events = &endpoint_events; - client_version = PW_VERSION_ENDPOINT; - destroy = (pw_destroy_t) endpoint_info_free; - info_func = info_endpoint; - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_EndpointStream)) { - events = &endpoint_stream_events; - client_version = PW_VERSION_ENDPOINT_STREAM; - destroy = (pw_destroy_t) endpoint_stream_info_free; - info_func = info_endpoint_stream; - } else { + class = find_class(global->type, global->version); + if (class == NULL) { *error = spa_aprintf("unsupported type %s", global->type); return false; } + global->class = class; proxy = pw_registry_bind(rd->registry, global->id, global->type, - client_version, + class->version, sizeof(struct proxy_data)); pd = pw_proxy_get_user_data(proxy); pd->rd = rd; pd->global = global; pd->proxy = proxy; - pd->info_func = info_func; - pd->destroy = destroy; - pw_proxy_add_object_listener(proxy, &pd->object_listener, events, pd); + pd->class = class; + pw_proxy_add_object_listener(proxy, &pd->object_listener, class->events, pd); pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd); global->proxy = proxy; @@ -1232,8 +1345,8 @@ global->info_pending = true; } else { pd = pw_proxy_get_user_data(global->proxy); - if (pd->info_func) - pd->info_func(pd); + if (pd->class->info) + pd->class->info(pd); } return true; } @@ -1257,7 +1370,6 @@ struct remote_data *rd = data->current; char *a[1]; int n; - uint32_t id; struct global *global; n = pw_split_ip(args, WHITESPACE, 1, a); @@ -1269,10 +1381,9 @@ pw_map_for_each(&rd->globals, do_global_info_all, NULL); } else { - id = atoi(a[0]); - global = pw_map_lookup(&rd->globals, id); + global = find_global(rd, a[0]); if (global == NULL) { - *error = spa_aprintf("%s: unknown global %d", cmd, id); + *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]); return false; } return do_global_info(global, error); @@ -1309,7 +1420,7 @@ pd = pw_proxy_get_user_data(proxy); pd->rd = rd; pd->proxy = proxy; - pd->destroy = (pw_destroy_t) pw_device_info_free; + pd->class = &device_class; pw_proxy_add_object_listener(proxy, &pd->object_listener, &device_events, pd); pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd); @@ -1348,7 +1459,7 @@ pd = pw_proxy_get_user_data(proxy); pd->rd = rd; pd->proxy = proxy; - pd->destroy = (pw_destroy_t) pw_node_info_free; + pd->class = &node_class; pw_proxy_add_object_listener(proxy, &pd->object_listener, &node_events, pd); pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd); @@ -1363,7 +1474,6 @@ struct remote_data *rd = data->current; char *a[1]; int n; - uint32_t id; struct global *global; n = pw_split_ip(args, WHITESPACE, 1, a); @@ -1371,13 +1481,12 @@ *error = spa_aprintf("%s <object-id>", cmd); return false; } - id = atoi(a[0]); - global = pw_map_lookup(&rd->globals, id); + global = find_global(rd, a[0]); if (global == NULL) { - *error = spa_aprintf("%s: unknown global %d", cmd, id); + *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]); return false; } - pw_registry_destroy(rd->registry, id); + pw_registry_destroy(rd->registry, global->id); return true; } @@ -1423,7 +1532,7 @@ pd = pw_proxy_get_user_data(proxy); pd->rd = rd; pd->proxy = proxy; - pd->destroy = (pw_destroy_t) pw_link_info_free; + pd->class = &link_class; pw_proxy_add_object_listener(proxy, &pd->object_listener, &link_events, pd); pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd); @@ -1477,26 +1586,12 @@ return false; } -static const struct spa_type_info *find_type_info(const struct spa_type_info *info, const char *name) -{ - while (info && info->name) { - if (spa_streq(info->name, name)) - return info; - if (spa_streq(spa_debug_type_short_name(info->name), name)) - return info; - if (info->type != 0 && info->type == (uint32_t)atoi(name)) - return info; - info++; - } - return NULL; -} - static bool do_enum_params(struct data *data, const char *cmd, char *args, char **error) { struct remote_data *rd = data->current; char *a[2]; int n; - uint32_t id, param_id; + uint32_t param_id; const struct spa_type_info *ti; struct global *global; @@ -1506,17 +1601,16 @@ return false; } - id = atoi(a[0]); - ti = find_type_info(spa_type_param, a[1]); + ti = spa_debug_type_find_short(spa_type_param, a[1]); if (ti == NULL) { *error = spa_aprintf("%s: unknown param type: %s", cmd, a[1]); return false; } param_id = ti->type; - global = pw_map_lookup(&rd->globals, id); + global = find_global(rd, a[0]); if (global == NULL) { - *error = spa_aprintf("%s: unknown global %d", cmd, id); + *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]); return false; } if (global->proxy == NULL) { @@ -1544,126 +1638,15 @@ return true; } -static int json_to_pod(struct spa_pod_builder *b, uint32_t id, - const struct spa_type_info *info, struct spa_json *iter, const char *value, int len) -{ - const struct spa_type_info *ti; - char key[256]; - struct spa_pod_frame f[1]; - struct spa_json it[1]; - int l, res; - const char *v; - uint32_t type; - - if (spa_json_is_object(value, len) && info != NULL) { - if ((ti = spa_debug_type_find(NULL, info->parent)) == NULL) - return -EINVAL; - - spa_pod_builder_push_object(b, &f[0], info->parent, id); - - spa_json_enter(iter, &it[0]); - while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) { - const struct spa_type_info *pi; - if ((l = spa_json_next(&it[0], &v)) <= 0) - break; - if ((pi = find_type_info(ti->values, key)) != NULL) - type = pi->type; - else if ((type = atoi(key)) == 0) - continue; - spa_pod_builder_prop(b, type, 0); - if ((res = json_to_pod(b, id, pi, &it[0], v, l)) < 0) - return res; - } - spa_pod_builder_pop(b, &f[0]); - } - else if (spa_json_is_array(value, len)) { - if (info == NULL || info->parent == SPA_TYPE_Struct) { - spa_pod_builder_push_struct(b, &f[0]); - } else { - spa_pod_builder_push_array(b, &f[0]); - info = info->values; - } - spa_json_enter(iter, &it[0]); - while ((l = spa_json_next(&it[0], &v)) > 0) - if ((res = json_to_pod(b, id, info, &it[0], v, l)) < 0) - return res; - spa_pod_builder_pop(b, &f[0]); - } - else if (spa_json_is_float(value, len)) { - float val = 0.0f; - spa_json_parse_float(value, len, &val); - switch (info ? info->parent : SPA_TYPE_Struct) { - case SPA_TYPE_Bool: - spa_pod_builder_bool(b, val >= 0.5f); - break; - case SPA_TYPE_Id: - spa_pod_builder_id(b, val); - break; - case SPA_TYPE_Int: - spa_pod_builder_int(b, val); - break; - case SPA_TYPE_Long: - spa_pod_builder_long(b, val); - break; - case SPA_TYPE_Struct: - if (spa_json_is_int(value, len)) - spa_pod_builder_int(b, val); - else - spa_pod_builder_float(b, val); - break; - case SPA_TYPE_Float: - spa_pod_builder_float(b, val); - break; - case SPA_TYPE_Double: - spa_pod_builder_double(b, val); - break; - default: - spa_pod_builder_none(b); - break; - } - } - else if (spa_json_is_bool(value, len)) { - bool val = false; - spa_json_parse_bool(value, len, &val); - spa_pod_builder_bool(b, val); - } - else if (spa_json_is_null(value, len)) { - spa_pod_builder_none(b); - } - else { - char *val = alloca(len+1); - spa_json_parse_stringn(value, len, val, len+1); - switch (info ? info->parent : SPA_TYPE_Struct) { - case SPA_TYPE_Id: - if ((ti = find_type_info(info->values, val)) != NULL) - type = ti->type; - else if ((type = atoi(val)) == 0) - return -EINVAL; - spa_pod_builder_id(b, type); - break; - case SPA_TYPE_Struct: - case SPA_TYPE_String: - spa_pod_builder_string(b, val); - break; - default: - spa_pod_builder_none(b); - break; - } - } - return 0; -} - static bool do_set_param(struct data *data, const char *cmd, char *args, char **error) { struct remote_data *rd = data->current; char *a[3]; - const char *val; - int res, n, len; - uint32_t id, param_id; + int res, n; + uint32_t param_id; struct global *global; - struct spa_json it[3]; uint8_t buffer[1024]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); const struct spa_type_info *ti; struct spa_pod *pod; @@ -1673,11 +1656,9 @@ return false; } - id = atoi(a[0]); - - global = pw_map_lookup(&rd->globals, id); + global = find_global(rd, a[0]); if (global == NULL) { - *error = spa_aprintf("%s: unknown global %d", cmd, id); + *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]); return false; } if (global->proxy == NULL) { @@ -1685,19 +1666,12 @@ return false; } - ti = find_type_info(spa_type_param, a[1]); + ti = spa_debug_type_find_short(spa_type_param, a[1]); if (ti == NULL) { *error = spa_aprintf("%s: unknown param type: %s", cmd, a[1]); return false; } - param_id = ti->type; - - spa_json_init(&it[0], a[2], strlen(a[2])); - if ((len = spa_json_next(&it[0], &val)) <= 0) { - *error = spa_aprintf("%s: not a JSON object: %s", cmd, a[2]); - return false; - } - if ((res = json_to_pod(&b, param_id, ti, &it[0], val, len)) < 0) { + if ((res = spa_json_to_pod(&b, 0, ti, a[2], strlen(a[2]))) < 0) { *error = spa_aprintf("%s: can't make pod: %s", cmd, spa_strerror(res)); return false; } @@ -1707,6 +1681,8 @@ } spa_debug_pod(0, NULL, pod); + param_id = ti->type; + if (spa_streq(global->type, PW_TYPE_INTERFACE_Node)) pw_node_set_param((struct pw_node*)global->proxy, param_id, 0, pod); @@ -1729,7 +1705,7 @@ struct remote_data *rd = data->current; char *a[3]; int n; - uint32_t id, p; + uint32_t p; struct global *global; struct pw_permission permissions[1]; @@ -1739,10 +1715,9 @@ return false; } - id = atoi(a[0]); - global = pw_map_lookup(&rd->globals, id); + global = find_global(rd, a[0]); if (global == NULL) { - *error = spa_aprintf("%s: unknown global %d", cmd, id); + *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]); return false; } if (!spa_streq(global->type, PW_TYPE_INTERFACE_Client)) { @@ -1770,7 +1745,6 @@ struct remote_data *rd = data->current; char *a[3]; int n; - uint32_t id; struct global *global; n = pw_split_ip(args, WHITESPACE, 1, a); @@ -1779,10 +1753,9 @@ return false; } - id = atoi(a[0]); - global = pw_map_lookup(&rd->globals, id); + global = find_global(rd, a[0]); if (global == NULL) { - *error = spa_aprintf("%s: unknown global %d", cmd, id); + *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]); return false; } if (!spa_streq(global->type, PW_TYPE_INTERFACE_Client)) {
View file
pipewire-0.3.43.tar.gz/src/tools/pw-dump.c -> pipewire-0.3.44.tar.gz/src/tools/pw-dump.c
Changed
@@ -30,6 +30,7 @@ #include <getopt.h> #include <limits.h> #include <math.h> +#include <fnmatch.h> #include <spa/utils/result.h> #include <spa/utils/string.h> @@ -37,6 +38,7 @@ #include <spa/debug/types.h> #include <spa/utils/json.h> #include <spa/utils/ansi.h> +#include <spa/utils/string.h> #include <pipewire/pipewire.h> #include <pipewire/extensions/metadata.h> @@ -65,7 +67,7 @@ struct spa_list object_list; - uint32_t id; + const char *pattern; FILE *out; int level; @@ -93,6 +95,7 @@ const void *events; void (*destroy) (struct object *object); void (*dump) (struct object *object); + const char *name_key; }; struct object { @@ -552,6 +555,7 @@ .type = PW_TYPE_INTERFACE_Core, .version = PW_VERSION_CORE, .dump = core_dump, + .name_key = PW_KEY_CORE_NAME, }; /* client */ @@ -608,6 +612,7 @@ .events = &client_events, .destroy = client_destroy, .dump = client_dump, + .name_key = PW_KEY_APP_NAME, }; /* module */ @@ -667,6 +672,7 @@ .events = &module_events, .destroy = module_destroy, .dump = module_dump, + .name_key = PW_KEY_MODULE_NAME, }; /* factory */ @@ -726,6 +732,7 @@ .events = &factory_events, .destroy = factory_destroy, .dump = factory_dump, + .name_key = PW_KEY_FACTORY_NAME, }; /* device */ @@ -810,6 +817,7 @@ .events = &device_events, .destroy = device_destroy, .dump = device_dump, + .name_key = PW_KEY_DEVICE_NAME, }; /* node */ @@ -906,6 +914,7 @@ .events = &node_events, .destroy = node_destroy, .dump = node_dump, + .name_key = PW_KEY_NODE_NAME, }; /* port */ @@ -991,6 +1000,7 @@ .events = &port_events, .destroy = port_destroy, .dump = port_dump, + .name_key = PW_KEY_PORT_NAME, }; /* link */ @@ -1206,6 +1216,7 @@ .events = &metadata_events, .destroy = metadata_destroy, .dump = metadata_dump, + .name_key = PW_KEY_METADATA_NAME, }; static const struct class *classes[] = @@ -1331,6 +1342,32 @@ .global_remove = registry_event_global_remove, }; +static bool object_matches(struct object *o, const char *pattern) +{ + uint32_t id; + const char *str; + + if (spa_atou32(pattern, &id, 0) && o->id == id) + return true; + + if (o->props == NULL) + return false; + + if (strstr(o->type, pattern) != NULL) + return true; + if ((str = pw_properties_get(o->props, PW_KEY_OBJECT_PATH)) != NULL && + fnmatch(pattern, str, FNM_EXTMATCH) == 0) + return true; + if ((str = pw_properties_get(o->props, PW_KEY_OBJECT_SERIAL)) != NULL && + spa_streq(pattern, str)) + return true; + if (o->class != NULL && o->class->name_key != NULL && + (str = pw_properties_get(o->props, o->class->name_key)) != NULL && + fnmatch(pattern, str, FNM_EXTMATCH) == 0) + return true; + return false; +} + static void dump_objects(struct data *d) { static const struct flags_info fl[] = { @@ -1345,7 +1382,7 @@ d->state = STATE_FIRST; spa_list_for_each(o, &d->object_list, link) { - if (d->id != SPA_ID_INVALID && d->id != o->id) + if (d->pattern != NULL && !object_matches(o, d->pattern)) continue; if (o->changed == 0) continue; @@ -1493,10 +1530,8 @@ } } - data.id = SPA_ID_INVALID; - if (optind < argc) { - spa_atou32(argv[optind++], &data.id, 0); - } + if (optind < argc) + data.pattern = argv[optind++]; data.loop = pw_main_loop_new(NULL); if (data.loop == NULL) {
View file
pipewire-0.3.43.tar.gz/src/tools/pw-metadata.c -> pipewire-0.3.44.tar.gz/src/tools/pw-metadata.c
Changed
@@ -96,7 +96,8 @@ if (!spa_streq(type, PW_TYPE_INTERFACE_Metadata)) return; - if ((str = spa_dict_lookup(props, PW_KEY_METADATA_NAME)) != NULL && + if (props != NULL && + (str = spa_dict_lookup(props, PW_KEY_METADATA_NAME)) != NULL && !spa_streq(str, d->opt_name)) return;
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
.