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