stream: improve the flush handling and docs

Flush with drain calls the drained callback for each cycle until paused
or resumed. Setting the stream to active again, clears the drained state
and makes things resume.

Flush without drain does not set the state to PAUSED but simply clears
the queued data. This is mostly useful when pausing or stopping.

At no point should the flush operation result in a PAUSED state change.
This commit is contained in:
Wim Taymans 2024-10-07 17:15:18 +02:00
parent 8cd3fc6922
commit ffbcf853e6
4 changed files with 20 additions and 6 deletions

View file

@ -498,14 +498,18 @@ static int impl_send_command(void *object, const struct spa_command *command)
{
struct filter *impl = object;
struct pw_filter *filter = &impl->this;
uint32_t id = SPA_NODE_COMMAND_ID(command);
switch (SPA_NODE_COMMAND_ID(command)) {
pw_log_debug("%p: command %s", impl,
spa_debug_type_find_name(spa_type_node_command_id, id));
switch (id) {
case SPA_NODE_COMMAND_Suspend:
case SPA_NODE_COMMAND_Flush:
case SPA_NODE_COMMAND_Pause:
pw_loop_invoke(impl->main_loop,
NULL, 0, NULL, 0, false, impl);
if (filter->state == PW_FILTER_STATE_STREAMING) {
if (filter->state == PW_FILTER_STATE_STREAMING && id != SPA_NODE_COMMAND_Flush) {
pw_log_debug("%p: pause", filter);
filter_set_state(filter, PW_FILTER_STATE_PAUSED, 0, NULL);
}

View file

@ -238,7 +238,10 @@ void *pw_filter_get_dsp_buffer(void *port_data, uint32_t n_samples);
int pw_filter_set_active(struct pw_filter *filter, bool active);
/** Flush a filter. When \a drain is true, the drained callback will
* be called when all data is played or recorded */
* be called when all data is played or recorded. The filter can be resumed
* after the drain by setting it active again with
* \ref pw_filter_set_active(). A flush without a drain is mostly useful afer
* a state change to PAUSED, to flush any remaining data from the queues. */
int pw_filter_flush(struct pw_filter *filter, bool drain);
/** Check if the filter is driving. The filter needs to have the

View file

@ -668,7 +668,7 @@ static int impl_send_command(void *object, const struct spa_command *command)
case SPA_NODE_COMMAND_Pause:
pw_loop_invoke(impl->main_loop,
NULL, 0, NULL, 0, false, impl);
if (stream->state == PW_STREAM_STATE_STREAMING) {
if (stream->state == PW_STREAM_STATE_STREAMING && id != SPA_NODE_COMMAND_Flush) {
pw_log_debug("%p: pause", stream);
stream_set_state(stream, PW_STREAM_STATE_PAUSED, 0, NULL);
}
@ -2325,8 +2325,11 @@ int pw_stream_set_active(struct pw_stream *stream, bool active)
pw_impl_node_set_active(stream->node, active);
if (!active || impl->drained)
if (!active || impl->drained) {
if (impl->drained && impl->io != NULL)
impl->io->status = SPA_STATUS_NEED_DATA;
impl->drained = impl->draining = false;
}
return 0;
}

View file

@ -594,7 +594,11 @@ int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer);
int pw_stream_set_active(struct pw_stream *stream, bool active);
/** Flush a stream. When \a drain is true, the drained callback will
* be called when all data is played or recorded */
* be called when all data is played or recorded. The stream can be resumed
* after the drain by setting it active again with
* \ref pw_stream_set_active(). A flush without a drain is mostly useful afer
* a state change to PAUSED, to flush any remaining data from the queues and
* the converters. */
int pw_stream_flush(struct pw_stream *stream, bool drain);
/** Check if the stream is driving. The stream needs to have the