entirely start/stop hls server pipeline depending on http requests (fixes idle cpu...
[dreamrtspserver.git] / src / dreamrtspserver.h
1 /*
2  * GStreamer dreamrtspserver
3  * Copyright 2015-2016 Andreas Frisch <fraxinas@opendreambox.org>
4  *
5  * This program is licensed under the Creative Commons
6  * Attribution-NonCommercial-ShareAlike 3.0 Unported
7  * License. To view a copy of this license, visit
8  * http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
9  * Creative Commons,559 Nathan Abbott Way,Stanford,California 94305,USA.
10  *
11  * Alternatively, this program may be distributed and executed on
12  * hardware which is licensed by Dream Property GmbH.
13  *
14  * This program is NOT free software. It is open source, you are allowed
15  * to modify it (if you keep the license), but it may not be commercially
16  * distributed other than under the conditions noted above.
17  */
18
19 #ifndef __DREAMRTSPSERVER_H__
20 #define __DREAMRTSPSERVER_H__
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <sys/stat.h>
26 #include <gio/gio.h>
27 #include <glib-unix.h>
28 #include <gst/gst.h>
29 #include <gst/app/app.h>
30 #include <gst/rtsp-server/rtsp-server.h>
31 #include <libsoup/soup.h>
32 #include "gstdreamrtsp.h"
33
34 GST_DEBUG_CATEGORY (dreamrtspserver_debug);
35 #define GST_CAT_DEFAULT dreamrtspserver_debug
36
37 #define DEFAULT_RTSP_PORT 554
38 #define DEFAULT_RTSP_PATH "/stream"
39 #define RTSP_ES_PATH_SUFX "-es"
40
41 #define HLS_PATH "/tmp/hls"
42 #define HLS_FRAGMENT_DURATION 2
43 #define HLS_FRAGMENT_NAME "segment%05d.ts"
44 #define HLS_PLAYLIST_NAME "dream.m3u8"
45
46 #define TOKEN_LEN 36
47
48 #define AAPPSINK "aappsink"
49 #define VAPPSINK "vappsink"
50 #define TSAPPSINK "tsappsink"
51
52 #define ES_AAPPSRC "es_aappsrc"
53 #define ES_VAPPSRC "es_vappsrc"
54 #define TS_APPSRC "ts_appsrc"
55
56 #define TS_PACK_SIZE 188
57 #define TS_PER_FRAME 7
58 #define BLOCK_SIZE   TS_PER_FRAME*188
59 #define TOKEN_LEN    36
60
61 #define MAX_OVERRUNS 5
62 #define OVERRUN_TIME G_GINT64_CONSTANT(15)*GST_SECOND
63 #define BITRATE_AVG_PERIOD G_GINT64_CONSTANT(6)*GST_SECOND
64
65 #define RESUME_DELAY 20
66
67 #define AUTO_BITRATE TRUE
68
69 #define WATCHDOG_TIMEOUT 5
70
71 #if HAVE_UPSTREAM
72         #pragma message("building with mediator upstream feature")
73 #else
74         #pragma message("building without mediator upstream feature")
75 #endif
76
77 #define DREAMRTSPSERVER_LOCK(obj) G_STMT_START {   \
78     GST_LOG_OBJECT (obj,                           \
79                     "LOCKING from thread %p",      \
80                     g_thread_self ());             \
81     g_mutex_lock (&obj->rtsp_mutex);               \
82     GST_LOG_OBJECT (obj,                           \
83                     "LOCKED from thread %p",       \
84                     g_thread_self ());             \
85 } G_STMT_END
86
87 #define DREAMRTSPSERVER_UNLOCK(obj) G_STMT_START { \
88     GST_LOG_OBJECT (obj,                           \
89                     "UNLOCKING from thread %p",    \
90                     g_thread_self ());             \
91     g_mutex_unlock (&obj->rtsp_mutex);             \
92 } G_STMT_END
93
94 G_BEGIN_DECLS
95
96 typedef enum {
97         INPUT_MODE_LIVE = 0,
98         INPUT_MODE_HDMI_IN = 1,
99         INPUT_MODE_BACKGROUND = 2
100 } inputMode;
101
102 typedef enum {
103         UPSTREAM_STATE_DISABLED = 0,
104         UPSTREAM_STATE_CONNECTING = 1,
105         UPSTREAM_STATE_WAITING = 2,
106         UPSTREAM_STATE_TRANSMITTING = 3,
107         UPSTREAM_STATE_OVERLOAD = 4,
108         UPSTREAM_STATE_ADJUSTING = 5,
109         UPSTREAM_STATE_FAILED = 9
110 } upstreamState;
111
112 typedef enum {
113         RTSP_STATE_DISABLED = 0,
114         RTSP_STATE_IDLE = 1,
115         RTSP_STATE_RUNNING = 2
116 } rtspState;
117
118 typedef enum {
119         HLS_STATE_DISABLED = 0,
120         HLS_STATE_IDLE = 1,
121         HLS_STATE_RUNNING = 2
122 } hlsState;
123
124 typedef struct {
125         GstElement *tstcpq, *tcpsink;
126         char token[TOKEN_LEN+1];
127         upstreamState state;
128         guint overrun_counter;
129         GstClockTime overrun_period, measure_start;
130         guint id_signal_overrun, id_signal_waiting, id_signal_keepalive;
131         gulong id_resume, id_bitrate_measure;
132         gsize bitrate_sum;
133         gint bitrate_avg;
134         gboolean auto_bitrate;
135 } DreamTCPupstream;
136
137 typedef struct {
138         GstDreamRTSPServer *server;
139         GstRTSPMountPoints *mounts;
140         GstDreamRTSPMediaFactory *es_factory, *ts_factory;
141         GstRTSPMedia *es_media, *ts_media;
142         GstElement *artspq, *vrtspq, *tsrtspq;
143         GstElement *es_aappsrc, *es_vappsrc;
144         GstElement *ts_appsrc;
145         GstElement *aappsink, *vappsink, *tsappsink;
146         GstClockTime rtsp_start_pts, rtsp_start_dts;
147         gchar *rtsp_user, *rtsp_pass;
148         GList *clients_list;
149         gchar *rtsp_port;
150         gchar *rtsp_ts_path, *rtsp_es_path;
151         guint source_id;
152         rtspState state;
153         gchar *uri_parameters;
154 } DreamRTSPserver;
155
156 typedef struct {
157         gint audioBitrate, videoBitrate;
158         guint framerate, width, height;
159 } SourceProperties;
160
161 typedef struct {
162         GstElement *queue;
163         GstElement *hlssink;
164         hlsState state;
165         SoupServer *soupserver;
166         SoupAuthDomain *soupauthdomain;
167         guint port;
168         gchar *hls_user, *hls_pass;
169         guint id_timeout;
170 } DreamHLSserver;
171
172 typedef struct {
173         GDBusConnection *dbus_connection;
174         GMainLoop *loop;
175         GstElement *pipeline;
176         GstElement *asrc, *vsrc, *aparse, *vparse;
177         GstElement *tsmux, *tstee;
178         GstElement *aq, *vq;
179         GstElement *atee, *vtee;
180         DreamTCPupstream *tcp_upstream;
181         DreamRTSPserver *rtsp_server;
182         DreamHLSserver *hls_server;
183         GMutex rtsp_mutex;
184         GstClock *clock;
185         SourceProperties source_properties;
186 } App;
187
188 static const gchar service[] = "com.dreambox.RTSPserver";
189 static const gchar object_name[] = "/com/dreambox/RTSPserver";
190 static GDBusNodeInfo *introspection_data = NULL;
191
192 static const gchar introspection_xml[] =
193   "<node>"
194   "  <interface name='com.dreambox.RTSPserver'>"
195   "    <signal name='ping' />"
196   "    <signal name='sourceStateChanged'>"
197   "      <arg type='i' name='state' direction='out'/>"
198   "    </signal>"
199   "    <property type='i' name='sourceState' access='read'/>"
200   "    <property type='i' name='audioBitrate' access='readwrite'/>"
201   "    <property type='i' name='videoBitrate' access='readwrite'/>"
202   "    <property type='i' name='framerate' access='readwrite'/>"
203   "    <property type='i' name='inputMode' access='readwrite'/>"
204   "    <property type='i' name='width' access='read'/>"
205   "    <property type='i' name='height' access='read'/>"
206   "    <method name='setResolution'>"
207   "      <arg type='i' name='width' direction='in'/>"
208   "      <arg type='i' name='height' direction='in'/>"
209   "    </method>"
210   "    <method name='enableHLS'>"
211   "      <arg type='b' name='state' direction='in'/>"
212   "      <arg type='u' name='port' direction='in'/>"
213   "      <arg type='s' name='user' direction='in'/>"
214   "      <arg type='s' name='pass' direction='in'/>"
215   "      <arg type='b' name='result' direction='out'/>"
216   "    </method>"
217   "    <signal name='hlsStateChanged'>"
218   "      <arg type='i' name='state' direction='out'/>"
219   "    </signal>"
220   "    <property type='i' name='hlsState' access='read'/>"
221   #if HAVE_UPSTREAM
222   "    <method name='enableUpstream'>"
223   "      <arg type='b' name='state' direction='in'/>"
224   "      <arg type='s' name='host' direction='in'/>"
225   "      <arg type='u' name='port' direction='in'/>"
226   "      <arg type='s' name='token' direction='in'/>"
227   "      <arg type='b' name='result' direction='out'/>"
228   "    </method>"
229   "    <signal name='upstreamStateChanged'>"
230   "      <arg type='i' name='state' direction='out'/>"
231   "    </signal>"
232   "    <property type='i' name='upstreamState' access='read'/>"
233   "    <signal name='tcpBitrate'>"
234   "      <arg type='i' name='kbps' direction='out'/>"
235   "    </signal>"
236 #endif
237   "    <method name='enableRTSP'>"
238   "      <arg type='b' name='state' direction='in'/>"
239   "      <arg type='s' name='path' direction='in'/>"
240   "      <arg type='u' name='port' direction='in'/>"
241   "      <arg type='s' name='user' direction='in'/>"
242   "      <arg type='s' name='pass' direction='in'/>"
243   "      <arg type='b' name='result' direction='out'/>"
244   "    </method>"
245   "    <signal name='rtspClientCountChanged'>"
246   "      <arg type='i' name='count' direction='out'/>"
247   "      <arg type='s' name='host' direction='out'/>"
248   "    </signal>"
249   "    <property type='i' name='rtspClientCount' access='read'/>"
250   "    <signal name='uriParametersChanged'>"
251   "      <arg type='s' name='parameters' direction='out'/>"
252   "    </signal>"
253   "    <signal name='rtspStateChanged'>"
254   "      <arg type='i' name='state' direction='out'/>"
255   "    </signal>"
256   "    <property type='i' name='rtspState' access='read'/>"
257   "    <property type='s' name='uriParameters' access='read'/>"
258   "    <property type='b' name='autoBitrate' access='readwrite'/>"
259   "    <signal name='encoderError'/>"
260   "  </interface>"
261   "</node>";
262
263 static gboolean gst_get_capsprop(App *app, GstElement *element, const gchar* prop_name, guint32 *value);
264 static gboolean gst_set_inputmode(App *app, inputMode input_mode);
265 static gboolean gst_set_framerate(App *app, int value);
266 static gboolean gst_set_resolution(App *app, int width, int height);
267 static gboolean gst_set_bitrate (App *app, GstElement *source, gint32 value);
268 static void get_source_properties (App *app);
269 static void apply_source_properties (App *app);
270
271 static void on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data);
272 static void on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data);
273 static void on_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data);
274 static GVariant *handle_get_property (GDBusConnection *, const gchar *, const gchar *, const gchar *, const gchar *, GError **, gpointer);
275 static gboolean handle_set_property (GDBusConnection *, const gchar *, const gchar *, const gchar *, const gchar *, GVariant *, GError **, gpointer);
276 static void handle_method_call (GDBusConnection *, const gchar *, const gchar *, const gchar *, const gchar *, GVariant *, GDBusMethodInvocation *, gpointer);
277 static void send_signal (App *app, const gchar *signal_name, GVariant *parameters);
278
279 void assert_tsmux(App *app);
280 gboolean assert_state(App *app, GstElement *element, GstState targetstate);
281
282 static gboolean message_cb (GstBus * bus, GstMessage * message, gpointer user_data);
283 static GstPadProbeReturn cancel_waiting_probe (GstPad * sinkpad, GstPadProbeInfo * info, gpointer user_data);
284 static GstPadProbeReturn bitrate_measure_probe (GstPad * sinkpad, GstPadProbeInfo * info, gpointer user_data);
285 gboolean upstream_keep_alive(App *app);
286 gboolean upstream_set_waiting(App *app);
287 gboolean upstream_resume_transmitting(App *app);
288 static GstPadProbeReturn inject_authorization (GstPad * sinkpad, GstPadProbeInfo * info, gpointer user_data);
289 static GstPadProbeReturn pad_probe_unlink_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data);
290 static void queue_underrun (GstElement *, gpointer);
291 static void queue_overrun (GstElement *, gpointer);
292 gboolean auto_adjust_bitrate(App *app);
293
294 gboolean create_source_pipeline(App *app);
295 gboolean halt_source_pipeline(App *app);
296 gboolean pause_source_pipeline(App *app);
297 gboolean unpause_source_pipeline(App *app);
298 gboolean destroy_pipeline(App *app);
299 gboolean watchdog_ping(gpointer user_data);
300 gboolean quit_signal(gpointer loop);
301 gboolean get_dot_graph (gpointer user_data);
302
303 DreamHLSserver *create_hls_server(App *app);
304 gboolean enable_hls_server(App *app, guint port, const gchar *user, const gchar *pass);
305 gboolean start_hls_pipeline(App *app);
306 gboolean stop_hls_pipeline(App *app);
307 gboolean disable_hls_server(App *app);
308 gboolean hls_client_timeout (gpointer user_data);
309 static void soup_do_get (SoupServer *server, SoupMessage *msg, const char *path, App *app);
310 static void soup_server_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data);
311
312 gboolean enable_tcp_upstream(App *app, const gchar *upstream_host, guint32 upstream_port, const gchar *token);
313 gboolean disable_tcp_upstream(App *app);
314
315 DreamRTSPserver *create_rtsp_server(App *app);
316 gboolean enable_rtsp_server(App *app, const gchar *path, guint32 port, const gchar *user, const gchar *pass);
317 gboolean disable_rtsp_server(App *app);
318 gboolean start_rtsp_pipeline(App *app);
319
320 static void encoder_signal_lost(GstElement *, gpointer user_data);
321
322 G_END_DECLS
323
324 #endif /* __DREAMRTSPSERVER_H__ */