1From 3196a96a408a90f707dff3f31fa3d05d64aeb68a Mon Sep 17 00:00:00 2001
2From: Alessandro Decina <alessandro.d@gmail.com>
3Date: Tue, 13 Oct 2015 12:49:19 +1100
4Subject: [PATCH] nicesrc: spin the agent mainloop in a separate thread
5
6Don't run the mainloop from the srcpad task, since that can get blocked in the
7pipeline and cause unnecessary STUN retrasmissions (at best) and completely
8block the agent (at worst).
9---
10 gst/gstnicesrc.c | 158 ++++++++++++++++++++++++++++++++-----------------------
11 gst/gstnicesrc.h | 4 +-
12 2 files changed, 93 insertions(+), 69 deletions(-)
13
14diff --git a/gst/gstnicesrc.c b/gst/gstnicesrc.c
15index d369e09..eb59fe9 100644
16--- a/gst/gstnicesrc.c
17+++ b/gst/gstnicesrc.c
18@@ -48,6 +48,14 @@ GST_DEBUG_CATEGORY_STATIC (nicesrc_debug);
19
20 #define BUFFER_SIZE (65536)
21
22+static gboolean
23+gst_nice_src_start (
24+ GstBaseSrc *basesrc);
25+
26+static gboolean
27+gst_nice_src_stop (
28+ GstBaseSrc *basesrc);
29+
30 static GstFlowReturn
31 gst_nice_src_create (
32 GstPushSrc *basesrc,
33@@ -57,10 +65,6 @@ static gboolean
34 gst_nice_src_unlock (
35 GstBaseSrc *basesrc);
36
37-static gboolean
38-gst_nice_src_unlock_stop (
39- GstBaseSrc *basesrc);
40-
41 static void
42 gst_nice_src_set_property (
43 GObject *object,
44@@ -116,8 +120,9 @@ gst_nice_src_class_init (GstNiceSrcClass *klass)
45 gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_nice_src_create);
46
47 gstbasesrc_class = (GstBaseSrcClass *) klass;
48+ gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_nice_src_start);
49+ gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_nice_src_stop);
50 gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_nice_src_unlock);
51- gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_nice_src_unlock_stop);
52
53 gobject_class = (GObjectClass *) klass;
54 gobject_class->set_property = gst_nice_src_set_property;
55@@ -179,9 +184,83 @@ gst_nice_src_init (GstNiceSrc *src)
56 src->component_id = 0;
57 src->mainctx = g_main_context_new ();
58 src->mainloop = g_main_loop_new (src->mainctx, FALSE);
59- src->unlocked = FALSE;
60- src->idle_source = NULL;
61 src->outbufs = g_queue_new ();
62+ src->agent_io_thread = NULL;
63+ g_cond_init (&src->outcond);
64+}
65+
66+static gpointer
67+gst_nice_src_agent_io_thread (gpointer data)
68+{
69+ GstNiceSrc *nicesrc = GST_NICE_SRC (data);
70+
71+ GST_INFO_OBJECT (nicesrc, "starting agent io thread");
72+ g_main_loop_run (nicesrc->mainloop);
73+ GST_INFO_OBJECT (nicesrc, "exiting agent io thread");
74+
75+ return NULL;
76+}
77+
78+static gboolean
79+main_loop_running_cb (gpointer data)
80+{
81+ GstNiceSrc *nicesrc = GST_NICE_SRC (data);
82+
83+ GST_OBJECT_LOCK (nicesrc);
84+ /* _start() and _stop() could both be waiting for the mainloop to start so we
85+ * need to broadcast */
86+ g_cond_broadcast (&nicesrc->outcond);
87+ GST_OBJECT_UNLOCK (nicesrc);
88+
89+ return FALSE;
90+}
91+
92+static gboolean
93+gst_nice_src_start (GstBaseSrc * basesrc)
94+{
95+ GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
96+ GSource *source;
97+ gchar *thread_name;
98+
99+ GST_OBJECT_LOCK (nicesrc);
100+ source = g_idle_source_new ();
101+ g_source_set_callback (source,
102+ (GSourceFunc) main_loop_running_cb, nicesrc, NULL);
103+ g_source_attach (source, nicesrc->mainctx);
104+ g_source_unref (source);
105+
106+ thread_name = g_strdup_printf ("%s:agent_io", GST_OBJECT_NAME (nicesrc));
107+ nicesrc->agent_io_thread = g_thread_new (thread_name, gst_nice_src_agent_io_thread, nicesrc);
108+ g_free (thread_name);
109+ /* wait until the agent thread starts spinning the mainloop or _stop() is
110+ * called */
111+ while (GST_BASE_SRC_IS_STARTING (basesrc) &&
112+ !g_main_loop_is_running (nicesrc->mainloop))
113+ g_cond_wait (&nicesrc->outcond, GST_OBJECT_GET_LOCK (nicesrc));
114+ GST_OBJECT_UNLOCK (nicesrc);
115+
116+ return TRUE;
117+}
118+
119+static gboolean
120+gst_nice_src_stop (GstBaseSrc * basesrc)
121+{
122+ GstNiceSrc *nicesrc = GST_NICE_SRC (basesrc);
123+ GThread *agent_io_thread = NULL;
124+
125+ GST_OBJECT_LOCK (nicesrc);
126+ /* here we wait for the agent thread created in _start() to be scheduled so
127+ * that we don't risk calling _quit() first and then _run() on the mainloop */
128+ while (!g_main_loop_is_running (nicesrc->mainloop))
129+ g_cond_wait (&nicesrc->outcond, GST_OBJECT_GET_LOCK (nicesrc));
130+ g_main_loop_quit (nicesrc->mainloop);
131+ agent_io_thread = nicesrc->agent_io_thread;
132+ nicesrc->agent_io_thread = NULL;
133+ GST_OBJECT_UNLOCK (nicesrc);
134+
135+ g_thread_join (agent_io_thread);
136+
137+ return TRUE;
138 }
139
140 static void
141@@ -207,62 +286,17 @@ gst_nice_src_read_callback (NiceAgent *agent,
142 #endif
143 GST_OBJECT_LOCK (nicesrc);
144 g_queue_push_tail (nicesrc->outbufs, buffer);
145- g_main_loop_quit (nicesrc->mainloop);
146+ g_cond_signal (&nicesrc->outcond);
147 GST_OBJECT_UNLOCK (nicesrc);
148 }
149
150 static gboolean
151-gst_nice_src_unlock_idler (gpointer data)
152-{
153- GstNiceSrc *nicesrc = GST_NICE_SRC (data);
154-
155- GST_OBJECT_LOCK (nicesrc);
156- if (nicesrc->unlocked)
157- g_main_loop_quit (nicesrc->mainloop);
158-
159- if (nicesrc->idle_source) {
160- g_source_destroy (nicesrc->idle_source);
161- g_source_unref (nicesrc->idle_source);
162- nicesrc->idle_source = NULL;
163- }
164- GST_OBJECT_UNLOCK (nicesrc);
165-
166- return FALSE;
167-}
168-
169-static gboolean
170 gst_nice_src_unlock (GstBaseSrc *src)
171 {
172 GstNiceSrc *nicesrc = GST_NICE_SRC (src);
173
174 GST_OBJECT_LOCK (src);
175- nicesrc->unlocked = TRUE;
176-
177- g_main_loop_quit (nicesrc->mainloop);
178-
179- if (!nicesrc->idle_source) {
180- nicesrc->idle_source = g_idle_source_new ();
181- g_source_set_priority (nicesrc->idle_source, G_PRIORITY_HIGH);
182- g_source_set_callback (nicesrc->idle_source, gst_nice_src_unlock_idler, src, NULL);
183- g_source_attach (nicesrc->idle_source, g_main_loop_get_context (nicesrc->mainloop));
184- }
185- GST_OBJECT_UNLOCK (src);
186-
187- return TRUE;
188-}
189-
190-static gboolean
191-gst_nice_src_unlock_stop (GstBaseSrc *src)
192-{
193- GstNiceSrc *nicesrc = GST_NICE_SRC (src);
194-
195- GST_OBJECT_LOCK (src);
196- nicesrc->unlocked = FALSE;
197- if (nicesrc->idle_source) {
198- g_source_destroy (nicesrc->idle_source);
199- g_source_unref(nicesrc->idle_source);
200- }
201- nicesrc->idle_source = NULL;
202+ g_cond_signal (&nicesrc->outcond);
203 GST_OBJECT_UNLOCK (src);
204
205 return TRUE;
206@@ -278,19 +312,8 @@ gst_nice_src_create (
207 GST_LOG_OBJECT (nicesrc, "create called");
208
209 GST_OBJECT_LOCK (basesrc);
210- if (nicesrc->unlocked) {
211- GST_OBJECT_UNLOCK (basesrc);
212-#if GST_CHECK_VERSION (1,0,0)
213- return GST_FLOW_FLUSHING;
214-#else
215- return GST_FLOW_WRONG_STATE;
216-#endif
217- }
218- if (g_queue_is_empty (nicesrc->outbufs)) {
219- GST_OBJECT_UNLOCK (basesrc);
220- g_main_loop_run (nicesrc->mainloop);
221- GST_OBJECT_LOCK (basesrc);
222- }
223+ if (g_queue_is_empty (nicesrc->outbufs))
224+ g_cond_wait (&nicesrc->outcond, GST_OBJECT_GET_LOCK (nicesrc));
225
226 *buffer = g_queue_pop_head (nicesrc->outbufs);
227 GST_OBJECT_UNLOCK (basesrc);
228@@ -331,6 +354,7 @@ gst_nice_src_dispose (GObject *object)
229 g_queue_free (src->outbufs);
230 }
231 src->outbufs = NULL;
232+ g_cond_clear (&src->outcond);
233
234 G_OBJECT_CLASS (gst_nice_src_parent_class)->dispose (object);
235 }
236diff --git a/gst/gstnicesrc.h b/gst/gstnicesrc.h
237index 5d3f554..2d9f674 100644
238--- a/gst/gstnicesrc.h
239+++ b/gst/gstnicesrc.h
240@@ -68,8 +68,8 @@ struct _GstNiceSrc
241 GMainContext *mainctx;
242 GMainLoop *mainloop;
243 GQueue *outbufs;
244- gboolean unlocked;
245- GSource *idle_source;
246+ GCond outcond;
247+ GThread *agent_io_thread;
248 };
249
250 typedef struct _GstNiceSrcClass GstNiceSrcClass;
251--
2522.3.4
253