We delay the audio a bit to keep packet intervals equal, which keeps
some data in buffers.
In theory the calculation keeps one buffer free, but it doesn't
explicitly keep "extra" buffer space so in theory might flush too late
and next process() might not have free buffers. However, as we encode
next packet right away this shouldn't really occur...
Try to keep one extra spare buffer free so that the flush time is
certainly early enough.
Don't emit node error for A2DP duplex sink channel, or when BAP server.
These can occur under normal conditions (remote side suspends
transport), and are not errors.
When a sink contributing to an ISO CIG does not have data, output
silence for it, as long as at least one sink in the CIG is running.
Only if writes to sockets fail, pause all streams to reset
synchronization.
This way we write exactly the same number of packets for each CIS at the
same time, which probably is the best tested configuration in BT
adapters and devices. We also don't then have to pause output if some
sinks are not running or miss their timing, as we generate silence on
the fly.
When using iso-io, have it initialize the codec instance, and have
media-sink uses that instance, so that silence and actual audio are
encoded with the same codec.
Determine correctly if we are resampling, and have the associated delay.
Add off-by-one sample adjustment to the resampling delay, which seems to
correctly align the resampled audio with non-resampled.
Resynchronize ISO streams on playback (re)start, so the stream positions
are aligned immediately. This is better than relying on rate matching
to correct any offsets.
Emit BAP device set nodes, which the session manager can use to combine
the sinks/sources of a device set to a single sink/source.
Emit the actual sinks/sources with media.class=.../Internal to hide them
from pipewire-pulse.
Add separate device set routes to the set leader device. Other routes
of the set members will be marked as unavailable when the set is active.
Accordingly, return failure for attempts to set these unavailable
routes, so that volumes etc. of the "internal" nodes are only controlled
via the device set route.
Use the ISO IO helpers to get synchronized BAP output, and rate match to
the ISO schedule.
The rate matching is necessary, since the driver may be ticking at a
corrected rate, different from the ISO interval rate.
Drivers should only read the target_ values in the timeout, update the
timeout with the new duration and then update the position.
For the position we simply need to add the previous duration to the
position and then set the new duration + rate.
Otherwise, everything else should read the duration/rate and not use
the target_ values.
Make BAP nodes align the first sample of their packets at multiples of
the ISO interval, counted in the shared graph sample position. This
skips a few samples (< 10ms) at the start of playback to ensure the
alignment.
Since the sinks align their flush timing to the graph time, this also
results to them sending packets corresponding to the same graph time at
the same real time instants.
Due to packet queues in kernel/controller, the playback may still be off
by multiples of packets. Kernel changes are needed to address that part.
This works towards making BAP left and right channels to be
synchronized in TWS headsets, where the two earpieces currently appear
as different devices.
If transport goes into error state too often, fail instead of trying to
acquire it again.
This avoids getting into a tight acquire->fail->reacquire loop.
Allow asynchronous changes in transport state in the sinks/sources.
Also allow transport acquire to be actually synchronous, in this case it
must set transport state during acquire call.
Separate driver start/stop from transport start/stop.
Add some guards against doing processing when there has been an error or
the node is not started. Set error status to IO. Continue driving on IO
errors.
In media-sink, there's no need to set RCVBUF.
In media-source, we don't need to set NONBLOCK, as reads are done with
DONTWAIT. Don't set SNDBUF as it's not needed there. Don't set RCVBUF,
but use the (big) kernel default value: decode-buffer will handle any
overruns. Small values of RCVBUF might cause problems if kernel is
sending packets in a burst faster than we wake up.
Delay output by one packet, so that we never need to wait for
node_process to supply more data when a packet is due out, and can write
audio packets at exactly equal intervals (up to timer/io accuracy).
In principle, this should not be necessary. However, enable it for now,
in case this improves the various stutter/etc. bug reports.
After flushing a packet, encode the next one immediately if we already
have the data. This makes the flush timing more accurate (std ~4x
smaller) as we don't need to wait for the encode.
Make a real debug context with a log function and move it to a new file.
This way we don't need to redefine a macro.
Make a new context for debugging to a log file. Make new functions to
debug to a log file.
Move the stringbuffer to string utils.
Integrate file/line/func and topics into the debug log.
We can remove some more things from the pipewire log_object function and
also add support for topics.
When reading the timerfd gives an error, we should return right away
because the timeout did not happen.
If we change the timerfd timeout before reading it, we can get -EAGAIN.
Don't log an error in that case but wait for the new timeout.
The free buffer check must happen before writing to check for leftover data in buffers. In case data is left over from previous submission, bitpool mustn't be increased.
Also improved logging by adding bitpool to the log message.
Bigger buffer allows for more fluctuation in transmission rate without
sound glitches.
It doesn't matter much for latency, as under normal conditions we are
not producing data faster than the BT adapter can transmit, so the
buffer generally is almost always empty or full, and in the latter case
we have to reduce the bitrate.
For backward compatibility with old Wireplumber releases, support the
old api.bluez5.a2dp.sink/source names, and use them in object events
instead of the media.sink/source names.
We can't determine which remote endpoint or device the
SelectConfiguration() call is associated with. For LE Audio BAP, as this
method is called only for the Initiator we set the whole instance as a
Central/Initiator.
This flag is unset on BAP media endpoint removal.