Instead of aligning the buffers to 16 bytes, use the CPU max_align
value (32 on intel).
Move the mix function from a static global variable to a per client
member because this could change per client.
The bar can start from 0 in JACK.
Add bar_start_tick and ticks_per_beat to the io_segment_bar so that we
can losslesly store the complete jack BBT values.
See #4314
This gets the next key and value from an object. This function is better
because it will skip key/value pairs that don't fit in the array to hold
the key.
The previous code patter would stop parsing the object as soon as a key
larger than the available space was found.
Add spa_json_begin_array/object to replace
spa_json_init+spa_json_begin_array/object
This function is better because it does not waste a useless spa_json
structure as an iterator. The relaxed versions also error out when the
container is mismatched because parsing a mismatched container is not
going to give any results anyway.
JACK emits the bufsize callback from the processing thread while
jack_activate() is called. Do the same with a blocking invoke.
The GStreamer plugin relies on this and when it reives the bufsize
callback later, it will error out.
Fixes#4260
Use the pipewire header version for the minor/micro/proto in the
jack version. That way the jack version will increment and we can
easily see what pipewire version it was compied with.
Add 2 new port format extensions, one for OSC and another for UMP.
Make sure we convert the events from UMP/OSC/MIDI to jack events
depending on the port type.
Try to produce UMP by default.
jack_port_get_buffer() can be called with 0 frames, This is to restrict
the available space in the returned midi buffer after mixdown. While we
mixdown, we should not check timestamps so that all midi events are
added to the mixdown buffer.
Fixes qsynth.
Make a property to pass a custom function pointer to create threads
instead of pthread_create.
Use this in jack instead of bypassing the thread utils create function,
which gives the wrong thread rt priority with rtkit.
Fixes#4099
This is the driver id that the client has received and is using right
now. We don't use this yet but it could be used in the future to check
if a client has the most up to date info.
Make sure newer clients can work with an older server:
- Add client and server versions in the activation
- On older server, clients needs to trigger peers without CAS of status
- On older server, jack transport is started with command.
- Use client version to know when to set the INACTIVE/FINISHED
state on the server instead.
- Async clients need to trigger peers on old server.
Avoid freeing the old io Position area before the data loop has managed
to get a pointer to it. Queue a free operation that will be executed
from the main loop after the data loop has the io area.
Fixes a crash when stressing jack clients to switch between drivers.
We are not allowed to call free_link from the data thread because it
does free() and some pw_mem calls which should only be called from the
main thread.
To solve this, pause the core, queue a free_link operation on the data
thread, which will be scheduled after the previous remove_link operation
completes, free the link and then resume the core. Blocking and resuming
the core is necessary because we can't block for completion of the
invoke calls (the jack method is not allowed to block) and we must
ensure that nothing can happen with the memory (like reuse the mem_id)
before we have cleaned it up.
Fixes a crash in jack with create/destroy link stress.
Manage them like we do on the client and reuse logic. Make a node
function to safely add and remove a target.
Activate the targets from the process loop when we can be sure that we
can resume them. This avoids incrementing the pending state when we are
not going to be able to resume the nodes (like when the cycle is ongoing
and we have already been scheduled) and avoids glitches and xruns.
When a node is added to the poll loop, it can activate its own targets.
This is mostly for driver so that they have something to schedule and
can then activate the other targets.
Try to resume the target when it is removed and we are supposed to be
scheduled.
Also add targets to the target_list when the node is remote to make sure
the profiler can see the targets as well.
Keep the node in the INACTIVE state as long as the eventfd of the node
is not added to the loop. Skip nodes in the INACTIVE state from going to
the NOT_TRIGGERED status, which avoids scheduling the node.
Make sure we remove any local targets we have in a node when we export
it, we will receive new targets from the server.
This should eliminate any glitches when adding and removing nodes from
the graph.
See #4026, #2468
Atomically change the node status from TRIGGERED to AWAKE. Only trigger
the peer nodes when the node was previously in the AWAKE state.
When we remove a node from the graph or when we destroy a link, we need
to manually resume the peers. We can do this now by atomically setting
the node to FINISHED and checking if it was previously != FINISHED.
This ensures that removing nodes/links never leaves some nodes (and also
the driver) untriggered and cause a xruns.
Fixes#4026
The larger events need to be copied into the target buffer at the same
offset as the source buffer or else we overwrite the header and make
a corrupt buffer.
Instead of doing (cycle+1) & 1 for output ports, simply swap the io
areas depending on the port direction (0 = input, 1 = output) and
just to cycle&1 for all ports.
When node.async is set, make the node async.
Advertize SPA_IO_AsyncBuffers on mixer ports when supported. Set a new
port flag when AsyncBuffer is supported on the port.
When making a link and if one of the nodes is async and the linked ports
support AsyncBuffer, make the link async and set this as a property on
the link. For async nodes we will use SPA_IO_AsyncBuffers on the mixer
ports.
Nodes that are async will not increment the peer required counters. This
ensures that the peer can start immediately before the async node is
ready.
On an async link, writers will write to the (cycle+1 & 1) async buffers
entry and readers will read from (cycle & 1). This makes the readers read
from the previously filled area.
We need to have two very controlled areas with specific rules for who
reads and who writes where because the two nodes will run concurrently
and no special synchronization is possible otherwise.
These async nodes can be paused and blocked without blocking or xrunning
the rest of graph. If the node didn't produce anything when the next
cycle starts, the graph will run with silence.
See #3509
Only activate the nodes when it was not-triggered, do this check with an
atomic compare-and-swap so that we only activate a node once.
We might be able to use this later to make sure that we resume the
untriggered peer nodes when we remove a node from the graph.
nframes in the midi buffer should be set to the current cycle
buffer_size and it should restrict the timestamps that can be set on the
midi events.
Keep the last max_frames around in a globals so that we can use it to
set the midi buffer to the default size.
Return NULL when we do jack_port_get_buffer() with larger nframes than
the current cycle buffer_size, just like JACK. Otherwise this could
result in a crash when we try to mix more than the available buffer
space.
Check and reset the midi buffer better. Check if the MAGIC is still ok.
jack_midi_reset_buffer() should restore the MAGIC and other values.
The output buffer size is always the current cycle buffer_size.
The size that is give by the JACK API is only used to restrict the
number of mixdown samples or midi offsets.
Fixes#3892
On the midi input ports, do the same trick as on the output ports:
first convert the midi to JACK and then copy the whole buffer to the
port specific storage.
This makes it possible to have a different midi buffer per port and
allow multiple threads to get the buffer concurrently.
Fixes#3901
node.sync-group can contain a list of strings. When a node in the graph
sets node.sync = true, it will be scheduled with all of the other nodes with
common node.sync-group strings. By default all nodes are placed in
group.sync.0 except the freewheel and dummy driver.
Use this to ensure that all nodes are grouped under the same driver
(that is not the freewheel and dummy driver) as soon as the transport is
started so that the transport is visible to all nodes from the same
sync-groups. We also don't deactive the sync-group anymore for the node,
even if the transport is stopped, to avoid driver changes and transport
jumps.
When the node that activated the sync/transport is destroyed, things are
restored to their original state. Note that this is different from JACK
where starting the transport outlives the application and always needs
to be explicitly stopped again. We can't really do this (by default) because
it leaves the graph in an unnatural state with all devices in sync.
The reason for the node.sync-group is that it is possible to still have N
different subgraphs with a separate transports by manually specifying
the node.sync-group.
It's also slightly different from the node.group, that is always active.
The sync-group is something you only want to enable in specific cases
because it groups drivers together and enables adaptive resampling etc.
It's also possible to place this option in the jack.conf file to
automatically sync all devices and apps as soon as a jack app is started.
Fixes#3850
Don't just overwite the node.group property when changing the freewheel
thate but append the frewheel group and remove it again to preserve
the original node.group.