}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
switch (new_state) {
case PA_SINK_SUSPENDED: {
}
/* Called from the IO thread. */
-static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) {
+static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
switch (new_state) {
case PA_SOURCE_SUSPENDED: {
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) {
+static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) {
+static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
bool running;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
running = new_state == PA_SINK_RUNNING;
pa_atomic_store(&u->thread_info.running, running);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
switch (new_state) {
case PA_SINK_SUSPENDED:
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) {
+static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) {
+static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
switch (new_state) {
case PA_SINK_SUSPENDED:
}
/* Called from the IO thread. */
-static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) {
+static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
switch (new_state) {
case PA_SOURCE_SUSPENDED:
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
if (!u->stream || pa_stream_get_state(u->stream) != PA_STREAM_READY)
return 0;
}
/* Called from the IO thread. */
-static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) {
+static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
if (!u->stream || pa_stream_get_state(u->stream) != PA_STREAM_READY)
return 0;
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
bool do_trigger = false;
bool quick = true;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
switch (new_state) {
case PA_SINK_SUSPENDED:
}
/* Called from the IO thread. */
-static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) {
+static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
bool do_trigger = false;
bool quick = true;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
switch (new_state) {
case PA_SOURCE_SUSPENDED:
}
/* Called from the IO thread. */
-static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
+static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
pa_assert(s);
pa_assert_se(u = s->userdata);
+ /* It may be that only the suspend cause is changing, in which case there's
+ * nothing to do. */
+ if (new_state == s->thread_info.state)
+ return 0;
+
switch (new_state) {
case PA_SINK_SUSPENDED:
pa_log_debug("RAOP: SUSPENDED");
int ret;
};
+struct set_state_data {
+ pa_sink_state_t state;
+ pa_suspend_cause_t suspend_cause;
+};
+
static void sink_free(pa_object *s);
static void pa_sink_volume_change_push(pa_sink *s);
* current approach of not setting any suspend cause works well enough. */
if (s->set_state_in_main_thread) {
- ret = s->set_state_in_main_thread(s, state, suspend_cause);
- /* set_state_in_main_thread() is allowed to fail only when resuming. */
- pa_assert(ret >= 0 || resuming);
+ if ((ret = s->set_state_in_main_thread(s, state, suspend_cause)) < 0) {
+ /* set_state_in_main_thread() is allowed to fail only when resuming. */
+ pa_assert(resuming);
+
+ /* If resuming fails, we set the state to SUSPENDED and
+ * suspend_cause to 0. */
+ state = PA_SINK_SUSPENDED;
+ suspend_cause = 0;
+ state_changed = false;
+ suspend_cause_changed = suspend_cause != s->suspend_cause;
+ resuming = false;
+
+ /* We know the state isn't changing. If the suspend cause isn't
+ * changing either, then there's nothing more to do. */
+ if (!suspend_cause_changed)
+ return ret;
+ }
}
- if (ret >= 0 && s->asyncmsgq && state_changed)
- if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
+ if (s->asyncmsgq) {
+ struct set_state_data data = { .state = state, .suspend_cause = suspend_cause };
+
+ if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, &data, 0, NULL)) < 0) {
/* SET_STATE is allowed to fail only when resuming. */
pa_assert(resuming);
if (s->set_state_in_main_thread)
s->set_state_in_main_thread(s, PA_SINK_SUSPENDED, 0);
+
+ /* If resuming fails, we set the state to SUSPENDED and
+ * suspend_cause to 0. */
+ state = PA_SINK_SUSPENDED;
+ suspend_cause = 0;
+ state_changed = false;
+ suspend_cause_changed = suspend_cause != s->suspend_cause;
+ resuming = false;
+
+ /* We know the state isn't changing. If the suspend cause isn't
+ * changing either, then there's nothing more to do. */
+ if (!suspend_cause_changed)
+ return ret;
}
+ }
if (suspend_cause_changed) {
char old_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE];
s->suspend_cause = suspend_cause;
}
- if (ret < 0)
- goto finish;
-
if (state_changed) {
pa_log_debug("%s: state: %s -> %s", s->name, pa_sink_state_to_string(s->state), pa_sink_state_to_string(state));
s->state = state;
i->suspend(i, state == PA_SINK_SUSPENDED);
}
-finish:
if ((suspending || resuming || suspend_cause_changed) && s->monitor_source && state != PA_SINK_UNLINKED)
pa_source_sync_suspend(s->monitor_source);
return 0;
case PA_SINK_MESSAGE_SET_STATE: {
-
+ struct set_state_data *data = userdata;
bool suspend_change =
- (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
- (PA_SINK_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SINK_SUSPENDED);
+ (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(data->state)) ||
+ (PA_SINK_IS_OPENED(s->thread_info.state) && data->state == PA_SINK_SUSPENDED);
if (s->set_state_in_io_thread) {
int r;
- if ((r = s->set_state_in_io_thread(s, PA_PTR_TO_UINT(userdata))) < 0)
+ if ((r = s->set_state_in_io_thread(s, data->state, data->suspend_cause)) < 0)
return r;
}
- s->thread_info.state = PA_PTR_TO_UINT(userdata);
+ s->thread_info.state = data->state;
if (s->thread_info.state == PA_SINK_SUSPENDED) {
s->thread_info.rewind_nbytes = 0;
* are updated only after all the callback calls. In case of failure, the
* state is set to SUSPENDED and the suspend cause is set to 0. */
int (*set_state_in_main_thread)(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause); /* may be NULL */
- int (*set_state_in_io_thread)(pa_sink *s, pa_sink_state_t state); /* may be NULL */
+ int (*set_state_in_io_thread)(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause); /* may be NULL */
/* Sink drivers that support hardware volume may set this
* callback. This is called when the current volume needs to be
int ret;
};
+struct set_state_data {
+ pa_source_state_t state;
+ pa_suspend_cause_t suspend_cause;
+};
+
static void source_free(pa_object *o);
static void pa_source_volume_change_push(pa_source *s);
* current approach of not setting any suspend cause works well enough. */
if (s->set_state_in_main_thread) {
- ret = s->set_state_in_main_thread(s, state, suspend_cause);
- /* set_state_in_main_thread() is allowed to fail only when resuming. */
- pa_assert(ret >= 0 || resuming);
+ if ((ret = s->set_state_in_main_thread(s, state, suspend_cause)) < 0) {
+ /* set_state_in_main_thread() is allowed to fail only when resuming. */
+ pa_assert(resuming);
+
+ /* If resuming fails, we set the state to SUSPENDED and
+ * suspend_cause to 0. */
+ state = PA_SOURCE_SUSPENDED;
+ suspend_cause = 0;
+ state_changed = false;
+ suspend_cause_changed = suspend_cause != s->suspend_cause;
+ resuming = false;
+
+ /* We know the state isn't changing. If the suspend cause isn't
+ * changing either, then there's nothing more to do. */
+ if (!suspend_cause_changed)
+ return ret;
+ }
}
- if (ret >= 0 && s->asyncmsgq && state_changed)
- if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
+ if (s->asyncmsgq) {
+ struct set_state_data data = { .state = state, .suspend_cause = suspend_cause };
+
+ if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, &data, 0, NULL)) < 0) {
/* SET_STATE is allowed to fail only when resuming. */
pa_assert(resuming);
if (s->set_state_in_main_thread)
s->set_state_in_main_thread(s, PA_SOURCE_SUSPENDED, 0);
+
+ /* If resuming fails, we set the state to SUSPENDED and
+ * suspend_cause to 0. */
+ state = PA_SOURCE_SUSPENDED;
+ suspend_cause = 0;
+ state_changed = false;
+ suspend_cause_changed = suspend_cause != s->suspend_cause;
+ resuming = false;
+
+ /* We know the state isn't changing. If the suspend cause isn't
+ * changing either, then there's nothing more to do. */
+ if (!suspend_cause_changed)
+ return ret;
}
+ }
if (suspend_cause_changed) {
char old_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE];
s->suspend_cause = suspend_cause;
}
- if (ret < 0)
- goto finish;
-
if (state_changed) {
pa_log_debug("%s: state: %s -> %s", s->name, pa_source_state_to_string(s->state), pa_source_state_to_string(state));
s->state = state;
o->suspend(o, state == PA_SOURCE_SUSPENDED);
}
-finish:
return ret;
}
return 0;
case PA_SOURCE_MESSAGE_SET_STATE: {
-
+ struct set_state_data *data = userdata;
bool suspend_change =
- (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
- (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
+ (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(data->state)) ||
+ (PA_SOURCE_IS_OPENED(s->thread_info.state) && data->state == PA_SOURCE_SUSPENDED);
if (s->set_state_in_io_thread) {
int r;
- if ((r = s->set_state_in_io_thread(s, PA_PTR_TO_UINT(userdata))) < 0)
+ if ((r = s->set_state_in_io_thread(s, data->state, data->suspend_cause)) < 0)
return r;
}
- s->thread_info.state = PA_PTR_TO_UINT(userdata);
+ s->thread_info.state = data->state;
if (suspend_change) {
pa_source_output *o;
* are updated only after all the callback calls. In case of failure, the
* state is set to SUSPENDED and the suspend cause is set to 0. */
int (*set_state_in_main_thread)(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause); /* may be NULL */
- int (*set_state_in_io_thread)(pa_source *s, pa_source_state_t state); /* may be NULL */
+ int (*set_state_in_io_thread)(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause); /* may be NULL */
/* Called when the volume is queried. Called from main loop
* context. If this is NULL a PA_SOURCE_MESSAGE_GET_VOLUME message