1 /* GStreamer
2 * Copyright (C) 2016 Centricular Ltd.
3 * Author: Arun Raghavan <arun@centricular.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>
26
27 #define GST_NET_API /* empty */
28
29 /* We need the internal netclock estimation function to (re)run the code on
30 * captured samples, plus its dependencies for the build to succeed. */
31 #include "../../libs/gst/net/gstntppacket.c"
32 #include "../../libs/gst/net/gstnettimepacket.c"
33 #include "../../libs/gst/net/gstnetclientclock.c"
34 #include "../../libs/gst/net/gstnetutils.c"
35
36 static gchar *input = NULL;
37 static gboolean debug = FALSE;
38 static gint rtt_limit = 0;
39
40 static GOptionEntry entries[] = {
41 {"input", 'i', 0, G_OPTION_ARG_FILENAME, &input,
42 "Clock reading file containing one local and remote time readings, one "
43 "per line",
44 "FILE"},
45 {"rtt-limit", 'r', 0, G_OPTION_ARG_INT64, &rtt_limit,
46 "Round trip time limit on packets (in ms)", "MSEC"},
47 {"debug", 'd', 0, G_OPTION_ARG_NONE, &debug, "Verbose debug output", NULL},
48 {NULL,}
49 };
50
51 static gboolean
parse_time_values(const gchar * line,GstClockTime * local_1,GstClockTime * remote_1,GstClockTime * remote_2,GstClockTime * local_2)52 parse_time_values (const gchar * line, GstClockTime * local_1,
53 GstClockTime * remote_1, GstClockTime * remote_2, GstClockTime * local_2)
54 {
55 gchar **split;
56 gboolean ret = FALSE;
57
58 if (!line)
59 return FALSE;
60
61 split = g_strsplit (line, " ", -1);
62
63 if (g_strv_length (split) != 4)
64 goto out;
65
66 if (!g_ascii_string_to_unsigned (split[0], 10, 0, G_MAXUINT64, local_1, NULL))
67 goto out;
68
69 if (!g_ascii_string_to_unsigned (split[1], 10, 0, G_MAXUINT64, remote_1,
70 NULL))
71 goto out;
72
73 if (!g_ascii_string_to_unsigned (split[2], 10, 0, G_MAXUINT64, remote_2,
74 NULL))
75 goto out;
76
77 if (!g_ascii_string_to_unsigned (split[3], 10, 0, G_MAXUINT64, local_2, NULL))
78 goto out;
79
80 ret = TRUE;
81 out:
82 g_strfreev (split);
83 return ret;
84 }
85
86 int
main(int argc,char * argv[])87 main (int argc, char *argv[])
88 {
89 GstNetClientInternalClock *clock;
90 GstBus *bus;
91 GIOChannel *channel;
92 GIOStatus status;
93 GError *error = NULL;
94 GOptionContext *context;
95 gchar *line;
96 int ret = 1;
97
98 context = g_option_context_new (NULL);
99 g_option_context_add_main_entries (context, entries, NULL);
100 g_option_context_add_group (context, gst_init_get_option_group ());
101
102 if (!g_option_context_parse (context, &argc, &argv, &error)) {
103 g_print ("Failed to parse options: %s\n\n", error->message);
104 g_error_free (error);
105 return 1;
106 }
107
108 if (input) {
109 if (!(channel = g_io_channel_new_file (input, "r", NULL))) {
110 g_print ("Could not read input file: %s\n", input);
111 return 1;
112 }
113 } else {
114 if (!(channel = g_io_channel_unix_new (0))) {
115 g_print ("Could not read stdin");
116 return 1;
117 }
118 }
119
120 clock = g_object_new (GST_TYPE_NET_CLIENT_INTERNAL_CLOCK, NULL);
121 bus = gst_bus_new ();
122
123 /* FIXME: Find a way to do this without touching the structure internals */
124 if (rtt_limit)
125 clock->roundtrip_limit = rtt_limit * GST_MSECOND;
126 clock->busses = g_list_prepend (clock->busses, bus);
127
128 while ((status = g_io_channel_read_line (channel, &line, NULL, NULL,
129 &error)) == G_IO_STATUS_NORMAL) {
130 GstClockTime local_1, remote_1, remote_2, local_2;
131 GstMessage *message;
132
133 if (!parse_time_values (line, &local_1, &remote_1, &remote_2, &local_2)) {
134 g_print ("Failed to get local/remote time values from: %s\n", line);
135 goto done;
136 }
137
138 if (debug)
139 g_print ("%s", line);
140
141 gst_net_client_internal_clock_observe_times (clock, local_1, remote_1,
142 remote_2, local_2);
143
144 g_free (line);
145
146 if ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ELEMENT))) {
147 const GstStructure *st;
148 gchar *str;
149
150 st = gst_message_get_structure (message);
151 str = gst_structure_to_string (st);
152
153 g_print ("%s\n", str);
154
155 g_free (str);
156 gst_message_unref (message);
157 }
158 }
159
160 if (status == G_IO_CHANNEL_ERROR) {
161 g_print ("Error reading file: %s\n", error->message);
162 g_error_free (error);
163 goto done;
164 }
165
166 g_io_channel_unref (channel);
167 g_free (input);
168 gst_object_unref (bus);
169
170 ret = 0;
171
172 done:
173 return ret;
174 }
175