From 3905e3b3d34aa8c433c8b0459c06da8631d1d935 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 4 Mar 2025 12:50:38 +0100 Subject: [PATCH] stream: set errno to the current error Make the state_changed event and _get_state() function set errno with the current error value if the state is in error, so that application can use this to give more detailed error reporting. Use this in alsa, v4l2 and pulse to give some other error codes than EIO. Fixes #4574 --- pipewire-alsa/alsa-plugins/pcm_pipewire.c | 2 +- pipewire-v4l2/src/pipewire-v4l2.c | 2 +- src/modules/module-protocol-pulse/pulse-server.c | 2 +- src/pipewire/filter.c | 9 ++++++++- src/pipewire/filter.h | 5 ++++- src/pipewire/stream.c | 9 ++++++++- src/pipewire/stream.h | 5 ++++- 7 files changed, 27 insertions(+), 7 deletions(-) diff --git a/pipewire-alsa/alsa-plugins/pcm_pipewire.c b/pipewire-alsa/alsa-plugins/pcm_pipewire.c index e51cf1b56..bd6836e53 100644 --- a/pipewire-alsa/alsa-plugins/pcm_pipewire.c +++ b/pipewire-alsa/alsa-plugins/pcm_pipewire.c @@ -391,7 +391,7 @@ static void on_stream_state_changed(void *data, enum pw_stream_state old, enum p if (state == PW_STREAM_STATE_ERROR) { pw_log_warn("%s", error); - pw->error = -EIO; + pw->error = -errno; update_active(&pw->io); } } diff --git a/pipewire-v4l2/src/pipewire-v4l2.c b/pipewire-v4l2/src/pipewire-v4l2.c index 2e5a4045d..691c8ec37 100644 --- a/pipewire-v4l2/src/pipewire-v4l2.c +++ b/pipewire-v4l2/src/pipewire-v4l2.c @@ -1696,7 +1696,7 @@ static int connect_stream(struct file *file) break; if (state == PW_STREAM_STATE_ERROR) { - res = -EIO; + res = -errno; goto exit; } if (file->error < 0) { diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 5b156fb94..cb66f75e2 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -1109,7 +1109,7 @@ static void stream_state_changed(void *data, enum pw_stream_state old, switch (state) { case PW_STREAM_STATE_ERROR: - reply_error(client, -1, stream->create_tag, -EIO); + reply_error(client, -1, stream->create_tag, -errno); destroy_stream = true; break; case PW_STREAM_STATE_UNCONNECTED: diff --git a/src/pipewire/filter.c b/src/pipewire/filter.c index 18ffb4e2a..519c1e2f7 100644 --- a/src/pipewire/filter.c +++ b/src/pipewire/filter.c @@ -407,8 +407,10 @@ static bool filter_set_state(struct pw_filter *filter, enum pw_filter_state stat pw_filter_state_as_string(old), pw_filter_state_as_string(state), res, error); - if (state == PW_FILTER_STATE_ERROR) + if (state == PW_FILTER_STATE_ERROR) { pw_log_error("%p: error (%d) %s", filter, res, error); + errno = -res; + } filter->state = state; pw_filter_emit_state_changed(filter, old, state, error); @@ -1126,11 +1128,14 @@ static void proxy_destroy(void *_data) static void proxy_error(void *_data, int seq, int res, const char *message) { struct pw_filter *filter = _data; + int old_errno = errno; /* we just emit the state change here to inform the application. * If this is supposed to be a permanent error, the app should * do a pw_filter_set_error() */ + errno = -res; pw_filter_emit_state_changed(filter, filter->state, PW_FILTER_STATE_ERROR, message); + errno = old_errno; } static void proxy_bound_props(void *_data, uint32_t global_id, const struct spa_dict *props) @@ -1474,6 +1479,8 @@ enum pw_filter_state pw_filter_get_state(struct pw_filter *filter, const char ** { if (error) *error = filter->error; + if (filter->state == PW_FILTER_STATE_ERROR) + errno = -filter->error_res; return filter->state; } diff --git a/src/pipewire/filter.h b/src/pipewire/filter.h index 97a1f9303..8298b6549 100644 --- a/src/pipewire/filter.h +++ b/src/pipewire/filter.h @@ -62,7 +62,8 @@ struct pw_filter_events { uint32_t version; void (*destroy) (void *data); - /** when the filter state changes */ + /** when the filter state changes. Since 1.4 this also sets errno when the + * new state is PW_FILTER_STATE_ERROR */ void (*state_changed) (void *data, enum pw_filter_state old, enum pw_filter_state state, const char *error); @@ -153,6 +154,8 @@ void pw_filter_add_listener(struct pw_filter *filter, const struct pw_filter_events *events, void *data); +/** Get the current filter state. Since 1.4 this also sets errno when the + * state is PW_FILTER_STATE_ERROR */ enum pw_filter_state pw_filter_get_state(struct pw_filter *filter, const char **error); const char *pw_filter_get_name(struct pw_filter *filter); diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index c2186996f..5e5aed3b7 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -400,8 +400,10 @@ static bool stream_set_state(struct pw_stream *stream, enum pw_stream_state stat pw_stream_state_as_string(old), pw_stream_state_as_string(state), res, stream->error); - if (state == PW_STREAM_STATE_ERROR) + if (state == PW_STREAM_STATE_ERROR) { pw_log_error("%p: error (%d) %s", stream, res, error); + errno = -res; + } stream->state = state; pw_stream_emit_state_changed(stream, old, state, error); @@ -1169,11 +1171,14 @@ static void proxy_destroy(void *_data) static void proxy_error(void *_data, int seq, int res, const char *message) { struct pw_stream *stream = _data; + int old_errno = errno; /* we just emit the state change here to inform the application. * If this is supposed to be a permanent error, the app should * do a pw_stream_set_error() */ + errno = -res; pw_stream_emit_state_changed(stream, stream->state, PW_STREAM_STATE_ERROR, message); + errno = old_errno; } static void proxy_bound_props(void *data, uint32_t global_id, const struct spa_dict *props) @@ -1772,6 +1777,8 @@ enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char ** { if (error) *error = stream->error; + if (stream->state == PW_STREAM_STATE_ERROR) + errno = -stream->error_res; return stream->state; } diff --git a/src/pipewire/stream.h b/src/pipewire/stream.h index 1a84f30ff..8e8ba0950 100644 --- a/src/pipewire/stream.h +++ b/src/pipewire/stream.h @@ -412,7 +412,8 @@ struct pw_stream_events { uint32_t version; void (*destroy) (void *data); - /** when the stream state changes */ + /** when the stream state changes. Since 1.4 this also sets errno when the + * new state is PW_STREAM_STATE_ERROR */ void (*state_changed) (void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error); @@ -517,6 +518,8 @@ void pw_stream_add_listener(struct pw_stream *stream, const struct pw_stream_events *events, void *data); +/** Get the current stream state. Since 1.4 this also sets errno when the + * state is PW_STREAM_STATE_ERROR */ enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char **error); const char *pw_stream_get_name(struct pw_stream *stream);