]> git.0d.be Git - empathy.git/blob - src/empathy-call-window.c
stop the pipeline and unref everything when the window goes away
[empathy.git] / src / empathy-call-window.c
1 /*
2  * empathy-call-window.c - Source for EmpathyCallWindow
3  * Copyright (C) 2008 Collabora Ltd.
4  * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <gst/gst.h>
26
27 #include <libempathy-gtk/empathy-video-widget.h>
28 #include <libempathy-gtk/empathy-audio-src.h>
29 #include <libempathy-gtk/empathy-audio-sink.h>
30 #include <libempathy-gtk/empathy-video-src.h>
31
32 #include "empathy-call-window.h"
33
34 G_DEFINE_TYPE(EmpathyCallWindow, empathy_call_window, GTK_TYPE_WINDOW)
35
36 /* signal enum */
37 #if 0
38 enum
39 {
40     LAST_SIGNAL
41 };
42
43 static guint signals[LAST_SIGNAL] = {0};
44 #endif
45
46 enum {
47   PROP_CALL_HANDLER = 1,
48 };
49
50 /* private structure */
51 typedef struct _EmpathyCallWindowPriv EmpathyCallWindowPriv;
52
53 struct _EmpathyCallWindowPriv
54 {
55   gboolean dispose_has_run;
56   EmpathyCallHandler *handler;
57   GtkWidget *video_output;
58   GtkWidget *video_preview;
59   GstElement *video_input;
60   GstElement *audio_input;
61   GstElement *audio_output;
62   GstElement *pipeline;
63   GstElement *video_tee;
64 };
65
66 #define GET_PRIV(o) \
67   (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_CALL_WINDOW, \
68     EmpathyCallWindowPriv))
69
70 static void empathy_call_window_realized_cb (GtkWidget *widget,
71   EmpathyCallWindow *window);
72
73 static gboolean empathy_call_window_delete_cb (GtkWidget *widget,
74   GdkEvent*event, EmpathyCallWindow *window);
75
76 static void
77 empathy_call_window_init (EmpathyCallWindow *self)
78 {
79   EmpathyCallWindowPriv *priv = GET_PRIV (self);
80   GtkWidget *hbox;
81   GstBus *bus;
82
83   priv->pipeline = gst_pipeline_new (NULL);
84
85   hbox = gtk_hbox_new (TRUE, 3);
86   gtk_container_add (GTK_CONTAINER (self), hbox);
87
88   bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
89
90   priv->video_output = empathy_video_widget_new (bus);
91
92   priv->video_tee = gst_element_factory_make ("tee", NULL);
93   gst_object_ref (priv->video_tee);
94   gst_object_sink (priv->video_tee);
95
96   priv->video_preview = empathy_video_widget_new (bus);
97
98   priv->video_input = empathy_video_src_new ();
99   gst_object_ref (priv->video_input);
100   gst_object_sink (priv->video_input);
101
102   priv->audio_input = empathy_audio_src_new ();
103   gst_object_ref (priv->audio_input);
104   gst_object_sink (priv->audio_input);
105
106   priv->audio_output = empathy_audio_sink_new ();
107   gst_object_ref (priv->audio_output);
108   gst_object_sink (priv->audio_output);
109
110   g_object_unref (bus);
111
112   gtk_box_pack_start (GTK_BOX (hbox), priv->video_preview, TRUE, TRUE, 3);
113   gtk_box_pack_start (GTK_BOX (hbox), priv->video_output, TRUE, TRUE, 3);
114
115   gtk_widget_show_all (hbox);
116
117   g_signal_connect (G_OBJECT (self), "realize",
118     G_CALLBACK (empathy_call_window_realized_cb), self);
119
120   g_signal_connect (G_OBJECT (self), "delete-event",
121     G_CALLBACK (empathy_call_window_delete_cb), self);
122 }
123
124 static void empathy_call_window_dispose (GObject *object);
125 static void empathy_call_window_finalize (GObject *object);
126
127 static void
128 empathy_call_window_set_property (GObject *object,
129   guint property_id, const GValue *value, GParamSpec *pspec)
130 {
131   EmpathyCallWindowPriv *priv = GET_PRIV (object);
132
133   switch (property_id)
134     {
135       case PROP_CALL_HANDLER:
136         priv->handler = g_value_dup_object (value);
137         break;
138       default:
139         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
140     }
141 }
142
143 static void
144 empathy_call_window_get_property (GObject *object,
145   guint property_id, GValue *value, GParamSpec *pspec)
146 {
147   EmpathyCallWindowPriv *priv = GET_PRIV (object);
148
149   switch (property_id)
150     {
151       case PROP_CALL_HANDLER:
152         g_value_set_object (value, priv->handler);
153         break;
154       default:
155         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
156     }
157 }
158
159 static void
160 empathy_call_window_class_init (
161   EmpathyCallWindowClass *empathy_call_window_class)
162 {
163   GObjectClass *object_class = G_OBJECT_CLASS (empathy_call_window_class);
164   GParamSpec *param_spec;
165
166   g_type_class_add_private (empathy_call_window_class,
167     sizeof (EmpathyCallWindowPriv));
168
169   object_class->set_property = empathy_call_window_set_property;
170   object_class->get_property = empathy_call_window_get_property;
171
172   object_class->dispose = empathy_call_window_dispose;
173   object_class->finalize = empathy_call_window_finalize;
174
175   param_spec = g_param_spec_object ("handler",
176     "handler", "The call handler",
177     EMPATHY_TYPE_CALL_HANDLER,
178     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
179   g_object_class_install_property (object_class,
180     PROP_CALL_HANDLER, param_spec);
181
182 }
183
184 void
185 empathy_call_window_dispose (GObject *object)
186 {
187   EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object);
188   EmpathyCallWindowPriv *priv = GET_PRIV (self);
189
190   if (priv->dispose_has_run)
191     return;
192
193   priv->dispose_has_run = TRUE;
194
195   if (priv->handler != NULL)
196     g_object_unref (priv->handler);
197
198   priv->handler = NULL;
199
200   if (priv->pipeline != NULL)
201     g_object_unref (priv->pipeline);
202   priv->pipeline = NULL;
203
204   if (priv->video_input != NULL)
205     g_object_unref (priv->video_input);
206   priv->video_input = NULL;
207
208   if (priv->audio_input != NULL)
209     g_object_unref (priv->audio_input);
210   priv->audio_input = NULL;
211
212   if (priv->audio_output != NULL)
213     g_object_unref (priv->audio_output);
214   priv->audio_output = NULL;
215
216   if (priv->video_tee != NULL)
217     g_object_unref (priv->video_tee);
218   priv->video_tee = NULL;
219
220   /* release any references held by the object here */
221   if (G_OBJECT_CLASS (empathy_call_window_parent_class)->dispose)
222     G_OBJECT_CLASS (empathy_call_window_parent_class)->dispose (object);
223 }
224
225 void
226 empathy_call_window_finalize (GObject *object)
227 {
228   //EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object);
229   //EmpathyCallWindowPriv *priv = GET_PRIV (self);
230
231   /* free any data held directly by the object here */
232
233   G_OBJECT_CLASS (empathy_call_window_parent_class)->finalize (object);
234 }
235
236
237 EmpathyCallWindow *
238 empathy_call_window_new (EmpathyCallHandler *handler)
239 {
240   return EMPATHY_CALL_WINDOW (
241     g_object_new (EMPATHY_TYPE_CALL_WINDOW, "handler", handler, NULL));
242 }
243
244 static void
245 empathy_call_window_conference_added_cb (EmpathyCallHandler *handler,
246   GstElement *conference, gpointer user_data)
247 {
248   EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (user_data);
249   EmpathyCallWindowPriv *priv = GET_PRIV (self);
250
251   gst_bin_add (GST_BIN (priv->pipeline), conference);
252
253   gst_element_set_state (conference, GST_STATE_PLAYING);
254
255   printf ("ADDING CONFERENCE\n");
256 }
257
258 static void
259 empathy_call_window_src_added_cb (EmpathyCallHandler *handler,
260   GstPad *src, guint media_type, gpointer user_data)
261 {
262   EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (user_data);
263   EmpathyCallWindowPriv *priv = GET_PRIV (self);
264
265   GstPad *pad;
266   GstElement *element;
267
268   printf ("ADDING SRC PAD %d\n", media_type);
269
270   switch (media_type)
271     {
272       case TP_MEDIA_STREAM_TYPE_AUDIO:
273         element = priv->audio_output;
274         g_object_ref (element);
275         break;
276       case TP_MEDIA_STREAM_TYPE_VIDEO:
277         element =
278           empathy_video_widget_get_element (
279             EMPATHY_VIDEO_WIDGET (priv->video_output));
280         break;
281       default:
282         g_assert_not_reached ();
283     }
284
285   gst_bin_add (GST_BIN (priv->pipeline), element);
286
287   pad = gst_element_get_static_pad (element, "sink");
288   gst_element_set_state (element, GST_STATE_PLAYING);
289
290   gst_pad_link (src, pad);
291 }
292
293 static void
294 empathy_call_window_sink_added_cb (EmpathyCallHandler *handler,
295   GstPad *sink, guint media_type, gpointer user_data)
296 {
297   EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (user_data);
298   EmpathyCallWindowPriv *priv = GET_PRIV (self);
299   GstPad *pad;
300
301   printf ("ADDING SINK PAD %d\n", media_type);
302
303   switch (media_type)
304     {
305       case TP_MEDIA_STREAM_TYPE_AUDIO:
306         gst_bin_add (GST_BIN (priv->pipeline), priv->audio_input);
307         gst_element_set_state (priv->audio_input, GST_STATE_PLAYING);
308
309         pad = gst_element_get_static_pad (priv->audio_input, "src");
310         gst_pad_link (pad, sink);
311         break;
312       case TP_MEDIA_STREAM_TYPE_VIDEO:
313         pad =  gst_element_get_request_pad (priv->video_tee, "src%d");
314         gst_pad_link (pad, sink);
315         break;
316       default:
317         g_assert_not_reached ();
318     }
319
320 }
321
322 static void
323 empathy_call_window_realized_cb (GtkWidget *widget, EmpathyCallWindow *window)
324 {
325   EmpathyCallWindowPriv *priv = GET_PRIV (window);
326   GstElement *preview;
327   GstBus *bus;
328
329   g_signal_connect (priv->handler, "conference-added",
330     G_CALLBACK (empathy_call_window_conference_added_cb), window);
331   g_signal_connect (priv->handler, "src-pad-added",
332     G_CALLBACK (empathy_call_window_src_added_cb), window);
333   g_signal_connect (priv->handler, "sink-pad-added",
334     G_CALLBACK (empathy_call_window_sink_added_cb), window);
335
336   bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
337   empathy_call_handler_set_bus (priv->handler, bus);
338   empathy_call_handler_start_call (priv->handler);
339
340   preview = empathy_video_widget_get_element (
341     EMPATHY_VIDEO_WIDGET (priv->video_preview));
342
343   gst_bin_add_many (GST_BIN (priv->pipeline), priv->video_input,
344     priv->video_tee, preview, NULL);
345   gst_element_link_many (priv->video_input, priv->video_tee,
346     preview, NULL);
347
348   gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
349
350   g_object_unref (bus);
351 }
352
353 static gboolean
354 empathy_call_window_delete_cb (GtkWidget *widget, GdkEvent*event,
355   EmpathyCallWindow *window)
356 {
357   EmpathyCallWindowPriv *priv = GET_PRIV (window);
358
359   gst_element_set_state (priv->pipeline, GST_STATE_NULL);
360
361   return FALSE;
362 }