webrtcbin: an element that handles the transport aspects of webrtc connections
[platform/upstream/gstreamer.git] / tests / examples / webrtc / webrtc.c
1 #include <gst/gst.h>
2 #include <gst/sdp/sdp.h>
3 #include <gst/webrtc/webrtc.h>
4
5 #include <string.h>
6
7 static GMainLoop *loop;
8 static GstElement *pipe1, *webrtc1, *webrtc2;
9 static GstBus *bus1;
10
11 static gboolean
12 _bus_watch (GstBus * bus, GstMessage * msg, GstElement * pipe)
13 {
14   switch (GST_MESSAGE_TYPE (msg)) {
15     case GST_MESSAGE_STATE_CHANGED:
16       if (GST_ELEMENT (msg->src) == pipe) {
17         GstState old, new, pending;
18
19         gst_message_parse_state_changed (msg, &old, &new, &pending);
20
21         {
22           gchar *dump_name = g_strconcat ("state_changed-",
23               gst_element_state_get_name (old), "_",
24               gst_element_state_get_name (new), NULL);
25           GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (msg->src),
26               GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
27           g_free (dump_name);
28         }
29       }
30       break;
31     case GST_MESSAGE_ERROR:{
32       GError *err = NULL;
33       gchar *dbg_info = NULL;
34
35       GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipe),
36           GST_DEBUG_GRAPH_SHOW_ALL, "error");
37
38       gst_message_parse_error (msg, &err, &dbg_info);
39       g_printerr ("ERROR from element %s: %s\n",
40           GST_OBJECT_NAME (msg->src), err->message);
41       g_printerr ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
42       g_error_free (err);
43       g_free (dbg_info);
44       g_main_loop_quit (loop);
45       break;
46     }
47     case GST_MESSAGE_EOS:{
48       GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipe),
49           GST_DEBUG_GRAPH_SHOW_ALL, "eos");
50       g_print ("EOS received\n");
51       g_main_loop_quit (loop);
52       break;
53     }
54     default:
55       break;
56   }
57
58   return TRUE;
59 }
60
61 static void
62 _webrtc_pad_added (GstElement * webrtc, GstPad * new_pad, GstElement * pipe)
63 {
64   GstElement *out;
65   GstPad *sink;
66
67   if (GST_PAD_DIRECTION (new_pad) != GST_PAD_SRC)
68     return;
69
70   out = gst_parse_bin_from_description ("rtpvp8depay ! vp8dec ! "
71       "videoconvert ! queue ! xvimagesink sync=false", TRUE, NULL);
72   gst_bin_add (GST_BIN (pipe), out);
73   gst_element_sync_state_with_parent (out);
74
75   sink = out->sinkpads->data;
76
77   gst_pad_link (new_pad, sink);
78 }
79
80 static void
81 _on_answer_received (GstPromise * promise, gpointer user_data)
82 {
83   GstWebRTCSessionDescription *answer = NULL;
84   const GstStructure *reply;
85   gchar *desc;
86
87   g_assert (gst_promise_wait (promise) == GST_PROMISE_RESULT_REPLIED);
88   reply = gst_promise_get_reply (promise);
89   gst_structure_get (reply, "answer",
90       GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL);
91   gst_promise_unref (promise);
92   desc = gst_sdp_message_as_text (answer->sdp);
93   g_print ("Created answer:\n%s\n", desc);
94   g_free (desc);
95
96   g_signal_emit_by_name (webrtc1, "set-remote-description", answer, NULL);
97   g_signal_emit_by_name (webrtc2, "set-local-description", answer, NULL);
98
99   gst_webrtc_session_description_free (answer);
100 }
101
102 static void
103 _on_offer_received (GstPromise * promise, gpointer user_data)
104 {
105   GstWebRTCSessionDescription *offer = NULL;
106   const GstStructure *reply;
107   gchar *desc;
108
109   g_assert (gst_promise_wait (promise) == GST_PROMISE_RESULT_REPLIED);
110   reply = gst_promise_get_reply (promise);
111   gst_structure_get (reply, "offer",
112       GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
113   gst_promise_unref (promise);
114   desc = gst_sdp_message_as_text (offer->sdp);
115   g_print ("Created offer:\n%s\n", desc);
116   g_free (desc);
117
118   g_signal_emit_by_name (webrtc1, "set-local-description", offer, NULL);
119   g_signal_emit_by_name (webrtc2, "set-remote-description", offer, NULL);
120
121   promise = gst_promise_new_with_change_func (_on_answer_received, user_data,
122       NULL);
123   g_signal_emit_by_name (webrtc2, "create-answer", NULL, promise);
124
125   gst_webrtc_session_description_free (offer);
126 }
127
128 static void
129 _on_negotiation_needed (GstElement * element, gpointer user_data)
130 {
131   GstPromise *promise;
132
133   promise = gst_promise_new_with_change_func (_on_offer_received, user_data,
134       NULL);
135   g_signal_emit_by_name (webrtc1, "create-offer", NULL, promise);
136 }
137
138 static void
139 _on_ice_candidate (GstElement * webrtc, guint mlineindex, gchar * candidate,
140     GstElement * other)
141 {
142   g_signal_emit_by_name (other, "add-ice-candidate", mlineindex, candidate);
143 }
144
145 int
146 main (int argc, char *argv[])
147 {
148   gst_init (&argc, &argv);
149
150   loop = g_main_loop_new (NULL, FALSE);
151   pipe1 =
152       gst_parse_launch
153       ("videotestsrc ! video/x-raw,framerate=1/1 ! queue ! vp8enc ! rtpvp8pay ! queue ! "
154       "application/x-rtp,media=video,payload=96,encoding-name=VP8 ! "
155       "webrtcbin name=send webrtcbin name=recv", NULL);
156   bus1 = gst_pipeline_get_bus (GST_PIPELINE (pipe1));
157   gst_bus_add_watch (bus1, (GstBusFunc) _bus_watch, pipe1);
158
159   webrtc1 = gst_bin_get_by_name (GST_BIN (pipe1), "send");
160   g_signal_connect (webrtc1, "on-negotiation-needed",
161       G_CALLBACK (_on_negotiation_needed), NULL);
162   webrtc2 = gst_bin_get_by_name (GST_BIN (pipe1), "recv");
163   g_signal_connect (webrtc2, "pad-added", G_CALLBACK (_webrtc_pad_added),
164       pipe1);
165   g_signal_connect (webrtc1, "on-ice-candidate",
166       G_CALLBACK (_on_ice_candidate), webrtc2);
167   g_signal_connect (webrtc2, "on-ice-candidate",
168       G_CALLBACK (_on_ice_candidate), webrtc1);
169
170   g_print ("Starting pipeline\n");
171   gst_element_set_state (GST_ELEMENT (pipe1), GST_STATE_PLAYING);
172
173   g_main_loop_run (loop);
174
175   gst_element_set_state (GST_ELEMENT (pipe1), GST_STATE_NULL);
176   g_print ("Pipeline stopped\n");
177
178   gst_object_unref (webrtc1);
179   gst_object_unref (webrtc2);
180   gst_bus_remove_watch (bus1);
181   gst_object_unref (bus1);
182   gst_object_unref (pipe1);
183
184   gst_deinit ();
185
186   return 0;
187 }