Propagate stream errors and check for successful negotioation or error
in _prepare(). This will return an error from _prepare() if there is no
target node to link to (unless PIPEWIRE_AUTOCONNECT=false).
It would be preferable to also set PW_STREAM_FLAG_INACTIVE to not start
processing until _start() is called but then it would not be possible to
signal successful negotiation.
Make NODE_NAME something that looks more like other node names.
Add MEDIA_NAME and NODE_DESCRIPTION.
Makes things look better in pw-top and the same in pavucontrol.
Always first use the env var and then check the properties. So that
PIPEWIRE_CORE=pipewire-1 PIPEWIRE_REMOTE=pipewire-1 make run runs
everything on pipewire-1 sockets regardless of the config files.
Also PIPEWIRE_NODE always needs to be taken into account first.
Place the configuration options directly into a pw_properties and use
that to connect the client and stream.
Add support for alsa.properties and alsa.rules to set default client and
stream properties based on rules.
See !1502
Method on_stream_process can be called multiple times with the same
pwt.delay and pwt.now values. Its a case, when snd_pcm_pipewire_process
returns less then b->requested frames. For example, if requested is 2048
and alsa period size is 512, then on_stream_process is called 4 times
in a row with the same pwt.delay and pwt.now values.
Store number of transferred frames for this "session" in separate variable
so its incremented each time the on_stream_process is called. Number
of transferred frames is cleared when a new "session" starts.
Introduce also number of buffered frames, which is number of frames
read from alsa but not sent to pipewire yet. This is the case
when period is not align with the quantum size. For example alsa period is
480, but quantum is 512. on_stream_process is called 2 times for the first
quantum, 512 frames is sent to pipewire and 448 frames are cached for the
next round. These 448 frames needs to be included in delay computation
in the next on_stream_process.
Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
When there is a core error, update_active method is called from
on_core_error. update_active is supposed to unblock alsa thread,
in case the alsa is waiting for more some room for data.
Checking for active state is not sufficient and spa_system_eventfd_write
needs to be called also in case of error.
Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
When there is not enough room for next data to write, alsa calls
snd_pcm_pipewire_poll_descriptors to setup file descriptor. This function
clears io->poll_fd by calling spa_system_eventfd_read and next time the
quantum is processed, update_active sets value in io->poll_fd,
alsa is notified and can continue to push data.
In bad case scenario, update_active is called simultaneously from
both - alsa thread and pw thread. In alsa thread, the check_active(io)
returns false, pw->active is set to false, but spa_system_eventfd_read
isn't called yet as Alsa thread is rescheduled. Pw thread starts to execute
the same code, however this time, check_active(io) returns true, pw->active
is set to true and spa_system_eventfd_write is called. When alsa thread
starts to run again, spa_system_eventfd_read is called and clears any
events from io->poll_fd.
Alsa starts to poll for events, io->poll_fd is clear, pw->active is set
to true and therefore spa_system_eventfd_write is not called ever again.
To fix this deadlock, write to io->poll_fd every time there is some
room for new data. Doing this is safe, as write only increases internal
counter and next read clears the counter.
This code can lead to opposite behavior - spa_system_eventfd_write is
called right after spa_system_eventfd_read, however there is no room for
new data. This would lead to busy loop in alsa thread. To prevent this
scenario, call update_active alsa in snd_pcm_pipewire_poll_revents.
Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
pw_stream_connect can take a very long time to finish connecting. This
process continues after snd_pcm_pipewire_prepare has released lock on
pw->main_loop and during this time the device returns EBUSY on write
attempts. This adds a significant latency to playback compared to pre-
pipewire configurations. This is a problem when using for example
Gstreamer alsasink with tight time synchronization options since
GstAudioBaseSink keeps track of internal time by counting processed
samples. Also worth noting is that alsasink calls prepare often,
for example on receiving a caps event.
With this change an existing pipewire stream will be updated rather than
destroyed and re-created when prepare is called.
uint32_t i;
for (i = 0; i < SPA_N_ELEMENTS(some_array); i++)
.. stuff with some_array[i].foo ...
becomes:
SPA_FOR_EACH_ELEMENT_VAR(some_array, p)
.. stuff with p->foo ..
Pass the parameters around in a structure.
Add BUFFER_BYTES argument to configure the buffer size.
Add PIPEWIRE_ALSA env variable to set format, rate, channels,
period-bytes and buffer-bytes.
Add more variables in the alsa config file.
Make one function that updates the eventfd based on the state of
the plugin.
Do this check before getting the desciptors. The functional difference
is that the eventfd could become blocking now as well when getting the
descriptors. This fixes a problem where the poll would wake up without
any work to do.
See #1697
Collect all timing info in the process function. When doing delay
reporting, get a consistent snapshot of all the pipewire side state to
calculate the result.
This should result in more correct timing results.
Only subtract the elapsed time from the server delay. Our reported
delay should always at least still include the data that we have
buffered or else read and write operations might think they can read
or write more than they actually can.
There is no need to patch the pw_time values with the io->rate just so
we can use it to convert the elapsed time to samples. Use the io->rate
directly instead.
snd_pcm_sw_params states "The software parameters can be changed at
any time.". Adding the ioplug callback sw_params to get relevant
updates, and if min_avail has changed update the node latency of
the stream.
Ignoring callback received prior to prepare as stream not yet created.
Make all streams and filters handle PIPEWIRE_PROPS.
The order for applying stream/filter properties is:
1) application provided properties.
2) generic config.
3) match rules.
4) environment variables (PIPEWIRE_PROPS, ...) from generic to
more specific.
5) defaults.
Deprecate pw_stream_get_time() in favour of _get_time_n() that contains
the size of the pw_time structure. Make the old one fill in the fields
up to the buffered field. Make the new one use the size to decide how
much info to fill in.
Add a new buffered field in pw_time that contains the buffered data
inside the converter/resampler. This leaves the queued field with
purely the user provided size in the buffers.
Use get_time_n() in places.