Instead of using timerfd, use the context timer-queue to schedule
timeouts. This saves fds and removes some redundant code.
Make the rtp-source timeout and standby code a bit better by using
atomic operations.
The state_changed callbacks fulfill multiple roles, which is both a problem
regarding separation of concerns and regarding code clarity. De facto,
these callbacks cover error reporting, opening connections, and closing
connection, all in one, depending on a state that is arguably an internal
stream detail. The code in these callbacks tie these internal states to
assumptions that opening/closing callbacks is directly tied to specific
state changes in a common way, which is not always true. For example,
stopping the stream may not _actually_ stop it if a background send timer
is still running.
The notion of a "state_changed" callback is also problematic because the
pw_streams that are used in rtp-sink and rtp-source also have a callback
for state changes, causing confusion.
Solve this by replacing state_changed with three new callbacks:
1. report_error : Used for reporting nonrecoverable errors to the caller.
Note that currently, no one does such error reporting, but the feature
does exist, so this callback is introduced to preserve said feature.
2. open_connection : Used for opening a connection. Its optional return
value informs about success or failure.
3. close_connection : Used for opening a connection. Its optional return
value informs about success or failure.
Importantly, these callbacks do not export any internal stream state. This
improves encapsulation, and also makes it possible to invoke these
callbacks in situations that may not neatly map to a state change. One
example could be to close the connection as part of a stream_start call
to close any connection(s) left over from a previous run. (Followup commits
will in fact introduce such measures.)
Direct timestamp mode was incorrectly using over/underrun detection logic
and fill level tracking logic that is actually meant for the other mode
(referred to from now on as "constant latency mode"). Over/underruns are
tracked implicitly in the direct timestamp mode, and the absolute fill
level is not relevant in that mode, since the latency is not needed to
be constant then.
Also improve log lines and the RTP module documentation to define these
buffer modes clearly and explain their differences and use cases.
Opus and MIDI code get TODOs added, since their direct timestamp mode
implementations still may be incorrect. Fixing those will be done in
a separate commit.
When we simply need to change some state for the code executed in the
loop, we can use locked() instead of invoke(). This is more efficient
and avoids some context switches in the normal case.
Because we don't know the stream state at the start of streaming, if
clients are deciding to connect on the basis of this flag, they will
never connect if we default to true. So let's be optimistic by default
and we'll find out on timeout if there actually isn't data to receive.
Idle the source when no packets are received and resume when new packets
arrive.
Add a stream.may-pause property to pause the stream when no packets are
received during the timeout window.
Make sure the rtp.streaming property is updated correctly and as soon as
we get the first packet.
Fixes#4456
If the sender is reset, the RTP stream may return, but may no longer
correspond to the stream for which we loaded this instance of
module-rtp-source. A power cycle or network reset on Dante devices
causes a new SDP and SSRC to be selected, for example.
So let's make sure we don't consider invalid receives while tracking our
"receiving" state. Arguable, we should bail entirely if this happens.
There isn't a good way to surface this information to the module owner
yet, so let's publish the information on the stream so we can try to
manage things in policy.
Expose the acquire_loop/release_loop functions and use them in the
modules.
Make sure the nodes created from the module use the same data loop as
the module. We need to ensure this because otherwise, the nodes might
be scheduled on different data loops and the invoke or timer logic will
fail.
Make a new function to set the rtp stream in the error state.
When we fail to start the stream, set the error state. Otherwise (like
when we try to use an invalid interface name) the socket create will
fail but the stream will still try to send data to the invalid socket.
Use `getaddrinfo` in `parse_address` instead of `inet_pton`.
Display Ipv6 addresses with scope identifiers correctly in `get_ip`
functions using `if_indextoname`.
Use the sess.latency.msec also for the sender and use it to control the
NODE_LATENCY. Make it a float to be in line with the other time values.
Set is to a default of ptime, which was what it used to be.
This makes it possible to set the ptime to a smaller value than the
sess.latency.msec so that we send out multiple packets per quantum.
This will result in some bursty output for now but with a timer that can
be improved later.
Update the docs a little, mention the new rtp.ptime and rtp.frametime.
Only listen for packets from source.ip in the unicast (v4) case by
calling connect(). If packets from any source address is wanted, set
source.ip = "0.0.0.0".