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 29
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Thu Jun 29 10:47:58 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.72 + +------------------------------------------------------------------- Sat May 20 12:08:17 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.71
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.71 +Version: 0.3.72 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
pipewire-0.3.71.tar.gz/.gitlab-ci.yml -> pipewire-0.3.72.tar.gz/.gitlab-ci.yml
Changed
@@ -25,7 +25,7 @@ .fedora: variables: # Update this tag when you want to trigger a rebuild - FDO_DISTRIBUTION_TAG: '2023-04-18.0' + FDO_DISTRIBUTION_TAG: '2023-05-31.0' FDO_DISTRIBUTION_VERSION: '37' FDO_DISTRIBUTION_PACKAGES: >- alsa-lib-devel @@ -46,6 +46,7 @@ jack-audio-connection-kit-devel libasan libcanberra-devel + libffado-devel libldac-devel libmysofa-devel libsndfile-devel @@ -304,6 +305,8 @@ -Droc=disabled -Dlibcamera=disabled -Dsession-managers= + -Dc_args='-UFASTPATH' + -Dcpp_args='-UFASTPATH' parallel: matrix: - CC: gcc, clang
View file
pipewire-0.3.71.tar.gz/NEWS -> pipewire-0.3.72.tar.gz/NEWS
Changed
@@ -1,3 +1,109 @@ +# PipeWire 0.3.72 (2023-06-26) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + - Fix a critical bug that would refuse to update the samplerate or + buffersize in JACK clients. (#3226) + - A new module-netjack2-driver and module-netjack2-manager were added + that are compatible with NETJACK2. This allows PipeWire to become + a NETJACK2 manager or a driver between JACK2 or PipeWire servers. + - Support was added for firewire devices with FFADO. This is untested + for now and MIDI is not implemented yet. + - The node scheduling was optimized some more. External drivers are now + as efficient as in-server ones. This should improve performance of + various drivers such as bluetooth and JACK based drivers. + - Many, many bug fixes and a ton of improvements. + + +## PipeWire + - pw-filter can now be used to write sinks and sources. + - The node activation for drivers was changed. The driver now does not + need to go to the server to start the processing cycle. This makes + out-of-server drivers as efficient as in-server drivers. + - Don't try to use drivers with 0 priority as fallback drivers. This + avoids making the screencast driver a driver for audio. (#3219) + - Improve xrun count reporting in pw-top and the profiler. Now each + node has their own xrun counter updated when it fails to complete + processing during the cycle. + - pw-filter now also has support for TRIGGER. + - A potential fd leak was found when fds were send to a zombie client. + (#1840) + - Fix a bug where monitor or capture streams were logged twice in the + profiler. (#3278) + - Remove stream hooks safely. (#3251) + - A bug in serialization of container properties was fixed. This could + result in truncated property values. (#3290) + - The PIPEWIRE_AUTOCONNECT environment variable now always overrides the + autoconnect settings of streams. (#3299) + - Node, port and link destroy now avoids some useless work. + - Port will now try to renegotiate a new format when idle. (#3266) + +## Modules + - The module-sap now is more compatible with AES67. + - A new FFADO driver module was added. This is completely untested because + of lack of hardware. Please test and report issues. + - A new NETJACK2 driver and a NETJACK2 manager module were added. These + should be drop in replacements for the JACK2 parts. + - The RAOP discover module now tries harder to only list devices once. + - The zeroconf discover module now tries harder to only list devices once. + - The RAOP sink module now handles latency better and is compatible with + some more devices. (#3247, #3282) + - The loopback and filter-chain modules now always dequeue the last input + buffer to avoid stuttering in some cases. (#3276) + - The SPA node factory module can now also export nodes. This is used to + export the PTP clock from the AES67 config file. + - A bug in module-jack-tunnel was fixed that would cause stuttering and + corrupted output in some cases. (#3255) + - The resampler is now disabled in module-loopback and filter-chain when + the samplerate is set to follow the graph rate. (#2969) + - The way the mixer peer is sent to clients was improved. It is now also + possible to let a remote node know about mixer port removes, which + can avoid memory leaks and some code simplifications. + +## SPA + - Monitor ports now report latency correctly. + - The ALSA plugin now uses htimestamp to get a more accurate ringbuffer + position to estimate the clock skew. + - The channelmixer now has min/max-volume settings to limit or fix the + volume. + - The ALSA plugin can now control the playback and capture rate of USB + gadgets. This can avoid resampling and instead use the USB feedback + to control the rate. + - The ALSA output to multiple devices has been improved, some lockups + are avoided when the device ringbuffer is full. + - The compress-offload sink has improved negotiation. + +## pulse-server + - Only try to use GSettings when the schema exists. + - @DEFAULT_SOURCE@, @DEFAULT_SINK@ and @DEFAULT_MONITOR@ are now correctly + handled as targets in playback and capture streams. (#3284) + - 2 new quirks are added to disable volume updates on sinks/sources. + (#1517) + - The virtual-sink and virtual-source modules were added. These are really + example modules but actually also work and are useful on PulseAudio so + implement them as well. + - Fix initial stream volumes. (#3306) + +## Bluetooth + - Only register A2DP or BAP when we have codecs. + - Include codec into the media.name + +## JACK + - Fix a critical bug that would refuse to update the samplerate or + buffersize. (#3226) + - Improve updates of samplerate/buffersize, delay the updates until the + client is activated. (#3297) + - Use the new mix-info updates to simplify the mixer setup and peer + detection. + +## GStreamer + - Fill default strides instead of 0 on pipewire video buffers. (#3236) + +Older versions: + + # PipeWire 0.3.71 (2023-05-17) This is a bugfix release that is API and ABI compatible with previous @@ -140,9 +246,6 @@ - Document the SPA Pod serialization. - Document the PipeWire native protocol. - -Older versions: - # PipeWire 0.3.70 (2023-04-20) This is a quick bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.71.tar.gz/doc/pipewire-modules.dox -> pipewire-0.3.72.tar.gz/doc/pipewire-modules.dox
Changed
@@ -59,12 +59,15 @@ - \subpage page_module_example_sink - \subpage page_module_example_source - \subpage page_module_fallback_sink +- \subpage page_module_ffado_driver - \subpage page_module_filter_chain - \subpage page_module_jackdbus_detect - \subpage page_module_jack_tunnel - \subpage page_module_link_factory - \subpage page_module_loopback - \subpage page_module_metadata +- \subpage page_module_netjack2_driver +- \subpage page_module_netjack2_manager - \subpage page_module_pipe_tunnel - \subpage page_module_portal - \subpage page_module_profiler
View file
pipewire-0.3.71.tar.gz/doc/pipewire-protocol.dox -> pipewire-0.3.72.tar.gz/doc/pipewire-protocol.dox
Changed
@@ -46,6 +46,10 @@ message than can fit in one message, the message is split into multiple parts. +A receiver needs to first read the header to know the size of the +complete message. After collecting the complete message, it can start +processing it. + The payload is a single POD see \ref page_spa_pod for details. After the payload, there is an optional footer POD object. @@ -61,14 +65,28 @@ The client opens the socket and allocates a Core proxy with id 0 and a Client -proxy with id 1. +proxy with id 1. The proxy is nothing more than a way to identify the remote +objects with an id. Usually they also contain the type and version of the +remote object and some helpers (interfaces) to dispatch messages. -The server will allocate a new Core resource with id 0. +The server will allocate a new Core resource with id 0. Resources are the +counterpart of client proxies and also typically contain extra information +and helpers (interfaces) to dispatch messages. The client sends the Core::Hello message on the socket to start the communication. -The server binds the client resource with id 1 to the client. +The server binds the client resource with id 1 to the client. This means +that the client object on the server will now have a resource with a +client side proxy associated with it. + +When the client sends a message for a certain proxy, the server side +resource with the same id for the client is found and the message is +dispatched to the object associated with the resource. + +Similarly when a server sends a message on a resource, the client will +find the proxy with the same id and dispatch the message to it's +associated object. The client then sends client properties to the server. @@ -1235,7 +1253,8 @@ ) ``` - readfd: the eventfd to start processing -- writefd: the eventfd to signal driver start +- writefd: the eventfd to signal when the driver completes and profiling is + enabled. - memfd: the index of the memfd of the activation record - offset: the offset in memfd of the start of the activation record - size: the size of the activation record @@ -1243,6 +1262,11 @@ The activation record is currently an internal data structure that is not yet ABI stable. +The writefd is meant to wake up the server after the driver completes so +that the profiler can collect the information. The profiler is active +when the pw_node_activation::flags fields has PW_NODE_ACTIVATION_FLAG_PROFILER +set. When the profiler is disabled (or when the node is not driving), this +eventfd should not be signaled. ### ClientNode::SetParam (Opcode 1)
View file
pipewire-0.3.71.tar.gz/doc/pipewire-scheduling.dox -> pipewire-0.3.72.tar.gz/doc/pipewire-scheduling.dox
Changed
@@ -17,7 +17,7 @@ - an activation record that lives in shared memory with memfd. ``` - evenfd + eventfd +-^---------+ | | in out @@ -42,7 +42,7 @@ - Information about repositions (seek) and timebase owners. -# links. +# Links When two nodes are linked together, the output node becomes a dependency for the input node. This means the input node can only start processing when the output node is finished. @@ -57,7 +57,7 @@ ``` - evenfd eventfd + eventfd eventfd +-^---------+ +-^---------+ | | link | | in A out ---------------------> in B out @@ -92,7 +92,7 @@ ``` - evenfd eventfd + eventfd eventfd +-^---------+ +-^---------+ | | link | | in A out ---------------------> in B out @@ -108,11 +108,11 @@ | | / / | | / / | | / / - | | / / + | | / / v | /-------------/ / activation { / status:OK, V---------------/ - pending:0, + pending:0, required:2 } +-^---------+ @@ -133,17 +133,16 @@ The driver will then start processing the graph by emitting the ready signal. PipeWire will then: - - Perform some statistics about the previous cycle. Did it complete? compute processing - times, cpu usage etc. + - Check the previous cycle. Did it complete? Mark xrun on unfinished nodes. - Perform reposition requests if any, timebase changes, etc.. - The pending counter of each follower node is set to the required field. - - it then loops over all targets of the driver and atomically decrements the required + - It then loops over all targets of the driver and atomically decrements the required field of the activation record. When the required field is 0, the eventfd is signaled and the node can be scheduled. -In our example above, Node A and be will have their pending state decremented. Node A +In our example above, Node A and B will have their pending state decremented. Node A will be 0 and will be triggered first (node B has 2 pending dependencies to start with and -will not be triggered yet). The driver itself also has 2 dependcies left and will not +will not be triggered yet). The driver itself also has 2 dependencies left and will not be triggered (complete) yet. ## Scheduling node A @@ -169,13 +168,15 @@ The graph always completes after the driver is triggered and scheduled. All required fields from all the nodes in the target list of the driver are now 0. +The driver calculates some stats about cpu time etc. + # Remote nodes. For remote nodes, the eventfd and the activation is transfered from the server to the client. This means that writing to the remote client eventfd will wake the client directly -without going to the server first. +without going to the server first. All remote clients also get the activation and eventfd of the peer and driver they are linked to and can directly trigger peers and drivers without going to the @@ -183,9 +184,10 @@ ## Remote driver nodes. -Currently the graph start cycle is managed by the server. +Remote drivers start the graph cycle directly without going to the server first. -Remote driver nodes therefore have an extra eventfd to wake up the server and signal -the graph start. +After they complete (and only when the profiler is active), they will trigger an +extra eventfd to signal the server that the graph completed. This is used by the +server to generate the profiler info. */
View file
pipewire-0.3.71.tar.gz/doc/spa-pod.dox -> pipewire-0.3.72.tar.gz/doc/spa-pod.dox
Changed
@@ -623,7 +623,7 @@ 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | 4 | + | 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 5 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -659,7 +659,7 @@ 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | 4 | + | 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 7 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -948,7 +948,7 @@ 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | size | + | 16 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 17 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -971,7 +971,7 @@ 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | size | + | 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 18 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
View file
pipewire-0.3.71.tar.gz/doc/tutorial1.c -> pipewire-0.3.72.tar.gz/doc/tutorial1.c
Changed
@@ -11,9 +11,9 @@ pw_init(&argc, &argv); fprintf(stdout, "Compiled with libpipewire %s\n" - "Linked with libpipewire %s\n", - pw_get_headers_version(), - pw_get_library_version()); + "Linked with libpipewire %s\n", + pw_get_headers_version(), + pw_get_library_version()); return 0; } /* code */
View file
pipewire-0.3.71.tar.gz/doc/tutorial2.c -> pipewire-0.3.72.tar.gz/doc/tutorial2.c
Changed
@@ -20,37 +20,37 @@ int main(int argc, char *argv) { - struct pw_main_loop *loop; - struct pw_context *context; - struct pw_core *core; - struct pw_registry *registry; - struct spa_hook registry_listener; + struct pw_main_loop *loop; + struct pw_context *context; + struct pw_core *core; + struct pw_registry *registry; + struct spa_hook registry_listener; - pw_init(&argc, &argv); + pw_init(&argc, &argv); - loop = pw_main_loop_new(NULL /* properties */); - context = pw_context_new(pw_main_loop_get_loop(loop), - NULL /* properties */, - 0 /* user_data size */); + loop = pw_main_loop_new(NULL /* properties */); + context = pw_context_new(pw_main_loop_get_loop(loop), + NULL /* properties */, + 0 /* user_data size */); - core = pw_context_connect(context, - NULL /* properties */, - 0 /* user_data size */); + core = pw_context_connect(context, + NULL /* properties */, + 0 /* user_data size */); - registry = pw_core_get_registry(core, PW_VERSION_REGISTRY, - 0 /* user_data size */); + registry = pw_core_get_registry(core, PW_VERSION_REGISTRY, + 0 /* user_data size */); - spa_zero(registry_listener); - pw_registry_add_listener(registry, ®istry_listener, - ®istry_events, NULL); + spa_zero(registry_listener); + pw_registry_add_listener(registry, ®istry_listener, + ®istry_events, NULL); - pw_main_loop_run(loop); + pw_main_loop_run(loop); - pw_proxy_destroy((struct pw_proxy*)registry); - pw_core_disconnect(core); - pw_context_destroy(context); - pw_main_loop_destroy(loop); + pw_proxy_destroy((struct pw_proxy*)registry); + pw_core_disconnect(core); + pw_context_destroy(context); + pw_main_loop_destroy(loop); - return 0; + return 0; } /* code */
View file
pipewire-0.3.71.tar.gz/doc/tutorial4.c -> pipewire-0.3.72.tar.gz/doc/tutorial4.c
Changed
@@ -43,15 +43,15 @@ stride = sizeof(int16_t) * DEFAULT_CHANNELS; n_frames = buf->datas0.maxsize / stride; - for (i = 0; i < n_frames; i++) { - data->accumulator += M_PI_M2 * 440 / DEFAULT_RATE; - if (data->accumulator >= M_PI_M2) - data->accumulator -= M_PI_M2; - - val = sin(data->accumulator) * DEFAULT_VOLUME * 16767.f; - for (c = 0; c < DEFAULT_CHANNELS; c++) - *dst++ = val; - } + for (i = 0; i < n_frames; i++) { + data->accumulator += M_PI_M2 * 440 / DEFAULT_RATE; + if (data->accumulator >= M_PI_M2) + data->accumulator -= M_PI_M2; + + val = sin(data->accumulator) * DEFAULT_VOLUME * 16767.f; + for (c = 0; c < DEFAULT_CHANNELS; c++) + *dst++ = val; + } buf->datas0.chunk->offset = 0; buf->datas0.chunk->stride = stride;
View file
pipewire-0.3.71.tar.gz/meson.build -> pipewire-0.3.72.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '0.3.71', + version : '0.3.72', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.61.1', default_options : 'warning_level=3', @@ -405,6 +405,9 @@ summary({'lilv (for lv2 plugins)': lilv_lib.found()}, bool_yn: true) cdata.set('HAVE_LILV', lilv_lib.found()) +libffado_dep = dependency('libffado', required: get_option('libffado')) +summary({'ffado': libffado_dep.found()}, bool_yn: true) + check_functions = 'gettid', '#include <unistd.h>', '-D_GNU_SOURCE', , 'memfd_create', '#include <sys/mman.h>', '-D_GNU_SOURCE', ,
View file
pipewire-0.3.71.tar.gz/meson_options.txt -> pipewire-0.3.72.tar.gz/meson_options.txt
Changed
@@ -322,3 +322,7 @@ description: 'Enable code that depends on opus', type: 'feature', value: 'auto') +option('libffado', + description: 'Enable code that depends on libffado', + type: 'feature', + value: 'auto')
View file
pipewire-0.3.71.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.72.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -142,7 +142,6 @@ uint32_t dst_serial; bool src_ours; bool dst_ours; - bool is_complete; struct port *our_input; struct port *our_output; } port_link; @@ -518,10 +517,13 @@ } -static void init_mix(struct mix *mix, uint32_t mix_id, struct port *port) +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); mix->id = mix_id; + mix->peer_id = peer_id; mix->port = port; + mix->peer_port = NULL; mix->io = NULL; mix->n_buffers = 0; spa_list_init(&mix->queue); @@ -538,6 +540,17 @@ return NULL; } +static struct mix *find_port_peer(struct port *port, uint32_t peer_id) +{ + struct mix *mix; + spa_list_for_each(mix, &port->mix, port_link) { + pw_log_info("%p %d %d", port, mix->peer_id, peer_id); + if (mix->peer_id == peer_id) + return mix; + } + return NULL; +} + static struct mix *find_mix(struct client *c, struct port *port, uint32_t mix_id) { struct mix *mix; @@ -549,14 +562,12 @@ return NULL; } -static struct mix *ensure_mix(struct client *c, struct port *port, uint32_t mix_id) +static struct mix *create_mix(struct client *c, struct port *port, + uint32_t mix_id, uint32_t peer_id) { struct mix *mix; uint32_t i; - if ((mix = find_mix(c, port, mix_id)) != NULL) - return mix; - if (spa_list_is_empty(&c->free_mix)) { mix = calloc(OBJECT_CHUNK, sizeof(struct mix)); if (mix == NULL) @@ -570,11 +581,19 @@ spa_list_append(&port->mix, &mix->port_link); - init_mix(mix, mix_id, port); + init_mix(mix, mix_id, port, peer_id); return mix; } +static struct mix *ensure_mix(struct client *c, struct port *port, uint32_t mix_id) +{ + struct mix *mix; + if ((mix = find_mix(c, port, mix_id)) != NULL) + return mix; + return create_mix(c, port, mix_id, SPA_ID_INVALID); +} + static int clear_buffers(struct client *c, struct mix *mix) { struct port *port = mix->port; @@ -926,7 +945,7 @@ notify = SPA_PTROFF(c->notify_buffer, index & NOTIFY_BUFFER_MASK, struct notify); o = notify->object; - pw_log_debug("%p: dequeue notify index:%08x %p type:%d %p arg1:%d\n", c, + pw_log_debug("%p: dequeue notify index:%08x %p type:%d %p arg1:%d", c, index, notify, notify->type, o, notify->arg1); switch (notify->type) { @@ -1025,10 +1044,8 @@ int32_t filled; uint32_t index; struct notify *notify; - bool emit = false;; + bool emit = false; - if ((type & NOTIFY_ACTIVE_FLAG) && !c->active) - return 0; switch (type) { case NOTIFY_TYPE_REGISTRATION: emit = c->registration_callback != NULL && o != NULL; @@ -1060,8 +1077,19 @@ default: break; } - if (!emit) { - pw_log_debug("%p: skip notify %d", c, type); + if (!emit || ((type & NOTIFY_ACTIVE_FLAG) && !c->active)) { + switch (type) { + case NOTIFY_TYPE_BUFFER_FRAMES: + if (!emit) + c->buffer_frames = arg1; + break; + case NOTIFY_TYPE_SAMPLE_RATE: + if (!emit) + c->sample_rate = arg1; + break; + } + 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); @@ -1080,7 +1108,7 @@ notify->object = o; notify->arg1 = arg1; notify->msg = msg; - pw_log_debug("%p: queue notify index:%08x %p type:%d %p arg1:%d msg:%s\n", c, + pw_log_debug("%p: queue notify index:%08x %p type:%d %p arg1:%d msg:%s", c, index, notify, notify->type, o, notify->arg1, notify->msg); index += sizeof(struct notify); spa_ringbuffer_write_update(&c->notify_ring, index); @@ -1597,11 +1625,10 @@ if (SPA_UNLIKELY(sample_rate != c->sample_rate)) { pw_log_info("%p: sample_rate old:%d new:%d cb:%p", c, c->sample_rate, sample_rate, c->srate_callback); - if (c->srate_callback != NULL) { + if (c->sample_rate != (uint32_t)-1) queue_notify(c, NOTIFY_TYPE_SAMPLE_RATE, NULL, sample_rate, NULL); - } else { + else c->sample_rate = sample_rate; - } } return c->sample_rate == sample_rate; } @@ -2679,13 +2706,6 @@ void *ptr; int res = 0; - if (c->node_id == node_id) { - pw_log_debug("%p: our activation %u: %u %u %u", c, node_id, - mem_id, offset, size); - close(signalfd); - return 0; - } - if (mem_id == SPA_ID_INVALID) { mm = ptr = NULL; size = 0; @@ -2701,8 +2721,13 @@ ptr = mm->ptr; } - pw_log_debug("%p: set activation %u: %u %u %u %p", c, node_id, - mem_id, offset, size, ptr); + if (c->node_id == node_id) { + pw_log_debug("%p: our activation %u: %u %u %u %p", c, node_id, + mem_id, offset, size, ptr); + } else { + pw_log_debug("%p: set activation %u: %u %u %u %p", c, node_id, + mem_id, offset, size, ptr); + } if (ptr) { link = calloc(1, sizeof(struct link)); @@ -2751,8 +2776,6 @@ struct client *c = (struct client *) data; struct port *p = GET_PORT(c, direction, port_id); struct mix *mix; - struct object *l; - uint32_t src, dst; int res = 0; if (p == NULL || !p->valid) { @@ -2760,40 +2783,21 @@ goto exit; } - if ((mix = ensure_mix(c, p, mix_id)) == NULL) { - res = -ENOMEM; - goto exit; - } - mix->peer_id = peer_id; + mix = find_mix(c, p, mix_id); - if (direction == SPA_DIRECTION_INPUT) { - src = peer_id; - dst = p->object->id; + if (peer_id == SPA_ID_INVALID) { + if (mix == NULL) {
View file
pipewire-0.3.71.tar.gz/po/ca.po -> pipewire-0.3.72.tar.gz/po/ca.po
Changed
@@ -5,7 +5,7 @@ # Xavier Conde Rueda <xavi.conde@gmail.com>, 2008. # Agustí Grau <fletxa@gmail.com>, 2009. # Judith Pintó Subirada <judithp@gmail.com> -# Jordi Mas i Herǹandez, <jmas@softcatala.org>, 2022 +# Jordi Mas i Herǹandez, <jmas@softcatala.org>, 2022-2023 # # This file is translated according to the glossary and style guide of # Softcatalà. If you plan to modify this file, please read first the page @@ -27,17 +27,20 @@ msgid "" msgstr "" "Project-Id-Version: pipewire\n" -"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/issues/new\n" -"POT-Creation-Date: 2021-04-18 16:54+0800\n" -"PO-Revision-Date: 2022-09-01 19:24+0000\n" +"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/" +"issues\n" +"POT-Creation-Date: 2023-06-06 15:28+0000\n" +"PO-Revision-Date: 2023-06-06 22:39+0200\n" "Last-Translator: Jordi Mas i Herǹandez, <jmas@softcatala.org>,\n" "Language-Team: Catalan <fedora@softcatala.net>\n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 2.4.2\n" -#: src/daemon/pipewire.c:43 +#: src/daemon/pipewire.c:26 #, c-format msgid "" "%s options\n" @@ -48,7 +51,8 @@ "%s opcions\n" " -h, --help Mostra aquesta ajuda\n" " --version Mostra la versió\n" -" -c, --config Carrega la configuració (predeterminada %s)\n" +" -c, --config Carrega la configuració " +"(predeterminada %s)\n" #: src/daemon/pipewire.desktop.in:4 msgid "PipeWire Media System" @@ -58,305 +62,347 @@ msgid "Start the PipeWire Media System" msgstr "Inicia el sistema multimèdia PipeWire" -#: src/examples/media-session/alsa-monitor.c:526 -#: spa/plugins/alsa/acp/compat.c:187 -msgid "Built-in Audio" -msgstr "Àudio intern" +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:141 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:141 +#, c-format +msgid "Tunnel to %s%s%s" +msgstr "Túnel cap a %s%s%s" -#: src/examples/media-session/alsa-monitor.c:530 -#: spa/plugins/alsa/acp/compat.c:192 -msgid "Modem" -msgstr "Mòdem" +#: src/modules/module-fallback-sink.c:31 +msgid "Dummy Output" +msgstr "Sortida fictícia" + +#: src/modules/module-pulse-tunnel.c:844 +#, c-format +msgid "Tunnel for %s@%s" +msgstr "Túnel per a %s@%s" -#: src/examples/media-session/alsa-monitor.c:539 +#: src/modules/module-zeroconf-discover.c:315 msgid "Unknown device" msgstr "Dispositiu desconegut" -#: src/tools/pw-cat.c:991 +#: src/modules/module-zeroconf-discover.c:327 +#, c-format +msgid "%s on %s@%s" +msgstr "%s en %s@%s" + +#: src/modules/module-zeroconf-discover.c:331 +#, c-format +msgid "%s on %s" +msgstr "%s en %s" + +#: src/tools/pw-cat.c:974 #, c-format msgid "" -"%s options <file>\n" +"%s options <file>|-\n" " -h, --help Show this help\n" " --version Show version\n" " -v, --verbose Enable verbose operations\n" "\n" msgstr "" -"%s opcions <fitxer>\n" +"%s opcions <fitxer>|-\n" " -h, --help Mostra aquesta ajuda\n" " --version Mostra la versió\n" " -v, --verbose Habilita les operacions detallades\n" -#: src/tools/pw-cat.c:998 -#, c-format, fuzzy +#: src/tools/pw-cat.c:981 +#, c-format msgid "" " -R, --remote Remote daemon name\n" " --media-type Set media type (default %s)\n" " --media-category Set media category (default %s)\n" " --media-role Set media role (default %s)\n" -" --target Set node target (default %s)\n" +" --target Set node target serial or name " +"(default %s)\n" " 0 means don't link\n" " --latency Set node latency (default %s)\n" " Xunit (unit = s, ms, us, ns)\n" " or direct samples (256)\n" -" the rate is the one of the source file\n" -" --list-targets List available targets for --target\n" +" the rate is the one of the source " +"file\n" +" -P --properties Set node properties\n" "\n" msgstr "" -"-R, --remote Nom del dimoni remot\n" -" --media-type Estableix el tipus de mitjà (per defecte %s)\n" -" --media-category Estableix la categoria dels mitjans (per defecte %s)\n" -" --media-role Estableix el rol del mitjà (per defecte %s)\n" -" --target Estableix l'objectiu del node (per defecte %s)\n" +" -R, --remote Nom del dimoni remot\n" +" --media-type Estableix el tipus de mitjà (per " +"defecte %s)\n" +" --media-category Estableix la categoria del " +"mitjà (per defecte %s)\n" +" --media-role Estableix el rol del mitjà (per " +"defecte %s)\n" +" --target Estableix l'objectiu sèrie o el nom " +"del node (per defecte %s)\n" " 0 vol dir que no enllaça\n" -" --latency Estableix latència del node (per defecte %s)\n" +" --latency Estableix latència del node (per " +"defecte %s)\n" " Xunit (unitat = s, ms, us, ns)\n" " o mostres directes (256)\n" " la taxa és la del fitxer d'origen\n" -" --list-targets Llista d'objectius disponibles per a --target" +" -P --properties Estableix les propietats del " +"node\n" +"\n" -#: src/tools/pw-cat.c:1016 -#, c-format, fuzzy +#: src/tools/pw-cat.c:999 +#, c-format msgid "" -" --rate Sample rate (req. for rec) (default %u)\n" -" --channels Number of channels (req. for rec) (default %u)\n" +" --rate Sample rate (req. for rec) (default " +"%u)\n" +" --channels Number of channels (req. for rec) " +"(default %u)\n" " --channel-map Channel map\n" -" one of: \"stereo\", \"surround-51\",... or\n" -" comma separated list of channel names: eg. \"FL,FR\"\n" -" --format Sample format %s (req. for rec) (default %s)\n" +" one of: \"stereo\", " +"\"surround-51\",... or\n" +" comma separated list of channel " +"names: eg. \"FL,FR\"\n" +" --format Sample format %s (req. for rec) " +"(default %s)\n" " --volume Stream volume 0-1.0 (default %.3f)\n" -" -q --quality Resampler quality (0 - 15) (default %d)\n" +" -q --quality Resampler quality (0 - 15) (default " +"%d)\n" "\n" msgstr "" -"--rate Freqüència de mostreig (req. per rec) (predeterminat %u)\n" -" --channels Nombre de canals (req. per rec) (predeterminat %u)\n" -" --channel-map Mapa de canals\n" -" un dels següents: \"estèreo\", \"surround-51\",... o\n" -" Llista separada per comes dels noms dels canals: per exemple. \"FL,FR\"\n" -" --format Format de mostra %s (req. per a rec) (predeterminat %s)\n" -" --volume Volum de flux 0-1.0 (predeterminat %.3f)\n" -" -q --qualitat Remostrador de qualitat (0 - 15) (per defecte %d)" - -#: src/tools/pw-cat.c:1033 -#, fuzzy +" --rate Freqüència de mostreig (req. per a " +"rec) (predeterminat %u)\n" +" --channels Nombre de canals (req. per a rec) " +"(predeterminat %u)\n" +" --channel-map Mapa de canals\n" +" un dels següents: \"stereo\", " +"\"surround-51\",... o\n" +" llista separada per comes dels " +"noms dels canals: per exemple. «FL,FR»\n" +" --format Format de mostra %s (req. per a rec) "
View file
pipewire-0.3.71.tar.gz/po/pl.po -> pipewire-0.3.72.tar.gz/po/pl.po
Changed
@@ -8,8 +8,8 @@ "Project-Id-Version: pipewire\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/" "issues\n" -"POT-Creation-Date: 2023-03-04 12:58+0000\n" -"PO-Revision-Date: 2023-03-04 14:10+0100\n" +"POT-Creation-Date: 2023-05-28 10:45+0000\n" +"PO-Revision-Date: 2023-05-28 12:48+0200\n" "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n" "Language-Team: Polish <community-poland@mozilla.org>\n" "Language: pl\n" @@ -41,17 +41,17 @@ msgid "Start the PipeWire Media System" msgstr "Uruchomienie systemu multimediów PipeWire" -#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:159 -#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:159 +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:141 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:141 #, c-format -msgid "Tunnel to %s/%s" -msgstr "Tunel do %s/%s" +msgid "Tunnel to %s%s%s" +msgstr "Tunel do %s%s%s" #: src/modules/module-fallback-sink.c:31 msgid "Dummy Output" msgstr "Głuche wyjście" -#: src/modules/module-pulse-tunnel.c:675 +#: src/modules/module-pulse-tunnel.c:844 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunel dla %s@%s" @@ -175,7 +175,7 @@ " -o, --encoded Tryb zakodowany\n" "\n" -#: src/tools/pw-cli.c:2216 +#: src/tools/pw-cli.c:2220 #, c-format msgid "" "%s options command\n" @@ -200,7 +200,7 @@ msgstr "Dźwięk w zastosowaniach profesjonalnych" #: spa/plugins/alsa/acp/acp.c:427 spa/plugins/alsa/acp/alsa-mixer.c:4648 -#: spa/plugins/bluez5/bluez5-device.c:1283 +#: spa/plugins/bluez5/bluez5-device.c:1586 msgid "Off" msgstr "Wyłączone" @@ -227,7 +227,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:2657 #: spa/plugins/alsa/acp/alsa-mixer.c:2741 -#: spa/plugins/bluez5/bluez5-device.c:1519 +#: spa/plugins/bluez5/bluez5-device.c:1831 msgid "Microphone" msgstr "Mikrofon" @@ -293,7 +293,7 @@ msgstr "Brak podbicia basów" #: spa/plugins/alsa/acp/alsa-mixer.c:2672 -#: spa/plugins/bluez5/bluez5-device.c:1525 +#: spa/plugins/bluez5/bluez5-device.c:1837 msgid "Speaker" msgstr "Głośnik" @@ -408,7 +408,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4484 #: spa/plugins/alsa/acp/alsa-mixer.c:4642 -#: spa/plugins/bluez5/bluez5-device.c:1507 +#: spa/plugins/bluez5/bluez5-device.c:1819 msgid "Headset" msgstr "Słuchawki z mikrofonem" @@ -522,12 +522,12 @@ msgid "Mono Chat + 7.1 Surround" msgstr "Rozmowa mono + przestrzenne 7.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4754 +#: spa/plugins/alsa/acp/alsa-mixer.c:4748 #, c-format msgid "%s Output" msgstr "Wyjście %s" -#: spa/plugins/alsa/acp/alsa-mixer.c:4761 +#: spa/plugins/alsa/acp/alsa-mixer.c:4756 #, c-format msgid "%s Input" msgstr "Wejście %s" @@ -632,104 +632,104 @@ msgid "Modem" msgstr "Modem" -#: spa/plugins/bluez5/bluez5-device.c:1294 +#: spa/plugins/bluez5/bluez5-device.c:1597 msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" msgstr "Bramka dźwięku (źródło A2DP i AG HSP/HFP)" -#: spa/plugins/bluez5/bluez5-device.c:1319 +#: spa/plugins/bluez5/bluez5-device.c:1622 #, c-format msgid "High Fidelity Playback (A2DP Sink, codec %s)" msgstr "Odtwarzanie o wysokiej dokładności (odpływ A2DP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1322 +#: spa/plugins/bluez5/bluez5-device.c:1625 #, c-format msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" msgstr "Dupleks o wysokiej dokładności (źródło/odpływ A2DP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1330 +#: spa/plugins/bluez5/bluez5-device.c:1633 msgid "High Fidelity Playback (A2DP Sink)" msgstr "Odtwarzanie o wysokiej dokładności (odpływ A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:1332 +#: spa/plugins/bluez5/bluez5-device.c:1635 msgid "High Fidelity Duplex (A2DP Source/Sink)" msgstr "Dupleks o wysokiej dokładności (źródło/odpływ A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:1374 +#: spa/plugins/bluez5/bluez5-device.c:1677 #, c-format msgid "High Fidelity Playback (BAP Sink, codec %s)" msgstr "Odtwarzanie o wysokiej dokładności (odpływ BAP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1378 +#: spa/plugins/bluez5/bluez5-device.c:1681 #, c-format msgid "High Fidelity Input (BAP Source, codec %s)" msgstr "Wejście o wysokiej dokładności (źródło BAP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1382 +#: spa/plugins/bluez5/bluez5-device.c:1685 #, c-format msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)" msgstr "Dupleks o wysokiej dokładności (źródło/odpływ BAP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1390= +#: spa/plugins/bluez5/bluez5-device.c:1693 msgid "High Fidelity Playback (BAP Sink)" msgstr "Odtwarzanie o wysokiej dokładności (odpływ BAP)" -#: spa/plugins/bluez5/bluez5-device.c:1393 +#: spa/plugins/bluez5/bluez5-device.c:1696 msgid "High Fidelity Input (BAP Source)" msgstr "Wejście o wysokiej dokładności (źródło BAP)" -#: spa/plugins/bluez5/bluez5-device.c:1396 +#: spa/plugins/bluez5/bluez5-device.c:1699 msgid "High Fidelity Duplex (BAP Source/Sink)" msgstr "Dupleks o wysokiej dokładności (źródło/odpływ BAP)" -#: spa/plugins/bluez5/bluez5-device.c:1424 +#: spa/plugins/bluez5/bluez5-device.c:1735 #, c-format msgid "Headset Head Unit (HSP/HFP, codec %s)" msgstr "Jednostka główna słuchawek z mikrofonem (HSP/HFP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1429 +#: spa/plugins/bluez5/bluez5-device.c:1740 msgid "Headset Head Unit (HSP/HFP)" msgstr "Jednostka główna słuchawek z mikrofonem (HSP/HFP)" -#: spa/plugins/bluez5/bluez5-device.c:1508 -#: spa/plugins/bluez5/bluez5-device.c:1513 -#: spa/plugins/bluez5/bluez5-device.c:1520 -#: spa/plugins/bluez5/bluez5-device.c:1526 -#: spa/plugins/bluez5/bluez5-device.c:1532 -#: spa/plugins/bluez5/bluez5-device.c:1538 -#: spa/plugins/bluez5/bluez5-device.c:1544 -#: spa/plugins/bluez5/bluez5-device.c:1550 -#: spa/plugins/bluez5/bluez5-device.c:1556 +#: spa/plugins/bluez5/bluez5-device.c:1820 +#: spa/plugins/bluez5/bluez5-device.c:1825 +#: spa/plugins/bluez5/bluez5-device.c:1832 +#: spa/plugins/bluez5/bluez5-device.c:1838 +#: spa/plugins/bluez5/bluez5-device.c:1844 +#: spa/plugins/bluez5/bluez5-device.c:1850 +#: spa/plugins/bluez5/bluez5-device.c:1856 +#: spa/plugins/bluez5/bluez5-device.c:1862 +#: spa/plugins/bluez5/bluez5-device.c:1868 msgid "Handsfree" msgstr "Zestaw głośnomówiący" -#: spa/plugins/bluez5/bluez5-device.c:1514 +#: spa/plugins/bluez5/bluez5-device.c:1826 msgid "Handsfree (HFP)" msgstr "Zestaw głośnomówiący (HFP)" -#: spa/plugins/bluez5/bluez5-device.c:1531 +#: spa/plugins/bluez5/bluez5-device.c:1843 msgid "Headphone" msgstr "Słuchawki"
View file
pipewire-0.3.71.tar.gz/po/tr.po -> pipewire-0.3.72.tar.gz/po/tr.po
Changed
@@ -1,6 +1,7 @@ # Turkish translation for PipeWire. -# Copyright (C) 2014 PipeWire's COPYRIGHT HOLDER +# Copyright (C) 2014-2023 PipeWire's COPYRIGHT HOLDER # This file is distributed under the same license as the PipeWire package. +# # Necdet Yücel <necdetyucel@gmail.com>, 2014. # Kaan Özdinçer <kaanozdincer@gmail.com>, 2014. # Muhammet Kara <muhammetk@gmail.com>, 2015, 2016, 2017. @@ -12,15 +13,15 @@ "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/" "issues/new\n" "POT-Creation-Date: 2022-06-30 12:50+0200\n" -"PO-Revision-Date: 2022-10-23 10:40+0300\n" -"Last-Translator: Oğuz Ersen <oguz@ersen.moe>\n" -"Language-Team: Turkish <tr>\n" +"PO-Revision-Date: 2023-05-26 23:39+0300\n" +"Last-Translator: Sabri Ünal <libreajans@gmail.com>\n" +"Language-Team: Türkçe <takim@gnome.org.tr>\n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.4.2\n" +"X-Generator: Poedit 3.2.2\n" #: src/daemon/pipewire.c:46 #, c-format @@ -96,7 +97,7 @@ " -P --properties Set node properties\n" "\n" msgstr "" -" -R, --remote Uzak arka plan programı adı\n" +" -R, --remote Uzak art alan hizmeti adı\n" " --media-type Ortam türünü ayarla (öntanımlı %s)\n" " --media-category Ortam kategorisini ayarla (öntanımlı " "%s)\n" @@ -175,7 +176,7 @@ "%s seçenekler komut\n" " -h, --help Bu yardımı göster\n" " --version Sürümü göster\n" -" -d, --daemon Arka plan programı olarak başlat " +" -d, --daemon Art alan hizmeti olarak başlat " "(Öntanımlı olarak yanlış)\n" " -r, --remote Uzak arka plan programı adı\n" "\n" @@ -683,9 +684,3 @@ #: spa/plugins/bluez5/bluez5-device.c:1498 msgid "Bluetooth (HFP)" msgstr "Bluetooth (HFP)" - -#~ msgid "PipeWire Media System" -#~ msgstr "PipeWire Ortam Sistemi" - -#~ msgid "Start the PipeWire Media System" -#~ msgstr "PipeWire Ortam Sistemini Başlat"
View file
pipewire-0.3.71.tar.gz/spa/plugins/alsa/alsa-compress-offload-sink.c -> pipewire-0.3.72.tar.gz/spa/plugins/alsa/alsa-compress-offload-sink.c
Changed
@@ -510,6 +510,8 @@ this->device_context = NULL; this->device_started = false; this->device_is_paused = false; + + this->have_format = false; } static int device_start(struct impl *this) @@ -919,11 +921,6 @@ if (this->started) return 0; - if (!this->have_format) - return -EIO; - if (this->n_buffers == 0) - return -EIO; - this->following = is_following(this); spa_log_debug(this->log, "%p: starting output; starting as follower: %d", this, this->following); @@ -1357,8 +1354,14 @@ break; case SPA_NODE_COMMAND_Start: + if (!this->have_format) + return -EIO; + if (this->n_buffers == 0) + return -EIO; + if (SPA_UNLIKELY((res = do_start(this)) < 0)) return res; + break; case SPA_NODE_COMMAND_Suspend: @@ -1403,6 +1406,12 @@ "device opened: %d have configured format: %d device started: %d", this, device_opened, this->have_format, device_started); + if (!this->started && this->have_format) { + spa_log_debug(this->log, "%p: closing device to reset configured format", this); + device_close(this); + device_opened = false; + } + if (!device_opened) { if ((res = device_open(this)) < 0) return res; @@ -1487,11 +1496,18 @@ return port_enum_formats(this, seq, start, num, filter, &b); case SPA_PARAM_Format: - if (!this->have_format) + if (!this->have_format) { + spa_log_debug(this->log, "%p: attempted to enumerate current " + "format, but no current audio info set", this); return -EIO; + } + if (result.index > 0) return 0; + spa_log_debug(this->log, "%p: current audio info is set; " + "enumerating currently set format", this); + param = spa_format_audio_build(&b, id, &this->current_audio_info); break; @@ -1557,8 +1573,6 @@ spa_log_debug(this->log, "%p: clearing format and closing device", this); device_close(this); clear_buffers(this); - - this->have_format = false; } else { struct spa_audio_info info = { 0 }; uint32_t rate;
View file
pipewire-0.3.71.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.72.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
@@ -771,6 +771,7 @@ break; case SPA_IO_RateMatch: this->rate_match = data; + spa_alsa_update_rate_match(this); break; default: return -ENOENT; @@ -819,6 +820,11 @@ io->status = SPA_STATUS_OK; } + else 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.71.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.72.tar.gz/spa/plugins/alsa/alsa-pcm-source.c
Changed
@@ -709,6 +709,7 @@ break; case SPA_IO_RateMatch: this->rate_match = data; + spa_alsa_update_rate_match(this); break; default: return -ENOENT;
View file
pipewire-0.3.71.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.72.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -477,6 +477,11 @@ .write = log_write, }; +static void silence_error_handler(const char *file, int line, + const char *function, int err, const char *fmt, ...) +{ +} + int spa_alsa_init(struct state *state, const struct spa_dict *info) { uint32_t i; @@ -546,6 +551,57 @@ return err; } +static int probe_pitch_ctl(struct state *state, const char* device_name) +{ + snd_ctl_elem_id_t *id; + /* TODO: Add configuration params for the control name and units */ + const char *elem_name = + state->stream == SND_PCM_STREAM_CAPTURE ? + "Capture Pitch 1000000" : + "Playback Pitch 1000000"; + int err; + + snd_lib_error_set_handler(silence_error_handler); + + err = snd_ctl_open(&state->ctl, device_name, SND_CTL_NONBLOCK); + if (err < 0) { + spa_log_info(state->log, "%s could not find ctl device: %s", + state->props.device, snd_strerror(err)); + state->ctl = NULL; + goto error; + } + + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_id_set_name(id, elem_name); + snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM); + + snd_ctl_elem_value_malloc(&state->pitch_elem); + snd_ctl_elem_value_set_id(state->pitch_elem, id); + + err = snd_ctl_elem_read(state->ctl, state->pitch_elem); + if (err < 0) { + spa_log_debug(state->log, "%s: did not find ctl %s: %s", + state->props.device, elem_name, snd_strerror(err)); + + snd_ctl_elem_value_free(state->pitch_elem); + state->pitch_elem = NULL; + + snd_ctl_close(state->ctl); + state->ctl = NULL; + goto error; + } + + snd_ctl_elem_value_set_integer(state->pitch_elem, 0, 1000000); + CHECK(snd_ctl_elem_write(state->ctl, state->pitch_elem), "snd_ctl_elem_write"); + state->last_rate = 1.0; + + spa_log_info(state->log, "%s: found ctl %s", state->props.device, elem_name); + err = 0; +error: + snd_lib_error_set_handler(NULL); + return err; +} + int spa_alsa_open(struct state *state, const char *params) { int err; @@ -588,6 +644,8 @@ state->sample_count = 0; state->sample_time = 0; + probe_pitch_ctl(state, device_name); + return 0; error_exit_close: @@ -622,6 +680,14 @@ state->have_format = false; state->opened = false; + if (state->pitch_elem) { + snd_ctl_elem_value_free(state->pitch_elem); + state->pitch_elem = NULL; + + snd_ctl_close(state->ctl); + state->ctl = NULL; + } + return err; } @@ -1665,6 +1731,41 @@ return match ? 0 : 1; } +int spa_alsa_update_rate_match(struct state *state) +{ + uint64_t pitch, last_pitch; + int err; + + if (!state->pitch_elem) + return -ENOENT; + + /* The rate/pitch defines the rate of input to output (if there were a + * resampler, it's the ratio of input samples to output samples). This + * means that to adjust the playback rate, we need to apply the inverse + * of the given rate. */ + if (state->stream == SND_PCM_STREAM_CAPTURE) { + pitch = 1000000 * state->rate_match->rate; + last_pitch = 1000000 * state->last_rate; + } else { + pitch = 1000000 / state->rate_match->rate; + last_pitch = 1000000 / state->last_rate; + } + + /* The pitch adjustment is limited to 1 ppm */ + if (pitch == last_pitch) + return 0; + + snd_ctl_elem_value_set_integer(state->pitch_elem, 0, pitch); + CHECK(snd_ctl_elem_write(state->ctl, state->pitch_elem), "snd_ctl_elem_write"); + + spa_log_trace_fp(state->log, "%s %u set rate to %g", + state->props.device, state->stream, state->rate_match->rate); + + state->last_rate = state->rate_match->rate; + + return 0; +} + static int set_swparams(struct state *state) { snd_pcm_t *hndl = state->hndl; @@ -1856,7 +1957,8 @@ return do_start(state); } -static int get_avail(struct state *state, uint64_t current_time) +#if 0 +static int get_avail(struct state *state, uint64_t current_time, snd_pcm_uframes_t *delay) { int res, missed; snd_pcm_sframes_t avail; @@ -1874,19 +1976,21 @@ } else { state->alsa_recovering = false; } + *delay = avail; return avail; } -#if 0 -static int get_avail_htimestamp(struct state *state, uint64_t current_time) +#else +static int get_avail(struct state *state, uint64_t current_time, snd_pcm_uframes_t *delay) { int res, missed; snd_pcm_uframes_t avail; snd_htimestamp_t tstamp; uint64_t then; + avail = snd_pcm_avail(state->hndl); if ((res = snd_pcm_htimestamp(state->hndl, &avail, &tstamp)) < 0) { - if ((res = alsa_recover(state, avail)) < 0) + if ((res = alsa_recover(state, res)) < 0) return res; if ((res = snd_pcm_htimestamp(state->hndl, &avail, &tstamp)) < 0) { if ((missed = ratelimit_test(&state->rate_limit, current_time)) >= 0) { @@ -1898,28 +2002,34 @@ } else { state->alsa_recovering = false; } + *delay = avail; if ((then = SPA_TIMESPEC_TO_NSEC(&tstamp)) != 0) { + int64_t diff; + if (then < current_time) - avail += (current_time - then) * state->rate / SPA_NSEC_PER_SEC; + diff = ((int64_t)(current_time - then)) * state->rate / SPA_NSEC_PER_SEC; else - avail -= (then - current_time) * state->rate / SPA_NSEC_PER_SEC; + diff = -((int64_t)(then - current_time)) * state->rate / SPA_NSEC_PER_SEC; + + spa_log_trace_fp(state->log, "%"PRIu64" %"PRIu64" %"PRIi64, current_time, then, diff); + + *delay += diff; } return SPA_MIN(avail, state->buffer_frames); } #endif -static int get_status(struct state *state, uint64_t current_time, +static int get_status(struct state *state, uint64_t current_time, snd_pcm_uframes_t *avail, snd_pcm_uframes_t *delay, snd_pcm_uframes_t *target) { - int avail;
View file
pipewire-0.3.71.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.72.tar.gz/spa/plugins/alsa/alsa-pcm.h
Changed
@@ -218,6 +218,11 @@ struct spa_latency_info latency2; struct spa_process_latency_info process_latency; + + /* Rate match via an ALSA ctl */ + snd_ctl_t *ctl; + snd_ctl_elem_value_t *pitch_elem; + double last_rate; }; struct spa_pod *spa_alsa_enum_propinfo(struct state *state, @@ -230,6 +235,7 @@ const struct spa_pod *filter); int spa_alsa_set_format(struct state *state, struct spa_audio_info *info, uint32_t flags); +int spa_alsa_update_rate_match(struct state *state); int spa_alsa_init(struct state *state, const struct spa_dict *info); int spa_alsa_clear(struct state *state);
View file
pipewire-0.3.71.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.72.tar.gz/spa/plugins/audioconvert/audioadapter.c
Changed
@@ -87,6 +87,7 @@ unsigned int add_listener:1; unsigned int have_format:1; unsigned int started:1; + unsigned int warned:1; unsigned int ready:1; unsigned int driver:1; unsigned int async:1; @@ -844,15 +845,18 @@ if ((res = negotiate_buffers(this)) < 0) return res; this->ready = true; + this->warned = false; break; case SPA_NODE_COMMAND_Suspend: this->started = false; this->ready = false; + this->warned = false; spa_log_debug(this->log, "%p: suspending", this); break; case SPA_NODE_COMMAND_Pause: this->started = false; this->ready = false; + this->warned = false; spa_log_debug(this->log, "%p: pausing", this); break; case SPA_NODE_COMMAND_Flush: @@ -1470,7 +1474,9 @@ int status = 0, fstatus, retry = 8; if (!this->started) { - spa_log_warn(this->log, "%p: scheduling stopped node", this); + if (!this->warned) + spa_log_warn(this->log, "%p: scheduling stopped node", this); + this->warned = true; return -EIO; }
View file
pipewire-0.3.71.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.72.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -44,8 +44,10 @@ #define MAX_DATAS SPA_AUDIO_MAX_CHANNELS #define MAX_PORTS (SPA_AUDIO_MAX_CHANNELS+1) -#define DEFAULT_MUTE false -#define DEFAULT_VOLUME VOLUME_NORM +#define DEFAULT_MUTE false +#define DEFAULT_VOLUME VOLUME_NORM +#define DEFAULT_MIN_VOLUME 0.0 +#define DEFAULT_MAX_VOLUME 10.0 struct volumes { bool mute; @@ -72,6 +74,8 @@ struct props { float volume; + float min_volume; + float max_volume; float prev_volume; uint32_t n_channels; uint32_t channel_mapSPA_AUDIO_MAX_CHANNELS; @@ -91,6 +95,8 @@ { uint32_t i; props->volume = DEFAULT_VOLUME; + props->min_volume = DEFAULT_MIN_VOLUME; + props->max_volume = DEFAULT_MAX_VOLUME; props->n_channels = 0; for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) props->channel_mapi = SPA_AUDIO_CHANNEL_UNKNOWN; @@ -446,7 +452,8 @@ SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_volume), SPA_PROP_INFO_description, SPA_POD_String("Volume"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0)); + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, + DEFAULT_MIN_VOLUME, DEFAULT_MAX_VOLUME)); break; case 1: param = spa_pod_builder_add_object(&b, @@ -460,7 +467,8 @@ SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_channelVolumes), SPA_PROP_INFO_description, SPA_POD_String("Channel Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, + DEFAULT_MIN_VOLUME, DEFAULT_MAX_VOLUME), SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); break; case 3: @@ -483,7 +491,8 @@ SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_monitorVolumes), SPA_PROP_INFO_description, SPA_POD_String("Monitor Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, + DEFAULT_MIN_VOLUME, DEFAULT_MAX_VOLUME), SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); break; case 6: @@ -498,7 +507,8 @@ SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_softVolumes), SPA_PROP_INFO_description, SPA_POD_String("Soft Volumes"), - SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, 0.0, 10.0), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->volume, + DEFAULT_MIN_VOLUME, DEFAULT_MAX_VOLUME), SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array)); break; case 8: @@ -521,13 +531,31 @@ case 10: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.min-volume"), + SPA_PROP_INFO_description, SPA_POD_String("Minimum volume level"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->min_volume, + DEFAULT_MIN_VOLUME, DEFAULT_MAX_VOLUME), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 11: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.max-volume"), + SPA_PROP_INFO_description, SPA_POD_String("Maximum volume level"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->max_volume, + DEFAULT_MIN_VOLUME, DEFAULT_MAX_VOLUME), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + case 12: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_name, SPA_POD_String("channelmix.normalize"), SPA_PROP_INFO_description, SPA_POD_String("Normalize Volumes"), SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool( SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_NORMALIZE)), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 11: + case 13: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_name, SPA_POD_String("channelmix.mix-lfe"), @@ -536,7 +564,7 @@ SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_MIX_LFE)), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 12: + case 14: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix"), @@ -545,7 +573,7 @@ SPA_FLAG_IS_SET(this->mix.options, CHANNELMIX_OPTION_UPMIX)), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 13: + case 15: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_name, SPA_POD_String("channelmix.lfe-cutoff"), @@ -554,7 +582,7 @@ this->mix.lfe_cutoff, 0.0, 1000.0), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 14: + case 16: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_name, SPA_POD_String("channelmix.fc-cutoff"), @@ -563,7 +591,7 @@ this->mix.fc_cutoff, 0.0, 48000.0), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 15: + case 17: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_name, SPA_POD_String("channelmix.rear-delay"), @@ -572,7 +600,7 @@ this->mix.rear_delay, 0.0, 1000.0), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 16: + case 18: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_name, SPA_POD_String("channelmix.stereo-widen"), @@ -581,7 +609,7 @@ this->mix.widen, 0.0, 1.0), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 17: + case 19: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_name, SPA_POD_String("channelmix.hilbert-taps"), @@ -590,7 +618,7 @@ this->mix.hilbert_taps, 0, MAX_TAPS), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 18: + case 20: spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_PropInfo, id); spa_pod_builder_add(&b, SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix-method"), @@ -609,14 +637,14 @@ spa_pod_builder_pop(&b, &f1); param = spa_pod_builder_pop(&b, &f0); break; - case 19: + case 21: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_rate), SPA_PROP_INFO_description, SPA_POD_String("Rate scaler"), SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Double(p->rate, 0.0, 10.0)); break; - case 20: + case 22: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_quality), @@ -625,7 +653,7 @@ SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->resample_quality, 0, 14), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 21: + case 23: param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_PropInfo, id, SPA_PROP_INFO_name, SPA_POD_String("resample.disable"), @@ -633,7 +661,7 @@ SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->resample_disabled), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; - case 22: + case 24: param = spa_pod_builder_add_object(&b,
View file
pipewire-0.3.71.tar.gz/spa/plugins/audioconvert/resample-native.c -> pipewire-0.3.72.tar.gz/spa/plugins/audioconvert/resample-native.c
Changed
@@ -169,8 +169,8 @@ r->func_name = data->info->inter_name; } - spa_log_trace_fp(r->log, "native %p: rate:%f in:%d out:%d phase:%d inc:%d frac:%d", r, - rate, data->in_rate, data->out_rate, data->phase, data->inc, data->frac); + spa_log_trace_fp(r->log, "native %p: rate:%f in:%d out:%d gcd:%d phase:%d inc:%d frac:%d", r, + rate, r->i_rate, r->o_rate, gcd, data->phase, data->inc, data->frac); } @@ -367,8 +367,8 @@ return -ENOTSUP; } - spa_log_debug(r->log, "native %p: q:%d in:%d out:%d n_taps:%d n_phases:%d features:%08x:%08x", - r, r->quality, in_rate, out_rate, n_taps, n_phases, + spa_log_debug(r->log, "native %p: q:%d in:%d out:%d gcd:%d n_taps:%d n_phases:%d features:%08x:%08x", + r, r->quality, r->i_rate, r->o_rate, gcd, n_taps, n_phases, r->cpu_flags, d->info->cpu_flags); r->cpu_flags = d->info->cpu_flags;
View file
pipewire-0.3.71.tar.gz/spa/plugins/bluez5/bluez-hardware.conf -> pipewire-0.3.72.tar.gz/spa/plugins/bluez5/bluez-hardware.conf
Changed
@@ -30,6 +30,7 @@ { name = "Air 1 Plus", no-features = hw-volume-mic }, { name = "AirPods", no-features = msbc-alt1, msbc-alt1-rtl }, { name = "AirPods Pro", no-features = msbc-alt1, msbc-alt1-rtl }, + { name = "Audio Pro_A26", address = "~^7c:96:d2:", no-features = hw-volume }, # doesn't remember volume, #pipewire-3225 { name = "AXLOIE Goin", no-features = msbc-alt1, msbc-alt1-rtl }, { name = "BAA 100", no-features = hw-volume }, # Buxton BAA 100, doesn't remember volume, #pipewire-1449 { name = "D50s", address = "~^00:13:ef:", no-features = hw-volume }, # volume has no effect, #pipewire-1562
View file
pipewire-0.3.71.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.72.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -203,6 +203,7 @@ static int spa_bt_transport_start_volume_timer(struct spa_bt_transport *transport); static int spa_bt_transport_stop_release_timer(struct spa_bt_transport *transport); static int spa_bt_transport_start_release_timer(struct spa_bt_transport *transport); +static void spa_bt_transport_commit_release_timer(struct spa_bt_transport *transport); static int device_start_timer(struct spa_bt_device *device); static int device_stop_timer(struct spa_bt_device *device); @@ -2589,6 +2590,13 @@ if (state >= SPA_BT_TRANSPORT_STATE_PENDING && old < SPA_BT_TRANSPORT_STATE_PENDING) transport_sync_volume(transport); + if (state < SPA_BT_TRANSPORT_STATE_ACTIVE) { + /* If transport becomes inactive, do any pending releases + * immediately, since the fd is not usable any more. + */ + spa_bt_transport_commit_release_timer(transport); + } + if (state == SPA_BT_TRANSPORT_STATE_ERROR) { uint64_t now = get_time_now(monitor); @@ -2719,6 +2727,27 @@ return res; } +static void spa_bt_transport_do_release(struct spa_bt_transport *transport) +{ + struct spa_bt_monitor *monitor = transport->monitor; + + spa_assert(transport->acquire_refcount >= 1); + spa_assert(transport->acquired); + + if (transport->acquire_refcount == 1) { + if (!transport->keepalive) { + spa_bt_transport_impl(transport, release, 0); + transport->acquired = false; + } else { + spa_log_debug(monitor->log, "transport %p: keepalive %s on release", + transport, transport->path); + } + } else { + spa_log_debug(monitor->log, "transport %p: delayed decref %s", transport, transport->path); + } + transport->acquire_refcount -= 1; +} + int spa_bt_transport_release(struct spa_bt_transport *transport) { struct spa_bt_monitor *monitor = transport->monitor; @@ -2736,8 +2765,15 @@ spa_assert(transport->acquire_refcount == 1); spa_assert(transport->acquired); - /* Postpone transport releases, since we might need it again soon */ - return spa_bt_transport_start_release_timer(transport); + /* Postpone active transport releases, since we might need it again soon. + * If not active, release now since it has to be reacquired before using again. + */ + if (transport->state == SPA_BT_TRANSPORT_STATE_ACTIVE) { + return spa_bt_transport_start_release_timer(transport); + } else { + spa_bt_transport_do_release(transport); + return 0; + } } static int spa_bt_transport_release_now(struct spa_bt_transport *transport) @@ -2808,25 +2844,9 @@ static void spa_bt_transport_release_timer_event(struct spa_source *source) { struct spa_bt_transport *transport = source->data; - struct spa_bt_monitor *monitor = transport->monitor; - - spa_assert(transport->acquire_refcount >= 1); - spa_assert(transport->acquired); spa_bt_transport_stop_release_timer(transport); - - if (transport->acquire_refcount == 1) { - if (!transport->keepalive) { - spa_bt_transport_impl(transport, release, 0); - transport->acquired = false; - } else { - spa_log_debug(monitor->log, "transport %p: keepalive %s on release", - transport, transport->path); - } - } else { - spa_log_debug(monitor->log, "transport %p: delayed decref %s", transport, transport->path); - } - transport->acquire_refcount -= 1; + spa_bt_transport_do_release(transport); } static int spa_bt_transport_start_release_timer(struct spa_bt_transport *transport) @@ -2842,6 +2862,17 @@ return stop_timeout_timer(transport->monitor, &transport->release_timer); } +static void spa_bt_transport_commit_release_timer(struct spa_bt_transport *transport) +{ + struct spa_bt_monitor *monitor = transport->monitor; + + /* Do release now if it is pending */ + if (transport->release_timer.data) { + spa_log_debug(monitor->log, "transport %p: commit pending release", transport); + spa_bt_transport_release_timer_event(&transport->release_timer); + } +} + static void spa_bt_transport_volume_changed(struct spa_bt_transport *transport) { struct spa_bt_monitor *monitor = transport->monitor; @@ -4906,10 +4937,28 @@ dbus_connection_unregister_object_path(monitor->conn, A2DP_OBJECT_MANAGER_PATH); } +static bool have_codec_endpoints(struct spa_bt_monitor *monitor, bool bap) +{ + const struct media_codec * const * const media_codecs = monitor->media_codecs; + int i; + + for (i = 0; media_codecsi; i++) { + const struct media_codec *codec = media_codecsi; + + if (codec->bap != bap) + continue; + if (endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SINK) || + endpoint_should_be_registered(monitor, codec, SPA_BT_MEDIA_SOURCE)) + return true; + } + return false; +} + static int adapter_register_application(struct spa_bt_adapter *a, bool bap) { const char *object_manager_path = bap ? BAP_OBJECT_MANAGER_PATH : A2DP_OBJECT_MANAGER_PATH; struct spa_bt_monitor *monitor = a->monitor; + const char *ep_type_name = (bap ? "LE Audio" : "A2DP"); DBusMessage *m; DBusMessageIter i, d; DBusPendingCall *call; @@ -4925,8 +4974,14 @@ return -ENOTSUP; } + if (!have_codec_endpoints(monitor, bap)) { + spa_log_warn(monitor->log, "No available %s codecs to register on adapter %s", + ep_type_name, a->path); + return -ENOENT; + } + spa_log_debug(monitor->log, "Registering bluez5 %s media application on adapter %s", - (bap ? "LE Audio" : "A2DP"), a->path); + ep_type_name, a->path); m = dbus_message_new_method_call(BLUEZ_SERVICE, a->path,
View file
pipewire-0.3.71.tar.gz/spa/plugins/bluez5/media-source.c -> pipewire-0.3.72.tar.gz/spa/plugins/bluez5/media-source.c
Changed
@@ -845,14 +845,23 @@ { uint64_t old = full ? this->info.change_mask : 0; char latency64; + char media_name256; + + spa_scnprintf( + media_name, + sizeof(media_name), + "%s (codec %s)", + ((this->transport && this->transport->device->name) ? + this->transport->device->name : this->codec->bap ? "BAP" : "A2DP"), + this->codec->description + ); struct spa_dict_item node_info_items = { { SPA_KEY_DEVICE_API, "bluez5" }, { SPA_KEY_MEDIA_CLASS, this->is_internal ? "Audio/Source/Internal" : this->is_input ? "Audio/Source" : "Stream/Output/Audio" }, { SPA_KEY_NODE_LATENCY, this->is_input ? "" : latency }, - { "media.name", ((this->transport && this->transport->device->name) ? - this->transport->device->name : this->codec->bap ? "BAP" : "A2DP") }, + { "media.name", media_name }, { SPA_KEY_NODE_DRIVER, this->is_input ? "true" : "false" }, };
View file
pipewire-0.3.71.tar.gz/spa/plugins/control/mixer.c -> pipewire-0.3.72.tar.gz/spa/plugins/control/mixer.c
Changed
@@ -656,10 +656,16 @@ d = inport->buffersinio->buffer_id.buffer->datas; if ((pod = spa_pod_from_data(d->data, d->maxsize, - d->chunk->offset, d->chunk->size)) == NULL) + d->chunk->offset, d->chunk->size)) == NULL) { + spa_log_trace_fp(this->log, NAME " %p: skip input idx:%d max:%u " + "offset:%u size:%u", this, i, + d->maxsize, d->chunk->offset, d->chunk->size); continue; - if (!spa_pod_is_sequence(pod)) + } + if (!spa_pod_is_sequence(pod)) { + spa_log_trace_fp(this->log, NAME " %p: skip input idx:%d", this, i); continue; + } seqn_seq = pod; ctrln_seq = spa_pod_control_first(&seqn_seq->body);
View file
pipewire-0.3.71.tar.gz/spa/plugins/support/node-driver.c -> pipewire-0.3.72.tar.gz/spa/plugins/support/node-driver.c
Changed
@@ -539,10 +539,10 @@ const char *s = info->itemsi.value; if (spa_streq(k, "node.freewheel")) { this->props.freewheel = spa_atob(s); - } else if (spa_streq(k, "clock.name")) { + } else if (spa_streq(k, "clock.name") && this->clock_fd < 0) { spa_scnprintf(this->props.clock_name, sizeof(this->props.clock_name), "%s", s); - } else if (spa_streq(k, "clock.id")) { + } else if (spa_streq(k, "clock.id") && this->clock_fd < 0) { this->props.clock_id = clock_name_to_id(s); if (this->props.clock_id == -1) { spa_log_warn(this->log, "unknown clock id '%s'", s); @@ -551,7 +551,7 @@ } else if (spa_streq(k, "clock.device")) { this->clock_fd = open(s, O_RDWR); if (this->clock_fd == -1) { - spa_log_warn(this->log, "failed to open clock device '%s'", s); + spa_log_info(this->log, "failed to open clock device '%s'", s); } else { this->props.clock_id = FD_TO_CLOCKID(this->clock_fd); }
View file
pipewire-0.3.71.tar.gz/src/daemon/pipewire-aes67.conf.in -> pipewire-0.3.72.tar.gz/src/daemon/pipewire-aes67.conf.in
Changed
@@ -18,10 +18,28 @@ #default.clock.quantum-limit = 8192 } -#context.spa-libs = { -# audio.convert.* = audioconvert/libspa-audioconvert -# support.* = support/libspa-support -#} +context.spa-libs = { + support.* = support/libspa-support +} + +context.objects = + # An example clock reading from /dev/ptp0. Another option is to sync the + # ptp clock to CLOCK_TAI and then set clock.id = tai. + # If both device and ID are given and available, device takes precedence + { factory = spa-node-factory + args = { + factory.name = support.node.driver + node.name = PTP0-Driver + node.group = pipewire.ptp0 + # This driver should only be used for network nodes marked with group + priority.driver = 0 + clock.name = "clock.system.ptp0" + clock.device = "/dev/ptp0" + clock.id = tai + object.export = true + } + } + context.modules = { name = libpipewire-module-rt @@ -35,12 +53,15 @@ } { name = libpipewire-module-protocol-native } { name = libpipewire-module-client-node } + { name = libpipewire-module-spa-node-factory } { name = libpipewire-module-adapter } { name = libpipewire-module-rtp-sap args = { local.ifname = eth0 sap.ip = 239.255.255.255 sap.port = 9875 + net.ttl = 32 + net.loop = true stream.rules = { @@ -55,10 +76,54 @@ media.class = "Audio/Source" device.api = aes67 sess.latency.msec = 10 + node.group = pipewire.ptp0 + } + } + }, + { + matches = + { + sess.sap.announce = true } + + actions = { + announce-stream = {} } - } + } } - } + }, + { name = libpipewire-module-rtp-sink + args = { + local.ifname = eth0 + destination.ip = 239.69.150.243 + destination.port = 5004 + net.mtu = 1280 + net.ttl = 32 + net.loop = true + sess.min-ptime = 1 + sess.max-ptime = 1 + sess.name = "PipeWire RTP stream" + sess.media = "audio" + sess.ts-refclk = "ptp=traceable" + sess.ts-offset = 0 + sess.ptime = 1 + sess.latency.msec = 1 + sess.announce = true + audio.format = "S24BE" + audio.rate = 48000 + audio.channels = 2 + audio.position = FL FR + + stream.props = { + node.name = "rtp-sink" + media.class = "Audio/Sink" + node.virtual = false + device.api = aes67 + sess.sap.announce = true + node.always-process = true + node.group = pipewire.ptp0 + } + } + },
View file
pipewire-0.3.71.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.72.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
@@ -129,6 +129,8 @@ # Possible quirks:" # force-s16-info forces sink and source info as S16 format # remove-capture-dont-move removes the capture DONT_MOVE flag + # block-source-volume blocks updates to source volume + # block-sink-volume blocks updates to sink volume #quirks = } } @@ -158,4 +160,8 @@ } } } + #{ + # matches = { application.process.binary = "Discord" } + # actions = { quirks = block-source-volume } + #}
View file
pipewire-0.3.71.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.72.tar.gz/src/daemon/pipewire.conf.in
Changed
@@ -221,19 +221,6 @@ node.freewheel = true } } - # An example clock reading from /dev/ptp0. Another option is to sync the - # ptp clock to CLOCK_TAI and then set clock.id = tai. - #{ factory = spa-node-factory - # args = { - # factory.name = support.node.driver - # node.name = PTP0-Driver - # node.group = pipewire.ptp0 - # priority.driver = 30000 - # clock.name = "clock.system.ptp0" - # #clock.id = tai - # clock.device = "/dev/ptp0" - # } - #} # This creates a new Source node. It will have input ports # that you can link, to provide audio for this source.
View file
pipewire-0.3.72.tar.gz/src/examples/internal.c
Added
@@ -0,0 +1,126 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +/* + title + In process pipewire graph + title + */ + +#include <stdio.h> +#include <errno.h> +#include <signal.h> +#include <math.h> + +#include <spa/utils/names.h> + +#include <pipewire/pipewire.h> +#include <pipewire/impl.h> + +struct data { + struct pw_main_loop *loop; + + struct pw_context *context; + struct pw_core *core; + + struct pw_proxy *source; + struct pw_proxy *sink; + struct pw_proxy *link; + + int res; +}; + +static void do_quit(void *userdata, int signal_number) +{ + struct data *data = userdata; + pw_main_loop_quit(data->loop); +} + +int main(int argc, char *argv) +{ + struct data data = { 0, }; + struct pw_properties *props; + const char *dev = "hw:0"; + + pw_init(&argc, &argv); + + data.loop = pw_main_loop_new(NULL); + + if (argc > 1) + dev = argv1; + + pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGINT, do_quit, &data); + pw_loop_add_signal(pw_main_loop_get_loop(data.loop), SIGTERM, do_quit, &data); + + data.context = pw_context_new(pw_main_loop_get_loop(data.loop), + pw_properties_new( + PW_KEY_CONFIG_NAME, "client-rt.conf", + NULL), 0); + + pw_context_load_module(data.context, "libpipewire-module-spa-node-factory", NULL, NULL); + pw_context_load_module(data.context, "libpipewire-module-link-factory", NULL, NULL); + + data.core = pw_context_connect_self(data.context, NULL, 0); + if (data.core == NULL) { + fprintf(stderr, "can't connect: %m\n"); + data.res = -errno; + goto cleanup; + } + + props = pw_properties_new( + SPA_KEY_LIBRARY_NAME, "audiotestsrc/libspa-audiotestsrc", + SPA_KEY_FACTORY_NAME, "audiotestsrc", + PW_KEY_NODE_NAME, "test_source", + "Spa:Pod:Object:Param:Props:live", "false", + NULL); + data.source = pw_core_create_object(data.core, + "spa-node-factory", + PW_TYPE_INTERFACE_Node, + PW_VERSION_NODE, + &props->dict, 0); + pw_properties_free(props); + + props = pw_properties_new( + SPA_KEY_LIBRARY_NAME, "alsa/libspa-alsa", + SPA_KEY_FACTORY_NAME, SPA_NAME_API_ALSA_PCM_SINK, + PW_KEY_NODE_NAME, "alsa_sink", + "api.alsa.path", dev, + "priority.driver", "1000", + NULL); + data.sink = pw_core_create_object(data.core, + "spa-node-factory", + PW_TYPE_INTERFACE_Node, + PW_VERSION_NODE, + &props->dict, 0); + + while (true) { + if (pw_proxy_get_bound_id(data.source) != SPA_ID_INVALID && + pw_proxy_get_bound_id(data.sink) != SPA_ID_INVALID) + break; + + pw_loop_iterate(pw_main_loop_get_loop(data.loop), -1); + } + + pw_properties_clear(props); + pw_properties_setf(props, + PW_KEY_LINK_OUTPUT_NODE, "%d", pw_proxy_get_bound_id(data.source)); + pw_properties_setf(props, + PW_KEY_LINK_INPUT_NODE, "%d", pw_proxy_get_bound_id(data.sink)); + + data.link = pw_core_create_object(data.core, + "link-factory", + PW_TYPE_INTERFACE_Link, + PW_VERSION_LINK, + &props->dict, 0); + pw_properties_free(props); + + pw_main_loop_run(data.loop); + +cleanup: + pw_context_destroy(data.context); + pw_main_loop_destroy(data.loop); + pw_deinit(); + + return data.res; +}
View file
pipewire-0.3.71.tar.gz/src/examples/meson.build -> pipewire-0.3.72.tar.gz/src/examples/meson.build
Changed
@@ -13,6 +13,7 @@ 'video-src-reneg', 'video-src-fixate', 'video-play-fixate', + 'internal', 'export-sink', 'export-source', 'export-spa',
View file
pipewire-0.3.71.tar.gz/src/gst/gstpipewiresink.c -> pipewire-0.3.72.tar.gz/src/gst/gstpipewiresink.c
Changed
@@ -482,7 +482,7 @@ GstMemory *mem = gst_buffer_peek_memory (buffer, i); d->chunk->offset = mem->offset; d->chunk->size = mem->size; - d->chunk->stride = 0; + d->chunk->stride = pwsink->pool->video_info.stridei; } GstVideoMeta *meta = gst_buffer_get_video_meta (buffer);
View file
pipewire-0.3.71.tar.gz/src/modules/meson.build -> pipewire-0.3.72.tar.gz/src/modules/meson.build
Changed
@@ -14,12 +14,15 @@ 'module-example-sink.c', 'module-example-source.c', 'module-fallback-sink.c', + 'module-ffado-driver.c', 'module-filter-chain.c', 'module-jack-tunnel.c', 'module-jackdbus-detect.c', 'module-link-factory.c', 'module-loopback.c', 'module-metadata.c', + 'module-netjack2-driver.c', + 'module-netjack2-manager.c', 'module-pipe-tunnel.c', 'module-portal.c', 'module-profiler.c', @@ -185,7 +188,45 @@ summary({'jack-tunnel': build_module_jack_tunnel}, bool_yn: true, section: 'Optional Modules') +build_module_ffado_driver = libffado_dep.found() +if build_module_ffado_driver + pipewire_module_jack_tunnel = shared_library('pipewire-module-ffado-driver', + 'module-ffado-driver.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : mathlib, dl_lib, pipewire_dep, libffado_dep, + ) +endif + +summary({'ffado-driver': build_module_ffado_driver}, bool_yn: true, section: 'Optional Modules') + +opus_custom_h = cc.has_header('opus/opus_custom.h', dependencies: opus_dep) +if opus_custom_h + opus_custom_dep = declare_dependency(compile_args: '-DHAVE_OPUS_CUSTOM', dependencies: opus_dep) +else + opus_custom_dep = dependency('', required: false) +endif +summary({'Opus with custom modes for NetJack2': opus_custom_dep}, bool_yn: true, section: 'Streaming between daemons') + +pipewire_module_netjack2_driver = shared_library('pipewire-module-netjack2-driver', + 'module-netjack2-driver.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : spa_dep, mathlib, dl_lib, pipewire_dep, opus_custom_dep, +) +pipewire_module_netjack2_manager = shared_library('pipewire-module-netjack2-manager', + 'module-netjack2-manager.c' , + include_directories : configinc, + install : true, + install_dir : modules_install_dir, + install_rpath: modules_install_dir, + dependencies : spa_dep, mathlib, dl_lib, pipewire_dep, opus_custom_dep, +) pipewire_module_profiler = shared_library('pipewire-module-profiler', 'module-profiler.c', @@ -322,6 +363,8 @@ 'module-protocol-pulse/modules/module-switch-on-connect.c', 'module-protocol-pulse/modules/module-tunnel-sink.c', 'module-protocol-pulse/modules/module-tunnel-source.c', + 'module-protocol-pulse/modules/module-virtual-sink.c', + 'module-protocol-pulse/modules/module-virtual-source.c', 'module-protocol-pulse/modules/module-x11-bell.c', 'module-protocol-pulse/modules/module-zeroconf-discover.c',
View file
pipewire-0.3.71.tar.gz/src/modules/module-client-node/client-node.c -> pipewire-0.3.72.tar.gz/src/modules/module-client-node/client-node.c
Changed
@@ -50,7 +50,7 @@ struct mix { unsigned int valid:1; - uint32_t id; + uint32_t mix_id; struct port *port; uint32_t peer_id; uint32_t n_buffers; @@ -209,10 +209,10 @@ return mix; } -static void mix_init(struct mix *mix, struct port *p, uint32_t id) +static void mix_init(struct mix *mix, struct port *p, uint32_t mix_id) { mix->valid = true; - mix->id = id; + mix->mix_id = mix_id; mix->port = p; mix->n_buffers = 0; } @@ -281,7 +281,7 @@ if (!mix->valid) return; do_port_use_buffers(impl, port->direction, port->id, - mix->id, 0, NULL, 0); + mix->mix_id, 0, NULL, 0); mix->valid = false; } @@ -890,8 +890,8 @@ * directly */ spa_log_warn(impl->log, "exported node activation"); spa_system_clock_gettime(impl->data_system, CLOCK_MONOTONIC, &ts); - n->rt.activation->status = PW_NODE_ACTIVATION_TRIGGERED; - n->rt.activation->signal_time = SPA_TIMESPEC_TO_NSEC(&ts); + n->rt.target.activation->status = PW_NODE_ACTIVATION_TRIGGERED; + n->rt.target.activation->signal_time = SPA_TIMESPEC_TO_NSEC(&ts); if (SPA_UNLIKELY(spa_system_eventfd_write(n->rt.target.system, n->rt.target.fd, 1) < 0)) pw_log_warn("%p: write failed %m", impl); @@ -1080,8 +1080,6 @@ if (SPA_LIKELY(source->rmask & SPA_IO_IN)) { uint64_t cmd; struct pw_impl_node *node = impl->this.node; - struct pw_node_activation *a = node->rt.activation; - int status; if (SPA_UNLIKELY(spa_system_eventfd_read(impl->data_system, impl->data_source.fd, &cmd) < 0)) @@ -1090,9 +1088,15 @@ pw_log_info("(%s-%u) client missed %"PRIu64" wakeups", node->name, node->info.id, cmd - 1); - status = a->state0.status; - spa_log_trace_fp(impl->log, "%p: got ready %d", impl, status); - spa_node_call_ready(&impl->callbacks, status); + if (impl->resource && impl->resource->version < 5) { + struct pw_node_activation *a = node->rt.target.activation; + int status = a->state0.status; + spa_log_trace_fp(impl->log, "%p: got ready %d", impl, status); + spa_node_call_ready(&impl->callbacks, status); + } else { + spa_log_trace_fp(impl->log, "%p: got complete", impl); + pw_context_driver_emit_complete(node->context, node); + } } } @@ -1197,6 +1201,57 @@ spa_node_emit_result(&impl->hooks, seq, 0, 0, NULL); } +static void node_peer_added(void *data, struct pw_impl_node *peer) +{ + struct impl *impl = data; + struct pw_memblock *m; + + m = pw_mempool_import_block(impl->client->pool, peer->activation); + if (m == NULL) { + pw_log_warn("%p: can't ensure mem: %m", impl); + return; + } + + pw_log_debug("%p: peer %p/%p id:%u added mem_id:%u", impl, peer, + impl->this.node, peer->info.id, m->id); + + if (impl->resource == NULL) + return; + + pw_client_node_resource_set_activation(impl->resource, + peer->info.id, + peer->source.fd, + m->id, + 0, + sizeof(struct pw_node_activation)); +} + +static void node_peer_removed(void *data, struct pw_impl_node *peer) +{ + struct impl *impl = data; + struct pw_memblock *m; + + m = pw_mempool_find_fd(impl->client->pool, peer->activation->fd); + if (m == NULL) { + pw_log_warn("%p: unknown peer %p fd:%d", impl, peer, + peer->source.fd); + return; + } + + pw_log_debug("%p: peer %p/%p id:%u removed mem_id:%u", impl, peer, + impl->this.node, peer->info.id, m->id); + + if (impl->resource != NULL) { + pw_client_node_resource_set_activation(impl->resource, + peer->info.id, + -1, + SPA_ID_INVALID, + 0, + 0); + } + pw_memblock_unref(m); +} + void pw_impl_client_node_registered(struct pw_impl_client_node *this, struct pw_global *global) { struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this); @@ -1225,6 +1280,8 @@ 0, sizeof(struct pw_node_activation)); + node_peer_added(impl, node); + if (impl->bind_node_id) { pw_global_bind(global, client, PW_PERM_ALL, impl->bind_node_version, impl->bind_node_id); @@ -1298,7 +1355,7 @@ pw_resource_destroy(impl->resource); if (impl->activation) - pw_memblock_unref(impl->activation); + pw_memblock_free(impl->activation); pw_array_for_each(area, &impl->io_areas) { if (*area) @@ -1351,6 +1408,11 @@ m->peer_id = mix->peer_id; + if (impl->resource && impl->resource->version >= 4) + pw_client_node_resource_port_set_mix_info(impl->resource, + mix->port.direction, mix->p->port_id, + mix->port.port_id, mix->peer_id, NULL); + pw_log_debug("%p: init mix id:%d io:%p base:%p", impl, mix->id, mix->io, area->map->ptr); @@ -1373,6 +1435,11 @@ if ((m = find_mix(port, mix->port.port_id)) == NULL || !m->valid) return -EINVAL; + if (impl->resource && impl->resource->version >= 4) + pw_client_node_resource_port_set_mix_info(impl->resource, + mix->port.direction, mix->p->port_id, + mix->port.port_id, SPA_ID_INVALID, NULL); + pw_map_remove(&impl->io_map, mix->id); m->valid = false; @@ -1458,13 +1525,7 @@ mix->io = data; else mix->io = NULL; - - if (mix->io != NULL && impl->resource && impl->resource->version >= 4) - pw_client_node_resource_port_set_mix_info(impl->resource, - direction, port->port_id, - mix->port.port_id, mix->peer_id, NULL); } - return do_port_set_io(impl, direction, port->port_id, mix->port.port_id, id, data, size); @@ -1544,62 +1605,6 @@ clear_port(impl, p); } -static void node_peer_added(void *data, struct pw_impl_node *peer) -{ - struct impl *impl = data; - struct pw_memblock *m; - - if (peer == impl->this.node) - return; - - m = pw_mempool_import_block(impl->client->pool, peer->activation); - if (m == NULL) { - pw_log_debug("%p: can't ensure mem: %m", impl); - return;
View file
pipewire-0.3.71.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.72.tar.gz/src/modules/module-client-node/remote-node.c
Changed
@@ -40,13 +40,15 @@ struct spa_list link; struct pw_impl_port *port; uint32_t mix_id; + uint32_t peer_id; struct pw_impl_port_mix mix; struct pw_array buffers; - bool active; }; struct node_data { struct pw_context *context; + struct spa_hook context_listener; + struct pw_loop *data_loop; struct spa_system *data_system; @@ -91,7 +93,7 @@ struct link *l; spa_list_for_each(l, links, link) { - if (l->node_id == node_id) + if (l->target.id == node_id) return l; } return NULL; @@ -138,66 +140,24 @@ } pw_memmap_free(data->activation); - data->node->rt.activation = data->node->activation->map->ptr; + data->node->rt.target.activation = data->node->activation->map->ptr; spa_system_close(data->data_system, data->rtwritefd); data->have_transport = false; } -static void mix_init(struct mix *mix, struct pw_impl_port *port, uint32_t mix_id) +static void mix_init(struct mix *mix, struct pw_impl_port *port, + uint32_t mix_id, uint32_t peer_id) { pw_log_debug("port %p: mix init %d.%d", port, port->port_id, mix_id); mix->port = port; mix->mix_id = mix_id; + mix->peer_id = peer_id; pw_impl_port_init_mix(port, &mix->mix); - mix->active = false; pw_array_init(&mix->buffers, 32); pw_array_ensure_size(&mix->buffers, sizeof(struct buffer) * 64); } -static int -do_deactivate_mix(struct spa_loop *loop, - bool async, uint32_t seq, const void *data, size_t size, void *user_data) -{ - struct mix *mix = user_data; - spa_list_remove(&mix->mix.rt_link); - return 0; -} - -static int -deactivate_mix(struct node_data *data, struct mix *mix) -{ - if (mix->active) { - pw_log_debug("node %p: mix %p deactivate", data, mix); - pw_loop_invoke(data->data_loop, - do_deactivate_mix, SPA_ID_INVALID, NULL, 0, true, mix); - mix->active = false; - } - return 0; -} - -static int -do_activate_mix(struct spa_loop *loop, - bool async, uint32_t seq, const void *data, size_t size, void *user_data) -{ - struct mix *mix = user_data; - - spa_list_append(&mix->port->rt.mix_list, &mix->mix.rt_link); - return 0; -} - -static int -activate_mix(struct node_data *data, struct mix *mix) -{ - if (!mix->active) { - pw_log_debug("node %p: mix %p activate", data, mix); - pw_loop_invoke(data->data_loop, - do_activate_mix, SPA_ID_INVALID, NULL, 0, false, mix); - mix->active = true; - } - return 0; -} - static struct mix *find_mix(struct node_data *data, enum spa_direction direction, uint32_t port_id, uint32_t mix_id) { @@ -214,15 +174,13 @@ return NULL; } -static struct mix *ensure_mix(struct node_data *data, - enum spa_direction direction, uint32_t port_id, uint32_t mix_id) +static struct mix *create_mix(struct node_data *data, + enum spa_direction direction, uint32_t port_id, + uint32_t mix_id, uint32_t peer_id) { struct mix *mix; struct pw_impl_port *port; - if ((mix = find_mix(data, direction, port_id, mix_id))) - return mix; - port = pw_impl_node_find_port(data->node, direction, port_id); if (port == NULL) return NULL; @@ -234,13 +192,21 @@ mix = spa_list_first(&data->free_mix, struct mix, link); spa_list_remove(&mix->link); } - - mix_init(mix, port, mix_id); + mix_init(mix, port, mix_id, peer_id); spa_list_append(&data->mixdirection, &mix->link); return mix; } +static struct mix *ensure_mix(struct node_data *data, + enum spa_direction direction, uint32_t port_id, + uint32_t mix_id) +{ + struct mix *mix; + if ((mix = find_mix(data, direction, port_id, mix_id))) + return mix; + return create_mix(data, direction, port_id, mix_id, SPA_ID_INVALID); +} static int client_node_transport(void *_data, int readfd, int writefd, uint32_t mem_id, uint32_t offset, uint32_t size) @@ -258,7 +224,10 @@ return -errno; } - node->rt.activation = data->activation->ptr; + node->rt.target.activation = data->activation->ptr; + node->rt.position = &node->rt.target.activation->position; + node->info.id = node->rt.target.activation->position.clock.id; + node->rt.target.id = node->info.id; pw_log_debug("remote-node %p: fds:%d %d node:%u activation:%p", proxy, readfd, writefd, data->remote_id, data->activation->ptr); @@ -824,11 +793,6 @@ pw_log_debug("port %p: set io:%s new:%p old:%p", mix->port, spa_debug_type_find_name(spa_type_io, id), ptr, mix->mix.io); - if (id == SPA_IO_Buffers) { - if (ptr == NULL && mix->mix.io) - deactivate_mix(data, mix); - } - if ((res = spa_node_port_set_io(mix->port->mix, direction, mix->mix.port.port_id, id, ptr, size)) < 0) { if (res == -ENOTSUP) @@ -836,11 +800,6 @@ else goto exit_free; } - if (id == SPA_IO_Buffers) { - mix->mix.io = ptr; - if (ptr) - activate_mix(data, mix); - } exit_free: pw_memmap_free(old); exit: @@ -878,13 +837,6 @@ struct link *link; int res = 0; - if (data->remote_id == node_id) { - pw_log_debug("node %p: our activation %u: %u %u %u", node, node_id, - memid, offset, size); - spa_system_close(data->data_system, signalfd); - return 0; - } - if (memid == SPA_ID_INVALID) { mm = ptr = NULL; size = 0; @@ -897,7 +849,13 @@ } ptr = mm->ptr; } - pw_log_debug("node %p: set activation %d %p %u %u", node, node_id, ptr, offset, size); + if (data->remote_id == node_id) { + pw_log_debug("node %p: our activation %u: %u %p %u %u", node, node_id, + memid, ptr, offset, size); + } else { + pw_log_debug("node %p: set activation %u: %u %p %u %u", node, node_id,
View file
pipewire-0.3.71.tar.gz/src/modules/module-combine-stream.c -> pipewire-0.3.72.tar.gz/src/modules/module-combine-stream.c
Changed
@@ -965,8 +965,17 @@ struct stream *s; bool delay_changed = false; - if ((in = pw_stream_dequeue_buffer(impl->combine)) == NULL) { - pw_log_debug("out of buffers: %m"); + in = NULL; + while (true) { + struct pw_buffer *t; + if ((t = pw_stream_dequeue_buffer(impl->combine)) == NULL) + break; + if (in) + pw_stream_queue_buffer(impl->combine, in); + in = t; + } + if (in == NULL) { + pw_log_debug("%p: out of input buffers: %m", impl); return; } @@ -980,7 +989,7 @@ delay_changed = true; if ((out = pw_stream_dequeue_buffer(s->stream)) == NULL) { - pw_log_warn("out of playback buffers: %m"); + pw_log_warn("%p: out of playback buffers: %m", s); goto do_trigger; } @@ -1033,7 +1042,7 @@ bool delay_changed = false; if ((out = pw_stream_dequeue_buffer(impl->combine)) == NULL) { - pw_log_debug("out of buffers: %m"); + pw_log_debug("%p: out of output buffers: %m", impl); return; } @@ -1046,8 +1055,17 @@ if (check_stream_delay(s)) delay_changed = true; - if ((in = pw_stream_dequeue_buffer(s->stream)) == NULL) { - pw_log_warn("%p: out of capture buffers: %m", s); + in = NULL; + while (true) { + struct pw_buffer *t; + if ((t = pw_stream_dequeue_buffer(s->stream)) == NULL) + break; + if (in) + pw_stream_queue_buffer(s->stream, in); + in = t; + } + if (in == NULL) { + pw_log_debug("%p: out of input buffers: %m", s); continue; } s->ready = false; @@ -1357,6 +1375,8 @@ pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); if (pw_properties_get(props, "resample.prefill") == NULL) pw_properties_set(props, "resample.prefill", "true"); + if (pw_properties_get(props, "resample.disable") == NULL) + pw_properties_set(props, "resample.disable", "true"); if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL) { if (impl->mode == MODE_SINK)
View file
pipewire-0.3.72.tar.gz/src/modules/module-ffado-driver.c
Added
@@ -0,0 +1,1148 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <limits.h> +#include <math.h> + +#include "config.h" + +#include <spa/utils/result.h> +#include <spa/utils/string.h> +#include <spa/utils/json.h> +#include <spa/debug/types.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format-utils.h> +#include <spa/param/latency-utils.h> +#include <spa/param/audio/raw.h> + +#include <pipewire/impl.h> +#include <pipewire/i18n.h> +#include <pipewire/private.h> +#include <pipewire/thread.h> + +#include <libffado/ffado.h> + +/** \page page_module_ffado_driver PipeWire Module: FFADO firewire audio driver + * + * The ffado-driver module provides a source or sink using the libffado library for + * reading and writing to firewire audio devices. + * + * ## Module Options + * + * - `driver.mode`: the driver mode, sink|source|duplex, default duplex + * - `ffado.devices`: array of devices to open, default hw:0 + * - `ffado.period-size`: period size,default 1024 + * - `ffado.period-num`: period number,default 3 + * - `ffado.sample-rate`: sample-rate, default 48000 + * - `ffado.slave-mode`: slave mode + * - `ffado.snoop-mode`: snoop mode + * - `ffado.verbose`: ffado verbose level + * - `latency.internal.input`: extra input latency in frames + * - `latency.internal.output`: extra output latency in frames + * - `source.props`: Extra properties for the source filter. + * - `sink.props`: Extra properties for the sink filter. + * + * ## General options + * + * Options with well-known behavior. + * + * - \ref PW_KEY_REMOTE_NAME + * - \ref SPA_KEY_AUDIO_POSITION + * - \ref PW_KEY_NODE_NAME + * - \ref PW_KEY_NODE_DESCRIPTION + * - \ref PW_KEY_NODE_GROUP + * - \ref PW_KEY_NODE_VIRTUAL + * - \ref PW_KEY_MEDIA_CLASS + * - \ref PW_KEY_TARGET_OBJECT to specify the remote node.name or serial.id to link to + * + * ## Example configuration of a duplex sink/source + * + *\code{.unparsed} + * context.modules = + * { name = libpipewire-module-ffado-driver + * args = { + * #driver.mode = duplex + * #ffado.devices = hw:0 + * #ffado.period-size = 1024 + * #ffado.period-num = 3 + * #ffado.sample-rate = 48000 + * #ffado.slave-mode = false + * #ffado.snoop-mode = false + * #ffado.verbose = 0 + * #latency.internal.input = 0 + * #latency.internal.output = 0 + * #audio.position = FL FR + * source.props = { + * # extra sink properties + * } + * sink.props = { + * # extra sink properties + * } + * } + * } + * + *\endcode + */ + +#define NAME "ffado-driver" + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +#define MAX_PORTS 128 + +#define DEFAULT_DEVICES " hw:0 " +#define DEFAULT_PERIOD_SIZE 1024 +#define DEFAULT_PERIOD_NUM 3 +#define DEFAULT_SAMPLE_RATE 48000 +#define DEFAULT_SLAVE_MODE false +#define DEFAULT_SNOOP_MODE false +#define DEFAULT_VERBOSE 0 + +#define DEFAULT_POSITION " FL FR " +#define DEFAULT_MIDI_PORTS 1 + +#define MODULE_USAGE "( remote.name=<remote> ) " \ + "( driver.mode=<sink|source|duplex> ) " \ + "( ffado.devices=<devices array size, default hw:0> ) " \ + "( ffado.period-size=<period size, default 1024> ) " \ + "( ffado.period-num=<period num, default 3> ) " \ + "( ffado.sample-rate=<sampe rate, default 48000> ) " \ + "( ffado.slave-mode=<slave mode, default false> ) " \ + "( ffado.snoop-mode=<snoop mode, default false> ) " \ + "( ffado.verbose=<verbose level, default 0> ) " \ + "( audio.position=<channel map> ) " \ + "( source.props=<properties> ) " \ + "( sink.props=<properties> ) " + + +static const struct spa_dict_item module_props = { + { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, + { PW_KEY_MODULE_DESCRIPTION, "Create an FFADO based driver" }, + { PW_KEY_MODULE_USAGE, MODULE_USAGE }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; + +struct port { + enum spa_direction direction; + struct spa_latency_info latency2; + bool latency_changed2; + unsigned int is_midi:1; + void *buffer; +}; + +struct volume { + bool mute; + uint32_t n_volumes; + float volumesSPA_AUDIO_MAX_CHANNELS; +}; + +struct stream { + struct impl *impl; + + enum spa_direction direction; + struct pw_properties *props; + struct pw_filter *filter; + struct spa_hook listener; + struct spa_audio_info_raw info; + uint32_t n_ports; + struct port *portsMAX_PORTS; + struct volume volume; + + unsigned int running:1; +}; + +struct impl { + struct pw_context *context; + struct pw_loop *main_loop; + struct spa_system *system; + struct spa_thread_utils *utils; + + ffado_device_info_t device_info; + ffado_options_t device_options; + ffado_device_t *dev; + +#define MODE_SINK (1<<0) +#define MODE_SOURCE (1<<1) +#define MODE_DUPLEX (MODE_SINK|MODE_SOURCE) + uint32_t mode; + struct pw_properties *props; + + struct pw_impl_module *module; + + struct spa_hook module_listener; + + struct pw_core *core; + struct spa_hook core_proxy_listener; + struct spa_hook core_listener; + + struct spa_io_position *position; + + uint32_t latency2; + + struct stream source; + struct stream sink; + + char *devicesFFADO_MAX_SPECSTRINGS; + uint32_t n_devices; + int32_t sample_rate; + int32_t period_size;
View file
pipewire-0.3.71.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.72.tar.gz/src/modules/module-filter-chain.c
Changed
@@ -166,6 +166,9 @@ * are read-only except for the bq_raw biquad, which can configure default values * depending on the graph rate and change those at runtime. * + * We refer to https://arachnoid.com/BiQuadDesigner/index.html for an explanation of + * the controls. + * * The following labels can be used: * * - `bq_lowpass` a lowpass filter. @@ -685,7 +688,16 @@ struct graph_port *port; struct spa_data *bd; - if ((in = pw_stream_dequeue_buffer(impl->capture)) == NULL) + in = NULL; + while (true) { + struct pw_buffer *t; + if ((t = pw_stream_dequeue_buffer(impl->capture)) == NULL) + break; + if (in) + pw_stream_queue_buffer(impl->capture, in); + in = t; + } + if (in == NULL) pw_log_debug("%p: out of capture buffers: %m", impl); if ((out = pw_stream_dequeue_buffer(impl->playback)) == NULL) @@ -2454,7 +2466,12 @@ parse_audio_info(impl->capture_props, &impl->capture_info); parse_audio_info(impl->playback_props, &impl->playback_info); - if (impl->capture_info.rate && !impl->playback_info.rate) + if (!impl->capture_info.rate && !impl->playback_info.rate) { + if (pw_properties_get(impl->playback_props, "resample.disable") == NULL) + pw_properties_set(impl->playback_props, "resample.disable", "true"); + if (pw_properties_get(impl->capture_props, "resample.disable") == NULL) + pw_properties_set(impl->capture_props, "resample.disable", "true"); + } else if (impl->capture_info.rate && !impl->playback_info.rate) impl->playback_info.rate = impl->capture_info.rate; else if (impl->playback_info.rate && !impl->capture_info.rate) impl->capture_info.rate = !impl->playback_info.rate;
View file
pipewire-0.3.71.tar.gz/src/modules/module-jack-tunnel.c -> pipewire-0.3.72.tar.gz/src/modules/module-jack-tunnel.c
Changed
@@ -193,6 +193,7 @@ uint32_t jack_xrun; unsigned int do_disconnect:1; + unsigned int triggered:1; unsigned int done:1; unsigned int new_xrun:1; unsigned int fix_midi:1; @@ -323,6 +324,11 @@ struct impl *impl = s->impl; uint32_t i, n_samples = position->clock.duration; + if (impl->mode & MODE_SINK && impl->triggered) { + impl->triggered = false; + return; + } + for (i = 0; i < s->n_ports; i++) { struct port *p = s->portsi; float *src, *dst; @@ -342,7 +348,7 @@ else do_volume(dst, src, &s->volume, i, n_samples); } - pw_log_trace_fp("done %u", impl->frame_time); + pw_log_trace_fp("done %u %u", impl->frame_time, n_samples); if (impl->mode & MODE_SINK) { impl->done = true; jack.cycle_signal(impl->client, 0); @@ -355,6 +361,14 @@ struct impl *impl = s->impl; uint32_t i, n_samples = position->clock.duration; + if (impl->mode == MODE_SOURCE && !impl->triggered) { + pw_log_trace_fp("done %u", impl->frame_time); + impl->done = true; + jack.cycle_signal(impl->client, 0); + return; + } + impl->triggered = false; + for (i = 0; i < s->n_ports; i++) { struct port *p = s->portsi; float *src, *dst; @@ -373,11 +387,6 @@ else do_volume(dst, src, &s->volume, i, n_samples); } - pw_log_trace_fp("done %u", impl->frame_time); - if (impl->mode == MODE_SOURCE) { - impl->done = true; - jack.cycle_signal(impl->client, 0); - } } static void stream_io_changed(void *data, void *port_data, uint32_t id, void *area, uint32_t size) @@ -606,9 +615,7 @@ const struct spa_pod *params4; uint8_t buffer1024; struct spa_pod_builder b; - struct spa_latency_info latency; - spa_zero(latency); n_params = 0; spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -703,11 +710,14 @@ } if (impl->mode & MODE_SINK && sink_running) { impl->done = false; + impl->triggered = true; pw_filter_trigger_process(impl->sink.filter); } else if (impl->mode == MODE_SOURCE && source_running) { impl->done = false; + impl->triggered = true; pw_filter_trigger_process(impl->source.filter); } else { + pw_log_trace_fp("done %d", nframes); jack.cycle_signal(impl->client, 0); } } @@ -801,9 +811,9 @@ jack.port_get_latency_range(port->jack_port, mode, &range); - latency.direction = s->direction; - latency.min_rate = range.min; - latency.max_rate = range.max; + latency = SPA_LATENCY_INFO(s->direction, + .min_rate = range.min, + .max_rate = range.max); pw_log_debug("port latency %d %d %d", mode, range.min, range.max); if (spa_latency_info_compare(&latency, &port->latencys->direction)) {
View file
pipewire-0.3.71.tar.gz/src/modules/module-jackdbus-detect.c -> pipewire-0.3.72.tar.gz/src/modules/module-jackdbus-detect.c
Changed
@@ -38,7 +38,7 @@ * ## Example configuration *\code{.unparsed} * context.modules = - * { name = libpipewire-jackdbus-detect + * { name = libpipewire-module-jackdbus-detect * args { * #jack.server = null * #tunnel.mode = duplex
View file
pipewire-0.3.71.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.72.tar.gz/src/modules/module-loopback.c
Changed
@@ -180,6 +180,7 @@ unsigned int do_disconnect:1; unsigned int recalc_delay:1; + struct spa_audio_info_raw delay_info; float target_delay; struct spa_ringbuffer buffer; uint8_t *buffer_data; @@ -195,7 +196,7 @@ static void recalculate_delay(struct impl *impl) { - uint32_t target = impl->capture_info.rate * impl->target_delay, cdelay, pdelay; + uint32_t target = impl->delay_info.rate * impl->target_delay, cdelay, pdelay; uint32_t delay, w; struct pw_time pwt; @@ -232,11 +233,20 @@ impl->recalc_delay = false; } - if ((in = pw_stream_dequeue_buffer(impl->capture)) == NULL) - pw_log_debug("out of capture buffers: %m"); + in = NULL; + while (true) { + struct pw_buffer *t; + if ((t = pw_stream_dequeue_buffer(impl->capture)) == NULL) + break; + if (in) + pw_stream_queue_buffer(impl->capture, in); + in = t; + } + if (in == NULL) + pw_log_debug("%p: out of capture buffers: %m", impl); if ((out = pw_stream_dequeue_buffer(impl->playback)) == NULL) - pw_log_debug("out of playback buffers: %m"); + pw_log_debug("%p: out of playback buffers: %m", impl); if (in != NULL && out != NULL) { uint32_t outsize = UINT32_MAX; @@ -347,11 +357,11 @@ static void recalculate_buffer(struct impl *impl) { if (impl->target_delay > 0.0f) { - uint32_t delay = impl->capture_info.rate * impl->target_delay; + uint32_t delay = impl->delay_info.rate * impl->target_delay; void *data; impl->buffer_size = (delay + (1u<<15)) * 4; - data = realloc(impl->buffer_data, impl->buffer_size * impl->capture_info.channels); + data = realloc(impl->buffer_data, impl->buffer_size * impl->delay_info.channels); if (data == NULL) { pw_log_warn("can't allocate delay buffer, delay disabled: %m"); impl->buffer_size = 0; @@ -385,7 +395,7 @@ info.channels > SPA_AUDIO_MAX_CHANNELS) return; - impl->capture_info = info; + impl->delay_info = info; recalculate_buffer(impl); break; } @@ -696,6 +706,23 @@ parse_audio_info(impl->capture_props, &impl->capture_info); parse_audio_info(impl->playback_props, &impl->playback_info); + if (!impl->capture_info.rate && !impl->playback_info.rate) { + if (pw_properties_get(impl->playback_props, "resample.disable") == NULL) + pw_properties_set(impl->playback_props, "resample.disable", "true"); + if (pw_properties_get(impl->capture_props, "resample.disable") == NULL) + pw_properties_set(impl->capture_props, "resample.disable", "true"); + } else if (impl->capture_info.rate && !impl->playback_info.rate) + impl->playback_info.rate = impl->capture_info.rate; + else if (impl->playback_info.rate && !impl->capture_info.rate) + impl->capture_info.rate = !impl->playback_info.rate; + else if (impl->capture_info.rate != impl->playback_info.rate) { + pw_log_warn("Both capture and playback rate are set, but" + " they are different. Using the highest of two. This behaviour" + " is deprecated, please use equal rates in the module config"); + impl->playback_info.rate = impl->capture_info.rate = + SPA_MAX(impl->playback_info.rate, impl->capture_info.rate); + } + if (pw_properties_get(impl->capture_props, PW_KEY_MEDIA_NAME) == NULL) pw_properties_setf(impl->capture_props, PW_KEY_MEDIA_NAME, "%s input", pw_properties_get(impl->capture_props, PW_KEY_NODE_DESCRIPTION));
View file
pipewire-0.3.72.tar.gz/src/modules/module-netjack2
Added
+(directory)
View file
pipewire-0.3.72.tar.gz/src/modules/module-netjack2-driver.c
Added
@@ -0,0 +1,1374 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <limits.h> +#include <arpa/inet.h> +#include <netinet/ip.h> +#include <netinet/in.h> +#include <net/if.h> +#include <math.h> + +#include "config.h" + +#include <spa/utils/result.h> +#include <spa/utils/string.h> +#include <spa/utils/json.h> +#include <spa/debug/types.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format-utils.h> +#include <spa/param/latency-utils.h> +#include <spa/param/audio/raw.h> + +#include <pipewire/impl.h> +#include <pipewire/i18n.h> +#include <pipewire/private.h> + +#include "module-netjack2/packets.h" +#include "module-netjack2/peer.c" + +#ifndef IPTOS_DSCP +#define IPTOS_DSCP_MASK 0xfc +#define IPTOS_DSCP(x) ((x) & IPTOS_DSCP_MASK) +#endif + +/** \page page_module_netjack2_driver PipeWire Module: Netjack2 driver + * + * The netjack2-driver module provides a source or sink that is following a + * netjack2 driver. + * + * ## Module Options + * + * - `driver.mode`: the driver mode, sink|source|duplex, default duplex + * - `local.ifname = <str>`: interface name to use + * - `net.ip =<str>`: multicast IP address, default "225.3.19.154" + * - `net.port =<int>`: control port, default "19000" + * - `net.mtu = <int>`: MTU to use, default 1500 + * - `net.ttl = <int>`: TTL to use, default 1 + * - `net.loop = <bool>`: loopback multicast, default false + * - `netjack2.client-name`: the name of the NETJACK2 client. + * - `netjack2.save`: if jack port connections should be save automatically. Can also be + * placed per stream. + * - `netjack2.latency`: the latency in cycles, default 2 + * - `audio.channels`: the number of audio ports. Can also be added to the stream props. + * - `midi.ports`: the number of midi ports. Can also be added to the stream props. + * - `source.props`: Extra properties for the source filter. + * - `sink.props`: Extra properties for the sink filter. + * + * ## General options + * + * Options with well-known behavior. + * + * - \ref PW_KEY_REMOTE_NAME + * - \ref PW_KEY_AUDIO_CHANNELS + * - \ref SPA_KEY_AUDIO_POSITION + * - \ref PW_KEY_NODE_NAME + * - \ref PW_KEY_NODE_DESCRIPTION + * - \ref PW_KEY_NODE_GROUP + * - \ref PW_KEY_NODE_VIRTUAL + * - \ref PW_KEY_MEDIA_CLASS + * - \ref PW_KEY_TARGET_OBJECT to specify the remote node.name or serial.id to link to + * + * ## Example configuration of a duplex sink/source + * + *\code{.unparsed} + * context.modules = + * { name = libpipewire-module-netjack2-driver + * args = { + * #driver.mode = duplex + * #netjack2.client-name = PipeWire + * #netjack2.save = false + * #netjack2.latency = 2 + * #midi.ports = 0 + * #audio.channels = 2 + * #audio.position = FL FR + * source.props = { + * # extra sink properties + * } + * sink.props = { + * # extra sink properties + * } + * } + * } + * + *\endcode + */ + +#define NAME "netjack2-driver" + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +#define MAX_PORTS 128 + +#define DEFAULT_NET_IP "225.3.19.154" +#define DEFAULT_NET_PORT 19000 +#define DEFAULT_NET_TTL 1 +#define DEFAULT_NET_MTU 1500 +#define DEFAULT_NET_LOOP false +#define DEFAULT_NET_DSCP 34 /* Default to AES-67 AF41 (34) */ +#define MAX_MTU 9000 + +#define DEFAULT_NETWORK_LATENCY 2 +#define NETWORK_MAX_LATENCY 30 + +#define DEFAULT_CLIENT_NAME "PipeWire" +#define DEFAULT_CHANNELS 2 +#define DEFAULT_POSITION " FL FR " +#define DEFAULT_MIDI_PORTS 1 + +#define FOLLOWER_INIT_TIMEOUT 1 +#define FOLLOWER_INIT_RETRY -1 + +#define MODULE_USAGE "( remote.name=<remote> ) " \ + "( driver.mode=<sink|source|duplex> ) " \ + "( local.ifname=<interface name> ) " \ + "( net.ip=<ip address to use, default 225.3.19.154> ) " \ + "( net.port=<port to use, default 19000> ) " \ + "( net.mtu=<MTU to use, default 1500> ) " \ + "( net.ttl=<TTL to use, default 1> ) " \ + "( net.loop=<loopback, default false> ) " \ + "( netjack2.client-name=<name of the NETJACK2 client> ) " \ + "( netjack2.save=<bool, save ports> ) " \ + "( netjack2.latency=<latency in cycles, default 2> ) " \ + "( midi.ports=<number of midi ports> ) " \ + "( audio.channels=<number of channels> ) " \ + "( audio.position=<channel map> ) " \ + "( source.props=<properties> ) " \ + "( sink.props=<properties> ) " + + +static const struct spa_dict_item module_props = { + { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, + { PW_KEY_MODULE_DESCRIPTION, "Create a netjack2 driver" }, + { PW_KEY_MODULE_USAGE, MODULE_USAGE }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; + +struct port { + enum spa_direction direction; + struct spa_latency_info latency2; + bool latency_changed2; + unsigned int is_midi:1; +}; + +struct stream { + struct impl *impl; + + enum spa_direction direction; + struct pw_properties *props; + struct pw_filter *filter; + struct spa_hook listener; + + struct spa_audio_info_raw info; + + uint32_t n_midi; + uint32_t n_ports; + struct port *portsMAX_PORTS; + + struct volume volume; + + uint32_t active_audio_ports; + uint32_t active_midi_ports; + + unsigned int running:1; +}; + +struct impl { + struct pw_context *context; + struct pw_loop *main_loop; + struct pw_data_loop *data_loop; + struct spa_system *system; + +#define MODE_SINK (1<<0) +#define MODE_SOURCE (1<<1) +#define MODE_DUPLEX (MODE_SINK|MODE_SOURCE) + uint32_t mode; + struct pw_properties *props; + + bool loop; + int ttl;
View file
pipewire-0.3.72.tar.gz/src/modules/module-netjack2-manager.c
Added
@@ -0,0 +1,1418 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <limits.h> +#include <arpa/inet.h> +#include <netinet/ip.h> +#include <netinet/in.h> +#include <net/if.h> +#include <math.h> + +#include "config.h" + +#include <spa/utils/result.h> +#include <spa/utils/string.h> +#include <spa/utils/json.h> +#include <spa/debug/types.h> +#include <spa/pod/builder.h> +#include <spa/param/audio/format-utils.h> +#include <spa/param/latency-utils.h> +#include <spa/param/audio/raw.h> + +#include <pipewire/impl.h> +#include <pipewire/i18n.h> +#include <pipewire/private.h> + +#include "module-netjack2/packets.h" + +#include "module-netjack2/peer.c" + +#ifndef IPTOS_DSCP +#define IPTOS_DSCP_MASK 0xfc +#define IPTOS_DSCP(x) ((x) & IPTOS_DSCP_MASK) +#endif + +/** \page page_module_netjack2_manager PipeWire Module: Netjack2 manager + * + * The netjack2 manager module listens for new netjack2 driver messages and will + * start a communication channel with them. + * + * ## Module Options + * + * - `local.ifname = <str>`: interface name to use + * - `net.ip =<str>`: multicast IP address, default "225.3.19.154" + * - `net.port =<int>`: control port, default "19000" + * - `net.mtu = <int>`: MTU to use, default 1500 + * - `net.ttl = <int>`: TTL to use, default 1 + * - `net.loop = <bool>`: loopback multicast, default false + * - `netjack2.connect`: if jack ports should be connected automatically. Can also be + * placed per stream. + * - `netjack2.sample-rate`: the sample rate to use, default 48000 + * - `netjack2.period-size`: the buffer size to use, default 1024 + * - `netjack2.encoding`: the encoding, float|opus|int, default float + * - `netjack2.kbps`: the number of kilobits per second when encoding, default 64 + * - `audio.channels`: the number of audio ports. Can also be added to the stream props. + * - `midi.ports`: the number of midi ports. Can also be added to the stream props. + * - `source.props`: Extra properties for the source filter. + * - `sink.props`: Extra properties for the sink filter. + * + * ## General options + * + * Options with well-known behavior. + * + * - \ref PW_KEY_REMOTE_NAME + * - \ref PW_KEY_AUDIO_CHANNELS + * - \ref SPA_KEY_AUDIO_POSITION + * - \ref PW_KEY_NODE_NAME + * - \ref PW_KEY_NODE_DESCRIPTION + * - \ref PW_KEY_NODE_GROUP + * - \ref PW_KEY_NODE_VIRTUAL + * - \ref PW_KEY_MEDIA_CLASS + * - \ref PW_KEY_TARGET_OBJECT to specify the remote node.name or serial.id to link to + * + * ## Example configuration of a duplex sink/source + * + *\code{.unparsed} + * context.modules = + * { name = libpipewire-module-netjack2-manager + * args = { + * #netjack2.connect = true + * #netjack2.sample-rate = 48000 + * #netjack2.period-size = 1024 + * #netjack2.encoding = float # float|opus + * #netjack2.kbps = 64 + * #midi.ports = 0 + * #audio.channels = 2 + * #audio.position = FL FR + * source.props = { + * # extra sink properties + * } + * sink.props = { + * # extra sink properties + * } + * } + * } + * + *\endcode + */ + +#define NAME "netjack2-manager" + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +#define MAX_PORTS 128 + +#define DEFAULT_NET_IP "225.3.19.154" +#define DEFAULT_NET_PORT 19000 +#define DEFAULT_NET_TTL 1 +#define DEFAULT_NET_MTU 1500 +#define DEFAULT_NET_LOOP false +#define DEFAULT_NET_DSCP 34 /* Default to AES-67 AF41 (34) */ +#define MAX_MTU 9000 + + +#define NETWORK_MAX_LATENCY 30 + +#define DEFAULT_SAMPLE_RATE 48000 +#define DEFAULT_PERIOD_SIZE 1024 +#define DEFAULT_ENCODING "float" +#define DEFAULT_KBPS 64 +#define DEFAULT_CHANNELS 2 +#define DEFAULT_POSITION " FL FR " +#define DEFAULT_MIDI_PORTS 1 + +#define MODULE_USAGE "( remote.name=<remote> ) " \ + "( local.ifname=<interface name> ) " \ + "( net.ip=<ip address to use, default 225.3.19.154> ) " \ + "( net.port=<port to use, default 19000> ) " \ + "( net.mtu=<MTU to use, default 1500> ) " \ + "( net.ttl=<TTL to use, default 1> ) " \ + "( net.loop=<loopback, default false> ) " \ + "( netjack2.connect=<bool, autoconnect ports> ) " \ + "( netjack2.sample-rate=<sampl erate, default 48000> ) "\ + "( netjack2.period-size=<period size, default 1024> ) " \ + "( midi.ports=<number of midi ports> ) " \ + "( audio.channels=<number of channels> ) " \ + "( audio.position=<channel map> ) " \ + "( source.props=<properties> ) " \ + "( sink.props=<properties> ) " + + +static const struct spa_dict_item module_props = { + { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, + { PW_KEY_MODULE_DESCRIPTION, "Create a netjack2 manager" }, + { PW_KEY_MODULE_USAGE, MODULE_USAGE }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; + +static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info); + +struct port { + enum spa_direction direction; + struct spa_latency_info latency2; + bool latency_changed2; + unsigned int is_midi:1; +}; + +struct stream { + struct impl *impl; + struct follower *follower; + + enum spa_direction direction; + struct pw_properties *props; + struct pw_filter *filter; + struct spa_hook listener; + + struct spa_audio_info_raw info; + + uint32_t n_midi; + uint32_t n_ports; + struct port *portsMAX_PORTS; + + struct volume volume; + + uint32_t active_audio_ports; + uint32_t active_midi_ports; + + unsigned int running:1; + unsigned int ready:1; +}; + +struct follower { + struct spa_list link; + struct impl *impl; + + struct spa_io_position *position; + + struct stream source;
View file
pipewire-0.3.72.tar.gz/src/modules/module-netjack2/packets.h
Added
@@ -0,0 +1,194 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans <wim.taymans@gmail.com> */ +/* SPDX-License-Identifier: MIT */ + +#ifndef PIPEWIRE_NETJACK2_H +#define PIPEWIRE_NETJACK2_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define JACK_CLIENT_NAME_SIZE 64 +#define JACK_SERVER_NAME_SIZE 256 + +struct nj2_session_params { + char type8; /* packet type ('param') */ +#define NJ2_NETWORK_PROTOCOL 8 + uint32_t version; /* version */ +#define NJ2_ID_FOLLOWER_AVAILABLE 0 /* a follower is available */ +#define NJ2_ID_FOLLOWER_SETUP 1 /* follower configuration */ +#define NJ2_ID_START_DRIVER 2 /* follower is ready, start driver */ +#define NJ2_ID_START_FOLLOWER 3 /* driver is ready, activate follower */ +#define NJ2_ID_STOP_DRIVER 4 /* driver must stop */ + int32_t packet_id; /* indicates the packet type */ + char nameJACK_CLIENT_NAME_SIZE; /* follower's name */ + char driver_nameJACK_SERVER_NAME_SIZE; /* driver hostname (network) */ + char follower_nameJACK_SERVER_NAME_SIZE; /* follower hostname (network) */ + uint32_t mtu; /* connection mtu */ + uint32_t id; /* follower's ID */ + uint32_t transport_sync; /* is the transport synced ? */ + int32_t send_audio_channels; /* number of driver->follower channels */ + int32_t recv_audio_channels; /* number of follower->driver channels */ + int32_t send_midi_channels; /* number of driver->follower midi channels */ + int32_t recv_midi_channels; /* number of follower->driver midi channels */ + uint32_t sample_rate; /* session sample rate */ + uint32_t period_size; /* period size */ +#define NJ2_ENCODER_FLOAT 0 +#define NJ2_ENCODER_INT 1 +#define NJ2_ENCODER_CELT 2 +#define NJ2_ENCODER_OPUS 3 + uint32_t sample_encoder; /* samples encoder */ + uint32_t kbps; /* KB per second for CELT encoder */ + uint32_t follower_sync_mode; /* is the follower in sync mode ? */ + uint32_t network_latency; /* network latency */ +} __attribute__ ((packed)); + +static inline void nj2_dump_session_params(struct nj2_session_params *params) +{ + pw_log_info("Type: '%s'", params->type); + pw_log_info("Version: %u", ntohl(params->version)); + pw_log_info("packet ID: %d", ntohl(params->packet_id)); + pw_log_info("Name: '%s'", params->name); + pw_log_info("Driver Name: '%s'", params->driver_name); + pw_log_info("Follower Name: '%s'", params->follower_name); + pw_log_info("MTU: %u", ntohl(params->mtu)); + pw_log_info("ID: %u", ntohl(params->id)); + pw_log_info("TransportSync: %u", ntohl(params->transport_sync)); + pw_log_info("Audio Send: %d", ntohl(params->send_audio_channels)); + pw_log_info("Audio Recv: %d", ntohl(params->recv_audio_channels)); + pw_log_info("MIDI Send: %d", ntohl(params->send_midi_channels)); + pw_log_info("MIDI Recv: %d", ntohl(params->recv_midi_channels)); + pw_log_info("Sample Rate: %u", ntohl(params->sample_rate)); + pw_log_info("Period Size: %u", ntohl(params->period_size)); + pw_log_info("Encoder: %u", ntohl(params->sample_encoder)); + pw_log_info("KBps: %u", ntohl(params->kbps)); + pw_log_info("Follower Sync: %u", ntohl(params->follower_sync_mode)); + pw_log_info("Latency: %u", ntohl(params->network_latency)); +} + +static inline void nj2_session_params_ntoh(struct nj2_session_params *host, + const struct nj2_session_params *net) +{ + memcpy(host, net, sizeof(*host)); + host->version = ntohl(net->version); + host->packet_id = ntohl(net->packet_id); + host->mtu = ntohl(net->mtu); + host->id = ntohl(net->id); + host->transport_sync = ntohl(net->transport_sync); + host->send_audio_channels = ntohl(net->send_audio_channels); + host->recv_audio_channels = ntohl(net->recv_audio_channels); + host->send_midi_channels = ntohl(net->send_midi_channels); + host->recv_midi_channels = ntohl(net->recv_midi_channels); + host->sample_rate = ntohl(net->sample_rate); + host->period_size = ntohl(net->period_size); + host->sample_encoder = ntohl(net->sample_encoder); + host->kbps = ntohl(net->kbps); + host->follower_sync_mode = ntohl(net->follower_sync_mode); + host->network_latency = ntohl(net->network_latency); +} + +static inline void nj2_session_params_hton(struct nj2_session_params *net, + const struct nj2_session_params *host) +{ + memcpy(net, host, sizeof(*net)); + net->version = htonl(host->version); + net->packet_id = htonl(host->packet_id); + net->mtu = htonl(host->mtu); + net->id = htonl(host->id); + net->transport_sync = htonl(host->transport_sync); + net->send_audio_channels = htonl(host->send_audio_channels); + net->recv_audio_channels = htonl(host->recv_audio_channels); + net->send_midi_channels = htonl(host->send_midi_channels); + net->recv_midi_channels = htonl(host->recv_midi_channels); + net->sample_rate = htonl(host->sample_rate); + net->period_size = htonl(host->period_size); + net->sample_encoder = htonl(host->sample_encoder); + net->kbps = htonl(host->kbps); + net->follower_sync_mode = htonl(host->follower_sync_mode); + net->network_latency = htonl(host->network_latency); +} + +struct nj2_packet_header { + char type8; /* packet type ('headr') */ + uint32_t data_type; /* 'a' for audio, 'm' for midi and 's' for sync */ + uint32_t data_stream; /* 's' for send, 'r' for return */ + uint32_t id; /* unique ID of the follower */ + uint32_t num_packets; /* number of data packets of the cycle */ + uint32_t packet_size; /* packet size in bytes */ + uint32_t active_ports; /* number of active ports */ + uint32_t cycle; /* process cycle counter */ + uint32_t sub_cycle; /* midi/audio subcycle counter */ + int32_t frames; /* process cycle size in frames (can be -1 to indicate entire buffer) */ + uint32_t is_last; /* is it the last packet of a given cycle ('y' or 'n') */ +} __attribute__ ((packed)); + +#define UDP_HEADER_SIZE 64 /* 40 bytes for IP header in IPV6, 20 in IPV4, 8 for UDP, so take 64 */ + +#define PACKET_AVAILABLE_SIZE(mtu) (mtu - UDP_HEADER_SIZE - sizeof(struct nj2_packet_header)) + +static inline void nj2_dump_packet_header(struct nj2_packet_header *header) +{ + pw_log_info("Type: %s", header->type); + pw_log_info("Data Type: %c", ntohl(header->data_type)); + pw_log_info("Data Stream: %c", ntohl(header->data_stream)); + pw_log_info("ID: %u", ntohl(header->id)); + pw_log_info("Num Packets: %u", ntohl(header->num_packets)); + pw_log_info("Packet Size: %u", ntohl(header->packet_size)); + pw_log_info("Active Ports: %u", ntohl(header->active_ports)); + pw_log_info("Cycle: %u", ntohl(header->cycle)); + pw_log_info("Sub Cycle: %u", ntohl(header->sub_cycle)); + pw_log_info("Frames %d", ntohl(header->frames)); + pw_log_info("Is Last: %u", ntohl(header->is_last)); +} + +#define MIDI_INLINE_MAX 4 + +struct nj2_midi_event { + uint32_t time; /**< Sample index at which event is valid */ + uint32_t size; /**< Number of bytes of data in the event */ + union { + uint32_t offset; /**< offset in buffer */ + uint8_t bufferMIDI_INLINE_MAX; /**< Raw inline data */ + }; +}; + +struct nj2_midi_buffer { +#define MIDI_BUFFER_MAGIC 0x900df00d + uint32_t magic; + uint32_t buffer_size; + uint32_t nframes; + uint32_t write_pos; + uint32_t event_count; + uint32_t lost_events; + + struct nj2_midi_event event1; +}; + +static inline void nj2_midi_buffer_hton(struct nj2_midi_buffer *net, + const struct nj2_midi_buffer *host) +{ + net->magic = htonl(host->magic); + net->buffer_size = htonl(host->buffer_size); + net->nframes = htonl(host->nframes); + net->write_pos = htonl(host->write_pos); + net->event_count = htonl(host->event_count); + net->lost_events = htonl(host->lost_events); +} + +static inline void nj2_midi_buffer_ntoh(struct nj2_midi_buffer *host, + const struct nj2_midi_buffer *net) +{ + host->magic = ntohl(net->magic); + host->buffer_size = ntohl(net->buffer_size); + host->nframes = ntohl(net->nframes); + host->write_pos = ntohl(net->write_pos); + host->event_count = ntohl(net->event_count); + host->lost_events = ntohl(net->lost_events); +} + +#ifdef __cplusplus +} +#endif + +#endif /* PIPEWIRE_NETJACK2_H */
View file
pipewire-0.3.72.tar.gz/src/modules/module-netjack2/peer.c
Added
@@ -0,0 +1,1031 @@ + +#include <byteswap.h> + +#ifdef HAVE_OPUS_CUSTOM +#include <opus/opus.h> +#include <opus/opus_custom.h> +#endif + +#define MAX_BUFFER_FRAMES 8192 + +struct volume { + bool mute; + uint32_t n_volumes; + float volumesSPA_AUDIO_MAX_CHANNELS; +}; + +static inline float bswap_f32(float f) +{ + union { + float f; + uint32_t u; + } v; + v.f = f; + v.u = bswap_32(v.u); + return v.f; +} + +static inline void do_volume(float *dst, const float *src, struct volume *vol, + uint32_t ch, uint32_t n_samples, bool recv) +{ + float v = vol->mute ? 0.0f : vol->volumesch; + uint32_t i; + + if (v == 0.0f || src == NULL) + memset(dst, 0, n_samples * sizeof(float)); + else if (v == 1.0f) { +#if __BYTE_ORDER == __BIG_ENDIAN + for (i = 0; i < n_samples; i++) + dsti = bswap_f32(srci); +#else + memcpy(dst, src, n_samples * sizeof(float)); +#endif + + } else { +#if __BYTE_ORDER == __BIG_ENDIAN + if (recv) { + for (i = 0; i < n_samples; i++) + dsti = bswap_f32(srci) * v; + } else { + for (i = 0; i < n_samples; i++) + dsti = bswap_f32(srci * v); + } +#else + for (i = 0; i < n_samples; i++) + dsti = srci * v; +#endif + } +} + +#define ITOF(type,v,scale) \ + (((type)(v)) * (1.0f / (scale))) +#define FTOI(type,v,scale,min,max) \ + (type)(SPA_CLAMPF((v) * (scale), min, max)) + +#define S16_MIN -32768 +#define S16_MAX 32767 +#define S16_SCALE 32768.0f +#define S16_TO_F32(v) ITOF(int16_t, v, S16_SCALE) +#define F32_TO_S16(v) FTOI(int16_t, v, S16_SCALE, S16_MIN, S16_MAX) + +static inline void do_volume_to_s16(int16_t *dst, const float *src, struct volume *vol, + uint32_t ch, uint32_t n_samples) +{ + float v = vol->mute ? 0.0f : vol->volumesch; + uint32_t i; + + if (v == 0.0f || src == NULL) + memset(dst, 0, n_samples * sizeof(int16_t)); + else if (v == 1.0f) { + for (i = 0; i < n_samples; i++) + dsti = F32_TO_S16(srci); + } else { + for (i = 0; i < n_samples; i++) + dsti = F32_TO_S16(srci * v); + } +} + +static inline void do_volume_from_s16(float *dst, const int16_t *src, struct volume *vol, + uint32_t ch, uint32_t n_samples) +{ + float v = vol->mute ? 0.0f : vol->volumesch; + uint32_t i; + + if (v == 0.0f || src == NULL) + memset(dst, 0, n_samples * sizeof(float)); + else if (v == 1.0f) { + for (i = 0; i < n_samples; i++) + dsti = S16_TO_F32(srci); + } else { + for (i = 0; i < n_samples; i++) + dsti = S16_TO_F32(srci) * v; + } +} + +struct netjack2_peer { + int fd; + + uint32_t our_stream; + uint32_t other_stream; + struct nj2_session_params params; + struct nj2_packet_header sync; + uint32_t cycle; + + struct volume *send_volume; + struct volume *recv_volume; + + void *midi_data; + uint32_t midi_size; + + float *empty; + void *encoded_data; + uint32_t encoded_size; + uint32_t max_encoded_size; +#ifdef HAVE_OPUS_CUSTOM + OpusCustomMode *opus_config; + OpusCustomEncoder **opus_enc; + OpusCustomDecoder **opus_dec; +#endif + + unsigned fix_midi:1; +}; + +static int netjack2_init(struct netjack2_peer *peer) +{ + int res = 0; + + peer->empty = calloc(MAX_BUFFER_FRAMES, sizeof(float)); + + peer->midi_size = peer->params.period_size * sizeof(float) * + SPA_MAX(peer->params.send_midi_channels, peer->params.recv_midi_channels); + peer->midi_data = calloc(1, peer->midi_size); + + if (peer->params.sample_encoder == NJ2_ENCODER_INT) { + peer->max_encoded_size = peer->params.period_size * sizeof(int16_t); + peer->encoded_size = peer->max_encoded_size * + SPA_MAX(peer->params.send_audio_channels, peer->params.recv_audio_channels); + if ((peer->encoded_data = calloc(1, peer->encoded_size)) == NULL) + goto error_errno; + } else if (peer->params.sample_encoder == NJ2_ENCODER_OPUS) { +#ifdef HAVE_OPUS_CUSTOM + int32_t i; + peer->max_encoded_size = (peer->params.kbps * peer->params.period_size * 1024) / + (peer->params.sample_rate * 8) + sizeof(uint16_t); + peer->encoded_size = peer->max_encoded_size * + SPA_MAX(peer->params.send_audio_channels, peer->params.recv_audio_channels); + if ((peer->encoded_data = calloc(1, peer->encoded_size)) == NULL) + goto error_errno; + if ((peer->opus_config = opus_custom_mode_create(peer->params.sample_rate, + peer->params.period_size, &res)) == NULL) + goto error_opus; + if ((peer->opus_enc = calloc(peer->params.send_audio_channels, + sizeof(OpusCustomEncoder*))) == NULL) + goto error_errno; + + for (i = 0; i < peer->params.send_audio_channels; i++) { + if ((peer->opus_enci = opus_custom_encoder_create(peer->opus_config, + 1, &res)) == NULL) + goto error_opus; + opus_custom_encoder_ctl(peer->opus_enci, + OPUS_SET_BITRATE(peer->params.kbps*1024)); // bits per second + opus_custom_encoder_ctl(peer->opus_enci, + OPUS_SET_COMPLEXITY(10)); + opus_custom_encoder_ctl(peer->opus_enci, + OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_custom_encoder_ctl(peer->opus_enci, + OPUS_SET_SIGNAL(OPUS_APPLICATION_RESTRICTED_LOWDELAY)); + } + if ((peer->opus_dec = calloc(peer->params.recv_audio_channels, + sizeof(OpusCustomDecoder*))) == NULL) + goto error_errno; + for (i = 0; i < peer->params.recv_audio_channels; i++) { + if ((peer->opus_deci = opus_custom_decoder_create(peer->opus_config, + 1, &res)) == NULL) + goto error_opus; + } +#else + return -ENOTSUP; +#endif + + } + return res; +error_errno: + pw_log_warn("error: %m"); + return -errno; +#ifdef HAVE_OPUS_CUSTOM +error_opus: + pw_log_warn("error: %d", res); + return -EINVAL; +#endif
View file
pipewire-0.3.71.tar.gz/src/modules/module-profiler.c -> pipewire-0.3.72.tar.gz/src/modules/module-profiler.c
Changed
@@ -168,7 +168,8 @@ struct impl *impl = data; struct spa_pod_builder b; struct spa_pod_frame f2; - struct pw_node_activation *a = node->rt.activation; + uint32_t id = node->info.id; + struct pw_node_activation *a = node->rt.target.activation; struct spa_io_position *pos = &a->position; struct pw_node_target *t; int32_t filled; @@ -205,42 +206,48 @@ spa_pod_builder_prop(&b, SPA_PROFILER_driverBlock, 0); spa_pod_builder_add_struct(&b, - SPA_POD_Int(node->info.id), + SPA_POD_Int(id), SPA_POD_String(node->name), SPA_POD_Long(a->prev_signal_time), SPA_POD_Long(a->signal_time), SPA_POD_Long(a->awake_time), SPA_POD_Long(a->finish_time), SPA_POD_Int(a->status), - SPA_POD_Fraction(&node->latency)); + SPA_POD_Fraction(&node->latency), + SPA_POD_Int(a->xrun_count)); spa_list_for_each(t, &node->rt.target_list, link) { struct pw_impl_node *n = t->node; struct pw_node_activation *na; struct spa_fraction latency; - if (n == NULL || n == node) + if (t->id == id || t->flags & PW_NODE_TARGET_PEER) continue; - latency = n->latency; - if (n->force_quantum != 0) - latency.num = n->force_quantum; - if (n->force_rate != 0) - latency.denom = n->force_rate; - else if (n->rate.denom != 0) - latency.denom = n->rate.denom; - - na = n->rt.activation; + if (n != NULL) { + latency = n->latency; + if (n->force_quantum != 0) + latency.num = n->force_quantum; + if (n->force_rate != 0) + latency.denom = n->force_rate; + else if (n->rate.denom != 0) + latency.denom = n->rate.denom; + } else { + spa_zero(latency); + } + + na = t->activation; spa_pod_builder_prop(&b, SPA_PROFILER_followerBlock, 0); spa_pod_builder_add_struct(&b, - SPA_POD_Int(n->info.id), - SPA_POD_String(n->name), + SPA_POD_Int(t->id), + SPA_POD_String(t->name), SPA_POD_Long(a->signal_time), SPA_POD_Long(na->signal_time), SPA_POD_Long(na->awake_time), SPA_POD_Long(na->finish_time), SPA_POD_Int(na->status), - SPA_POD_Fraction(&latency)); + SPA_POD_Fraction(&latency), + SPA_POD_Int(na->xrun_count)); } spa_pod_builder_pop(&b, &f0); @@ -275,19 +282,11 @@ .complete = context_do_profile, }; -static int do_stop(struct spa_loop *loop, - bool async, uint32_t seq, const void *data, size_t size, void *user_data) -{ - struct impl *impl = user_data; - spa_hook_remove(&impl->context_listener); - return 0; -} - static void stop_listener(struct impl *impl) { if (impl->listening) { - pw_loop_invoke(impl->data_loop, - do_stop, SPA_ID_INVALID, NULL, 0, true, impl); + pw_context_driver_remove_listener(impl->context, + &impl->context_listener); impl->listening = false; } } @@ -307,16 +306,6 @@ }; static int -do_start(struct spa_loop *loop, - bool async, uint32_t seq, const void *data, size_t size, void *user_data) -{ - struct impl *impl = user_data; - spa_hook_list_append(&impl->context->driver_listener_list, - &impl->context_listener, - &context_events, impl); - return 0; -} -static int global_bind(void *object, struct pw_impl_client *client, uint32_t permissions, uint32_t version, uint32_t id) { @@ -340,8 +329,9 @@ if (++impl->busy == 1) { pw_log_info("%p: starting profiler", impl); - pw_loop_invoke(impl->data_loop, - do_start, SPA_ID_INVALID, NULL, 0, false, impl); + pw_context_driver_add_listener(impl->context, + &impl->context_listener, + &context_events, impl); impl->listening = true; } return 0;
View file
pipewire-0.3.71.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.72.tar.gz/src/modules/module-protocol-native.c
Changed
@@ -919,12 +919,18 @@ proxy = pw_core_find_proxy(this, msg->id); if (proxy == NULL || proxy->zombie) { + uint32_t i; + if (proxy == NULL) pw_log_error("%p: could not find proxy %u", this, msg->id); else pw_log_debug("%p: zombie proxy %u", this, msg->id); - /* FIXME close fds */ + /* close fds */ + for (i = 0; i < msg->n_fds; i++) { + pw_log_debug("%p: close fd:%d", conn, msg->fdsi); + close(msg->fdsi); + } continue; }
View file
pipewire-0.3.71.tar.gz/src/modules/module-protocol-native/connection.c -> pipewire-0.3.72.tar.gz/src/modules/module-protocol-native/connection.c
Changed
@@ -205,7 +205,7 @@ char cmsgbufCMSG_SPACE(MAX_FDS_MSG * sizeof(int)); struct cmsghdr align; } cmsgbuf; - int n_fds = 0; + int i, n_fds = 0, *fds; size_t avail; avail = buf->buffer_maxsize - buf->buffer_size; @@ -242,10 +242,13 @@ continue; n_fds = cmsg_data_length(cmsg) / sizeof(int); + fds = (int*)CMSG_DATA(cmsg); if (n_fds + buf->n_fds > MAX_FDS) goto too_many_fds; - memcpy(&buf->fdsbuf->n_fds, CMSG_DATA(cmsg), n_fds * sizeof(int)); - buf->n_fds += n_fds; + for (i = 0; i < n_fds; i++) { + pw_log_debug("connection %p: buffer:%p got fd:%d", conn, buf, fdsi); + buf->fdsbuf->n_fds++ = fdsi; + } } pw_log_trace("connection %p: %d read %zd bytes and %d fds", conn, conn->fd, len, n_fds); @@ -272,7 +275,7 @@ { uint32_t i; - pw_log_debug("clear fds:%d", fds); + pw_log_debug("%p clear fds:%d n_fds:%d", buf, fds, buf->n_fds); if (fds) { for (i = 0; i < buf->n_fds; i++) { pw_log_debug("%p: close fd:%d", buf, buf->fdsi); @@ -848,6 +851,8 @@ { struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); + pw_log_debug("%p: clear", conn); + clear_buffer(&impl->out, true); clear_buffer(&impl->in, true);
View file
pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/modules/module-gsettings.c -> pipewire-0.3.72.tar.gz/src/modules/module-protocol-pulse/modules/module-gsettings.c
Changed
@@ -137,6 +137,27 @@ return 0; } +static bool schema_exists(const char *schema_id) +{ + GSettingsSchemaSource *source; + GSettingsSchema *schema; + + source = g_settings_schema_source_get_default(); + if (!source) { + pw_log_error("gsettings schema source not found"); + return false; + } + + schema = g_settings_schema_source_lookup(source, schema_id, TRUE); + if (!schema) { + pw_log_error("required gsettings schema %s does not exist", schema_id); + return false; + } + + g_settings_schema_unref(schema); + return true; +} + static void handle_module_group(struct module_gsettings_data *d, gchar *name) { struct impl *impl = d->module->impl; @@ -147,6 +168,9 @@ snprintf(p, sizeof(p), PA_GSETTINGS_MODULE_GROUPS_PATH"%s/", name); + if (!schema_exists(PA_GSETTINGS_MODULE_GROUP_SCHEMA)) + return; + settings = g_settings_new_with_path(PA_GSETTINGS_MODULE_GROUP_SCHEMA, p); if (settings == NULL) return; @@ -198,12 +222,20 @@ struct module_gsettings_data *data = module->user_data; gchar **name; + /* Check the required schema files are installed. If not, Glib will + * abort in g_settings_new */ + if (!schema_exists(PA_GSETTINGS_MODULE_GROUPS_SCHEMA) || + !schema_exists(PA_GSETTINGS_MODULE_GROUP_SCHEMA)) + return -EIO; + data->context = g_main_context_new(); g_main_context_push_thread_default(data->context); data->settings = g_settings_new(PA_GSETTINGS_MODULE_GROUPS_SCHEMA); - if (data->settings == NULL) + if (data->settings == NULL) { + g_main_context_pop_thread_default(data->context); return -EIO; + } data->group_names = g_settings_list_children(data->settings); @@ -238,15 +270,19 @@ struct module_gsettings_data *d = module->user_data; struct group *g; - g_main_context_invoke(d->context, do_stop, d); - pw_thread_utils_join(d->thr, NULL); - g_main_context_unref(d->context); + if (d->context) { + g_main_context_invoke(d->context, do_stop, d); + if (d->thr) + pw_thread_utils_join(d->thr, NULL); + g_main_context_unref(d->context); + } spa_list_consume(g, &d->groups, link) unload_module(d, g); g_strfreev(d->group_names); - g_object_unref(G_OBJECT(d->settings)); + if (d->settings) + g_object_unref(G_OBJECT(d->settings)); return 0; }
View file
pipewire-0.3.72.tar.gz/src/modules/module-protocol-pulse/modules/module-virtual-sink.c
Added
@@ -0,0 +1,179 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans <wim.taymans@gmail.com> */ +/* SPDX-License-Identifier: MIT */ + +#include <spa/param/audio/format-utils.h> +#include <spa/utils/hook.h> +#include <spa/utils/json.h> +#include <pipewire/pipewire.h> + +#include "../defs.h" +#include "../module.h" + +#define NAME "virtual-sink" + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +struct module_virtual_sink_data { + struct module *module; + + struct pw_impl_module *mod; + struct spa_hook mod_listener; + + struct pw_properties *global_props; + struct pw_properties *capture_props; + struct pw_properties *playback_props; +}; + +static void module_destroy(void *data) +{ + struct module_virtual_sink_data *d = data; + spa_hook_remove(&d->mod_listener); + d->mod = NULL; + module_schedule_unload(d->module); +} + +static const struct pw_impl_module_events module_events = { + PW_VERSION_IMPL_MODULE_EVENTS, + .destroy = module_destroy +}; + +static int module_virtual_sink_load(struct module *module) +{ + struct module_virtual_sink_data *data = module->user_data; + FILE *f; + char *args; + size_t size; + + pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "virtual-sink-%u", module->index); + pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "virtual-sink-%u", module->index); + pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); + pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); + + if ((f = open_memstream(&args, &size)) == NULL) + return -errno; + + fprintf(f, "{"); + pw_properties_serialize_dict(f, &data->global_props->dict, 0); + fprintf(f, " capture.props = {"); + pw_properties_serialize_dict(f, &data->capture_props->dict, 0); + fprintf(f, " } playback.props = {"); + pw_properties_serialize_dict(f, &data->playback_props->dict, 0); + fprintf(f, " } }"); + fclose(f); + + data->mod = pw_context_load_module(module->impl->context, + "libpipewire-module-loopback", + args, NULL); + free(args); + + if (data->mod == NULL) + return -errno; + + pw_impl_module_add_listener(data->mod, + &data->mod_listener, + &module_events, data); + + return 0; +} + +static int module_virtual_sink_unload(struct module *module) +{ + struct module_virtual_sink_data *d = module->user_data; + + if (d->mod) { + spa_hook_remove(&d->mod_listener); + pw_impl_module_destroy(d->mod); + d->mod = NULL; + } + + pw_properties_free(d->capture_props); + pw_properties_free(d->playback_props); + pw_properties_free(d->global_props); + + return 0; +} + +static const struct spa_dict_item module_virtual_sink_info = { + { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, + { PW_KEY_MODULE_DESCRIPTION, "Virtual sink" }, + { PW_KEY_MODULE_USAGE, "sink_name=<name for the sink> " + "sink_properties=<properties for the sink> " + "master=<name of sink to filter> " + "channels=<number of channels> " + "channel_map=<channel map> " + "use_volume_sharing=<yes or no> " + "force_flat_volume=<yes or no> " }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; + +static int module_virtual_sink_prepare(struct module * const module) +{ + struct module_virtual_sink_data * const d = module->user_data; + struct pw_properties * const props = module->props; + struct pw_properties *global_props = NULL, *playback_props = NULL, *capture_props = NULL; + const char *str; + struct spa_audio_info_raw info = { 0 }; + int res; + + PW_LOG_TOPIC_INIT(mod_topic); + + global_props = pw_properties_new(NULL, NULL); + capture_props = pw_properties_new(NULL, NULL); + playback_props = pw_properties_new(NULL, NULL); + if (!global_props || !capture_props || !playback_props) { + res = -EINVAL; + goto out; + } + + if ((str = pw_properties_get(props, "sink_name")) != NULL) { + pw_properties_set(global_props, PW_KEY_NODE_NAME, str); + pw_properties_set(global_props, PW_KEY_NODE_DESCRIPTION, str); + pw_properties_set(props, "sink_name", NULL); + } else { + pw_properties_set(global_props, PW_KEY_NODE_NAME, "vsink"); + pw_properties_set(global_props, PW_KEY_NODE_DESCRIPTION, "Virtual Sink"); + } + if ((str = pw_properties_get(props, "sink_properties")) != NULL) { + module_args_add_props(capture_props, str); + pw_properties_set(props, "sink_properties", NULL); + } + pw_properties_set(playback_props, PW_KEY_NODE_PASSIVE, "true"); + if (pw_properties_get(capture_props, PW_KEY_MEDIA_CLASS) == NULL) + pw_properties_set(capture_props, PW_KEY_MEDIA_CLASS, "Audio/Sink"); + + if ((str = pw_properties_get(props, "master")) != NULL) { + pw_properties_set(playback_props, PW_KEY_TARGET_OBJECT, str); + pw_properties_set(props, "master", NULL); + } + + if (module_args_to_audioinfo_keys(module->impl, props, + NULL, NULL, "channels", "channel_map", &info) < 0) { + res = -EINVAL; + goto out; + } + audioinfo_to_properties(&info, global_props); + + d->module = module; + d->global_props = global_props; + d->capture_props = capture_props; + d->playback_props = playback_props; + + return 0; +out: + pw_properties_free(global_props); + pw_properties_free(playback_props); + pw_properties_free(capture_props); + + return res; +} + +DEFINE_MODULE_INFO(module_virtual_sink) = { + .name = "module-virtual-sink", + .prepare = module_virtual_sink_prepare, + .load = module_virtual_sink_load, + .unload = module_virtual_sink_unload, + .properties = &SPA_DICT_INIT_ARRAY(module_virtual_sink_info), + .data_size = sizeof(struct module_virtual_sink_data), +};
View file
pipewire-0.3.72.tar.gz/src/modules/module-protocol-pulse/modules/module-virtual-source.c
Added
@@ -0,0 +1,188 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2021 Wim Taymans <wim.taymans@gmail.com> */ +/* SPDX-FileCopyrightText: Copyright © 2021 Arun Raghavan <arun@asymptotic.io> */ +/* SPDX-License-Identifier: MIT */ + +#include <spa/param/audio/format-utils.h> +#include <spa/utils/hook.h> +#include <spa/utils/json.h> +#include <pipewire/pipewire.h> + +#include "../defs.h" +#include "../module.h" + +#define NAME "virtual-source" + +PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); +#define PW_LOG_TOPIC_DEFAULT mod_topic + +struct module_virtual_source_data { + struct module *module; + + struct pw_impl_module *mod; + struct spa_hook mod_listener; + + struct pw_properties *global_props; + struct pw_properties *capture_props; + struct pw_properties *playback_props; +}; + +static void module_destroy(void *data) +{ + struct module_virtual_source_data *d = data; + spa_hook_remove(&d->mod_listener); + d->mod = NULL; + module_schedule_unload(d->module); +} + +static const struct pw_impl_module_events module_events = { + PW_VERSION_IMPL_MODULE_EVENTS, + .destroy = module_destroy +}; + +static int module_virtual_source_load(struct module *module) +{ + struct module_virtual_source_data *data = module->user_data; + FILE *f; + char *args; + size_t size; + + pw_properties_setf(data->capture_props, PW_KEY_NODE_GROUP, "virtual-source-%u", module->index); + pw_properties_setf(data->playback_props, PW_KEY_NODE_GROUP, "virtual-source-%u", module->index); + pw_properties_setf(data->capture_props, "pulse.module.id", "%u", module->index); + pw_properties_setf(data->playback_props, "pulse.module.id", "%u", module->index); + + if ((f = open_memstream(&args, &size)) == NULL) + return -errno; + + fprintf(f, "{"); + pw_properties_serialize_dict(f, &data->global_props->dict, 0); + fprintf(f, " capture.props = {"); + pw_properties_serialize_dict(f, &data->capture_props->dict, 0); + fprintf(f, " } playback.props = {"); + pw_properties_serialize_dict(f, &data->playback_props->dict, 0); + fprintf(f, " } }"); + fclose(f); + + data->mod = pw_context_load_module(module->impl->context, + "libpipewire-module-loopback", + args, NULL); + free(args); + + if (data->mod == NULL) + return -errno; + + pw_impl_module_add_listener(data->mod, + &data->mod_listener, + &module_events, data); + + return 0; +} + +static int module_virtual_source_unload(struct module *module) +{ + struct module_virtual_source_data *d = module->user_data; + + if (d->mod) { + spa_hook_remove(&d->mod_listener); + pw_impl_module_destroy(d->mod); + d->mod = NULL; + } + + pw_properties_free(d->capture_props); + pw_properties_free(d->playback_props); + pw_properties_free(d->global_props); + + return 0; +} + +static const struct spa_dict_item module_virtual_source_info = { + { PW_KEY_MODULE_AUTHOR, "Arun Raghavan <arun@asymptotic.io>" }, + { PW_KEY_MODULE_DESCRIPTION, "Loopback from source to sink" }, + { PW_KEY_MODULE_USAGE, "source_name=<name for the source> " + "source_properties=<properties for the source> " + "master=<name of source to filter> " + "uplink_sink=<name> (optional)" + "channels=<number of channels> " + "channel_map=<channel map> " + "use_volume_sharing=<yes or no> " + "force_flat_volume=<yes or no> " }, + { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, +}; + +static int module_virtual_source_prepare(struct module * const module) +{ + struct module_virtual_source_data * const d = module->user_data; + struct pw_properties * const props = module->props; + struct pw_properties *global_props = NULL, *playback_props = NULL, *capture_props = NULL; + const char *str; + struct spa_audio_info_raw info = { 0 }; + int res; + + PW_LOG_TOPIC_INIT(mod_topic); + + global_props = pw_properties_new(NULL, NULL); + capture_props = pw_properties_new(NULL, NULL); + playback_props = pw_properties_new(NULL, NULL); + if (!global_props || !capture_props || !playback_props) { + res = -EINVAL; + goto out; + } + + if ((str = pw_properties_get(props, "source_name")) != NULL) { + pw_properties_set(global_props, PW_KEY_NODE_NAME, str); + pw_properties_set(global_props, PW_KEY_NODE_DESCRIPTION, str); + pw_properties_set(props, "source_name", NULL); + } else { + pw_properties_set(global_props, PW_KEY_NODE_NAME, "vsource"); + pw_properties_set(global_props, PW_KEY_NODE_DESCRIPTION, "Virtual Source"); + } + if ((str = pw_properties_get(props, "source_properties")) != NULL) { + module_args_add_props(playback_props, str); + pw_properties_set(props, "source_properties", NULL); + } + pw_properties_set(capture_props, PW_KEY_NODE_PASSIVE, "true"); + if (pw_properties_get(playback_props, PW_KEY_MEDIA_CLASS) == NULL) + pw_properties_set(playback_props, PW_KEY_MEDIA_CLASS, "Audio/Source"); + + if ((str = pw_properties_get(props, "master")) != NULL) { + if (spa_strendswith(str, ".monitor")) { + pw_properties_setf(capture_props, PW_KEY_TARGET_OBJECT, + "%.*s", (int)strlen(str)-8, str); + pw_properties_set(capture_props, PW_KEY_STREAM_CAPTURE_SINK, + "true"); + } else { + pw_properties_set(capture_props, PW_KEY_TARGET_OBJECT, str); + } + pw_properties_set(props, "master", NULL); + } + + if (module_args_to_audioinfo_keys(module->impl, props, + NULL, NULL, "channels", "channel_map", &info) < 0) { + res = -EINVAL; + goto out; + } + audioinfo_to_properties(&info, global_props); + + d->module = module; + d->global_props = global_props; + d->capture_props = capture_props; + d->playback_props = playback_props; + + return 0; +out: + pw_properties_free(global_props); + pw_properties_free(playback_props); + pw_properties_free(capture_props); + + return res; +} + +DEFINE_MODULE_INFO(module_virtual_source) = { + .name = "module-virtual-source", + .prepare = module_virtual_source_prepare, + .load = module_virtual_source_load, + .unload = module_virtual_source_unload, + .properties = &SPA_DICT_INIT_ARRAY(module_virtual_source_info), + .data_size = sizeof(struct module_virtual_source_data), +};
View file
pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.72.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
@@ -1097,13 +1097,17 @@ switch (id) { case SPA_PROP_channelVolumes: - stream->volume.channels = control->n_values; - memcpy(stream->volume.values, control->values, control->n_values * sizeof(float)); - pw_log_info("stream %p: volume changed %f", stream, stream->volume.values0); + if (!stream->volume_set) { + stream->volume.channels = control->n_values; + memcpy(stream->volume.values, control->values, control->n_values * sizeof(float)); + pw_log_info("stream %p: volume changed %f", stream, stream->volume.values0); + } break; case SPA_PROP_mute: - stream->muted = control->values0 >= 0.5; - pw_log_info("stream %p: mute changed %d", stream, stream->muted); + if (!stream->muted_set) { + stream->muted = control->values0 >= 0.5; + pw_log_info("stream %p: mute changed %d", stream, stream->muted); + } break; } } @@ -1208,11 +1212,13 @@ struct pw_manager_object *peer; if (stream->volume_set) { + stream->volume_set = false; pw_stream_set_control(stream->stream, SPA_PROP_channelVolumes, stream->volume.channels, stream->volume.values, 0); } if (stream->muted_set) { float val = stream->muted ? 1.0f : 0.0f; + stream->muted_set = false; pw_stream_set_control(stream->stream, SPA_PROP_mute, 1, &val, 0); } @@ -1586,6 +1592,8 @@ const struct spa_pod *paramsMAX_FORMATS; uint8_t buffer4096; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + struct pw_manager_object *o; + bool is_monitor; props = pw_properties_copy(client->props); if (props == NULL) @@ -1632,22 +1640,17 @@ TAG_INVALID) < 0) goto error_protocol; } + o = find_device(client, sink_index, sink_name, true, &is_monitor); spa_zero(fix_ss); spa_zero(fix_map); - if (fix_format || fix_rate || fix_channels) { - struct pw_manager_object *o; - bool is_monitor; - - o = find_device(client, sink_index, sink_name, true, &is_monitor); - if (o != NULL) { - struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT); - collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs); - fix_ss.format = fix_format ? dev_info.ss.format : 0; - fix_ss.rate = fix_rate ? dev_info.ss.rate : 0; - fix_ss.channels = fix_channels ? dev_info.ss.channels : 0; - fix_map = dev_info.map; - } + if ((fix_format || fix_rate || fix_channels) && o != NULL) { + struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT); + collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs); + fix_ss.format = fix_format ? dev_info.ss.format : 0; + fix_ss.rate = fix_rate ? dev_info.ss.rate : 0; + fix_ss.channels = fix_channels ? dev_info.ss.channels : 0; + fix_map = dev_info.map; } if (client->version >= 13) { @@ -1772,6 +1775,9 @@ flags |= PW_STREAM_FLAG_DONT_RECONNECT; if (sink_name != NULL) { + if (o != NULL) + sink_name = pw_properties_get(o->props, + PW_KEY_NODE_NAME); pw_properties_set(props, PW_KEY_TARGET_OBJECT, sink_name); } else if (sink_index != SPA_ID_INVALID && sink_index != 0) { @@ -1858,6 +1864,8 @@ const struct spa_pod *paramsMAX_FORMATS; uint8_t buffer4096; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + struct pw_manager_object *o; + bool is_monitor = false; props = pw_properties_copy(client->props); if (props == NULL) @@ -1922,22 +1930,17 @@ TAG_INVALID) < 0) goto error_protocol; } + o = find_device(client, source_index, source_name, false, &is_monitor); spa_zero(fix_ss); spa_zero(fix_map); - if (fix_format || fix_rate || fix_channels) { - struct pw_manager_object *o; - bool is_monitor; - - o = find_device(client, source_index, source_name, false, &is_monitor); - if (o != NULL) { - struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_INPUT); - collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs); - fix_ss.format = fix_format ? dev_info.ss.format : 0; - fix_ss.rate = fix_rate ? dev_info.ss.rate : 0; - fix_ss.channels = fix_channels ? dev_info.ss.channels : 0; - fix_map = dev_info.map; - } + if ((fix_format || fix_rate || fix_channels) && o != NULL) { + struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_INPUT); + collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs); + fix_ss.format = fix_format ? dev_info.ss.format : 0; + fix_ss.rate = fix_rate ? dev_info.ss.rate : 0; + fix_ss.channels = fix_channels ? dev_info.ss.channels : 0; + fix_map = dev_info.map; } if (client->version >= 22) { @@ -2048,16 +2051,21 @@ pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%u", source_index); } else if (source_name != NULL) { + if (o != NULL) + source_name = pw_properties_get(o->props, + PW_KEY_NODE_NAME); if (spa_strendswith(source_name, ".monitor")) { + is_monitor = true; pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%.*s", (int)strlen(source_name)-8, source_name); - pw_properties_set(props, - PW_KEY_STREAM_CAPTURE_SINK, "true"); } else { pw_properties_set(props, PW_KEY_TARGET_OBJECT, source_name); } + if (is_monitor) + pw_properties_set(props, + PW_KEY_STREAM_CAPTURE_SINK, "true"); } stream->stream = pw_stream_new(client->core, name, props); @@ -2453,6 +2461,7 @@ return NULL; sink = true; find_default = true; + monitor = true; } else if (spa_streq(name, DEFAULT_SOURCE)) { if (sink) return NULL; @@ -2908,10 +2917,15 @@ (index != SPA_ID_INVALID && name != NULL)) return -EINVAL; - if (command == COMMAND_SET_SINK_VOLUME) + if (command == COMMAND_SET_SINK_VOLUME) { + if (client->quirks & QUIRK_BLOCK_SINK_VOLUME) + return -EPERM; direction = PW_DIRECTION_OUTPUT; - else + } else { + if (client->quirks & QUIRK_BLOCK_SOURCE_VOLUME) + return -EPERM; direction = PW_DIRECTION_INPUT; + } o = find_device(client, index, name, direction == PW_DIRECTION_OUTPUT, &is_monitor); if (o == NULL || (info = o->info) == NULL || info->props == NULL)
View file
pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/quirks.c -> pipewire-0.3.72.tar.gz/src/modules/module-protocol-pulse/quirks.c
Changed
@@ -17,6 +17,8 @@ static const struct { const char *key; uint64_t value; } quirk_keys = { { "force-s16-info", QUIRK_FORCE_S16_FORMAT }, { "remove-capture-dont-move", QUIRK_REMOVE_CAPTURE_DONT_MOVE }, + { "block-source-volume", QUIRK_BLOCK_SOURCE_VOLUME }, + { "block-sink-volume", QUIRK_BLOCK_SINK_VOLUME }, }; SPA_FOR_EACH_ELEMENT_VAR(quirk_keys, i) { if (spa_streq(str, i->key))
View file
pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/quirks.h -> pipewire-0.3.72.tar.gz/src/modules/module-protocol-pulse/quirks.h
Changed
@@ -10,6 +10,8 @@ #define QUIRK_FORCE_S16_FORMAT (1ull<<0) /** forces S16 sample format in sink and source * info */ #define QUIRK_REMOVE_CAPTURE_DONT_MOVE (1ull<<1) /** removes the capture stream DONT_MOVE flag */ +#define QUIRK_BLOCK_SOURCE_VOLUME (1ull<<2) /** block volume changes to sources */ +#define QUIRK_BLOCK_SINK_VOLUME (1ull<<3) /** block volume changes to sinks */ int client_update_quirks(struct client *client);
View file
pipewire-0.3.71.tar.gz/src/modules/module-protocol-pulse/stream.c -> pipewire-0.3.72.tar.gz/src/modules/module-protocol-pulse/stream.c
Changed
@@ -179,11 +179,18 @@ missing -= stream->requested; missing -= avail; - if (missing <= 0) + if (missing <= 0) { + pw_log_debug("stream %p: (tlen:%u - req:%"PRIi64" - avail:%"PRIi64") <= 0", + stream, stream->attr.tlength, stream->requested, avail); return 0; + } - if (missing < stream->attr.minreq && !stream_prebuf_active(stream, avail)) + if (missing < stream->attr.minreq && !stream_prebuf_active(stream, avail)) { + pw_log_debug("stream %p: (tlen:%u - req:%"PRIi64" - avail:%"PRIi64") <= minreq:%u", + stream, stream->attr.tlength, stream->requested, avail, + stream->attr.minreq); return 0; + } stream->requested += missing; @@ -304,11 +311,12 @@ uint32_t size; size = stream_pop_missing(stream); - pw_log_debug("stream %p: REQUEST channel:%d %u", stream, stream->channel, size); if (size == 0) return 0; + pw_log_debug("stream %p: REQUEST channel:%d %u", stream, stream->channel, size); + msg = message_alloc(impl, -1, 0); message_put(msg, TAG_U32, COMMAND_REQUEST,
View file
pipewire-0.3.71.tar.gz/src/modules/module-raop-discover.c -> pipewire-0.3.72.tar.gz/src/modules/module-raop-discover.c
Changed
@@ -126,9 +126,6 @@ struct tunnel_info { const char *name; - const char *host_name; - const char *ip; - const char *port; }; #define TUNNEL_INFO(...) ((struct tunnel_info){ __VA_ARGS__ }) @@ -151,9 +148,6 @@ return NULL; t->info.name = strdup(info->name); - t->info.host_name = strdup(info->host_name); - t->info.ip = strdup(info->ip); - t->info.port = strdup(info->port); spa_list_append(&impl->tunnel_list, &t->link); return t; @@ -171,7 +165,11 @@ static void free_tunnel(struct tunnel *t) { - pw_impl_module_destroy(t->module); + spa_list_remove(&t->link); + if (t->module) + pw_impl_module_destroy(t->module); + free((char *) t->info.name); + free(t); } static void impl_free(struct impl *impl) @@ -284,16 +282,8 @@ static void submodule_destroy(void *data) { struct tunnel *t = data; - - spa_list_remove(&t->link); spa_hook_remove(&t->module_listener); - - free((char *) t->info.name); - free((char *) t->info.host_name); - free((char *) t->info.ip); - free((char *) t->info.port); - - free(t); + t->module = NULL; } static const struct pw_impl_module_events submodule_events = { @@ -304,19 +294,18 @@ struct match_info { struct impl *impl; struct pw_properties *props; - struct tunnel_info *tinfo; + struct tunnel *tunnel; bool matched; }; static int create_stream(struct impl *impl, struct pw_properties *props, - struct tunnel_info *tinfo) + struct tunnel *t) { FILE *f; char *args; size_t size; int res = 0; struct pw_impl_module *mod; - struct tunnel *t; if ((f = open_memstream(&args, &size)) == NULL) { res = -errno; @@ -341,16 +330,7 @@ goto done; } - t = make_tunnel(impl, tinfo); - if (t == NULL) { - res = -errno; - pw_log_error("Can't make tunnel: %m"); - pw_impl_module_destroy(mod); - goto done; - } - pw_impl_module_add_listener(mod, &t->module_listener, &submodule_events, t); - t->module = mod; done: return res; @@ -365,7 +345,7 @@ i->matched = true; if (spa_streq(action, "create-stream")) { pw_properties_update_string(i->props, str, len); - create_stream(i->impl, i->props, i->tinfo); + create_stream(i->impl, i->props, i->tunnel); } return res; } @@ -377,10 +357,12 @@ { struct impl *impl = userdata; struct tunnel_info tinfo; - const char *str, *port_str; + struct tunnel *t; + const char *str; AvahiStringList *l; struct pw_properties *props = NULL; char atAVAHI_ADDRESS_STR_MAX; + int ipv; if (event != AVAHI_RESOLVER_FOUND) { pw_log_error("Resolving of '%s' failed: %s", name, @@ -388,7 +370,19 @@ goto done; } - avahi_address_snprint(at, sizeof(at), a); + tinfo = TUNNEL_INFO(.name = name); + + t = find_tunnel(impl, &tinfo); + if (t == NULL) + t = make_tunnel(impl, &tinfo); + if (t == NULL) { + pw_log_error("Can't make tunnel: %m"); + goto done; + } + if (t->module != NULL) { + pw_log_info("found duplicate mdns entry - skipping tunnel creation"); + goto done; + } props = pw_properties_new(NULL, NULL); if (props == NULL) { @@ -396,7 +390,10 @@ goto done; } + avahi_address_snprint(at, sizeof(at), a); + ipv = protocol == AVAHI_PROTO_INET ? 4 : 6; pw_properties_setf(props, "raop.ip", "%s", at); + pw_properties_setf(props, "raop.ip.version", "%d", ipv); pw_properties_setf(props, "raop.port", "%u", port); pw_properties_setf(props, "raop.name", "%s", name); pw_properties_setf(props, "raop.hostname", "%s", host_name); @@ -413,20 +410,13 @@ avahi_free(value); } - port_str = pw_properties_get(props, "raop.port"); - - tinfo = TUNNEL_INFO(.name = name, - .host_name = host_name, - .ip = at, - .port = port_str); - if ((str = pw_properties_get(impl->properties, "stream.rules")) == NULL) str = DEFAULT_CREATE_RULES; if (str != NULL) { struct match_info minfo = { .impl = impl, .props = props, - .tinfo = &tinfo, + .tunnel = t, }; pw_conf_match_rules(str, strlen(str), NAME, &props->dict, rule_matched, &minfo); @@ -459,7 +449,7 @@ switch (event) { case AVAHI_BROWSER_NEW: if (t != NULL) { - pw_log_debug("found duplicate mdns entry - skipping tunnel creation"); + pw_log_info("found duplicate mdns entry - skipping tunnel creation"); return; } if (!(avahi_service_resolver_new(impl->client,
View file
pipewire-0.3.71.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.72.tar.gz/src/modules/module-raop-sink.c
Changed
@@ -122,6 +122,9 @@ #define FRAMES_PER_TCP_PACKET 4096 #define FRAMES_PER_UDP_PACKET 352 +#define RAOP_LATENCY_MIN 11025u +#define DEFAULT_LATENCY_MS "1000" + #define DEFAULT_TCP_AUDIO_PORT 6000 #define DEFAULT_UDP_AUDIO_PORT 6000 #define DEFAULT_UDP_CONTROL_PORT 6001 @@ -143,8 +146,6 @@ #define DEFAULT_CHANNELS 2 #define DEFAULT_POSITION " FL FR " -#define DEFAULT_LATENCY 22050 - #define VOLUME_MAX 0.0 #define VOLUME_DEF -30.0 #define VOLUME_MIN -144.0 @@ -243,7 +244,6 @@ struct spa_source *server_source; uint32_t block_size; - uint32_t delay; uint32_t latency; uint16_t seq; @@ -297,10 +297,10 @@ return ntp | (uint64_t) (ts->tv_sec + 0x83aa7e80) << 32; } -static inline uint64_t ntp_now(int clockid) +static inline uint64_t ntp_now(void) { struct timespec now; - clock_gettime(clockid, &now); + clock_gettime(CLOCK_REALTIME, &now); return timespec_to_ntp(&now); } @@ -309,22 +309,20 @@ { uint32_t pkt5; uint32_t rtptime = impl->rtptime; - uint32_t delay = impl->delay; + uint32_t latency = impl->latency; uint64_t transmitted; pkt0 = htonl(0x80d40007); if (impl->first) pkt0 |= htonl(0x10000000); - rtptime -= delay; - pkt1 = htonl(rtptime); - transmitted = ntp_now(CLOCK_MONOTONIC); + pkt1 = htonl(rtptime - latency); + transmitted = ntp_now(); pkt2 = htonl(transmitted >> 32); pkt3 = htonl(transmitted & 0xffffffff); - rtptime += delay; pkt4 = htonl(rtptime); - pw_log_debug("sync: delayed:%u now:%"PRIu64" rtptime:%u", - rtptime - delay, transmitted, rtptime); + pw_log_debug("sync: first:%d latency:%u now:%"PRIx64" rtptime:%u", + impl->first, latency, transmitted, rtptime); return sendto(impl->control_fd, pkt, sizeof(pkt), 0, dest_addr, addrlen); } @@ -341,11 +339,11 @@ pkt3 = htonl(remote & 0xffffffff); pkt4 = htonl(received >> 32); pkt5 = htonl(received & 0xffffffff); - transmitted = ntp_now(CLOCK_MONOTONIC); + transmitted = ntp_now(); pkt6 = htonl(transmitted >> 32); pkt7 = htonl(transmitted & 0xffffffff); - pw_log_debug("sync: remote:%"PRIu64" received:%"PRIu64" transmitted:%"PRIu64, + pw_log_debug("sync: remote:%"PRIx64" received:%"PRIx64" transmitted:%"PRIx64, remote, received, transmitted); return sendto(impl->timing_fd, pkt, sizeof(pkt), 0, dest_addr, addrlen); @@ -391,8 +389,7 @@ if (!impl->recording) return 0; - impl->sync++; - if (impl->first || impl->sync == impl->sync_period) { + if (impl->first || ++impl->sync == impl->sync_period) { impl->sync = 0; send_udp_sync_packet(impl, NULL, 0); } @@ -642,12 +639,17 @@ uint32_t packet8; ssize_t bytes; + if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { + pw_log_warn("error on timing socket: %08x", mask); + pw_loop_update_io(impl->loop, impl->timing_source, 0); + return; + } if (mask & SPA_IO_IN) { uint64_t remote, received; struct sockaddr_storage sender; socklen_t sender_size = sizeof(sender); - received = ntp_now(CLOCK_MONOTONIC); + received = ntp_now(); bytes = recvfrom(impl->timing_fd, packet, sizeof(packet), 0, (struct sockaddr*)&sender, &sender_size); if (bytes < 0) { @@ -679,13 +681,18 @@ uint32_t packet2; ssize_t bytes; + if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { + pw_log_warn("error on control socket: %08x", mask); + pw_loop_update_io(impl->loop, impl->control_source, 0); + return; + } if (mask & SPA_IO_IN) { uint32_t hdr; uint16_t seq, num; bytes = read(impl->control_fd, packet, sizeof(packet)); if (bytes < 0) { - pw_log_debug("error reading control packet: %m"); + pw_log_warn("error reading control packet: %m"); return; } if (bytes != sizeof(packet)) { @@ -882,15 +889,14 @@ pw_log_info("reply %d", status); if ((str = spa_dict_lookup(headers, "Audio-Latency")) != NULL) { - if (!spa_atou32(str, &impl->latency, 0)) - impl->latency = DEFAULT_LATENCY; - } else { - impl->latency = DEFAULT_LATENCY; + uint32_t l; + if (spa_atou32(str, &l, 0)) + impl->latency = SPA_MAX(l, impl->latency); } spa_zero(latency); latency.direction = PW_DIRECTION_INPUT; - latency.min_rate = latency.max_rate = impl->latency; + latency.min_rate = latency.max_rate = impl->latency + RAOP_LATENCY_MIN; n_params = 0; spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -1033,7 +1039,7 @@ if ((impl->timing_fd = connect_socket(impl, SOCK_DGRAM, impl->timing_fd, timing_port)) < 0) return impl->timing_fd; - ntp = ntp_now(CLOCK_MONOTONIC); + ntp = ntp_now(); send_udp_timing_packet(impl, ntp, ntp, NULL, 0); } @@ -1206,8 +1212,6 @@ int res, frames, rsa_len, ip_version; char *sdp; char local_ip256; - int min_latency; - min_latency = DEFAULT_LATENCY; host = pw_properties_get(impl->props, "raop.ip"); if (impl->protocol == PROTO_TCP) @@ -1222,7 +1226,7 @@ switch (impl->encryption) { case CRYPTO_NONE: - asprintf(&sdp, "v=0\r\n" + sdp = spa_aprintf("v=0\r\n" "o=iTunes %s 0 IN IP%d %s\r\n" "s=iTunes\r\n" "c=IN IP%d %s\r\n" @@ -1232,10 +1236,12 @@ "a=fmtp:96 %d 0 16 40 10 14 2 255 0 0 %u\r\n", impl->session_id, ip_version, local_ip, ip_version, host, frames, impl->info.rate); + if (!sdp) + return -errno; break; case CRYPTO_AUTH_SETUP: - asprintf(&sdp, "v=0\r\n" + sdp = spa_aprintf("v=0\r\n" "o=iTunes %s 0 IN IP%d %s\r\n" "s=iTunes\r\n" "c=IN IP%d %s\r\n" @@ -1246,7 +1252,9 @@ "a=min-latency:%d", impl->session_id, ip_version, local_ip, ip_version, host, frames, impl->info.rate, - min_latency); + RAOP_LATENCY_MIN); + if (!sdp) + return -errno;
View file
pipewire-0.3.71.tar.gz/src/modules/module-raop/rtsp-client.c -> pipewire-0.3.72.tar.gz/src/modules/module-raop/rtsp-client.c
Changed
@@ -490,6 +490,7 @@ pw_log_error("getaddrinfo: %s", gai_strerror(res)); return -EINVAL; } + res = -ENOENT; for (rp = result; rp != NULL; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype | SOCK_CLOEXEC | SOCK_NONBLOCK, @@ -501,12 +502,14 @@ if (res == 0 || (res < 0 && errno == EINPROGRESS)) break; + res = -errno; close(fd); } freeaddrinfo(result); if (rp == NULL) { - pw_log_error("Could not connect to %s:%u", hostname, port); + pw_log_error("Could not connect to %s:%u: %s", hostname, port, + spa_strerror(res)); return -EINVAL; }
View file
pipewire-0.3.71.tar.gz/src/modules/module-rtp-sap.c -> pipewire-0.3.72.tar.gz/src/modules/module-rtp-sap.c
Changed
@@ -355,8 +355,10 @@ return false; } -static int make_send_socket(struct sockaddr_storage *sa, socklen_t salen, - bool loop, int ttl, char *ifname) +static int make_send_socket( + struct sockaddr_storage *src, socklen_t src_len, + struct sockaddr_storage *sa, socklen_t salen, + bool loop, int ttl) { int af, fd, val, res; @@ -365,6 +367,11 @@ pw_log_error("socket failed: %m"); return -errno; } + if (bind(fd, (struct sockaddr*)src, src_len) < 0) { + res = -errno; + pw_log_error("bind() failed: %m"); + goto error; + } if (connect(fd, (struct sockaddr*)sa, salen) < 0) { res = -errno; pw_log_error("connect() failed: %m"); @@ -520,43 +527,42 @@ snprintf(dst_ttl, sizeof(dst_ttl), "/%d", sdp->ttl); spa_strbuf_init(&buf, buffer, sizeof(buffer)); + /* Don't add any sdp records in between this definition or change the order + it will break compatibility with Dante/AES67 devices. Add new records to + the end. */ spa_strbuf_append(&buf, "v=0\n" "o=%s %u 0 IN %s %s\n" "s=%s\n" "c=IN %s %s%s\n" "t=%u 0\n" - "a=recvonly\n" - "a=tool:PipeWire %s\n" - "a=type:broadcast\n", + "m=%s %u RTP/AVP %i\n", user_name, sdp->ntp, src_ip4 ? "IP4" : "IP6", src_addr, sdp->session_name, dst_ip4 ? "IP4" : "IP6", dst_addr, dst_ttl, sdp->ntp, - pw_get_library_version()); - spa_strbuf_append(&buf, - "m=%s %u RTP/AVP %i\n", - sdp->media_type, - sdp->dst_port, sdp->payload); + sdp->media_type, sdp->dst_port, sdp->payload); if (sdp->channels) { - spa_strbuf_append(&buf, - "a=rtpmap:%i %s/%u/%u\n", - sdp->payload, sdp->mime_type, - sdp->rate, sdp->channels); if (sdp->channelmap0 != 0) { spa_strbuf_append(&buf, "i=%d channels: %s\n", sdp->channels, sdp->channelmap); } + spa_strbuf_append(&buf, + "a=recvonly\n" + "a=rtpmap:%i %s/%u/%u\n", + sdp->payload, sdp->mime_type, + sdp->rate, sdp->channels); } else { spa_strbuf_append(&buf, "a=rtpmap:%i %s/%u\n", sdp->payload, sdp->mime_type, sdp->rate); } - if (sdp->ptime != 0) + + if (sdp->ptime > 0) spa_strbuf_append(&buf, - "a=ptime:%f\n", sdp->ptime); + "a=ptime:%.6g\n", sdp->ptime); if (sdp->ts_refclk != NULL) { spa_strbuf_append(&buf, @@ -568,6 +574,11 @@ spa_strbuf_append(&buf, "a=mediaclk:sender\n"); } + spa_strbuf_append(&buf, + "a=tool:PipeWire %s\n" + "a=type:broadcast\n", + pw_get_library_version()); + pw_log_debug("sending SAP for %u %s", sess->node->id, buffer); iov3.iov_base = buffer; @@ -672,6 +683,10 @@ sdp->ttl = pw_properties_get_int32(props, "rtp.ttl", DEFAULT_TTL); sdp->payload = pw_properties_get_int32(props, "rtp.payload", 127); + if ((str = pw_properties_get(props, "rtp.ptime")) != NULL) + if (!spa_atof(str, &sdp->ptime)) + sdp->ptime = 0.0; + if ((str = pw_properties_get(props, "rtp.media")) != NULL) sdp->media_type = strdup(str); if ((str = pw_properties_get(props, "rtp.mime")) != NULL) @@ -684,7 +699,7 @@ sdp->ts_offset = atoi(str); if ((str = pw_properties_get(props, "rtp.ts-refclk")) != NULL) sdp->ts_refclk = strdup(str); - if ((str = pw_properties_get(props, "rtp.channel-names")) != NULL) + if ((str = pw_properties_get(props, PW_KEY_NODE_CHANNELNAMES)) != NULL) snprintf(sdp->channelmap, sizeof(sdp->channelmap), "%s", str); pw_log_info("created new session for node:%u", node->id); @@ -884,6 +899,7 @@ pw_properties_setf(props, "rtp.destination.ip", "%s", dst_addr); pw_properties_setf(props, "rtp.destination.port", "%u", info->dst_port); pw_properties_setf(props, "rtp.payload", "%u", info->payload); + pw_properties_setf(props, "rtp.ptime", "%f", info->ptime); pw_properties_setf(props, "rtp.media", "%s", info->media_type); pw_properties_setf(props, "rtp.mime", "%s", info->mime_type); pw_properties_setf(props, "rtp.rate", "%u", info->rate); @@ -1209,9 +1225,9 @@ int fd, res; struct timespec value, interval; - if ((fd = make_send_socket(&impl->sap_addr, impl->sap_len, - impl->mcast_loop, impl->ttl, - impl->ifname)) < 0) + if ((fd = make_send_socket(&impl->src_addr, impl->src_len, + &impl->sap_addr, impl->sap_len, + impl->mcast_loop, impl->ttl)) < 0) return fd; impl->sap_fd = fd; @@ -1456,8 +1472,23 @@ impl->cleanup_interval = pw_properties_get_uint32(impl->props, "sap.cleanup.sec", DEFAULT_CLEANUP_SEC); - if ((str = pw_properties_get(props, "source.ip")) == NULL) + if ((str = pw_properties_get(props, "source.ip")) == NULL) { str = DEFAULT_SOURCE_IP; + if (impl->ifname) { + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd >= 0) { + struct ifreq req; + spa_zero(req); + req.ifr_addr.sa_family = AF_INET; + snprintf(req.ifr_name, sizeof(req.ifr_name), "%s", impl->ifname); + res = ioctl(fd, SIOCGIFADDR, &req); + if (res < 0) + pw_log_warn("SIOCGIFADDR %s failed: %m", impl->ifname); + str = inet_ntoa(((struct sockaddr_in *)&req.ifr_addr)->sin_addr); + close(fd); + } + } + } if ((res = parse_address(str, port, &impl->src_addr, &impl->src_len)) < 0) { pw_log_error("invalid source.ip %s: %s", str, spa_strerror(res)); goto out;
View file
pipewire-0.3.71.tar.gz/src/modules/module-rtp-source.c -> pipewire-0.3.72.tar.gz/src/modules/module-rtp-source.c
Changed
@@ -18,6 +18,7 @@ #include <spa/utils/hook.h> #include <spa/utils/result.h> #include <spa/utils/ringbuffer.h> +#include <spa/utils/defs.h> #include <spa/utils/dll.h> #include <spa/utils/json.h> #include <spa/param/audio/format-utils.h> @@ -164,7 +165,8 @@ if (len < 12) goto short_packet; - rtp_stream_receive_packet(impl->stream, buffer, len); + if (SPA_LIKELY(impl->stream)) + rtp_stream_receive_packet(impl->stream, buffer, len); impl->receiving = true; }
View file
pipewire-0.3.71.tar.gz/src/modules/module-rtp/stream.c -> pipewire-0.3.72.tar.gz/src/modules/module-rtp/stream.c
Changed
@@ -389,9 +389,20 @@ min_samples = min_ptime * impl->rate / 1000; max_samples = max_ptime * impl->rate / 1000; - impl->psamples = impl->mtu / impl->stride; - impl->psamples = SPA_CLAMP(impl->psamples, min_samples, max_samples); + float ptime = 0; + if ((str = pw_properties_get(props, "rtp.ptime")) != NULL) + if (!spa_atof(str, &ptime)) + ptime = 0.0; + if (ptime) { + impl->psamples = ptime * impl->rate / 1000; + } else { + impl->psamples = impl->mtu / impl->stride; + impl->psamples = SPA_CLAMP(impl->psamples, min_samples, max_samples); + if (direction == PW_DIRECTION_OUTPUT) + pw_properties_setf(props, "rtp.ptime", "%f", + impl->psamples * 1000.0 / impl->rate); + } latency_msec = pw_properties_get_uint32(props, "sess.latency.msec", DEFAULT_SESS_LATENCY); impl->target_buffer = msec_to_samples(impl, latency_msec); @@ -407,8 +418,6 @@ } pw_properties_setf(props, "net.mtu", "%u", impl->mtu); - pw_properties_setf(props, "rtp.ptime", "%u", - impl->psamples * 1000 / impl->rate); pw_properties_setf(props, "rtp.media", "%s", impl->format_info->media_type); pw_properties_setf(props, "rtp.mime", "%s", impl->format_info->mime); pw_properties_setf(props, "rtp.payload", "%u", impl->payload);
View file
pipewire-0.3.71.tar.gz/src/modules/module-session-manager/client-endpoint/endpoint-stream.c -> pipewire-0.3.72.tar.gz/src/modules/module-session-manager/client-endpoint/endpoint-stream.c
Changed
@@ -10,6 +10,7 @@ #include <pipewire/extensions/session-manager.h> #include <spa/pod/filter.h> +#include <spa/pod/dynamic.h> #include "endpoint-stream.h" #include "client-endpoint.h" @@ -39,8 +40,8 @@ struct endpoint_stream *this = data->stream; struct spa_pod *result; struct spa_pod *param; - uint8_t buffer1024; - struct spa_pod_builder b = { 0 }; + uint8_t buffer2048; + struct spa_pod_dynamic_builder b = { 0 }; uint32_t index; uint32_t next = start; uint32_t count = 0; @@ -55,15 +56,15 @@ if (param == NULL || !spa_pod_is_object_id(param, id)) continue; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if (spa_pod_filter(&b, &result, param, filter) != 0) - continue; - - pw_log_debug(NAME" %p: %d param %u", this, seq, index); - - pw_endpoint_stream_resource_param(resource, seq, id, index, next, result); + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + if (spa_pod_filter(&b.b, &result, param, filter) == 0) { + pw_log_debug(NAME" %p: %d param %u", this, seq, index); + pw_endpoint_stream_resource_param(resource, seq, id, index, next, result); + count++; + } + spa_pod_dynamic_builder_clean(&b); - if (++count == num) + if (count == num) break; } return 0;
View file
pipewire-0.3.71.tar.gz/src/modules/module-session-manager/client-endpoint/endpoint.c -> pipewire-0.3.72.tar.gz/src/modules/module-session-manager/client-endpoint/endpoint.c
Changed
@@ -10,6 +10,7 @@ #include <pipewire/extensions/session-manager.h> #include <spa/pod/filter.h> +#include <spa/pod/dynamic.h> #include "endpoint.h" #include "client-endpoint.h" @@ -39,8 +40,8 @@ struct endpoint *this = data->endpoint; struct spa_pod *result; struct spa_pod *param; - uint8_t buffer1024; - struct spa_pod_builder b = { 0 }; + uint8_t buffer2048; + struct spa_pod_dynamic_builder b = { 0 }; uint32_t index; uint32_t next = start; uint32_t count = 0; @@ -57,15 +58,15 @@ if (param == NULL || !spa_pod_is_object_id(param, id)) continue; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if (spa_pod_filter(&b, &result, param, filter) != 0) - continue; - - pw_log_debug(NAME" %p: %d param %u", this, seq, index); - - pw_endpoint_resource_param(resource, seq, id, index, next, result); + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + if (spa_pod_filter(&b.b, &result, param, filter) == 0) { + pw_log_debug(NAME" %p: %d param %u", this, seq, index); + pw_endpoint_resource_param(resource, seq, id, index, next, result); + count++; + } + spa_pod_dynamic_builder_clean(&b); - if (++count == num) + if (count == num) break; } return 0;
View file
pipewire-0.3.71.tar.gz/src/modules/module-session-manager/client-session/endpoint-link.c -> pipewire-0.3.72.tar.gz/src/modules/module-session-manager/client-session/endpoint-link.c
Changed
@@ -10,6 +10,7 @@ #include <pipewire/extensions/session-manager.h> #include <spa/pod/filter.h> +#include <spa/pod/dynamic.h> #include "endpoint-link.h" #include "client-session.h" @@ -39,8 +40,8 @@ struct endpoint_link *this = data->link; struct spa_pod *result; struct spa_pod *param; - uint8_t buffer1024; - struct spa_pod_builder b = { 0 }; + uint8_t buffer2048; + struct spa_pod_dynamic_builder b = { 0 }; uint32_t index; uint32_t next = start; uint32_t count = 0; @@ -55,15 +56,15 @@ if (param == NULL || !spa_pod_is_object_id(param, id)) continue; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if (spa_pod_filter(&b, &result, param, filter) != 0) - continue; - - pw_log_debug(NAME" %p: %d param %u", this, seq, index); - - pw_endpoint_link_resource_param(resource, seq, id, index, next, result); + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + if (spa_pod_filter(&b.b, &result, param, filter) == 0) { + pw_log_debug(NAME" %p: %d param %u", this, seq, index); + pw_endpoint_link_resource_param(resource, seq, id, index, next, result); + count++; + } + spa_pod_dynamic_builder_clean(&b); - if (++count == num) + if (count == num) break; } return 0;
View file
pipewire-0.3.71.tar.gz/src/modules/module-session-manager/client-session/session.c -> pipewire-0.3.72.tar.gz/src/modules/module-session-manager/client-session/session.c
Changed
@@ -10,6 +10,7 @@ #include <pipewire/extensions/session-manager.h> #include <spa/pod/filter.h> +#include <spa/pod/dynamic.h> #include "session.h" #include "client-session.h" @@ -39,8 +40,8 @@ struct session *this = data->session; struct spa_pod *result; struct spa_pod *param; - uint8_t buffer1024; - struct spa_pod_builder b = { 0 }; + uint8_t buffer2048; + struct spa_pod_dynamic_builder b = { 0 }; uint32_t index; uint32_t next = start; uint32_t count = 0; @@ -55,15 +56,15 @@ if (param == NULL || !spa_pod_is_object_id(param, id)) continue; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if (spa_pod_filter(&b, &result, param, filter) != 0) - continue; - - pw_log_debug(NAME" %p: %d param %u", this, seq, index); - - pw_session_resource_param(resource, seq, id, index, next, result); + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + if (spa_pod_filter(&b.b, &result, param, filter) == 0) { + pw_log_debug(NAME" %p: %d param %u", this, seq, index); + pw_session_resource_param(resource, seq, id, index, next, result); + count++; + } + spa_pod_dynamic_builder_clean(&b); - if (++count == num) + if (count == num) break; } return 0;
View file
pipewire-0.3.71.tar.gz/src/modules/module-session-manager/endpoint-link.c -> pipewire-0.3.72.tar.gz/src/modules/module-session-manager/endpoint-link.c
Changed
@@ -10,6 +10,7 @@ #include <spa/utils/result.h> #include <spa/pod/builder.h> #include <spa/pod/filter.h> +#include <spa/pod/dynamic.h> #define MAX_PARAMS 32 @@ -84,8 +85,8 @@ struct param_data *pdata; struct spa_pod *result; struct spa_pod *param; - uint8_t buffer1024; - struct spa_pod_builder b = { 0 }; + uint8_t buffer2048; + struct spa_pod_dynamic_builder b = { 0 }; uint32_t index; uint32_t next = start; uint32_t count = 0; @@ -103,15 +104,15 @@ param = *pw_array_get_unchecked(&pdata->params, index, struct spa_pod*); - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if (spa_pod_filter(&b, &result, param, filter) != 0) - continue; + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + if (spa_pod_filter(&b.b, &result, param, filter) == 0) { + pw_log_debug(NAME" %p: %d param %u", impl, seq, index); + pw_endpoint_link_resource_param(d->resource, seq, id, index, next, result); + count++; + } + spa_pod_dynamic_builder_clean(&b); - pw_log_debug(NAME" %p: %d param %u", impl, seq, index); - - pw_endpoint_link_resource_param(d->resource, seq, id, index, next, result); - - if (++count == num) + if (count == num) return 0; } }
View file
pipewire-0.3.71.tar.gz/src/modules/module-session-manager/endpoint-stream.c -> pipewire-0.3.72.tar.gz/src/modules/module-session-manager/endpoint-stream.c
Changed
@@ -10,6 +10,7 @@ #include <spa/utils/result.h> #include <spa/pod/builder.h> #include <spa/pod/filter.h> +#include <spa/pod/dynamic.h> #define MAX_PARAMS 32 @@ -84,8 +85,8 @@ struct param_data *pdata; struct spa_pod *result; struct spa_pod *param; - uint8_t buffer1024; - struct spa_pod_builder b = { 0 }; + uint8_t buffer2048; + struct spa_pod_dynamic_builder b = { 0 }; uint32_t index; uint32_t next = start; uint32_t count = 0; @@ -103,15 +104,15 @@ param = *pw_array_get_unchecked(&pdata->params, index, struct spa_pod*); - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if (spa_pod_filter(&b, &result, param, filter) != 0) - continue; + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + if (spa_pod_filter(&b.b, &result, param, filter) == 0) { + pw_log_debug(NAME" %p: %d param %u", impl, seq, index); + pw_endpoint_stream_resource_param(d->resource, seq, id, index, next, result); + count++; + } + spa_pod_dynamic_builder_clean(&b); - pw_log_debug(NAME" %p: %d param %u", impl, seq, index); - - pw_endpoint_stream_resource_param(d->resource, seq, id, index, next, result); - - if (++count == num) + if (count == num) return 0; } }
View file
pipewire-0.3.71.tar.gz/src/modules/module-session-manager/endpoint.c -> pipewire-0.3.72.tar.gz/src/modules/module-session-manager/endpoint.c
Changed
@@ -9,6 +9,7 @@ #include <spa/utils/result.h> #include <spa/pod/builder.h> +#include <spa/pod/dynamic.h> #include <spa/pod/filter.h> #define MAX_PARAMS 32 @@ -84,8 +85,8 @@ struct param_data *pdata; struct spa_pod *result; struct spa_pod *param; - uint8_t buffer1024; - struct spa_pod_builder b = { 0 }; + uint8_t buffer2048; + struct spa_pod_dynamic_builder b = { 0 }; uint32_t index; uint32_t next = start; uint32_t count = 0; @@ -103,15 +104,15 @@ param = *pw_array_get_unchecked(&pdata->params, index, struct spa_pod*); - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if (spa_pod_filter(&b, &result, param, filter) != 0) - continue; + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + if (spa_pod_filter(&b.b, &result, param, filter) == 0) { + pw_log_debug(NAME" %p: %d param %u", impl, seq, index); + pw_endpoint_resource_param(d->resource, seq, id, index, next, result); + count++; + } + spa_pod_dynamic_builder_clean(&b); - pw_log_debug(NAME" %p: %d param %u", impl, seq, index); - - pw_endpoint_resource_param(d->resource, seq, id, index, next, result); - - if (++count == num) + if (count == num) return 0; } }
View file
pipewire-0.3.71.tar.gz/src/modules/module-session-manager/session.c -> pipewire-0.3.72.tar.gz/src/modules/module-session-manager/session.c
Changed
@@ -10,6 +10,7 @@ #include <spa/utils/result.h> #include <spa/pod/builder.h> #include <spa/pod/filter.h> +#include <spa/pod/dynamic.h> #define MAX_PARAMS 32 @@ -84,8 +85,8 @@ struct param_data *pdata; struct spa_pod *result; struct spa_pod *param; - uint8_t buffer1024; - struct spa_pod_builder b = { 0 }; + uint8_t buffer2048; + struct spa_pod_dynamic_builder b = { 0 }; uint32_t index; uint32_t next = start; uint32_t count = 0; @@ -103,15 +104,15 @@ param = *pw_array_get_unchecked(&pdata->params, index, struct spa_pod*); - spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if (spa_pod_filter(&b, &result, param, filter) != 0) - continue; + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + if (spa_pod_filter(&b.b, &result, param, filter) == 0) { + pw_log_debug(NAME" %p: %d param %u", impl, seq, index); + pw_session_resource_param(d->resource, seq, id, index, next, result); + count++; + } + spa_pod_dynamic_builder_clean(&b); - pw_log_debug(NAME" %p: %d param %u", impl, seq, index); - - pw_session_resource_param(d->resource, seq, id, index, next, result); - - if (++count == num) + if (count == num) return 0; } }
View file
pipewire-0.3.71.tar.gz/src/modules/module-zeroconf-discover.c -> pipewire-0.3.72.tar.gz/src/modules/module-zeroconf-discover.c
Changed
@@ -85,11 +85,7 @@ }; struct tunnel_info { - AvahiIfIndex interface; - AvahiProtocol protocol; const char *name; - const char *type; - const char *domain; }; #define TUNNEL_INFO(...) ((struct tunnel_info){ __VA_ARGS__ }) @@ -111,11 +107,7 @@ if (t == NULL) return NULL; - t->info.interface = info->interface; - t->info.protocol = info->protocol; t->info.name = strdup(info->name); - t->info.type = strdup(info->type); - t->info.domain = strdup(info->domain); spa_list_append(&impl->tunnel_list, &t->link); return t; @@ -125,11 +117,7 @@ { struct tunnel *t; spa_list_for_each(t, &impl->tunnel_list, link) { - if (t->info.interface == info->interface && - t->info.protocol == info->protocol && - spa_streq(t->info.name, info->name) && - spa_streq(t->info.type, info->type) && - spa_streq(t->info.domain, info->domain)) + if (spa_streq(t->info.name, info->name)) return t; } return NULL; @@ -137,7 +125,12 @@ static void free_tunnel(struct tunnel *t) { - pw_impl_module_destroy(t->module); + spa_list_remove(&t->link); + if (t->module) + pw_impl_module_destroy(t->module); + free((char *) t->info.name); + + free(t); } static void impl_free(struct impl *impl) @@ -226,14 +219,8 @@ { struct tunnel *t = data; - spa_list_remove(&t->link); spa_hook_remove(&t->module_listener); - - free((char *) t->info.name); - free((char *) t->info.type); - free((char *) t->info.domain); - - free(t); + t->module = NULL; } static const struct pw_impl_module_events submodule_events = { @@ -264,11 +251,20 @@ avahi_strerror(avahi_client_errno(impl->client))); goto done; } - tinfo = TUNNEL_INFO(.interface = interface, - .protocol = protocol, - .name = name, - .type = type, - .domain = domain); + + tinfo = TUNNEL_INFO(.name = name); + + t = find_tunnel(impl, &tinfo); + if (t == NULL) + t = make_tunnel(impl, &tinfo); + if (t == NULL) { + pw_log_error("Can't make tunnel: %m"); + goto done; + } + if (t->module != NULL) { + pw_log_info("found duplicate mdns entry - skipping tunnel creation"); + goto done; + } props = pw_properties_new(NULL, NULL); if (props == NULL) { @@ -346,8 +342,6 @@ fprintf(f, "}"); fclose(f); - pw_properties_free(props); - pw_log_info("loading module args:'%s'", args); mod = pw_context_load_module(impl->context, "libpipewire-module-pulse-tunnel", @@ -359,19 +353,13 @@ goto done; } - t = make_tunnel(impl, &tinfo); - if (t == NULL) { - pw_log_error("Can't make tunnel: %m"); - pw_impl_module_destroy(mod); - goto done; - } - pw_impl_module_add_listener(mod, &t->module_listener, &submodule_events, t); t->module = mod; done: avahi_service_resolver_free(r); + pw_properties_free(props); } @@ -386,18 +374,16 @@ if (flags & AVAHI_LOOKUP_RESULT_LOCAL) return; - info = TUNNEL_INFO(.interface = interface, - .protocol = protocol, - .name = name, - .type = type, - .domain = domain); + info = TUNNEL_INFO(.name = name); t = find_tunnel(impl, &info); switch (event) { case AVAHI_BROWSER_NEW: - if (t != NULL) + if (t != NULL) { + pw_log_info("found duplicate mdns entry - skipping tunnel creation"); return; + } if (!(avahi_service_resolver_new(impl->client, interface, protocol, name, type, domain,
View file
pipewire-0.3.71.tar.gz/src/modules/spa/module-node-factory.c -> pipewire-0.3.72.tar.gz/src/modules/spa/module-node-factory.c
Changed
@@ -49,8 +49,100 @@ struct pw_resource *resource; struct spa_hook resource_listener; unsigned int linger:1; + + struct pw_core *core; + struct spa_hook core_listener; + struct spa_hook core_proxy_listener; + struct pw_proxy *proxy; + struct spa_hook proxy_listener; +}; + +static void proxy_removed(void *_data) +{ + struct node_data *nd = _data; + pw_log_debug("%p: removed", nd); + pw_proxy_destroy(nd->proxy); +} + +static void proxy_destroy(void *_data) +{ + struct node_data *nd = _data; + pw_log_debug("%p: destroy", nd); + spa_hook_remove(&nd->proxy_listener); + nd->proxy = NULL; + if (nd->node) + pw_impl_node_destroy(nd->node); +} + +static const struct pw_proxy_events proxy_events = { + PW_VERSION_PROXY_EVENTS, + .removed = proxy_removed, + .destroy = proxy_destroy, }; +static void core_error(void *data, uint32_t id, int seq, int res, const char *message) +{ + struct node_data *nd = data; + + pw_log_error("error id:%u seq:%d res:%d (%s): %s", + id, seq, res, spa_strerror(res), message); + + if (id == PW_ID_CORE && res == -EPIPE) + pw_impl_node_destroy(nd->node); +} + +static const struct pw_core_events core_events = { + PW_VERSION_CORE_EVENTS, + .error = core_error, +}; + +static void core_removed(void *d) +{ + struct node_data *nd = d; + pw_log_debug("%p: removed", nd); + spa_hook_remove(&nd->core_proxy_listener); + spa_hook_remove(&nd->core_listener); + nd->core = NULL; + if (nd->node) + pw_impl_node_destroy(nd->node); +} + +static const struct pw_proxy_events core_proxy_events = { + .removed = core_removed, +}; + +static int export_node(struct node_data *nd, struct pw_properties *props) +{ + const char *str; + + str = pw_properties_get(props, PW_KEY_REMOTE_NAME); + nd->core = pw_context_connect(nd->data->context, + pw_properties_new( + PW_KEY_REMOTE_NAME, str, + NULL), + 0); + if (nd->core == NULL) { + pw_log_error("can't connect: %m"); + return -errno; + } + pw_proxy_add_listener((struct pw_proxy*)nd->core, + &nd->core_proxy_listener, + &core_proxy_events, nd); + pw_core_add_listener(nd->core, + &nd->core_listener, + &core_events, nd); + + pw_log_debug("%p: export node %p", nd, nd->node); + nd->proxy = pw_core_export(nd->core, + PW_TYPE_INTERFACE_Node, NULL, nd->node, 0); + if (nd->proxy == NULL) + return -errno; + + pw_proxy_add_listener(nd->proxy, &nd->proxy_listener, &proxy_events, nd); + + return 0; +} + static void resource_destroy(void *data) { struct node_data *nd = data; @@ -78,6 +170,10 @@ spa_hook_remove(&nd->resource_listener); nd->resource = NULL; } + if (nd->core) { + pw_core_disconnect(nd->core); + nd->core = NULL; + } } static const struct pw_impl_node_events node_events = { @@ -145,6 +241,11 @@ pw_resource_add_listener(nd->resource, &nd->resource_listener, &resource_events, nd); } + if (pw_properties_get_bool(properties, PW_KEY_OBJECT_EXPORT, false)) { + res = export_node(nd, properties); + if (res < 0) + goto error_export; + } return node; error_properties: @@ -160,6 +261,10 @@ pw_resource_errorf_id(resource, new_id, res, "can't bind node"); pw_impl_node_destroy(node); goto error_exit; +error_export: + pw_resource_errorf_id(resource, new_id, res, "can't export node"); + pw_impl_node_destroy(node); + goto error_exit; error_exit_cleanup: pw_properties_free(properties);
View file
pipewire-0.3.71.tar.gz/src/pipewire/context.c -> pipewire-0.3.72.tar.gz/src/pipewire/context.c
Changed
@@ -478,6 +478,61 @@ spa_hook_list_append(&context->listener_list, listener, events, data); } +struct listener_data { + struct spa_hook *listener; + const struct pw_context_driver_events *events; + void *data; +}; + +static int +do_add_listener(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct pw_context *context = user_data; + const struct listener_data *d = data; + spa_hook_list_append(&context->driver_listener_list, + d->listener, d->events, d->data); + return 0; +} + +SPA_EXPORT +void pw_context_driver_add_listener(struct pw_context *context, + struct spa_hook *listener, + const struct pw_context_driver_events *events, + void *data) +{ + struct listener_data d = { + .listener = listener, + .events = events, + .data = data }; + struct pw_impl_node *n; + spa_list_for_each(n, &context->driver_list, driver_link) { + SPA_FLAG_SET(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER); + } + pw_loop_invoke(context->data_loop, + do_add_listener, SPA_ID_INVALID, &d, sizeof(d), false, context); +} + +static int do_remove_listener(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct spa_hook *listener = user_data; + spa_hook_remove(listener); + return 0; +} + +SPA_EXPORT +void pw_context_driver_remove_listener(struct pw_context *context, + struct spa_hook *listener) +{ + struct pw_impl_node *n; + spa_list_for_each(n, &context->driver_list, driver_link) { + SPA_FLAG_CLEAR(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER); + } + pw_loop_invoke(context->data_loop, + do_remove_listener, SPA_ID_INVALID, NULL, 0, true, listener); +} + SPA_EXPORT const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support) { @@ -1190,7 +1245,7 @@ /* clean up the flags first */ spa_list_for_each(n, &context->node_list, link) { n->visited = false; - n->runnable = n->always_process; + n->runnable = n->always_process && n->active; } get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &lim_quantum, &rate_quantum); @@ -1213,9 +1268,10 @@ collect_nodes(context, n, &collect); move_to_driver(context, &collect, n); } - /* from now on we are only interested in active driving nodes. - * We're going to see if there are active followers. */ - if (!n->driving || !n->active) + /* from now on we are only interested in active driving nodes + * with a driver_priority. We're going to see if there are + * active followers. */ + if (!n->driving || !n->active || n->priority_driver <= 0) continue; /* first active driving node is fallback */
View file
pipewire-0.3.71.tar.gz/src/pipewire/core.c -> pipewire-0.3.72.tar.gz/src/pipewire/core.c
Changed
@@ -479,7 +479,9 @@ int pw_core_disconnect(struct pw_core *core) { pw_log_debug("%p: disconnect", core); - pw_proxy_remove(&core->proxy); - pw_proxy_destroy(&core->proxy); + if (!core->removed) + pw_proxy_remove(&core->proxy); + if (!core->destroyed) + pw_proxy_destroy(&core->proxy); return 0; }
View file
pipewire-0.3.71.tar.gz/src/pipewire/extensions/client-node.h -> pipewire-0.3.72.tar.gz/src/pipewire/extensions/client-node.h
Changed
@@ -22,7 +22,7 @@ */ #define PW_TYPE_INTERFACE_ClientNode PW_TYPE_INFO_INTERFACE_BASE "ClientNode" -#define PW_VERSION_CLIENT_NODE 4 +#define PW_VERSION_CLIENT_NODE 5 struct pw_client_node; #define PW_EXTENSION_MODULE_CLIENT_NODE PIPEWIRE_MODULE_PREFIX "module-client-node"
View file
pipewire-0.3.71.tar.gz/src/pipewire/filter.c -> pipewire-0.3.72.tar.gz/src/pipewire/filter.c
Changed
@@ -151,6 +151,8 @@ unsigned int warn_mlock:1; unsigned int process_rt:1; unsigned int driving:1; + unsigned int trigger:1; + int in_emit_param_changed; }; static int get_param_index(uint32_t id) @@ -275,6 +277,8 @@ { struct param *p, *t; struct spa_list *param_list; + bool found = false; + int i, idx; if (port) param_list = &port->param_list; @@ -284,10 +288,42 @@ spa_list_for_each_safe(p, t, param_list, link) { if (id == SPA_ID_INVALID || (p->id == id && !(p->flags & PARAM_FLAG_LOCKED))) { + found = true; spa_list_remove(&p->link); free(p); } } + if (found) { + if (id == SPA_ID_INVALID) { + if (port) { + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + for (i = 0; i < N_PORT_PARAMS; i++) { + port->paramsi.flags &= ~SPA_PARAM_INFO_READ; + port->paramsi.user++; + } + } else { + impl->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + for (i = 0; i < N_NODE_PARAMS; i++) { + impl->paramsi.flags &= ~SPA_PARAM_INFO_READ; + impl->paramsi.user++; + } + } + } else { + if (port) { + if ((idx = get_port_param_index(id)) != -1) { + port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->paramsidx.flags &= ~SPA_PARAM_INFO_READ; + port->paramsidx.user++; + } + } else { + if ((idx = get_param_index(id)) != -1) { + impl->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + impl->paramsidx.flags &= ~SPA_PARAM_INFO_READ; + impl->paramsidx.user++; + } + } + } + } } static struct port *alloc_port(struct filter *filter, @@ -433,12 +469,19 @@ return enum_params(impl, &impl->param_list, seq, id, start, num, filter); } -static int impl_set_param(void *object, uint32_t id, uint32_t flags, const struct spa_pod *param) +static inline void emit_param_changed(struct filter *impl, void *port, + uint32_t id, const struct spa_pod *param) { - struct filter *impl = object; struct pw_filter *filter = &impl->this; + if (impl->in_emit_param_changed++ == 0) + pw_filter_emit_param_changed(filter, port, id, param); + impl->in_emit_param_changed--; +} - pw_filter_emit_param_changed(filter, NULL, id, param); +static int impl_set_param(void *object, uint32_t id, uint32_t flags, const struct spa_pod *param) +{ + struct filter *impl = object; + emit_param_changed(impl, NULL, id, param); return 0; } @@ -776,7 +819,6 @@ static int handle_latency(struct filter *impl, struct port *port, const struct spa_pod *param) { - struct pw_filter *filter = &impl->this; struct spa_latency_info info; int res; @@ -796,7 +838,7 @@ return 0; if (SPA_FLAG_IS_SET(impl->flags, PW_FILTER_FLAG_CUSTOM_LATENCY)) { - pw_filter_emit_param_changed(filter, port->user_data, + emit_param_changed(impl, port->user_data, SPA_PARAM_Latency, param); } else { default_latency(impl, port, info.direction); @@ -848,7 +890,7 @@ } if (emit) - pw_filter_emit_param_changed(filter, port->user_data, id, param); + emit_param_changed(impl, port->user_data, id, param); if (filter->state == PW_FILTER_STATE_ERROR) return filter->error_res; @@ -966,12 +1008,12 @@ static void call_process(struct filter *impl) { - pw_log_trace("%p: call process", impl); + pw_log_trace_fp("%p: call process", impl); if (SPA_FLAG_IS_SET(impl->flags, PW_FILTER_FLAG_RT_PROCESS)) { - spa_callbacks_call(&impl->rt_callbacks, struct pw_filter_events, - process, 0, impl->rt.position); - } - else { + if (impl->rt_callbacks.funcs) + spa_callbacks_call_fast(&impl->rt_callbacks, struct pw_filter_events, + process, 0, impl->rt.position); + } else { pw_loop_invoke(impl->main_loop, do_call_process, 1, NULL, 0, false, impl); } @@ -1000,6 +1042,7 @@ struct port *p; struct buffer *b; bool drained = true; + int res = 0; pw_log_trace_fp("%p: do process %p", impl, impl->rt.position); @@ -1041,6 +1084,7 @@ continue; if (p->direction == SPA_DIRECTION_INPUT) { + res |= SPA_STATUS_NEED_DATA; if (SPA_UNLIKELY(io->status != SPA_STATUS_HAVE_DATA)) continue; @@ -1053,17 +1097,21 @@ } io->status = SPA_STATUS_NEED_DATA; } else { - if (SPA_UNLIKELY(io->status == SPA_STATUS_HAVE_DATA)) + if (SPA_UNLIKELY(io->status == SPA_STATUS_HAVE_DATA)) { + res |= SPA_STATUS_HAVE_DATA; continue; + } if ((b = pop_queue(p, &p->queued)) != NULL) { pw_log_trace_fp("%p: pop %d %p", impl, b->id, io); io->buffer_id = b->id; io->status = SPA_STATUS_HAVE_DATA; + res |= SPA_STATUS_HAVE_DATA; drained = false; } else { io->buffer_id = SPA_ID_INVALID; io->status = SPA_STATUS_NEED_DATA; + res |= SPA_STATUS_NEED_DATA; } } } @@ -1071,7 +1119,7 @@ if (SPA_UNLIKELY(drained && impl->draining)) call_drained(impl); - return SPA_STATUS_NEED_DATA | SPA_STATUS_HAVE_DATA; + return res; } static const struct spa_node_methods impl_node = { @@ -1429,10 +1477,22 @@ free(impl); } +static int +do_remove_callbacks(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct filter *impl = user_data; + spa_zero(impl->rt_callbacks); + return 0; +} + static void hook_removed(struct spa_hook *hook) { struct filter *impl = hook->priv; - spa_zero(impl->rt_callbacks); + if (impl->data_loop) + pw_loop_invoke(impl->data_loop, do_remove_callbacks, 1, NULL, 0, true, impl); + else + spa_zero(impl->rt_callbacks); hook->priv = NULL; hook->removed = NULL; }
View file
pipewire-0.3.71.tar.gz/src/pipewire/filter.h -> pipewire-0.3.72.tar.gz/src/pipewire/filter.h
Changed
@@ -104,6 +104,11 @@ PW_FILTER_FLAG_CUSTOM_LATENCY = (1 << 3), /**< don't call the default latency algorithm * but emit the param_changed event for the * ports when Latency params are received. */ + PW_FILTER_FLAG_TRIGGER = (1 << 4), /**< the filter will not be scheduled + * automatically but _trigger_process() + * needs to be called. This can be used + * when the filter depends on processing + * of other filters. */ }; enum pw_filter_port_flags {
View file
pipewire-0.3.71.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.72.tar.gz/src/pipewire/impl-link.c
Changed
@@ -27,7 +27,6 @@ struct impl { struct pw_impl_link this; - unsigned int io_set:1; unsigned int activated:1; struct pw_work_queue *work; @@ -57,7 +56,7 @@ struct pw_node_peer *peer; spa_list_for_each(peer, &onode->peer_list, link) { - if (peer->target.node == inode) { + if (peer->target.id == inode->info.id) { pw_log_debug("exiting peer %p from %p to %p", peer, onode, inode); peer->ref++; return peer; @@ -70,10 +69,8 @@ peer->ref = 1; peer->output = onode; peer->active_count = 0; - peer->target.node = inode; - peer->target.activation = inode->rt.activation; - peer->target.system = inode->data_system; - peer->target.fd = inode->source.fd; + copy_target(&peer->target, &inode->rt.target); + peer->target.flags = PW_NODE_TARGET_PEER; spa_list_append(&onode->peer_list, &peer->link); pw_log_debug("new peer %p from %p to %p", peer, onode, inode); @@ -105,8 +102,8 @@ peer->target.active = true; } } - pw_log_trace("%p: node:%p state:%p pending:%d/%d", peer->output, - peer->target.node, state, state->pending, state->required); + pw_log_trace("%p: node:%s state:%p pending:%d/%d", peer->output, + peer->target.name, state, state->pending, state->required); } static void pw_node_peer_deactivate(struct pw_node_peer *peer) @@ -122,8 +119,8 @@ peer->target.active = false; } } - pw_log_trace("%p: node:%p state:%p pending:%d/%d", peer->output, - peer->target.node, state, state->pending, state->required); + pw_log_trace("%p: node:%s state:%p pending:%d/%d", peer->output, + peer->target.name, state, state->pending, state->required); } @@ -160,12 +157,16 @@ pw_link_state_as_string(state), error); if (state == PW_LINK_STATE_ERROR) { - pw_log_error("(%s) %s -> error (%s)", link->name, - pw_link_state_as_string(old), error); + pw_log_error("(%s) %s -> error (%s) (%s-%s)", link->name, + pw_link_state_as_string(old), error, + pw_impl_port_state_as_string(link->output->state), + pw_impl_port_state_as_string(link->input->state)); } else { - pw_log_info("(%s) %s -> %s", link->name, + pw_log_info("(%s) %s -> %s (%s-%s)", link->name, pw_link_state_as_string(old), - pw_link_state_as_string(state)); + pw_link_state_as_string(state), + pw_impl_port_state_as_string(link->output->state), + pw_impl_port_state_as_string(link->input->state)); } pw_impl_link_emit_state_changed(link, old, state, error); @@ -485,7 +486,6 @@ { int res = 0; - mix->io = data; pw_log_debug("%p: %s port %p %d.%d set io: %d %p %zd", this, pw_direction_as_string(port->direction), port, port->port_id, mix->port.port_id, id, data, size); @@ -641,15 +641,9 @@ bool async, uint32_t seq, const void *data, size_t size, void *user_data) { struct pw_impl_link *this = user_data; - pw_log_trace("%p: activate", this); - - spa_list_append(&this->output->rt.mix_list, &this->rt.out_mix.rt_link); - spa_list_append(&this->input->rt.mix_list, &this->rt.in_mix.rt_link); - if (this->peer) pw_node_peer_activate(this->peer); - return 0; } @@ -661,20 +655,21 @@ pw_log_debug("%p: activate activated:%d state:%s", this, impl->activated, pw_link_state_as_string(this->info.state)); - if (impl->activated || !this->prepared || + if (this->destroyed || impl->activated || !this->prepared || !impl->inode->runnable || !impl->onode->runnable) return 0; - if (!impl->io_set) { - if ((res = port_set_io(this, this->output, SPA_IO_Buffers, this->io, - sizeof(struct spa_io_buffers), &this->rt.out_mix)) < 0) - return res; + if ((res = port_set_io(this, this->input, SPA_IO_Buffers, this->io, + sizeof(struct spa_io_buffers), &this->rt.in_mix)) < 0) + return res; - if ((res = port_set_io(this, this->input, SPA_IO_Buffers, this->io, - sizeof(struct spa_io_buffers), &this->rt.in_mix)) < 0) - return res; - impl->io_set = true; + if ((res = port_set_io(this, this->output, SPA_IO_Buffers, this->io, + sizeof(struct spa_io_buffers), &this->rt.out_mix)) < 0) { + port_set_io(this, this->input, SPA_IO_Buffers, NULL, 0, + &this->rt.in_mix); + return res; } + pw_loop_invoke(this->output->node->data_loop, do_activate_link, SPA_ID_INVALID, NULL, 0, false, this); @@ -828,7 +823,7 @@ if (!impl->inode->active || !impl->onode->active) return 0; - if (this->preparing || this->prepared) + if (this->destroyed || this->preparing || this->prepared) return 0; this->preparing = true; @@ -844,15 +839,9 @@ bool async, uint32_t seq, const void *data, size_t size, void *user_data) { struct pw_impl_link *this = user_data; - - pw_log_trace("%p: disable %p and %p", this, &this->rt.in_mix, &this->rt.out_mix); - - spa_list_remove(&this->rt.out_mix.rt_link); - spa_list_remove(&this->rt.in_mix.rt_link); - + pw_log_trace("%p: disable out %p", this, &this->rt.out_mix); if (this->peer) pw_node_peer_deactivate(this->peer); - return 0; } @@ -873,11 +862,11 @@ port_set_io(this, this->input, SPA_IO_Buffers, NULL, 0, &this->rt.in_mix); - impl->io_set = false; impl->activated = false; pw_log_info("(%s) deactivated", this->name); - link_update_state(this, PW_LINK_STATE_PAUSED, 0, NULL); - + link_update_state(this, this->destroyed ? + PW_LINK_STATE_INIT : PW_LINK_STATE_PAUSED, + 0, NULL); return 0; } @@ -1306,9 +1295,9 @@ output_node, output->port_id, this->rt.out_mix.port.port_id, input_node, input->port_id, this->rt.in_mix.port.port_id); - this->name = spa_aprintf("%d.%d -> %d.%d", - output_node->info.id, output->port_id, - input_node->info.id, input->port_id); + this->name = spa_aprintf("%d.%d.%d -> %d.%d.%d", + output_node->info.id, output->port_id, this->rt.out_mix.port.port_id, + input_node->info.id, input->port_id, this->rt.in_mix.port.port_id); pw_log_info("(%s) (%s) -> (%s)", this->name, output_node->name, input_node->name); pw_impl_port_emit_link_added(output, this); @@ -1448,6 +1437,8 @@ pw_log_debug("%p: destroy", impl); pw_log_info("(%s) destroy", link->name); + + link->destroyed = true; pw_impl_link_emit_destroy(link); pw_impl_link_deactivate(link);
View file
pipewire-0.3.71.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.72.tar.gz/src/pipewire/impl-node.c
Changed
@@ -41,8 +41,6 @@ unsigned int cache_params:1; unsigned int pending_play:1; - - uint64_t prev_signal_time; }; #define pw_node_resource(r,m,v,...) pw_resource_call(r,struct pw_node_events,m,v,__VA_ARGS__) @@ -89,21 +87,18 @@ return; pw_log_trace("%p: add to driver %p %p %p", this, driver, - driver->rt.activation, this->rt.activation); + driver->rt.target.activation, this->rt.target.activation); /* let the driver trigger us as part of the processing cycle */ spa_list_append(&driver->rt.target_list, &this->rt.target.link); - nstate = &this->rt.activation->state0; + nstate = &this->rt.target.activation->state0; if (!this->rt.target.active) { nstate->required++; this->rt.target.active = true; } /* trigger the driver when we complete */ - this->rt.driver_target.activation = driver->rt.activation; - this->rt.driver_target.node = driver; - this->rt.driver_target.system = driver->data_system; - this->rt.driver_target.fd = driver->source.fd; + copy_target(&this->rt.driver_target, &driver->rt.target); spa_list_append(&this->rt.target_list, &this->rt.driver_target.link); /* now increment the required states of all this node targets, including @@ -129,13 +124,13 @@ if (this->exported) return; - pw_log_trace("%p: remove from driver %p %p %p", - this, this->rt.driver_target.node, - this->rt.driver_target.activation, this->rt.activation); + pw_log_trace("%p: remove from driver %s %p %p", + this, this->rt.driver_target.name, + this->rt.driver_target.activation, this->rt.target.activation); spa_list_remove(&this->rt.target.link); - nstate = &this->rt.activation->state0; + nstate = &this->rt.target.activation->state0; if (this->rt.target.active) { nstate->required--; this->rt.target.active = false; @@ -153,7 +148,7 @@ } spa_list_remove(&this->rt.driver_target.link); - this->rt.driver_target.node = NULL; + spa_zero(this->rt.driver_target); } static int @@ -707,27 +702,31 @@ static void update_io(struct pw_impl_node *node) { + struct pw_node_target *t = &node->rt.target; + pw_log_debug("%p: id:%d", node, node->info.id); if (spa_node_set_io(node->node, SPA_IO_Position, - &node->rt.activation->position, + &t->activation->position, sizeof(struct spa_io_position)) >= 0) { - pw_log_debug("%p: set position %p", node, &node->rt.activation->position); - node->rt.position = &node->rt.activation->position; + pw_log_debug("%p: set position %p", node, &t->activation->position); + node->rt.position = &t->activation->position; node->target_rate = node->rt.position->clock.target_rate; node->target_quantum = node->rt.position->clock.target_duration; node->target_pending = false; + + pw_impl_node_emit_peer_added(node, node); } else if (node->driver) { pw_log_warn("%p: can't set position on driver", node); } if (spa_node_set_io(node->node, SPA_IO_Clock, - &node->rt.activation->position.clock, + &t->activation->position.clock, sizeof(struct spa_io_clock)) >= 0) { - pw_log_debug("%p: set clock %p", node, &node->rt.activation->position.clock); - node->rt.clock = &node->rt.activation->position.clock; + pw_log_debug("%p: set clock %p", node, &t->activation->position.clock); + node->rt.clock = &t->activation->position.clock; } } @@ -778,9 +777,10 @@ insert_driver(context, this); this->registered = true; - this->rt.activation->position.clock.id = this->global->id; + this->rt.target.activation->position.clock.id = this->global->id; this->info.id = this->global->id; + this->rt.target.id = this->info.id; pw_properties_setf(this->properties, PW_KEY_OBJECT_ID, "%d", this->info.id); pw_properties_setf(this->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64, pw_global_get_serial(this->global)); @@ -830,8 +830,8 @@ pw_log_trace("%p: driver:%p->%p", node, node->driver_node, driver); - pw_log_trace("%p: set position %p", node, &driver->rt.activation->position); - node->rt.position = &driver->rt.activation->position; + pw_log_trace("%p: set position %p", node, &driver->rt.target.activation->position); + node->rt.position = &driver->rt.target.activation->position; node->target_rate = node->rt.position->clock.target_rate; node->target_quantum = node->rt.position->clock.target_duration; @@ -845,7 +845,7 @@ static void remove_segment_owner(struct pw_impl_node *driver, uint32_t node_id) { - struct pw_node_activation *a = driver->rt.activation; + struct pw_node_activation *a = driver->rt.target.activation; ATOMIC_CAS(a->segment_owner0, node_id, 0); ATOMIC_CAS(a->segment_owner1, node_id, 0); } @@ -890,7 +890,7 @@ if ((res = spa_node_set_io(node->node, SPA_IO_Position, - &driver->rt.activation->position, + &driver->rt.target.activation->position, sizeof(struct spa_io_position))) < 0) { pw_log_debug("%p: set position: %s", node, spa_strerror(res)); } @@ -901,6 +901,9 @@ pw_impl_node_emit_driver_changed(node, old, driver); + pw_impl_node_emit_peer_added(driver, node); + pw_impl_node_emit_peer_removed(old, node); + return 0; } @@ -922,6 +925,7 @@ (node->name == NULL || !spa_streq(node->name, str))) { free(node->name); node->name = strdup(str); + snprintf(node->rt.target.name, sizeof(node->rt.target.name), "%s", node->name); pw_log_debug("%p: name '%s'", node, node->name); } @@ -950,9 +954,9 @@ if (trigger != node->trigger) { node->trigger = trigger; if (trigger) - node->rt.activation->state0.required++; + node->rt.target.activation->state0.required++; else - node->rt.activation->state0.required--; + node->rt.target.activation->state0.required--; } /* group defines what nodes are scheduled together */ @@ -1077,27 +1081,40 @@ return "unknown"; } -static void dump_states(struct pw_impl_node *driver) +static void update_xrun_stats(struct pw_node_activation *a, uint64_t trigger, uint64_t delay) +{ + a->xrun_count++; + a->xrun_time = trigger; + a->xrun_delay = delay; + a->max_delay = SPA_MAX(a->max_delay, delay); +} + +static void check_states(struct pw_impl_node *driver, uint64_t nsec) { struct pw_node_target *t; - struct pw_node_activation *na = driver->rt.activation; + 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; + + if (ratelimit_test(&driver->rt.rate_limit, nsec, SPA_LOG_LEVEL_DEBUG)) + level = SPA_LOG_LEVEL_INFO; spa_list_for_each(t, &driver->rt.target_list, link) { struct pw_node_activation *a = t->activation; struct pw_node_activation_state *state = &a->state0; - if (t->node == NULL) - continue; +
View file
pipewire-0.3.71.tar.gz/src/pipewire/impl-port.c -> pipewire-0.3.72.tar.gz/src/pipewire/impl-port.c
Changed
@@ -27,6 +27,7 @@ struct impl { struct pw_impl_port this; struct spa_node mix_node; /**< mix node implementation */ + struct spa_list mix_list; struct spa_list param_list; struct spa_list pending_list; @@ -69,7 +70,7 @@ port->info.change_mask = 0; } -static const char *port_state_as_string(enum pw_impl_port_state state) +const char *pw_impl_port_state_as_string(enum pw_impl_port_state state) { switch (state) { case PW_IMPL_PORT_STATE_ERROR: @@ -100,7 +101,8 @@ pw_log(state == PW_IMPL_PORT_STATE_ERROR ? SPA_LOG_LEVEL_ERROR : SPA_LOG_LEVEL_DEBUG, "%p: state %s -> %s (%s)", port, - port_state_as_string(old), port_state_as_string(state), error); + pw_impl_port_state_as_string(old), + pw_impl_port_state_as_string(state), error); pw_impl_port_emit_state_changed(port, old, state, error); @@ -111,6 +113,72 @@ } } +static struct pw_impl_port_mix *find_mix(struct pw_impl_port *port, + enum spa_direction direction, uint32_t port_id) +{ + struct pw_impl_port_mix *mix; + spa_list_for_each(mix, &port->mix_list, link) { + if (mix->port.direction == direction && mix->port.port_id == port_id) + return mix; + } + return NULL; +} + +static int +do_add_mix(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct pw_impl_port_mix *mix = user_data; + struct pw_impl_port *this = mix->p; + struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this); + pw_log_trace("%p: add mix %p", this, mix); + if (!mix->active) { + spa_list_append(&impl->mix_list, &mix->rt_link); + mix->active = true; + } + return 0; +} + +static int +do_remove_mix(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct pw_impl_port_mix *mix = user_data; + struct pw_impl_port *this = mix->p; + pw_log_trace("%p: remove mix %p", this, mix); + if (mix->active) { + spa_list_remove(&mix->rt_link); + mix->active = false; + } + return 0; +} + +static int port_set_io(void *object, + enum spa_direction direction, uint32_t port_id, uint32_t id, + void *data, size_t size) +{ + struct impl *impl = object; + struct pw_impl_port *this = &impl->this; + struct pw_impl_port_mix *mix; + + mix = find_mix(this, direction, port_id); + if (mix == NULL) + return -ENOENT; + + if (id == SPA_IO_Buffers) { + if (data == NULL || size == 0) { + pw_loop_invoke(this->node->data_loop, + do_remove_mix, SPA_ID_INVALID, NULL, 0, true, mix); + mix->io = NULL; + } else if (data != NULL && size >= sizeof(struct spa_io_buffers)) { + mix->io = data; + pw_loop_invoke(this->node->data_loop, + do_add_mix, SPA_ID_INVALID, NULL, 0, false, mix); + } + } + return 0; +} + static int tee_process(void *object) { struct impl *impl = object; @@ -119,7 +187,7 @@ struct spa_io_buffers *io = &this->rt.io; pw_log_trace_fp("%p: tee input %d %d", this, io->status, io->buffer_id); - spa_list_for_each(mix, &this->rt.mix_list, rt_link) { + spa_list_for_each(mix, &impl->mix_list, rt_link) { pw_log_trace_fp("%p: port %d %p->%p %d", this, mix->port.port_id, io, mix->io, mix->io->buffer_id); *mix->io = *io; @@ -136,13 +204,13 @@ pw_log_trace_fp("%p: tee reuse buffer %d %d", this, port_id, buffer_id); spa_node_port_reuse_buffer(this->node->node, this->port_id, buffer_id); - return 0; } static const struct spa_node_methods schedule_tee_node = { SPA_VERSION_NODE_METHODS, .process = tee_process, + .port_set_io = port_set_io, .port_reuse_buffer = tee_reuse_buffer, }; @@ -156,7 +224,7 @@ if (SPA_UNLIKELY(PW_IMPL_PORT_IS_CONTROL(this))) return SPA_STATUS_HAVE_DATA | SPA_STATUS_NEED_DATA; - spa_list_for_each(mix, &this->rt.mix_list, rt_link) { + spa_list_for_each(mix, &impl->mix_list, rt_link) { pw_log_trace_fp("%p: mix input %d %p->%p %d %d", this, mix->port.port_id, mix->io, io, mix->io->status, mix->io->buffer_id); *io = *mix->io; @@ -169,11 +237,10 @@ static int schedule_mix_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id) { struct impl *impl = object; - struct pw_impl_port *this = &impl->this; struct pw_impl_port_mix *mix; - spa_list_for_each(mix, &this->rt.mix_list, rt_link) { - pw_log_trace_fp("%p: reuse buffer %d %d", this, port_id, buffer_id); + spa_list_for_each(mix, &impl->mix_list, rt_link) { + pw_log_trace_fp("%p: reuse buffer %d %d", impl, port_id, buffer_id); /* FIXME send reuse buffer to peer */ break; } @@ -183,6 +250,7 @@ static const struct spa_node_methods schedule_mix_node = { SPA_VERSION_NODE_METHODS, .process = schedule_mix_input, + .port_set_io = port_set_io, .port_reuse_buffer = schedule_mix_reuse_buffer, }; @@ -263,6 +331,9 @@ res = pw_impl_port_call_release_mix(port, mix); + if (port->destroying) + return res; + if ((res = spa_node_remove_port(port->mix, port->direction, port_id)) < 0 && res != -ENOTSUP) pw_log_warn("can't remove mix port %d: %s", port_id, spa_strerror(res)); @@ -276,6 +347,8 @@ port->direction, port->port_id, SPA_IO_Buffers, NULL, sizeof(port->rt.io)); + + pw_impl_port_set_param(port, SPA_PARAM_Format, 0, NULL); } return res; } @@ -472,8 +545,10 @@ spa_list_init(&impl->param_list); spa_list_init(&impl->pending_list); impl->cache_params = true; + spa_list_init(&impl->mix_list); this = &impl->this; + pw_log_debug("%p: new %s %d", this, pw_direction_as_string(direction), port_id); @@ -512,7 +587,6 @@ spa_list_init(&this->links); spa_list_init(&this->mix_list); - spa_list_init(&this->rt.mix_list); spa_list_init(&this->control_list0); spa_list_init(&this->control_list1); @@ -1643,7 +1717,7 @@ int res = 0, res2; pw_log_debug("%p: %d:%d.%d: %d buffers flags:%d state:%d n_mix:%d", port, - port->direction, port->port_id, mix->id, + port->direction, port->port_id, mix->port.port_id, n_buffers, flags, port->state, port->n_mix);
View file
pipewire-0.3.71.tar.gz/src/pipewire/impl-port.h -> pipewire-0.3.72.tar.gz/src/pipewire/impl-port.h
Changed
@@ -98,6 +98,9 @@ /** Get the port id */ uint32_t pw_impl_port_get_id(struct pw_impl_port *port); +/** Get the port state as a string */ +const char *pw_impl_port_state_as_string(enum pw_impl_port_state state); + /** Get the port parent node or NULL when not yet set */ struct pw_impl_node *pw_impl_port_get_node(struct pw_impl_port *port);
View file
pipewire-0.3.71.tar.gz/src/pipewire/introspect.c -> pipewire-0.3.72.tar.gz/src/pipewire/introspect.c
Changed
@@ -212,6 +212,7 @@ } info->n_params = n_params; for (; i < info->n_params; i++) { + spa_zero(info->paramsi); info->paramsi.id = update->paramsi.id; info->paramsi.flags = update->paramsi.flags; info->paramsi.user = 1; @@ -285,6 +286,7 @@ } info->n_params = n_params; for (; i < info->n_params; i++) { + spa_zero(info->paramsi); info->paramsi.id = update->paramsi.id; info->paramsi.flags = update->paramsi.flags; info->paramsi.user = 1; @@ -448,6 +450,7 @@ } info->n_params = n_params; for (; i < info->n_params; i++) { + spa_zero(info->paramsi); info->paramsi.id = update->paramsi.id; info->paramsi.flags = update->paramsi.flags; info->paramsi.user = 1;
View file
pipewire-0.3.71.tar.gz/src/pipewire/keys.h -> pipewire-0.3.72.tar.gz/src/pipewire/keys.h
Changed
@@ -52,7 +52,8 @@ #define PW_KEY_OBJECT_LINGER "object.linger" /**< the object lives on even after the client * that created it has been destroyed */ #define PW_KEY_OBJECT_REGISTER "object.register" /**< If the object should be registered. */ - +#define PW_KEY_OBJECT_EXPORT "object.export" /**< If the object should be exported, + * since 0.3.72 */ /* config */ #define PW_KEY_CONFIG_PREFIX "config.prefix" /**< a config prefix directory */
View file
pipewire-0.3.71.tar.gz/src/pipewire/private.h -> pipewire-0.3.72.tar.gz/src/pipewire/private.h
Changed
@@ -423,6 +423,13 @@ void (*complete) (void *data, struct pw_impl_node *node); }; +void pw_context_driver_add_listener(struct pw_context *context, + struct spa_hook *listener, + const struct pw_context_driver_events *events, + void *data); +void pw_context_driver_remove_listener(struct pw_context *context, + struct spa_hook *listener); + #define pw_registry_resource(r,m,v,...) pw_resource_call(r, struct pw_registry_events,m,v,##__VA_ARGS__) #define pw_registry_resource_global(r,...) pw_registry_resource(r,global,0,__VA_ARGS__) #define pw_registry_resource_global_remove(r,...) pw_registry_resource(r,global_remove,0,__VA_ARGS__) @@ -584,6 +591,11 @@ struct pw_node_target { struct spa_list link; +#define PW_NODE_TARGET_NONE 0 +#define PW_NODE_TARGET_PEER 1 + uint32_t flags; + uint32_t id; + char name128; struct pw_impl_node *node; struct pw_node_activation *activation; struct spa_system *system; @@ -591,6 +603,16 @@ unsigned int active:1; }; +static inline void copy_target(struct pw_node_target *dst, const struct pw_node_target *src) +{ + dst->id = src->id; + memcpy(dst->name, src->name, sizeof(dst->name)); + dst->node = src->node; + dst->activation = src->activation; + dst->system = src->system; + dst->fd = src->fd; +} + struct pw_node_activation { #define PW_NODE_ACTIVATION_NOT_TRIGGERED 0 #define PW_NODE_ACTIVATION_TRIGGERED 1 @@ -616,9 +638,13 @@ * used when driver segment_owner has this node id */ /* for drivers, shared with all nodes */ - uint32_t segment_owner32; /* id of owners for each segment info struct. + uint32_t segment_owner16; /* id of owners for each segment info struct. * nodes that want to update segment info need to * CAS their node id in this array. */ + uint32_t padding15; +#define PW_NODE_ACTIVATION_FLAG_NONE 0 +#define PW_NODE_ACTIVATION_FLAG_PROFILER (1<<0) /* the profiler is running */ + uint32_t flags; /* extra flags */ struct spa_io_position position; /* contains current position and segment info. * extra info is updated by nodes that have set * themselves as owner in the segment structs */ @@ -764,7 +790,6 @@ struct { struct spa_io_clock *clock; /**< io area of the clock or NULL */ struct spa_io_position *position; - struct pw_node_activation *activation; struct spa_list target_list; /* list of targets to signal after * this node */ @@ -781,6 +806,8 @@ struct spa_fraction target_rate; uint64_t target_quantum; + uint64_t driver_start; + void *user_data; /**< extra user data */ }; @@ -796,6 +823,7 @@ uint32_t id; uint32_t peer_id; unsigned int have_buffers:1; + unsigned int active:1; }; struct pw_impl_port_implementation { @@ -884,8 +912,6 @@ struct { struct spa_io_buffers io; /**< io area of the port */ - struct spa_io_clock clock; /**< io area of the clock */ - struct spa_list mix_list; struct spa_list node_link; } rt; /**< data only accessed from the data thread */ unsigned int added:1; @@ -964,6 +990,7 @@ unsigned int preparing:1; unsigned int prepared:1; unsigned int passive:1; + unsigned int destroyed:1; }; #define pw_resource_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_resource_events, m, v, ##__VA_ARGS__)
View file
pipewire-0.3.71.tar.gz/src/pipewire/properties.c -> pipewire-0.3.72.tar.gz/src/pipewire/properties.c
Changed
@@ -706,8 +706,11 @@ if (value == NULL || len == 0) { fprintf(file, "%snull%s", LITERAL(c), NORMAL(c)); } else if (spa_json_is_container(value, len) && !c->recurse) { - len = spa_json_container_len(it, value, len); - fprintf(file, "%s%.*s%s", CONTAINER(c), len, value, NORMAL(c)); + spa_json_enter_container(it, &sub, value0); + if (spa_json_container_len(&sub, value, len) == len) + fprintf(file, "%s%.*s%s", CONTAINER(c), len, value, NORMAL(c)); + else + encode_string(c, STRING(c), value, len, NORMAL(c)); } else if (spa_json_is_array(value, len)) { fprintf(file, ""); spa_json_enter(it, &sub); @@ -782,15 +785,11 @@ fprintf(f, "%s%s%s: ", KEY(c), key, NORMAL(c)); } value = it->value; - len = value ? strlen(value) : 0; spa_json_init(&sub, value, len); - if ((len = spa_json_next(&sub, &value)) < 0) + if (c->recurse && spa_json_next(&sub, &value) < 0) break; - if (!spa_json_is_container(value, len)) - len = value ? strlen(value) : 0; - dump(c, c->indent, &sub, value, len); count++; }
View file
pipewire-0.3.71.tar.gz/src/pipewire/stream.c -> pipewire-0.3.72.tar.gz/src/pipewire/stream.c
Changed
@@ -158,6 +158,7 @@ unsigned int using_trigger:1; unsigned int trigger:1; int in_set_param; + int in_emit_param_changed; }; static int get_param_index(uint32_t id) @@ -268,14 +269,42 @@ static void clear_params(struct stream *impl, uint32_t id) { struct param *p, *t; + bool found = false; + int i, idx; spa_list_for_each_safe(p, t, &impl->param_list, link) { if (id == SPA_ID_INVALID || (p->id == id && !(p->flags & PARAM_FLAG_LOCKED))) { + found = true; spa_list_remove(&p->link); free(p); } } + if (found) { + if (id == SPA_ID_INVALID) { + impl->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + for (i = 0; i < N_NODE_PARAMS; i++) { + impl->paramsi.flags &= ~SPA_PARAM_INFO_READ; + impl->paramsi.user++; + } + impl->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + for (i = 0; i < N_PORT_PARAMS; i++) { + impl->port_paramsi.flags &= ~SPA_PARAM_INFO_READ; + impl->port_paramsi.user++; + } + } else { + if ((idx = get_param_index(id)) != -1) { + impl->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + impl->paramsidx.flags &= ~SPA_PARAM_INFO_READ; + impl->paramsidx.user++; + } + if ((idx = get_port_param_index(id)) != -1) { + impl->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + impl->port_paramsidx.flags &= ~SPA_PARAM_INFO_READ; + impl->port_paramsidx.user++; + } + } + } } static int update_params(struct stream *impl, uint32_t id, @@ -424,13 +453,16 @@ static inline void call_process(struct stream *impl) { pw_log_trace_fp("%p: call process rt:%u", impl, impl->process_rt); - if (impl->direction == SPA_DIRECTION_OUTPUT && update_requested(impl) <= 0) + if (impl->n_buffers == 0 || + (impl->direction == SPA_DIRECTION_OUTPUT && update_requested(impl) <= 0)) return; - if (impl->process_rt) - spa_callbacks_call(&impl->rt_callbacks, struct pw_stream_events, process, 0); - else + if (impl->process_rt) { + if (impl->rt_callbacks.funcs) + spa_callbacks_call_fast(&impl->rt_callbacks, struct pw_stream_events, process, 0); + } else { pw_loop_invoke(impl->main_loop, do_call_process, 1, NULL, 0, false, impl); + } } static int @@ -561,16 +593,24 @@ return enum_params(object, false, seq, id, start, num, filter); } +static inline void emit_param_changed(struct stream *impl, + uint32_t id, const struct spa_pod *param) +{ + struct pw_stream *stream = &impl->this; + if (impl->in_emit_param_changed++ == 0) + pw_stream_emit_param_changed(stream, id, param); + impl->in_emit_param_changed--; +} + static int impl_set_param(void *object, uint32_t id, uint32_t flags, const struct spa_pod *param) { struct stream *impl = object; - struct pw_stream *stream = &impl->this; if (id != SPA_PARAM_Props) return -ENOTSUP; if (impl->in_set_param == 0) - pw_stream_emit_param_changed(stream, id, param); + emit_param_changed(impl, id, param); return 0; } @@ -883,7 +923,7 @@ break; } - pw_stream_emit_param_changed(stream, id, param); + emit_param_changed(impl, id, param); if (stream->state == PW_STREAM_STATE_ERROR) return stream->error_res; @@ -996,12 +1036,15 @@ /* push new buffer */ pw_log_trace_fp("%p: push %d %p", stream, b->id, io); if (queue_push(impl, &impl->dequeued, b) == 0) { - copy_position(impl, impl->dequeued.incount); if (b->busy) ATOMIC_INC(b->busy->count); - call_process(impl); } } + if (!queue_is_empty(impl, &impl->dequeued)) { + copy_position(impl, impl->dequeued.incount); + call_process(impl); + } + if (io->status != SPA_STATUS_NEED_DATA || io->buffer_id == SPA_ID_INVALID) { /* pop buffer to recycle */ if ((b = queue_pop(impl, &impl->queued))) { @@ -1342,8 +1385,10 @@ static void node_event_destroy(void *data) { struct pw_stream *stream = data; + struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); spa_hook_remove(&stream->node_listener); stream->node = NULL; + impl->data_loop = NULL; } static void node_event_info(void *data, const struct pw_node_info *info) @@ -1515,7 +1560,7 @@ impl->allow_mlock = context->settings.mem_allow_mlock; impl->warn_mlock = context->settings.mem_warn_mlock; - spa_hook_list_append(&impl->context->driver_listener_list, + pw_context_driver_add_listener(impl->context, &impl->context_listener, &context_events, impl); return impl; @@ -1683,7 +1728,8 @@ spa_hook_list_clean(&impl->hooks); spa_hook_list_clean(&stream->listener_list); - spa_hook_remove(&impl->context_listener); + pw_context_driver_remove_listener(impl->context, + &impl->context_listener); if (impl->data.context) pw_context_destroy(impl->data.context); @@ -1692,10 +1738,22 @@ free(impl); } +static int +do_remove_callbacks(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct stream *impl = user_data; + spa_zero(impl->rt_callbacks); + return 0; +} + static void hook_removed(struct spa_hook *hook) { struct stream *impl = hook->priv; - spa_zero(impl->rt_callbacks); + if (impl->data_loop) + pw_loop_invoke(impl->data_loop, do_remove_callbacks, 1, NULL, 0, true, impl); + else + spa_zero(impl->rt_callbacks); hook->priv = NULL; hook->removed = NULL; } @@ -1953,10 +2011,12 @@ /* XXX this is deprecated but still used by the portal and its apps */ pw_properties_setf(stream->properties, PW_KEY_NODE_TARGET, "%d", target_id); - if ((flags & PW_STREAM_FLAG_AUTOCONNECT) && + if ((str = getenv("PIPEWIRE_AUTOCONNECT")) != NULL) + pw_properties_set(stream->properties, + PW_KEY_NODE_AUTOCONNECT, spa_atob(str) ? "true" : "false"); + else if ((flags & PW_STREAM_FLAG_AUTOCONNECT) && pw_properties_get(stream->properties, PW_KEY_NODE_AUTOCONNECT) == NULL) { - str = getenv("PIPEWIRE_AUTOCONNECT"); - pw_properties_set(stream->properties, PW_KEY_NODE_AUTOCONNECT, str ? str : "true"); + pw_properties_set(stream->properties, PW_KEY_NODE_AUTOCONNECT, "true"); } if (flags & PW_STREAM_FLAG_DRIVER) pw_properties_set(stream->properties, PW_KEY_NODE_DRIVER, "true"); @@ -2471,7 +2531,7 @@ struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); int res = 0;
View file
pipewire-0.3.71.tar.gz/src/pipewire/stream.h -> pipewire-0.3.72.tar.gz/src/pipewire/stream.h
Changed
@@ -151,6 +151,9 @@ * * \section sec_stream_environment Environment Variables * + * The environment variable PIPEWIRE_AUTOCONNECT can be used to override the + * flag and force apps to autoconnect or not. + * */ /** \defgroup pw_stream Stream *
View file
pipewire-0.3.71.tar.gz/src/pipewire/thread-loop.c -> pipewire-0.3.72.tar.gz/src/pipewire/thread-loop.c
Changed
@@ -50,7 +50,7 @@ { int res; if ((res = pthread_mutex_lock(&this->lock)) != 0) - pw_log_error("%p: thread:%lu: %s", this, pthread_self(), strerror(res)); + pw_log_error("%p: thread:%p: %s", this, (void *) pthread_self(), strerror(res)); else this->recurse++; return -res; @@ -62,7 +62,7 @@ spa_return_val_if_fail(this->recurse > 0, -EIO); this->recurse--; if ((res = pthread_mutex_unlock(&this->lock)) != 0) { - pw_log_error("%p: thread:%lu: %s", this, pthread_self(), strerror(res)); + pw_log_error("%p: thread:%p: %s", this, (void *) pthread_self(), strerror(res)); this->recurse++; } return -res; @@ -97,13 +97,13 @@ /* if lock taken by something else, error */ if ((res = pthread_mutex_trylock(&this->lock)) != 0) { - pw_log_debug("%p: thread:%lu: %s", this, pthread_self(), strerror(res)); + pw_log_debug("%p: thread:%p: %s", this, (void *) pthread_self(), strerror(res)); return -res; } /* we could take the lock, check if we actually locked it somewhere */ res = this->recurse > 0 ? 1 : -EPERM; if (res < 0) - pw_log_debug("%p: thread:%lu: recurse:%d", this, pthread_self(), this->recurse); + pw_log_debug("%p: thread:%p: recurse:%d", this, (void *) pthread_self(), this->recurse); pthread_mutex_unlock(&this->lock); return res; } @@ -398,7 +398,7 @@ while (loop->n_waiting_for_accept > 0) { int res; if ((res = pthread_cond_wait(&loop->accept_cond, &loop->lock)) != 0) - pw_log_error("%p: thread:%lu: %s", loop, pthread_self(), strerror(res)); + pw_log_error("%p: thread:%p: %s", loop, (void *) pthread_self(), strerror(res)); } } } @@ -418,7 +418,7 @@ loop->n_waiting++; loop->recurse--; if ((res = pthread_cond_wait(&loop->cond, &loop->lock)) != 0) - pw_log_error("%p: thread:%lu: %s", loop, pthread_self(), strerror(res)); + pw_log_error("%p: thread:%p: %s", loop, (void *) pthread_self(), strerror(res)); loop->recurse++; loop->n_waiting--; pw_log_trace("%p, waiting done %d", loop, loop->n_waiting);
View file
pipewire-0.3.71.tar.gz/src/tools/pw-top.c -> pipewire-0.3.72.tar.gz/src/tools/pw-top.c
Changed
@@ -22,6 +22,8 @@ #define MAX_FORMAT 16 #define MAX_NAME 128 +#define XRUN_INVALID (uint32_t)-1 + struct driver { int64_t count; float cpu_load3; @@ -38,6 +40,7 @@ int64_t awake; int64_t finish; struct spa_fraction latency; + uint32_t xrun_count; }; struct node { @@ -49,8 +52,6 @@ struct measurement measurement; struct driver info; struct node *driver; - uint32_t errors; - int32_t last_error_status; uint32_t generation; char formatMAX_FORMAT+1; struct pw_proxy *proxy; @@ -319,6 +320,7 @@ int res; spa_zero(m); + m.xrun_count = XRUN_INVALID; if ((res = spa_pod_parse_struct(pod, SPA_POD_Int(&id), SPA_POD_String(&name), @@ -327,7 +329,8 @@ SPA_POD_Long(&m.awake), SPA_POD_Long(&m.finish), SPA_POD_Int(&m.status), - SPA_POD_Fraction(&m.latency))) < 0) + SPA_POD_Fraction(&m.latency), + SPA_POD_OPT_Int(&m.xrun_count))) < 0) return res; if ((n = find_node(d, id)) == NULL) @@ -338,12 +341,6 @@ n->info = point->info; point->driver = n; n->generation = d->generation; - - if (m.status != 3) { - n->errors++; - if (n->last_error_status == -1) - n->last_error_status = m.status; - } return 0; } @@ -356,6 +353,7 @@ int res; spa_zero(m); + m.xrun_count = XRUN_INVALID; if ((res = spa_pod_parse_struct(pod, SPA_POD_Int(&id), SPA_POD_String(&name), @@ -364,7 +362,8 @@ SPA_POD_Long(&m.awake), SPA_POD_Long(&m.finish), SPA_POD_Int(&m.status), - SPA_POD_Fraction(&m.latency))) < 0) + SPA_POD_Fraction(&m.latency), + SPA_POD_OPT_Int(&m.xrun_count))) < 0) return res; if ((n = find_node(d, id)) == NULL) @@ -376,11 +375,6 @@ d->pending_refresh = true; } n->generation = d->generation; - if (m.status != 3) { - n->errors++; - if (n->last_error_status == -1) - n->last_error_status = m.status; - } return 0; } @@ -476,7 +470,8 @@ print_time(buf2, active, 64, busy), print_perc(buf3, active, 64, waiting, quantum), print_perc(buf4, active, 64, busy, quantum), - i->xrun_count + n->errors, + n->measurement.xrun_count == XRUN_INVALID ? + i->xrun_count : n->measurement.xrun_count, active ? n->format : "", n->driver == n ? "" : " + ", n->name); @@ -487,8 +482,6 @@ n->driver = n; spa_zero(n->measurement); spa_zero(n->info); - n->errors = 0; - n->last_error_status = 0; } static void do_refresh(struct data *d)
View file
pipewire-0.3.71.tar.gz/test/test-logger.c -> pipewire-0.3.72.tar.gz/test/test-logger.c
Changed
@@ -504,7 +504,7 @@ } sd_journal_seek_tail(journal); - sd_journal_next(journal); + sd_journal_previous(journal); spa_scnprintf(token, sizeof(token), "MARK %s:%d", __func__, __LINE__); spa_logt_info(iface, &topic, "%s", token); @@ -572,7 +572,7 @@ } sd_journal_seek_tail(journal); - sd_journal_next(journal); + sd_journal_previous(journal); spa_scnprintf(token, sizeof(token), "MARK %s:%d", __func__, __LINE__);
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
.