Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 34
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Fri Sep 22 17:21:32 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.80 + +------------------------------------------------------------------- Wed Aug 30 13:49:39 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.79
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.79 +Version: 0.3.80 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
pipewire-0.3.79.tar.gz/.gitignore -> pipewire-0.3.80.tar.gz/.gitignore
Changed
@@ -18,6 +18,7 @@ subprojects/libyaml.wrap subprojects/libyaml subprojects/libcamera +subprojects/webrtc-audio-processing # Created by https://www.gitignore.io/api/vim
View file
pipewire-0.3.79.tar.gz/NEWS -> pipewire-0.3.80.tar.gz/NEWS
Changed
@@ -1,3 +1,71 @@ +# PipeWire 0.3.80 (2023-09-14) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + - A new Tag param was added that allows arbitrary metadata to be transported + out-of-band in the graph. + - Vulkan DMA buf support was merged. + - The echo-canceller was ported to webrtc-audio-processing-1. + - Fix a regression in locating monitor sources by id in pulse-server. + - Mixer io areas updates are now synchronized correctly with the data + thread to avoid potential crashes. + - Many more bugfixes and improvements. + + +## PipeWire + - Handle driver nodes that refuse to change the quantum or rate. + - A new Tag param was added that allows arbitrary metadata to be transported + out-of-band in the graph. + +## Modules + - The pipe-tunnel source has been reworked to use a ringbuffer and rate + adaption to keep the latency constant. It can now also function as a + driver to reduce resampling. (#3478) + +## Tools + - pw-cat will now place media properties in Tag params. + - pw-mon can now filter props and params. + +## SPA + - ALSA refuses to change quantum and rate when in IRQ mode. + - ALSA will now be smarter in selecting the period size for batch devices + and will make it depend on the samplerate. (#3444) + - Vulkan DMA buf support was merged. + - ALSA latency will now be reported in the time domain of the graph. + - Add udev based autodetection for compress-offload devices. + - The echo-canceller was ported to webrtc-audio-processing-1. + - The v4l2 inotify code was rewritten to avoid a use-after-free and by + using a separate watch (but same fd) for each device. (#3439) + - The tag and latency handling was improved in audioadpter. + - Don't use -Ofast on alpha because it can crash on denormalized + values. (#3489) + - The mixers now synchronize spa_io_buffers updates with the data + thread to avoid crashes. + - Handle NULL param updates. (#3504) + +## Pulse-server + - Fix a regression in locating monitor sources by id. (#3476) + - Add support for use_system_clock_for_timing in module-pipe-sink. + - Add support for checking module arguments. + - Avoid some useless change events. + +## Bluetooth + - Ports are now marked as physical, which makes the bluetooth devices show + up as hardware devices in Ardour and other JACK apps. (#3418) + - Some fixes for LE audio support (#3479) + +## JACK + - Also emit unregister notify even when supressed when creating the + client. + - The notify callbacks now match JACK2 behaviour more. + - The mixer io areas are updated and handled safely now to avoid + crashes. (#3506) + +Older versions: + + # PipeWire 0.3.79 (2023-08-29) This is a quick bugfix release that is API and ABI compatible with previous @@ -53,9 +121,6 @@ - Improve property handling, support lists and ranges in addition to fixed values. (#3451) -Older versions: - - # PipeWire 0.3.78 (2023-08-22) This is a small bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.79.tar.gz/man/pipewire-pulse.1.rst.in -> pipewire-0.3.80.tar.gz/man/pipewire-pulse.1.rst.in
Changed
@@ -17,8 +17,8 @@ =========== **pipewire-pulse** starts a PulseAudio-compatible daemon that integrates with -the PipeWire media server. This daemon is a drop-in replacement for the -PulseAudio daemon. +the PipeWire media server, by running a pipewire process through a systemd +service. This daemon is a drop-in replacement for the PulseAudio daemon. OPTIONS =======
View file
pipewire-0.3.79.tar.gz/man/pipewire.conf.5.rst.in -> pipewire-0.3.80.tar.gz/man/pipewire.conf.5.rst.in
Changed
@@ -69,7 +69,7 @@ of use, a relaxed format may be used where: * ``:`` to delimit keys and values can be substuted by ``=`` or a space. - * ``"`` around keys and string can be omited as long as no special characters are used in the strings. + * ``"`` around keys and string can be omitted as long as no special characters are used in the strings. * ``,`` to separate objects can be replaced with a whitespace character. * ``#`` can be used to start a comment until the line end
View file
pipewire-0.3.79.tar.gz/man/pw-top.1.rst.in -> pipewire-0.3.80.tar.gz/man/pw-top.1.rst.in
Changed
@@ -155,11 +155,17 @@ -h | --help Show help. +-b | --batch-mode + Run in non-interactive batch mode, similar to top's batch mode. + +-n | --iterations=NUMBER + Exit after NUMBER of batch iterations. Only used in batch mode. + -r | --remote=NAME The name the *remote* instance to monitor. If left unspecified, a connection is made to the default PipeWire instance. ---version +-V | --version Show version information.
View file
pipewire-0.3.79.tar.gz/meson.build -> pipewire-0.3.80.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '0.3.79', + version : '0.3.80', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.61.1', default_options : 'warning_level=3', @@ -49,7 +49,9 @@ pipewire_confdatadir = pipewire_datadir / 'pipewire' modules_install_dir = pipewire_libdir / pipewire_name -if host_machine.system() == 'linux' +cc = meson.get_compiler('c') + +if cc.has_header('features.h') and cc.get_define('__GLIBC__', prefix: '#include <features.h>') != '' # glibc ld.so interprets ${LIB} in a library loading path with an # appropriate value for the current architecture, typically something # like lib, lib64 or lib/x86_64-linux-gnu. @@ -72,8 +74,6 @@ pkgconfig = import('pkgconfig') -cc = meson.get_compiler('c') - common_flags = '-fvisibility=hidden', '-fno-strict-aliasing', @@ -375,8 +375,8 @@ cdata.set('HAVE_GSTREAMER_DEVICE_PROVIDER', get_option('gstreamer-device-provider').allowed()) -webrtc_dep = dependency('webrtc-audio-processing', - version : '>= 0.2', '< 1.0', +webrtc_dep = dependency('webrtc-audio-processing-1', + version : '>= 1.2' , required : get_option('echo-cancel-webrtc')) summary({'WebRTC Echo Canceling': webrtc_dep.found()}, bool_yn: true, section: 'Misc dependencies') cdata.set('HAVE_WEBRTC', webrtc_dep.found())
View file
pipewire-0.3.79.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.80.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -247,6 +247,7 @@ struct spa_io_buffers io; struct spa_list mix; + uint32_t n_mix; struct mix *global_mix; struct port *tied; @@ -526,6 +527,27 @@ } +struct io_info { + struct mix *mix; + void *data; +}; + +static int +do_mix_set_io(struct spa_loop *loop, bool async, uint32_t seq, + const void *data, size_t size, void *user_data) +{ + struct io_info *info = user_data; + info->mix->io = info->data; + return 0; +} + +static inline void mix_set_io(struct mix *mix, void *data) +{ + struct io_info info = { .mix = mix, .data = data }; + pw_data_loop_invoke(mix->port->client->loop, + do_mix_set_io, SPA_ID_INVALID, NULL, 0, true, &info); +} + static void init_mix(struct mix *mix, uint32_t mix_id, struct port *port, uint32_t peer_id) { pw_log_debug("create %p mix:%d peer:%d", port, mix_id, peer_id); @@ -538,6 +560,8 @@ spa_list_init(&mix->queue); if (mix_id == SPA_ID_INVALID) port->global_mix = mix; + else if (port->n_mix++ == 0 && port->global_mix != NULL) + mix_set_io(port->global_mix, &port->io); } static struct mix *find_mix_peer(struct client *c, uint32_t peer_id) { @@ -618,10 +642,14 @@ static void free_mix(struct client *c, struct mix *mix) { + struct port *port = mix->port; + clear_buffers(c, mix); spa_list_remove(&mix->port_link); if (mix->id == SPA_ID_INVALID) - mix->port->global_mix = NULL; + port->global_mix = NULL; + else if (--port->n_mix == 0 && port->global_mix != NULL) + mix_set_io(port->global_mix, NULL); spa_list_remove(&mix->link); spa_list_append(&c->free_mix, &mix->link); } @@ -1108,9 +1136,12 @@ } pw_log_debug("%p: skip notify %08x active:%d emit:%d", c, type, c->active, emit); - if (o != NULL && arg1 == 0 && o->removing) { - o->removing = false; - free_object(c, o); + if (o != NULL) { + o->registered = arg1; + if (arg1 == 0 && o->removing) { + o->removing = false; + free_object(c, o); + } } return res; } @@ -1395,6 +1426,7 @@ void *ptr = NULL; struct buffer *b; struct spa_data *d; + struct spa_io_buffers *io; if (frames == 0 || !p->valid) return NULL; @@ -1402,20 +1434,21 @@ if (SPA_UNLIKELY((mix = p->global_mix) == NULL)) return NULL; - pw_log_trace_fp("%p: port %s %d get buffer %d n_buffers:%d", - c, p->object->port.name, p->port_id, frames, mix->n_buffers); + pw_log_trace_fp("%p: port %s %d get buffer %d n_buffers:%d io:%p", + c, p->object->port.name, p->port_id, frames, + mix->n_buffers, mix->io); - if (SPA_UNLIKELY(mix->n_buffers == 0)) + if (SPA_UNLIKELY((io = mix->io) == NULL)) return NULL; - if (p->io.status == SPA_STATUS_HAVE_DATA && - p->io.buffer_id < mix->n_buffers) { - b = &mix->buffersp->io.buffer_id; + if (io->status == SPA_STATUS_HAVE_DATA && + io->buffer_id < mix->n_buffers) { + b = &mix->buffersio->buffer_id; d = &b->datas0; } else { - if (p->io.buffer_id < mix->n_buffers) { - reuse_buffer(c, mix, p->io.buffer_id); - p->io.buffer_id = SPA_ID_INVALID; + if (io->buffer_id < mix->n_buffers) { + reuse_buffer(c, mix, io->buffer_id); + io->buffer_id = SPA_ID_INVALID; } if (SPA_UNLIKELY((b = dequeue_buffer(c, mix)) == NULL)) { pw_log_warn("port %p: out of buffers", p); @@ -1426,8 +1459,8 @@ d->chunk->size = frames * sizeof(float); d->chunk->stride = stride; - p->io.status = SPA_STATUS_HAVE_DATA; - p->io.buffer_id = b->id; + io->status = SPA_STATUS_HAVE_DATA; + io->buffer_id = b->id; } ptr = d->data; if (buf) @@ -1469,14 +1502,19 @@ static void prepare_output(struct port *p, uint32_t frames) { struct mix *mix; + struct spa_io_buffers *io; if (SPA_UNLIKELY(p->empty_out || p->tied)) process_empty(p, frames); + if (p->global_mix == NULL || (io = p->global_mix->io) == NULL) + return; + spa_list_for_each(mix, &p->mix, port_link) { if (SPA_LIKELY(mix->io != NULL)) - *mix->io = p->io; + *mix->io = *io; } + io->status = SPA_STATUS_NEED_DATA; } static void complete_process(struct client *c, uint32_t frames) @@ -1492,7 +1530,6 @@ if (!p->valid) continue; prepare_output(p, frames); - p->io.status = SPA_STATUS_NEED_DATA; } pw_array_for_each(item, &c->portsSPA_DIRECTION_INPUT.items) { if (pw_map_item_is_free(item)) @@ -2405,7 +2442,6 @@ if (param == NULL) return 0; - if ((res = spa_latency_parse(param, &info)) < 0) return res; @@ -2685,7 +2721,7 @@ switch (id) { case SPA_IO_Buffers: - mix->io = ptr; + mix_set_io(mix, ptr); break; default: break; @@ -2812,6 +2848,9 @@ mix = find_mix(c, p, mix_id); + pw_log_debug("%p: port %p mix:%d peer_id:%u info:%p", c, p, mix_id, + peer_id, props); + if (peer_id == SPA_ID_INVALID) { if (mix == NULL) { res = -ENOENT; @@ -3110,15 +3149,23 @@ pw_node_state_as_string(info->state), n->node.is_running); if (info->change_mask & PW_NODE_CHANGE_MASK_STATE) { - struct object *p; + struct object *p, *l; spa_list_for_each(p, &c->context.objects, link) { if (p->type != INTERFACE_Port || p->removed || p->port.node_id != info->id) continue; if (n->node.is_running) queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, p, 1, NULL); - else + else { + spa_list_for_each(l, &c->context.objects, link) { + if (l->type != INTERFACE_Link || l->removed || + (l->port_link.src_serial != p->serial &&
View file
pipewire-0.3.79.tar.gz/spa/include/spa/debug/log.h -> pipewire-0.3.80.tar.gz/spa/include/spa/debug/log.h
Changed
@@ -53,25 +53,32 @@ #define spa_debug_log_pod(l,lev,indent,info,pod) \ ({ \ - struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ + struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \ spa_debugc_pod(&c.ctx, indent, info, pod); \ }) #define spa_debug_log_format(l,lev,indent,info,format) \ ({ \ - struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ + struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \ spa_debugc_format(&c.ctx, indent, info, format); \ }) #define spa_debug_log_mem(l,lev,indent,data,len) \ ({ \ - struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ + struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \ spa_debugc_mem(&c.ctx, indent, data, len); \ }) +#define spa_debug_log_dict(l,lev,indent,dict) \ +({ \ + struct spa_debug_log_ctx c = SPA_LOG_DEBUG_INIT(l,lev); \ + if (SPA_UNLIKELY(spa_log_level_topic_enabled(c.log, c.topic, c.level))) \ + spa_debugc_dict(&c.ctx, indent, dict); \ +}) + /** * \} */
View file
pipewire-0.3.79.tar.gz/spa/include/spa/node/keys.h -> pipewire-0.3.80.tar.gz/spa/include/spa/node/keys.h
Changed
@@ -16,6 +16,8 @@ /** node keys */ #define SPA_KEY_NODE_NAME "node.name" /**< a node name */ +#define SPA_KEY_NODE_DESCRIPTION "node.description" /**< localized human readable node one-line + * description. Ex. "Foobar USB Headset" */ #define SPA_KEY_NODE_LATENCY "node.latency" /**< the requested node latency */ #define SPA_KEY_NODE_MAX_LATENCY "node.max-latency" /**< maximum supported latency */
View file
pipewire-0.3.79.tar.gz/spa/include/spa/node/node.h -> pipewire-0.3.80.tar.gz/spa/include/spa/node/node.h
Changed
@@ -485,7 +485,9 @@ * * When \a param is NULL, the parameter will be unset. * - * This function must be called from the main thread. + * This function must be called from the main thread. The node muse be paused + * or the port SPA_IO_Buffers area is NULL when this function is called with + * a param that changes the processing state (like a format change). * * \param node a struct \ref spa_node * \param direction a enum \ref spa_direction @@ -540,7 +542,8 @@ * When this function returns async, use the spa_node_sync operation to * wait for completion. * - * This function must be called from the main thread. + * This function must be called from the main thread. The node muse be paused + * or the port SPA_IO_Buffers area is NULL when this function is called. * * \param object an object implementing the interface * \param direction a port direction @@ -566,6 +569,11 @@ * * This function must be called from the main thread. * + * This function can be called when the node is running and the node + * must be prepared to handle changes in io areas while running. This + * is normally done by synchronizing the port io updates with the + * data processing loop. + * * \param direction a spa_direction * \param port_id a port id * \param id the id of the io area, the available ids can be
View file
pipewire-0.3.79.tar.gz/spa/include/spa/param/param-types.h -> pipewire-0.3.80.tar.gz/spa/include/spa/param/param-types.h
Changed
@@ -40,6 +40,7 @@ { SPA_PARAM_Control, SPA_TYPE_Sequence, SPA_TYPE_INFO_PARAM_ID_BASE "Control", NULL }, { SPA_PARAM_Latency, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_INFO_PARAM_ID_BASE "Latency", NULL }, { SPA_PARAM_ProcessLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_INFO_PARAM_ID_BASE "ProcessLatency", NULL }, + { SPA_PARAM_Tag, SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_INFO_PARAM_ID_BASE "Tag", NULL }, { 0, 0, NULL, NULL }, };
View file
pipewire-0.3.79.tar.gz/spa/include/spa/param/param.h -> pipewire-0.3.80.tar.gz/spa/include/spa/param/param.h
Changed
@@ -39,6 +39,7 @@ SPA_PARAM_Control, /**< Control parameter, a SPA_TYPE_Sequence */ SPA_PARAM_Latency, /**< latency reporting, a SPA_TYPE_OBJECT_ParamLatency */ SPA_PARAM_ProcessLatency, /**< processing latency, a SPA_TYPE_OBJECT_ParamProcessLatency */ + SPA_PARAM_Tag, /**< tag reporting, a SPA_TYPE_OBJECT_ParamTag. Since 0.3.79 */ }; /** information about a parameter */
View file
pipewire-0.3.80.tar.gz/spa/include/spa/param/tag-types.h
Added
@@ -0,0 +1,39 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_PARAM_TAG_TYPES_H +#define SPA_PARAM_TAG_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/utils/enum-types.h> +#include <spa/param/param-types.h> +#include <spa/param/tag.h> + +#define SPA_TYPE_INFO_PARAM_Tag SPA_TYPE_INFO_PARAM_BASE "Tag" +#define SPA_TYPE_INFO_PARAM_TAG_BASE SPA_TYPE_INFO_PARAM_Tag ":" + +static const struct spa_type_info spa_type_param_tag = { + { SPA_PARAM_TAG_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_TAG_BASE, spa_type_param, }, + { SPA_PARAM_TAG_direction, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_TAG_BASE "direction", spa_type_direction, }, + { SPA_PARAM_TAG_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_TAG_BASE "info", NULL, }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_TAG_TYPES_H */
View file
pipewire-0.3.80.tar.gz/spa/include/spa/param/tag-utils.h
Added
@@ -0,0 +1,143 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_PARAM_TAG_UTILS_H +#define SPA_PARAM_TAG_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <float.h> + +#include <spa/utils/dict.h> +#include <spa/pod/builder.h> +#include <spa/pod/parser.h> +#include <spa/param/tag.h> + +static inline int +spa_tag_compare(const struct spa_pod *a, const struct spa_pod *b) +{ + return ((a == b) || (a && b && SPA_POD_SIZE(a) == SPA_POD_SIZE(b) && + memcmp(a, b, SPA_POD_SIZE(b)) == 0)) ? 0 : 1; +} + +static inline int +spa_tag_parse(const struct spa_pod *tag, struct spa_tag_info *info, void **state) +{ + int res; + const struct spa_pod_object *obj = (const struct spa_pod_object*)tag; + const struct spa_pod_prop *first, *start, *cur; + + spa_zero(*info); + + if ((res = spa_pod_parse_object(tag, + SPA_TYPE_OBJECT_ParamTag, NULL, + SPA_PARAM_TAG_direction, SPA_POD_Id(&info->direction))) < 0) + return res; + + first = spa_pod_prop_first(&obj->body); + start = *state ? spa_pod_prop_next((struct spa_pod_prop*)*state) : first; + + res = 0; + for (cur = start; spa_pod_prop_is_inside(&obj->body, obj->pod.size, cur); + cur = spa_pod_prop_next(cur)) { + if (cur->key == SPA_PARAM_TAG_info) { + info->info = &cur->value; + *state = (void*)cur; + return 1; + } + } + return 0; +} + +static inline int +spa_tag_info_parse(const struct spa_tag_info *info, struct spa_dict *dict, struct spa_dict_item *items) +{ + struct spa_pod_parser prs; + uint32_t n, n_items; + const char *key, *value; + struct spa_pod_frame f1; + + spa_pod_parser_pod(&prs, info->info); + if (spa_pod_parser_push_struct(&prs, &f0) < 0 || + spa_pod_parser_get_int(&prs, (int32_t*)&n_items) < 0) + return -EINVAL; + + if (items == NULL) { + dict->n_items = n_items; + return 0; + } + n_items = SPA_MIN(dict->n_items, n_items); + + for (n = 0; n < n_items; n++) { + if (spa_pod_parser_get(&prs, + SPA_POD_String(&key), + SPA_POD_String(&value), + NULL) < 0) + break; + itemsn.key = key; + itemsn.value = value; + } + dict->items = items; + spa_pod_parser_pop(&prs, &f0); + return 0; +} + +static inline void +spa_tag_build_start(struct spa_pod_builder *builder, struct spa_pod_frame *f, + uint32_t id, enum spa_direction direction) +{ + spa_pod_builder_push_object(builder, f, SPA_TYPE_OBJECT_ParamTag, id); + spa_pod_builder_add(builder, + SPA_PARAM_TAG_direction, SPA_POD_Id(direction), + 0); +} + +static inline void +spa_tag_build_add_info(struct spa_pod_builder *builder, const struct spa_pod *info) +{ + spa_pod_builder_add(builder, + SPA_PARAM_TAG_info, SPA_POD_Pod(info), + 0); +} + +static inline void +spa_tag_build_add_dict(struct spa_pod_builder *builder, const struct spa_dict *dict) +{ + uint32_t i, n_items; + struct spa_pod_frame f; + + n_items = dict ? dict->n_items : 0; + + spa_pod_builder_prop(builder, SPA_PARAM_TAG_info, SPA_POD_PROP_FLAG_HINT_DICT); + spa_pod_builder_push_struct(builder, &f); + spa_pod_builder_int(builder, n_items); + for (i = 0; i < n_items; i++) { + spa_pod_builder_string(builder, dict->itemsi.key); + spa_pod_builder_string(builder, dict->itemsi.value); + } + spa_pod_builder_pop(builder, &f); +} + +static inline struct spa_pod * +spa_tag_build_end(struct spa_pod_builder *builder, struct spa_pod_frame *f) +{ + return (struct spa_pod*)spa_pod_builder_pop(builder, f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_TAG_UTILS_H */
View file
pipewire-0.3.80.tar.gz/spa/include/spa/param/tag.h
Added
@@ -0,0 +1,46 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_PARAM_TAG_H +#define SPA_PARAM_TAG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#include <spa/param/param.h> + +/** properties for SPA_TYPE_OBJECT_ParamTag */ +enum spa_param_tag { + SPA_PARAM_TAG_START, + SPA_PARAM_TAG_direction, /**< direction, input/output (Id enum spa_direction) */ + SPA_PARAM_TAG_info, /**< Struct( + * Int: n_items + * (String: key + * String: value)* + * ) */ +}; + +/** helper structure for managing tag objects */ +struct spa_tag_info { + enum spa_direction direction; + const struct spa_pod *info; +}; + +#define SPA_TAG_INFO(dir,...) ((struct spa_tag_info) { .direction = (dir), ## __VA_ARGS__ }) + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_TAG_H */
View file
pipewire-0.3.79.tar.gz/spa/include/spa/param/type-info.h -> pipewire-0.3.80.tar.gz/spa/include/spa/param/type-info.h
Changed
@@ -14,5 +14,6 @@ #include <spa/param/profiler-types.h> #include <spa/param/profile-types.h> #include <spa/param/route-types.h> +#include <spa/param/tag-types.h> #endif /* SPA_PARAM_TYPE_INFO_H */
View file
pipewire-0.3.79.tar.gz/spa/include/spa/utils/names.h -> pipewire-0.3.80.tar.gz/spa/include/spa/utils/names.h
Changed
@@ -90,8 +90,10 @@ #define SPA_NAME_API_ALSA_SEQ_BRIDGE "api.alsa.seq.bridge" /**< an alsa Node interface for * bridging midi ports */ #define SPA_NAME_API_ALSA_ACP_DEVICE "api.alsa.acp.device" /**< an alsa ACP Device interface */ -#define SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_SINK "api.alsa.compress.offload.sink" /**< an alsa Node interface for - * compressed audio */ +#define SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_DEVICE "api.alsa.compress.offload.device" /**< an alsa Device interface for + * compressed audio */ +#define SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_SINK "api.alsa.compress.offload.sink" /**< an alsa Node interface for + * compressed audio */ /** keys for bluez5 factory names */ #define SPA_NAME_API_BLUEZ5_ENUM_DBUS "api.bluez5.enum.dbus" /**< a dbus Device interface */
View file
pipewire-0.3.79.tar.gz/spa/include/spa/utils/ratelimit.h -> pipewire-0.3.80.tar.gz/spa/include/spa/utils/ratelimit.h
Changed
@@ -17,23 +17,23 @@ uint64_t begin; unsigned burst; unsigned n_printed; - unsigned n_missed; + unsigned n_suppressed; }; static inline int spa_ratelimit_test(struct spa_ratelimit *r, uint64_t now) { - unsigned missed = 0; + unsigned suppressed = 0; if (r->begin + r->interval < now) { - missed = r->n_missed; + suppressed = r->n_suppressed; r->begin = now; r->n_printed = 0; - r->n_missed = 0; + r->n_suppressed = 0; } else if (r->n_printed >= r->burst) { - r->n_missed++; + r->n_suppressed++; return -1; } r->n_printed++; - return missed; + return suppressed; } #ifdef __cplusplus
View file
pipewire-0.3.79.tar.gz/spa/include/spa/utils/type-info.h -> pipewire-0.3.80.tar.gz/spa/include/spa/utils/type-info.h
Changed
@@ -83,6 +83,7 @@ { SPA_TYPE_OBJECT_Profiler, SPA_TYPE_Object, SPA_TYPE_INFO_Profiler, spa_type_profiler }, { SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Latency, spa_type_param_latency }, { SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_ProcessLatency, spa_type_param_process_latency }, + { SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Tag, spa_type_param_tag }, { 0, 0, NULL, NULL } };
View file
pipewire-0.3.79.tar.gz/spa/include/spa/utils/type.h -> pipewire-0.3.80.tar.gz/spa/include/spa/utils/type.h
Changed
@@ -78,6 +78,7 @@ SPA_TYPE_OBJECT_Profiler, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_OBJECT_ParamProcessLatency, + SPA_TYPE_OBJECT_ParamTag, _SPA_TYPE_OBJECT_LAST, /**< not part of ABI */ /* vendor extensions */
View file
pipewire-0.3.79.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.80.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Changed
@@ -13,9 +13,7 @@ #include <spa/utils/json.h> #include <spa/support/plugin.h> -#include <webrtc/modules/audio_processing/include/audio_processing.h> -#include <webrtc/modules/interface/module_common_types.h> -#include <webrtc/system_wrappers/include/trace.h> +#include <modules/audio_processing/include/audio_processing.h> struct impl_data { struct spa_handle handle; @@ -41,53 +39,6 @@ return default_value; } - -/* f0 f1 f2 */ -static int parse_point(struct spa_json *it, float (&f)3) -{ - struct spa_json arr; - int i, res; - - if (spa_json_enter_array(it, &arr) <= 0) - return -EINVAL; - - for (i = 0; i < 3; i++) { - if ((res = spa_json_get_float(&arr, &fi)) <= 0) - return -EINVAL; - } - return 0; -} - -/* point1 point2 ... */ -static int parse_mic_geometry(struct impl_data *impl, const char *mic_geometry, - std::vector<webrtc::Point>& geometry) -{ - int res; - size_t i; - struct spa_json it2; - - spa_json_init(&it0, mic_geometry, strlen(mic_geometry)); - if (spa_json_enter_array(&it0, &it1) <= 0) { - spa_log_error(impl->log, "Error: webrtc.mic-geometry expects an array"); - return -EINVAL; - } - - for (i = 0; i < geometry.size(); i++) { - float f3; - - if ((res = parse_point(&it1, f)) < 0) { - spa_log_error(impl->log, "Error: can't parse webrtc.mic-geometry points: %d", res); - return res; - } - - spa_log_info(impl->log, "mic %zd position: (%g %g %g)", i, f0, f1, f2); - geometryi.c0 = f0; - geometryi.c1 = f1; - geometryi.c2 = f2; - } - return 0; -} - static int webrtc_init2(void *object, const struct spa_dict *args, struct spa_audio_info_raw *rec_info, struct spa_audio_info_raw *out_info, struct spa_audio_info_raw *play_info) @@ -95,69 +46,33 @@ auto impl = static_cast<struct impl_data*>(object); int res; - bool extended_filter = webrtc_get_spa_bool(args, "webrtc.extended_filter", true); - bool delay_agnostic = webrtc_get_spa_bool(args, "webrtc.delay_agnostic", true); bool high_pass_filter = webrtc_get_spa_bool(args, "webrtc.high_pass_filter", true); bool noise_suppression = webrtc_get_spa_bool(args, "webrtc.noise_suppression", true); + bool transient_suppression = webrtc_get_spa_bool(args, "webrtc.transient_suppression", true); bool voice_detection = webrtc_get_spa_bool(args, "webrtc.voice_detection", true); // Note: AGC seems to mess up with Agnostic Delay Detection, especially with speech, // result in very poor performance, disable by default bool gain_control = webrtc_get_spa_bool(args, "webrtc.gain_control", false); - // Disable experimental flags by default - bool experimental_agc = webrtc_get_spa_bool(args, "webrtc.experimental_agc", false); - bool experimental_ns = webrtc_get_spa_bool(args, "webrtc.experimental_ns", false); - - bool beamforming = webrtc_get_spa_bool(args, "webrtc.beamforming", false); - // FIXME: Intelligibility enhancer is not currently supported // This filter will modify playback buffer (when calling ProcessReverseStream), but now // playback buffer modifications are discarded. - webrtc::Config config; - config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(extended_filter)); - config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(delay_agnostic)); - config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(experimental_agc)); - config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns)); - - if (beamforming) { - std::vector<webrtc::Point> geometry(rec_info->channels); - const char *mic_geometry, *target_direction; - - /* The beamformer gives a single mono channel */ - out_info->channels = 1; - out_info->position0 = SPA_AUDIO_CHANNEL_MONO; - - if ((mic_geometry = spa_dict_lookup(args, "webrtc.mic-geometry")) == NULL) { - spa_log_error(impl->log, "Error: webrtc.beamforming requires webrtc.mic-geometry"); - return -EINVAL; - } - - if ((res = parse_mic_geometry(impl, mic_geometry, geometry)) < 0) - return res; - - if ((target_direction = spa_dict_lookup(args, "webrtc.target-direction")) != NULL) { - webrtc::SphericalPointf direction(0.0f, 0.0f, 0.0f); - struct spa_json it; - float f3; - - spa_json_init(&it, target_direction, strlen(target_direction)); - if (parse_point(&it, f) < 0) { - spa_log_error(impl->log, "Error: can't parse target-direction %s", - target_direction); - return -EINVAL; - } - - direction.s0 = f0; - direction.s1 = f1; - direction.s2 = f2; - - config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry, direction)); - } else { - config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry)); - } - } + webrtc::AudioProcessing::Config config; + config.echo_canceller.enabled = true; + // FIXME: Example code enables both gain controllers, but that seems sus + config.gain_controller1.enabled = gain_control; + config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital; + config.gain_controller1.analog_level_minimum = 0; + config.gain_controller1.analog_level_maximum = 255; + config.gain_controller2.enabled = gain_control; + config.high_pass_filter.enabled = high_pass_filter; + config.noise_suppression.enabled = noise_suppression; + config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kHigh; + // FIXME: expose pre/postamp gain + config.transient_suppression.enabled = transient_suppression; + config.voice_detection.enabled = voice_detection; webrtc::ProcessingConfig pconfig = {{ webrtc::StreamConfig(rec_info->rate, rec_info->channels, false), /* input stream */ @@ -166,26 +81,15 @@ webrtc::StreamConfig(play_info->rate, play_info->channels, false), /* reverse output stream */ }}; - auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config)); + auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessingBuilder().Create()); + + apm->ApplyConfig(config); + if ((res = apm->Initialize(pconfig)) != webrtc::AudioProcessing::kNoError) { spa_log_error(impl->log, "Error initialising webrtc audio processing module: %d", res); return -EINVAL; } - apm->high_pass_filter()->Enable(high_pass_filter); - // Always disable drift compensation since PipeWire will already do - // drift compensation on all sinks and sources linked to this echo-canceler - apm->echo_cancellation()->enable_drift_compensation(false); - apm->echo_cancellation()->Enable(true); - // TODO: wire up supression levels to args - apm->echo_cancellation()->set_suppression_level(webrtc::EchoCancellation::kHighSuppression); - apm->noise_suppression()->set_level(webrtc::NoiseSuppression::kHigh); - apm->noise_suppression()->Enable(noise_suppression); - apm->voice_detection()->Enable(voice_detection); - // TODO: wire up AGC parameters to args - apm->gain_control()->set_analog_level_limits(0, 255); - apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital); - apm->gain_control()->Enable(gain_control); impl->apm = std::move(apm); impl->rec_info = *rec_info; impl->out_info = *out_info;
View file
pipewire-0.3.79.tar.gz/spa/plugins/alsa/acp/volume.h -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/acp/volume.h
Changed
@@ -83,7 +83,7 @@ static inline pa_volume_t pa_sw_volume_from_dB(double dB) { - if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY) + if (dB == -INFINITY || dB <= PA_DECIBEL_MININFTY) return PA_VOLUME_MUTED; return pa_sw_volume_from_linear(pa_volume_dB_to_linear(dB)); }
View file
pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-compress-offload-device.c
Added
@@ -0,0 +1,578 @@ +/* Spa ALSA Compress-Offload device */ +/* SPDX-FileCopyrightText: Copyright @ 2023 Carlos Rafael Giani */ +/* SPDX-License-Identifier: MIT */ + +#include <sys/types.h> +#include <limits.h> +#include <dirent.h> + +#include <alsa/asoundlib.h> + +#include <spa/debug/dict.h> +#include <spa/debug/log.h> +#include <spa/debug/pod.h> +#include <spa/node/node.h> +#include <spa/support/plugin.h> +#include <spa/monitor/device.h> +#include <spa/monitor/utils.h> +#include <spa/node/keys.h> +#include <spa/param/param.h> +#include <spa/pod/filter.h> +#include <spa/pod/parser.h> +#include <spa/utils/cleanup.h> +#include <spa/utils/dict.h> +#include <spa/utils/keys.h> +#include <spa/utils/names.h> +#include <spa/utils/string.h> + +#include "compress-offload-api-util.h" +#include "alsa.h" + +static const char default_device = "hw:0"; + +struct props { + char device64; + unsigned int card_nr; +}; + +static void reset_props(struct props *props) +{ + strncpy(props->device, default_device, 64); + props->card_nr = 0; +} + +struct impl { + struct spa_handle handle; + struct spa_device device; + + struct spa_log *log; + + struct spa_hook_list hooks; + + struct props props; + uint32_t n_nodes; + uint32_t n_capture; + uint32_t n_playback; + + uint32_t profile; +}; + +#define ADD_DICT_ITEM(key, value) do { itemsn_items++ = SPA_DICT_ITEM_INIT(key, value); } while (0) + +static void emit_node(struct impl *this, const char *device_node, unsigned int device_nr, + enum spa_compress_offload_direction direction, snd_ctl_card_info_t *cardinfo, + uint32_t id) +{ + struct spa_dict_item items5; + uint32_t n_items = 0; + char alsa_path128, path180; + char node_name200; + char node_desc200; + struct spa_device_object_info info; + const char *stream; + + spa_log_debug(this->log, "emitting node info for device %s (card nr %u device nr %u)", + device_node, this->props.card_nr, device_nr); + + info = SPA_DEVICE_OBJECT_INFO_INIT(); + info.type = SPA_TYPE_INTERFACE_Node; + + if (direction == SPA_COMPRESS_OFFLOAD_DIRECTION_PLAYBACK) { + stream = "playback"; + info.factory_name = SPA_NAME_API_ALSA_COMPRESS_OFFLOAD_SINK; + } else { + stream = "capture"; + /* TODO: This is not yet implemented, because getting Compress-Offload + * hardware that can capture audio is difficult to do. The only hardware + * known is the Wolfson ADSP; the only driver in the kernel that exposes + * Compress-Offload capture devices is the one for that hardware. */ + assert(false); + } + + info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS; + + snprintf(alsa_path, sizeof(alsa_path), "%s,%u", this->props.device, device_nr); + snprintf(path, sizeof(path), "alsa:compressed:%s:%u:%s", snd_ctl_card_info_get_id(cardinfo), device_nr, stream); + snprintf(node_name, sizeof(node_name), "comprC%uD%u", this->props.card_nr, device_nr); + snprintf(node_desc, sizeof(node_desc), "Compress-Offload sink node (ALSA card %u device %u)", this->props.card_nr, device_nr); + + ADD_DICT_ITEM(SPA_KEY_NODE_NAME, node_name); + ADD_DICT_ITEM(SPA_KEY_NODE_DESCRIPTION, node_desc); + ADD_DICT_ITEM(SPA_KEY_OBJECT_PATH, path); + ADD_DICT_ITEM(SPA_KEY_API_ALSA_PATH, alsa_path); + /* NOTE: Set alsa.name, since session managers look for this, or for + * SPA_KEY_API_ALSA_PCM_NAME, or other items. The best fit in this + * case seems to be alsa.name, since SPA_KEY_API_ALSA_PCM_NAME is + * PCM specific, as the name suggests. If none of these items are + * provided, session managers may not work properly. WirePlumber's + * alsa.lua script looks for these for example. + * And, since we have no good way of getting a name, just reuse + * the alsa_path here. */ + ADD_DICT_ITEM("alsa.name", alsa_path); + + info.props = &SPA_DICT_INIT(items, n_items); + + spa_log_debug(this->log, "node information:"); + spa_debug_dict(2, info.props); + + spa_device_emit_object_info(&this->hooks, id, &info); +} + +static int set_profile(struct impl *this, uint32_t id) +{ + int ret = 0; + uint32_t i, n_cap, n_play; + char prefix32; + int prefix_length; + struct dirent *entry; + DIR *snd_dir = NULL; + snd_ctl_t *ctl_handle = NULL; + snd_ctl_card_info_t *cardinfo; + + spa_log_debug(this->log, "enumerate Compress-Offload nodes for card %s; profile: %d", + this->props.device, id); + + if ((ret = snd_ctl_open(&ctl_handle, this->props.device, 0)) < 0) { + spa_log_error(this->log, "can't open control for card %s: %s", + this->props.device, snd_strerror(ret)); + goto finish; + } + + this->profile = id; + + snd_ctl_card_info_alloca(&cardinfo); + if ((ret = snd_ctl_card_info(ctl_handle, cardinfo)) < 0) { + spa_log_error(this->log, "error card info: %s", snd_strerror(ret)); + goto finish; + } + + /* Clear any previous node object info. */ + for (i = 0; i < this->n_nodes; i++) + spa_device_emit_object_info(&this->hooks, i, NULL); + + this->n_nodes = this->n_capture = this->n_playback = 0; + + /* Profile ID 0 is the "off" profile, that is, the profile where the device + * is "disabled". To implement such a disabled state, simply exit here without + * adding any nodes after we removed any existing one (see above). */ + if (id == 0) + { + spa_log_debug(this->log, "\"Off\" profile selected - exiting without " + "creating any nodes after all previous ones were removed"); + goto finish; + } + + spa_scnprintf(prefix, sizeof(prefix), "comprC%uD", this->props.card_nr); + prefix_length = strlen(prefix); + + /* There is no API to enumerate all Compress-Offload devices, so we have + * to stick to walking through the /dev/snd directory entries and looking + * for device nodes that match the comprC<card number>D prefix. */ + snd_dir = opendir("/dev/snd"); + if (snd_dir == NULL) + goto errno_error; + + i = 0; + i = n_cap = n_play = 0; + while ((errno = 0, entry = readdir(snd_dir)) != NULL) { + long long device_nr; + enum spa_compress_offload_direction direction; + + if (!(entry->d_type == DT_CHR && spa_strstartswith(entry->d_name, prefix))) + continue; + + /* Parse the device number from the device filename. We know that the filename + * is always structured like this: comprC<card number>D<device number> + * We consider "comprC<card number>D" to form the "prefix" here. Right after + * that prefix, the device number can be parsed, so skip the prefix. */ + device_nr = strtol(entry->d_name + prefix_length, NULL, 10); + if ((device_nr < 0) || (device_nr > UINT_MAX)) { + spa_log_warn(this->log, "device %s contains unusable device number; " + "skipping", entry->d_name); + continue; + } + + if (get_compress_offload_device_direction(this->props.card_nr, device_nr, + this->log, &direction) < 0) + goto finish; + + switch (direction) {
View file
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-pcm-device.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm-device.c
Changed
@@ -154,7 +154,6 @@ snd_pcm_info_t *pcminfo; snd_ctl_card_info_t *cardinfo; - spa_log_debug(this->log, "profile %d", id); this->profile = id; snd_ctl_card_info_alloca(&cardinfo); @@ -216,7 +215,9 @@ snd_ctl_t *ctl_hndl; int err; - spa_log_debug(this->log, "open card %s", this->props.device); + spa_log_debug(this->log, "enumerate PCM nodes for card %s; profile: %d", + this->props.device, id); + if ((err = snd_ctl_open(&ctl_hndl, this->props.device, 0)) < 0) { spa_log_error(this->log, "can't open control for card %s: %s", this->props.device, snd_strerror(err)); @@ -225,7 +226,7 @@ err = activate_profile(this, ctl_hndl, id); - spa_log_debug(this->log, "close card %s", this->props.device); + spa_log_debug(this->log, "done enumerating PCM nodes for card %s", this->props.device); snd_ctl_close(ctl_hndl); return err; @@ -551,7 +552,7 @@ return 1; } -const struct spa_handle_factory spa_alsa_device_factory = { +const struct spa_handle_factory spa_alsa_pcm_device_factory = { SPA_VERSION_HANDLE_FACTORY, SPA_NAME_API_ALSA_PCM_DEVICE, NULL,
View file
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
@@ -15,6 +15,8 @@ #include <spa/utils/string.h> #include <spa/param/audio/format.h> #include <spa/pod/filter.h> +#include <spa/debug/log.h> +#include <spa/debug/pod.h> #include "alsa-pcm.h" @@ -669,7 +671,7 @@ const struct spa_pod *param) { struct state *this = object; - int res; + int res = 0; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -693,9 +695,12 @@ this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; this->port_paramsPORT_Latency.user++; emit_port_info(this, false); - res = 0; break; } + case SPA_PARAM_Tag: + if (param != NULL) + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); + break; default: res = -ENOENT; break; @@ -815,14 +820,9 @@ spa_list_append(&this->ready, &b->link); SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT); io->buffer_id = SPA_ID_INVALID; - - spa_alsa_write(this); - - io->status = SPA_STATUS_OK; } - else if (!spa_list_is_empty(&this->ready)) { + if (!spa_list_is_empty(&this->ready)) { spa_alsa_write(this); - io->status = SPA_STATUS_OK; } return SPA_STATUS_HAVE_DATA;
View file
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -920,7 +920,7 @@ min = max = rate; if (rate == 0) - rate = state->position ? state->position->clock.rate.denom : DEFAULT_RATE; + rate = state->position ? state->position->clock.target_rate.denom : DEFAULT_RATE; rate = SPA_CLAMP(rate, min, max); @@ -1349,6 +1349,17 @@ return 1; } +/* find smaller power of 2 */ +static uint32_t flp2(uint32_t x) +{ + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >> 16); + return x - (x >> 1); +} + int spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num, const struct spa_pod *filter) @@ -1426,6 +1437,7 @@ unsigned int periods; bool match = true, planar = false, is_batch; char spdif_params128 = ""; + uint32_t default_period, latency; spa_log_debug(state->log, "opened:%d format:%d started:%d", state->opened, state->have_format, state->started); @@ -1651,12 +1663,15 @@ period_size = state->default_period_size; is_batch = snd_pcm_hw_params_is_batch(params) && !state->disable_batch; + default_period = SPA_SCALE32_UP(DEFAULT_PERIOD, state->rate, DEFAULT_RATE); + default_period = flp2(2 * default_period - 1); + /* no period size specified. If we are batch or not using timers, * use the graph duration as the period */ if (period_size == 0 && (is_batch || state->disable_tsched)) - period_size = state->position ? state->position->clock.target_duration : DEFAULT_PERIOD; + period_size = state->position ? state->position->clock.target_duration : default_period; if (period_size == 0) - period_size = DEFAULT_PERIOD; + period_size = default_period; if (!state->disable_tsched) { if (is_batch) { @@ -1664,7 +1679,7 @@ * 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; + period_size = SPA_MIN(period_size, default_period) / 2; } else { /* disable ALSA wakeups */ if (snd_pcm_hw_params_can_disable_period_wakeup(params)) @@ -1723,9 +1738,12 @@ state->headroom = SPA_MIN(state->headroom, state->buffer_frames); state->start_delay = state->default_start_delay; + latency = SPA_MAX(state->min_delay, SPA_MIN(state->max_delay, state->headroom)); + if (state->position != NULL) + latency = SPA_SCALE32_UP(latency, state->position->clock.target_rate.denom, state->rate); + state->latencystate->port_direction.min_rate = - state->latencystate->port_direction.max_rate = - SPA_MAX(state->min_delay, SPA_MIN(state->max_delay, state->headroom)); + state->latencystate->port_direction.max_rate = latency; spa_log_info(state->log, "%s (%s): format:%s access:%s-%s rate:%d channels:%d " "buffer frames %lu, period frames %lu, periods %u, frame_size %zd " @@ -1931,16 +1949,15 @@ delay = SPA_TIMEVAL_TO_USEC(&diff); missing = delay * state->rate / SPA_USEC_PER_SEC; - if (missing == 0) - missing = state->threshold; + missing += state->start_delay + state->threshold + state->headroom; spa_log_trace(state->log, "%p: xrun of %"PRIu64" usec %"PRIu64, state, delay, missing); - if (state->clock) - state->clock->xrun += missing; - state->sample_count += missing; - + if (state->clock) { + state->clock->xrun += SPA_SCALE32_UP(missing, + state->clock->rate.denom, state->rate); + } spa_node_call_xrun(&state->callbacks, SPA_TIMEVAL_TO_USEC(&trigger), delay, NULL); break; @@ -1977,16 +1994,16 @@ static int get_avail(struct state *state, uint64_t current_time, snd_pcm_uframes_t *delay) { - int res, missed; + int res, suppressed; snd_pcm_sframes_t avail; if (SPA_UNLIKELY((avail = snd_pcm_avail(state->hndl)) < 0)) { if ((res = alsa_recover(state, avail)) < 0) return res; if ((avail = snd_pcm_avail(state->hndl)) < 0) { - if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) { - spa_log_warn(state->log, "%s: (%d missed) snd_pcm_avail after recover: %s", - state->props.device, missed, snd_strerror(avail)); + if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) { + spa_log_warn(state->log, "%s: (%d suppressed) snd_pcm_avail after recover: %s", + state->props.device, suppressed, snd_strerror(avail)); } avail = state->threshold * 2; } @@ -2001,9 +2018,9 @@ uint64_t then; if ((res = snd_pcm_htimestamp(state->hndl, &havail, &tstamp)) < 0) { - if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) { - spa_log_warn(state->log, "%s: (%d missed) snd_pcm_htimestamp error: %s", - state->props.device, missed, snd_strerror(res)); + if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) { + spa_log_warn(state->log, "%s: (%d suppressed) snd_pcm_htimestamp error: %s", + state->props.device, suppressed, snd_strerror(res)); } return avail; } @@ -2029,9 +2046,9 @@ state->htimestamp_error = 0; state->htimestamp = false; } - else if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) { - spa_log_warn(state->log, "%s: (%d missed) impossible htimestamp diff:%"PRIi64, - state->props.device, missed, diff); + else if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) { + spa_log_warn(state->log, "%s: (%d suppressed) impossible htimestamp diff:%"PRIi64, + state->props.device, suppressed, diff); } } } @@ -2205,8 +2222,15 @@ if (SPA_UNLIKELY(state->position == NULL)) return 0; - target_duration = state->position->clock.target_duration; - target_rate = state->position->clock.target_rate; + if (state->disable_tsched && state->started && !state->following) { + target_duration = state->period_frames; + target_rate = SPA_FRACTION(1, state->rate); + state->position->clock.target_duration = target_duration; + state->position->clock.target_rate = target_rate; + } else { + target_duration = state->position->clock.target_duration; + target_rate = state->position->clock.target_rate; + } if (SPA_UNLIKELY((state->duration != target_duration) || (state->rate_denom != target_rate.denom))) { @@ -2229,7 +2253,7 @@ const snd_pcm_channel_area_t *my_areas; snd_pcm_uframes_t written, frames, offset, off, to_write, total_written, max_write; snd_pcm_sframes_t commitres; - int res, missed; + int res, suppressed; size_t frame_size = state->frame_size; if ((res = check_position_config(state)) < 0) @@ -2257,11 +2281,11 @@ else lev = SPA_LOG_LEVEL_INFO; - if ((missed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) { + if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) { spa_log_lev(state->log, lev, "%s: follower avail:%lu delay:%ld " - "target:%ld thr:%u, resync (%d missed)", + "target:%ld thr:%u, resync (%d suppressed)", state->props.device, avail, delay, - target, state->threshold, missed); + target, state->threshold, suppressed); } if (avail > target) @@ -2467,7 +2491,7 @@ const snd_pcm_channel_area_t *my_areas; snd_pcm_uframes_t read, frames, offset; snd_pcm_sframes_t commitres; - int res, missed; + int res, suppressed; if ((res = check_position_config(state)) < 0) return res; @@ -2494,10 +2518,10 @@ else lev = SPA_LOG_LEVEL_INFO;
View file
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-seq-bridge.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-seq-bridge.c
Changed
@@ -691,7 +691,9 @@ case SPA_PARAM_Latency: { struct spa_latency_info info; - if ((res = spa_latency_parse(param, &info)) < 0) + if (param == NULL) + info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction)); + else if ((res = spa_latency_parse(param, &info)) < 0) return res; if (direction == info.direction) return -EINVAL;
View file
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa-udev.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa-udev.c
Changed
@@ -24,24 +24,52 @@ #include <spa/support/plugin.h> #include <spa/monitor/device.h> #include <spa/monitor/utils.h> +#include <spa/debug/log.h> +#include <spa/debug/dict.h> #include "alsa.h" -#define MAX_DEVICES 64 +#define MAX_CARDS 64 #define ACTION_ADD 0 #define ACTION_REMOVE 1 #define ACTION_DISABLE 2 -struct device { - uint32_t id; - struct udev_device *dev; +/* Used for unavailable devices in the card structure. */ +#define ID_DEVICE_NOT_SUPPORTED 0 + +/* This represents an ALSA card. + * One card can have up to 1 PCM and 1 Compress-Offload device. */ +struct card { + unsigned int card_nr; + struct udev_device *udev_device; unsigned int unavailable:1; unsigned int accessible:1; unsigned int ignored:1; unsigned int emitted:1; + + /* Local SPA object IDs. (Global IDs are produced by PipeWire + * out of this using its registry.) Compress-Offload or PCM + * is not available, the corresponding ID is set to + * ID_DEVICE_NOT_SUPPORTED (= 0). + * PCM device IDs are (card nr + 1) * 2, and Compress-Offload + * device IDs are (card nr + 1) * 2 + 1. Assigning IDs like this + * makes it easy to deal with removed devices. (card nr + 1) + * is used because 0 is a valid ALSA card number. */ + uint32_t pcm_device_id; + uint32_t compress_offload_device_id; }; +static uint32_t calc_pcm_device_id(struct card *card) +{ + return (card->card_nr + 1) * 2 + 0; +} + +static uint32_t calc_compress_offload_device_id(struct card *card) +{ + return (card->card_nr + 1) * 2 + 1; +} + struct impl { struct spa_handle handle; struct spa_device device; @@ -58,8 +86,8 @@ struct udev *udev; struct udev_monitor *umonitor; - struct device devicesMAX_DEVICES; - uint32_t n_devices; + struct card cardsMAX_CARDS; + unsigned int n_cards; struct spa_source source; struct spa_source notify; @@ -84,58 +112,60 @@ return 0; } -static struct device *add_device(struct impl *this, uint32_t id, struct udev_device *dev) +static struct card *add_card(struct impl *this, unsigned int card_nr, struct udev_device *udev_device) { - struct device *device; + struct card *card; - if (this->n_devices >= MAX_DEVICES) + if (this->n_cards >= MAX_CARDS) return NULL; - device = &this->devicesthis->n_devices++; - spa_zero(*device); - device->id = id; - udev_device_ref(dev); - device->dev = dev; - return device; + + card = &this->cardsthis->n_cards++; + spa_zero(*card); + card->card_nr = card_nr; + udev_device_ref(udev_device); + card->udev_device = udev_device; + + return card; } -static struct device *find_device(struct impl *this, uint32_t id) +static struct card *find_card(struct impl *this, unsigned int card_nr) { - uint32_t i; - for (i = 0; i < this->n_devices; i++) { - if (this->devicesi.id == id) - return &this->devicesi; + unsigned int i; + for (i = 0; i < this->n_cards; i++) { + if (this->cardsi.card_nr == card_nr) + return &this->cardsi; } return NULL; } -static void remove_device(struct impl *this, struct device *device) +static void remove_card(struct impl *this, struct card *card) { - udev_device_unref(device->dev); - *device = this->devices--this->n_devices; + udev_device_unref(card->udev_device); + *card = this->cards--this->n_cards; } -static void clear_devices(struct impl *this) +static void clear_cards(struct impl *this) { - uint32_t i; - for (i = 0; i < this->n_devices; i++) - udev_device_unref(this->devicesi.dev); - this->n_devices = 0; + unsigned int i; + for (i = 0; i < this->n_cards; i++) + udev_device_unref(this->cardsi.udev_device); + this->n_cards = 0; } -static uint32_t get_card_id(struct impl *this, struct udev_device *dev) +static unsigned int get_card_nr(struct impl *this, struct udev_device *udev_device) { const char *e, *str; - if (udev_device_get_property_value(dev, "ACP_IGNORE")) + if (udev_device_get_property_value(udev_device, "ACP_IGNORE")) return SPA_ID_INVALID; - if ((str = udev_device_get_property_value(dev, "SOUND_CLASS")) && spa_streq(str, "modem")) + if ((str = udev_device_get_property_value(udev_device, "SOUND_CLASS")) && spa_streq(str, "modem")) return SPA_ID_INVALID; - if (udev_device_get_property_value(dev, "SOUND_INITIALIZED") == NULL) + if (udev_device_get_property_value(udev_device, "SOUND_INITIALIZED") == NULL) return SPA_ID_INVALID; - if ((str = udev_device_get_property_value(dev, "DEVPATH")) == NULL) + if ((str = udev_device_get_property_value(udev_device, "DEVPATH")) == NULL) return SPA_ID_INVALID; if ((e = strrchr(str, '/')) == NULL) @@ -244,7 +274,7 @@ return spa_strstartswith(buf, "modem") ? -ENXIO : 0; } -static int get_num_pcm_devices(unsigned int card_id) +static int get_num_pcm_devices(unsigned int card_nr) { char prefix32; struct dirent *entry; @@ -253,7 +283,7 @@ /* Check if card has PCM devices, without opening them */ - spa_scnprintf(prefix, sizeof(prefix), "pcmC%uD", card_id); + spa_scnprintf(prefix, sizeof(prefix), "pcmC%uD", card_nr); spa_autoptr(DIR) snd = opendir("/dev/snd"); if (snd == NULL) @@ -274,7 +304,33 @@ return errno != 0 ? -errno : num_dev; } -static int check_device_available(struct impl *this, struct device *device, int *num_pcm) +static int get_num_compress_offload_devices(unsigned int card_nr) +{ + char prefix32; + struct dirent *entry; + int num_dev = 0; + + /* Check if card has Compress-Offload devices, without opening them */ + + spa_scnprintf(prefix, sizeof(prefix), "comprC%uD", card_nr); + + spa_autoptr(DIR) snd = opendir("/dev/snd"); + if (snd == NULL) + return -errno; + + while ((errno = 0, entry = readdir(snd)) != NULL) { + if (!(entry->d_type == DT_CHR && + spa_strstartswith(entry->d_name, prefix))) + continue; + + ++num_dev; + }
View file
pipewire-0.3.79.tar.gz/spa/plugins/alsa/alsa.c -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/alsa.c
Changed
@@ -12,11 +12,12 @@ extern const struct spa_handle_factory spa_alsa_source_factory; extern const struct spa_handle_factory spa_alsa_sink_factory; extern const struct spa_handle_factory spa_alsa_udev_factory; -extern const struct spa_handle_factory spa_alsa_device_factory; +extern const struct spa_handle_factory spa_alsa_pcm_device_factory; extern const struct spa_handle_factory spa_alsa_seq_bridge_factory; extern const struct spa_handle_factory spa_alsa_acp_device_factory; #ifdef HAVE_ALSA_COMPRESS_OFFLOAD extern const struct spa_handle_factory spa_alsa_compress_offload_sink_factory; +extern const struct spa_handle_factory spa_alsa_compress_offload_device_factory; #endif struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.alsa"); @@ -39,7 +40,7 @@ *factory = &spa_alsa_udev_factory; break; case 3: - *factory = &spa_alsa_device_factory; + *factory = &spa_alsa_pcm_device_factory; break; case 4: *factory = &spa_alsa_seq_bridge_factory; @@ -51,6 +52,9 @@ case 6: *factory = &spa_alsa_compress_offload_sink_factory; break; + case 7: + *factory = &spa_alsa_compress_offload_device_factory; + break; #endif default: return 0;
View file
pipewire-0.3.80.tar.gz/spa/plugins/alsa/compress-offload-api-util.c
Added
@@ -0,0 +1,36 @@ +#include <errno.h> +#include <inttypes.h> +#include "compress-offload-api.h" +#include "compress-offload-api-util.h" + +int get_compress_offload_device_direction(int card_nr, int device_nr, + struct spa_log *log, + enum spa_compress_offload_direction *direction) +{ + int ret = 0; + struct compress_offload_api_context *device_context; + const struct snd_compr_caps *compr_caps; + + device_context = compress_offload_api_open(card_nr, device_nr, log); + if (device_context == NULL) + return -errno; + + compr_caps = compress_offload_api_get_caps(device_context); + + switch (compr_caps->direction) { + case SND_COMPRESS_PLAYBACK: + *direction = SPA_COMPRESS_OFFLOAD_DIRECTION_PLAYBACK; + break; + case SND_COMPRESS_CAPTURE: + *direction = SPA_COMPRESS_OFFLOAD_DIRECTION_CAPTURE; + break; + default: + spa_log_error(log, "card nr %d device nr %d: unknown direction %#" PRIx32, + card_nr, device_nr, (uint32_t)(compr_caps->direction)); + ret = -EINVAL; + } + + compress_offload_api_close(device_context); + + return ret; +}
View file
pipewire-0.3.80.tar.gz/spa/plugins/alsa/compress-offload-api-util.h
Added
@@ -0,0 +1,30 @@ +#ifndef SPA_ALSA_COMPRESS_OFFLOAD_DEVICE_UTIL_H +#define SPA_ALSA_COMPRESS_OFFLOAD_DEVICE_UTIL_H + +#include <spa/support/log.h> + +#if defined(__GNUC__) && __GNUC__ >= 4 +#define COMPR_API_PRIVATE __attribute__((visibility("hidden"))) +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590) +#define COMPR_API_PRIVATE __attribute__((visibility("hidden"))) +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) +#define COMPR_API_PRIVATE __hidden +#else +#define COMPR_API_PRIVATE +#endif + +enum spa_compress_offload_direction { + SPA_COMPRESS_OFFLOAD_DIRECTION_PLAYBACK, + SPA_COMPRESS_OFFLOAD_DIRECTION_CAPTURE +}; + +/* This exists for situations where both the direction of the compress-offload + * device and the functions from asoundlib.h are needed. It is not possible to + * include asoundlib.h and the compress-offload headers in the same C file, + * since these headers contain conflicting declarations. Provide this direction + * check function to keep the compress-offload headers encapsulated. */ +COMPR_API_PRIVATE int get_compress_offload_device_direction(int card_nr, int device_nr, + struct spa_log *log, + enum spa_compress_offload_direction *direction); + +#endif /* SPA_ALSA_COMPRESS_OFFLOAD_DEVICE_UTIL_H */
View file
pipewire-0.3.79.tar.gz/spa/plugins/alsa/compress-offload-api.h -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/compress-offload-api.h
Changed
@@ -6,22 +6,12 @@ #include <sound/compress_offload.h> #include <sound/compress_params.h> #include <spa/support/log.h> +#include "compress-offload-api-util.h" struct compress_offload_api_context; -#if defined(__GNUC__) && __GNUC__ >= 4 -#define COMPR_API_PRIVATE __attribute__((visibility("hidden"))) -#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590) -#define COMPR_API_PRIVATE __attribute__((visibility("hidden"))) -#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) -#define COMPR_API_PRIVATE __hidden -#else -#define COMPR_API_PRIVATE -#endif - - /* This is a simple encapsulation of the ALSA Compress-Offload API * and its ioctl calls. It is intentionally not using any PipeWire * or SPA headers to allow for porting it or extracting it as its
View file
pipewire-0.3.79.tar.gz/spa/plugins/alsa/meson.build -> pipewire-0.3.80.tar.gz/spa/plugins/alsa/meson.build
Changed
@@ -15,7 +15,10 @@ 'alsa-seq.c' if compress_offload_option.allowed() - spa_alsa_sources += 'alsa-compress-offload-sink.c', 'compress-offload-api.c' + spa_alsa_sources += 'alsa-compress-offload-sink.c', + 'alsa-compress-offload-device.c', + 'compress-offload-api-util.c', + 'compress-offload-api.c' endif spa_alsa = shared_library(
View file
pipewire-0.3.79.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.80.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
@@ -20,6 +20,7 @@ #include <spa/param/param.h> #include <spa/param/audio/format-utils.h> #include <spa/param/latency-utils.h> +#include <spa/param/tag-utils.h> #include <spa/debug/format.h> #include <spa/debug/pod.h> #include <spa/debug/log.h> @@ -75,7 +76,8 @@ #define IDX_PortConfig 5 #define IDX_Latency 6 #define IDX_ProcessLatency 7 -#define N_NODE_PARAMS 8 +#define IDX_Tag 8 +#define N_NODE_PARAMS 9 struct spa_param_info paramsN_NODE_PARAMS; uint32_t convert_params_flagsN_NODE_PARAMS; uint32_t follower_params_flagsN_NODE_PARAMS; @@ -93,6 +95,7 @@ unsigned int async:1; unsigned int passthrough:1; unsigned int follower_removing:1; + unsigned int in_recalc; }; /** \endcond */ @@ -204,6 +207,7 @@ case SPA_PARAM_EnumFormat: case SPA_PARAM_Format: case SPA_PARAM_Latency: + case SPA_PARAM_Tag: res = spa_node_port_enum_params_sync(this->follower, this->direction, 0, id, &result.next, filter, &result.param, &b.b); @@ -541,6 +545,80 @@ static const struct spa_node_events follower_node_events; +static int recalc_latency(struct impl *this, struct spa_node *src, enum spa_direction direction, + uint32_t port_id, struct spa_node *dst) +{ + struct spa_pod_builder b = { 0 }; + uint8_t buffer1024; + struct spa_pod *param; + uint32_t index = 0; + struct spa_latency_info latency; + int res; + + spa_log_info(this->log, "%p: %d:%d", this, direction, port_id); + + if (this->target == this->follower) + return 0; + + while (true) { + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + if ((res = spa_node_port_enum_params_sync(src, + direction, port_id, SPA_PARAM_Latency, + &index, NULL, ¶m, &b)) != 1) { + param = NULL; + break; + } + if ((res = spa_latency_parse(param, &latency)) < 0) + return res; + if (latency.direction == direction) + break; + } + if ((res = spa_node_port_set_param(dst, + SPA_DIRECTION_REVERSE(direction), 0, + SPA_PARAM_Latency, 0, param)) < 0) + return res; + + return 0; +} + +static int recalc_tag(struct impl *this, struct spa_node *src, enum spa_direction direction, + uint32_t port_id, struct spa_node *dst) +{ + struct spa_pod_builder b = { 0 }; + uint8_t buffer1024; + struct spa_pod *param; + uint32_t index = 0; + struct spa_tag_info info; + int res; + + spa_log_debug(this->log, "%p: %d:%d", this, direction, port_id); + + if (this->target == this->follower) + return 0; + + while (true) { + void *state = NULL; + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + if ((res = spa_node_port_enum_params_sync(src, + direction, port_id, SPA_PARAM_Tag, + &index, NULL, ¶m, &b)) != 1) { + param = NULL; + break; + } + if ((res = spa_tag_parse(param, &info, &state)) < 0) + return res; + if (info.direction == direction) + break; + } + if ((res = spa_node_port_set_param(dst, + SPA_DIRECTION_REVERSE(direction), 0, + SPA_PARAM_Tag, 0, param)) < 0) + return res; + + return 0; +} + + static int reconfigure_mode(struct impl *this, bool passthrough, enum spa_direction direction, struct spa_pod *format) { @@ -590,6 +668,8 @@ emit_node_info(this, false); + spa_log_debug(this->log, "%p: passthrough mode %d", this, passthrough); + return 0; } @@ -673,6 +753,8 @@ if (this->target != this->follower) { if ((res = spa_node_set_param(this->target, id, flags, param)) < 0) return res; + + res = recalc_latency(this, this->follower, this->direction, 0, this->convert); } break; } @@ -953,6 +1035,61 @@ emit_node_info(this, false); } +static void follower_convert_port_info(void *data, + enum spa_direction direction, uint32_t port_id, + const struct spa_port_info *info) +{ + struct impl *this = data; + uint32_t i; + int res; + + spa_log_info(this->log, "%p: convert port info %s %p %08"PRIx64, this, + this->direction == SPA_DIRECTION_INPUT ? + "Input" : "Output", info, info->change_mask); + + if (info->change_mask & SPA_PORT_CHANGE_MASK_PARAMS) { + for (i = 0; i < info->n_params; i++) { + uint32_t idx; + + switch (info->paramsi.id) { + case SPA_PARAM_Latency: + idx = IDX_Latency; + break; + case SPA_PARAM_Tag: + idx = IDX_Tag; + break; + default: + continue; + } + + if (!this->add_listener && + this->convert_params_flagsidx == info->paramsi.flags) + continue; + + this->convert_params_flagsidx = info->paramsi.flags; + + if (this->add_listener) + continue; + + if (idx == IDX_Latency) { + this->in_recalc++; + res = recalc_latency(this, this->convert, direction, port_id, this->follower); + this->in_recalc--; + spa_log_debug(this->log, "latency: %d (%s)", res, + spa_strerror(res)); + } + if (idx == IDX_Tag) { + this->in_recalc++; + res = recalc_tag(this, this->convert, direction, port_id, this->follower); + this->in_recalc--; + spa_log_debug(this->log, "tag: %d (%s)", res, + spa_strerror(res)); + } + spa_log_debug(this->log, "param %d changed", info->paramsi.id); + } + } +} + static void convert_port_info(void *data, enum spa_direction direction, uint32_t port_id, const struct spa_port_info *info) @@ -961,10 +1098,11 @@ struct spa_port_info pi; if (direction != this->direction) { - /* skip the converter output port into the follower */
View file
pipewire-0.3.79.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.80.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -24,6 +24,7 @@ #include <spa/param/audio/format-utils.h> #include <spa/param/param.h> #include <spa/param/latency-utils.h> +#include <spa/param/tag-utils.h> #include <spa/pod/filter.h> #include <spa/pod/dynamic.h> #include <spa/debug/types.h> @@ -138,13 +139,17 @@ #define IDX_Format 3 #define IDX_Buffers 4 #define IDX_Latency 5 -#define N_PORT_PARAMS 6 +#define IDX_Tag 6 +#define N_PORT_PARAMS 7 struct spa_param_info paramsN_PORT_PARAMS; char position16; struct buffer buffersMAX_BUFFERS; uint32_t n_buffers; + struct spa_latency_info latency2; + unsigned int have_latency:1; + struct spa_audio_info format; unsigned int have_format:1; unsigned int is_dsp:1; @@ -170,7 +175,7 @@ struct spa_audio_info format; unsigned int have_format:1; unsigned int have_profile:1; - struct spa_latency_info latency; + struct spa_pod *tag; uint32_t remapMAX_PORTS; @@ -323,6 +328,8 @@ } port->direction = direction; port->id = port_id; + port->latencySPA_DIRECTION_INPUT = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); + port->latencySPA_DIRECTION_OUTPUT = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); name = spa_debug_type_find_short_name(spa_type_audio_channel, position); snprintf(port->position, sizeof(port->position), "%s", name ? name : "UNK"); @@ -339,6 +346,7 @@ port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->paramsIDX_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); port->paramsIDX_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE); + port->paramsIDX_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_READWRITE); port->info.params = port->params; port->info.n_params = N_PORT_PARAMS; @@ -996,7 +1004,7 @@ spa_log_info(this->log, "generating ramp up sequence from %f to %f with a" " step value %f at scale %d", p->prev_volume, p->volume, volume_step, p->vrp.scale); do { - // spa_log_debug(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum)); + spa_log_trace(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum)); spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties); spa_pod_builder_add_object(&b.b, SPA_TYPE_OBJECT_Props, 0, @@ -1025,7 +1033,7 @@ spa_log_info(this->log, "generating ramp down sequence from %f to %f with a" " step value %f at scale %d", p->prev_volume, p->volume, volume_step, p->vrp.scale); do { - // spa_log_debug(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum)); + spa_log_trace(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum)); spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties); spa_pod_builder_add_object(&b.b, SPA_TYPE_OBJECT_Props, 0, @@ -2101,7 +2109,23 @@ uint32_t idx = result.index; if (port->is_monitor) idx = idx ^ 1; - param = spa_latency_build(&b, id, &this->diridx.latency); + param = spa_latency_build(&b, id, &port->latencyidx); + break; + } + default: + return 0; + } + break; + case SPA_PARAM_Tag: + switch (result.index) { + case 0: case 1: + { + uint32_t idx = result.index; + if (port->is_monitor) + idx = idx ^ 1; + param = this->diridx.tag; + if (param == NULL) + goto next; break; } default: @@ -2142,33 +2166,111 @@ struct impl *this = object; struct port *port, *oport; enum spa_direction other = SPA_DIRECTION_REVERSE(direction); + struct spa_latency_info info; + bool have_latency, emit = false;; uint32_t i; - spa_log_debug(this->log, "%p: set latency direction:%d id:%d", - this, direction, port_id); + spa_log_debug(this->log, "%p: set latency direction:%d id:%d %p", + this, direction, port_id, latency); port = GET_PORT(this, direction, port_id); if (port->is_monitor) return 0; if (latency == NULL) { - this->dirother.latency = SPA_LATENCY_INFO(other); + info = SPA_LATENCY_INFO(other); + have_latency = false; } else { - struct spa_latency_info info; if (spa_latency_parse(latency, &info) < 0 || info.direction != other) return -EINVAL; - this->dirother.latency = info; + have_latency = true; } + emit = spa_latency_info_compare(&info, &port->latencyother) != 0 || + port->have_latency == have_latency; + + port->latencyother = info; + port->have_latency = have_latency; + + spa_log_debug(this->log, "%p: set %s latency %f-%f %d-%d %"PRIu64"-%"PRIu64, this, + info.direction == SPA_DIRECTION_INPUT ? "input" : "output", + info.min_quantum, info.max_quantum, + info.min_rate, info.max_rate, + info.min_ns, info.max_ns); + + spa_latency_info_combine_start(&info, other); + for (i = 0; i < this->dirdirection.n_ports; i++) { + oport = GET_PORT(this, direction, i); + if (oport->is_monitor || !oport->have_latency) + continue; + spa_log_debug(this->log, "%p: combine %d", this, i); + spa_latency_info_combine(&info, &oport->latencyother); + } + spa_latency_info_combine_finish(&info); + + spa_log_debug(this->log, "%p: combined %s latency %f-%f %d-%d %"PRIu64"-%"PRIu64, this, + info.direction == SPA_DIRECTION_INPUT ? "input" : "output", + info.min_quantum, info.max_quantum, + info.min_rate, info.max_rate, + info.min_ns, info.max_ns); for (i = 0; i < this->dirother.n_ports; i++) { oport = GET_PORT(this, other, i); - oport->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; - oport->paramsIDX_Latency.user++; - emit_port_info(this, oport, false); + + spa_log_debug(this->log, "%p: change %d", this, i); + if (spa_latency_info_compare(&info, &oport->latencyother) != 0) { + oport->latencyother = info; + oport->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + oport->paramsIDX_Latency.user++; + emit_port_info(this, oport, false); + } + } + if (emit) { + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->paramsIDX_Latency.user++; + emit_port_info(this, port, false); + } + return 0; +} + +static int port_set_tag(void *object, + enum spa_direction direction, + uint32_t port_id, + uint32_t flags, + const struct spa_pod *tag) +{ + struct impl *this = object; + struct port *port, *oport; + enum spa_direction other = SPA_DIRECTION_REVERSE(direction); + uint32_t i; + + spa_log_debug(this->log, "%p: set tag direction:%d id:%d %p", + this, direction, port_id, tag); + + port = GET_PORT(this, direction, port_id); + if (port->is_monitor) + return 0; + + if (tag != NULL) { + struct spa_tag_info info; + void *state = NULL; + if (spa_tag_parse(tag, &info, &state) < 0 || + info.direction != other) + return -EINVAL; + }
View file
pipewire-0.3.79.tar.gz/spa/plugins/audioconvert/meson.build -> pipewire-0.3.80.tar.gz/spa/plugins/audioconvert/meson.build
Changed
@@ -7,6 +7,13 @@ simd_cargs = simd_dependencies = +opt_flags = +if host_machine.cpu_family() != 'alpha' + opt_flags += '-Ofast' +else + opt_flags += '-O3' +endif + audioconvert_c = static_library('audioconvert_c', 'channelmix-ops-c.c', 'biquad.c', @@ -15,7 +22,7 @@ 'peaks-ops-c.c', 'resample-native-c.c', 'fmt-ops-c.c' , - c_args : '-Ofast', '-ffast-math', + c_args : opt_flags , dependencies : spa_dep , install : false ) @@ -27,7 +34,7 @@ 'volume-ops-sse.c', 'peaks-ops-sse.c', 'channelmix-ops-sse.c' , - c_args : sse_args, '-Ofast', '-DHAVE_SSE', + c_args : sse_args, opt_flags, '-DHAVE_SSE', dependencies : spa_dep , install : false )
View file
pipewire-0.3.79.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.80.tar.gz/spa/plugins/audiomixer/audiomixer.c
Changed
@@ -9,6 +9,7 @@ #include <spa/support/plugin.h> #include <spa/support/log.h> #include <spa/support/cpu.h> +#include <spa/support/loop.h> #include <spa/utils/list.h> #include <spa/utils/names.h> #include <spa/utils/string.h> @@ -88,6 +89,9 @@ struct spa_cpu *cpu; uint32_t cpu_flags; uint32_t max_align; + + struct spa_loop *data_loop; + uint32_t quantum_limit; struct mix_ops ops; @@ -525,6 +529,8 @@ port = GET_PORT(this, direction, port_id); + spa_return_val_if_fail(!this->started || port->io == NULL, -EIO); + if (format == NULL) { if (port->have_format) { port->have_format = false; @@ -632,6 +638,8 @@ port = GET_PORT(this, direction, port_id); + spa_return_val_if_fail(!this->started || port->io == NULL, -EIO); + clear_buffers(this, port); if (n_buffers > 0 && !port->have_format) @@ -670,6 +678,19 @@ return 0; } +struct io_info { + struct port *port; + void *data; +}; + +static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq, + const void *data, size_t size, void *user_data) +{ + struct io_info *info = user_data; + info->port->io = info->data; + return 0; +} + static int impl_node_port_set_io(void *object, enum spa_direction direction, uint32_t port_id, @@ -677,6 +698,7 @@ { struct impl *this = object; struct port *port; + struct io_info info; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -686,10 +708,13 @@ spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); port = GET_PORT(this, direction, port_id); + info.port = port; + info.data = data; switch (id) { case SPA_IO_Buffers: - port->io = data; + spa_loop_invoke(this->data_loop, + do_port_set_io, SPA_ID_INVALID, NULL, 0, true, &info); break; default: return -ENOENT;
View file
pipewire-0.3.79.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.80.tar.gz/spa/plugins/audiomixer/mixer-dsp.c
Changed
@@ -9,6 +9,7 @@ #include <spa/support/plugin.h> #include <spa/support/log.h> #include <spa/support/cpu.h> +#include <spa/support/loop.h> #include <spa/utils/list.h> #include <spa/utils/names.h> #include <spa/utils/string.h> @@ -85,6 +86,8 @@ uint32_t cpu_flags; uint32_t max_align; + struct spa_loop *data_loop; + uint32_t quantum_limit; struct mix_ops ops; @@ -474,6 +477,8 @@ port = GET_PORT(this, direction, port_id); + spa_return_val_if_fail(!this->started || port->io == NULL, -EIO); + if (format == NULL) { if (port->have_format) { port->have_format = false; @@ -569,6 +574,8 @@ port = GET_PORT(this, direction, port_id); + spa_return_val_if_fail(!this->started || port->io == NULL, -EIO); + clear_buffers(this, port); if (n_buffers > 0 && !port->have_format) @@ -606,6 +613,19 @@ return 0; } +struct io_info { + struct port *port; + void *data; +}; + +static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq, + const void *data, size_t size, void *user_data) +{ + struct io_info *info = user_data; + info->port->io = info->data; + return 0; +} + static int impl_node_port_set_io(void *object, enum spa_direction direction, uint32_t port_id, @@ -613,6 +633,7 @@ { struct impl *this = object; struct port *port; + struct io_info info; spa_return_val_if_fail(this != NULL, -EINVAL); @@ -622,10 +643,13 @@ spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); port = GET_PORT(this, direction, port_id); + info.port = port; + info.data = data; switch (id) { case SPA_IO_Buffers: - port->io = data; + spa_loop_invoke(this->data_loop, + do_port_set_io, SPA_ID_INVALID, NULL, 0, true, &info); break; default: return -ENOENT; @@ -833,6 +857,12 @@ this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); spa_log_topic_init(this->log, log_topic); + this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); + if (this->data_loop == NULL) { + spa_log_error(this->log, "a data loop is needed"); + return -EINVAL; + } + this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); if (this->cpu) { this->cpu_flags = spa_cpu_get_flags(this->cpu);
View file
pipewire-0.3.79.tar.gz/spa/plugins/avb/avb-pcm-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/avb/avb-pcm-sink.c
Changed
@@ -572,7 +572,9 @@ case SPA_PARAM_Latency: { struct spa_latency_info info; - if ((res = spa_latency_parse(param, &info)) < 0) + if (param == NULL) + info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction)); + else if ((res = spa_latency_parse(param, &info)) < 0) return res; if (direction == info.direction) return -EINVAL;
View file
pipewire-0.3.79.tar.gz/spa/plugins/avb/avb-pcm-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/avb/avb-pcm-source.c
Changed
@@ -572,7 +572,9 @@ case SPA_PARAM_Latency: { struct spa_latency_info info; - if ((res = spa_latency_parse(param, &info)) < 0) + if (param == NULL) + info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction)); + else if ((res = spa_latency_parse(param, &info)) < 0) return res; if (direction == info.direction) return -EINVAL;
View file
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -526,6 +526,26 @@ } } +static enum spa_bt_profile swap_profile(enum spa_bt_profile profile) +{ + switch (profile) { + case SPA_BT_PROFILE_A2DP_SOURCE: + return SPA_BT_PROFILE_A2DP_SINK; + case SPA_BT_PROFILE_A2DP_SINK: + return SPA_BT_PROFILE_A2DP_SOURCE; + case SPA_BT_PROFILE_BAP_SOURCE: + return SPA_BT_PROFILE_BAP_SINK; + case SPA_BT_PROFILE_BAP_SINK: + return SPA_BT_PROFILE_BAP_SOURCE; + case SPA_BT_PROFILE_BAP_BROADCAST_SOURCE: + return SPA_BT_PROFILE_BAP_BROADCAST_SINK; + case SPA_BT_PROFILE_BAP_BROADCAST_SINK: + return SPA_BT_PROFILE_BAP_BROADCAST_SOURCE; + default: + return SPA_BT_PROFILE_NULL; + } +} + static bool endpoint_should_be_registered(struct spa_bt_monitor *monitor, const struct media_codec *codec, enum spa_bt_media_direction direction) @@ -2230,11 +2250,11 @@ return device->adapter && device->address; } -bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, bool sink) +bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, enum spa_bt_profile profile) { struct spa_bt_monitor *monitor = device->monitor; struct spa_bt_remote_endpoint *ep; - enum spa_bt_profile codec_profile; + enum spa_bt_profile codec_target_profile; struct spa_bt_transport *t; const struct { enum spa_bluetooth_audio_codec codec; uint32_t mask; } quirks = { { SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ, SPA_BT_FEATURE_SBC_XQ }, @@ -2270,17 +2290,14 @@ return false; } + for (i = 0, codec_target_profile = 0; i < (size_t)SPA_BT_MEDIA_DIRECTION_LAST; ++i) + if (codec_has_direction(codec, i)) + codec_target_profile |= swap_profile(get_codec_profile(codec, i)); + spa_list_for_each(ep, &device->remote_endpoint_list, device_link) { - enum spa_bt_profile profile = spa_bt_profile_from_uuid(ep->uuid); - if (codec->bap) { - if ((profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) || (profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE)) - codec_profile = sink ? SPA_BT_PROFILE_BAP_BROADCAST_SINK : SPA_BT_PROFILE_BAP_BROADCAST_SOURCE; - else - codec_profile = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE; - } else - codec_profile = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE; + enum spa_bt_profile ep_profile = spa_bt_profile_from_uuid(ep->uuid); - if (profile != codec_profile) + if (!(ep_profile & codec_target_profile & profile)) continue; if (media_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len, @@ -2296,15 +2313,7 @@ * can only know that the currently configured codec is supported. */ spa_list_for_each(t, &device->transport_list, device_link) { - if (codec->bap) { - if((t->profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) || (t->profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE)) - codec_profile = sink ? SPA_BT_PROFILE_BAP_BROADCAST_SINK : SPA_BT_PROFILE_BAP_BROADCAST_SOURCE; - else - codec_profile = sink ? SPA_BT_PROFILE_BAP_SINK : SPA_BT_PROFILE_BAP_SOURCE; - } else - codec_profile = sink ? SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE; - - if (t->profile != codec_profile) + if (!(t->profile & codec_target_profile & profile)) continue; if (codec == t->media_codec) @@ -2314,7 +2323,7 @@ return false; } -const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count, bool sink) +const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count) { struct spa_bt_monitor *monitor = device->monitor; const struct media_codec * const * const media_codecs = monitor->media_codecs; @@ -2329,7 +2338,7 @@ j = 0; for (i = 0; media_codecsi != NULL; ++i) { - if (spa_bt_device_supports_media_codec(device, media_codecsi, sink)) { + if (spa_bt_device_supports_media_codec(device, media_codecsi, device->connected_profiles)) { supported_codecsj = media_codecsi; ++j; } @@ -2373,10 +2382,17 @@ return NULL; } -static struct spa_bt_device* create_bcast_device(struct spa_bt_monitor *monitor, - const char *object_path) +static struct spa_bt_device *create_bcast_device(struct spa_bt_monitor *monitor, const char *object_path) { struct spa_bt_device *d; + struct spa_bt_adapter *adapter; + + adapter = adapter_find(monitor, object_path); + if (adapter == NULL) { + spa_log_warn(monitor->log, "unknown adapter %s", object_path); + return NULL; + } + d = device_create(monitor, object_path); if (d == NULL) { spa_log_warn(monitor->log, "can't create Bluetooth device %s: %m", @@ -2384,22 +2400,12 @@ return NULL; } - d->adapter = adapter_find(monitor, object_path); - if (d->adapter == NULL) { - spa_log_warn(monitor->log, "unknown adapter %s", d->adapter_path); - } - d->adapter_path = d->adapter->path; - d->alias = strdup("bcast_device"); - d->name = strdup("bcast_device"); + d->adapter = adapter; + d->adapter_path = strdup(adapter->path); + d->alias = strdup(adapter->alias); + d->name = strdup(adapter->name); d->address = strdup("00:00:00:00:00:00"); - - spa_bt_device_check_profiles(d, false); - d->reconnect_state = BT_DEVICE_RECONNECT_INIT; - - if (!device_props_ready(d)) - { - return NULL; - } + d->reconnect_state = BT_DEVICE_RECONNECT_STOP; device_update_hw_volume_profiles(d); @@ -2439,6 +2445,7 @@ } else if (spa_streq(key, "Device")) { struct spa_bt_device *device; + device = spa_bt_device_find(monitor, value); if (device == NULL) { /* @@ -2447,11 +2454,11 @@ * This is done because BlueZ sets the adapter as the device * that is connected to for a broadcast sink endpoint/transport. */ - if(spa_streq(remote_endpoint->uuid, SPA_BT_UUID_BAP_BROADCAST_SINK)) { + if (spa_streq(remote_endpoint->uuid, SPA_BT_UUID_BAP_BROADCAST_SINK)) { device = create_bcast_device(monitor, value); - if(device == NULL) { + if (device == NULL) goto next; - } + remote_endpoint->acceptor = true; device_set_connected(device, 1); } else { @@ -3048,29 +3055,9 @@ spa_log_debug(monitor->log, "transport %p: %s=%s", transport, key, value); if (spa_streq(key, "UUID")) { - switch (spa_bt_profile_from_uuid(value)) { - case SPA_BT_PROFILE_A2DP_SOURCE: - transport->profile = SPA_BT_PROFILE_A2DP_SINK; - break; - case SPA_BT_PROFILE_A2DP_SINK: - transport->profile = SPA_BT_PROFILE_A2DP_SOURCE; - break; - case SPA_BT_PROFILE_BAP_SOURCE: - transport->profile = SPA_BT_PROFILE_BAP_SINK; - break; - case SPA_BT_PROFILE_BAP_SINK: - transport->profile = SPA_BT_PROFILE_BAP_SOURCE; - break; - case SPA_BT_PROFILE_BAP_BROADCAST_SOURCE: - transport->profile = SPA_BT_PROFILE_BAP_BROADCAST_SINK; - break; - case SPA_BT_PROFILE_BAP_BROADCAST_SINK: - transport->profile = SPA_BT_PROFILE_BAP_BROADCAST_SOURCE; - break; - default: + transport->profile = swap_profile(spa_bt_profile_from_uuid(value)); + if (transport->profile == SPA_BT_PROFILE_NULL) spa_log_warn(monitor->log, "unknown profile %s", value); - break; - }
View file
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
@@ -190,10 +190,12 @@ *codecs = NULL; } -static const struct media_codec *get_supported_media_codec(struct impl *this, enum spa_bluetooth_audio_codec id, size_t *idx) +static const struct media_codec *get_supported_media_codec(struct impl *this, enum spa_bluetooth_audio_codec id, + size_t *idx, enum spa_bt_profile profile) { const struct media_codec *media_codec = NULL; size_t i; + for (i = 0; i < this->supported_codec_count; ++i) { if (this->supported_codecsi->id == id) { media_codec = this->supported_codecsi; @@ -201,6 +203,13 @@ *idx = i; } } + + if (!media_codec) + return NULL; + + if (!spa_bt_device_supports_media_codec(this->bt_dev, media_codec, profile)) + return NULL; + return media_codec; } @@ -625,6 +634,8 @@ char transport32, str_id32, object_path512; bool is_dyn_node = SPA_FLAG_IS_SET(id, DYNAMIC_NODE_ID_FLAG); + spa_log_debug(this->log, "node, transport:%p id:%08x factory:%s", t, id, factory_name); + snprintf(transport, sizeof(transport), "pointer:%p", t); items0 = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_TRANSPORT, transport); items1 = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_PROFILE, spa_bt_profile_name(t->profile)); @@ -1016,9 +1027,6 @@ } } } - - if (get_supported_media_codec(this, this->props.codec, NULL) == NULL) - this->props.codec = 0; break; case DEVICE_PROFILE_BAP: if (this->bt_dev->connected_profiles & (SPA_BT_PROFILE_BAP_SOURCE)) { @@ -1070,9 +1078,6 @@ DEVICE_ID_SOURCE, SPA_NAME_API_BLUEZ5_MEDIA_SOURCE, false); } } - - if (get_supported_media_codec(this, this->props.codec, NULL) == NULL) - this->props.codec = 0; break; case DEVICE_PROFILE_HSP_HFP: if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT) { @@ -1119,6 +1124,8 @@ static void emit_remove_nodes(struct impl *this) { + spa_log_debug(this->log, "remove nodes"); + remove_dynamic_node (&this->dyn_media_source); remove_dynamic_node (&this->dyn_media_sink); remove_dynamic_node (&this->dyn_sco_source); @@ -1278,11 +1285,9 @@ if (this->switching_codec) return; - if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_MEDIA_SINK) { - free(this->supported_codecs); - this->supported_codecs = spa_bt_device_get_supported_media_codecs( - this->bt_dev, &this->supported_codec_count, true); - } + free(this->supported_codecs); + this->supported_codecs = spa_bt_device_get_supported_media_codecs( + this->bt_dev, &this->supported_codec_count); switch (this->profile) { case DEVICE_PROFILE_OFF: @@ -1297,8 +1302,6 @@ break; case DEVICE_PROFILE_A2DP: case DEVICE_PROFILE_BAP: - if (get_supported_media_codec(this, this->props.codec, NULL) == NULL) - this->props.codec = 0; nodes_changed = (connected_change & (SPA_BT_PROFILE_MEDIA_SINK | SPA_BT_PROFILE_MEDIA_SOURCE)); spa_log_debug(this->log, "profiles changed: media nodes changed: %d", @@ -1419,7 +1422,7 @@ if (device->connected_profiles & SPA_BT_PROFILE_A2DP_SINK) have_output = true; - media_codec = get_supported_media_codec(this, codec, NULL); + media_codec = get_supported_media_codec(this, codec, NULL, device->connected_profiles); if (media_codec && media_codec->duplex_codec) have_input = true; break; @@ -1533,7 +1536,7 @@ if (this->supported_codecs) free(this->supported_codecs); this->supported_codecs = spa_bt_device_get_supported_media_codecs( - this->bt_dev, &this->supported_codec_count, true); + this->bt_dev, &this->supported_codec_count); /* Prefer BAP, then A2DP, then HFP, then null, but select AG if the device appears not to have BAP_SINK, A2DP_SINK or any HEAD_UNIT profile */ @@ -1625,7 +1628,7 @@ n_sink++; if (codec) { size_t idx; - const struct media_codec *media_codec = get_supported_media_codec(this, codec, &idx); + const struct media_codec *media_codec = get_supported_media_codec(this, codec, &idx, profile); if (media_codec == NULL) { errno = EINVAL; return NULL; @@ -1686,7 +1689,7 @@ name = spa_bt_profile_name(profile); if (codec) { - media_codec = get_supported_media_codec(this, codec, &idx); + media_codec = get_supported_media_codec(this, codec, &idx, profile); if (media_codec == NULL) { errno = EINVAL; return NULL;
View file
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/defs.h
Changed
@@ -169,6 +169,7 @@ SPA_BT_MEDIA_SINK, SPA_BT_MEDIA_SOURCE_BROADCAST, SPA_BT_MEDIA_SINK_BROADCAST, + SPA_BT_MEDIA_DIRECTION_LAST, }; enum spa_bt_profile { @@ -538,8 +539,8 @@ int spa_bt_device_connect_profile(struct spa_bt_device *device, enum spa_bt_profile profile); int spa_bt_device_check_profiles(struct spa_bt_device *device, bool force); int spa_bt_device_ensure_media_codec(struct spa_bt_device *device, const struct media_codec * const *codecs); -bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, bool sink); -const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count, bool sink); +bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const struct media_codec *codec, enum spa_bt_profile profile); +const struct media_codec **spa_bt_device_get_supported_media_codecs(struct spa_bt_device *device, size_t *count); int spa_bt_device_ensure_hfp_codec(struct spa_bt_device *device, unsigned int codec); int spa_bt_device_supports_hfp_codec(struct spa_bt_device *device, unsigned int codec); int spa_bt_device_release_transports(struct spa_bt_device *device);
View file
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/media-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/media-sink.c
Changed
@@ -1694,8 +1694,6 @@ port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; if (port->have_format) { - port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS; - port->info.flags = SPA_PORT_FLAG_LIVE; port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE; port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate); port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); @@ -2078,7 +2076,9 @@ port->info_all = SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_PARAMS; port->info = SPA_PORT_INFO_INIT(); - port->info.flags = 0; + port->info.flags = SPA_PORT_FLAG_LIVE | + SPA_PORT_FLAG_PHYSICAL | + SPA_PORT_FLAG_TERMINAL; port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); port->paramsIDX_IO = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
View file
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/media-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/media-source.c
Changed
@@ -1137,8 +1137,6 @@ port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; if (port->have_format) { - port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS; - port->info.flags = SPA_PORT_FLAG_LIVE; port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE; port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate); port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); @@ -1669,6 +1667,7 @@ port->info = SPA_PORT_INFO_INIT(); port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS; port->info.flags = SPA_PORT_FLAG_LIVE | + SPA_PORT_FLAG_PHYSICAL | SPA_PORT_FLAG_TERMINAL; port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
View file
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/midi-node.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/midi-node.c
Changed
@@ -2033,7 +2033,9 @@ SPA_PORT_CHANGE_MASK_PARAMS; port->info = SPA_PORT_INFO_INIT(); port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS; - port->info.flags = SPA_PORT_FLAG_LIVE; + port->info.flags = SPA_PORT_FLAG_LIVE | + SPA_PORT_FLAG_PHYSICAL | + SPA_PORT_FLAG_TERMINAL; port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); port->paramsIDX_IO = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
View file
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/sco-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/sco-sink.c
Changed
@@ -1157,8 +1157,6 @@ port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; if (port->have_format) { - port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS; - port->info.flags = SPA_PORT_FLAG_LIVE; port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE; port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate); port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); @@ -1499,7 +1497,9 @@ port->info_all = SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_PARAMS; port->info = SPA_PORT_INFO_INIT(); - port->info.flags = 0; + port->info.flags = SPA_PORT_FLAG_LIVE | + SPA_PORT_FLAG_PHYSICAL | + SPA_PORT_FLAG_TERMINAL; port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); port->paramsIDX_IO = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
View file
pipewire-0.3.79.tar.gz/spa/plugins/bluez5/sco-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/bluez5/sco-source.c
Changed
@@ -1135,8 +1135,6 @@ port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; if (port->have_format) { - port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS; - port->info.flags = SPA_PORT_FLAG_LIVE; port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE; port->info.rate = SPA_FRACTION(1, port->current_format.info.raw.rate); port->paramsIDX_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); @@ -1601,6 +1599,7 @@ port->info = SPA_PORT_INFO_INIT(); port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS; port->info.flags = SPA_PORT_FLAG_LIVE | + SPA_PORT_FLAG_PHYSICAL | SPA_PORT_FLAG_TERMINAL; port->paramsIDX_EnumFormat = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); port->paramsIDX_Meta = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
View file
pipewire-0.3.79.tar.gz/spa/plugins/control/mixer.c -> pipewire-0.3.80.tar.gz/spa/plugins/control/mixer.c
Changed
@@ -6,9 +6,10 @@ #include <string.h> #include <stdio.h> -#include <spa/support/plugin.h> -#include <spa/support/log.h> #include <spa/support/cpu.h> +#include <spa/support/log.h> +#include <spa/support/loop.h> +#include <spa/support/plugin.h> #include <spa/utils/list.h> #include <spa/utils/names.h> #include <spa/utils/string.h> @@ -59,6 +60,8 @@ struct spa_log *log; + struct spa_loop *data_loop; + uint64_t info_all; struct spa_node_info info; struct spa_param_info params8; @@ -412,6 +415,8 @@ port = GET_PORT(this, direction, port_id); + spa_return_val_if_fail(!this->started || port->io == NULL, -EIO); + if (format == NULL) { if (port->have_format) { port->have_format = false; @@ -489,6 +494,8 @@ spa_log_debug(this->log, NAME " %p: use buffers %d on port %d:%d", this, n_buffers, direction, port_id); + spa_return_val_if_fail(!this->started || port->io == NULL, -EIO); + clear_buffers(this, port); if (n_buffers > 0 && !port->have_format) @@ -517,6 +524,19 @@ return 0; } +struct io_info { + struct port *port; + void *data; +}; + +static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq, + const void *data, size_t size, void *user_data) +{ + struct io_info *info = user_data; + info->port->io = info->data; + return 0; +} + static int impl_node_port_set_io(void *object, enum spa_direction direction, uint32_t port_id, @@ -524,18 +544,23 @@ { struct impl *this = object; struct port *port; + struct io_info info; spa_return_val_if_fail(this != NULL, -EINVAL); - spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); - - port = GET_PORT(this, direction, port_id); spa_log_debug(this->log, NAME " %p: port %d:%d io %d %p/%zd", this, direction, port_id, id, data, size); + spa_return_val_if_fail(CHECK_PORT(this, direction, port_id), -EINVAL); + + port = GET_PORT(this, direction, port_id); + info.port = port; + info.data = data; + switch (id) { case SPA_IO_Buffers: - port->io = data; + spa_loop_invoke(this->data_loop, + do_port_set_io, SPA_ID_INVALID, NULL, 0, true, &info); break; default: return -ENOENT; @@ -793,6 +818,12 @@ this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + this->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop); + if (this->data_loop == NULL) { + spa_log_error(this->log, "a data loop is needed"); + return -EINVAL; + } + spa_hook_list_init(&this->hooks); this->node.iface = SPA_INTERFACE_INIT(
View file
pipewire-0.3.79.tar.gz/spa/plugins/support/node-driver.c -> pipewire-0.3.80.tar.gz/spa/plugins/support/node-driver.c
Changed
@@ -241,7 +241,7 @@ if ((res = spa_system_timerfd_read(this->data_system, this->timer_source.fd, &expirations)) < 0) { - if (res != EAGAIN) + if (res != -EAGAIN) spa_log_error(this->log, NAME " %p: timerfd error: %s", this, spa_strerror(res)); return;
View file
pipewire-0.3.79.tar.gz/spa/plugins/support/null-audio-sink.c -> pipewire-0.3.80.tar.gz/spa/plugins/support/null-audio-sink.c
Changed
@@ -273,7 +273,7 @@ if ((res = spa_system_timerfd_read(this->data_system, this->timer_source.fd, &expirations)) < 0) { - if (res != EAGAIN) + if (res != -EAGAIN) spa_log_error(this->log, NAME " %p: timerfd error: %s", this, spa_strerror(res)); return;
View file
pipewire-0.3.79.tar.gz/spa/plugins/v4l2/v4l2-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/v4l2/v4l2-source.c
Changed
@@ -729,7 +729,9 @@ case SPA_PARAM_Latency: { struct spa_latency_info info; - if ((res = spa_latency_parse(param, &info)) < 0) + if (param == NULL) + info = SPA_LATENCY_INFO(SPA_DIRECTION_REVERSE(direction)); + else if ((res = spa_latency_parse(param, &info)) < 0) return res; if (direction == info.direction) return -EINVAL;
View file
pipewire-0.3.79.tar.gz/spa/plugins/v4l2/v4l2-udev.c -> pipewire-0.3.80.tar.gz/spa/plugins/v4l2/v4l2-udev.c
Changed
@@ -33,10 +33,9 @@ #define ACTION_DISABLE 2 struct device { - struct impl *impl; uint32_t id; struct udev_device *dev; - struct spa_source notify; + int inotify_wd; unsigned int accessible:1; unsigned int ignored:1; unsigned int emitted:1; @@ -61,79 +60,91 @@ uint32_t n_devices; struct spa_source source; + struct spa_source notify; }; -static int stop_inotify(struct device *dev); -static int start_inotify(struct device *dev); - -static int impl_udev_open(struct impl *impl) +static int impl_udev_open(struct impl *this) { - if (impl->udev == NULL) { - impl->udev = udev_new(); - if (impl->udev == NULL) + if (this->udev == NULL) { + this->udev = udev_new(); + if (this->udev == NULL) return -ENOMEM; } return 0; } -static int impl_udev_close(struct impl *impl) +static int impl_udev_close(struct impl *this) { - if (impl->udev != NULL) - udev_unref(impl->udev); - impl->udev = NULL; + if (this->udev != NULL) + udev_unref(this->udev); + this->udev = NULL; return 0; } -static struct device *add_device(struct impl *impl, uint32_t id, struct udev_device *dev) +static void start_watching_device(struct impl *this, struct device *device) +{ + if (this->notify.fd < 0 || device->inotify_wd >= 0) + return; + + char path64; + snprintf(path, sizeof(path), "/dev/video%" PRIu32, device->id); + + device->inotify_wd = inotify_add_watch(this->notify.fd, path, IN_ATTRIB); +} + +static void stop_watching_device(struct impl *this, struct device *device) +{ + if (device->inotify_wd < 0) + return; + + spa_assert(this->notify.fd >= 0); + + inotify_rm_watch(this->notify.fd, device->inotify_wd); + device->inotify_wd = -1; +} + +static struct device *add_device(struct impl *this, uint32_t id, struct udev_device *dev) { struct device *device; - if (impl->n_devices >= MAX_DEVICES) + if (this->n_devices >= MAX_DEVICES) return NULL; - device = &impl->devicesimpl->n_devices++; + device = &this->devicesthis->n_devices++; spa_zero(*device); - device->impl = impl; - device->notify.fd = -1; device->id = id; udev_device_ref(dev); device->dev = dev; - start_inotify(device); + device->inotify_wd = -1; + + start_watching_device(this, device); + return device; } -static struct device *find_device(struct impl *impl, uint32_t id) +static struct device *find_device(struct impl *this, uint32_t id) { uint32_t i; - for (i = 0; i < impl->n_devices; i++) { - if (impl->devicesi.id == id) - return &impl->devicesi; + for (i = 0; i < this->n_devices; i++) { + if (this->devicesi.id == id) + return &this->devicesi; } return NULL; } -static void clear_device(struct device *device) +static void remove_device(struct impl *this, struct device *device) { - stop_inotify(device); - if (device->dev) - udev_device_unref(device->dev); + device->dev = udev_device_unref(device->dev); + stop_watching_device(this, device); + *device = this->devices--this->n_devices; } -static void remove_device(struct device *device) +static void clear_devices(struct impl *this) { - struct impl *impl = device->impl; - clear_device(device); - *device = impl->devices--impl->n_devices; + while (this->n_devices > 0) + remove_device(this, &this->devices0); } -static void clear_devices(struct impl *impl) -{ - uint32_t i; - for (i = 0; i < impl->n_devices; i++) - clear_device(&impl->devicesi); - impl->n_devices = 0; -} - -static uint32_t get_device_id(struct impl *impl, struct udev_device *dev) +static uint32_t get_device_id(struct impl *this, struct udev_device *dev) { const char *str; @@ -229,9 +240,8 @@ *d = 0; } -static int emit_object_info(struct device *device) +static int emit_object_info(struct impl *this, struct device *device) { - struct impl *impl = device->impl; struct spa_device_object_info info; uint32_t id = device->id; struct udev_device *dev = device->dev; @@ -331,55 +341,54 @@ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_CAPABILITIES, str); } info.props = &SPA_DICT_INIT(items, n_items); - spa_device_emit_object_info(&impl->hooks, id, &info); + spa_device_emit_object_info(&this->hooks, id, &info); device->emitted = true; return 1; } -static bool check_access(struct device *device) +static bool check_access(struct impl *this, struct device *device) { char path128; snprintf(path, sizeof(path), "/dev/video%u", device->id); device->accessible = access(path, R_OK|W_OK) >= 0; - spa_log_debug(device->impl->log, "%s accessible:%u", path, device->accessible); + spa_log_debug(this->log, "%s accessible:%u", path, device->accessible); return device->accessible; } -static void process_device(struct impl *impl, uint32_t action, struct udev_device *dev) +static void process_device(struct impl *this, uint32_t action, struct udev_device *dev) { uint32_t id; struct device *device; bool emitted; - if ((id = get_device_id(impl, dev)) == SPA_ID_INVALID) + if ((id = get_device_id(this, dev)) == SPA_ID_INVALID) return; - device = find_device(impl, id); + device = find_device(this, id); if (device && device->ignored) return; switch (action) { case ACTION_ADD: if (device == NULL) - device = add_device(impl, id, dev); + device = add_device(this, id, dev); if (device == NULL) return;
View file
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/dmabuf.h
Added
@@ -0,0 +1,62 @@ +// Copyright (c) 2023 The wlroots contributors +// +// 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. +// +// Obtained from https://gitlab.freedesktop.org/wlroots/wlroots/ + +/* SPDX-FileCopyrightText: Copyright © 2023 The wlroots contributors */ +/* SPDX-License-Identifier: MIT */ + +#ifndef RENDER_DMABUF_H +#define RENDER_DMABUF_H + +#include <stdbool.h> +#include <stdint.h> + +#include "spa/support/log.h" + +// Copied from <linux/dma-buf.h> to avoid #ifdef soup +#define DMA_BUF_SYNC_READ (1 << 0) +#define DMA_BUF_SYNC_WRITE (2 << 0) +#define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE) + +/** + * Check whether DMA-BUF import/export from/to sync_file is available. + * + * If this function returns true, dmabuf_import_sync_file() is supported. + */ +bool dmabuf_check_sync_file_import_export(struct spa_log *log); + +/** + * Import a sync_file into a DMA-BUF with DMA_BUF_IOCTL_IMPORT_SYNC_FILE. + * + * This can be used to make explicit sync interoperate with implicit sync. + */ +bool dmabuf_import_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags, int sync_file_fd); + +/** + * Export a sync_file from a DMA-BUF with DMA_BUF_IOCTL_EXPORT_SYNC_FILE. + * + * The sync_file FD is returned on success, -1 is returned on error. + * + * This can be used to make explicit sync interoperate with implicit sync. + */ +int dmabuf_export_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags); + +#endif
View file
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/dmabuf_fallback.c
Added
@@ -0,0 +1,42 @@ +// Copyright (c) 2023 The wlroots contributors +// +// 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. +// +// Obtained from https://gitlab.freedesktop.org/wlroots/wlroots/ + +/* SPDX-FileCopyrightText: Copyright © 2023 The wlroots contributors */ +/* SPDX-License-Identifier: MIT */ + +#include <spa/support/log.h> +#include <spa/utils/result.h> + + +bool dmabuf_check_sync_file_import_export(struct spa_log *log) { + return false; +} + +bool dmabuf_import_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags, int sync_file_fd) { + spa_log_error("DMA-BUF sync_file import IOCTL not available on this system"); + return false; +} + +int dmabuf_export_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags) { + spa_log_error("DMA-BUF sync_file export IOCTL not available on this system"); + return false; +}
View file
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/dmabuf_linux.c
Added
@@ -0,0 +1,127 @@ +// Copyright (c) 2023 The wlroots contributors +// +// 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. +// +// Obtained from https://gitlab.freedesktop.org/wlroots/wlroots/ + +/* SPDX-FileCopyrightText: Copyright © 2023 The wlroots contributors */ +/* SPDX-License-Identifier: MIT */ + +#include <linux/dma-buf.h> +#include <linux/version.h> +#include <stdlib.h> +#include <sys/utsname.h> +#include <xf86drm.h> +#include <errno.h> + +#include <spa/support/log.h> +#include <spa/utils/result.h> + +#include "dmabuf.h" + +bool dmabuf_check_sync_file_import_export(struct spa_log *log) { + /* Unfortunately there's no better way to check the availability of the + * IOCTL than to check the kernel version. See the discussion at: + * https://lore.kernel.org/dri-devel/20220601161303.64797-1-contact@emersion.fr/ + */ + + struct utsname utsname = {0}; + if (uname(&utsname) != 0) { + spa_log_warn(log, "uname failed"); + return false; + } + + if (strcmp(utsname.sysname, "Linux") != 0) { + return false; + } + + // Trim release suffix if any, e.g. "-arch1-1" + for (size_t i = 0; utsname.releasei != '\0'; i++) { + char ch = utsname.releasei; + if ((ch < '0' || ch > '9') && ch != '.') { + utsname.releasei = '\0'; + break; + } + } + + char *rel = strtok(utsname.release, "."); + int major = atoi(rel); + + int minor = 0; + rel = strtok(NULL, "."); + if (rel != NULL) { + minor = atoi(rel); + } + + int patch = 0; + rel = strtok(NULL, "."); + if (rel != NULL) { + patch = atoi(rel); + } + + return KERNEL_VERSION(major, minor, patch) >= KERNEL_VERSION(5, 20, 0); +} + +// TODO: drop these definitions once widespread + +#if !defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE) + +struct dma_buf_import_sync_file { + __u32 flags; + __s32 fd; +}; + +#define DMA_BUF_IOCTL_IMPORT_SYNC_FILE _IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file) + +#endif + +#if !defined(DMA_BUF_IOCTL_EXPORT_SYNC_FILE) + +struct dma_buf_export_sync_file { + __u32 flags; + __s32 fd; +}; + +#define DMA_BUF_IOCTL_EXPORT_SYNC_FILE _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file) + +#endif + +bool dmabuf_import_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags, int sync_file_fd) { + struct dma_buf_import_sync_file data = { + .flags = flags, + .fd = sync_file_fd, + }; + if (drmIoctl(dmabuf_fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &data) != 0) { + spa_log_error(log, "drmIoctl(IMPORT_SYNC_FILE) failed with %d (%s)", errno, spa_strerror(-errno)); + return false; + } + return true; +} + +int dmabuf_export_sync_file(struct spa_log *log, int dmabuf_fd, uint32_t flags) { + struct dma_buf_export_sync_file data = { + .flags = flags, + .fd = -1, + }; + if (drmIoctl(dmabuf_fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &data) != 0) { + spa_log_error(log, "drmIoctl(EXPORT_SYNC_FILE) failed with %d (%s)", errno, spa_strerror(-errno)); + return -1; + } + return data.fd; +}
View file
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/meson.build -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/meson.build
Changed
@@ -2,11 +2,20 @@ 'plugin.c', 'vulkan-compute-filter.c', 'vulkan-compute-source.c', + 'vulkan-compute-utils.c', 'vulkan-utils.c' +drm = dependency('libdrm') + +if cc.has_header('linux/dma-buf.h') and target_machine.system() == 'linux' + spa_vulkan_sources += files('dmabuf_linux.c') +else + spa_vulkan_sources += files('dmabuf_fallback.c') +endif + spa_vulkan = shared_library('spa-vulkan', spa_vulkan_sources, - dependencies : spa_dep, vulkan_dep, mathlib , + dependencies : spa_dep, vulkan_dep, mathlib, drm , install : true, install_dir : spa_plugindir / 'vulkan')
View file
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/vulkan-compute-filter.c -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-compute-filter.c
Changed
@@ -23,7 +23,7 @@ #include <spa/param/param.h> #include <spa/pod/filter.h> -#include "vulkan-utils.h" +#include "vulkan-compute-utils.h" #define NAME "vulkan-compute-filter" @@ -73,7 +73,7 @@ bool started; - struct vulkan_state state; + struct vulkan_compute_state state; struct port port2; }; @@ -269,6 +269,64 @@ return -ENOTSUP; } +static struct spa_pod *build_EnumFormat(uint32_t fmt, const struct vulkan_format_info *fmtInfo, struct spa_pod_builder *builder) { + struct spa_pod_frame f2; + uint32_t i, c; + + spa_pod_builder_push_object(builder, &f0, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); + spa_pod_builder_add(builder, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), 0); + spa_pod_builder_add(builder, SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), 0); + spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(fmt), 0); + if (fmtInfo && fmtInfo->modifierCount > 0) { + spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE); + spa_pod_builder_push_choice(builder, &f1, SPA_CHOICE_Enum, 0); + for (i = 0, c = 0; i < fmtInfo->modifierCount; i++) { + spa_pod_builder_long(builder, fmtInfo->infosi.props.drmFormatModifier); + if (c++ == 0) + spa_pod_builder_long(builder, fmtInfo->infosi.props.drmFormatModifier); + } + spa_pod_builder_pop(builder, &f1); + } + return spa_pod_builder_pop(builder, &f0); +} + +// This function enumerates the available formats in vulkan_state::formats, announcing all formats capable to support DmaBufs +// first and then falling back to those supported with SHM buffers. +static bool find_EnumFormatInfo(struct vulkan_base *s, uint32_t index, uint32_t caps, uint32_t *fmt_idx, bool *has_modifier) { + int64_t fmtIterator = 0; + int64_t maxIterator = 0; + if (caps & VULKAN_BUFFER_TYPE_CAP_SHM) + maxIterator += s->formatInfoCount; + if (caps & VULKAN_BUFFER_TYPE_CAP_DMABUF) + maxIterator += s->formatInfoCount; + // Count available formats until index underflows, while fmtIterator indexes the current format. + // Iterate twice over formats first time with modifiers, second time without if both caps are supported. + while (index < (uint32_t)-1 && fmtIterator < maxIterator) { + const struct vulkan_format_info *f_info = &s->formatInfosfmtIterator%s->formatInfoCount; + if (caps & VULKAN_BUFFER_TYPE_CAP_DMABUF && fmtIterator < s->formatInfoCount) { + // First round, check for modifiers + if (f_info->modifierCount > 0) { + index--; + } + } else if (caps & VULKAN_BUFFER_TYPE_CAP_SHM) { + // Second round, every format should be supported. + index--; + } + fmtIterator++; + } + + if (index != (uint32_t)-1) { + // No more formats available + return false; + } + // Undo end of loop increment + fmtIterator--; + *fmt_idx = fmtIterator%s->formatInfoCount; + // Loop finished in first round + *has_modifier = caps & VULKAN_BUFFER_TYPE_CAP_DMABUF && fmtIterator < s->formatInfoCount; + return true; +} + static int port_enum_formats(void *object, enum spa_direction direction, uint32_t port_id, uint32_t index, @@ -276,17 +334,30 @@ struct spa_pod **param, struct spa_pod_builder *builder) { - switch (index) { - case 0: - *param = spa_pod_builder_add_object(builder, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), - SPA_FORMAT_VIDEO_format, SPA_POD_Id(SPA_VIDEO_FORMAT_DSP_F32)); - break; - default: - return 0; + struct impl *this = object; + + uint32_t fmt_index; + bool has_modifier; + if (this->portport_id.have_format + && this->portport_id.current_format.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER + && this->portport_id.current_format.info.dsp.flags ^ SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED) { + if (index == 0) { + spa_log_info(this->log, "vulkan-compute-filter: enum_formats fixated format idx: %d, format %d, has_modifier 1", + index, this->portport_id.current_format.info.dsp.format); + *param = spa_format_video_dsp_build(builder, SPA_PARAM_EnumFormat, &this->portport_id.current_format.info.dsp); + return 1; + } + if (!find_EnumFormatInfo(&this->state.base, index-1, spa_vulkan_get_buffer_caps(&this->state, direction), &fmt_index, &has_modifier)) + return 0; + } else { + if (!find_EnumFormatInfo(&this->state.base, index, spa_vulkan_get_buffer_caps(&this->state, direction), &fmt_index, &has_modifier)) + return 0; } + + const struct vulkan_format_info *f_info = &this->state.base.formatInfosfmt_index; + spa_log_info(this->log, "vulkan-compute-filter: enum_formats idx: %d, format %d, has_modifier %d", index, f_info->spa_format, has_modifier); + *param = build_EnumFormat(f_info->spa_format, has_modifier ? f_info : NULL, builder); + return 1; } @@ -348,13 +419,25 @@ this->position->video.size.height, this->position->video.stride); - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_ParamBuffers, id, - 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_Int(this->position->video.stride * - this->position->video.size.height), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->position->video.stride)); + if (port->current_format.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER) { + struct vulkan_modifier_info *mod_info = spa_vulkan_get_modifier_info(&this->state, + &port->current_format.info.dsp); + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamBuffers, id, + SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS), + SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(mod_info->props.drmFormatModifierPlaneCount), + SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1<<SPA_DATA_DmaBuf)); + } else { + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamBuffers, id, + 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_Int(this->position->video.stride * + this->position->video.size.height), + SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->position->video.stride), + SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1<<SPA_DATA_MemPtr)); + } + break; } case SPA_PARAM_Meta: @@ -390,7 +473,7 @@ if (port->n_buffers > 0) { spa_log_debug(this->log, NAME " %p: clear buffers", this); spa_vulkan_stop(&this->state); - spa_vulkan_use_buffers(&this->state, &this->state.streamsport->stream_id, 0, 0, NULL); + spa_vulkan_use_buffers(&this->state, &this->state.streamsport->stream_id, 0, &port->current_format.info.dsp, 0, NULL); port->n_buffers = 0; spa_list_init(&port->empty); spa_list_init(&port->ready); @@ -428,8 +511,49 @@ this->state.constants.width = this->position->video.size.width; this->state.constants.height = this->position->video.size.height; + bool modifier_fixed = false; + if (port->direction == SPA_DIRECTION_OUTPUT + && info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER + && info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED) { + const struct spa_pod_prop *mod_prop; + if ((mod_prop = spa_pod_find_prop(format, NULL, SPA_FORMAT_VIDEO_modifier)) == NULL) + return -EINVAL; + + const struct spa_pod *mod_pod = &mod_prop->value; + uint32_t modifierCount = SPA_POD_CHOICE_N_VALUES(mod_pod); + uint64_t *modifiers = SPA_POD_CHOICE_VALUES(mod_pod); + if (modifierCount <= 1) + return -EINVAL; + // SPA_POD_CHOICE carries the "preferred" value at position 0 + modifierCount -= 1; + modifiers++; + uint64_t fixed_modifier; + if (spa_vulkan_fixate_modifier(&this->state, &this->state.streamsport->stream_id, &info.info.dsp, modifierCount, modifiers, &fixed_modifier) != 0) + return -EINVAL; + + spa_log_info(this->log, NAME ": modifier fixated %"PRIu64, fixed_modifier); + + info.info.dsp.modifier = fixed_modifier; + info.info.dsp.flags &= ~SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED; + modifier_fixed = true; + } + + if (info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER) { + port->info.flags |= SPA_PORT_FLAG_CAN_ALLOC_BUFFERS; + } else {
View file
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c
Changed
@@ -24,7 +24,7 @@ #include <spa/param/param.h> #include <spa/pod/filter.h> -#include "vulkan-utils.h" +#include "vulkan-compute-utils.h" #define NAME "vulkan-compute-source" @@ -97,7 +97,7 @@ uint64_t frame_count; - struct vulkan_state state; + struct vulkan_compute_state state; struct port port; }; @@ -503,6 +503,64 @@ return -ENOTSUP; } +static struct spa_pod *build_EnumFormat(uint32_t fmt, const struct vulkan_format_info *fmtInfo, struct spa_pod_builder *builder) { + struct spa_pod_frame f2; + uint32_t i, c; + + spa_pod_builder_push_object(builder, &f0, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); + spa_pod_builder_add(builder, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), 0); + spa_pod_builder_add(builder, SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), 0); + spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(fmt), 0); + if (fmtInfo && fmtInfo->modifierCount > 0) { + spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE); + spa_pod_builder_push_choice(builder, &f1, SPA_CHOICE_Enum, 0); + for (i = 0, c = 0; i < fmtInfo->modifierCount; i++) { + spa_pod_builder_long(builder, fmtInfo->infosi.props.drmFormatModifier); + if (c++ == 0) + spa_pod_builder_long(builder, fmtInfo->infosi.props.drmFormatModifier); + } + spa_pod_builder_pop(builder, &f1); + } + return spa_pod_builder_pop(builder, &f0); +} + +// This function enumerates the available formats in vulkan_state::formats, announcing all formats capable to support DmaBufs +// first and then falling back to those supported with SHM buffers. +static bool find_EnumFormatInfo(struct vulkan_base *s, uint32_t index, uint32_t caps, uint32_t *fmt_idx, bool *has_modifier) { + int64_t fmtIterator = 0; + int64_t maxIterator = 0; + if (caps & VULKAN_BUFFER_TYPE_CAP_SHM) + maxIterator += s->formatInfoCount; + if (caps & VULKAN_BUFFER_TYPE_CAP_DMABUF) + maxIterator += s->formatInfoCount; + // Count available formats until index underflows, while fmtIterator indexes the current format. + // Iterate twice over formats first time with modifiers, second time without if both caps are supported. + while (index < (uint32_t)-1 && fmtIterator < maxIterator) { + const struct vulkan_format_info *f_info = &s->formatInfosfmtIterator%s->formatInfoCount; + if (caps & VULKAN_BUFFER_TYPE_CAP_DMABUF && fmtIterator < s->formatInfoCount) { + // First round, check for modifiers + if (f_info->modifierCount > 0) { + index--; + } + } else if (caps & VULKAN_BUFFER_TYPE_CAP_SHM) { + // Second round, every format should be supported. + index--; + } + fmtIterator++; + } + + if (index != (uint32_t)-1) { + // No more formats available + return false; + } + // Undo end of loop increment + fmtIterator--; + *fmt_idx = fmtIterator%s->formatInfoCount; + // Loop finished in first round + *has_modifier = caps & VULKAN_BUFFER_TYPE_CAP_DMABUF && fmtIterator < s->formatInfoCount; + return true; +} + static int port_enum_formats(void *object, enum spa_direction direction, uint32_t port_id, uint32_t index, @@ -510,17 +568,30 @@ struct spa_pod **param, struct spa_pod_builder *builder) { - switch (index) { - case 0: - *param = spa_pod_builder_add_object(builder, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, - SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), - SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_dsp), - SPA_FORMAT_VIDEO_format, SPA_POD_Id(SPA_VIDEO_FORMAT_DSP_F32)); - break; - default: - return 0; + struct impl *this = object; + + uint32_t fmt_index; + bool has_modifier; + if (this->port.have_format + && this->port.current_format.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER + && this->port.current_format.info.dsp.flags ^ SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED) { + if (index == 0) { + spa_log_info(this->log, "vulkan-compute-source: enum_formats fixated format idx: %d, format %d, has_modifier 1", + index, this->port.current_format.info.dsp.format); + *param = spa_format_video_dsp_build(builder, SPA_PARAM_EnumFormat, &this->port.current_format.info.dsp); + return 1; + } + if (!find_EnumFormatInfo(&this->state.base, index-1, spa_vulkan_get_buffer_caps(&this->state, direction), &fmt_index, &has_modifier)) + return 0; + } else { + if (!find_EnumFormatInfo(&this->state.base, index, spa_vulkan_get_buffer_caps(&this->state, direction), &fmt_index, &has_modifier)) + return 0; } + + const struct vulkan_format_info *f_info = &this->state.base.formatInfosfmt_index; + spa_log_info(this->log, "vulkan-compute-source: enum_formats idx: %d, format %d, has_modifier %d", index, f_info->spa_format, has_modifier); + *param = build_EnumFormat(f_info->spa_format, has_modifier ? f_info : NULL, builder); + return 1; } @@ -582,13 +653,26 @@ this->position->video.size.height, this->position->video.stride); - param = spa_pod_builder_add_object(&b, - SPA_TYPE_OBJECT_ParamBuffers, id, - 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_Int(this->position->video.stride * - this->position->video.size.height), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->position->video.stride)); + + if (port->current_format.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER) { + struct vulkan_modifier_info *mod_info = spa_vulkan_get_modifier_info(&this->state, + &port->current_format.info.dsp); + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamBuffers, id, + SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS), + SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(mod_info->props.drmFormatModifierPlaneCount), + SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1<<SPA_DATA_DmaBuf)); + } else { + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamBuffers, id, + 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_Int(this->position->video.stride * + this->position->video.size.height), + SPA_PARAM_BUFFERS_stride, SPA_POD_Int(this->position->video.stride), + SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(1<<SPA_DATA_MemPtr)); + } + break; } case SPA_PARAM_Meta: @@ -623,7 +707,7 @@ { if (port->n_buffers > 0) { spa_log_debug(this->log, NAME " %p: clear buffers", this); - spa_vulkan_use_buffers(&this->state, &this->state.streams0, 0, 0, NULL); + spa_vulkan_use_buffers(&this->state, &this->state.streams0, 0, &port->current_format.info.dsp, 0, NULL); port->n_buffers = 0; spa_list_init(&port->empty); spa_list_init(&port->ready); @@ -662,9 +746,50 @@ this->state.constants.width = this->position->video.size.width; this->state.constants.height = this->position->video.size.height; + bool modifier_fixed = false; + if (info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER + && info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED) { + const struct spa_pod_prop *mod_prop; + if ((mod_prop = spa_pod_find_prop(format, NULL, SPA_FORMAT_VIDEO_modifier)) == NULL) + return -EINVAL; + + const struct spa_pod *mod_pod = &mod_prop->value; + uint32_t modifierCount = SPA_POD_CHOICE_N_VALUES(mod_pod); + uint64_t *modifiers = SPA_POD_CHOICE_VALUES(mod_pod); + if (modifierCount <= 1) + return -EINVAL; + // SPA_POD_CHOICE carries the "preferred" value at position 0 + modifierCount -= 1; + modifiers++; + + uint64_t fixed_modifier; + if (spa_vulkan_fixate_modifier(&this->state, &this->state.streams0, &info.info.dsp, modifierCount, modifiers, &fixed_modifier) != 0) + return -EINVAL; + + spa_log_info(this->log, NAME ": modifier fixated %"PRIu64, fixed_modifier); + + info.info.dsp.modifier = fixed_modifier; + info.info.dsp.flags &= ~SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED; + modifier_fixed = true; + } + + if (info.info.dsp.flags & SPA_VIDEO_FLAG_MODIFIER) { + port->info.flags |= SPA_PORT_FLAG_CAN_ALLOC_BUFFERS;
View file
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-compute-utils.c
Added
@@ -0,0 +1,675 @@ +/* Spa */ +/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#include <vulkan/vulkan.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <string.h> +#include <vulkan/vulkan_core.h> +#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) +#include <alloca.h> +#endif +#include <errno.h> +#include <stdio.h> +#include <assert.h> +#include <math.h> +#include <time.h> + +#include <spa/utils/result.h> +#include <spa/utils/string.h> +#include <spa/support/log.h> +#include <spa/debug/mem.h> + +#include "vulkan-compute-utils.h" +#include "vulkan-utils.h" + +#define VULKAN_INSTANCE_FUNCTION(name) \ + PFN_##name name = (PFN_##name)vkGetInstanceProcAddr(s->base.instance, #name) + +static int createFence(struct vulkan_compute_state *s) { + VkFenceCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = 0, + }; + VK_CHECK_RESULT(vkCreateFence(s->base.device, &createInfo, NULL, &s->fence)); + + return 0; +}; + +static int createDescriptors(struct vulkan_compute_state *s) +{ + uint32_t i; + + VkDescriptorPoolSize descriptorPoolSizes2 = { + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = 1, + }, + { + .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = s->n_streams - 1, + }, + }; + const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = s->n_streams, + .poolSizeCount = s->n_streams > 1 ? 2 : 1, + .pPoolSizes = descriptorPoolSizes, + }; + + VK_CHECK_RESULT(vkCreateDescriptorPool(s->base.device, + &descriptorPoolCreateInfo, NULL, + &s->descriptorPool)); + + VkDescriptorSetLayoutBinding descriptorSetLayoutBindings->n_streams; + descriptorSetLayoutBinding0 = (VkDescriptorSetLayoutBinding) { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT + }; + for (i = 1; i < s->n_streams; i++) { + descriptorSetLayoutBindingi = (VkDescriptorSetLayoutBinding) { + .binding = i, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT + }; + }; + const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = s->n_streams, + .pBindings = descriptorSetLayoutBinding + }; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(s->base.device, + &descriptorSetLayoutCreateInfo, NULL, + &s->descriptorSetLayout)); + + const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = s->descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &s->descriptorSetLayout + }; + + VK_CHECK_RESULT(vkAllocateDescriptorSets(s->base.device, + &descriptorSetAllocateInfo, + &s->descriptorSet)); + + const VkSamplerCreateInfo samplerInfo = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .magFilter = VK_FILTER_LINEAR, + .minFilter = VK_FILTER_LINEAR, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, + .unnormalizedCoordinates = VK_FALSE, + .compareEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_ALWAYS, + .mipLodBias = 0.0f, + .minLod = 0, + .maxLod = 5, + }; + VK_CHECK_RESULT(vkCreateSampler(s->base.device, &samplerInfo, NULL, &s->sampler)); + + return 0; +} + +static int updateDescriptors(struct vulkan_compute_state *s) +{ + uint32_t i; + VkDescriptorImageInfo descriptorImageInfos->n_streams; + VkWriteDescriptorSet writeDescriptorSets->n_streams; + uint32_t descriptorSetLen = 0; + + for (i = 0; i < s->n_streams; i++) { + struct vulkan_stream *p = &s->streamsi; + + if (p->current_buffer_id == p->pending_buffer_id || + p->pending_buffer_id == SPA_ID_INVALID) + continue; + + p->current_buffer_id = p->pending_buffer_id; + p->busy_buffer_id = p->current_buffer_id; + p->pending_buffer_id = SPA_ID_INVALID; + + descriptorImageInfodescriptorSetLen = (VkDescriptorImageInfo) { + .sampler = s->sampler, + .imageView = p->buffersp->current_buffer_id.view, + .imageLayout = VK_IMAGE_LAYOUT_GENERAL, + }; + writeDescriptorSetdescriptorSetLen = (VkWriteDescriptorSet) { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = s->descriptorSet, + .dstBinding = i, + .descriptorCount = 1, + .descriptorType = i == 0 ? + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE : + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &descriptorImageInfoi, + }; + descriptorSetLen++; + } + vkUpdateDescriptorSets(s->base.device, descriptorSetLen, + writeDescriptorSet, 0, NULL); + + return 0; +} + +static VkShaderModule createShaderModule(struct vulkan_compute_state *s, const char* shaderFile) +{ + VkShaderModule shaderModule = VK_NULL_HANDLE; + VkResult result; + void *data; + int fd; + struct stat stat; + + if ((fd = open(shaderFile, 0, O_RDONLY)) == -1) { + spa_log_error(s->log, "can't open %s: %m", shaderFile); + return VK_NULL_HANDLE; + } + if (fstat(fd, &stat) < 0) { + spa_log_error(s->log, "can't stat %s: %m", shaderFile); + close(fd); + return VK_NULL_HANDLE; + } + + data = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + + const VkShaderModuleCreateInfo shaderModuleCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = stat.st_size, + .pCode = data, + }; + result = vkCreateShaderModule(s->base.device, + &shaderModuleCreateInfo, 0, &shaderModule); + + munmap(data, stat.st_size); + close(fd); + + if (result != VK_SUCCESS) { + spa_log_error(s->log, "can't create shader %s: %m", shaderFile); + return VK_NULL_HANDLE;
View file
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-compute-utils.h
Added
@@ -0,0 +1,80 @@ +/* Spa */ +/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#include <vulkan/vulkan.h> + +#include <spa/buffer/buffer.h> +#include <spa/param/video/format.h> +#include <spa/node/node.h> + +#include "vulkan-utils.h" + +#define MAX_STREAMS 2 +#define WORKGROUP_SIZE 32 + +struct pixel { + float r, g, b, a; +}; + +struct push_constants { + float time; + int frame; + int width; + int height; +}; + + +struct vulkan_compute_state { + struct spa_log *log; + + struct push_constants constants; + + struct vulkan_base base; + + VkPipeline pipeline; + VkPipelineLayout pipelineLayout; + const char *shaderName; + VkShaderModule computeShaderModule; + + VkCommandPool commandPool; + VkCommandBuffer commandBuffer; + + VkFence fence; + VkSemaphore pipelineSemaphore; + unsigned int initialized:1; + unsigned int prepared:1; + unsigned int started:1; + + VkDescriptorPool descriptorPool; + VkDescriptorSetLayout descriptorSetLayout; + + VkSampler sampler; + + uint32_t n_streams; + VkDescriptorSet descriptorSet; + struct vulkan_stream streamsMAX_STREAMS; +}; + +int spa_vulkan_init_stream(struct vulkan_compute_state *s, struct vulkan_stream *stream, enum spa_direction, + struct spa_dict *props); + +int spa_vulkan_fixate_modifier(struct vulkan_compute_state *s, struct vulkan_stream *p, struct spa_video_info_dsp *dsp_info, + uint32_t modifierCount, uint64_t *modifiers, uint64_t *modifier); +int spa_vulkan_prepare(struct vulkan_compute_state *s); +int spa_vulkan_use_buffers(struct vulkan_compute_state *s, struct vulkan_stream *stream, uint32_t flags, + struct spa_video_info_dsp *dsp_info, uint32_t n_buffers, struct spa_buffer **buffers); +int spa_vulkan_unprepare(struct vulkan_compute_state *s); + +int spa_vulkan_start(struct vulkan_compute_state *s); +int spa_vulkan_stop(struct vulkan_compute_state *s); +int spa_vulkan_ready(struct vulkan_compute_state *s); +int spa_vulkan_process(struct vulkan_compute_state *s); +int spa_vulkan_cleanup(struct vulkan_compute_state *s); + +int spa_vulkan_get_buffer_caps(struct vulkan_compute_state *s, enum spa_direction direction); +struct vulkan_modifier_info *spa_vulkan_get_modifier_info(struct vulkan_compute_state *s, + struct spa_video_info_dsp *dsp_info); + +int spa_vulkan_init(struct vulkan_compute_state *s); +void spa_vulkan_deinit(struct vulkan_compute_state *s);
View file
pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-types.h
Added
@@ -0,0 +1,75 @@ +#pragma once + +#include <vulkan/vulkan.h> + +#include <spa/buffer/buffer.h> +#include <spa/node/node.h> + +#define MAX_BUFFERS 16 +#define DMABUF_MAX_PLANES 1 + +enum buffer_type_caps { + VULKAN_BUFFER_TYPE_CAP_SHM = 1<<0, + VULKAN_BUFFER_TYPE_CAP_DMABUF = 1<<1, +}; + +struct vulkan_modifier_info { + VkDrmFormatModifierPropertiesEXT props; + VkExtent2D max_extent; +}; + +struct vulkan_format_info { + uint32_t spa_format; + VkFormat vk_format; + uint32_t modifierCount; + struct vulkan_modifier_info *infos; +}; + +struct vulkan_buffer { + int fd; + VkImage image; + VkImageView view; + VkDeviceMemory memory; + VkSemaphore foreign_semaphore; +}; + +struct vulkan_stream { + enum spa_direction direction; + + uint32_t pending_buffer_id; + uint32_t current_buffer_id; + uint32_t busy_buffer_id; + uint32_t ready_buffer_id; + + struct vulkan_buffer buffersMAX_BUFFERS; + struct spa_buffer *spa_buffersMAX_BUFFERS; + uint32_t n_buffers; +}; + +struct vulkan_base_info { + uint32_t queueFlags; + + struct { + uint32_t formatCount; + uint32_t *formats; + } formatInfo; +}; + +struct vulkan_base { + struct spa_log *log; + + VkInstance instance; + + VkPhysicalDevice physicalDevice; + + VkQueue queue; + uint32_t queueFamilyIndex; + VkDevice device; + + uint32_t formatInfoCount; + struct vulkan_format_info *formatInfos; + + bool implicit_sync_interop; + + unsigned int initialized:1; +};
View file
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/vulkan-utils.c -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-utils.c
Changed
@@ -1,3 +1,7 @@ +/* Spa */ +/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + #include <vulkan/vulkan.h> #include <unistd.h> @@ -6,6 +10,7 @@ #include <sys/mman.h> #include <fcntl.h> #include <string.h> +#include <poll.h> #if !defined(__FreeBSD__) && !defined(__MidnightBSD__) #include <alloca.h> #endif @@ -17,10 +22,12 @@ #include <spa/utils/result.h> #include <spa/utils/string.h> +#include <spa/param/video/format.h> #include <spa/support/log.h> #include <spa/debug/mem.h> #include "vulkan-utils.h" +#include "dmabuf.h" //#define ENABLE_VALIDATION @@ -91,23 +98,14 @@ } } -#define VK_CHECK_RESULT(f) \ -{ \ - VkResult _result = (f); \ - int _r = -vkresult_to_errno(_result); \ - if (_result != VK_SUCCESS) { \ - spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \ - return _r; \ - } \ -} -#define CHECK(f) \ -{ \ - int _res = (f); \ - if (_res < 0) \ - return _res; \ -} +static struct { + VkFormat format; + uint32_t id; +} vk_video_format_convs = { + { VK_FORMAT_R32G32B32A32_SFLOAT, SPA_VIDEO_FORMAT_RGBA_F32 }, +}; -static int createInstance(struct vulkan_state *s) +static int createInstance(struct vulkan_base *s) { static const VkApplicationInfo applicationInfo = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, @@ -154,7 +152,24 @@ return 0; } -static uint32_t getComputeQueueFamilyIndex(struct vulkan_state *s) +static int findPhysicalDevice(struct vulkan_base *s) +{ + uint32_t deviceCount; + VkPhysicalDevice *devices; + + vkEnumeratePhysicalDevices(s->instance, &deviceCount, NULL); + if (deviceCount == 0) + return -ENODEV; + + devices = alloca(deviceCount * sizeof(VkPhysicalDevice)); + vkEnumeratePhysicalDevices(s->instance, &deviceCount, devices); + + s->physicalDevice = devices0; + + return 0; +} + +static int getComputeQueueFamilyIndex(struct vulkan_base *s, uint32_t queueFlags, uint32_t *queueFamilyIndex) { uint32_t i, queueFamilyCount; VkQueueFamilyProperties *queueFamilies; @@ -167,283 +182,245 @@ for (i = 0; i < queueFamilyCount; i++) { VkQueueFamilyProperties props = queueFamiliesi; - if (props.queueCount > 0 && (props.queueFlags & VK_QUEUE_COMPUTE_BIT)) + if (props.queueCount > 0 && ((props.queueFlags & queueFlags) == queueFlags)) break; } if (i == queueFamilyCount) return -ENODEV; - return i; -} - -static int findPhysicalDevice(struct vulkan_state *s) -{ - uint32_t deviceCount; - VkPhysicalDevice *devices; - - vkEnumeratePhysicalDevices(s->instance, &deviceCount, NULL); - if (deviceCount == 0) - return -ENODEV; - - devices = alloca(deviceCount * sizeof(VkPhysicalDevice)); - vkEnumeratePhysicalDevices(s->instance, &deviceCount, devices); - - s->physicalDevice = devices0; - - s->queueFamilyIndex = getComputeQueueFamilyIndex(s); - + *queueFamilyIndex = i; return 0; } -static int createDevice(struct vulkan_state *s) +static int createDevice(struct vulkan_base *s, struct vulkan_base_info *info) { + CHECK(getComputeQueueFamilyIndex(s, info->queueFlags, &s->queueFamilyIndex)); + const VkDeviceQueueCreateInfo queueCreateInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .queueFamilyIndex = s->queueFamilyIndex, .queueCount = 1, .pQueuePriorities = (const float) { 1.0f } }; + const VkPhysicalDeviceSynchronization2FeaturesKHR sync2_features = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR, + .synchronization2 = VK_TRUE, + }; static const char * const extensions = { VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, - VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME + VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, + VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, + VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, + VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME }; const VkDeviceCreateInfo deviceCreateInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queueCreateInfo, - .enabledExtensionCount = 2, + .enabledExtensionCount = SPA_N_ELEMENTS(extensions), .ppEnabledExtensionNames = extensions, + .pNext = &sync2_features, }; VK_CHECK_RESULT(vkCreateDevice(s->physicalDevice, &deviceCreateInfo, NULL, &s->device)); vkGetDeviceQueue(s->device, s->queueFamilyIndex, 0, &s->queue); - static const VkFenceCreateInfo fenceCreateInfo = { - .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - .flags = 0, - }; - VK_CHECK_RESULT(vkCreateFence(s->device, &fenceCreateInfo, NULL, &s->fence)); - return 0; } -static uint32_t findMemoryType(struct vulkan_state *s, - uint32_t memoryTypeBits, VkMemoryPropertyFlags properties) +static int queryFormatInfo(struct vulkan_base *s, struct vulkan_base_info *info) { - uint32_t i; - VkPhysicalDeviceMemoryProperties memoryProperties; + if (s->formatInfos) + return 0; - vkGetPhysicalDeviceMemoryProperties(s->physicalDevice, &memoryProperties); + s->formatInfos = calloc(info->formatInfo.formatCount, sizeof(struct vulkan_format_info)); + if (!s->formatInfos) + return -ENOMEM; - for (i = 0; i < memoryProperties.memoryTypeCount; i++) { - if ((memoryTypeBits & (1 << i)) && - ((memoryProperties.memoryTypesi.propertyFlags & properties) == properties)) - return i; - } - return -1; -} + for (uint32_t i = 0; i < info->formatInfo.formatCount; i++) { + VkFormat format = vulkan_id_to_vkformat(info->formatInfo.formatsi); + if (format == VK_FORMAT_UNDEFINED) + continue; + struct vulkan_format_info *f_info = &s->formatInfoss->formatInfoCount++; + f_info->spa_format = info->formatInfo.formatsi; + f_info->vk_format = format; -static int createDescriptors(struct vulkan_state *s) -{ - uint32_t i;
View file
pipewire-0.3.79.tar.gz/spa/plugins/vulkan/vulkan-utils.h -> pipewire-0.3.80.tar.gz/spa/plugins/vulkan/vulkan-utils.h
Changed
@@ -1,86 +1,105 @@ +/* Spa */ +/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#pragma once + #include <vulkan/vulkan.h> #include <spa/buffer/buffer.h> #include <spa/node/node.h> -#define MAX_STREAMS 2 -#define MAX_BUFFERS 16 -#define WORKGROUP_SIZE 32 - -struct pixel { - float r, g, b, a; +#include "vulkan-types.h" + +#define VK_CHECK_RESULT(f) \ +{ \ + VkResult _result = (f); \ + int _r = -vulkan_vkresult_to_errno(_result); \ + if (_result != VK_SUCCESS) { \ + spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \ + return _r; \ + } \ +} +#define VK_CHECK_RESULT_WITH_CLEANUP(f, c) \ +{ \ + VkResult _result = (f); \ + int _r = -vkresult_to_errno(_result); \ + if (_result != VK_SUCCESS) { \ + spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \ + (c); \ + return _r; \ + } \ +} +#define VK_CHECK_RESULT_LOOP(f) \ +{ \ + VkResult _result = (f); \ + int _r = -vkresult_to_errno(_result); \ + if (_result != VK_SUCCESS) { \ + spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \ + continue; \ + } \ +} +#define CHECK(f) \ +{ \ + int _res = (f); \ + if (_res < 0) \ + return _res; \ +} + +struct vulkan_read_pixels_info { + struct spa_rectangle size; + void *data; + uint32_t offset; + uint32_t stride; + uint32_t bytes_per_pixel; }; -struct push_constants { - float time; - int frame; - int width; - int height; +struct dmabuf_fixation_info { + VkFormat format; + uint64_t modifierCount; + uint64_t *modifiers; + struct spa_rectangle size; + VkImageUsageFlags usage; }; -struct vulkan_buffer { - int fd; - VkImage image; - VkImageView view; - VkDeviceMemory memory; -}; - -struct vulkan_stream { - enum spa_direction direction; - - uint32_t pending_buffer_id; - uint32_t current_buffer_id; - uint32_t busy_buffer_id; - uint32_t ready_buffer_id; - - struct vulkan_buffer buffersMAX_BUFFERS; - uint32_t n_buffers; +struct external_buffer_info { + VkFormat format; + uint64_t modifier; + struct spa_rectangle size; + VkImageUsageFlags usage; + struct spa_buffer *spa_buf; }; -struct vulkan_state { - struct spa_log *log; - - struct push_constants constants; - - VkInstance instance; +int vulkan_read_pixels(struct vulkan_base *s, struct vulkan_read_pixels_info *info, struct vulkan_buffer *vk_buf); - VkPhysicalDevice physicalDevice; - VkDevice device; +int vulkan_sync_foreign_dmabuf(struct vulkan_base *s, struct vulkan_buffer *vk_buf); +bool vulkan_sync_export_dmabuf(struct vulkan_base *s, struct vulkan_buffer *vk_buf, int sync_file_fd); - VkPipeline pipeline; - VkPipelineLayout pipelineLayout; - const char *shaderName; - VkShaderModule computeShaderModule; +int vulkan_fixate_modifier(struct vulkan_base *s, struct dmabuf_fixation_info *info, uint64_t *modifier); +int vulkan_create_dmabuf(struct vulkan_base *s, struct external_buffer_info *info, struct vulkan_buffer *vk_buf); +int vulkan_import_dmabuf(struct vulkan_base *s, struct external_buffer_info *info, struct vulkan_buffer *vk_buf); +int vulkan_import_memptr(struct vulkan_base *s, struct external_buffer_info *info, struct vulkan_buffer *vk_buf); - VkCommandPool commandPool; - VkCommandBuffer commandBuffer; +int vulkan_commandPool_create(struct vulkan_base *s, VkCommandPool *commandPool); +int vulkan_commandBuffer_create(struct vulkan_base *s, VkCommandPool commandPool, VkCommandBuffer *commandBuffer); - VkQueue queue; - uint32_t queueFamilyIndex; - VkFence fence; - unsigned int prepared:1; - unsigned int started:1; +uint32_t vulkan_memoryType_find(struct vulkan_base *s, + uint32_t memoryTypeBits, VkMemoryPropertyFlags properties); +struct vulkan_format_info *vulkan_formatInfo_find(struct vulkan_base *s, VkFormat format); +struct vulkan_modifier_info *vulkan_modifierInfo_find(struct vulkan_base *s, VkFormat format, uint64_t modifier); - VkDescriptorPool descriptorPool; - VkDescriptorSetLayout descriptorSetLayout; +void vulkan_buffer_clear(struct vulkan_base *s, struct vulkan_buffer *buffer); - VkSampler sampler; +int vulkan_stream_init(struct vulkan_stream *stream, enum spa_direction direction, + struct spa_dict *props); - uint32_t n_streams; - VkDescriptorSet descriptorSet; - struct vulkan_stream streamsMAX_STREAMS; -}; +uint32_t vulkan_vkformat_to_id(VkFormat vkFormat); +VkFormat vulkan_id_to_vkformat(uint32_t id); -int spa_vulkan_init_stream(struct vulkan_state *s, struct vulkan_stream *stream, enum spa_direction, - struct spa_dict *props); +int vulkan_vkresult_to_errno(VkResult result); -int spa_vulkan_prepare(struct vulkan_state *s); -int spa_vulkan_use_buffers(struct vulkan_state *s, struct vulkan_stream *stream, uint32_t flags, - uint32_t n_buffers, struct spa_buffer **buffers); -int spa_vulkan_unprepare(struct vulkan_state *s); +int vulkan_wait_fence(struct vulkan_base *s, VkFence fence); +int vulkan_wait_idle(struct vulkan_base *s); -int spa_vulkan_start(struct vulkan_state *s); -int spa_vulkan_stop(struct vulkan_state *s); -int spa_vulkan_ready(struct vulkan_state *s); -int spa_vulkan_process(struct vulkan_state *s); -int spa_vulkan_cleanup(struct vulkan_state *s); +int vulkan_base_init(struct vulkan_base *s, struct vulkan_base_info *info); +void vulkan_base_deinit(struct vulkan_base *s);
View file
pipewire-0.3.79.tar.gz/src/daemon/meson.build -> pipewire-0.3.80.tar.gz/src/daemon/meson.build
Changed
@@ -27,6 +27,8 @@ build_wp = 'wireplumber' in get_option('session-managers') default_sm = get_option('session-managers').get(0, '') +build_vk = get_option('vulkan').enabled() + summary({'Build media-session': build_ms, 'Build wireplumber': build_wp, 'Default session-manager': default_sm}, @@ -75,6 +77,10 @@ 'pipewire-aes67.conf', +if build_vk + conf_files += 'pipewire-vulkan.conf' +endif + foreach c : conf_files configure_file(input : '@0@.in'.format(c), output : c, @@ -107,7 +113,17 @@ ln = find_program('ln') -foreach alias : 'pipewire-pulse', 'pipewire-avb', 'pipewire-aes67' +pipewire_aliases = + 'pipewire-pulse', + 'pipewire-avb', + 'pipewire-aes67', + + +if build_vk + pipewire_aliases += 'pipewire-vulkan' +endif + +foreach alias : pipewire_aliases custom_target( alias, build_by_default: true,
View file
pipewire-0.3.79.tar.gz/src/daemon/minimal.conf.in -> pipewire-0.3.80.tar.gz/src/daemon/minimal.conf.in
Changed
@@ -144,11 +144,11 @@ # 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-node-factory args = { factory.name = videotestsrc node.name = videotestsrc node.description = 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 = adapter args = { factory.name = audiotestsrc node.name = my-test node.description = audiotestsrc } } #{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } } # Make a default metadata store
View file
pipewire-0.3.80.tar.gz/src/daemon/pipewire-vulkan.conf.in
Added
@@ -0,0 +1,98 @@ +# Config file for PipeWire version "0.3.77" # +# +# This config file should start the vulkan-compute-source/filter as proxied +# clients +# + +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 = 4 + #cpu.zero.denormals = false + + #default.clock.quantum-limit = 8192 +} + +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. + # + api.vulkan.* = vulkan/libspa-vulkan + support.* = support/libspa-support +} + +context.modules = + #{ name = <module-name> + # ( args = { <key> = <value> ... } ) + # ( flags = ( ifexists ) ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) + #} + # + # Loads a module with the given parameters. + # If ifexists is given, the module is ignored when it is not found. + # If nofail is given, module initialization failures are ignored. + # If condition is given, the module is loaded only when the context + # properties all match the match rules. + # + + # Uses realtime scheduling to boost the audio thread priorities. This uses + # 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 } + + # 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 } + + # Makes a factory for wrapping nodes in an adapter with a + # converter and resampler. + { name = libpipewire-module-adapter } + + +context.objects = + #{ factory = <factory-name> + # ( args = { <key> = <value> ... } ) + # ( flags = ( nofail ) ) + # ( condition = { <key> = <value> ... } ... ) + #} + # + # Creates an object from a PipeWire factory with the given parameters. + # If nofail is given, errors are ignored (and no object is created). + # If condition is given, the object is created only when the context properties + # all match the match rules. + # + #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } } + #{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = nofail } + #{ 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 = vulkan-compute-source object.export = true } } + { factory = spa-node-factory args = { factory.name = api.vulkan.compute.filter node.name = vulkan-compute-filter object.export = true } } +
View file
pipewire-0.3.79.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.80.tar.gz/src/daemon/pipewire.conf.in
Changed
@@ -193,11 +193,11 @@ # If condition is given, the object is created only when the context properties # all match the match rules. # - #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc Spa:Pod:Object:Param:Props:patternType = 1 } } + #{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc node.description = 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 = adapter args = { factory.name = audiotestsrc node.name = my-test node.description = audiotestsrc } } #{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } } # A default dummy driver. This handles nodes marked with the "node.always-driver"
View file
pipewire-0.3.79.tar.gz/src/examples/video-play.c -> pipewire-0.3.80.tar.gz/src/examples/video-play.c
Changed
@@ -14,8 +14,10 @@ #include <spa/utils/result.h> #include <spa/param/video/format-utils.h> +#include <spa/param/tag-utils.h> #include <spa/param/props.h> #include <spa/debug/format.h> +#include <spa/debug/pod.h> #include <pipewire/pipewire.h> @@ -278,6 +280,10 @@ void *d; int32_t mult, size; + if (param != NULL && id == SPA_PARAM_Tag) { + spa_debug_pod(0, NULL, param); + return; + } /* NULL means to clear the format */ if (param == NULL || id != SPA_PARAM_Format) return; @@ -422,7 +428,7 @@ int main(int argc, char *argv) { struct data data = { 0, }; - const struct spa_pod *params2; + const struct spa_pod *params3; uint8_t buffer1024; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); struct pw_properties *props; @@ -478,6 +484,16 @@ * object to the stack. */ n_params = build_format(&data, &b, params); + { + struct spa_pod_frame f; + struct spa_dict_item items1; + /* send a tag, input tags travel upstream */ + spa_tag_build_start(&b, &f, SPA_PARAM_Tag, SPA_DIRECTION_INPUT); + items0 = SPA_DICT_ITEM_INIT("my-tag-other-key", "my-special-other-tag-value"); + spa_tag_build_add_dict(&b, &SPA_DICT_INIT(items, 1)); + paramsn_params++ = spa_tag_build_end(&b, &f); + } + /* now connect the stream, we need a direction (input/output), * an optional target node to connect to, some flags and parameters */
View file
pipewire-0.3.79.tar.gz/src/examples/video-src.c -> pipewire-0.3.80.tar.gz/src/examples/video-src.c
Changed
@@ -14,6 +14,8 @@ #include <math.h> #include <spa/param/video/format-utils.h> +#include <spa/param/tag-utils.h> +#include <spa/debug/pod.h> #include <pipewire/pipewire.h> @@ -212,6 +214,10 @@ struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); const struct spa_pod *params5; + if (param != NULL && id == SPA_PARAM_Tag) { + spa_debug_pod(0, NULL, param); + return; + } if (param == NULL || id != SPA_PARAM_Format) return; @@ -276,7 +282,7 @@ int main(int argc, char *argv) { struct data data = { 0, }; - const struct spa_pod *params1; + const struct spa_pod *params2; uint8_t buffer1024; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); @@ -314,6 +320,16 @@ &SPA_RECTANGLE(4096, 4096)), SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&SPA_FRACTION(25, 1))); + { + struct spa_pod_frame f; + struct spa_dict_item items1; + /* send a tag, output tags travel downstream */ + spa_tag_build_start(&b, &f, SPA_PARAM_Tag, SPA_DIRECTION_OUTPUT); + items0 = SPA_DICT_ITEM_INIT("my-tag-key", "my-special-tag-value"); + spa_tag_build_add_dict(&b, &SPA_DICT_INIT(items, 1)); + params1 = spa_tag_build_end(&b, &f); + } + pw_stream_add_listener(data.stream, &data.stream_listener, &stream_events, @@ -324,7 +340,7 @@ PW_ID_ANY, PW_STREAM_FLAG_DRIVER | PW_STREAM_FLAG_MAP_BUFFERS, - params, 1); + params, 2); pw_main_loop_run(data.loop);
View file
pipewire-0.3.79.tar.gz/src/modules/module-combine-stream.c -> pipewire-0.3.80.tar.gz/src/modules/module-combine-stream.c
Changed
@@ -697,7 +697,7 @@ update_delay(s->impl); break; case SPA_PARAM_Latency: - if (!param) { + if (param == NULL) { s->have_latency = false; } else if (spa_latency_parse(param, &latency) == 0 && latency.direction == get_combine_direction(s->impl)) {
View file
pipewire-0.3.79.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.80.tar.gz/src/modules/module-echo-cancel.c
Changed
@@ -604,7 +604,7 @@ struct spa_pod_builder b; const struct spa_pod *params1; - if (spa_latency_parse(param, &latency) < 0) + if (param == NULL || spa_latency_parse(param, &latency) < 0) return; spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -767,7 +767,7 @@ struct spa_pod_builder b; const struct spa_pod *params1; - if (spa_latency_parse(param, &latency) < 0) + if (param == NULL || spa_latency_parse(param, &latency) < 0) return; spa_pod_builder_init(&b, buffer, sizeof(buffer));
View file
pipewire-0.3.79.tar.gz/src/modules/module-example-filter.c -> pipewire-0.3.80.tar.gz/src/modules/module-example-filter.c
Changed
@@ -227,7 +227,7 @@ struct spa_pod_builder b; const struct spa_pod *params1; - if (spa_latency_parse(param, &latency) < 0) + if (param == NULL || spa_latency_parse(param, &latency) < 0) return; *info = latency;
View file
pipewire-0.3.79.tar.gz/src/modules/module-ffado-driver.c -> pipewire-0.3.80.tar.gz/src/modules/module-ffado-driver.c
Changed
@@ -417,7 +417,7 @@ bool update = false; enum spa_direction direction = port->direction; - if (spa_latency_parse(param, &latency) < 0) + if (param == NULL || spa_latency_parse(param, &latency) < 0) return; if (spa_latency_info_compare(&port->latencydirection, &latency)) {
View file
pipewire-0.3.79.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.80.tar.gz/src/modules/module-filter-chain.c
Changed
@@ -20,6 +20,7 @@ #include <spa/utils/json.h> #include <spa/support/cpu.h> #include <spa/param/latency-utils.h> +#include <spa/param/tag-utils.h> #include <spa/pod/dynamic.h> #include <spa/debug/types.h> @@ -1109,7 +1110,7 @@ struct spa_pod_builder b; const struct spa_pod *params1; - if (spa_latency_parse(param, &latency) < 0) + if (param == NULL || spa_latency_parse(param, &latency) < 0) return; spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -1121,6 +1122,21 @@ pw_stream_update_params(impl->playback, params, 1); } +static void param_tag_changed(struct impl *impl, const struct spa_pod *param) +{ + struct spa_tag_info tag; + const struct spa_pod *params1 = { param }; + void *state = NULL; + + if (param == 0 || spa_tag_parse(param, &tag, &state) < 0) + return; + + if (tag.direction == SPA_DIRECTION_INPUT) + pw_stream_update_params(impl->capture, params, 1); + else + pw_stream_update_params(impl->playback, params, 1); +} + static void state_changed(void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { @@ -1208,6 +1224,9 @@ case SPA_PARAM_Latency: param_latency_changed(impl, param); break; + case SPA_PARAM_Tag: + param_tag_changed(impl, param); + break; } return;
View file
pipewire-0.3.79.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.80.tar.gz/src/modules/module-filter-chain/builtin_plugin.c
Changed
@@ -921,7 +921,7 @@ pw_log_error("convolver:filename requires a string or an array"); return NULL; } else { - filenamesi = strdup(v); + filenames0 = strdup(v); } } else if (spa_streq(key, "offset")) {
View file
pipewire-0.3.79.tar.gz/src/modules/module-jack-tunnel.c -> pipewire-0.3.80.tar.gz/src/modules/module-jack-tunnel.c
Changed
@@ -410,7 +410,7 @@ bool update = false; enum spa_direction direction = port->direction; - if (spa_latency_parse(param, &latency) < 0) + if (param == NULL || spa_latency_parse(param, &latency) < 0) return; if (spa_latency_info_compare(&port->latencydirection, &latency)) {
View file
pipewire-0.3.79.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.80.tar.gz/src/modules/module-loopback.c
Changed
@@ -171,13 +171,11 @@ struct pw_stream *capture; struct spa_hook capture_listener; struct spa_audio_info_raw capture_info; - struct spa_latency_info capture_latency; struct pw_properties *playback_props; struct pw_stream *playback; struct spa_hook playback_listener; struct spa_audio_info_raw playback_info; - struct spa_latency_info playback_latency; unsigned int do_disconnect:1; unsigned int recalc_delay:1; @@ -317,18 +315,16 @@ } static void param_latency_changed(struct impl *impl, const struct spa_pod *param, - struct spa_latency_info *info, struct pw_stream *other) + struct pw_stream *other) { struct spa_latency_info latency; uint8_t buffer1024; struct spa_pod_builder b; const struct spa_pod *params1; - if (spa_latency_parse(param, &latency) < 0) + if (param == NULL || spa_latency_parse(param, &latency) < 0) return; - *info = latency; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); params0 = spa_latency_build(&b, SPA_PARAM_Latency, &latency); pw_stream_update_params(other, params, 1); @@ -336,6 +332,15 @@ impl->recalc_delay = true; } +static void param_tag_changed(struct impl *impl, const struct spa_pod *param, + struct pw_stream *other) +{ + const struct spa_pod *params1 = { param }; + if (param == NULL) + return; + pw_stream_update_params(other, params, 1); +} + static void recalculate_buffer(struct impl *impl) { if (impl->target_delay > 0.0f) { @@ -414,7 +419,10 @@ break; } case SPA_PARAM_Latency: - param_latency_changed(impl, param, &impl->capture_latency, impl->playback); + param_latency_changed(impl, param, impl->playback); + break; + case SPA_PARAM_Tag: + param_tag_changed(impl, param, impl->playback); break; } } @@ -453,7 +461,10 @@ switch (id) { case SPA_PARAM_Latency: - param_latency_changed(impl, param, &impl->playback_latency, impl->capture); + param_latency_changed(impl, param, impl->capture); + break; + case SPA_PARAM_Tag: + param_tag_changed(impl, param, impl->capture); break; } }
View file
pipewire-0.3.79.tar.gz/src/modules/module-netjack2-driver.c -> pipewire-0.3.80.tar.gz/src/modules/module-netjack2-driver.c
Changed
@@ -371,7 +371,7 @@ bool update = false; enum spa_direction direction = port->direction; - if (spa_latency_parse(param, &latency) < 0) + if (param == NULL || spa_latency_parse(param, &latency) < 0) return; if (spa_latency_info_compare(&port->latencydirection, &latency)) {
View file
pipewire-0.3.79.tar.gz/src/modules/module-netjack2-manager.c -> pipewire-0.3.80.tar.gz/src/modules/module-netjack2-manager.c
Changed
@@ -493,7 +493,7 @@ bool update = false; enum spa_direction direction = port->direction; - if (spa_latency_parse(param, &latency) < 0) + if (param == NULL || spa_latency_parse(param, &latency) < 0) return; if (spa_latency_info_compare(&port->latencydirection, &latency)) {
View file
pipewire-0.3.79.tar.gz/src/modules/module-pipe-tunnel.c -> pipewire-0.3.80.tar.gz/src/modules/module-pipe-tunnel.c
Changed
@@ -111,6 +111,9 @@ #define DEFAULT_CHANNELS 2 #define DEFAULT_POSITION " FL FR " +#define RINGBUFFER_SIZE (1u << 22) +#define RINGBUFFER_MASK (RINGBUFFER_SIZE-1) + PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); #define PW_LOG_TOPIC_DEFAULT mod_topic @@ -137,6 +140,7 @@ struct impl { struct pw_context *context; + struct pw_loop *data_loop; #define MODE_PLAYBACK 0 #define MODE_CAPTURE 1 @@ -156,6 +160,8 @@ char *filename; unsigned int unlink_fifo; int fd; + struct spa_source *socket; + struct spa_source *timer; struct pw_properties *stream_props; enum pw_direction direction; @@ -165,10 +171,78 @@ uint32_t frame_size; unsigned int do_disconnect:1; - uint32_t leftover_count; - uint8_t *leftover; + unsigned int driving:1; + unsigned int have_sync:1; + + struct spa_ringbuffer ring; + void *buffer; + uint32_t target_buffer; + + struct spa_io_rate_match *rate_match; + struct spa_io_position *position; + + struct spa_dll dll; + float max_error; + float corr; + + uint64_t next_time; }; +static uint64_t get_time_ns(struct impl *impl) +{ + struct timespec now; + if (spa_system_clock_gettime(impl->data_loop->system, CLOCK_MONOTONIC, &now) < 0) + return 0; + return SPA_TIMESPEC_TO_NSEC(&now); +} + +static int set_timeout(struct impl *impl, uint64_t time) +{ + struct timespec timeout, interval; + timeout.tv_sec = time / SPA_NSEC_PER_SEC; + timeout.tv_nsec = time % SPA_NSEC_PER_SEC; + interval.tv_sec = 0; + interval.tv_nsec = 0; + pw_loop_update_timer(impl->data_loop, + impl->timer, &timeout, &interval, true); + return 0; +} + +static void on_timeout(void *d, uint64_t expirations) +{ + struct impl *impl = d; + uint64_t duration, current_time; + uint32_t rate, index; + int32_t avail; + struct spa_io_position *pos = impl->position; + + if (SPA_LIKELY(pos)) { + duration = pos->clock.target_duration; + rate = pos->clock.target_rate.denom; + } else { + duration = 1024; + rate = 48000; + } + pw_log_debug("timeout %"PRIu64, duration); + + current_time = impl->next_time; + impl->next_time += duration / impl->corr * 1e9 / rate; + avail = spa_ringbuffer_get_read_index(&impl->ring, &index); + + if (SPA_LIKELY(pos)) { + pos->clock.nsec = current_time; + pos->clock.rate = pos->clock.target_rate; + pos->clock.position += pos->clock.duration; + pos->clock.duration = pos->clock.target_duration; + pos->clock.delay = SPA_SCALE32_UP(avail, rate, impl->info.rate); + pos->clock.rate_diff = impl->corr; + pos->clock.next_nsec = impl->next_time; + } + set_timeout(impl, impl->next_time); + + pw_stream_trigger_process(impl->stream); +} + static void stream_destroy(void *d) { struct impl *impl = d; @@ -186,8 +260,20 @@ pw_impl_module_schedule_destroy(impl->module); break; case PW_STREAM_STATE_PAUSED: + if (impl->direction == PW_DIRECTION_OUTPUT) { + pw_loop_update_io(impl->data_loop, impl->socket, 0); + set_timeout(impl, 0); + } break; case PW_STREAM_STATE_STREAMING: + if (impl->direction == PW_DIRECTION_OUTPUT) { + pw_loop_update_io(impl->data_loop, impl->socket, SPA_IO_IN); + impl->driving = pw_stream_is_driving(impl->stream); + if (impl->driving) { + impl->next_time = get_time_ns(impl); + set_timeout(impl, impl->next_time); + } + } break; default: break; @@ -221,9 +307,12 @@ continue; } else if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Don't continue writing */ + pw_log_debug("pipe (%s) overrun: %m", + impl->filename); break; } else { - pw_log_warn("Failed to write to pipe sink"); + pw_log_warn("Failed to write to pipe (%s): %m", + impl->filename); } } offs += written; @@ -233,53 +322,95 @@ pw_stream_queue_buffer(impl->stream, buf); } +static void update_rate(struct impl *impl, uint32_t filled) +{ + float error; + + if (impl->rate_match == NULL) + return; + + error = (float)impl->target_buffer - (float)(filled); + error = SPA_CLAMP(error, -impl->max_error, impl->max_error); + + impl->corr = spa_dll_update(&impl->dll, error); + pw_log_debug("error:%f corr:%f current:%u target:%u", + error, impl->corr, filled, impl->target_buffer); + + if (!impl->driving) { + SPA_FLAG_SET(impl->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE); + impl->rate_match->rate = 1.0f / impl->corr; + } +} + static void capture_stream_process(void *data) { struct impl *impl = data; struct pw_buffer *buf; - struct spa_data *d; - uint32_t req; - ssize_t nread; + struct spa_data *bd; + uint32_t req, index, size; + int32_t avail; if ((buf = pw_stream_dequeue_buffer(impl->stream)) == NULL) { - pw_log_debug("out of buffers: %m"); + pw_log_warn("out of buffers: %m"); return; } - d = &buf->buffer->datas0; + bd = &buf->buffer->datas0; if ((req = buf->requested * impl->frame_size) == 0) req = 4096 * impl->frame_size; - req = SPA_MIN(req, d->maxsize); + size = SPA_MIN(req, bd->maxsize); + size = SPA_ROUND_DOWN(size, impl->frame_size); - d->chunk->offset = 0; - d->chunk->stride = impl->frame_size; - d->chunk->size = SPA_MIN(req, impl->leftover_count); - memcpy(d->data, impl->leftover, d->chunk->size); - req -= d->chunk->size; + avail = spa_ringbuffer_get_read_index(&impl->ring, &index);
View file
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/manager.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/manager.c
Changed
@@ -318,7 +318,7 @@ case SPA_PARAM_EnumRoute: changed++; break; - case SPA_PARAM_Route: + default: break; } add_param(&o->pending_list, info->paramsi.seq, id, NULL); @@ -435,7 +435,16 @@ continue; info->paramsi.user = 0; - changed++; + switch (id) { + case SPA_PARAM_Props: + case SPA_PARAM_PropInfo: + case SPA_PARAM_Format: + case SPA_PARAM_EnumFormat: + changed++; + break; + default: + break; + } add_param(&o->pending_list, info->paramsi.seq, id, NULL); if (!(info->paramsi.flags & SPA_PARAM_INFO_READ)) continue;
View file
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/module.c
Changed
@@ -164,6 +164,28 @@ } } +static bool find_key(const char * const keys, const char *key) +{ + for (int i = 0; keysi != NULL; i++) + if (spa_streq(keysi, key)) + return true; + return false; +} + +static int module_args_check(struct pw_properties *props, const char * const valid_args) +{ + if (valid_args != NULL) { + const struct spa_dict_item *it; + spa_dict_for_each(it, &props->dict) { + if (!find_key(valid_args, it->key)) { + pw_log_warn("'%s' is not a valid module argument key", it->key); + return -EINVAL; + } + } + } + return 0; +} + int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props, const char *key_format, const char *key_rate, const char *key_channels, const char *key_channel_map, @@ -299,6 +321,7 @@ { const struct module_info *info; struct module *module; + int res; info = find_module_info(name); if (info == NULL) { @@ -321,19 +344,19 @@ return NULL; module->props = pw_properties_new(NULL, NULL); - if (module->props == NULL) { - module_free(module); - return NULL; - } + if (module->props == NULL) + goto error_free; if (args) module_args_add_props(module->props, args); + if ((res = module_args_check(module->props, info->valid_args)) < 0) { + errno = -res; + goto error_free; + } - int res = module->info->prepare(module); - if (res < 0) { - module_free(module); + if ((res = module->info->prepare(module)) < 0) { errno = -res; - return NULL; + goto error_free; } module->index = pw_map_insert_new(&impl->modules, module); @@ -346,4 +369,9 @@ module->index |= MODULE_FLAG; return module; + +error_free: + module_free(module); + return NULL; + }
View file
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/module.h -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/module.h
Changed
@@ -23,6 +23,7 @@ int (*load) (struct module *module); int (*unload) (struct module *module); + const char* const *valid_args; const struct spa_dict *properties; size_t data_size; };
View file
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c
Changed
@@ -26,7 +26,7 @@ struct pw_impl_module *mod; struct pw_properties *global_props; - struct pw_properties *capture_props; + struct pw_properties *stream_props; }; static void module_destroy(void *data) @@ -49,7 +49,7 @@ char *args; size_t size; - pw_properties_setf(data->capture_props, "pulse.module.id", + pw_properties_setf(data->stream_props, "pulse.module.id", "%u", module->index); if ((f = open_memstream(&args, &size)) == NULL) @@ -58,7 +58,7 @@ fprintf(f, "{"); pw_properties_serialize_dict(f, &data->global_props->dict, 0); fprintf(f, " \"stream.props\": {"); - pw_properties_serialize_dict(f, &data->capture_props->dict, 0); + pw_properties_serialize_dict(f, &data->stream_props->dict, 0); fprintf(f, " } }"); fclose(f); @@ -86,7 +86,7 @@ pw_impl_module_destroy(d->mod); d->mod = NULL; } - pw_properties_free(d->capture_props); + pw_properties_free(d->stream_props); pw_properties_free(d->global_props); return 0; } @@ -100,7 +100,8 @@ "format=<sample format> " "rate=<sample rate> " "channels=<number of channels> " - "channel_map=<channel map> " }, + "channel_map=<channel map> " + "use_system_clock_for_timing=<yes or no> " }, { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; @@ -108,16 +109,17 @@ { struct module_pipesink_data * const d = module->user_data; struct pw_properties * const props = module->props; - struct pw_properties *global_props = NULL, *capture_props = NULL; + struct pw_properties *global_props = NULL, *stream_props = NULL; struct spa_audio_info_raw info = { 0 }; const char *str; + bool use_system_clock; int res = 0; PW_LOG_TOPIC_INIT(mod_topic); global_props = pw_properties_new(NULL, NULL); - capture_props = pw_properties_new(NULL, NULL); - if (!global_props || !capture_props) { + stream_props = pw_properties_new(NULL, NULL); + if (!global_props || !stream_props) { res = -EINVAL; goto out; } @@ -133,31 +135,39 @@ audioinfo_to_properties(&info, global_props); if ((str = pw_properties_get(props, "sink_name")) != NULL) { - pw_properties_set(capture_props, PW_KEY_NODE_NAME, str); + pw_properties_set(stream_props, PW_KEY_NODE_NAME, str); pw_properties_set(props, "sink_name", NULL); } if ((str = pw_properties_get(props, "sink_properties")) != NULL) - module_args_add_props(capture_props, str); + module_args_add_props(stream_props, str); if ((str = pw_properties_get(props, "file")) != NULL) { pw_properties_set(global_props, "pipe.filename", str); pw_properties_set(props, "file", NULL); } - if ((str = pw_properties_get(capture_props, PW_KEY_DEVICE_ICON_NAME)) == NULL) - pw_properties_set(capture_props, PW_KEY_DEVICE_ICON_NAME, + str = pw_properties_get(props, "use_system_clock_for_timing"); + use_system_clock = str ? module_args_parse_bool(str) : false; + + if ((str = pw_properties_get(stream_props, PW_KEY_NODE_GROUP)) == NULL) { + if (use_system_clock) + pw_properties_set(stream_props, PW_KEY_NODE_GROUP, + "pipewire.dummy"); + } + if ((str = pw_properties_get(stream_props, PW_KEY_DEVICE_ICON_NAME)) == NULL) + pw_properties_set(stream_props, PW_KEY_DEVICE_ICON_NAME, "audio-card"); - if ((str = pw_properties_get(capture_props, PW_KEY_NODE_NAME)) == NULL) - pw_properties_set(capture_props, PW_KEY_NODE_NAME, + if ((str = pw_properties_get(stream_props, PW_KEY_NODE_NAME)) == NULL) + pw_properties_set(stream_props, PW_KEY_NODE_NAME, "fifo_output"); d->module = module; d->global_props = global_props; - d->capture_props = capture_props; + d->stream_props = stream_props; return 0; out: pw_properties_free(global_props); - pw_properties_free(capture_props); + pw_properties_free(stream_props); return res; }
View file
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c
Changed
@@ -26,7 +26,7 @@ struct pw_impl_module *mod; struct pw_properties *global_props; - struct pw_properties *playback_props; + struct pw_properties *stream_props; }; static void module_destroy(void *data) @@ -49,7 +49,7 @@ char *args; size_t size; - pw_properties_setf(data->playback_props, "pulse.module.id", + pw_properties_setf(data->stream_props, "pulse.module.id", "%u", module->index); if ((f = open_memstream(&args, &size)) == NULL) @@ -58,7 +58,7 @@ fprintf(f, "{"); pw_properties_serialize_dict(f, &data->global_props->dict, 0); fprintf(f, " \"stream.props\": {"); - pw_properties_serialize_dict(f, &data->playback_props->dict, 0); + pw_properties_serialize_dict(f, &data->stream_props->dict, 0); fprintf(f, " } }"); fclose(f); @@ -86,7 +86,7 @@ pw_impl_module_destroy(d->mod); d->mod = NULL; } - pw_properties_free(d->playback_props); + pw_properties_free(d->stream_props); pw_properties_free(d->global_props); return 0; } @@ -108,7 +108,7 @@ { struct module_pipesrc_data * const d = module->user_data; struct pw_properties * const props = module->props; - struct pw_properties *global_props = NULL, *playback_props = NULL; + struct pw_properties *global_props = NULL, *stream_props = NULL; struct spa_audio_info_raw info = { 0 }; const char *str; int res = 0; @@ -116,8 +116,8 @@ PW_LOG_TOPIC_INIT(mod_topic); global_props = pw_properties_new(NULL, NULL); - playback_props = pw_properties_new(NULL, NULL); - if (!global_props || !playback_props) { + stream_props = pw_properties_new(NULL, NULL); + if (!global_props || !stream_props) { res = -errno; goto out; } @@ -133,31 +133,36 @@ audioinfo_to_properties(&info, global_props); if ((str = pw_properties_get(props, "source_name")) != NULL) { - pw_properties_set(playback_props, PW_KEY_NODE_NAME, str); + pw_properties_set(stream_props, PW_KEY_NODE_NAME, str); pw_properties_set(props, "source_name", NULL); } if ((str = pw_properties_get(props, "source_properties")) != NULL) - module_args_add_props(playback_props, str); + module_args_add_props(stream_props, str); if ((str = pw_properties_get(props, "file")) != NULL) { pw_properties_set(global_props, "pipe.filename", str); pw_properties_set(props, "file", NULL); } - if ((str = pw_properties_get(playback_props, PW_KEY_DEVICE_ICON_NAME)) == NULL) - pw_properties_set(playback_props, PW_KEY_DEVICE_ICON_NAME, + if ((str = pw_properties_get(stream_props, PW_KEY_DEVICE_ICON_NAME)) == NULL) + pw_properties_set(stream_props, PW_KEY_DEVICE_ICON_NAME, "audio-input-microphone"); - if ((str = pw_properties_get(playback_props, PW_KEY_NODE_NAME)) == NULL) - pw_properties_set(playback_props, PW_KEY_NODE_NAME, + if ((str = pw_properties_get(stream_props, PW_KEY_NODE_NAME)) == NULL) + pw_properties_set(stream_props, PW_KEY_NODE_NAME, "fifo_input"); + if ((str = pw_properties_get(stream_props, PW_KEY_NODE_DRIVER)) == NULL) + pw_properties_set(stream_props, PW_KEY_NODE_DRIVER, "true"); + if ((str = pw_properties_get(stream_props, PW_KEY_PRIORITY_DRIVER)) == NULL) + pw_properties_set(stream_props, PW_KEY_PRIORITY_DRIVER, "50000"); + d->module = module; - d->playback_props = playback_props; + d->stream_props = stream_props; d->global_props = global_props; return 0; out: pw_properties_free(global_props); - pw_properties_free(playback_props); + pw_properties_free(stream_props); return res; }
View file
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c
Changed
@@ -89,6 +89,15 @@ return 0; } +static const char* const valid_args = { + "sink_name", + "sink_properties", + "fec_code", + "remote_ip", + "remote_source_port", + "remote_repair_port", + NULL +}; static const struct spa_dict_item module_roc_sink_info = { { PW_KEY_MODULE_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" }, { PW_KEY_MODULE_DESCRIPTION, "roc sink" }, @@ -169,6 +178,7 @@ DEFINE_MODULE_INFO(module_roc_sink) = { .name = "module-roc-sink", + .valid_args = valid_args, .prepare = module_roc_sink_prepare, .load = module_roc_sink_load, .unload = module_roc_sink_unload,
View file
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c
Changed
@@ -89,6 +89,18 @@ return 0; } +static const char* const valid_args = { + "source_name", + "source_properties", + "resampler_profile", + "fec_code", + "sess_latency_msec", + "local_ip", + "local_source_port", + "local_repair_port", + NULL +}; + static const struct spa_dict_item module_roc_source_info = { { PW_KEY_MODULE_AUTHOR, "Sanchayan Maity <sanchayan@asymptotic.io>" }, { PW_KEY_MODULE_DESCRIPTION, "roc source" }, @@ -178,6 +190,7 @@ DEFINE_MODULE_INFO(module_roc_source) = { .name = "module-roc-source", + .valid_args = valid_args, .prepare = module_roc_source_prepare, .load = module_roc_source_load, .unload = module_roc_source_unload,
View file
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
@@ -2505,8 +2505,12 @@ allow_monitor = true; } } - } else if (index == SPA_ID_INVALID) + } else if (index != SPA_ID_INVALID) { + if (!sink) + allow_monitor = true; + } else { return NULL; + } spa_zero(sel);
View file
pipewire-0.3.79.tar.gz/src/modules/module-protocol-pulse/stream.c -> pipewire-0.3.80.tar.gz/src/modules/module-protocol-pulse/stream.c
Changed
@@ -216,11 +216,11 @@ struct client *client = stream->client; struct impl *impl = client->impl; struct message *reply; - int missed; + int suppressed; - if ((missed = spa_ratelimit_test(&impl->rate_limit, stream->timestamp)) >= 0) { - pw_log_info("%s: UNDERFLOW channel:%u offset:%" PRIi64" (%d missed)", - client->name, stream->channel, offset, missed); + if ((suppressed = spa_ratelimit_test(&impl->rate_limit, stream->timestamp)) >= 0) { + pw_log_info("%s: UNDERFLOW channel:%u offset:%" PRIi64" (%d suppressed)", + client->name, stream->channel, offset, suppressed); } reply = message_alloc(impl, -1, 0);
View file
pipewire-0.3.79.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.80.tar.gz/src/modules/module-pulse-tunnel.c
Changed
@@ -393,23 +393,26 @@ req = 4096 * impl->frame_size; size = SPA_MIN(bd->maxsize, req); + size = SPA_ROUND_DOWN(size, impl->frame_size); avail = spa_ringbuffer_get_read_index(&impl->ring, &index); - if (avail < (int32_t)size) { + if (avail < (int32_t)size) memset(bd->data, 0, size); - } else { - if (avail > (int32_t)RINGBUFFER_SIZE) { - avail = impl->target_buffer; - index += avail - impl->target_buffer; - } else { - update_rate(impl, avail / impl->frame_size); - } + if (avail > (int32_t)RINGBUFFER_SIZE) { + index += avail - impl->target_buffer; + avail = impl->target_buffer; + } + if (avail > 0) { + avail = SPA_ROUND_DOWN(avail, impl->frame_size); + update_rate(impl, avail / impl->frame_size); + + avail = SPA_MIN(size, (uint32_t)avail); spa_ringbuffer_read_data(&impl->ring, impl->buffer, RINGBUFFER_SIZE, index & RINGBUFFER_MASK, - bd->data, size); + bd->data, avail); - index += size; + index += avail; spa_ringbuffer_read_update(&impl->ring, index); } bd->chunk->offset = 0; @@ -669,22 +672,22 @@ { struct impl *impl = userdata; struct timespec ts; - int missed; + int suppressed; clock_gettime(CLOCK_MONOTONIC, &ts); - if ((missed = spa_ratelimit_test(&impl->rate_limit, SPA_TIMESPEC_TO_NSEC(&ts))) >= 0) - pw_log_warn("underflow (%d missed)", missed); + if ((suppressed = spa_ratelimit_test(&impl->rate_limit, SPA_TIMESPEC_TO_NSEC(&ts))) >= 0) + pw_log_warn("underflow (%d suppressed)", suppressed); impl->resync = true; } static void stream_overflow_cb(pa_stream *s, void *userdata) { struct impl *impl = userdata; struct timespec ts; - int missed; + int suppressed; clock_gettime(CLOCK_MONOTONIC, &ts); - if ((missed = spa_ratelimit_test(&impl->rate_limit, SPA_TIMESPEC_TO_NSEC(&ts))) >= 0) - pw_log_warn("overflow (%d missed)", missed); + if ((suppressed = spa_ratelimit_test(&impl->rate_limit, SPA_TIMESPEC_TO_NSEC(&ts))) >= 0) + pw_log_warn("overflow (%d suppressed)", suppressed); impl->resync = true; }
View file
pipewire-0.3.79.tar.gz/src/modules/module-rtp-source.c -> pipewire-0.3.80.tar.gz/src/modules/module-rtp-source.c
Changed
@@ -40,7 +40,7 @@ * The `rtp-source` module creates a PipeWire source that receives audio * and midi RTP packets. * - * This module is usually loaded from the \page page_module_rtp_sap so that the + * This module is usually loaded from the \ref page_module_rtp_sap so that the * source.ip and source.port and format parameters matches that of the sender. * * ## Module Options
View file
pipewire-0.3.79.tar.gz/src/pipewire/context.c -> pipewire-0.3.80.tar.gz/src/pipewire/context.c
Changed
@@ -807,7 +807,7 @@ spa_list_for_each(l, &p->links, input_link) { t = l->output->node; - if (!t->active || !l->prepared || (!t->driving && t->runnable)) + if (!t->active || !l->prepared || (!t->driving && SPA_FLAG_IS_SET(t->checked, 1u<<direction))) continue; pw_log_debug(" peer %p: '%s'", t, t->name); @@ -820,7 +820,7 @@ spa_list_for_each(l, &p->links, output_link) { t = l->input->node; - if (!t->active || !l->prepared || (!t->driving && t->runnable)) + if (!t->active || !l->prepared || (!t->driving && SPA_FLAG_IS_SET(t->checked, 1u<<direction))) continue; pw_log_debug(" peer %p: '%s'", t, t->name); @@ -837,7 +837,7 @@ if (node->link_group != NULL) { spa_list_for_each(t, nodes, sort_link) { if (t->exported || !t->active || - SPA_FLAG_IS_SET(t->checked, 1u<<direction)) + SPA_FLAG_IS_SET(t->checked, 1u<<direction)) continue; if (!spa_streq(t->link_group, node->link_group)) continue; @@ -1496,6 +1496,9 @@ n->rt.position->clock.rate = n->target_rate; } n->target_pending = false; + } else { + n->target_quantum = n->rt.position->clock.target_duration; + n->target_rate = n->rt.position->clock.target_rate; } pw_log_debug("%p: driver %p running:%d runnable:%d quantum:%u '%s'",
View file
pipewire-0.3.79.tar.gz/src/pipewire/filter.c -> pipewire-0.3.80.tar.gz/src/pipewire/filter.c
Changed
@@ -83,7 +83,8 @@ #define PORT_Format 3 #define PORT_Buffers 4 #define PORT_Latency 5 -#define N_PORT_PARAMS 6 +#define PORT_Tag 6 +#define N_PORT_PARAMS 7 struct spa_param_info paramsN_PORT_PARAMS; struct spa_io_buffers *io; @@ -189,15 +190,17 @@ return PORT_Buffers; case SPA_PARAM_Latency: return PORT_Latency; + case SPA_PARAM_Tag: + return PORT_Tag; default: return -1; } } -static void fix_datatype(const struct spa_pod *param) +static void fix_datatype(struct spa_pod *param) { const struct spa_pod_prop *pod_param; - const struct spa_pod *vals; + struct spa_pod *vals; uint32_t dataType, n_vals, choice; pod_param = spa_pod_find_prop(param, NULL, SPA_PARAM_BUFFERS_dataType); @@ -237,11 +240,6 @@ if (p == NULL) return NULL; - if (id == SPA_PARAM_Buffers && port != NULL && - SPA_FLAG_IS_SET(port->flags, PW_FILTER_PORT_FLAG_MAP_BUFFERS) && - port->direction == SPA_DIRECTION_INPUT) - fix_datatype(param); - if (id == SPA_PARAM_ProcessLatency && port == NULL) spa_process_latency_parse(param, &impl->process_latency); @@ -251,6 +249,11 @@ memcpy(p->param, param, SPA_POD_SIZE(param)); SPA_POD_OBJECT_ID(p->param) = id; + if (id == SPA_PARAM_Buffers && port != NULL && + SPA_FLAG_IS_SET(port->flags, PW_FILTER_PORT_FLAG_MAP_BUFFERS) && + port->direction == SPA_DIRECTION_INPUT) + fix_datatype(p->param); + pw_log_debug("%p: port %p param id %d (%s)", impl, p, id, spa_debug_type_find_name(spa_type_param, id)); @@ -1849,6 +1852,7 @@ p->paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); p->paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); p->paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_WRITE); + p->paramsPORT_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_WRITE); p->info.params = p->params; p->info.n_params = N_PORT_PARAMS;
View file
pipewire-0.3.79.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.80.tar.gz/src/pipewire/impl-link.c
Changed
@@ -774,6 +774,7 @@ pw_impl_port_emit_link_removed(this->input, this); pw_impl_port_recalc_latency(this->input); + pw_impl_port_recalc_tag(this->input); if ((res = pw_impl_port_use_buffers(port, mix, 0, NULL, 0)) < 0) { pw_log_warn("%p: port %p clear error %s", this, port, spa_strerror(res)); @@ -803,6 +804,7 @@ pw_impl_port_emit_link_removed(this->output, this); pw_impl_port_recalc_latency(this->output); + pw_impl_port_recalc_tag(this->output); /* we don't clear output buffers when the link goes away. They will get * cleared when the node goes to suspend */ @@ -988,6 +990,14 @@ pw_impl_port_recalc_latency(this->output); } +static void input_port_tag_changed(void *data) +{ + struct impl *impl = data; + struct pw_impl_link *this = &impl->this; + if (!this->feedback) + pw_impl_port_recalc_tag(this->output); +} + static void output_port_latency_changed(void *data) { struct impl *impl = data; @@ -996,11 +1006,20 @@ pw_impl_port_recalc_latency(this->input); } +static void output_port_tag_changed(void *data) +{ + struct impl *impl = data; + struct pw_impl_link *this = &impl->this; + if (!this->feedback) + pw_impl_port_recalc_tag(this->input); +} + static const struct pw_impl_port_events input_port_events = { PW_VERSION_IMPL_PORT_EVENTS, .param_changed = input_port_param_changed, .state_changed = input_port_state_changed, .latency_changed = input_port_latency_changed, + .tag_changed = input_port_tag_changed, }; static const struct pw_impl_port_events output_port_events = { @@ -1008,6 +1027,7 @@ .param_changed = output_port_param_changed, .state_changed = output_port_state_changed, .latency_changed = output_port_latency_changed, + .tag_changed = output_port_tag_changed, }; static void node_result(struct impl *impl, void *obj, @@ -1395,6 +1415,8 @@ pw_impl_port_recalc_latency(output); pw_impl_port_recalc_latency(input); + pw_impl_port_recalc_tag(output); + pw_impl_port_recalc_tag(input); if (impl->onode != impl->inode) this->peer = pw_node_peer_ref(impl->onode, impl->inode);
View file
pipewire-0.3.79.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.80.tar.gz/src/pipewire/impl-node.c
Changed
@@ -1105,9 +1105,9 @@ struct pw_node_activation *na = driver->rt.target.activation; struct spa_io_clock *cl = &na->position.clock; enum spa_log_level level = SPA_LOG_LEVEL_DEBUG; - int missed; + int suppressed; - if ((missed = spa_ratelimit_test(&driver->rt.rate_limit, nsec)) >= 0) + if ((suppressed = spa_ratelimit_test(&driver->rt.rate_limit, nsec)) >= 0) level = SPA_LOG_LEVEL_INFO; spa_list_for_each(t, &driver->rt.target_list, link) { @@ -1121,11 +1121,11 @@ a->status == PW_NODE_ACTIVATION_AWAKE) { update_xrun_stats(a, nsec / 1000, 0); - pw_log(level, "(%s-%u) client too slow! rate:%u/%u pos:%"PRIu64" status:%s (%u missed)", + pw_log(level, "(%s-%u) client too slow! rate:%u/%u pos:%"PRIu64" status:%s (%u suppressed)", t->name, t->id, (uint32_t)(cl->rate.num * cl->duration), cl->rate.denom, cl->position, str_status(a->status), - missed); + suppressed); } pw_log_debug("(%s-%u) state:%p pending:%d/%d s:%"PRIu64" a:%"PRIu64" f:%"PRIu64 " waiting:%"PRIu64" process:%"PRIu64" status:%s sync:%d", @@ -1900,11 +1900,11 @@ struct pw_node_activation *da = this->rt.driver_target.activation; struct spa_system *data_system = this->data_system; uint64_t nsec = get_time_ns(data_system); - int missed; + int suppressed; update_xrun_stats(a, trigger, delay); - if ((missed = spa_ratelimit_test(&this->rt.rate_limit, nsec)) >= 0) { + if ((suppressed = spa_ratelimit_test(&this->rt.rate_limit, nsec)) >= 0) { struct spa_fraction rate; if (da) { struct spa_io_clock *cl = &da->position.clock; @@ -1914,11 +1914,11 @@ rate = SPA_FRACTION(0,0); } pw_log_info("(%s-%d) XRun! rate:%u/%u count:%u time:%"PRIu64 - " delay:%"PRIu64" max:%"PRIu64" (%d missed)", + " delay:%"PRIu64" max:%"PRIu64" (%d suppressed)", this->name, this->info.id, rate.num, rate.denom, a->xrun_count, trigger, delay, a->max_delay, - missed); + suppressed); } pw_impl_node_rt_emit_xrun(this); @@ -2133,7 +2133,6 @@ uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param); int seq; - uint32_t count; unsigned int cache:1; }; @@ -2147,11 +2146,8 @@ const struct spa_result_node_params *r = result; if (d->seq == seq) { d->callback(d->data, seq, r->id, r->index, r->next, r->param); - if (d->cache) { - if (d->count++ == 0) - pw_param_add(&impl->pending_list, seq, r->id, NULL); + if (d->cache) pw_param_add(&impl->pending_list, seq, r->id, r->param); - } } break; } @@ -2172,7 +2168,7 @@ { int res; struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); - struct result_node_params_data user_data = { impl, data, callback, seq, 0, false }; + struct result_node_params_data user_data = { impl, data, callback, seq, false }; struct spa_hook listener; struct spa_param_info *pi; static const struct spa_node_events node_events = { @@ -2226,6 +2222,9 @@ user_data.cache = impl->cache_params && (filter == NULL && index == 0 && max == UINT32_MAX); + if (user_data.cache) + pw_param_add(&impl->pending_list, seq, param_id, NULL); + spa_zero(listener); spa_node_add_listener(node->node, &listener, &node_events, &user_data); res = spa_node_enum_params(node->node, seq,
View file
pipewire-0.3.79.tar.gz/src/pipewire/impl-port.c -> pipewire-0.3.80.tar.gz/src/pipewire/impl-port.c
Changed
@@ -9,6 +9,7 @@ #include <spa/pod/parser.h> #include <spa/param/audio/format-utils.h> +#include <spa/param/tag-utils.h> #include <spa/node/utils.h> #include <spa/utils/names.h> #include <spa/utils/string.h> @@ -16,6 +17,7 @@ #include <spa/debug/types.h> #include <spa/pod/filter.h> #include <spa/pod/dynamic.h> +#include <spa/debug/pod.h> #include "pipewire/impl.h" #include "pipewire/private.h" @@ -444,7 +446,7 @@ struct pw_impl_port *this = data; struct spa_latency_info latency; - if (id != SPA_PARAM_Latency) + if (id != SPA_PARAM_Latency || param == NULL) return -EINVAL; if (spa_latency_parse(param, &latency) < 0) @@ -464,6 +466,37 @@ return 0; } +static int process_tag_param(void *data, int seq, + uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param) +{ + struct pw_impl_port *this = data; + struct spa_tag_info info; + struct spa_pod *old; + void *state = NULL; + + if (id != SPA_PARAM_Tag || param == NULL) + return -EINVAL; + if (spa_tag_parse(param, &info, &state) < 0) + return 0; + + old = this->taginfo.direction; + + if (spa_tag_compare(old, param) == 0) + return 0; + + pw_log_debug("port %p: got %s tag %p", this, + pw_direction_as_string(info.direction), param); + if (param) + pw_log_pod(SPA_LOG_LEVEL_DEBUG, param); + + free(old); + this->taginfo.direction = spa_pod_copy(param); + + if (info.direction == this->direction) + pw_impl_port_emit_tag_changed(this); + + return 0; +} static void update_info(struct pw_impl_port *port, const struct spa_port_info *info) { @@ -514,6 +547,13 @@ pw_impl_port_for_each_param(port, 0, id, 0, UINT32_MAX, NULL, process_latency_param, port); break; + case SPA_PARAM_Tag: + port->have_tag_param = + SPA_FLAG_IS_SET(info->paramsi.flags, SPA_PARAM_INFO_WRITE); + if (port->node != NULL) + pw_impl_port_for_each_param(port, 0, id, 0, UINT32_MAX, + NULL, process_tag_param, port); + break; default: break; } @@ -1061,6 +1101,7 @@ pw_impl_port_for_each_param(port, 0, SPA_PARAM_IO, 0, 0, NULL, check_param_io, port); pw_impl_port_for_each_param(port, 0, SPA_PARAM_Latency, 0, 0, NULL, process_latency_param, port); + pw_impl_port_for_each_param(port, 0, SPA_PARAM_Tag, 0, 0, NULL, process_tag_param, port); nprops = pw_impl_node_get_properties(node); media_class = pw_properties_get(nprops, PW_KEY_MEDIA_CLASS); @@ -1310,6 +1351,8 @@ pw_param_clear(&impl->param_list, SPA_ID_INVALID); pw_param_clear(&impl->pending_list, SPA_ID_INVALID); + free(port->tagSPA_DIRECTION_INPUT); + free(port->tagSPA_DIRECTION_OUTPUT); pw_map_clear(&port->mix_port_map); @@ -1325,7 +1368,6 @@ uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param); int seq; - uint32_t count; unsigned int cache:1; }; @@ -1339,11 +1381,8 @@ const struct spa_result_node_params *r = result; if (d->seq == seq) { d->callback(d->data, seq, r->id, r->index, r->next, r->param); - if (d->cache) { - if (d->count++ == 0) - pw_param_add(&impl->pending_list, seq, r->id, NULL); + if (d->cache) pw_param_add(&impl->pending_list, seq, r->id, r->param); - } } break; } @@ -1365,7 +1404,7 @@ int res; struct impl *impl = SPA_CONTAINER_OF(port, struct impl, this); struct pw_impl_node *node = port->node; - struct result_port_params_data user_data = { impl, data, callback, seq, 0, false }; + struct result_port_params_data user_data = { impl, data, callback, seq, false }; struct spa_hook listener; struct spa_param_info *pi; static const struct spa_node_events node_events = { @@ -1419,6 +1458,9 @@ user_data.cache = impl->cache_params && (filter == NULL && index == 0 && max == UINT32_MAX); + if (user_data.cache) + pw_param_add(&impl->pending_list, seq, param_id, NULL); + spa_zero(listener); spa_node_add_listener(node->node, &listener, &node_events, &user_data); res = spa_node_port_enum_params(node->node, seq, @@ -1507,6 +1549,7 @@ struct spa_pod_builder b = { 0 }; uint8_t buffer1024; bool changed; + int count = 0; if (port->destroying) return 0; @@ -1529,6 +1572,7 @@ latency.min_quantum, latency.max_quantum, latency.min_rate, latency.max_rate, latency.min_ns, latency.max_ns); + count++; } } else { spa_list_for_each(l, &port->links, input_link) { @@ -1544,13 +1588,16 @@ latency.min_quantum, latency.max_quantum, latency.min_rate, latency.max_rate, latency.min_ns, latency.max_ns); + count++; } } spa_latency_info_combine_finish(&latency); - current = &port->latencylatency.direction; - - changed = spa_latency_info_compare(current, &latency) != 0; + current = port->have_latency ? &port->latencylatency.direction : NULL; + if (current == NULL) + changed = count > 0; + else + changed = spa_latency_info_compare(current, &latency) != 0; pw_log_info("port %d: %s %s latency %f-%f %d-%d %"PRIu64"-%"PRIu64, port->info.id, changed ? "set" : "keep", @@ -1562,16 +1609,90 @@ if (!changed) return 0; - *current = latency; + port->latencylatency.direction = latency; + port->have_latency = count > 0; if (!port->have_latency_param) return 0; spa_pod_builder_init(&b, buffer, sizeof(buffer)); - param = spa_latency_build(&b, SPA_PARAM_Latency, &latency); + param = port->have_latency ? spa_latency_build(&b, SPA_PARAM_Latency, &latency) : NULL; return pw_impl_port_set_param(port, SPA_PARAM_Latency, 0, param); } +int pw_impl_port_recalc_tag(struct pw_impl_port *port) +{ + struct pw_impl_link *l; + struct pw_impl_port *other; + struct spa_pod *param, *tag, *old; + struct spa_pod_dynamic_builder b = { 0 }; + struct spa_pod_frame f; + struct spa_tag_info info; + enum spa_direction direction; + uint8_t buffer1024; + int count = 0; + bool changed; +
View file
pipewire-0.3.79.tar.gz/src/pipewire/impl-port.h -> pipewire-0.3.80.tar.gz/src/pipewire/impl-port.h
Changed
@@ -36,7 +36,7 @@ /** Port events, use \ref pw_impl_port_add_listener */ struct pw_impl_port_events { -#define PW_VERSION_IMPL_PORT_EVENTS 2 +#define PW_VERSION_IMPL_PORT_EVENTS 3 uint32_t version; /** The port is destroyed */ @@ -72,6 +72,8 @@ /** latency changed. Since version 2 */ void (*latency_changed) (void *data); + /** tag changed. Since version 3 */ + void (*tag_changed) (void *data); }; /** Create a new port
View file
pipewire-0.3.79.tar.gz/src/pipewire/private.h -> pipewire-0.3.80.tar.gz/src/pipewire/private.h
Changed
@@ -782,6 +782,7 @@ #define pw_impl_port_emit_control_removed(p,c) pw_impl_port_emit(p, control_removed, 0, c) #define pw_impl_port_emit_param_changed(p,i) pw_impl_port_emit(p, param_changed, 1, i) #define pw_impl_port_emit_latency_changed(p) pw_impl_port_emit(p, latency_changed, 2) +#define pw_impl_port_emit_tag_changed(p) pw_impl_port_emit(p, tag_changed, 3) #define PW_IMPL_PORT_IS_CONTROL(port) SPA_FLAG_MASK((port)->flags, \ PW_IMPL_PORT_FLAG_BUFFERS|PW_IMPL_PORT_FLAG_CONTROL,\ @@ -846,6 +847,10 @@ struct spa_latency_info latency2; /**< latencies */ unsigned int have_latency_param:1; unsigned int ignore_latency:1; + unsigned int have_latency:1; + + unsigned int have_tag_param:1; + struct spa_pod *tag2; /**< tags */ void *owner_data; /**< extra owner data */ void *user_data; /**< extra user data */ @@ -1221,6 +1226,7 @@ struct spa_buffer **buffers, uint32_t n_buffers); int pw_impl_port_recalc_latency(struct pw_impl_port *port); +int pw_impl_port_recalc_tag(struct pw_impl_port *port); /** Change the state of the node */ int pw_impl_node_set_state(struct pw_impl_node *node, enum pw_node_state state);
View file
pipewire-0.3.79.tar.gz/src/pipewire/stream.c -> pipewire-0.3.80.tar.gz/src/pipewire/stream.c
Changed
@@ -113,7 +113,8 @@ #define PORT_Format 3 #define PORT_Buffers 4 #define PORT_Latency 5 -#define N_PORT_PARAMS 6 +#define PORT_Tag 6 +#define N_PORT_PARAMS 7 struct spa_param_info port_paramsN_PORT_PARAMS; struct spa_list param_list; @@ -191,15 +192,17 @@ return PORT_Buffers; case SPA_PARAM_Latency: return PORT_Latency; + case SPA_PARAM_Tag: + return PORT_Tag; default: return -1; } } -static void fix_datatype(const struct spa_pod *param) +static void fix_datatype(struct spa_pod *param) { const struct spa_pod_prop *pod_param; - const struct spa_pod *vals; + struct spa_pod *vals; uint32_t dataType, n_vals, choice; pod_param = spa_pod_find_prop(param, NULL, SPA_PARAM_BUFFERS_dataType); @@ -239,17 +242,17 @@ if (p == NULL) return NULL; - if (id == SPA_PARAM_Buffers && - SPA_FLAG_IS_SET(impl->flags, PW_STREAM_FLAG_MAP_BUFFERS) && - impl->direction == SPA_DIRECTION_INPUT) - fix_datatype(param); - p->id = id; p->flags = flags; p->param = SPA_PTROFF(p, sizeof(struct param), struct spa_pod); memcpy(p->param, param, SPA_POD_SIZE(param)); SPA_POD_OBJECT_ID(p->param) = id; + if (id == SPA_PARAM_Buffers && + SPA_FLAG_IS_SET(impl->flags, PW_STREAM_FLAG_MAP_BUFFERS) && + impl->direction == SPA_DIRECTION_INPUT) + fix_datatype(p->param); + spa_list_append(&impl->param_list, &p->link); if ((idx = get_param_index(id)) != -1) { @@ -1960,6 +1963,7 @@ impl->port_paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); impl->port_paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); impl->port_paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_WRITE); + impl->port_paramsPORT_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_WRITE); impl->port_info.props = &impl->port_props->dict; impl->port_info.params = impl->port_params; impl->port_info.n_params = N_PORT_PARAMS;
View file
pipewire-0.3.79.tar.gz/src/pipewire/stream.h -> pipewire-0.3.80.tar.gz/src/pipewire/stream.h
Changed
@@ -469,9 +469,7 @@ /** Update the param exposed on the stream. */ int pw_stream_update_params(struct pw_stream *stream, /**< a \ref pw_stream */ - const struct spa_pod **params, /**< an array of params. The params should - * ideally contain parameters for doing - * buffer allocation. */ + const struct spa_pod **params, /**< an array of params. */ uint32_t n_params /**< number of elements in \a params */); /**
View file
pipewire-0.3.79.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.80.tar.gz/src/tools/pw-cat.c
Changed
@@ -20,6 +20,7 @@ #include <spa/param/audio/layout.h> #include <spa/param/audio/format-utils.h> #include <spa/param/audio/type-info.h> +#include <spa/param/tag-utils.h> #include <spa/param/props.h> #include <spa/utils/result.h> #include <spa/utils/string.h> @@ -1569,7 +1570,8 @@ { struct data data = { 0, }; struct pw_loop *l; - const struct spa_pod *params1; + const struct spa_pod *params2; + uint32_t n_params = 0; uint8_t buffer1024; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); const char *prog; @@ -1793,19 +1795,6 @@ } data.filename = argvoptind++; - if (pw_properties_get(data.props, PW_KEY_MEDIA_TYPE) == NULL) - pw_properties_set(data.props, PW_KEY_MEDIA_TYPE, data.media_type); - if (pw_properties_get(data.props, PW_KEY_MEDIA_CATEGORY) == NULL) - pw_properties_set(data.props, PW_KEY_MEDIA_CATEGORY, data.media_category); - if (pw_properties_get(data.props, PW_KEY_MEDIA_ROLE) == NULL) - pw_properties_set(data.props, PW_KEY_MEDIA_ROLE, data.media_role); - if (pw_properties_get(data.props, PW_KEY_MEDIA_FILENAME) == NULL) - pw_properties_set(data.props, PW_KEY_MEDIA_FILENAME, data.filename); - if (pw_properties_get(data.props, PW_KEY_MEDIA_NAME) == NULL) - pw_properties_set(data.props, PW_KEY_MEDIA_NAME, data.filename); - if (pw_properties_get(data.props, PW_KEY_TARGET_OBJECT) == NULL) - pw_properties_set(data.props, PW_KEY_TARGET_OBJECT, data.target); - /* make a main loop. If you already have another main loop, you can add * the fd of this pipewire mainloop to it. */ data.loop = pw_main_loop_new(NULL); @@ -1874,6 +1863,19 @@ } ret = setup_properties(&data); + if (pw_properties_get(data.props, PW_KEY_MEDIA_TYPE) == NULL) + pw_properties_set(data.props, PW_KEY_MEDIA_TYPE, data.media_type); + if (pw_properties_get(data.props, PW_KEY_MEDIA_CATEGORY) == NULL) + pw_properties_set(data.props, PW_KEY_MEDIA_CATEGORY, data.media_category); + if (pw_properties_get(data.props, PW_KEY_MEDIA_ROLE) == NULL) + pw_properties_set(data.props, PW_KEY_MEDIA_ROLE, data.media_role); + if (pw_properties_get(data.props, PW_KEY_MEDIA_FILENAME) == NULL) + pw_properties_set(data.props, PW_KEY_MEDIA_FILENAME, data.filename); + if (pw_properties_get(data.props, PW_KEY_MEDIA_NAME) == NULL) + pw_properties_set(data.props, PW_KEY_MEDIA_NAME, data.filename); + if (pw_properties_get(data.props, PW_KEY_TARGET_OBJECT) == NULL) + pw_properties_set(data.props, PW_KEY_TARGET_OBJECT, data.target); + switch (data.data_type) { #ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION case TYPE_ENCODED: @@ -1886,7 +1888,7 @@ ret = av_codec_params_to_audio_info(&data, data.encoded.audio_stream->codecpar, &info); if (ret < 0) goto error_bad_file; - params0 = spa_format_audio_build(&b, SPA_PARAM_EnumFormat, &info); + paramsn_params++ = spa_format_audio_build(&b, SPA_PARAM_EnumFormat, &info); break; } #endif @@ -1902,11 +1904,11 @@ if (data.channelmap.n_channels) memcpy(info.position, data.channelmap.channels, data.channels * sizeof(int)); - params0 = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info); + paramsn_params++ = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info); break; } case TYPE_MIDI: - params0 = spa_pod_builder_add_object(&b, + paramsn_params++ = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); @@ -1928,10 +1930,25 @@ memcpy(info.position, i->info.position, info.channels * sizeof(uint32_t)); } - params0 = spa_format_audio_dsd_build(&b, SPA_PARAM_EnumFormat, &info); + paramsn_params++ = spa_format_audio_dsd_build(&b, SPA_PARAM_EnumFormat, &info); break; } } + if (data.mode == mode_playback) { + struct spa_dict_item items64; + uint32_t i, n_items = 0; + + for (i = 0; i < data.props->dict.n_items; i++) { + if (spa_strstartswith(data.props->dict.itemsi.key, "media.")) + itemsn_items++ = data.props->dict.itemsi; + } + if (n_items > 0) { + struct spa_pod_frame f; + spa_tag_build_start(&b, &f, SPA_PARAM_Tag, SPA_DIRECTION_OUTPUT); + spa_tag_build_add_dict(&b, &SPA_DICT_INIT(items, n_items)); + paramsn_params++ = spa_tag_build_end(&b, &f); + } + } data.stream = pw_stream_new(data.core, prog, data.props); data.props = NULL; @@ -1955,7 +1972,7 @@ PW_ID_ANY, flags | PW_STREAM_FLAG_MAP_BUFFERS, - params, 1); + params, n_params); if (ret < 0) { fprintf(stderr, "error: failed connect: %s\n", spa_strerror(ret)); goto error_connect_fail;
View file
pipewire-0.3.79.tar.gz/src/tools/pw-mon.c -> pipewire-0.3.80.tar.gz/src/tools/pw-mon.c
Changed
@@ -55,6 +55,9 @@ struct spa_list pending_list; struct spa_list global_list; + + bool hide_params; + bool hide_props; }; struct proxy_data { @@ -152,7 +155,7 @@ spa_list_append(&data->param_list, &p->link); } -static void print_params(struct proxy_data *data, bool use_prefix) +static void print_parameters(struct proxy_data *data, bool use_prefix) { struct param *p; @@ -198,9 +201,12 @@ #define MARK_CHANGE(f) (!!(print_mark && ((info)->change_mask & (f)))) -static void on_core_info(void *data, const struct pw_core_info *info) +static void on_core_info(void *_data, const struct pw_core_info *info) { - bool print_all = true, print_mark = true; + struct proxy_data *data = _data; + bool hide_props, print_mark = true; + + hide_props = data->data->hide_props; printf("\ttype: %s\n", PW_TYPE_INTERFACE_Core); printf("\tcookie: %u\n", info->cookie); @@ -208,22 +214,22 @@ printf("\thost-name: \"%s\"\n", info->host_name); printf("\tversion: \"%s\"\n", info->version); printf("\tname: \"%s\"\n", info->name); - if (print_all) { + if (!hide_props) { print_properties(info->props, MARK_CHANGE(PW_CORE_CHANGE_MASK_PROPS)); } } static void module_event_info(void *_data, const struct pw_module_info *info) { - struct proxy_data *data = _data; - bool print_all, print_mark; + struct proxy_data *data = _data; + bool hide_props, print_mark; - print_all = true; - if (data->info == NULL) { + hide_props = data->data->hide_props; + if (data->info == NULL) { printf("added:\n"); print_mark = false; } - else { + else { printf("changed:\n"); print_mark = true; } @@ -237,7 +243,7 @@ printf("\tname: \"%s\"\n", info->name); printf("\tfilename: \"%s\"\n", info->filename); printf("\targs: \"%s\"\n", info->args); - if (print_all) { + if (!hide_props) { print_properties(info->props, MARK_CHANGE(PW_MODULE_CHANGE_MASK_PROPS)); } } @@ -250,15 +256,17 @@ static void print_node(struct proxy_data *data) { struct pw_node_info *info = data->info; - bool print_all, print_mark; + bool hide_params, hide_props, print_mark; - print_all = true; - if (data->first) { + hide_params = data->data->hide_params; + hide_props = data->data->hide_props; + + if (data->first) { printf("added:\n"); print_mark = false; data->first = false; } - else { + else { printf("changed:\n"); print_mark = true; } @@ -267,8 +275,8 @@ printf("\tpermissions: "PW_PERMISSION_FORMAT"\n", PW_PERMISSION_ARGS(data->permissions)); printf("\ttype: %s (version %d)\n", data->type, data->version); - if (print_all) { - print_params(data, MARK_CHANGE(PW_NODE_CHANGE_MASK_PARAMS)); + if (!hide_params) { + print_parameters(data, MARK_CHANGE(PW_NODE_CHANGE_MASK_PARAMS)); with_prefix(MARK_CHANGE(PW_NODE_CHANGE_MASK_INPUT_PORTS)) { printf("\tinput ports: %u/%u\n", info->n_input_ports, info->max_input_ports); @@ -285,6 +293,9 @@ printf(" \"%s\"\n", info->error); else printf("\n"); + } + + if (!hide_props) { print_properties(info->props, MARK_CHANGE(PW_NODE_CHANGE_MASK_PROPS)); } } @@ -323,15 +334,17 @@ static void print_port(struct proxy_data *data) { struct pw_port_info *info = data->info; - bool print_all, print_mark; + bool hide_params, hide_props, print_mark; + + hide_params = data->data->hide_params; + hide_props = data->data->hide_props; - print_all = true; - if (data->first) { + if (data->first) { printf("added:\n"); print_mark = false; data->first = false; } - else { + else { printf("changed:\n"); print_mark = true; } @@ -342,8 +355,12 @@ printf("\ttype: %s (version %d)\n", data->type, data->version); printf("\tdirection: \"%s\"\n", pw_direction_as_string(info->direction)); - if (print_all) { - print_params(data, MARK_CHANGE(PW_PORT_CHANGE_MASK_PARAMS)); + + if (!hide_params) { + print_parameters(data, MARK_CHANGE(PW_PORT_CHANGE_MASK_PARAMS)); + } + + if (!hide_props) { print_properties(info->props, MARK_CHANGE(PW_PORT_CHANGE_MASK_PROPS)); } } @@ -382,14 +399,15 @@ static void factory_event_info(void *_data, const struct pw_factory_info *info) { struct proxy_data *data = _data; - bool print_all, print_mark; + bool hide_props, print_mark; + + hide_props = data->data->hide_props; - print_all = true; - if (data->info == NULL) { + if (data->info == NULL) { printf("added:\n"); print_mark = false; } - else { + else { printf("changed:\n"); print_mark = true; } @@ -403,7 +421,7 @@ printf("\tname: \"%s\"\n", info->name); printf("\tobject-type: %s/%d\n", info->type, info->version); - if (print_all) { + if (!hide_props) { print_properties(info->props, MARK_CHANGE(PW_FACTORY_CHANGE_MASK_PROPS)); } } @@ -416,14 +434,15 @@ static void client_event_info(void *_data, const struct pw_client_info *info) { struct proxy_data *data = _data; - bool print_all, print_mark; + bool hide_props, print_mark; + + hide_props = data->data->hide_props; - print_all = true; - if (data->info == NULL) { + if (data->info == NULL) { printf("added:\n"); print_mark = false; } - else { + else { printf("changed:\n"); print_mark = true;
View file
pipewire-0.3.79.tar.gz/src/tools/pw-top.c -> pipewire-0.3.80.tar.gz/src/tools/pw-top.c
Changed
@@ -721,8 +721,8 @@ { fprintf(error ? stderr : stdout, "Usage:\n%s options\n\n" "Options:\n" - " -b, --batch-mode run in non-interactive batch_mode mode\n" - " -n, --iterations = NUMBER exit on maximum iterations NUMBER\n" + " -b, --batch-mode run in non-interactive batch mode\n" + " -n, --iterations = NUMBER exit after NUMBER batch iterations\n" " -r, --remote Remote daemon name\n" "\n" " -h, --help Show this help\n"
View file
pipewire-0.3.80.tar.gz/subprojects/webrtc-audio-processing.wrap
Added
@@ -0,0 +1,8 @@ +wrap-git +directory = webrtc-audio-processing +url = https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing.git +push-url = git@gitlab.freedesktop.org:pulseaudio/webrtc-audio-processing.git +revision = v1.3 + +provide +dependency_names = webrtc-audio-coding-1, webrtc-audio-processing-1
View file
pipewire-0.3.79.tar.gz/test/test-spa-utils.c -> pipewire-0.3.80.tar.gz/test/test-spa-utils.c
Changed
@@ -125,7 +125,8 @@ pwtest_int_eq(SPA_TYPE_OBJECT_Profiler, 0x4000a); pwtest_int_eq(SPA_TYPE_OBJECT_ParamLatency, 0x4000b); pwtest_int_eq(SPA_TYPE_OBJECT_ParamProcessLatency, 0x4000c); - pwtest_int_eq(_SPA_TYPE_OBJECT_LAST, 0x4000d); + pwtest_int_eq(SPA_TYPE_OBJECT_ParamTag, 0x4000d); + pwtest_int_eq(_SPA_TYPE_OBJECT_LAST, 0x4000e); pwtest_int_eq(SPA_TYPE_VENDOR_PipeWire, 0x02000000); pwtest_int_eq(SPA_TYPE_VENDOR_Other, 0x7f000000);
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
.