pulse-server: clean up killed and errored streams

Make a stream in error or unconnected as done and run the cleanup
loop to destroy them. Fixes leaks caused by pavucontrol.
This commit is contained in:
Wim Taymans 2020-11-16 13:31:15 +01:00
parent 6fa622d2d9
commit 9f9be7d7f2

View file

@ -187,6 +187,7 @@ struct stream {
unsigned int have_time:1; unsigned int have_time:1;
unsigned int is_underrun:1; unsigned int is_underrun:1;
unsigned int in_prebuf:1; unsigned int in_prebuf:1;
unsigned int done:1;
}; };
struct server { struct server {
@ -1166,22 +1167,25 @@ static void stream_state_changed(void *data, enum pw_stream_state old,
{ {
struct stream *stream = data; struct stream *stream = data;
struct client *client = stream->client; struct client *client = stream->client;
struct impl *impl = client->impl;
switch (state) { switch (state) {
case PW_STREAM_STATE_ERROR: case PW_STREAM_STATE_ERROR:
reply_error(client, -1, -1, -EIO); reply_error(client, -1, -1, -EIO);
stream->done = true;
break; break;
case PW_STREAM_STATE_UNCONNECTED: case PW_STREAM_STATE_UNCONNECTED:
if (!client->disconnecting) if (!client->disconnecting)
send_stream_killed(stream); send_stream_killed(stream);
stream->done = true;
break; break;
case PW_STREAM_STATE_CONNECTING: case PW_STREAM_STATE_CONNECTING:
break;
case PW_STREAM_STATE_PAUSED: case PW_STREAM_STATE_PAUSED:
break;
case PW_STREAM_STATE_STREAMING: case PW_STREAM_STATE_STREAMING:
break; break;
} }
if (stream->done)
pw_loop_signal_event(impl->loop, client->cleanup);
} }
static const struct spa_pod *get_buffers_param(struct stream *s, static const struct spa_pod *get_buffers_param(struct stream *s,
@ -4708,6 +4712,14 @@ exit:
return res; return res;
} }
static int client_cleanup_stream(void *item, void *data)
{
struct stream *s = item;
if (s->done)
stream_free(s);
return 0;
}
static void on_client_cleanup(void *data, uint64_t count) static void on_client_cleanup(void *data, uint64_t count)
{ {
struct client *client = data; struct client *client = data;
@ -4716,6 +4728,7 @@ static void on_client_cleanup(void *data, uint64_t count)
if (p->done) if (p->done)
pending_sample_free(p); pending_sample_free(p);
} }
pw_map_for_each(&client->streams, client_cleanup_stream, client);
} }
static void static void