1 /* GStreamer 2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> 3 * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org> 4 * Copyright (C) <2011> Collabora Ltd. 5 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public 18 * License along with this library; if not, write to the 19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 */ 22 23 24 #ifndef __GST_MULTI_HANDLE_SINK_H__ 25 #define __GST_MULTI_HANDLE_SINK_H__ 26 27 #include <gst/gst.h> 28 #include <gst/base/gstbasesink.h> 29 #include <gio/gio.h> 30 31 G_BEGIN_DECLS 32 33 #define GST_TYPE_MULTI_HANDLE_SINK \ 34 (gst_multi_handle_sink_get_type()) 35 #define GST_MULTI_HANDLE_SINK(obj) \ 36 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULTI_HANDLE_SINK,GstMultiHandleSink)) 37 #define GST_MULTI_HANDLE_SINK_CAST(obj) ((GstMultiHandleSink *)(obj)) 38 #define GST_MULTI_HANDLE_SINK_CLASS(klass) \ 39 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTI_HANDLE_SINK,GstMultiHandleSinkClass)) 40 #define GST_IS_MULTI_HANDLE_SINK(obj) \ 41 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTI_HANDLE_SINK)) 42 #define GST_IS_MULTI_HANDLE_SINK_CLASS(klass) \ 43 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTI_HANDLE_SINK)) 44 #define GST_MULTI_HANDLE_SINK_GET_CLASS(klass) \ 45 (G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_MULTI_HANDLE_SINK, GstMultiHandleSinkClass)) 46 47 48 typedef struct _GstMultiHandleSink GstMultiHandleSink; 49 typedef struct _GstMultiHandleSinkClass GstMultiHandleSinkClass; 50 51 typedef enum { 52 GST_MULTI_HANDLE_SINK_OPEN = (GST_ELEMENT_FLAG_LAST << 0), 53 54 GST_MULTI_HANDLE_SINK_FLAG_LAST = (GST_ELEMENT_FLAG_LAST << 2) 55 } GstMultiHandleSinkFlags; 56 57 /** 58 * GstRecoverPolicy: 59 * @GST_RECOVER_POLICY_NONE : no recovering is done 60 * @GST_RECOVER_POLICY_RESYNC_LATEST : client is moved to last buffer 61 * @GST_RECOVER_POLICY_RESYNC_SOFT_LIMIT: client is moved to the soft limit 62 * @GST_RECOVER_POLICY_RESYNC_KEYFRAME : client is moved to latest keyframe 63 * 64 * Possible values for the recovery procedure to use when a client consumes 65 * data too slow and has a backlag of more that soft-limit buffers. 66 */ 67 typedef enum 68 { 69 GST_RECOVER_POLICY_NONE, 70 GST_RECOVER_POLICY_RESYNC_LATEST, 71 GST_RECOVER_POLICY_RESYNC_SOFT_LIMIT, 72 GST_RECOVER_POLICY_RESYNC_KEYFRAME 73 } GstRecoverPolicy; 74 75 /** 76 * GstSyncMethod: 77 * @GST_SYNC_METHOD_LATEST : client receives most recent buffer 78 * @GST_SYNC_METHOD_NEXT_KEYFRAME : client receives next keyframe 79 * @GST_SYNC_METHOD_LATEST_KEYFRAME : client receives latest keyframe (burst) 80 * @GST_SYNC_METHOD_BURST : client receives specific amount of data 81 * @GST_SYNC_METHOD_BURST_KEYFRAME : client receives specific amount of data 82 * starting from latest keyframe 83 * @GST_SYNC_METHOD_BURST_WITH_KEYFRAME : client receives specific amount of data from 84 * a keyframe, or if there is not enough data after 85 * the keyframe, starting before the keyframe 86 * 87 * This enum defines the selection of the first buffer that is sent 88 * to a new client. 89 */ 90 typedef enum 91 { 92 GST_SYNC_METHOD_LATEST, 93 GST_SYNC_METHOD_NEXT_KEYFRAME, 94 GST_SYNC_METHOD_LATEST_KEYFRAME, 95 GST_SYNC_METHOD_BURST, 96 GST_SYNC_METHOD_BURST_KEYFRAME, 97 GST_SYNC_METHOD_BURST_WITH_KEYFRAME 98 } GstSyncMethod; 99 100 /** 101 * GstClientStatus: 102 * @GST_CLIENT_STATUS_OK : client is ok 103 * @GST_CLIENT_STATUS_CLOSED : client closed the socket 104 * @GST_CLIENT_STATUS_REMOVED : client is removed 105 * @GST_CLIENT_STATUS_SLOW : client is too slow 106 * @GST_CLIENT_STATUS_ERROR : client is in error 107 * @GST_CLIENT_STATUS_DUPLICATE: same client added twice 108 * @GST_CLIENT_STATUS_FLUSHING : client is flushing out the remaining buffers. 109 * 110 * This specifies the reason why a client was removed from 111 * multisocketsink and is received in the "client-removed" signal. 112 */ 113 typedef enum 114 { 115 GST_CLIENT_STATUS_OK = 0, 116 GST_CLIENT_STATUS_CLOSED = 1, 117 GST_CLIENT_STATUS_REMOVED = 2, 118 GST_CLIENT_STATUS_SLOW = 3, 119 GST_CLIENT_STATUS_ERROR = 4, 120 GST_CLIENT_STATUS_DUPLICATE = 5, 121 GST_CLIENT_STATUS_FLUSHING = 6 122 } GstClientStatus; 123 124 // FIXME: is it better to use GSocket * or a gpointer here ? 125 typedef union 126 { 127 gpointer pointer; 128 int fd; 129 GSocket *socket; 130 } GstMultiSinkHandle; 131 132 /* structure for a client 133 */ 134 typedef struct { 135 GstMultiSinkHandle handle; 136 137 gchar debug[30]; /* a debug string used in debug calls to 138 identify the client */ 139 gint bufpos; /* position of this client in the global queue */ 140 gint flushcount; /* the remaining number of buffers to flush out or -1 if the 141 client is not flushing. */ 142 143 GstClientStatus status; 144 145 GSList *sending; /* the buffers we need to send */ 146 gint bufoffset; /* offset in the first buffer */ 147 148 gboolean discont; 149 150 gboolean new_connection; 151 gboolean currently_removing; 152 153 154 /* method to sync client when connecting */ 155 GstSyncMethod sync_method; 156 GstFormat burst_min_format; 157 guint64 burst_min_value; 158 GstFormat burst_max_format; 159 guint64 burst_max_value; 160 161 GstCaps *caps; /* caps of last queued buffer */ 162 163 /* stats */ 164 guint64 bytes_sent; 165 guint64 connect_time; 166 guint64 connect_time_monotonic; 167 guint64 disconnect_time; 168 guint64 disconnect_time_monotonic; 169 guint64 last_activity_time; 170 guint64 last_activity_time_monotonic; 171 guint64 dropped_buffers; 172 guint64 avg_queue_size; 173 guint64 first_buffer_ts; 174 guint64 last_buffer_ts; 175 } GstMultiHandleClient; 176 177 #define CLIENTS_LOCK_INIT(mhsink) (g_rec_mutex_init(&(mhsink)->clientslock)) 178 #define CLIENTS_LOCK_CLEAR(mhsink) (g_rec_mutex_clear(&(mhsink)->clientslock)) 179 #define CLIENTS_LOCK(mhsink) (g_rec_mutex_lock(&(mhsink)->clientslock)) 180 #define CLIENTS_UNLOCK(mhsink) (g_rec_mutex_unlock(&(mhsink)->clientslock)) 181 182 gint gst_multi_handle_sink_setup_dscp_client (GstMultiHandleSink * sink, GstMultiHandleClient * client); 183 gint 184 gst_multi_handle_sink_new_client_position (GstMultiHandleSink * sink, 185 GstMultiHandleClient * client); 186 187 /** 188 * GstMultiHandleSink: 189 * 190 * The multisocketsink object structure. 191 */ 192 struct _GstMultiHandleSink { 193 GstBaseSink element; 194 195 /*< private >*/ 196 guint64 bytes_to_serve; /* how much bytes we must serve */ 197 guint64 bytes_served; /* how much bytes have we served */ 198 199 GRecMutex clientslock; /* lock to protect the clients list */ 200 GList *clients; /* list of clients we are serving */ 201 guint clients_cookie; /* Cookie to detect changes to the clients list */ 202 203 GHashTable *handle_hash; /* index of handle -> GstMultiHandleClient */ 204 205 GMainContext *main_context; 206 GCancellable *cancellable; 207 208 gint qos_dscp; 209 210 GArray *bufqueue; /* global queue of buffers */ 211 212 gboolean running; /* the thread state */ 213 GThread *thread; /* the sender thread */ 214 215 /* these values are used to check if a client is reading fast 216 * enough and to control receovery */ 217 GstFormat unit_format;/* the format of the units */ 218 gint64 units_max; /* max units to queue for a client */ 219 gint64 units_soft_max; /* max units a client can lag before recovery starts */ 220 GstRecoverPolicy recover_policy; 221 GstClockTime timeout; /* max amount of nanoseconds to remain idle */ 222 223 GstSyncMethod def_sync_method; /* what method to use for connecting clients */ 224 GstFormat def_burst_format; 225 guint64 def_burst_value; 226 227 /* these values are used to control the amount of data 228 * kept in the queues. It allows clients to perform a burst 229 * on connect. */ 230 gint bytes_min; /* min number of bytes to queue */ 231 gint64 time_min; /* min time to queue */ 232 gint buffers_min; /* min number of buffers to queue */ 233 234 gboolean resend_streamheader; /* resend streamheader if it changes */ 235 236 /* stats */ 237 gint buffers_queued; /* number of queued buffers */ 238 gint bytes_queued; /* number of queued bytes */ 239 gint time_queued; /* number of queued time */ 240 }; 241 242 struct _GstMultiHandleSinkClass { 243 GstBaseSinkClass parent_class; 244 245 /* methods */ 246 void (*clear) (GstMultiHandleSink *sink); 247 void (*stop_pre) (GstMultiHandleSink *sink); 248 void (*stop_post) (GstMultiHandleSink *sink); 249 gboolean (*start_pre) (GstMultiHandleSink *sink); 250 gpointer (*thread) (GstMultiHandleSink *sink); 251 /* called by subclass when it has a new buffer to queue for a client */ 252 gboolean (*client_queue_buffer) 253 (GstMultiHandleSink *sink, 254 GstMultiHandleClient *client, 255 GstBuffer *buffer); 256 int (*client_get_fd) 257 (GstMultiHandleClient *client); 258 void (*client_free) (GstMultiHandleSink *mhsink, 259 GstMultiHandleClient *client); 260 void (*handle_debug) (GstMultiSinkHandle handle, gchar debug[30]); 261 gpointer (*handle_hash_key) (GstMultiSinkHandle handle); 262 /* called when the client hash/list has been changed */ 263 void (*hash_changed) (GstMultiHandleSink *mhsink); 264 void (*hash_adding) (GstMultiHandleSink *mhsink, GstMultiHandleClient *client); 265 void (*hash_removing) (GstMultiHandleSink *mhsink, GstMultiHandleClient *client); 266 GstMultiHandleClient* (*new_client) (GstMultiHandleSink *mhsink, GstMultiSinkHandle handle, GstSyncMethod sync_method); 267 268 269 /* vtable */ 270 gboolean (*init) (GstMultiHandleSink *sink); 271 gboolean (*close) (GstMultiHandleSink *sink); 272 void (*removed) (GstMultiHandleSink *sink, GstMultiSinkHandle handle); 273 274 /* subclass needs to emit these because actual argument size (int/pointer) differs */ 275 void (*emit_client_added) (GstMultiHandleSink *mhsink, GstMultiSinkHandle handle); 276 void (*emit_client_removed) (GstMultiHandleSink *mhsink, GstMultiSinkHandle handle, GstClientStatus status); 277 }; 278 279 GType gst_multi_handle_sink_get_type (void); 280 281 void gst_multi_handle_sink_add (GstMultiHandleSink *sink, GstMultiSinkHandle handle); 282 void gst_multi_handle_sink_add_full (GstMultiHandleSink *sink, GstMultiSinkHandle handle, GstSyncMethod sync, 283 GstFormat min_format, guint64 min_value, 284 GstFormat max_format, guint64 max_value); 285 void gst_multi_handle_sink_remove (GstMultiHandleSink *sink, GstMultiSinkHandle handle); 286 void gst_multi_handle_sink_remove_flush (GstMultiHandleSink *sink, GstMultiSinkHandle handle); 287 GstStructure* gst_multi_handle_sink_get_stats (GstMultiHandleSink *sink, GstMultiSinkHandle handle); 288 void gst_multi_handle_sink_remove_client_link (GstMultiHandleSink * sink, 289 GList * link); 290 291 void gst_multi_handle_sink_client_init (GstMultiHandleClient * client, GstSyncMethod sync_method); 292 293 #define GST_TYPE_RECOVER_POLICY (gst_multi_handle_sink_recover_policy_get_type()) 294 GType gst_multi_handle_sink_recover_policy_get_type (void); 295 #define GST_TYPE_SYNC_METHOD (gst_multi_handle_sink_sync_method_get_type()) 296 GType gst_multi_handle_sink_sync_method_get_type (void); 297 #define GST_TYPE_CLIENT_STATUS (gst_multi_handle_sink_client_status_get_type()) 298 GType gst_multi_handle_sink_client_status_get_type (void); 299 300 301 G_END_DECLS 302 303 #endif /* __GST_MULTI_HANDLE_SINK_H__ */ 304