When the link on the pipewire side is destroyed, on video streams, buffers
are removed abruptly and there is no way this pipeline can be revived,
so let's post an element error to stop it.
On a normal shutdown, the pool is first set to flushing in change_state(),
so checking for the flushing state is a good indicator to know if this
is a normal shutdown or not.
See #1980
This is for readability and better control.
Make sure we clear out all pointers to anything related to the released
pw_buffer, including all the memories.
The gst_video_info_from_caps() API isn't really intended to be used as a
check-for-videoness function (it generates an error-level GStreamer
debug message when used this way).
We check the caps for a video/ name for this reason, which is
functionally equivalent.
Both the GPtrArray and its contents are leaked in case of success.
`pw_stream_connect()` copies the params as needed, so use `g_autoptr()`
to free the array and with it, its contents.
The threadloop might fail to create because of missing plugins, so
handle that.
The context might fail to create because of some fatal config error or
missing plugin, handle that too instead of crashing.
See #3994
gst_pad_get_current_caps may return NULL and passing that into
gst_caps_is_equal may result in fatal critical log due to the
"g_return_val_if_fail (GST_IS_CAPS (caps1)" check. Fix by checking for
NULL to avoid this.
Some clients like many camera apps, including Cheese or Snapshot,
trigger a lot of unnessecary renegotiations. While arguably that should
be solved on a Gstreamer level, we can help out by checking if the
preferred new caps are the same that are already in use and skip the
renegotiation in this case.
This allows several apps to e.g. take pictures without a slow and heavy
stream restart.
In order to follow the documentation more closely. Also restructure the
code a bit to make it easier to follow.
See also: e3227b2b5 (gst: simplify modifier extraction)
Fixes: f1b75fc6f (gst: Add support for DMA_DRM / explicit modifiers)
spa_pod_get_values() handles both single values and Choice values and
turns the single value into a None choice.
Check that we have a None or Enum choice because we don't handle
anything else.
See !1952
A peer may announce support for a single modifier, in which case it may
not use a choice-pod. And while the documentation in `dma-buf.dox`
requires modifiers to always be announced as `SPA_CHOICE_Enum`, this has
been supported in the past - as well as matching Pipewire conventions.
Thus, in order to not break existing clients not crash, reintroduce
handling of modifiers as a single long.
Fixes: f1b75fc6f (gst: Add support for DMA_DRM / explicit modifiers)
Solution suggested by Barnabás Pőcze <pobrn@protonmail.com>
Parse the audio rate from the caps and set this as the stream node.rate
property. This will try to switch the graph to this rate and avoids
resampling.
Rework some of the property handling.
`gst_caps_make_writable()` may create a copy which we have to keep
using afterwards. The return value was meant to be used for that,
but was promptly forgotten for the initial user.
Avoid such errors in the future by using an in-out parameter instead.
While on it, add a type check and remove a check for an impossible
condition.
Fixes: 8a271a87b ("gst: Sanitize caps before translating")
gst-play uses autoaudiosink by default when playing audio, which
iterates over all sinks sorting them by rank. By default,
pipewiresink sets the rank to 0, but it can be overridden
by setting the GST_PLUGIN_FEATURE_RANK env. var. like this:
`GST_PLUGIN_FEATURE_RANK=pipewiresink:268 gst-play-1.0 /usr/share/sounds/alsa/test.wav`
But that doesn't work either because the autoaudiosink plugin also
filters the available options, testing for "Sink" and "Audio" to
appear in the classification metadata
(in the strstr comparison in
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/subprojects/gst-plugins-good/gst/autodetect/gstautodetect.c?ref_type=heads#L220
klass is what's set by pipewire as classification,
self->type_klass is "Sink" and self->media_klass is "Audio")
Just adding the word Audio to the classification metadata fixes
this and allows pipewiresink to be selected by autoaudiosink.
I also set it in the source plugin since looking at the code,
autoaudiosrc works exactly the same.
DMABuf caps without concrete formats and modifiers don't map well to the
Pipewire negotiation process.
Introduce a new gst_caps_sanitize() helper function, where such cases
can be handled.
Gstreamer 1.24 added and largely switched to a new, modifier aware
DMABuf API. Unfortunately that breaks the existing DMABuf support in the
PW Gst element.
Add support for the new API.
Make a method to get the current time to compare agains the pw_time-now
field. This is currently CLOCK_MONOTONIC but make this into a method
so that we can more easily change it later.
When we disable autoconnect, disable the timeouts as well. Otherwise the
user has to connect the stream within the 30 second timeout or get a
failure. With autoconnect we can reasonably assume there is a problem
when the stream is not connected after 30 seconds.
Fixes#3884
When the session manager sends an error to the client, it typically
also destroys the node after the error, which causes the stream to go
to STATE_UNCONNECTED via proxy_removed(). In that case, make sure
we exit the loop early, otherwise it will take 30 seconds to unblock
gst_element_set_state()
This is a revised version of the fix that was commited via !1763
and then reverted, as it was problematic. Now the code ensures
that it breaks out only if the state was previously CONNECTING
or higher.
GStreamer uses a time stamp for the decoding time, but PipeWire uses an
offset to the presentation time. Thus, the pipewiresink must not use the
DTS as dts_offset, but has to calculate the offset.
If the buffer's DTS is invalid, assume that dts is pts.
Keep a list of ports for the node. When the node goes away, clear the
port links to the node. Handle the case where the port no longer has a
node.
This avoids a crash when, for example, the node permission is removed
and the port points to the now freed node_data.
Fixes#3708
Tabs and spaces are mixed for indentation in the pipewiresink. Replace
all tabs with 8 spaces although indentation is 2 spaces, since that
looks like the intended indent.
The messages are printed for every buffer. Therefore, they should be log
messages. Also add the bufferpool to the message to be able to identify
the bufferpool that handles the buffers.
The buffers are added to the pipewirepool during setup. Therefore, they
should be debug messages. As at it, use the debug helper to print the
string of the buffer type.
This reverts commit 7465175ad0.
wait_started() is called before the stream is connecting and so
exits with an error immediately, which then makes the stream start
too early and block.
When the session manager sends an error to the client, it typically
also destroys the node after the error, which causes the stream to go
to STATE_UNCONNECTED via proxy_removed(). In that case, make sure
we exit the loop early, otherwise it will take 30 seconds to unblock
gst_element_set_state()
First, make the error permanent by calling pw_stream_set_error()
and when this emits an error state again, report that to GStreamer.
Do the same in pipewiresink, which didn't even have the
pw_stream_set_error() call before, so the stream wasn't really going
into an error state at all.
For encoded formats, buffer size is the size of the actual data in the
buffer and may change for each frame depending on the content. Thus,
configuring the buffer pool of the pipewiresrc with the size of the
first buffer may be insufficient for later buffers.
Configure the buffer pool to the maximum size of the first upstream
buffer and assume that the following buffers will be allocated with the
same size as the first buffer.
For encoded formats, p->video_info.size will be 0. If the pipewiresrc
handles an encoded format, the bufferpool will be configured to allocate
buffers of size 0. This will cause errors later when trying to copy the
frames into the pipewire buffers.
Update the bufferpool size only if video_info defines an actual buffer
size.
If the pipewiresink needs to copy the GStreamer buffers to the PipeWire
buffers, because the upstream element didn't use the pipewirepool, the
metadata must be copied, too. Otherwise the pipewire datas will be
filled with the metadata from the buffer during the initialization and
not the currently used buffer.
For example, without copying the metadata the buffer timestamp will be
missing on the pipewire buffers.
The provider might fail to connect to the PipeWire core when starting up, so
when stopping we need to check the core is valid before attempting to acquire a
mutex on its loop.