When inspecting the loaded modules, actually list the properties that
were used when loading the module instead of the informational generic
ones from the info.
Pulsaudio also does not list the Usage properties when listing modules.
Add some more fields like the type, default value and possible enum
values for the module_args.
Use this to generate the Usage in describe-module and the docs.
This should give more consistent and correct Usage output in all
modules.
Use spa_json_begin_array() instead of the relaxed variant when parsing
property values in pw_conf_find_match().
This prevents plain string values containing ':' (such as object.path)
from being incorrectly tokenized while preserving support for actual
JSON array properties.
`SPA_PARAM_BUFFERS_blocks` is a specific value, the plugin host should
not use any other number of data planes, so reject other values.
For example, the `buffers[i]->n_datas > planes.size()` situation was
not handled correctly, and this removes the need for handling that.
Expose the libcamera header and library versions in the device properties
similarly to `api.v4l2.cap.version` used by the v4l2 plugin.
The keys are not yet promoted into the public `keys.h` header file.
There was one file "libcamera.c" that was a C source file, which
prevents the addition of C++ functions, includes, etc. to "libcamera.h".
So compile that file as C++ as well.
This makes it possible to dynamically add / remove receivers, which is
necesary for sending to multiple receivers. Mixed multi- and unicast
receivers are possible. Example pw-cli calls (56 is the ID of the RTP
sink node):
pw-cli c 56 User '{ extra="{ \"command.id\" : \"add-receiver\" , \"destination.ip\" : \"10.42.0.1\", \"destination.port\" : 55001 }" }'
pw-cli c 56 User '{ extra="{ \"command.id\" : \"remove-receiver\", \"destination.ip\" : \"10.42.0.1\" }" }'
pw-cli c 56 User '{ extra="{ \"command.id\" : \"clear-receivers\" }" }'
Commands and their arguments:
* "add-receiver" : Adds a receiver to the sink's list. If the given
IP address <-> port combination was already added, the command is
logged, but otherwise ignored. Arguments:
- "destination.ip" : IP address to send data to. Can be a uni- or
multicast address, but must be a valid address.
- "destination.port" : Port to send data to. Must be valid.
- "local.ifname", "source.ip", "net.ttl", "net.dscp", "net.loop" :
These are all optional, and work just like in the RTP sink
module's properties.
* "remove-receiver" : Removes a receiver from the sink's list. The
receiver is identified by the given IP address. A port can optionally
be specified as well. If it isn't, then the first receiver with that IP
address is removed. If no matching receiver is in the sink's list,
this command does nothing. Arguments:
- "destination.ip" : IP address to send data to. Can be a uni- or
multicast address, but must be a valid address.
- "destination.port" : Port to send data to. This is optional. But, if
it is set, it must be a valid port number.
* "clear-receivers" : Removes all receivers from the sink's list. If the
list is empty, this does nothing. This command has no arguments.
If the RTP sink module is created with the "destination.ip" and
"destination.port" properties set, it behaves as if "add-receiver" were
called right after the module was initialized. This means that if none
of these commands are used, the module behaves just as it did prior to
this patch. Note that the "remove-receivers" command can remove this
initial receiver as well.
If no receivers are added, the module continues to work normally.
Adding and removing receivers mid-operation is supported.
NOTE: "destination.ip") handling in stream_props_changed() is removed,
since it never really did anything other than change the param value.
Always use the pffft aligned alloc function. The fftw alloc function
only aligns to 16 bytes and the AVX code uses stores that rely on an
alignment of 32 bytes. The pffft alloc alignes to 64 bytes.
Fixes#5320
rtp_stream_new() acquires a data loop with pw_context_acquire_loop() but
the out: error path never calls pw_context_release_loop(), leaking the loop
reference on every failure after acquisition.
Mirror rtp_stream_destroy() and other modules that pair acquire with release.
A 0 result from the iteration with a NULL filter means the end of the
iteration, if we get this for the first item, we assume there was no
item (same as unknown item)
A 0 result for the iteration with filter means nothing matches the
filter and so the filter should not be included in the result. A result
of -ENOENT means the param is unknown and the filter should be included
in the result.
Fixes#5313
When adding the freeze/thaw recalc graph calls, triggering the actual
recalc of the graph (when an active node with a driver was removed) was
removed.
The thaw only actually recalcs the graph when something set the
recalc_pending flag so we still need something to set this. Normally
this would be because of some of the ports or links that got destroyed
but if not, the original recalc trigger needs to remain as a fallback.
Some operations like deactivating nodes deactivates all links to the
node and this causes a graph recalc for each link.
It's actually a bit more problematic with suspend, which first
deactivates the links and then suspends the ports. The suspension of the
ports cause a recalc, which for the not yet suspended ports makes the
link active again, causing issues then when the port is suspended later.
Make recalc a counter and only recalc when the counter is 0. If the
counter is not 0, set the pending recalc, which will trigger when the
counter goes to 0.
With this, we can add a freeze/thaw operation on the recalc and delay
recalculation until all ports and links are handled.
We can also group some other operations with a freeze/thaw pair, such as
the destruction of ports, which destroys all links. Also the destruction
of nodes can freeze the recalc until all ports are destroyed.
When there is no input buffer because of an xrun or the io was removed,
ramp down the signal. Only remove the port from the mix list when the io
was removed, otherwise, ramp back up when there is a buffers on the
input again.
This avoids pops and click around xrun nodes.
Only ramp down when the IO was removed. We don't want to ramp down
because there was no buffer because of an xrun, because after the
ramp down, the port is removed from the mix ports and stays silent.
Add a new pulse.zeroramp.gap property that will enable gap detection and
fade-in/fade-out on gaps on playback streams.
Make a rule to enable this on chrome, which does not do a cork/pause
when a stream is paused but sends out silence. With the gap detection
enabled, this allows the audioconvert to perform fades to avoid pops and
clocks from sudden DC changes at the gaps.
Fixes#4745
Make a new zeroramp.duration and zeroramp.gap property on audioconver.
It detects N samples of silence before triggering a fade-in or fade-out
of the given zeroramp.duration.
The zeroramp.duration is by default 5ms and zeroramp.gap is set to 0.
When the zeroramp.gap is set to 0, the audioconver will not do any gap
detection but it will only do fade-out from the last sample when the IO
Buffer area is removed from a port.
This by default makes the audio adapter perform a fade-out when the last
input of the port mixer was removed and the mixer is no longer scheduled
and the IO Area removed from the audioconverter input port.
Pass the zeroramp.duration property from the node to the port and then
to the mixer so that it can be configured.
Add the zeroramp.duration to the docs.
When the port IO_Buffers is set, do a fade-in of the next buffer data
into the final mixed output.
When the port IO Buffers in cleared, do a fade-out of that last sample.
Add a zeroramp.duration property that controls the length in seconds of
the fade-in/out curve. By default, set this to 5ms.
The fade-in and fade-outs avoid popping noise from sudden DC voltage
changes when ports a linked and unlinked.
It will also trigger when the upstream peer is paused, because that will
also remove the IO Buffers from the mixer ports.
Each port mix embedded its buffer table in struct mix as a fixed array
buffers[MAX_BUFFERS] (MAX_BUFFERS == 64), and every struct buffer in turn
embedded datas[MAX_DATAS] (MAX_DATAS == 256) and metas[MAX_METAS]. This
reserved ~674 KB per mix in create_mix() regardless of the actual buffer,
data and meta counts, multiplied by every port mix (one per link end).
Turn buffers, datas and metas into pointers and allocate the buffer table
together with the per-buffer data and meta pools in a single calloc in
do_port_use_buffers(), sized to the real number of buffers and their
n_datas/n_metas, and release it in clear_buffers(). create_mix() now starts
with an empty (NULL) table, so an idle mix costs only the struct header.
This mirrors the dynamic-allocation approach already used for the
audioconvert and audiomixer port buffers and removes the dominant heap and
mmap consumer in the client-node graph.
Co-authored-by: Copilot <copilot@github.com>
Fix incorrect assertion condition that compares fragment_size
with max_fragments instead of num_fragments.
The condition should validate num_fragments range, not mix
fragment_size with max_fragments limit.
Since we know DTS and AC3 devices don't provide the snd_pcm_info of the
real underlying device, let's look for them by name (doesn't seem to be
a better way to detect this case), and avoid overwriting any previously
detected h/w device index (from one of the PCM paths).
Always place the follower EnumFormat or Format as internalFormat on
the EnumPortConfig and PortConfig respectively.
This ways, internalFormat always refers to the follower formats and
the format is the external format after (optional) conversion by the
adapter.
The idea was to keep some sort of compatibility with older versions but
that doesn't really apply because the format was never used on
EnumPortConfig and interalFormat didn't exist.
Like the audioconvert node, the DSP mixer embedded a fixed
buffers[MAX_BUFFERS] array (MAX_BUFFERS == 64) in struct port, each
struct buffer holding datas[MAX_DATAS] (MAX_DATAS == 64), reserving
~37 KB per port regardless of the actual buffer/channel count. A DSP
mixer port is created for every link set that mixes into a port, so
this adds up.
Allocate the buffer table and the per-buffer data-pointer pool in a
single calloc in port_use_buffers(), sized to the real number of
buffers and their data blocks, and release it in clear_buffers().
remove_port() now clears the port before zeroing it so a pooled port
does not leak its allocation, and impl_clear() clears the input and
output ports on teardown. Mirrors the audioconvert dynamic-allocation
change.
Co-authored-by: Copilot <copilot@github.com>
The port buffer table was embedded in struct port as a fixed array
buffers[MAX_BUFFERS] of struct buffer, each holding datas[MAX_DATAS]
(MAX_DATAS == SPA_AUDIO_MAX_CHANNELS == 64). This reserved ~17 KB per
port regardless of the actual buffer/channel count, multiplied by every
active port.
Allocate the buffer table and the per-buffer data-pointer pool in a
single calloc in port_use_buffers(), sized to the real number of
buffers and blocks, and release it in clear_buffers(). free_dir() now
clears each port so the allocation (and any mmapped buffer data) is
released on node destruction. This mirrors the dynamic-allocation
approach already used for the channelmix matrices and preserves a lot
of memory in the common low-channel-count case.
Co-authored-by: Copilot <copilot@github.com>
In the past, it made no difference whether or not an RTP sink's
sess.ts-direct property was set to true. This changed in commit
6bf81ebe59 . Now, sess.ts-direct must be
set to true if an associated RTP source is using direct timestamp mode.
That's because when the RTP sink's direct timestamp mode is not enabled,
it will set the new internal ts_align offset to a nonzero value, which
then corrupts timestamps and causes out of sync playback in the RTP
sources.
Also, copy the sess.ts-direct property from the global RTP sink props
to the stream props to match the behavior of the RTP source module.
* Rename do_disconnect to do_disconnect_core, since the original name
is ambiguous (it can be interpreted as being about disconnecting
a network socket).
* impl->session_name is not used at all, so remove it.
This fixes code duplication, since the checks are the same regardless
of payload type. hlen is also calculated the same across payload types,
so it is moved as well. The impl->receive_rtp() function pointer then
solely addresses the actual payload processing.
Rename format_info to rtp_format_info to make the purpose of that struct
and the associated variable clearer.
Document what info and stream_info are there for, since their purpose
is not immediately obvious.
Using find_audio_format_info() for Opus and MIDI makes no sense, since
both of these only have one info each, which is always found, so one might
as well just use that single, always-matching RTP format info directly.
This means that the audio_format_info array remains there solely for PCM,
so rename it to rtp_pcm_audio_format_info.