Commit graph

164 commits

Author SHA1 Message Date
Wim Taymans
3c11772df6 alsa: rework config and properties
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
2023-01-19 17:12:29 +01:00
Wim Taymans
3873256211 alsa: free properties
When we simply update the properties of an existing stream, don't leak
the properties.
2023-01-19 15:32:29 +01:00
Wim Taymans
2254c74fb9 use TARGET_OBJECT instead of the deprecated NODE_TARGET
Clarify the docs.
2023-01-10 16:51:47 +01:00
Thomas Weißschuh
ed46324872 alsa: fix memory leak of properties 2023-01-01 02:00:36 +00:00
Wim Taymans
89ac6b3535 alsa: don´t set -1 as node.target
Leave the target unset when -1, just like what pw-stream does.

See #2893
2022-12-17 18:17:33 +01:00
Wim Taymans
122252ce52 alsa: add brackets for clarity 2022-10-27 09:12:06 +02:00
Wim Taymans
431176c618 alsa: avoid division by 0
Use the wanted amount of samples to determine the buffered data.
Also make sure we don't divide by 0.
2022-10-26 13:22:38 +02:00
Wim Taymans
9d0be53be9 alsa: fix some signedness warnings 2022-10-25 16:27:46 +02:00
Martin Geier
f5f4be5109 alsa-plugin: improve alsa plugin delay precision if alsa period is not align with the quantum
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>
2022-10-25 11:32:00 +00:00
Martin Geier
1a4c2ce624 alsa-plugin: unblock alsa poll when there is pw error
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>
2022-10-25 11:26:20 +00:00
Martin Geier
422c2ad726 alsa-plugin: prevent deadlock when update_active is called from two threads
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>
2022-10-25 11:26:20 +00:00
Erik Fröbrant
552bca8595 pcm_pipewire: optimize by updating existing stream
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.
2022-10-06 15:13:03 +00:00
Wim Taymans
d22feab92a spa: add macro to simplify array iterations some more
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 ..
2022-09-30 16:24:26 +02:00
Wim Taymans
95cfb531a0 alsa: initialise the format
Otherwise the format is 0 (S8) and only S8 will be allowed.
2022-09-20 17:45:46 +02:00
Wim Taymans
c9753b0722 alsa: rework parameter handling
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.
2022-09-20 16:24:21 +02:00
Wim Taymans
26e789124f alsa: increase max periods
We can easily split the buffer into smaller periods and get a lower
latency overall.

See #1697
2022-09-17 18:59:45 +02:00
Wim Taymans
3ad1a5d4dc alsa: rework eventfd handling
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
2022-09-13 17:20:02 +02:00
Wim Taymans
0862e8c2ef alsa: add more debug
Debug the hw and sw params to the debug log
2022-09-12 13:29:39 +02:00
Wim Taymans
0d08f41c28 alsa: calculate elapsed time only when running 2022-09-09 18:13:02 +02:00
Wim Taymans
ca228003c4 alsa: only calculate elapsed time when known 2022-09-09 18:11:23 +02:00
Wim Taymans
5fb361724c alsa: rework timings
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.
2022-09-09 17:59:07 +02:00
Wim Taymans
da9a5cfa5d alsa: subtract elapsed time from server delay only
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.
2022-09-09 16:36:33 +02:00
Wim Taymans
f58021ed45 alsa: improve elapsed time correction
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.
2022-09-09 16:34:18 +02:00
Wim Taymans
41e937e3fd alsa: add some more debug 2022-09-09 16:33:01 +02:00
Wim Taymans
009e61f585 alsa: improve debug 2022-09-09 12:22:08 +02:00
Wim Taymans
4593ac4113 alsa: pass bool argument properly 2022-09-01 10:18:55 +02:00
Wim Taymans
3215b58bae alsa: save volumes
Instruct the session manager to save the volumes when set with the
ALSA ctrl API.
2022-09-01 09:43:10 +02:00
Wim Taymans
565c385228 alsa: add lock around sw_params
The stream and data is protected with the lock.
2022-07-06 13:46:54 +02:00
Lucas Holt
6a15a02ec2 Add support for MidnightBSD
Fix build issue

Fix build issue
2022-06-19 18:22:47 +00:00
Wim Taymans
b1578ee109 alsa: avoid allocation 2022-05-16 09:36:14 +02:00
Robert Rosengren
cd389240fa alsa-plugin: use ioplug sw_params callback
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.
2022-05-16 09:33:01 +02:00
Wim Taymans
61d318125e move PIPEWIRE_PROPS to stream and filter
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.
2022-04-22 09:37:21 +02:00
Quentin Wenger
22fc9eec35 Cleanup argument names in methods and events interfaces
First method argument is object, first event argument is data.

Closes !963
2022-04-15 10:11:49 +02:00
Wim Taymans
5a9d2679ca stream: add pw_stream_get_time_n()
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.
2022-03-29 17:30:38 +02:00
Wim Taymans
7e42c905a8 remove the rate_match io
Now that the stream provides us with a requested size, we don't need to
use the rate_match anymore.
2022-03-29 09:57:49 +02:00
Wim Taymans
c46113faa3 json: spa_json_get_string() writes up to len chars or fail 2022-01-04 10:42:32 +01:00
Wim Taymans
35cbe4e939 buffers: make alignment optional
Make the alignment parameter optional when negotiating buffers.
Default to a 16 bytes alignment and adjust for the max cpu
alignment.
Remove the useless align buffer parameter in plugins, we always
set it to 16 anyway.
2022-01-03 12:32:26 +01:00
Wim Taymans
c1a0a602a5 alsa-plugin: do correct boundary check
The hw_ptr must be wrapped at the boundary value, not after.

See #1941
2021-12-22 20:03:13 +01:00
Jonas Holmberg
6aeb640e31 tests: Add pipewire-alsa stress test
Add test that opens, prepares and closes the alsa pcm device in several
threads simultaneously in an infinite loop.
2021-12-15 16:13:08 +01:00
Wim Taymans
e75282d0f5 alsa-plugin: clip offset and size in capture
Be a bit more careful with the offset and size in the buffer and make
sure we clip them according to the maxsize.
2021-11-25 12:32:24 +01:00
Wim Taymans
955dde5272 alsa-plugin: use hw_avail in _delay for playback
for playback streams we want to include the hw_avail, which is the amount of
data that the hardware can read or the amount of data the application has
written.

This is in contrast to using _avail for the capture stream, which is
what the application can read. hw_avail for a capture stream is how many
samples the hardware can write or the amount of free space.

See #1697
2021-11-24 13:12:23 +01:00
Wim Taymans
743cced63e alsa-plugin: improve debug 2021-11-24 12:40:02 +01:00
Wim Taymans
301e729864 alsa-plugin: fix delay reporting
The delay should be calculated based on the amount of samples available
to the application, not the hardware.

This overreported the delay.

See #1697
2021-11-24 12:24:29 +01:00
Wim Taymans
d8e24fca1c alsa-plugin: don't rate match for capture streams
For capture streams we can simple copy the complete pipewire buffer into
the alsa pcm ringbuffer to make it available for the application.
2021-11-24 12:24:29 +01:00
Wim Taymans
33f087d4db alsa-plugin: don't clamp elapsed time to stream delay
There is no reason to limit the elapsed time to the stream delay, it is
possible that it is larger and then it will be clamped later.
2021-11-24 12:24:29 +01:00
Wim Taymans
6f0c5b6428 alsa-plugin: improve debug 2021-11-24 12:24:29 +01:00
Wim Taymans
5ed4977b38 destroy proxies when global is removed
When a global is removed, also remove the proxies. We can have multiple
proxies to a global otherwise when a client has a sequence of events
queued from the server like this:

Global 1 added
Global 1 removed
Global 1 added

The proxy we added in the firt event would not be destroyed because the
server did not know about it when global 1 was removed and then a
second one would be made.
2021-11-08 12:55:41 +01:00
Wim Taymans
25ddf0e3cf alsa-plugin: fix a compiler warnings 2021-11-02 17:18:58 +01:00
Martin Geier
1b96142903 alsa: do not ignore rate change when stream is already created
gstreamer alsasink can change sample while stream is already created.
In that case, gstreamer calls snd_pcm_ioplug_callback_t::stop,
snd_pcm_ioplug_callback_t::hw_params and snd_pcm_ioplug_callback_t::prepare

Add new flag to the snd_pcm_pipewire_t that is set every time
snd_pcm_pipewire_hw_params is called to prevent using stream with old
sample rate

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
2021-11-02 15:37:07 +00:00
Martin Geier
a7d238ed59 alsa: increase precision of delay function
pw->time.delay is delay in number of frames in pw->time.rate domain,
however snd_pcm_pipewire_delay function is suppose to return number of
frames in io->rate domain. Convert pw->time.delay to io->rate domain to
increase precision when the io->rate is not equal to the pw->time.rate

snd_pcm_pipewire_delay should return how many frames are queued in
pipewire, pw_stream_get_time returns numbers of the queued frames before
snd_pcm_pipewire_process is called, however this function inserts (or
removes) some frames from pipewire. Therefore newly inserted (removed)
frames should be added to pw->time.delay to increase precision.

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
2021-11-02 15:37:07 +00:00