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
This commit is contained in:
Wim Taymans 2025-03-04 12:50:38 +01:00
parent 491fb26f18
commit 3905e3b3d3
7 changed files with 27 additions and 7 deletions

View file

@ -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) { if (state == PW_STREAM_STATE_ERROR) {
pw_log_warn("%s", error); pw_log_warn("%s", error);
pw->error = -EIO; pw->error = -errno;
update_active(&pw->io); update_active(&pw->io);
} }
} }

View file

@ -1696,7 +1696,7 @@ static int connect_stream(struct file *file)
break; break;
if (state == PW_STREAM_STATE_ERROR) { if (state == PW_STREAM_STATE_ERROR) {
res = -EIO; res = -errno;
goto exit; goto exit;
} }
if (file->error < 0) { if (file->error < 0) {

View file

@ -1109,7 +1109,7 @@ static void stream_state_changed(void *data, enum pw_stream_state old,
switch (state) { switch (state) {
case PW_STREAM_STATE_ERROR: case PW_STREAM_STATE_ERROR:
reply_error(client, -1, stream->create_tag, -EIO); reply_error(client, -1, stream->create_tag, -errno);
destroy_stream = true; destroy_stream = true;
break; break;
case PW_STREAM_STATE_UNCONNECTED: case PW_STREAM_STATE_UNCONNECTED:

View file

@ -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(old),
pw_filter_state_as_string(state), res, error); 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); pw_log_error("%p: error (%d) %s", filter, res, error);
errno = -res;
}
filter->state = state; filter->state = state;
pw_filter_emit_state_changed(filter, old, state, error); 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) static void proxy_error(void *_data, int seq, int res, const char *message)
{ {
struct pw_filter *filter = _data; struct pw_filter *filter = _data;
int old_errno = errno;
/* we just emit the state change here to inform the application. /* we just emit the state change here to inform the application.
* If this is supposed to be a permanent error, the app should * If this is supposed to be a permanent error, the app should
* do a pw_filter_set_error() */ * do a pw_filter_set_error() */
errno = -res;
pw_filter_emit_state_changed(filter, filter->state, pw_filter_emit_state_changed(filter, filter->state,
PW_FILTER_STATE_ERROR, message); PW_FILTER_STATE_ERROR, message);
errno = old_errno;
} }
static void proxy_bound_props(void *_data, uint32_t global_id, const struct spa_dict *props) 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) if (error)
*error = filter->error; *error = filter->error;
if (filter->state == PW_FILTER_STATE_ERROR)
errno = -filter->error_res;
return filter->state; return filter->state;
} }

View file

@ -62,7 +62,8 @@ struct pw_filter_events {
uint32_t version; uint32_t version;
void (*destroy) (void *data); 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, void (*state_changed) (void *data, enum pw_filter_state old,
enum pw_filter_state state, const char *error); 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, const struct pw_filter_events *events,
void *data); 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); 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); const char *pw_filter_get_name(struct pw_filter *filter);

View file

@ -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(old),
pw_stream_state_as_string(state), res, stream->error); 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); pw_log_error("%p: error (%d) %s", stream, res, error);
errno = -res;
}
stream->state = state; stream->state = state;
pw_stream_emit_state_changed(stream, old, state, error); 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) static void proxy_error(void *_data, int seq, int res, const char *message)
{ {
struct pw_stream *stream = _data; struct pw_stream *stream = _data;
int old_errno = errno;
/* we just emit the state change here to inform the application. /* we just emit the state change here to inform the application.
* If this is supposed to be a permanent error, the app should * If this is supposed to be a permanent error, the app should
* do a pw_stream_set_error() */ * do a pw_stream_set_error() */
errno = -res;
pw_stream_emit_state_changed(stream, stream->state, pw_stream_emit_state_changed(stream, stream->state,
PW_STREAM_STATE_ERROR, message); PW_STREAM_STATE_ERROR, message);
errno = old_errno;
} }
static void proxy_bound_props(void *data, uint32_t global_id, const struct spa_dict *props) 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) if (error)
*error = stream->error; *error = stream->error;
if (stream->state == PW_STREAM_STATE_ERROR)
errno = -stream->error_res;
return stream->state; return stream->state;
} }

View file

@ -412,7 +412,8 @@ struct pw_stream_events {
uint32_t version; uint32_t version;
void (*destroy) (void *data); 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, void (*state_changed) (void *data, enum pw_stream_state old,
enum pw_stream_state state, const char *error); 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, const struct pw_stream_events *events,
void *data); 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); 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); const char *pw_stream_get_name(struct pw_stream *stream);