+
+#define CHECK_SUCCESS_GOTO(rerror, expression, label) \
+ do { \
+ if (!(expression)) { \
+ rerror = AVERROR_EXTERNAL; \
+ goto label; \
+ } \
+ } while(0);
+
+#define CHECK_DEAD_GOTO(p, rerror, label) \
+ do { \
+ if (!(p)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((p)->context)) || \
+ !(p)->stream || !PA_STREAM_IS_GOOD(pa_stream_get_state((p)->stream))) { \
+ rerror = AVERROR_EXTERNAL; \
+ goto label; \
+ } \
+ } while(0);
+
+static void context_state_cb(pa_context *c, void *userdata) {
+ PulseData *p = userdata;
+
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal(p->mainloop, 0);
+ break;
+ }
+}
+
+static void stream_state_cb(pa_stream *s, void * userdata) {
+ PulseData *p = userdata;
+
+ switch (pa_stream_get_state(s)) {
+ case PA_STREAM_READY:
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ pa_threaded_mainloop_signal(p->mainloop, 0);
+ break;
+ }
+}
+
+static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
+ PulseData *p = userdata;
+
+ pa_threaded_mainloop_signal(p->mainloop, 0);
+}
+
+static void stream_latency_update_cb(pa_stream *s, void *userdata) {
+ PulseData *p = userdata;
+
+ pa_threaded_mainloop_signal(p->mainloop, 0);
+}
+
+static av_cold int pulse_close(AVFormatContext *s)
+{
+ PulseData *pd = s->priv_data;
+
+ if (pd->mainloop)
+ pa_threaded_mainloop_stop(pd->mainloop);
+
+ if (pd->stream)
+ pa_stream_unref(pd->stream);
+ pd->stream = NULL;
+
+ if (pd->context) {
+ pa_context_disconnect(pd->context);
+ pa_context_unref(pd->context);
+ }
+ pd->context = NULL;
+
+ if (pd->mainloop)
+ pa_threaded_mainloop_free(pd->mainloop);
+ pd->mainloop = NULL;
+
+ ff_timefilter_destroy(pd->timefilter);
+ pd->timefilter = NULL;
+
+ return 0;
+}
+