1 #include <gst/gst.h>
2 
3 static GMainLoop *loop = NULL;
4 static GstElement *backpipe = NULL;
5 static gint stream_id = -1;
6 
7 #define PCMU_CAPS "application/x-rtp, media=audio, payload=0, clock-rate=8000, encoding-name=PCMU"
8 
9 static GstFlowReturn
new_sample(GstElement * appsink,GstElement * rtspsrc)10 new_sample (GstElement * appsink, GstElement * rtspsrc)
11 {
12   GstSample *sample;
13   GstFlowReturn ret = GST_FLOW_OK;
14 
15   g_assert (stream_id != -1);
16 
17   g_signal_emit_by_name (appsink, "pull-sample", &sample);
18 
19   if (!sample)
20     goto out;
21 
22   g_signal_emit_by_name (rtspsrc, "push-backchannel-buffer", stream_id, sample,
23       &ret);
24 
25 out:
26   return ret;
27 }
28 
29 static void
setup_backchannel_shoveler(GstElement * rtspsrc,GstCaps * caps)30 setup_backchannel_shoveler (GstElement * rtspsrc, GstCaps * caps)
31 {
32   GstElement *appsink;
33 
34   backpipe = gst_parse_launch ("audiotestsrc is-live=true wave=red-noise ! "
35       "mulawenc ! rtppcmupay ! appsink name=out", NULL);
36   if (!backpipe)
37     g_error ("Could not setup backchannel pipeline");
38 
39   appsink = gst_bin_get_by_name (GST_BIN (backpipe), "out");
40   g_object_set (G_OBJECT (appsink), "caps", caps, "emit-signals", TRUE, NULL);
41 
42   g_signal_connect (appsink, "new-sample", G_CALLBACK (new_sample), rtspsrc);
43 
44   g_print ("Playing backchannel shoveler\n");
45   gst_element_set_state (backpipe, GST_STATE_PLAYING);
46 }
47 
48 static gboolean
remove_extra_fields(GQuark field_id,GValue * value G_GNUC_UNUSED,gpointer user_data G_GNUC_UNUSED)49 remove_extra_fields (GQuark field_id, GValue * value G_GNUC_UNUSED,
50     gpointer user_data G_GNUC_UNUSED)
51 {
52   return !g_str_has_prefix (g_quark_to_string (field_id), "a-");
53 }
54 
55 static gboolean
find_backchannel(GstElement * rtspsrc,guint idx,GstCaps * caps,gpointer user_data G_GNUC_UNUSED)56 find_backchannel (GstElement * rtspsrc, guint idx, GstCaps * caps,
57     gpointer user_data G_GNUC_UNUSED)
58 {
59   GstStructure *s;
60   gchar *caps_str = gst_caps_to_string (caps);
61   g_print ("Selecting stream idx %u, caps %s\n", idx, caps_str);
62   g_free (caps_str);
63 
64   s = gst_caps_get_structure (caps, 0);
65   if (gst_structure_has_field (s, "a-sendonly")) {
66     stream_id = idx;
67     caps = gst_caps_new_empty ();
68     s = gst_structure_copy (s);
69     gst_structure_set_name (s, "application/x-rtp");
70     gst_structure_filter_and_map_in_place (s, remove_extra_fields, NULL);
71     gst_caps_append_structure (caps, s);
72     setup_backchannel_shoveler (rtspsrc, caps);
73   }
74 
75   return TRUE;
76 }
77 
78 int
main(int argc,char * argv[])79 main (int argc, char *argv[])
80 {
81   GstElement *pipeline, *rtspsrc;
82   const gchar *location;
83 
84   gst_init (&argc, &argv);
85 
86   if (argc >= 2)
87     location = argv[1];
88   else
89     location = "rtsp://127.0.0.1:8554/test";
90 
91   loop = g_main_loop_new (NULL, FALSE);
92 
93   pipeline = gst_parse_launch ("rtspsrc backchannel=onvif debug=true name=r "
94       "r. ! queue ! decodebin ! queue ! xvimagesink async=false "
95       "r. ! queue ! decodebin ! queue ! pulsesink async=false ", NULL);
96   if (!pipeline)
97     g_error ("Failed to parse pipeline");
98 
99   rtspsrc = gst_bin_get_by_name (GST_BIN (pipeline), "r");
100   g_object_set (G_OBJECT (rtspsrc), "location", location, NULL);
101   g_signal_connect (rtspsrc, "select-stream", G_CALLBACK (find_backchannel),
102       NULL);
103 
104   gst_element_set_state (pipeline, GST_STATE_PLAYING);
105 
106   g_main_loop_run (loop);
107   return 0;
108 }
109