1 /*! \file   janus_streaming.c
2  * \author Lorenzo Miniero <lorenzo@meetecho.com>
3  * \copyright GNU General Public License v3
4  * \brief  Janus Streaming plugin
5  * \details Check the \ref streaming for more details.
6  *
7  * \ingroup plugins
8  * \ref plugins
9  *
10  * \page streaming Streaming plugin documentation
11  * This is a streaming plugin for Janus, allowing WebRTC peers
12  * to watch/listen to pre-recorded files or media generated by another tool.
13  * Specifically, the plugin currently supports three different type of streams:
14  *
15  * -# on-demand streaming of pre-recorded media files (different
16  * streaming context for each peer);
17  * -# live streaming of pre-recorded media files (shared streaming
18  * context for all peers attached to the stream);
19  * -# live streaming of media generated by another tool (shared
20  * streaming context for all peers attached to the stream).
21  *
22  * For what concerns types 1. and 2., considering the proof of concept
23  * nature of the implementation the only pre-recorded media files
24  * that the plugins supports right now are Opus, raw mu-Law and a-Law files:
25  * support is of course planned for other additional widespread formats
26  * as well.
27  *
28  * For what concerns type 3., instead, the plugin is configured
29  * to listen on a couple of ports for RTP: this means that the plugin
30  * is implemented to receive RTP on those ports and relay them to all
31  * peers attached to that stream. Any tool that can generate audio/video
32  * RTP streams and specify a destination is good for the purpose: the
33  * examples section contains samples that make use of GStreamer (http://gstreamer.freedesktop.org/)
34  * but other tools like FFmpeg (http://www.ffmpeg.org/), LibAV (http://libav.org/)
35  * or others are fine as well. This makes it really easy to capture and
36  * encode whatever you want using your favourite tool, and then have it
37  * transparently broadcasted via WebRTC using Janus. Notice that we recently
38  * added  the possibility to also add a datachannel track to an RTP streaming
39  * mountpoint: this allows you to send, via UDP, a text-based message to
40  * relay via datachannels (e.g., the title of the current song, if this
41  * is a radio streaming channel). When using this feature, though, beware
42  * that you'll have to stay within the boundaries of the MTU, as each
43  * message will have to stay within the size of an UDP packet.
44  *
45  * Streams to make available are listed in the plugin configuration file.
46  * A pre-filled configuration file is provided in \c conf/janus.plugin.streaming.jcfg
47  * and includes a stream of every type.
48  *
49  * To add more streams or modify the existing ones, you can use the following
50  * syntax:
51  *
52  * \verbatim
53 stream-name: {
54 	[settings]
55 }
56 \endverbatim
57  *
58  * with the allowed settings listed below:
59  *
60  * \verbatim
61 type = rtp|live|ondemand|rtsp
62        rtp = stream originated by an external tool (e.g., gstreamer or
63              ffmpeg) and sent to the plugin via RTP
64        live = local file streamed live to multiple viewers
65               (multiple viewers = same streaming context)
66        ondemand = local file streamed on-demand to a single listener
67                   (multiple viewers = different streaming contexts)
68        rtsp = stream originated by an external RTSP feed (only
69               available if libcurl support was compiled)
70 id = <unique numeric ID>
71 description = This is my awesome stream
72 metadata = An optional string that can contain any metadata (e.g., JSON)
73 			associated with the stream you want users to receive
74 is_private = true|false (private streams don't appear when you do a 'list' request)
75 filename = path to the local file to stream (only for live/ondemand)
76 secret = <optional password needed for manipulating (e.g., destroying
77 		or enabling/disabling) the stream>
78 pin = <optional password needed for watching the stream>
79 audio = true|false (do/don't stream audio)
80 video = true|false (do/don't stream video)
81    The following options are only valid for the 'rtp' type:
82 data = true|false (do/don't stream text via datachannels)
83 audioport = local port for receiving audio frames
84 audiortcpport = local port for receiving and sending audio RTCP feedback
85 audiomcast = multicast group for receiving audio frames, if any
86 audioiface = network interface or IP address to bind to, if any (binds to all otherwise)
87 audiopt = <audio RTP payload type> (e.g., 111)
88 audiortpmap = RTP map of the audio codec (e.g., opus/48000/2)
89 audiofmtp = Codec specific parameters, if any
90 audioskew = true|false (whether the plugin should perform skew
91 	analisys and compensation on incoming audio RTP stream, EXPERIMENTAL)
92 videoport = local port for receiving video frames (only for rtp)
93 videortcpport = local port for receiving and sending video RTCP feedback
94 videomcast = multicast group for receiving video frames, if any
95 videoiface = network interface or IP address to bind to, if any (binds to all otherwise)
96 videopt = <video RTP payload type> (e.g., 100)
97 videortpmap = RTP map of the video codec (e.g., VP8/90000)
98 videofmtp = Codec specific parameters, if any
99 videobufferkf = true|false (whether the plugin should store the latest
100 	keyframe and send it immediately for new viewers, EXPERIMENTAL)
101 videosimulcast = true|false (do|don't enable video simulcasting)
102 videoport2 = second local port for receiving video frames (only for rtp, and simulcasting)
103 videoport3 = third local port for receiving video frames (only for rtp, and simulcasting)
104 videoskew = true|false (whether the plugin should perform skew
105 	analisys and compensation on incoming video RTP stream, EXPERIMENTAL)
106 videosvc = true|false (whether the video will have SVC support; works only for VP9-SVC, default=false)
107 collision = in case of collision (more than one SSRC hitting the same port), the plugin
108 	will discard incoming RTP packets with a new SSRC unless this many milliseconds
109 	passed, which would then change the current SSRC (0=disabled)
110 dataport = local port for receiving data messages to relay
111 dataiface = network interface or IP address to bind to, if any (binds to all otherwise)
112 datatype = text|binary (type of data this mountpoint will relay, default=text)
113 databuffermsg = true|false (whether the plugin should store the latest
114 	message and send it immediately for new viewers)
115 threads = number of threads to assist with the relaying part, which can help
116 	if you expect a lot of viewers that may cause the RTP receiving part
117 	in the Streaming plugin to slow down and fail to catch up (default=0)
118 
119 In case you want to use SRTP for your RTP-based mountpoint, you'll need
120 to configure the SRTP-related properties as well, namely the suite to
121 use for hashing (32 or 80) and the crypto information for decrypting
122 the stream (as a base64 encoded string the way SDES does it). Notice
123 that with SRTP involved you'll have to pay extra attention to what you
124 feed the mountpoint, as you may risk getting SRTP decrypt errors:
125 srtpsuite = 32
126 srtpcrypto = WbTBosdVUZqEb6Htqhn+m3z7wUh4RJVR8nE15GbN
127 
128 The Streaming plugin can also be used to (re)stream media that has been
129 encrypted using something that can be consumed via Insertable Streams.
130 In that case, we only need to be aware of it, so that we can send the
131 info along with the SDP. How to decrypt the media is out of scope, and
132 up to the application since, again, this is end-to-end encryption and
133 so neither Janus nor the Streaming plugin have access to anything.
134 DO NOT SET THIS PROPERTY IF YOU DON'T KNOW WHAT YOU'RE DOING!
135 e2ee = true
136 
137 The following options are only valid for the 'rtsp' type:
138 url = RTSP stream URL
139 rtsp_user = RTSP authorization username, if needed
140 rtsp_pwd = RTSP authorization password, if needed
141 rtsp_failcheck = whether an error should be returned if connecting to the RTSP server fails (default=true)
142 rtspiface = network interface IP address or device name to listen on when receiving RTSP streams
143 rtsp_reconnect_delay = after n seconds passed and no media assumed, the RTSP server has gone and schedule a reconnect (default=5s)
144 rtsp_session_timeout = by default the streaming plugin will check the RTSP connection with an OPTIONS query,
145 	the value of the timeout comes from the RTSP session initializer and by default
146 	this session timeout is the half of this value In some cases this value can be too high (for example more than one minute)
147 	because of the media server. In that case this plugin will calculate the timeout with this
148 	formula: timeout = min(session_timeout, rtsp_session_timeout / 2). (default=0s)
149 rtsp_timeout = communication timeout (CURLOPT_TIMEOUT) for cURL call gathering the RTSP information (default=10s)
150 rtsp_conn_timeout = connection timeout for cURL (CURLOPT_CONNECTTIMEOUT) call gathering the RTSP information (default=5s)
151 \endverbatim
152  *
153  * \section streamapi Streaming API
154  *
155  * The Streaming API supports several requests, some of which are
156  * synchronous and some asynchronous. There are some situations, though,
157  * (invalid JSON, invalid request) which will always result in a
158  * synchronous error response even for asynchronous requests.
159  *
160  * \c list , \c info , \c create , \c destroy , \c recording , \c edit ,
161  * \c enable and \c disable are synchronous requests, which means you'll
162  * get a response directly within the context of the transaction. \c list
163  * lists all the available streams; \c create allows you to create a new
164  * mountpoint dynamically, as an alternative to using the configuration
165  * file; \c destroy removes a mountpoint and destroys it; \c recording
166  * instructs the plugin on whether or not a live RTP stream should be
167  * recorded while it's broadcasted; \c enable and \c disable respectively
168  * enable and disable a mountpoint, that is decide whether or not a
169  * mountpoint should be available to users without destroying it.
170  * \c edit allows you to dynamically edit some mountpoint properties (e.g., the PIN);
171  *
172  * The \c watch , \c start , \c configure , \c pause , \c switch and \c stop requests
173  * instead are all asynchronous, which means you'll get a notification
174  * about their success or failure in an event. \c watch asks the plugin
175  * to prepare the playout of one of the available streams; \c start
176  * starts the actual playout; \c pause allows you to pause a playout
177  * without tearing down the PeerConnection; \c switch allows you to
178  * switch to a different mountpoint of the same kind (note: only live
179  * RTP mountpoints supported as of now) without having to stop and watch
180  * the new one; \c stop stops the playout and tears the PeerConnection
181  * down.
182  *
183  * Notice that, in general, all users can create mountpoints, no matter
184  * what type they are. If you want to limit this functionality, you can
185  * configure an admin \c admin_key in the plugin settings. When
186  * configured, only "create" requests that include the correct
187  * \c admin_key value in an "admin_key" property will succeed, and will
188  * be rejected otherwise.
189  *
190  * \subsection streamingsync Synchronous requests
191  *
192  * To list the available Streaming mountpoints (both those created via
193  * configuration file and those created via API), you can use the \c list
194  * request:
195  *
196 \verbatim
197 {
198 	"request" : "list"
199 }
200 \endverbatim
201  *
202  * If successful, it will return an array with a list of all the mountpoints.
203  * Notice that only the public mountpoints will be returned: those with
204  * an \c is_private set to yes/true will be skipped. The response will
205  * be formatted like this:
206  *
207 \verbatim
208 {
209 	"streaming" : "list",
210 	"list" : [
211 		{
212 			"id" : <unique ID of mountpoint #1>,
213 			"type" : "<type of mountpoint #1, in line with the types introduced above>",
214 			"description" : "<description of mountpoint #1>",
215 			"metadata" : "<metadata of mountpoint #1, if any>",
216 			"enabled" : <true|false, depending on whether the mountpoint is currently enabled or not>,
217 			"audio_age_ms" : <how much time passed since we last received audio; optional, available for RTP mountpoints only>,
218 			"video_age_ms" : <how much time passed since we last received video; optional, available for RTP mountpoints only>
219 		},
220 		{
221 			"id" : <unique ID of mountpoint #2>,
222 			"type" : "<type of mountpoint #2, in line with the types introduced above>",
223 			"description" : "<description of mountpoint #2>",
224 			"metadata" : "<metadata of mountpoint #2, if any>",
225 			"audio_age_ms" : <how much time passed since we last received audio; optional, available for RTP mountpoints only>,
226 			"video_age_ms" : <how much time passed since we last received video; optional, available for RTP mountpoints only>
227 		},
228 		...
229 	]
230 }
231 \endverbatim
232  *
233  * As you can see, the \c list request only returns very generic info on
234  * each mounpoint. In case you're interested in learning more details about
235  * a specific mountpoint, you can use the \c info request instead, which
236  * returns more information, or all of it if the mountpoint secret is
237  * provided in the request. An \c info request must be formatted like this:
238  *
239 \verbatim
240 {
241 	"request" : "info"
242 	"id" : <unique ID of mountpoint to query>,
243 	"secret" : <mountpoint secret; optional, can be used to return more info>"
244 }
245 \endverbatim
246  *
247  * If successful, this will have the plugin return an object containing
248  * more info on the mountpoint:
249  *
250 \verbatim
251 {
252 	"streaming" : "info",
253 	"info" : {
254 		"id" : <unique ID of mountpoint>,
255 		"name" : "<unique name of mountpoint>",
256 		"description" : "<description of mountpoint>",
257 		"metadata" : "<metadata of mountpoint, if any>",
258 		"secret" : "<secret of mountpoint; only available if a valid secret was provided>",
259 		"pin" : "<PIN to access mountpoint; only available if a valid secret was provided>",
260 		"is_private" : <true|false, depending on whether the mountpoint is listable; only available if a valid secret was provided>,
261 		"viewers" : <count of current subscribers, if any>,
262 		"enabled" : <true|false, depending on whether the mountpoint is currently enabled or not>,
263 		"audio" : <true, only present if the mountpoint contains audio>,
264 		"audiopt" : <audio payload type, only present if configured and the mountpoint contains audio>,
265 		"audiortpmap" : "<audio SDP rtpmap value, only present if configured and the mountpoint contains audio>",
266 		"audiofmtp" : "<audio SDP fmtp value, only present if configured and the mountpoint contains audio>",
267 		"video" : <true, only present if the mountpoint contains video>,
268 		"videopt" : <video payload type, only present if configured and the mountpoint contains video>,
269 		"videortpmap" : "<video SDP rtpmap value, only present if configured and the mountpoint contains video>",
270 		"videofmtp" : "<video SDP fmtp value, only present if configured and the mountpoint contains video>",
271 		...
272 	}
273 }
274 \endverbatim
275  *
276  * Considering the different mountpoint types that you can create in this
277  * plugin, the nature of the rest of the returned info obviously depends
278  * on which mountpoint you're querying. This is especially true for RTP
279  * and RTSP mountpoints. Notice that info like the ports an RTP mountpoint
280  * is listening on will only be returned if you provide the correct secret,
281  * as otherwise they're treated like sensitive information and are not
282  * returned to generic \c info calls.
283  *
284  * We've seen how you can create a new mountpoint via configuration file,
285  * but you can create one via API as well, using the \c create request.
286  * Most importantly, you can also choose whether or not a \c create
287  * request should result in the mountpoint being saved to configuration
288  * file so that it's still available after a server restart. The common
289  * syntax for all \c create requests is the following:
290  *
291 \verbatim
292 {
293 	"request" : "create",
294 	"admin_key" : "<plugin administrator key; mandatory if configured>",
295 	"type" : "<type of the mountpoint to create; mandatory>",
296 	"id" : <unique ID to assign the mountpoint; optional, will be chosen by the server if missing>,
297 	"name" : "<unique name for the mountpoint; optional, will be chosen by the server if missing>",
298 	"description" : "<description of mountpoint; optional>",
299 	"metadata" : "<metadata of mountpoint; optional>",
300 	"secret" : "<secret to query/edit the mountpoint later; optional>",
301 	"pin" : "<PIN required for viewers to access mountpoint; optional>",
302 	"is_private" : <true|false, whether the mountpoint should be listable; true by default>,
303 	"audio" : <true|false, whether the mountpoint will have audio; false by default>,
304 	"video" : <true|false, whether the mountpoint will have video; false by default>,
305 	"data" : <true|false, whether the mountpoint will have datachannels; false by default>,
306 	"permanent" : <true|false, whether the mountpoint should be saved to configuration file or not; false by default>,
307 	...
308 }
309 \endverbatim
310  *
311  * Of course, different mountpoint types will have different properties
312  * you can specify in a \c create. Please refer to the documentation on
313  * configuration files to see the fields you can pass. The only important
314  * difference to highlight is that, unlike in configuration files, you will
315  * NOT have to escape semicolons with a trailing slash, in those properties
316  * where a semicolon might be needed (e.g., \c audiofmtp or \c videofmtp ).
317  *
318  * A successful \c create will result in a \c created response:
319  *
320 \verbatim
321 {
322 	"streaming" : "created",
323 	"create" : "<unique name of the just created mountpoint>",
324 	"permanent" : <true|false, depending on whether the mountpoint was saved to configuration file or not>,
325 	"stream": {
326 		"id" : <unique ID of the just created mountpoint>,
327 		"type" : "<type of the just created mountpoint>",
328 		"description" : "<description of the just created mountpoint>",
329 		"is_private" : <true|false, depending on whether the new mountpoint is listable>,
330 		...
331 	}
332 }
333 \endverbatim
334  *
335  * Notice that additional information, namely the ports the mountpoint
336  * bound to, will only be added for new RTP mountpoints, otherwise this
337  * is all that a \c created request will contain. If you want to double
338  * check everything in your \c create request went as expected, you may
339  * want to issue a followup \c info request to compare the results.
340  *
341  * Once you created a mountpoint, you can modify some (not all) of its
342  * properties via an \c edit request. Namely, you can only modify generic
343  * properties like the mountpoint description, the secret, the PIN and
344  * whether or not the mountpoint should be listable. All other properties
345  * are considered to be immutable. Again, you can choose whether the changes
346  * should be permanent, e.g., saved to configuration file, or not. Notice
347  * that an \c edit request requires the right secret to be provided, if
348  * the mountpoint has one, or will return an error instead. The \c edit
349  * request must be formatted like this:
350  *
351 \verbatim
352 {
353 	"request" : "edit",
354 	"id" : <unique ID of the mountpoint to edit; mandatory>,
355 	"secret" : "<secret to edit the mountpoint; mandatory if configured>",
356 	"new_description" : "<new description for the mountpoint; optional>",
357 	"new_metadata" : "<new metadata for the mountpoint; optional>",
358 	"new_secret" : "<new secret for the mountpoint; optional>",
359 	"new_pin" : "<new PIN for the mountpoint; optional>",
360 	"new_is_private" : <true|false, depending on whether the mountpoint should be now listable; optional>,
361 	"permanent" : <true|false, whether the mountpoint should be saved to configuration file or not; false by default>
362 }
363 \endverbatim
364  *
365  * A successful \c edit will result in an \c edited response:
366  *
367 \verbatim
368 {
369 	"streaming" : "edited",
370 	"id" : <unique ID of the just edited mountpoint>,
371 	"permanent" : <true|false, depending on whether the changes were saved to configuration file or not>
372 }
373 \endverbatim
374  *
375  * Just as you can create and edit mountpoints, you can of course also destroy
376  * them. Again, this applies to all mountpoints, whether created statically
377  * via configuration file or dynamically via API, and the mountpoint destruction
378  * can be made permanent in the configuration file as well. A \c destroy
379  * request must be formatted as follows:
380  *
381 \verbatim
382 {
383 	"request" : "destroy",
384 	"id" : <unique ID of the mountpoint to destroy; mandatory>,
385 	"secret" : "<secret to destroy the mountpoint; mandatory if configured>",
386 	"permanent" : <true|false, whether the mountpoint should be removed from the configuration file or not; false by default>
387 }
388 \endverbatim
389  *
390  * If successful, the result will be confirmed in a \c destroyed event:
391  *
392 \verbatim
393 {
394 	"streaming" : "destroyed",
395 	"id" : <unique ID of the just destroyed mountpoint>
396 }
397 \endverbatim
398  *
399  * Notice that destroying a mountpoint while viewers are still subscribed
400  * to it will result in all viewers being removed, and their PeerConnection
401  * closed as a consequence.
402  *
403  * You can also dynamically enable and disable mountpoints via API. A
404  * disabled mountpoint is a mountpoint that exists, and still works as
405  * expected, but is not accessible to viewers until it's enabled again.
406  * This is a useful property, especially in case of mountpoints that
407  * need to be prepared in advance but must not be accessible until a
408  * specific moment, and a much better alternative to just create the
409  * mountpoint at the very last minute and destroy it otherwise. The
410  * syntax for both the \c enable and \c disable requests is the same,
411  * and looks like the following:
412  *
413 \verbatim
414 {
415 	"request" : "enable",
416 	"id" : <unique ID of the mountpoint to enable; mandatory>,
417 	"secret" : "<secret to enable the mountpoint; mandatory if configured>"
418 }
419 \endverbatim
420  *
421  * If successful, a generic \c ok is returned:
422  *
423 \verbatim
424 {
425 	"streaming" : "ok"
426 }
427 \endverbatim
428 \verbatim
429 {
430 	"request" : "disable",
431 	"id" : <unique ID of the mountpoint to disable; mandatory>,
432 	"stop_recording" : <true|false, whether the recording should also be stopped or not; true by default>
433 	"secret" : "<secret to disable the mountpoint; mandatory if configured>"
434 }
435 \endverbatim
436  *
437  * If successful, a generic \c ok is returned:
438  *
439 \verbatim
440 {
441 	"streaming" : "ok"
442 }
443 \endverbatim
444  *
445  * Finally, you can record a mountpoint to the internal Janus .mjr format
446  * using the \c recording request. The same request can also be used to
447  * stop recording. Although the same request is used in both cases, though,
448  * the syntax for the two use cases differs a bit, namely in terms of the
449  * type of some properties.
450  *
451  * To start recording a new mountpoint, the request should be formatted
452  * like this:
453  *
454 \verbatim
455 {
456 	"request" : "recording",
457 	"action" : "start",
458 	"id" : <unique ID of the mountpoint to manipulate; mandatory>,
459 	"audio" : "<enable audio recording, and use this base path/filename; optional>",
460 	"video" : "<enable video recording, and use this base path/filename; optional>",
461 	"data" : "<enable data recording, and use this base path/filename; optional>"
462 }
463 \endverbatim
464  *
465  * To stop a recording, instead, this is the request syntax:
466  *
467 \verbatim
468 {
469 	"request" : "recording",
470 	"action" : "stop",
471 	"id" : <unique ID of the mountpoint to manipulate; mandatory>,
472 	"audio" : <true|false; whether or not audio recording should be stopped>,
473 	"video" : <true|false; whether or not video recording should be stopped>,
474 	"data" : <true|false; whether or not datachannel recording should be stopped>
475 }
476 \endverbatim
477  *
478  * As you can notice, when you want to start a recording the \c audio ,
479  * \c video and \c data properties are strings, and specify the base path
480  * to use for the recording filename; when stopping a recording, instead,
481  * they're interpreted as boolean properties. Notice that, as with all
482  * APIs that wrap .mjr recordings, the filename you specify here is not
483  * the actual filename: an \c .mjr extension is always going to be added
484  * by the Janus core, so you should take this into account when tracking
485  * the related recording files.
486  *
487  * Whether you started or stopped a recording, a successful request will
488  * always result in a simple \c ok response:
489  *
490 \verbatim
491 {
492 	"streaming" : "ok"
493 }
494 \endverbatim
495  *
496  * \subsection streamingasync Asynchronous requests
497  *
498  * All the requests we've gone through so far are synchronous. This means
499  * that they return a response right away. That said, many of the requests
500  * this plugin supports are asynchronous instead, which means Janus will
501  * send an ack when they're received, and a response will only follow
502  * later on. This is especially true for requests dealing with the
503  * management and setup of mountpoint viewers, e.g., for the purpose of
504  * negotiating a WebRTC PeerConnection to receive media from a mountpoint.
505  *
506  * To subscribe to a specific mountpoint, an interested viewer can make
507  * use of the \c watch request. As suggested by the request name, this
508  * instructs the plugin to setup a new PeerConnection to allow the new
509  * viewer to watch the specified mountpoint. The \c watch request must
510  * be formatted like this:
511  *
512 \verbatim
513 {
514 	"request" : "watch",
515 	"id" : <unique ID of the mountpoint to subscribe to; mandatory>,
516 	"pin" : "<PIN required to access the mountpoint; mandatory if configured>",
517 	"offer_audio" : <true|false; whether or not audio should be negotiated; true by default if the mountpoint has audio>,
518 	"offer_video" : <true|false; whether or not video should be negotiated; true by default if the mountpoint has video>,
519 	"offer_data" : <true|false; whether or not datachannels should be negotiated; true by default if the mountpoint has datachannels>
520 }
521 \endverbatim
522  *
523  * As you can see, it's just a matter of specifying the ID of the mountpoint to
524  * subscribe to and, if needed, the PIN to access the mountpoint in case
525  * it's protected. The \c offer_audio , \c offer_video and \c offer_data are
526  * also particularly interesting, though, as they allow you to only subscribe
527  * to a subset of the mountpoint media. By default, in fact, a \c watch
528  * request will result in the plugin preparing a new SDP offer trying to
529  * negotiate all the media streams available in the mountpoint; in case
530  * the viewer knows they don't support one of the mountpoint codecs, though
531  * (e.g., the video in the mountpoint is VP8, but they only support H.264),
532  * or are not interested in getting all the media (e.g., they're ok with
533  * just audio and not video, or don't have enough bandwidth for both),
534  * they can use those properties to shape the SDP offer to their needs.
535  *
536  * As anticipated, if successful this request will generate a new JSEP SDP
537  * offer, which will be attached to a \c preparing status event:
538  *
539 \verbatim
540 {
541 	"status" : "preparing"
542 }
543 \endverbatim
544  *
545  * At this stage, to complete the setup of a subscription the viewer is
546  * supposed to send a JSEP SDP answer back to the plugin. This is done
547  * by means of a \c start request, which in this case MUST be associated
548  * with a JSEP SDP answer but otherwise requires no arguments:
549  *
550 \verbatim
551 {
552 	"request" : "start"
553 }
554 \endverbatim
555  *
556  * If successful this request returns a \c starting status event:
557  *
558 \verbatim
559 {
560 	"status" : "starting"
561 }
562 \endverbatim
563  *
564  * Once this is done, all that's needed is waiting for the WebRTC PeerConnection
565  * establishment to succeed. As soon as that happens, the Streaming plugin
566  * can start relaying media from the mountpoint the viewer subscribed to
567  * to the viewer themselves.
568  *
569  * Notice that the same exact steps we just went through (\c watch request,
570  * followed by JSEP offer by the plugin, followed by \c start request with
571  * JSEP answer by the viewer) is what you also use when renegotiations are
572  * needed, e.g., for the purpose of ICE restarts.
573  *
574  * As a viewer, you can temporarily pause and resume the whole media delivery
575  * with a \c pause and, again, \c start request (in this case without any JSEP
576  * SDP answer attached). Neither expect other arguments, as the context
577  * is implicitly derived from the handle they're sent on:
578  *
579 \verbatim
580 {
581 	"request" : "pause"
582 }
583 \endverbatim
584  *
585 \verbatim
586 {
587 	"request" : "start"
588 }
589 \endverbatim
590  *
591  * Unsurprisingly, they just result in, respectively, \c pausing and
592  * \c starting events:
593  *
594 \verbatim
595 {
596 	"status" : "pausing"
597 }
598 \endverbatim
599  *
600 \verbatim
601 {
602 	"status" : "starting"
603 }
604 \endverbatim
605  *
606  * For more drill-down manipulations of a subscription, a \c configure
607  * request can be used instead. This request allows viewers to dynamically
608  * change some properties associated to their media subscription, e.g.,
609  * in terms of what should and should not be sent at a specific time. A
610  * \c configure request must be formatted as follows:
611  *
612 \verbatim
613 {
614 	"request" : "configure",
615 	"audio" : <true|false, depending on whether audio should be relayed or not; optional>,
616 	"video" : <true|false, depending on whether video should be relayed or not; optional>,
617 	"data" : <true|false, depending on whether datachannel messages should be relayed or not; optional>,
618 	"substream" : <substream to receive (0-2), in case simulcasting is enabled; optional>,
619 	"temporal" : <temporal layers to receive (0-2), in case simulcasting is enabled; optional>,
620 	"fallback" : <How much time (in us, default 250000) without receiving packets will make us drop to the substream below>,
621 	"spatial_layer" : <spatial layer to receive (0-1), in case VP9-SVC is enabled; optional>,
622 	"temporal_layer" : <temporal layers to receive (0-2), in case VP9-SVC is enabled; optional>
623 }
624 \endverbatim
625  *
626  * As you can see, the \c audio , \c video and \c data properties can be
627  * used as a media-level pause/resume functionality, whereas \c pause
628  * and \c start simply pause and resume all streams at the same time.
629  * The \c substream and \c temporal properties, instead, only make sense
630  * when the mountpoint is configured with video simulcasting support, and
631  * as such the viewer is interested in receiving a specific substream
632  * or temporal layer, rather than any other of the available ones.
633  * The \c spatial_layer and \c temporal_layer have exactly the same meaning,
634  * but within the context of VP9-SVC mountpoints, and will have no effect
635  * on mountpoints involving a different video codec.
636  *
637  * Another interesting feature in the Streaming plugin is the so-called
638  * mountpoint "switching". Basically, when subscribed to a specific
639  * mountpoint and receiving media from there, you can at any time "switch"
640  * to a different mountpoint, and as such start receiving media from that
641  * other mountpoint instead. Think of it as changing channel on a TV: you
642  * keep on using the same PeerConnection, the plugin simply changes the
643  * source of the media transparently. Of course, while powerful and effective
644  * this request has some limitations. First of all, it only works with RTP
645  * mountpoints, and not other mountpoint types; besides, the two mountpoints
646  * must have the same media configuration, that is, use the same codecs,
647  * the same payload types, etc. In fact, since the same PeerConnection is
648  * used for this feature, switching to a mountpoint with a different
649  * configuration might result in media incompatible with the PeerConnection
650  * setup being relayed to the viewer, and as such in no audio/video being
651  * played. That said, a \c switch request must be formatted like this:
652  *
653 \verbatim
654 {
655 	"request" : "switch",
656 	"id" : <unique ID of the new mountpoint to switch to; mandatory>
657 }
658 \endverbatim
659  *
660  * If successful, you'll be unsubscribed from the previous mountpoint,
661  * and subscribed to the new mountpoint instead. The event to confirm
662  * the switch was successful will look like this:
663  *
664 \verbatim
665 {
666 	"switched" : "ok",
667 	"id" : <unique ID of the new mountpoint>
668 }
669 \endverbatim
670  *
671  * Finally, to stop the subscription to the mountpoint and tear down the
672  * related PeerConnection, you can use the \c stop request. Since context
673  * is implicit, no other argument is required:
674  *
675 \verbatim
676 {
677 	"request" : "stop"
678 }
679 \endverbatim
680  *
681  * If successful, the plugin will attempt to tear down the PeerConnection,
682  * and will send back a \c stopping status event:
683  *
684 \verbatim
685 {
686 	"status" : "stopping"
687 }
688 \endverbatim
689  *
690  * Once a PeerConnection has been torn down and the subscription closed,
691  * as a viewer you're free to subscribe to a different mountpoint instead.
692  * In fact, while you can't watch more than one mountpoint at the same
693  * time on the same handle, there's no limit on how many mountpoints
694  * you can watch in sequence, again on the same handle. If you're interested
695  * in subscribing to multiple mountpoints at the same time, instead, you'll
696  * have to create multiple handles for the purpose.
697  */
698 
699 
700 #include "plugin.h"
701 
702 #include <errno.h>
703 #include <netdb.h>
704 #include <sys/poll.h>
705 #include <sys/socket.h>
706 #include <sys/time.h>
707 
708 #include <jansson.h>
709 
710 #ifdef HAVE_LIBCURL
711 #include <curl/curl.h>
712 #ifndef CURL_AT_LEAST_VERSION
713 #define CURL_AT_LEAST_VERSION(x,y,z) 0
714 #endif
715 #endif
716 
717 #ifdef HAVE_LIBOGG
718 #include <ogg/ogg.h>
719 #endif
720 
721 #include "../debug.h"
722 #include "../apierror.h"
723 #include "../config.h"
724 #include "../mutex.h"
725 #include "../rtp.h"
726 #include "../rtpsrtp.h"
727 #include "../rtcp.h"
728 #include "../record.h"
729 #include "../utils.h"
730 #include "../ip-utils.h"
731 
732 /* Default settings */
733 #define JANUS_STREAMING_DEFAULT_SESSION_TIMEOUT 0 /* Overwrite the RTSP session timeout. If set to zero, the RTSP timeout is derived from a session. */
734 #define JANUS_STREAMING_DEFAULT_RECONNECT_DELAY 5 /* Reconnecting delay in seconds. */
735 #define JANUS_STREAMING_DEFAULT_CURL_TIMEOUT 10L /* Communication timeout for cURL. */
736 #define JANUS_STREAMING_DEFAULT_CURL_CONNECT_TIMEOUT 5L /* Connection timeout for cURL. */
737 
738 /* Plugin information */
739 #define JANUS_STREAMING_VERSION			8
740 #define JANUS_STREAMING_VERSION_STRING	"0.0.8"
741 #define JANUS_STREAMING_DESCRIPTION		"This is a streaming plugin for Janus, allowing WebRTC peers to watch/listen to pre-recorded files or media generated by an external source."
742 #define JANUS_STREAMING_NAME			"JANUS Streaming plugin"
743 #define JANUS_STREAMING_AUTHOR			"Meetecho s.r.l."
744 #define JANUS_STREAMING_PACKAGE			"janus.plugin.streaming"
745 
746 /* Plugin methods */
747 janus_plugin *create(void);
748 int janus_streaming_init(janus_callbacks *callback, const char *config_path);
749 void janus_streaming_destroy(void);
750 int janus_streaming_get_api_compatibility(void);
751 int janus_streaming_get_version(void);
752 const char *janus_streaming_get_version_string(void);
753 const char *janus_streaming_get_description(void);
754 const char *janus_streaming_get_name(void);
755 const char *janus_streaming_get_author(void);
756 const char *janus_streaming_get_package(void);
757 void janus_streaming_create_session(janus_plugin_session *handle, int *error);
758 struct janus_plugin_result *janus_streaming_handle_message(janus_plugin_session *handle, char *transaction, json_t *message, json_t *jsep);
759 json_t *janus_streaming_handle_admin_message(json_t *message);
760 void janus_streaming_setup_media(janus_plugin_session *handle);
761 void janus_streaming_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *packet);
762 void janus_streaming_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp *packet);
763 void janus_streaming_data_ready(janus_plugin_session *handle);
764 void janus_streaming_hangup_media(janus_plugin_session *handle);
765 void janus_streaming_destroy_session(janus_plugin_session *handle, int *error);
766 json_t *janus_streaming_query_session(janus_plugin_session *handle);
767 static int janus_streaming_get_fd_port(int fd);
768 
769 /* Plugin setup */
770 static janus_plugin janus_streaming_plugin =
771 	JANUS_PLUGIN_INIT (
772 		.init = janus_streaming_init,
773 		.destroy = janus_streaming_destroy,
774 
775 		.get_api_compatibility = janus_streaming_get_api_compatibility,
776 		.get_version = janus_streaming_get_version,
777 		.get_version_string = janus_streaming_get_version_string,
778 		.get_description = janus_streaming_get_description,
779 		.get_name = janus_streaming_get_name,
780 		.get_author = janus_streaming_get_author,
781 		.get_package = janus_streaming_get_package,
782 
783 		.create_session = janus_streaming_create_session,
784 		.handle_message = janus_streaming_handle_message,
785 		.handle_admin_message = janus_streaming_handle_admin_message,
786 		.setup_media = janus_streaming_setup_media,
787 		.incoming_rtp = janus_streaming_incoming_rtp,
788 		.incoming_rtcp = janus_streaming_incoming_rtcp,
789 		.data_ready = janus_streaming_data_ready,
790 		.hangup_media = janus_streaming_hangup_media,
791 		.destroy_session = janus_streaming_destroy_session,
792 		.query_session = janus_streaming_query_session,
793 	);
794 
795 /* Plugin creator */
create(void)796 janus_plugin *create(void) {
797 	JANUS_LOG(LOG_VERB, "%s created!\n", JANUS_STREAMING_NAME);
798 	return &janus_streaming_plugin;
799 }
800 
801 /* Parameter validation */
802 static struct janus_json_parameter request_parameters[] = {
803 	{"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
804 };
805 static struct janus_json_parameter id_parameters[] = {
806 	{"id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
807 };
808 static struct janus_json_parameter idopt_parameters[] = {
809 	{"id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
810 };
811 static struct janus_json_parameter idstr_parameters[] = {
812 	{"id", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
813 };
814 static struct janus_json_parameter idstropt_parameters[] = {
815 	{"id", JSON_STRING, 0}
816 };
817 static struct janus_json_parameter watch_parameters[] = {
818 	{"pin", JSON_STRING, 0},
819 	{"offer_audio", JANUS_JSON_BOOL, 0},
820 	{"offer_video", JANUS_JSON_BOOL, 0},
821 	{"offer_data", JANUS_JSON_BOOL, 0},
822 	{"restart", JANUS_JSON_BOOL, 0}
823 };
824 static struct janus_json_parameter adminkey_parameters[] = {
825 	{"admin_key", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
826 };
827 static struct janus_json_parameter edit_parameters[] = {
828 	{"new_description", JSON_STRING, 0},
829 	{"new_secret", JSON_STRING, 0},
830 	{"new_pin", JSON_STRING, 0},
831 	{"new_is_private", JANUS_JSON_BOOL, 0},
832 	{"permanent", JANUS_JSON_BOOL, 0}
833 };
834 static struct janus_json_parameter create_parameters[] = {
835 	{"name", JSON_STRING, 0},
836 	{"description", JSON_STRING, 0},
837 	{"metadata", JSON_STRING, 0},
838 	{"is_private", JANUS_JSON_BOOL, 0},
839 	{"type", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
840 	{"secret", JSON_STRING, 0},
841 	{"pin", JSON_STRING, 0},
842 	{"audio", JANUS_JSON_BOOL, 0},
843 	{"video", JANUS_JSON_BOOL, 0},
844 	{"data", JANUS_JSON_BOOL, 0},
845 	{"permanent", JANUS_JSON_BOOL, 0}
846 };
847 static struct janus_json_parameter rtp_parameters[] = {
848 	{"collision", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
849 	{"threads", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
850 	{"srtpsuite", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
851 	{"srtpcrypto", JSON_STRING, 0},
852 	{"e2ee", JANUS_JSON_BOOL, 0}
853 };
854 static struct janus_json_parameter live_parameters[] = {
855 	{"filename", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
856 	{"audiortpmap", JSON_STRING, 0},
857 	{"audiofmtp", JSON_STRING, 0},
858 	{"audiopt", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
859 };
860 static struct janus_json_parameter ondemand_parameters[] = {
861 	{"filename", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
862 	{"audiortpmap", JSON_STRING, 0},
863 	{"audiofmtp", JSON_STRING, 0},
864 	{"audiopt", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
865 };
866 #ifdef HAVE_LIBCURL
867 static struct janus_json_parameter rtsp_parameters[] = {
868 	{"url", JSON_STRING, 0},
869 	{"rtsp_user", JSON_STRING, 0},
870 	{"rtsp_pwd", JSON_STRING, 0},
871 	{"rtsp_reconnect_delay", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
872 	{"rtsp_session_timeout", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
873 	{"rtsp_timeout", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
874 	{"rtsp_conn_timeout", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
875 	{"audiortpmap", JSON_STRING, 0},
876 	{"audiofmtp", JSON_STRING, 0},
877 	{"audiopt", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
878 	{"videortpmap", JSON_STRING, 0},
879 	{"videofmtp", JSON_STRING, 0},
880 	{"videopt", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
881 	{"videobufferkf", JANUS_JSON_BOOL, 0},
882 	{"threads", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
883 	{"rtspiface", JSON_STRING, 0},
884 	{"rtsp_failcheck", JANUS_JSON_BOOL, 0}
885 };
886 #endif
887 static struct janus_json_parameter rtp_audio_parameters[] = {
888 	{"audiomcast", JSON_STRING, 0},
889 	{"audioport", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
890 	{"audiortcpport", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
891 	{"audiopt", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
892 	{"audiortpmap", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
893 	{"audiofmtp", JSON_STRING, 0},
894 	{"audioiface", JSON_STRING, 0},
895 	{"audioskew", JANUS_JSON_BOOL, 0}
896 };
897 static struct janus_json_parameter rtp_video_parameters[] = {
898 	{"videomcast", JSON_STRING, 0},
899 	{"videoport", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
900 	{"videortcpport", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
901 	{"videopt", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
902 	{"videortpmap", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
903 	{"videofmtp", JSON_STRING, 0},
904 	{"videobufferkf", JANUS_JSON_BOOL, 0},
905 	{"videoiface", JSON_STRING, 0},
906 	{"videosimulcast", JANUS_JSON_BOOL, 0},
907 	{"videoport2", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
908 	{"videoport3", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
909 	{"videoskew", JANUS_JSON_BOOL, 0},
910 	{"videosvc", JANUS_JSON_BOOL, 0}
911 };
912 static struct janus_json_parameter rtp_data_parameters[] = {
913 	{"dataport", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
914 	{"databuffermsg", JANUS_JSON_BOOL, 0},
915 	{"datatype", JSON_STRING, 0},
916 	{"dataiface", JSON_STRING, 0}
917 };
918 static struct janus_json_parameter destroy_parameters[] = {
919 	{"permanent", JANUS_JSON_BOOL, 0}
920 };
921 static struct janus_json_parameter recording_parameters[] = {
922 	{"action", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
923 };
924 static struct janus_json_parameter recording_start_parameters[] = {
925 	{"audio", JSON_STRING, 0},
926 	{"video", JSON_STRING, 0},
927 	{"data", JSON_STRING, 0}
928 };
929 static struct janus_json_parameter recording_stop_parameters[] = {
930 	{"audio", JANUS_JSON_BOOL, 0},
931 	{"video", JANUS_JSON_BOOL, 0},
932 	{"data", JANUS_JSON_BOOL, 0}
933 };
934 static struct janus_json_parameter simulcast_parameters[] = {
935 	{"substream", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
936 	{"temporal", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
937 	{"fallback", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
938 };
939 static struct janus_json_parameter svc_parameters[] = {
940 	{"spatial_layer", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
941 	{"temporal_layer", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
942 };
943 static struct janus_json_parameter configure_parameters[] = {
944 	{"audio", JANUS_JSON_BOOL, 0},
945 	{"video", JANUS_JSON_BOOL, 0},
946 	{"data", JANUS_JSON_BOOL, 0},
947 	/* For VP8 (or H.264) simulcast */
948 	{"substream", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
949 	{"temporal", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
950 	{"fallback", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
951 	/* For VP9 SVC */
952 	{"spatial_layer", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
953 	{"temporal_layer", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
954 };
955 static struct janus_json_parameter disable_parameters[] = {
956 	{"stop_recording", JANUS_JSON_BOOL, 0}
957 };
958 
959 /* Static configuration instance */
960 static janus_config *config = NULL;
961 static const char *config_folder = NULL;
962 static janus_mutex config_mutex = JANUS_MUTEX_INITIALIZER;
963 
964 /* Useful stuff */
965 static volatile gint initialized = 0, stopping = 0;
966 static gboolean notify_events = TRUE;
967 static gboolean string_ids = FALSE;
968 static janus_callbacks *gateway = NULL;
969 static GThread *handler_thread;
970 static void *janus_streaming_handler(void *data);
971 
972 /* RTP range to use for random ports */
973 #define DEFAULT_RTP_RANGE_MIN 10000
974 #define DEFAULT_RTP_RANGE_MAX 60000
975 static uint16_t rtp_range_min = DEFAULT_RTP_RANGE_MIN;
976 static uint16_t rtp_range_max = DEFAULT_RTP_RANGE_MAX;
977 static uint16_t rtp_range_slider = DEFAULT_RTP_RANGE_MIN;
978 static janus_mutex fd_mutex = JANUS_MUTEX_INITIALIZER;
979 
980 static void *janus_streaming_ondemand_thread(void *data);
981 static void *janus_streaming_filesource_thread(void *data);
982 static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data);
983 static void janus_streaming_relay_rtcp_packet(gpointer data, gpointer user_data);
984 static void *janus_streaming_relay_thread(void *data);
985 static void janus_streaming_hangup_media_internal(janus_plugin_session *handle);
986 
987 typedef enum janus_streaming_type {
988 	janus_streaming_type_none = 0,
989 	janus_streaming_type_live,
990 	janus_streaming_type_on_demand,
991 } janus_streaming_type;
992 
993 typedef enum janus_streaming_source {
994 	janus_streaming_source_none = 0,
995 	janus_streaming_source_file,
996 	janus_streaming_source_rtp,
997 } janus_streaming_source;
998 
999 typedef struct janus_streaming_rtp_keyframe {
1000 	gboolean enabled;
1001 	/* If enabled, we store the packets of the last keyframe, to immediately send them for new viewers */
1002 	GList *latest_keyframe;
1003 	/* This is where we store packets while we're still collecting the whole keyframe */
1004 	GList *temp_keyframe;
1005 	guint32 temp_ts;
1006 	janus_mutex mutex;
1007 } janus_streaming_rtp_keyframe;
1008 
1009 typedef struct janus_streaming_rtp_relay_packet {
1010 	janus_rtp_header *data;
1011 	gint length;
1012 	gboolean is_rtp;	/* This may be a data packet and not RTP */
1013 	gboolean is_data;
1014 	gboolean is_video;
1015 	gboolean is_keyframe;
1016 	gboolean simulcast;
1017 	uint32_t ssrc[3];
1018 	janus_videocodec codec;
1019 	int substream;
1020 	int ptype;
1021 	uint32_t timestamp;
1022 	uint16_t seq_number;
1023 	/* The following are only relevant for VP9 SVC*/
1024 	gboolean svc;
1025 	janus_vp9_svc_info svc_info;
1026 	/* The following is only relevant for datachannels */
1027 	gboolean textdata;
1028 } janus_streaming_rtp_relay_packet;
1029 static janus_streaming_rtp_relay_packet exit_packet;
janus_streaming_rtp_relay_packet_free(janus_streaming_rtp_relay_packet * pkt)1030 static void janus_streaming_rtp_relay_packet_free(janus_streaming_rtp_relay_packet *pkt) {
1031 	if(pkt == NULL || pkt == &exit_packet)
1032 		return;
1033 	g_free(pkt->data);
1034 	g_free(pkt);
1035 
1036 }
1037 
1038 #ifdef HAVE_LIBCURL
1039 typedef struct janus_streaming_buffer {
1040 	char *buffer;
1041 	size_t size;
1042 } janus_streaming_buffer;
1043 #endif
1044 
1045 typedef struct janus_streaming_rtp_source {
1046 	char *audio_host;
1047 	gint audio_port, remote_audio_port;
1048 	gint audio_rtcp_port, remote_audio_rtcp_port;
1049 	in_addr_t audio_mcast;
1050 	char *video_host;
1051 	gint video_port[3], remote_video_port;
1052 	gint video_rtcp_port, remote_video_rtcp_port;
1053 	in_addr_t video_mcast;
1054 	char *data_host;
1055 	gint data_port;
1056 	janus_recorder *arc;	/* The Janus recorder instance for this streams's audio, if enabled */
1057 	janus_recorder *vrc;	/* The Janus recorder instance for this streams's video, if enabled */
1058 	janus_recorder *drc;	/* The Janus recorder instance for this streams's data, if enabled */
1059 	janus_mutex rec_mutex;	/* Mutex to protect the recorders from race conditions */
1060 	janus_rtp_switching_context context[3];
1061 	int audio_fd;
1062 	int video_fd[3];
1063 	int data_fd;
1064 	int pipefd[2];			/* Just needed to quickly interrupt the poll when it's time to wrap up */
1065 	int audio_rtcp_fd;
1066 	int video_rtcp_fd;
1067 	gboolean simulcast;
1068 	gboolean svc;
1069 	gboolean askew, vskew;
1070 	gint64 last_received_audio;
1071 	gint64 last_received_video;
1072 	gint64 last_received_data;
1073 	uint32_t audio_ssrc;		/* Only needed for fixing outgoing RTCP packets */
1074 	uint32_t video_ssrc;		/* Only needed for fixing outgoing RTCP packets */
1075 	volatile gint need_pli;		/* Whether we need to send a PLI later */
1076 	volatile gint sending_pli;	/* Whether we're currently sending a PLI */
1077 	gint64 pli_latest;			/* Time of latest sent PLI (to avoid flooding) */
1078 	uint32_t lowest_bitrate;	/* Lowest bitrate received by viewers via REMB since last update */
1079 	gint64 remb_latest;			/* Time of latest sent REMB (to avoid flooding) */
1080 	struct sockaddr_storage audio_rtcp_addr, video_rtcp_addr;
1081 #ifdef HAVE_LIBCURL
1082 	gboolean rtsp;
1083 	CURL *curl;
1084 	janus_streaming_buffer *curldata;
1085 	char *rtsp_url;
1086 	char *rtsp_username, *rtsp_password;
1087 	gint64 ka_timeout;
1088 	char *rtsp_ahost, *rtsp_vhost;
1089 	gboolean reconnecting;
1090 	gint64 reconnect_timer;
1091 	gint64 reconnect_delay;
1092 	gint64 session_timeout;
1093 	int rtsp_timeout;
1094 	int rtsp_conn_timeout;
1095 	janus_mutex rtsp_mutex;
1096 #endif
1097 	janus_streaming_rtp_keyframe keyframe;
1098 	gboolean textdata;
1099 	gboolean buffermsg;
1100 	int rtp_collision;
1101 	void *last_msg;
1102 	janus_mutex buffermsg_mutex;
1103 	janus_network_address audio_iface;
1104 	janus_network_address video_iface;
1105 	janus_network_address data_iface;
1106 	/* Only needed for SRTP support */
1107 	gboolean is_srtp;
1108 	int srtpsuite;
1109 	char *srtpcrypto;
1110 	srtp_t srtp_ctx;
1111 	srtp_policy_t srtp_policy;
1112 	/* If the media is end-to-end encrypted, we may need to know */
1113 	gboolean e2ee;
1114 } janus_streaming_rtp_source;
1115 
1116 typedef struct janus_streaming_file_source {
1117 	char *filename;
1118 	gboolean opus;
1119 } janus_streaming_file_source;
1120 
1121 /* used for audio/video fd and RTCP fd */
1122 typedef struct multiple_fds {
1123 	int fd;
1124 	int rtcp_fd;
1125 } multiple_fds;
1126 
1127 typedef struct janus_streaming_codecs {
1128 	gint audio_pt;
1129 	char *audio_rtpmap;
1130 	char *audio_fmtp;
1131 	janus_videocodec video_codec;
1132 	gint video_pt;
1133 	char *video_rtpmap;
1134 	char *video_fmtp;
1135 } janus_streaming_codecs;
1136 
1137 typedef struct janus_streaming_mountpoint {
1138 	guint64 id;			/* Unique mountpoint ID (when using integers) */
1139 	gchar *id_str;		/* Unique mountpoint ID (when using strings) */
1140 	char *name;
1141 	char *description;
1142 	char *metadata;
1143 	gboolean is_private;
1144 	char *secret;
1145 	char *pin;
1146 	gboolean enabled;
1147 	gboolean active;
1148 	GThread *thread;	/* A mountpoint may or may not have a thread */
1149 	janus_streaming_type streaming_type;
1150 	janus_streaming_source streaming_source;
1151 	void *source;	/* Can differ according to the source type */
1152 	GDestroyNotify source_destroy;
1153 	janus_streaming_codecs codecs;
1154 	gboolean audio, video, data;
1155 	GList *viewers;
1156 	int helper_threads;		/* Only relevant for RTP/RTSP mountpoints */
1157 	GList *threads;			/* Only relevant for RTP/RTSP mountpoints */
1158 	volatile gint destroyed;
1159 	janus_mutex mutex;
1160 	janus_refcount ref;
1161 } janus_streaming_mountpoint;
1162 GHashTable *mountpoints = NULL, *mountpoints_temp = NULL;
1163 janus_mutex mountpoints_mutex = JANUS_MUTEX_INITIALIZER;
1164 static char *admin_key = NULL;
1165 
1166 typedef struct janus_streaming_helper {
1167 	janus_streaming_mountpoint *mp;
1168 	guint id;
1169 	GThread *thread;
1170 	int num_viewers;
1171 	GList *viewers;
1172 	GAsyncQueue *queued_packets;
1173 	volatile gint destroyed;
1174 	janus_mutex mutex;
1175 	janus_refcount ref;
1176 } janus_streaming_helper;
janus_streaming_helper_destroy(janus_streaming_helper * helper)1177 static void janus_streaming_helper_destroy(janus_streaming_helper *helper) {
1178 	if(helper && g_atomic_int_compare_and_exchange(&helper->destroyed, 0, 1))
1179 		janus_refcount_decrease(&helper->ref);
1180 }
janus_streaming_helper_free(const janus_refcount * helper_ref)1181 static void janus_streaming_helper_free(const janus_refcount *helper_ref) {
1182 	janus_streaming_helper *helper = janus_refcount_containerof(helper_ref, janus_streaming_helper, ref);
1183 	/* This helper can be destroyed, free all the resources */
1184 	g_async_queue_unref(helper->queued_packets);
1185 	if(helper->viewers != NULL)
1186 		g_list_free(helper->viewers);
1187 	g_free(helper);
1188 }
1189 static void *janus_streaming_helper_thread(void *data);
1190 static void janus_streaming_helper_rtprtcp_packet(gpointer data, gpointer user_data);
1191 
1192 /* Helper to create an RTP live source (e.g., from gstreamer/ffmpeg/vlc/etc.) */
1193 janus_streaming_mountpoint *janus_streaming_create_rtp_source(
1194 		uint64_t id, char *id_str, char *name, char *desc, char *metadata,
1195 		int srtpsuite, char *srtpcrypto, int threads, gboolean e2ee,
1196 		gboolean doaudio, gboolean doaudiortcp, char *amcast, const janus_network_address *aiface,
1197 			uint16_t aport, uint16_t artcpport, uint8_t acodec, char *artpmap, char *afmtp, gboolean doaskew,
1198 		gboolean dovideo, gboolean dovideortcp, char *vmcast, const janus_network_address *viface,
1199 			uint16_t vport, uint16_t vrtcpport, uint8_t vcodec, char *vrtpmap, char *vfmtp, gboolean bufferkf,
1200 			gboolean simulcast, uint16_t vport2, uint16_t vport3, gboolean svc, gboolean dovskew, int rtp_collision,
1201 		gboolean dodata, const janus_network_address *diface, uint16_t dport, gboolean textdata, gboolean buffermsg);
1202 /* Helper to create a file/ondemand live source */
1203 janus_streaming_mountpoint *janus_streaming_create_file_source(
1204 		uint64_t id, char *id_str, char *name, char *desc, char *metadata, char *filename, gboolean live,
1205 		gboolean doaudio, uint8_t acodec, char *artpmap, char *afmtp, gboolean dovideo);
1206 /* Helper to create a rtsp live source */
1207 janus_streaming_mountpoint *janus_streaming_create_rtsp_source(
1208 		uint64_t id, char *id_str, char *name, char *desc, char *metadata,
1209 		char *url, char *username, char *password,
1210 		gboolean doaudio, int audiopt, char *artpmap, char *afmtp,
1211 		gboolean dovideo, int videopt, char *vrtpmap, char *vfmtp, gboolean bufferkf,
1212 		const janus_network_address *iface, int threads,
1213 		gint64 reconnect_delay, gint64 session_timeout, int rtsp_timeout, int rtsp_conn_timeout,
1214 		gboolean error_on_failure);
1215 
1216 typedef struct janus_streaming_message {
1217 	janus_plugin_session *handle;
1218 	char *transaction;
1219 	json_t *message;
1220 	json_t *jsep;
1221 } janus_streaming_message;
1222 static GAsyncQueue *messages = NULL;
1223 static janus_streaming_message exit_message;
1224 
1225 typedef struct janus_streaming_session {
1226 	janus_plugin_session *handle;
1227 	janus_streaming_mountpoint *mountpoint;
1228 	gint64 sdp_sessid;
1229 	gint64 sdp_version;
1230 	volatile gint started;
1231 	volatile gint paused;
1232 	gboolean audio, video, data;		/* Whether audio, video and/or data must be sent to this listener */
1233 	int audio_pt, video_pt;
1234 	janus_rtp_switching_context context;
1235 	janus_rtp_simulcasting_context sim_context;
1236 	janus_vp8_simulcast_context vp8_context;
1237 	/* The following are only relevant the mountpoint is VP9-SVC, and are not to be confused with VP8
1238 	 * simulcast, which has similar info (substream/templayer) but in a completely different context */
1239 	int spatial_layer, target_spatial_layer;
1240 	gint64 last_spatial_layer[3];
1241 	int temporal_layer, target_temporal_layer;
1242 	/* If the media is end-to-end encrypted, we may need to know */
1243 	gboolean e2ee;
1244 	janus_mutex mutex;
1245 	volatile gint dataready;
1246 	volatile gint stopping;
1247 	volatile gint renegotiating;
1248 	volatile gint hangingup;
1249 	volatile gint destroyed;
1250 	janus_refcount ref;
1251 } janus_streaming_session;
1252 static GHashTable *sessions;
1253 static janus_mutex sessions_mutex = JANUS_MUTEX_INITIALIZER;
1254 
janus_streaming_session_destroy(janus_streaming_session * session)1255 static void janus_streaming_session_destroy(janus_streaming_session *session) {
1256 	if(session && g_atomic_int_compare_and_exchange(&session->destroyed, 0, 1))
1257 		janus_refcount_decrease(&session->ref);
1258 }
1259 
janus_streaming_session_free(const janus_refcount * session_ref)1260 static void janus_streaming_session_free(const janus_refcount *session_ref) {
1261 	janus_streaming_session *session = janus_refcount_containerof(session_ref, janus_streaming_session, ref);
1262 	/* Remove the reference to the core plugin session */
1263 	janus_refcount_decrease(&session->handle->ref);
1264 	/* This session can be destroyed, free all the resources */
1265 	g_free(session);
1266 }
1267 
janus_streaming_mountpoint_destroy(janus_streaming_mountpoint * mountpoint)1268 static void janus_streaming_mountpoint_destroy(janus_streaming_mountpoint *mountpoint) {
1269 	if(!mountpoint)
1270 		return;
1271 	if(!g_atomic_int_compare_and_exchange(&mountpoint->destroyed, 0, 1))
1272 		return;
1273 	/* If this is an RTP source, interrupt the poll */
1274 	if(mountpoint->streaming_source == janus_streaming_source_rtp) {
1275 		janus_streaming_rtp_source *source = mountpoint->source;
1276 		if(source != NULL && source->pipefd[1] > 0) {
1277 			int code = 1;
1278 			ssize_t res = 0;
1279 			do {
1280 				res = write(source->pipefd[1], &code, sizeof(int));
1281 			} while(res == -1 && errno == EINTR);
1282 		}
1283 	}
1284 	/* Wait for the thread to finish */
1285 	if(mountpoint->thread != NULL)
1286 		g_thread_join(mountpoint->thread);
1287 	/* Get rid of the helper threads, if any */
1288 	if(mountpoint->helper_threads > 0) {
1289 		GList *l = mountpoint->threads;
1290 		while(l) {
1291 			janus_streaming_helper *ht = (janus_streaming_helper *)l->data;
1292 			g_async_queue_push(ht->queued_packets, &exit_packet);
1293 			janus_streaming_helper_destroy(ht);
1294 			l = l->next;
1295 		}
1296 	}
1297 	/* Decrease the counter */
1298 	janus_refcount_decrease(&mountpoint->ref);
1299 }
1300 
janus_streaming_mountpoint_free(const janus_refcount * mp_ref)1301 static void janus_streaming_mountpoint_free(const janus_refcount *mp_ref) {
1302 	janus_streaming_mountpoint *mp = janus_refcount_containerof(mp_ref, janus_streaming_mountpoint, ref);
1303 	/* This mountpoint can be destroyed, free all the resources */
1304 
1305 	g_free(mp->id_str);
1306 	g_free(mp->name);
1307 	g_free(mp->description);
1308 	g_free(mp->metadata);
1309 	g_free(mp->secret);
1310 	g_free(mp->pin);
1311 	janus_mutex_lock(&mp->mutex);
1312 	if(mp->viewers != NULL)
1313 		g_list_free(mp->viewers);
1314 	if(mp->threads != NULL) {
1315 		/* Remove the last reference to the helper threads, if any */
1316 		GList *l = mp->threads;
1317 		while(l) {
1318 			janus_streaming_helper *ht = (janus_streaming_helper *)l->data;
1319 			janus_refcount_decrease(&ht->ref);
1320 			l = l->next;
1321 		}
1322 		/* Destroy the list */
1323 		g_list_free(mp->threads);
1324 	}
1325 	janus_mutex_unlock(&mp->mutex);
1326 
1327 	if(mp->source != NULL && mp->source_destroy != NULL) {
1328 		mp->source_destroy(mp->source);
1329 	}
1330 
1331 	g_free(mp->codecs.audio_rtpmap);
1332 	g_free(mp->codecs.audio_fmtp);
1333 	g_free(mp->codecs.video_rtpmap);
1334 	g_free(mp->codecs.video_fmtp);
1335 
1336 	g_free(mp);
1337 }
1338 
janus_streaming_message_free(janus_streaming_message * msg)1339 static void janus_streaming_message_free(janus_streaming_message *msg) {
1340 	if(!msg || msg == &exit_message)
1341 		return;
1342 
1343 	if(msg->handle && msg->handle->plugin_handle) {
1344 		janus_streaming_session *session = (janus_streaming_session *)msg->handle->plugin_handle;
1345 		janus_refcount_decrease(&session->ref);
1346 	}
1347 	msg->handle = NULL;
1348 
1349 	g_free(msg->transaction);
1350 	msg->transaction = NULL;
1351 	if(msg->message)
1352 		json_decref(msg->message);
1353 	msg->message = NULL;
1354 	if(msg->jsep)
1355 		json_decref(msg->jsep);
1356 	msg->jsep = NULL;
1357 
1358 	g_free(msg);
1359 }
1360 
1361 #ifdef HAVE_LIBOGG
1362 /* Helper struct to handle the playout of Opus files */
1363 typedef struct janus_streaming_opus_context {
1364 	char *name, *filename;
1365 	FILE *file;
1366 	ogg_sync_state sync;
1367 	ogg_stream_state stream;
1368 	ogg_page page;
1369 	ogg_packet pkt;
1370 	char *oggbuf;
1371 	gint state, headers;
1372 } janus_streaming_opus_context;
1373 /* Helper method to open an Opus file, and make sure it's valid */
janus_streaming_opus_context_init(janus_streaming_opus_context * ctx)1374 static int janus_streaming_opus_context_init(janus_streaming_opus_context *ctx) {
1375 	if(ctx == NULL || ctx->file == NULL)
1376 		return -1;
1377 	fseek(ctx->file, 0, SEEK_SET);
1378 	ogg_stream_clear(&ctx->stream);
1379 	ogg_sync_clear(&ctx->sync);
1380 	if(ogg_sync_init(&ctx->sync) < 0) {
1381 		JANUS_LOG(LOG_ERR, "[%s] Error re-initializing Ogg sync state...\n", ctx->name);
1382 		return -1;
1383 	}
1384 	ctx->headers = 0;
1385 	return 0;
1386 }
1387 /* Helper method to check if an Ogg page begins with an Ogg stream */
janus_streaming_ogg_is_opus(ogg_page * page)1388 static gboolean janus_streaming_ogg_is_opus(ogg_page *page) {
1389 	ogg_stream_state state;
1390 	ogg_packet pkt;
1391 	ogg_stream_init(&state, ogg_page_serialno(page));
1392 	ogg_stream_pagein(&state, page);
1393 	if(ogg_stream_packetout(&state, &pkt) == 1) {
1394 		if(pkt.bytes >= 19 && !memcmp(pkt.packet, "OpusHead", 8)) {
1395 			ogg_stream_clear(&state);
1396 			return 1;
1397 		}
1398 	}
1399 	ogg_stream_clear(&state);
1400 	return FALSE;
1401 }
1402 /* Helper method to traverse the Opus file until we get a packet we can send */
janus_streaming_opus_context_read(janus_streaming_opus_context * ctx,char * buffer,int length)1403 static int janus_streaming_opus_context_read(janus_streaming_opus_context *ctx, char *buffer, int length) {
1404 	if(ctx == NULL || ctx->file == NULL || buffer == NULL)
1405 		return -1;
1406 	/* Check our current state in processing the Ogg file */
1407 	int read = 0;
1408 	if(ctx->state == 0) {
1409 		/* Prepare a buffer, and read from the Ogg file... */
1410 		ctx->oggbuf = ogg_sync_buffer(&ctx->sync, 8192);
1411 		if(ctx->oggbuf == NULL) {
1412 			JANUS_LOG(LOG_ERR, "[%s] ogg_sync_buffer failed...\n", ctx->name);
1413 			return -2;
1414 		}
1415 		read = fread(ctx->oggbuf, 1, 8192, ctx->file);
1416 		if(read == 0 && feof(ctx->file)) {
1417 			/* FIXME We're doing this forever... should this be configurable? */
1418 			JANUS_LOG(LOG_VERB, "[%s] Rewind! (%s)\n", ctx->name, ctx->filename);
1419 			if(janus_streaming_opus_context_init(ctx) < 0)
1420 				return -3;
1421 			return janus_streaming_opus_context_read(ctx, buffer, length);
1422 		}
1423 		if(ogg_sync_wrote(&ctx->sync, read) < 0) {
1424 			JANUS_LOG(LOG_ERR, "[%s] ogg_sync_wrote failed...\n", ctx->name);
1425 			return -4;
1426 		}
1427 		/* Next state: sync pageout */
1428 		ctx->state = 1;
1429 	}
1430 	if(ctx->state == 1) {
1431 		/* Prepare an ogg_page out of the buffer */
1432 		while((read = ogg_sync_pageout(&ctx->sync, &ctx->page)) == 1) {
1433 			/* Let's look for an Opus stream, first of all */
1434 			if(ctx->headers == 0) {
1435 				if(janus_streaming_ogg_is_opus(&ctx->page)) {
1436 					/* This is the start of an Opus stream */
1437 					if(ogg_stream_init(&ctx->stream, ogg_page_serialno(&ctx->page)) < 0) {
1438 						JANUS_LOG(LOG_ERR, "[%s] ogg_stream_init failed...\n", ctx->name);
1439 						return -5;
1440 					}
1441 					ctx->headers++;
1442 				} else if(!ogg_page_bos(&ctx->page)) {
1443 					/* No Opus stream? */
1444 					JANUS_LOG(LOG_ERR, "[%s] No Opus stream...\n", ctx->name);
1445 					return -6;
1446 				} else {
1447 					/* Still waiting for an Opus stream */
1448 					return janus_streaming_opus_context_read(ctx, buffer, length);
1449 				}
1450 			}
1451 			/* Submit the page for packetization */
1452 			if(ogg_stream_pagein(&ctx->stream, &ctx->page) < 0) {
1453 				JANUS_LOG(LOG_ERR, "[%s] ogg_stream_pagein failed...\n", ctx->name);
1454 				return -7;
1455 			}
1456 			/* Time to start reading packets */
1457 			ctx->state = 2;
1458 			break;
1459 		}
1460 		if(read != 1) {
1461 			/* Go back to reading from the file */
1462 			ctx->state = 0;
1463 			return janus_streaming_opus_context_read(ctx, buffer, length);
1464 		}
1465 	}
1466 	if(ctx->state == 2) {
1467 		/* Read and process available packets */
1468 		if(ogg_stream_packetout(&ctx->stream, &ctx->pkt) != 1) {
1469 			/* Go back to reading pages */
1470 			ctx->state = 1;
1471 			return janus_streaming_opus_context_read(ctx, buffer, length);
1472 		} else {
1473 			/* Skip header packets */
1474 			if(ctx->headers == 1 && ctx->pkt.bytes >= 19 && !memcmp(ctx->pkt.packet, "OpusHead", 8)) {
1475 				ctx->headers++;
1476 				return janus_streaming_opus_context_read(ctx, buffer, length);
1477 			}
1478 			if(ctx->headers == 2 && ctx->pkt.bytes >= 16 && !memcmp(ctx->pkt.packet, "OpusTags", 8)) {
1479 				ctx->headers++;
1480 				return janus_streaming_opus_context_read(ctx, buffer, length);
1481 			}
1482 			/* Get the packet duration */
1483 			if(length < ctx->pkt.bytes) {
1484 				JANUS_LOG(LOG_WARN, "[%s] Buffer too short for Opus packet (%d < %ld)\n",
1485 					ctx->name, length, ctx->pkt.bytes);
1486 				return -8;
1487 			}
1488 			memcpy(buffer, ctx->pkt.packet, ctx->pkt.bytes);
1489 			length = ctx->pkt.bytes;
1490 			return length;
1491 		}
1492 	}
1493 	/* If we got here, continue with the iteration */
1494 	return -9;
1495 }
1496 /* Helper method to cleanup an Opus context */
janus_streaming_opus_context_cleanup(janus_streaming_opus_context * ctx)1497 static void janus_streaming_opus_context_cleanup(janus_streaming_opus_context *ctx) {
1498 	if(ctx == NULL)
1499 		return;
1500 	if(ctx->headers > 0)
1501 		ogg_stream_clear(&ctx->stream);
1502 	ogg_sync_clear(&ctx->sync);
1503 }
1504 #endif
1505 
1506 
1507 /* Helper method to send an RTCP PLI */
janus_streaming_rtcp_pli_send(janus_streaming_rtp_source * source)1508 static void janus_streaming_rtcp_pli_send(janus_streaming_rtp_source *source) {
1509 	if(source == NULL || source->video_rtcp_fd < 0 || source->video_rtcp_addr.ss_family == 0)
1510 		return;
1511 	if(!g_atomic_int_compare_and_exchange(&source->sending_pli, 0, 1))
1512 		return;
1513 	gint64 now = janus_get_monotonic_time();
1514 	if(now - source->pli_latest < G_USEC_PER_SEC) {
1515 		/* We just sent a PLI less than a second ago, schedule a new delivery later */
1516 		g_atomic_int_set(&source->need_pli, 1);
1517 		g_atomic_int_set(&source->sending_pli, 0);
1518 		return;
1519 	}
1520 	/* Update the time of when we last sent a keyframe request */
1521 	g_atomic_int_set(&source->need_pli, 0);
1522 	source->pli_latest = janus_get_monotonic_time();
1523 	JANUS_LOG(LOG_HUGE, "Sending PLI\n");
1524 	/* Generate a PLI */
1525 	char rtcp_buf[12];
1526 	int rtcp_len = 12;
1527 	janus_rtcp_pli((char *)&rtcp_buf, rtcp_len);
1528 	janus_rtcp_fix_ssrc(NULL, rtcp_buf, rtcp_len, 1, 1, source->video_ssrc);
1529 	/* Send the packet */
1530 	int sent = 0;
1531 	if((sent = sendto(source->video_rtcp_fd, rtcp_buf, rtcp_len, 0,
1532 			(struct sockaddr *)&source->video_rtcp_addr, sizeof(source->video_rtcp_addr))) < 0) {
1533 		JANUS_LOG(LOG_ERR, "Error in sendto... %d (%s)\n", errno, g_strerror(errno));
1534 	} else {
1535 		JANUS_LOG(LOG_HUGE, "Sent %d/%d bytes\n", sent, rtcp_len);
1536 	}
1537 	g_atomic_int_set(&source->sending_pli, 0);
1538 }
1539 
1540 /* Helper method to send an RTCP REMB */
janus_streaming_rtcp_remb_send(janus_streaming_rtp_source * source)1541 static void janus_streaming_rtcp_remb_send(janus_streaming_rtp_source *source) {
1542 	if(source == NULL || source->video_rtcp_fd < 0 || source->video_rtcp_addr.ss_family == 0)
1543 		return;
1544 	/* Update the time of when we last sent REMB feedback */
1545 	source->remb_latest = janus_get_monotonic_time();
1546 	/* Generate a REMB */
1547 	char rtcp_buf[24];
1548 	int rtcp_len = 24;
1549 	janus_rtcp_remb((char *)(&rtcp_buf), rtcp_len, source->lowest_bitrate);
1550 	janus_rtcp_fix_ssrc(NULL, rtcp_buf, rtcp_len, 1, 1, source->video_ssrc);
1551 	JANUS_LOG(LOG_HUGE, "Sending REMB: %"SCNu32"\n", source->lowest_bitrate);
1552 	/* Reset the lowest bitrate */
1553 	source->lowest_bitrate = 0;
1554 	/* Send the packet */
1555 	int sent = 0;
1556 	if((sent = sendto(source->video_rtcp_fd, rtcp_buf, rtcp_len, 0,
1557 			(struct sockaddr *)&source->video_rtcp_addr, sizeof(source->video_rtcp_addr))) < 0) {
1558 		JANUS_LOG(LOG_ERR, "Error in sendto... %d (%s)\n", errno, g_strerror(errno));
1559 	} else {
1560 		JANUS_LOG(LOG_HUGE, "Sent %d/%d bytes\n", sent, rtcp_len);
1561 	}
1562 }
1563 
1564 
1565 /* Error codes */
1566 #define JANUS_STREAMING_ERROR_NO_MESSAGE			450
1567 #define JANUS_STREAMING_ERROR_INVALID_JSON			451
1568 #define JANUS_STREAMING_ERROR_INVALID_REQUEST		452
1569 #define JANUS_STREAMING_ERROR_MISSING_ELEMENT		453
1570 #define JANUS_STREAMING_ERROR_INVALID_ELEMENT		454
1571 #define JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT	455
1572 #define JANUS_STREAMING_ERROR_CANT_CREATE			456
1573 #define JANUS_STREAMING_ERROR_UNAUTHORIZED			457
1574 #define JANUS_STREAMING_ERROR_CANT_SWITCH			458
1575 #define JANUS_STREAMING_ERROR_CANT_RECORD			459
1576 #define JANUS_STREAMING_ERROR_INVALID_STATE			460
1577 #define JANUS_STREAMING_ERROR_UNKNOWN_ERROR			470
1578 
1579 
1580 /* Plugin implementation */
janus_streaming_init(janus_callbacks * callback,const char * config_path)1581 int janus_streaming_init(janus_callbacks *callback, const char *config_path) {
1582 #ifdef HAVE_LIBCURL
1583 	curl_global_init(CURL_GLOBAL_ALL);
1584 #else
1585 	JANUS_LOG(LOG_WARN, "libcurl not available, Streaming plugin will not have RTSP support\n");
1586 #endif
1587 #ifndef HAVE_LIBOGG
1588 	JANUS_LOG(LOG_WARN, "libogg not available, Streaming plugin will not have file-based Opus streaming\n");
1589 #endif
1590 	if(g_atomic_int_get(&stopping)) {
1591 		/* Still stopping from before */
1592 		return -1;
1593 	}
1594 	if(callback == NULL || config_path == NULL) {
1595 		/* Invalid arguments */
1596 		return -1;
1597 	}
1598 
1599 	struct ifaddrs *ifas = NULL;
1600 	if(getifaddrs(&ifas) == -1) {
1601 		JANUS_LOG(LOG_ERR, "Unable to acquire list of network devices/interfaces; some configurations may not work as expected... %d (%s)\n",
1602 			errno, g_strerror(errno));
1603 	}
1604 
1605 	/* Read configuration */
1606 	char filename[255];
1607 	g_snprintf(filename, 255, "%s/%s.jcfg", config_path, JANUS_STREAMING_PACKAGE);
1608 	JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
1609 	config = janus_config_parse(filename);
1610 	if(config == NULL) {
1611 		JANUS_LOG(LOG_WARN, "Couldn't find .jcfg configuration file (%s), trying .cfg\n", JANUS_STREAMING_PACKAGE);
1612 		g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_STREAMING_PACKAGE);
1613 		JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
1614 		config = janus_config_parse(filename);
1615 	}
1616 	config_folder = config_path;
1617 	if(config != NULL)
1618 		janus_config_print(config);
1619 
1620 	/* Threads will expect this to be set */
1621 	g_atomic_int_set(&initialized, 1);
1622 
1623 	/* Parse configuration to populate the mountpoints */
1624 	if(config != NULL) {
1625 		janus_config_category *config_general = janus_config_get_create(config, NULL, janus_config_type_category, "general");
1626 		/* Any admin key to limit who can "create"? */
1627 		janus_config_item *key = janus_config_get(config, config_general, janus_config_type_item, "admin_key");
1628 		if(key != NULL && key->value != NULL)
1629 			admin_key = g_strdup(key->value);
1630 		janus_config_item *range = janus_config_get(config, config_general, janus_config_type_item, "rtp_port_range");
1631 		if(range && range->value) {
1632 			/* Split in min and max port */
1633 			char *maxport = strrchr(range->value, '-');
1634 			if(maxport != NULL) {
1635 				*maxport = '\0';
1636 				maxport++;
1637 				if(janus_string_to_uint16(range->value, &rtp_range_min) < 0)
1638 					JANUS_LOG(LOG_WARN, "Invalid RTP min port value: %s (assuming 0)\n", range->value);
1639 				if(janus_string_to_uint16(maxport, &rtp_range_max) < 0)
1640 					JANUS_LOG(LOG_WARN, "Invalid RTP max port value: %s (assuming 0)\n", maxport);
1641 				maxport--;
1642 				*maxport = '-';
1643 			}
1644 			if(rtp_range_min > rtp_range_max) {
1645 				uint16_t temp_port = rtp_range_min;
1646 				rtp_range_min = rtp_range_max;
1647 				rtp_range_max = temp_port;
1648 			}
1649 			if(rtp_range_min % 2)
1650 				rtp_range_min++;	/* Pick an even port for RTP */
1651 			if(rtp_range_min > rtp_range_max) {
1652 				JANUS_LOG(LOG_WARN, "Incorrect port range (%u -- %u), switching min and max\n", rtp_range_min, rtp_range_max);
1653 				uint16_t range_temp = rtp_range_max;
1654 				rtp_range_max = rtp_range_min;
1655 				rtp_range_min = range_temp;
1656 			}
1657 			if(rtp_range_max == 0)
1658 				rtp_range_max = 65535;
1659 			rtp_range_slider = rtp_range_min;
1660 			JANUS_LOG(LOG_VERB, "Streaming RTP/RTCP port range: %u -- %u\n", rtp_range_min, rtp_range_max);
1661 		}
1662 		janus_config_item *events = janus_config_get(config, config_general, janus_config_type_item, "events");
1663 		if(events != NULL && events->value != NULL)
1664 			notify_events = janus_is_true(events->value);
1665 		if(!notify_events && callback->events_is_enabled()) {
1666 			JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_STREAMING_NAME);
1667 		}
1668 		janus_config_item *ids = janus_config_get(config, config_general, janus_config_type_item, "string_ids");
1669 		if(ids != NULL && ids->value != NULL)
1670 			string_ids = janus_is_true(ids->value);
1671 		if(string_ids) {
1672 			JANUS_LOG(LOG_INFO, "Streaming will use alphanumeric IDs, not numeric\n");
1673 		}
1674 	}
1675 	/* Iterate on all mountpoints */
1676 	mountpoints = g_hash_table_new_full(string_ids ? g_str_hash : g_int64_hash, string_ids ? g_str_equal : g_int64_equal,
1677 		(GDestroyNotify)g_free, (GDestroyNotify)janus_streaming_mountpoint_destroy);
1678 	mountpoints_temp = g_hash_table_new_full(string_ids ? g_str_hash : g_int64_hash, string_ids ? g_str_equal : g_int64_equal,
1679 		(GDestroyNotify)g_free, NULL);
1680 	if(config != NULL) {
1681 		GList *clist = janus_config_get_categories(config, NULL), *cl = clist;
1682 		while(cl != NULL) {
1683 			janus_config_category *cat = (janus_config_category *)cl->data;
1684 			if(cat->name == NULL || !strcasecmp(cat->name, "general")) {
1685 				cl = cl->next;
1686 				continue;
1687 			}
1688 			JANUS_LOG(LOG_VERB, "Adding Streaming mountpoint '%s'\n", cat->name);
1689 			janus_config_item *type = janus_config_get(config, cat, janus_config_type_item, "type");
1690 			if(type == NULL || type->value == NULL) {
1691 				JANUS_LOG(LOG_WARN, "  -- Invalid type, skipping mountpoint '%s'...\n", cat->name);
1692 				cl = cl->next;
1693 				continue;
1694 			}
1695 			janus_config_item *id = janus_config_get(config, cat, janus_config_type_item, "id");
1696 			guint64 mpid = 0;
1697 			if(id == NULL || id->value == NULL) {
1698 				JANUS_LOG(LOG_VERB, "Missing id for mountpoint '%s', will generate a random one...\n", cat->name);
1699 			} else {
1700 				janus_mutex_lock(&mountpoints_mutex);
1701 				if(!string_ids) {
1702 					mpid = g_ascii_strtoull(id->value, 0, 10);
1703 					/* Make sure the ID is completely numeric */
1704 					char mpid_str[30];
1705 					g_snprintf(mpid_str, sizeof(mpid_str), "%"SCNu64, mpid);
1706 					if(strcmp(id->value, mpid_str)) {
1707 						janus_mutex_unlock(&mountpoints_mutex);
1708 						JANUS_LOG(LOG_ERR, "Can't add the Streaming mountpoint '%s', ID '%s' is not numeric...\n",
1709 							cat->name, id->value);
1710 						cl = cl->next;
1711 						continue;
1712 					}
1713 					if(mpid == 0) {
1714 						janus_mutex_unlock(&mountpoints_mutex);
1715 						JANUS_LOG(LOG_ERR, "Can't add the Streaming mountpoint '%s', invalid ID '%s'...\n",
1716 							cat->name, id->value);
1717 						cl = cl->next;
1718 						continue;
1719 					}
1720 				}
1721 				/* Let's make sure the mountpoint doesn't exist already */
1722 				if(g_hash_table_lookup(mountpoints, string_ids ? (gpointer)id->value : (gpointer)&mpid) != NULL) {
1723 					/* It does... */
1724 					janus_mutex_unlock(&mountpoints_mutex);
1725 					JANUS_LOG(LOG_ERR, "Can't add the Streaming mountpoint '%s', ID '%s' already exists...\n",
1726 						cat->name, id->value);
1727 					cl = cl->next;
1728 					continue;
1729 				}
1730 				janus_mutex_unlock(&mountpoints_mutex);
1731 			}
1732 			if(!strcasecmp(type->value, "rtp")) {
1733 				janus_network_address video_iface, audio_iface, data_iface;
1734 				/* RTP live source (e.g., from gstreamer/ffmpeg/vlc/etc.) */
1735 				janus_config_item *desc = janus_config_get(config, cat, janus_config_type_item, "description");
1736 				janus_config_item *md = janus_config_get(config, cat, janus_config_type_item, "metadata");
1737 				janus_config_item *priv = janus_config_get(config, cat, janus_config_type_item, "is_private");
1738 				janus_config_item *secret = janus_config_get(config, cat, janus_config_type_item, "secret");
1739 				janus_config_item *pin = janus_config_get(config, cat, janus_config_type_item, "pin");
1740 				janus_config_item *audio = janus_config_get(config, cat, janus_config_type_item, "audio");
1741 				janus_config_item *askew = janus_config_get(config, cat, janus_config_type_item, "audioskew");
1742 				janus_config_item *video = janus_config_get(config, cat, janus_config_type_item, "video");
1743 				janus_config_item *vskew = janus_config_get(config, cat, janus_config_type_item, "videoskew");
1744 				janus_config_item *vsvc = janus_config_get(config, cat, janus_config_type_item, "videosvc");
1745 				janus_config_item *data = janus_config_get(config, cat, janus_config_type_item, "data");
1746 				janus_config_item *diface = janus_config_get(config, cat, janus_config_type_item, "dataiface");
1747 				janus_config_item *amcast = janus_config_get(config, cat, janus_config_type_item, "audiomcast");
1748 				janus_config_item *aiface = janus_config_get(config, cat, janus_config_type_item, "audioiface");
1749 				janus_config_item *aport = janus_config_get(config, cat, janus_config_type_item, "audioport");
1750 				janus_config_item *artcpport = janus_config_get(config, cat, janus_config_type_item, "audiortcpport");
1751 				janus_config_item *acodec = janus_config_get(config, cat, janus_config_type_item, "audiopt");
1752 				janus_config_item *artpmap = janus_config_get(config, cat, janus_config_type_item, "audiortpmap");
1753 				janus_config_item *afmtp = janus_config_get(config, cat, janus_config_type_item, "audiofmtp");
1754 				janus_config_item *vmcast = janus_config_get(config, cat, janus_config_type_item, "videomcast");
1755 				janus_config_item *viface = janus_config_get(config, cat, janus_config_type_item, "videoiface");
1756 				janus_config_item *vport = janus_config_get(config, cat, janus_config_type_item, "videoport");
1757 				janus_config_item *vrtcpport = janus_config_get(config, cat, janus_config_type_item, "videortcpport");
1758 				janus_config_item *vcodec = janus_config_get(config, cat, janus_config_type_item, "videopt");
1759 				janus_config_item *vrtpmap = janus_config_get(config, cat, janus_config_type_item, "videortpmap");
1760 				janus_config_item *vfmtp = janus_config_get(config, cat, janus_config_type_item, "videofmtp");
1761 				janus_config_item *vkf = janus_config_get(config, cat, janus_config_type_item, "videobufferkf");
1762 				janus_config_item *vsc = janus_config_get(config, cat, janus_config_type_item, "videosimulcast");
1763 				janus_config_item *vport2 = janus_config_get(config, cat, janus_config_type_item, "videoport2");
1764 				janus_config_item *vport3 = janus_config_get(config, cat, janus_config_type_item, "videoport3");
1765 				janus_config_item *dport = janus_config_get(config, cat, janus_config_type_item, "dataport");
1766 				janus_config_item *dbm = janus_config_get(config, cat, janus_config_type_item, "databuffermsg");
1767 				janus_config_item *dt = janus_config_get(config, cat, janus_config_type_item, "datatype");
1768 				janus_config_item *rtpcollision = janus_config_get(config, cat, janus_config_type_item, "collision");
1769 				janus_config_item *threads = janus_config_get(config, cat, janus_config_type_item, "threads");
1770 				janus_config_item *ssuite = janus_config_get(config, cat, janus_config_type_item, "srtpsuite");
1771 				janus_config_item *scrypto = janus_config_get(config, cat, janus_config_type_item, "srtpcrypto");
1772 				janus_config_item *e2ee = janus_config_get(config, cat, janus_config_type_item, "e2ee");
1773 				gboolean is_private = priv && priv->value && janus_is_true(priv->value);
1774 				gboolean doaudio = audio && audio->value && janus_is_true(audio->value);
1775 				gboolean doaskew = audio && askew && askew->value && janus_is_true(askew->value);
1776 				gboolean dovideo = video && video->value && janus_is_true(video->value);
1777 				gboolean dovskew = video && vskew && vskew->value && janus_is_true(vskew->value);
1778 				gboolean dosvc = video && vsvc && vsvc->value && janus_is_true(vsvc->value);
1779 				gboolean dodata = data && data->value && janus_is_true(data->value);
1780 				gboolean bufferkf = video && vkf && vkf->value && janus_is_true(vkf->value);
1781 				gboolean simulcast = video && vsc && vsc->value && janus_is_true(vsc->value);
1782 				if(simulcast && bufferkf) {
1783 					/* FIXME We'll need to take care of this */
1784 					JANUS_LOG(LOG_WARN, "Simulcasting enabled, so disabling buffering of keyframes\n");
1785 					bufferkf = FALSE;
1786 				}
1787 				gboolean buffermsg = data && dbm && dbm->value && janus_is_true(dbm->value);
1788 				gboolean textdata = TRUE;
1789 				if(data && dt && dt->value) {
1790 					if(!strcasecmp(dt->value, "text"))
1791 						textdata = TRUE;
1792 					else if(!strcasecmp(dt->value, "binary"))
1793 						textdata = FALSE;
1794 					else {
1795 						JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid data type '%s'...\n", cat->name, dt->value);
1796 						cl = cl->next;
1797 						continue;
1798 					}
1799 				}
1800 				if(!doaudio && !dovideo && !dodata) {
1801 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', no audio, video or data have to be streamed...\n", cat->name);
1802 					cl = cl->next;
1803 					continue;
1804 				}
1805 				uint16_t audio_port = 0, audio_rtcp_port = 0;
1806 				if(doaudio &&
1807 						(aport == NULL || aport->value == NULL ||
1808 						janus_string_to_uint16(aport->value, &audio_port) < 0 || audio_port == 0 ||
1809 						acodec == NULL || acodec->value == NULL ||
1810 						artpmap == NULL || artpmap->value == NULL)) {
1811 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', missing mandatory information for audio...\n", cat->name);
1812 					cl = cl->next;
1813 					continue;
1814 				}
1815 				if(doaudio && artcpport != NULL && artcpport->value != NULL &&
1816 						(janus_string_to_uint16(artcpport->value, &audio_rtcp_port) < 0)) {
1817 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid audio RTCP port...\n", cat->name);
1818 					cl = cl->next;
1819 					continue;
1820 				}
1821 				gboolean doaudiortcp = (artcpport != NULL && artcpport->value != NULL);
1822 				if(doaudio && aiface) {
1823 					if(!ifas) {
1824 						JANUS_LOG(LOG_ERR, "Skipping 'rtp' mountpoint '%s', it relies on network configuration but network device information is unavailable...\n", cat->name);
1825 						cl = cl->next;
1826 						continue;
1827 					}
1828 					if(janus_network_lookup_interface(ifas, aiface->value, &audio_iface) != 0) {
1829 						JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid network interface configuration for audio...\n", cat->name);
1830 						cl = cl->next;
1831 						continue;
1832 					}
1833 				}
1834 				uint16_t video_port = 0, video_port2 = 0, video_port3 = 0, video_rtcp_port = 0;
1835 				if(dovideo &&
1836 						(vport == NULL || vport->value == NULL ||
1837 						janus_string_to_uint16(vport->value, &video_port) < 0 || video_port == 0 ||
1838 						vcodec == NULL || vcodec->value == NULL ||
1839 						vrtpmap == NULL || vrtpmap->value == NULL)) {
1840 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', missing mandatory information for video...\n", cat->name);
1841 					cl = cl->next;
1842 					continue;
1843 				}
1844 				if(dovideo && vrtcpport != NULL && vrtcpport->value != NULL &&
1845 						(janus_string_to_uint16(vrtcpport->value, &video_rtcp_port) < 0)) {
1846 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid video RTCP port...\n", cat->name);
1847 					cl = cl->next;
1848 					continue;
1849 				}
1850 				gboolean dovideortcp = (vrtcpport != NULL && vrtcpport->value != NULL);
1851 				if(dovideo && vport2 != NULL && vport2->value != NULL &&
1852 						(janus_string_to_uint16(vport2->value, &video_port2) < 0)) {
1853 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid simulcast port...\n", cat->name);
1854 					cl = cl->next;
1855 					continue;
1856 				}
1857 				if(dovideo && vport3 != NULL && vport3->value != NULL &&
1858 						(janus_string_to_uint16(vport3->value, &video_port3) < 0)) {
1859 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid simulcast port...\n", cat->name);
1860 					cl = cl->next;
1861 					continue;
1862 				}
1863 				if(dovideo && viface) {
1864 					if(!ifas) {
1865 						JANUS_LOG(LOG_ERR, "Skipping 'rtp' mountpoint '%s', it relies on network configuration but network device information is unavailable...\n", cat->name);
1866 						cl = cl->next;
1867 						continue;
1868 					}
1869 					if(janus_network_lookup_interface(ifas, viface->value, &video_iface) != 0) {
1870 						JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid network interface configuration for video...\n", cat->name);
1871 						cl = cl->next;
1872 						continue;
1873 					}
1874 				}
1875 				uint16_t data_port = 0;
1876 				if(dodata && (dport == NULL || dport->value == NULL ||
1877 						janus_string_to_uint16(dport->value, &data_port) < 0 || data_port == 0)) {
1878 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', missing mandatory information for data...\n", cat->name);
1879 					cl = cl->next;
1880 					continue;
1881 				}
1882 #ifndef HAVE_SCTP
1883 				if(dodata) {
1884 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s': no datachannels support......\n", cat->name);
1885 					cl = cl->next;
1886 					continue;
1887 				}
1888 #endif
1889 				if(dodata && diface) {
1890 					if(!ifas) {
1891 						JANUS_LOG(LOG_ERR, "Skipping 'rtp' mountpoint '%s', it relies on network configuration but network device information is unavailable...\n", cat->name);
1892 						cl = cl->next;
1893 						continue;
1894 					}
1895 					if(janus_network_lookup_interface(ifas, diface->value, &data_iface) != 0) {
1896 						JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid network interface configuration for data...\n", cat->name);
1897 						cl = cl->next;
1898 						continue;
1899 					}
1900 				}
1901 				if(ssuite && ssuite->value && atoi(ssuite->value) != 32 && atoi(ssuite->value) != 80) {
1902 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid SRTP suite...\n", cat->name);
1903 					cl = cl->next;
1904 					continue;
1905 				}
1906 				if(rtpcollision && rtpcollision->value && atoi(rtpcollision->value) < 0) {
1907 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid collision configuration...\n", cat->name);
1908 					cl = cl->next;
1909 					continue;
1910 				}
1911 				if(threads && threads->value && atoi(threads->value) < 0) {
1912 					JANUS_LOG(LOG_ERR, "Can't add 'rtp' mountpoint '%s', invalid threads configuration...\n", cat->name);
1913 					cl = cl->next;
1914 					continue;
1915 				}
1916 				JANUS_LOG(LOG_VERB, "Audio %s, Video %s, Data %s\n",
1917 					doaudio ? "enabled" : "NOT enabled",
1918 					dovideo ? "enabled" : "NOT enabled",
1919 					dodata ? "enabled" : "NOT enabled");
1920 				janus_streaming_mountpoint *mp = NULL;
1921 				if((mp = janus_streaming_create_rtp_source(
1922 						mpid, (char *)(id ? id->value : NULL),
1923 						(char *)cat->name,
1924 						desc ? (char *)desc->value : NULL,
1925 						md ? (char *)md->value : NULL,
1926 						ssuite && ssuite->value ? atoi(ssuite->value) : 0,
1927 						scrypto && scrypto->value ? (char *)scrypto->value : NULL,
1928 						(threads && threads->value) ? atoi(threads->value) : 0,
1929 						(e2ee && e2ee->value) ? janus_is_true(e2ee->value) : FALSE,
1930 						doaudio, doaudiortcp,
1931 						amcast ? (char *)amcast->value : NULL,
1932 						doaudio && aiface && aiface->value ? &audio_iface : NULL,
1933 						(aport && aport->value) ? audio_port : 0,
1934 						(artcpport && artcpport->value) ? audio_rtcp_port : 0,
1935 						(acodec && acodec->value) ? atoi(acodec->value) : 0,
1936 						artpmap ? (char *)artpmap->value : NULL,
1937 						afmtp ? (char *)afmtp->value : NULL,
1938 						doaskew,
1939 						dovideo, dovideortcp,
1940 						vmcast ? (char *)vmcast->value : NULL,
1941 						dovideo && viface && viface->value ? &video_iface : NULL,
1942 						(vport && vport->value) ? video_port : 0,
1943 						(vrtcpport && vrtcpport->value) ? video_rtcp_port : 0,
1944 						(vcodec && vcodec->value) ? atoi(vcodec->value) : 0,
1945 						vrtpmap ? (char *)vrtpmap->value : NULL,
1946 						vfmtp ? (char *)vfmtp->value : NULL,
1947 						bufferkf,
1948 						simulcast,
1949 						(vport2 && vport2->value) ? video_port2 : 0,
1950 						(vport3 && vport3->value) ? video_port3 : 0,
1951 						dosvc,
1952 						dovskew,
1953 						(rtpcollision && rtpcollision->value) ?  atoi(rtpcollision->value) : 0,
1954 						dodata,
1955 						dodata && diface && diface->value ? &data_iface : NULL,
1956 						(dport && dport->value) ? data_port : 0,
1957 						textdata, buffermsg)) == NULL) {
1958 					JANUS_LOG(LOG_ERR, "Error creating 'rtp' mountpoint '%s'...\n", cat->name);
1959 					cl = cl->next;
1960 					continue;
1961 				}
1962 				mp->is_private = is_private;
1963 				if(secret && secret->value)
1964 					mp->secret = g_strdup(secret->value);
1965 				if(pin && pin->value)
1966 					mp->pin = g_strdup(pin->value);
1967 			} else if(!strcasecmp(type->value, "live")) {
1968 				/* File-based live source */
1969 				janus_config_item *desc = janus_config_get(config, cat, janus_config_type_item, "description");
1970 				janus_config_item *md = janus_config_get(config, cat, janus_config_type_item, "metadata");
1971 				janus_config_item *priv = janus_config_get(config, cat, janus_config_type_item, "is_private");
1972 				janus_config_item *secret = janus_config_get(config, cat, janus_config_type_item, "secret");
1973 				janus_config_item *pin = janus_config_get(config, cat, janus_config_type_item, "pin");
1974 				janus_config_item *file = janus_config_get(config, cat, janus_config_type_item, "filename");
1975 				janus_config_item *audio = janus_config_get(config, cat, janus_config_type_item, "audio");
1976 				janus_config_item *acodec = janus_config_get(config, cat, janus_config_type_item, "audiopt");
1977 				janus_config_item *artpmap = janus_config_get(config, cat, janus_config_type_item, "audiortpmap");
1978 				janus_config_item *afmtp = janus_config_get(config, cat, janus_config_type_item, "audiofmtp");
1979 				janus_config_item *video = janus_config_get(config, cat, janus_config_type_item, "video");
1980 				if(file == NULL || file->value == NULL) {
1981 					JANUS_LOG(LOG_ERR, "Can't add 'live' mountpoint '%s', missing mandatory information...\n", cat->name);
1982 					cl = cl->next;
1983 					continue;
1984 				}
1985 				gboolean is_private = priv && priv->value && janus_is_true(priv->value);
1986 				gboolean doaudio = audio && audio->value && janus_is_true(audio->value);
1987 				gboolean dovideo = video && video->value && janus_is_true(video->value);
1988 				/* We only support audio for file-based streaming at the moment: for streaming
1989 				 * files using other codecs/formats an external tools should feed us RTP instead */
1990 				if(!doaudio || dovideo) {
1991 					JANUS_LOG(LOG_ERR, "Can't add 'live' mountpoint '%s', we only support audio file streaming right now...\n", cat->name);
1992 					cl = cl->next;
1993 					continue;
1994 				}
1995 #ifdef HAVE_LIBOGG
1996 				if(!strstr(file->value, ".opus") && !strstr(file->value, ".alaw") && !strstr(file->value, ".mulaw")) {
1997 					JANUS_LOG(LOG_ERR, "Can't add 'live' mountpoint '%s', unsupported format (we only support Opus and raw mu-Law/a-Law files right now)\n", cat->name);
1998 #else
1999 				if(!strstr(file->value, ".alaw") && !strstr(file->value, ".mulaw")) {
2000 					JANUS_LOG(LOG_ERR, "Can't add 'live' mountpoint '%s', unsupported format (we only support raw mu-Law and a-Law files right now)\n", cat->name);
2001 #endif
2002 					cl = cl->next;
2003 					continue;
2004 				}
2005 				FILE *audiofile = fopen(file->value, "rb");
2006 				if(!audiofile) {
2007 					JANUS_LOG(LOG_ERR, "Can't add 'live' mountpoint, no such file '%s'...\n", file->value);
2008 					cl = cl->next;
2009 					continue;
2010 				}
2011 				fclose(audiofile);
2012 
2013 				janus_streaming_mountpoint *mp = NULL;
2014 				if((mp = janus_streaming_create_file_source(
2015 						mpid, (char *)(id ? id->value : NULL),
2016 						(char *)cat->name,
2017 						desc ? (char *)desc->value : NULL,
2018 						md ? (char *)md->value : NULL,
2019 						(char *)file->value, TRUE,
2020 						doaudio,
2021 						(acodec && acodec->value) ? atoi(acodec->value) : 0,
2022 						artpmap ? (char *)artpmap->value : NULL,
2023 						afmtp ? (char *)afmtp->value : NULL,
2024 						dovideo)) == NULL) {
2025 					JANUS_LOG(LOG_ERR, "Error creating 'live' mountpoint '%s'...\n", cat->name);
2026 					cl = cl->next;
2027 					continue;
2028 				}
2029 				mp->is_private = is_private;
2030 				if(secret && secret->value)
2031 					mp->secret = g_strdup(secret->value);
2032 				if(pin && pin->value)
2033 					mp->pin = g_strdup(pin->value);
2034 			} else if(!strcasecmp(type->value, "ondemand")) {
2035 				/* File-based on demand source */
2036 				janus_config_item *desc = janus_config_get(config, cat, janus_config_type_item, "description");
2037 				janus_config_item *md = janus_config_get(config, cat, janus_config_type_item, "metadata");
2038 				janus_config_item *priv = janus_config_get(config, cat, janus_config_type_item, "is_private");
2039 				janus_config_item *secret = janus_config_get(config, cat, janus_config_type_item, "secret");
2040 				janus_config_item *pin = janus_config_get(config, cat, janus_config_type_item, "pin");
2041 				janus_config_item *file = janus_config_get(config, cat, janus_config_type_item, "filename");
2042 				janus_config_item *audio = janus_config_get(config, cat, janus_config_type_item, "audio");
2043 				janus_config_item *acodec = janus_config_get(config, cat, janus_config_type_item, "audiopt");
2044 				janus_config_item *artpmap = janus_config_get(config, cat, janus_config_type_item, "audiortpmap");
2045 				janus_config_item *afmtp = janus_config_get(config, cat, janus_config_type_item, "audiofmtp");
2046 				janus_config_item *video = janus_config_get(config, cat, janus_config_type_item, "video");
2047 				if(file == NULL || file->value == NULL) {
2048 					JANUS_LOG(LOG_ERR, "Can't add 'ondemand' mountpoint '%s', missing mandatory information...\n", cat->name);
2049 					cl = cl->next;
2050 					continue;
2051 				}
2052 				gboolean is_private = priv && priv->value && janus_is_true(priv->value);
2053 				gboolean doaudio = audio && audio->value && janus_is_true(audio->value);
2054 				gboolean dovideo = video && video->value && janus_is_true(video->value);
2055 				/* We only support audio for file-based streaming at the moment: for streaming
2056 				 * files using other codecs/formats an external tools should feed us RTP instead */
2057 				if(!doaudio || dovideo) {
2058 					JANUS_LOG(LOG_ERR, "Can't add 'ondemand' mountpoint '%s', we only support audio file streaming right now...\n", cat->name);
2059 					cl = cl->next;
2060 					continue;
2061 				}
2062 #ifdef HAVE_LIBOGG
2063 				if(!strstr(file->value, ".opus") && !strstr(file->value, ".alaw") && !strstr(file->value, ".mulaw")) {
2064 					JANUS_LOG(LOG_ERR, "Can't add 'live' mountpoint '%s', unsupported format (we only support Opus and raw mu-Law/a-Law files right now)\n", cat->name);
2065 #else
2066 				if(!strstr(file->value, ".alaw") && !strstr(file->value, ".mulaw")) {
2067 					JANUS_LOG(LOG_ERR, "Can't add 'ondemand' mountpoint '%s', unsupported format (we only support raw mu-Law and a-Law files right now)\n", cat->name);
2068 #endif
2069 					cl = cl->next;
2070 					continue;
2071 				}
2072 				FILE *audiofile = fopen(file->value, "rb");
2073 				if(!audiofile) {
2074 					JANUS_LOG(LOG_ERR, "Can't add 'ondemand' mountpoint, no such file '%s'...\n", file->value);
2075 					cl = cl->next;
2076 					continue;
2077 				}
2078 				fclose(audiofile);
2079 
2080 				janus_streaming_mountpoint *mp = NULL;
2081 				if((mp = janus_streaming_create_file_source(
2082 						mpid, (char *)(id ? id->value : NULL),
2083 						(char *)cat->name,
2084 						desc ? (char *)desc->value : NULL,
2085 						md ? (char *)md->value : NULL,
2086 						(char *)file->value, FALSE,
2087 						doaudio,
2088 						(acodec && acodec->value) ? atoi(acodec->value) : 0,
2089 						artpmap ? (char *)artpmap->value : NULL,
2090 						afmtp ? (char *)afmtp->value : NULL,
2091 						dovideo)) == NULL) {
2092 					JANUS_LOG(LOG_ERR, "Error creating 'ondemand' mountpoint '%s'...\n", cat->name);
2093 					cl = cl->next;
2094 					continue;
2095 				}
2096 				mp->is_private = is_private;
2097 				if(secret && secret->value)
2098 					mp->secret = g_strdup(secret->value);
2099 				if(pin && pin->value)
2100 					mp->pin = g_strdup(pin->value);
2101 			} else if(!strcasecmp(type->value, "rtsp")) {
2102 #ifndef HAVE_LIBCURL
2103 				JANUS_LOG(LOG_ERR, "Can't add 'rtsp' mountpoint '%s', libcurl support not compiled...\n", cat->name);
2104 				cl = cl->next;
2105 				continue;
2106 #else
2107 				janus_config_item *desc = janus_config_get(config, cat, janus_config_type_item, "description");
2108 				janus_config_item *md = janus_config_get(config, cat, janus_config_type_item, "metadata");
2109 				janus_config_item *priv = janus_config_get(config, cat, janus_config_type_item, "is_private");
2110 				janus_config_item *secret = janus_config_get(config, cat, janus_config_type_item, "secret");
2111 				janus_config_item *pin = janus_config_get(config, cat, janus_config_type_item, "pin");
2112 				janus_config_item *file = janus_config_get(config, cat, janus_config_type_item, "url");
2113 				janus_config_item *username = janus_config_get(config, cat, janus_config_type_item, "rtsp_user");
2114 				janus_config_item *password = janus_config_get(config, cat, janus_config_type_item, "rtsp_pwd");
2115 				janus_config_item *audio = janus_config_get(config, cat, janus_config_type_item, "audio");
2116 				janus_config_item *artpmap = janus_config_get(config, cat, janus_config_type_item, "audiortpmap");
2117 				janus_config_item *acodec = janus_config_get(config, cat, janus_config_type_item, "audiopt");
2118 				janus_config_item *afmtp = janus_config_get(config, cat, janus_config_type_item, "audiofmtp");
2119 				janus_config_item *video = janus_config_get(config, cat, janus_config_type_item, "video");
2120 				janus_config_item *vcodec = janus_config_get(config, cat, janus_config_type_item, "videopt");
2121 				janus_config_item *vrtpmap = janus_config_get(config, cat, janus_config_type_item, "videortpmap");
2122 				janus_config_item *vfmtp = janus_config_get(config, cat, janus_config_type_item, "videofmtp");
2123 				janus_config_item *vkf = janus_config_get(config, cat, janus_config_type_item, "videobufferkf");
2124 				janus_config_item *iface = janus_config_get(config, cat, janus_config_type_item, "rtspiface");
2125 				janus_config_item *failerr = janus_config_get(config, cat, janus_config_type_item, "rtsp_failcheck");
2126 				janus_config_item *threads = janus_config_get(config, cat, janus_config_type_item, "threads");
2127 				janus_config_item *reconnect_delay = janus_config_get(config, cat, janus_config_type_item, "rtsp_reconnect_delay");
2128 				janus_config_item *session_timeout = janus_config_get(config, cat, janus_config_type_item, "rtsp_session_timeout");
2129 				janus_config_item *rtsp_timeout = janus_config_get(config, cat, janus_config_type_item, "rtsp_timeout");
2130 				janus_config_item *rtsp_conn_timeout = janus_config_get(config, cat, janus_config_type_item, "rtsp_conn_timeout");
2131 				janus_network_address iface_value;
2132 				if(file == NULL || file->value == NULL) {
2133 					JANUS_LOG(LOG_ERR, "Can't add 'rtsp' mountpoint '%s', missing mandatory information...\n", cat->name);
2134 					cl = cl->next;
2135 					continue;
2136 				}
2137 				gboolean is_private = priv && priv->value && janus_is_true(priv->value);
2138 				gboolean doaudio = audio && audio->value && janus_is_true(audio->value);
2139 				gboolean dovideo = video && video->value && janus_is_true(video->value);
2140 				gboolean bufferkf = video && vkf && vkf->value && janus_is_true(vkf->value);
2141 				gboolean error_on_failure = TRUE;
2142 				if(failerr && failerr->value)
2143 					error_on_failure = janus_is_true(failerr->value);
2144 				if(threads && threads->value && atoi(threads->value) < 0) {
2145 					JANUS_LOG(LOG_ERR, "Can't add 'rtsp' mountpoint '%s', invalid threads configuration...\n", cat->name);
2146 					cl = cl->next;
2147 					continue;
2148 				}
2149 
2150 				if((doaudio || dovideo) && iface && iface->value) {
2151 					if(!ifas) {
2152 						JANUS_LOG(LOG_ERR, "Skipping 'rtsp' mountpoint '%s', it relies on network configuration but network device information is unavailable...\n", cat->name);
2153 						cl = cl->next;
2154 						continue;
2155 					}
2156 					if(janus_network_lookup_interface(ifas, iface->value, &iface_value) != 0) {
2157 						JANUS_LOG(LOG_ERR, "Can't add 'rtsp' mountpoint '%s', invalid network interface configuration for stream...\n", cat->name);
2158 						cl = cl->next;
2159 						continue;
2160 					}
2161 				}
2162 
2163 				janus_streaming_mountpoint *mp = NULL;
2164 				if((mp = janus_streaming_create_rtsp_source(
2165 						mpid, (char *)(id ? id->value : NULL),
2166 						(char *)cat->name,
2167 						desc ? (char *)desc->value : NULL,
2168 						md ? (char *)md->value : NULL,
2169 						(char *)file->value,
2170 						username ? (char *)username->value : NULL,
2171 						password ? (char *)password->value : NULL,
2172 						doaudio,
2173 						(acodec && acodec->value) ? atoi(acodec->value) : -1,
2174 						artpmap ? (char *)artpmap->value : NULL,
2175 						afmtp ? (char *)afmtp->value : NULL,
2176 						dovideo,
2177 						(vcodec && vcodec->value) ? atoi(vcodec->value) : -1,
2178 						vrtpmap ? (char *)vrtpmap->value : NULL,
2179 						vfmtp ? (char *)vfmtp->value : NULL,
2180 						bufferkf,
2181 						iface && iface->value ? &iface_value : NULL,
2182 						(threads && threads->value) ? atoi(threads->value) : 0,
2183 						((reconnect_delay && reconnect_delay->value) ? atoi(reconnect_delay->value) : JANUS_STREAMING_DEFAULT_RECONNECT_DELAY) * G_USEC_PER_SEC,
2184 						((session_timeout && session_timeout->value) ? atoi(session_timeout->value) : JANUS_STREAMING_DEFAULT_SESSION_TIMEOUT) * G_USEC_PER_SEC,
2185 						((rtsp_timeout && rtsp_timeout->value) ? atoi(rtsp_timeout->value) : JANUS_STREAMING_DEFAULT_CURL_TIMEOUT),
2186 						((rtsp_conn_timeout && rtsp_conn_timeout->value) ? atoi(rtsp_conn_timeout->value) : JANUS_STREAMING_DEFAULT_CURL_CONNECT_TIMEOUT),
2187 						error_on_failure)) == NULL) {
2188 					JANUS_LOG(LOG_ERR, "Error creating 'rtsp' mountpoint '%s'...\n", cat->name);
2189 					cl = cl->next;
2190 					continue;
2191 				}
2192 				mp->is_private = is_private;
2193 				if(secret && secret->value)
2194 					mp->secret = g_strdup(secret->value);
2195 				if(pin && pin->value)
2196 					mp->pin = g_strdup(pin->value);
2197 #endif
2198 			} else {
2199 				JANUS_LOG(LOG_WARN, "Ignoring unknown mountpoint type '%s' (%s)...\n", type->value, cat->name);
2200 			}
2201 			cl = cl->next;
2202 		}
2203 		g_list_free(clist);
2204 		/* Done: we keep the configuration file open in case we get a "create" or "destroy" with permanent=true */
2205 	}
2206 	if(ifas) {
2207 		freeifaddrs(ifas);
2208 	}
2209 
2210 	/* Show available mountpoints */
2211 	janus_mutex_lock(&mountpoints_mutex);
2212 	GHashTableIter iter;
2213 	gpointer value;
2214 	g_hash_table_iter_init(&iter, mountpoints);
2215 	while(g_hash_table_iter_next(&iter, NULL, &value)) {
2216 		janus_streaming_mountpoint *mp = value;
2217 		JANUS_LOG(LOG_VERB, "  ::: [%s][%s] %s (%s, %s, %s, pin: %s)\n", mp->id_str, mp->name, mp->description,
2218 			mp->streaming_type == janus_streaming_type_live ? "live" : "on demand",
2219 			mp->streaming_source == janus_streaming_source_rtp ? "RTP source" : "file source",
2220 			mp->is_private ? "private" : "public",
2221 			mp->pin ? mp->pin : "no pin");
2222 	}
2223 	janus_mutex_unlock(&mountpoints_mutex);
2224 
2225 	sessions = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)janus_streaming_session_destroy);
2226 	messages = g_async_queue_new_full((GDestroyNotify) janus_streaming_message_free);
2227 	/* This is the callback we'll need to invoke to contact the Janus core */
2228 	gateway = callback;
2229 
2230 	/* Launch the thread that will handle incoming messages */
2231 	GError *error = NULL;
2232 	handler_thread = g_thread_try_new("streaming handler", janus_streaming_handler, NULL, &error);
2233 	if(error != NULL) {
2234 		g_atomic_int_set(&initialized, 0);
2235 		JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the Streaming handler thread...\n",
2236 			error->code, error->message ? error->message : "??");
2237 		g_error_free(error);
2238 		janus_config_destroy(config);
2239 		return -1;
2240 	}
2241 	JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_STREAMING_NAME);
2242 	return 0;
2243 }
2244 
2245 void janus_streaming_destroy(void) {
2246 	if(!g_atomic_int_get(&initialized))
2247 		return;
2248 	g_atomic_int_set(&stopping, 1);
2249 
2250 	g_async_queue_push(messages, &exit_message);
2251 	if(handler_thread != NULL) {
2252 		g_thread_join(handler_thread);
2253 		handler_thread = NULL;
2254 	}
2255 
2256 	/* Remove all mountpoints */
2257 	janus_mutex_lock(&mountpoints_mutex);
2258 	g_hash_table_destroy(mountpoints);
2259 	mountpoints = NULL;
2260 	g_hash_table_destroy(mountpoints_temp);
2261 	mountpoints_temp = NULL;
2262 	janus_mutex_unlock(&mountpoints_mutex);
2263 	janus_mutex_lock(&sessions_mutex);
2264 	g_hash_table_destroy(sessions);
2265 	sessions = NULL;
2266 	janus_mutex_unlock(&sessions_mutex);
2267 	g_async_queue_unref(messages);
2268 	messages = NULL;
2269 
2270 	janus_config_destroy(config);
2271 	g_free(admin_key);
2272 
2273 	g_atomic_int_set(&initialized, 0);
2274 	g_atomic_int_set(&stopping, 0);
2275 	JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_STREAMING_NAME);
2276 }
2277 
2278 int janus_streaming_get_api_compatibility(void) {
2279 	/* Important! This is what your plugin MUST always return: don't lie here or bad things will happen */
2280 	return JANUS_PLUGIN_API_VERSION;
2281 }
2282 
2283 int janus_streaming_get_version(void) {
2284 	return JANUS_STREAMING_VERSION;
2285 }
2286 
2287 const char *janus_streaming_get_version_string(void) {
2288 	return JANUS_STREAMING_VERSION_STRING;
2289 }
2290 
2291 const char *janus_streaming_get_description(void) {
2292 	return JANUS_STREAMING_DESCRIPTION;
2293 }
2294 
2295 const char *janus_streaming_get_name(void) {
2296 	return JANUS_STREAMING_NAME;
2297 }
2298 
2299 const char *janus_streaming_get_author(void) {
2300 	return JANUS_STREAMING_AUTHOR;
2301 }
2302 
2303 const char *janus_streaming_get_package(void) {
2304 	return JANUS_STREAMING_PACKAGE;
2305 }
2306 
2307 static janus_streaming_session *janus_streaming_lookup_session(janus_plugin_session *handle) {
2308 	janus_streaming_session *session = NULL;
2309 	if(g_hash_table_contains(sessions, handle)) {
2310 		session = (janus_streaming_session *)handle->plugin_handle;
2311 	}
2312 	return session;
2313 }
2314 
2315 void janus_streaming_create_session(janus_plugin_session *handle, int *error) {
2316 	if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
2317 		*error = -1;
2318 		return;
2319 	}
2320 	janus_streaming_session *session = g_malloc0(sizeof(janus_streaming_session));
2321 	session->handle = handle;
2322 	session->mountpoint = NULL;	/* This will happen later */
2323 	janus_mutex_init(&session->mutex);
2324 	g_atomic_int_set(&session->started, 0);
2325 	g_atomic_int_set(&session->paused, 0);
2326 	g_atomic_int_set(&session->destroyed, 0);
2327 	g_atomic_int_set(&session->hangingup, 0);
2328 	session->audio_pt = -1;
2329 	session->video_pt = -1;
2330 	handle->plugin_handle = session;
2331 	janus_refcount_init(&session->ref, janus_streaming_session_free);
2332 	janus_mutex_lock(&sessions_mutex);
2333 	g_hash_table_insert(sessions, handle, session);
2334 	janus_mutex_unlock(&sessions_mutex);
2335 
2336 	return;
2337 }
2338 
2339 void janus_streaming_destroy_session(janus_plugin_session *handle, int *error) {
2340 	if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
2341 		*error = -1;
2342 		return;
2343 	}
2344 	janus_mutex_lock(&sessions_mutex);
2345 	janus_streaming_session *session = janus_streaming_lookup_session(handle);
2346 	if(!session) {
2347 		janus_mutex_unlock(&sessions_mutex);
2348 		JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
2349 		*error = -2;
2350 		return;
2351 	}
2352 	JANUS_LOG(LOG_VERB, "Removing streaming session...\n");
2353 	janus_streaming_hangup_media_internal(handle);
2354 	g_hash_table_remove(sessions, handle);
2355 	janus_mutex_unlock(&sessions_mutex);
2356 	return;
2357 }
2358 
2359 json_t *janus_streaming_query_session(janus_plugin_session *handle) {
2360 	if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
2361 		return NULL;
2362 	}
2363 	janus_mutex_lock(&sessions_mutex);
2364 	janus_streaming_session *session = janus_streaming_lookup_session(handle);
2365 	if(!session) {
2366 		janus_mutex_unlock(&sessions_mutex);
2367 		JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
2368 		return NULL;
2369 	}
2370 	janus_refcount_increase(&session->ref);
2371 	janus_mutex_unlock(&sessions_mutex);
2372 	/* What is this user watching, if anything? */
2373 	json_t *info = json_object();
2374 	janus_streaming_mountpoint *mp = session->mountpoint;
2375 	json_object_set_new(info, "state", json_string(mp ? "watching" : "idle"));
2376 	if(mp) {
2377 		janus_refcount_increase(&mp->ref);
2378 		json_object_set_new(info, "mountpoint_id", string_ids ? json_string(mp->id_str) : json_integer(mp->id));
2379 		json_object_set_new(info, "mountpoint_name", mp->name ? json_string(mp->name) : NULL);
2380 		janus_mutex_lock(&mp->mutex);
2381 		json_object_set_new(info, "mountpoint_viewers", json_integer(mp->viewers ? g_list_length(mp->viewers) : 0));
2382 		janus_mutex_unlock(&mp->mutex);
2383 		json_t *media = json_object();
2384 		json_object_set_new(media, "audio", session->audio ? json_true() : json_false());
2385 		json_object_set_new(media, "video", session->video ? json_true() : json_false());
2386 		json_object_set_new(media, "data", session->data ? json_true() : json_false());
2387 		json_object_set_new(info, "media", media);
2388 		if(mp->streaming_source == janus_streaming_source_rtp) {
2389 			janus_streaming_rtp_source *source = mp->source;
2390 			if(source->simulcast) {
2391 				json_t *simulcast = json_object();
2392 				json_object_set_new(simulcast, "substream", json_integer(session->sim_context.substream));
2393 				json_object_set_new(simulcast, "substream-target", json_integer(session->sim_context.substream_target));
2394 				json_object_set_new(simulcast, "temporal-layer", json_integer(session->sim_context.templayer));
2395 				json_object_set_new(simulcast, "temporal-layer-target", json_integer(session->sim_context.templayer_target));
2396 				if(session->sim_context.drop_trigger > 0)
2397 					json_object_set_new(simulcast, "fallback", json_integer(session->sim_context.drop_trigger));
2398 				json_object_set_new(info, "simulcast", simulcast);
2399 			}
2400 			if(source->svc) {
2401 				json_t *svc = json_object();
2402 				json_object_set_new(svc, "spatial-layer", json_integer(session->spatial_layer));
2403 				json_object_set_new(svc, "target-spatial-layer", json_integer(session->target_spatial_layer));
2404 				json_object_set_new(svc, "temporal-layer", json_integer(session->temporal_layer));
2405 				json_object_set_new(svc, "target-temporal-layer", json_integer(session->target_temporal_layer));
2406 				json_object_set_new(info, "svc", svc);
2407 			}
2408 		}
2409 		janus_refcount_decrease(&mp->ref);
2410 	}
2411 	if(session->e2ee)
2412 		json_object_set_new(info, "e2ee", json_true());
2413 	json_object_set_new(info, "hangingup", json_integer(g_atomic_int_get(&session->hangingup)));
2414 	json_object_set_new(info, "started", json_integer(g_atomic_int_get(&session->started)));
2415 	json_object_set_new(info, "dataready", json_integer(g_atomic_int_get(&session->dataready)));
2416 	json_object_set_new(info, "paused", json_integer(g_atomic_int_get(&session->paused)));
2417 	json_object_set_new(info, "stopping", json_integer(g_atomic_int_get(&session->stopping)));
2418 	json_object_set_new(info, "destroyed", json_integer(g_atomic_int_get(&session->destroyed)));
2419 	janus_refcount_decrease(&session->ref);
2420 	return info;
2421 }
2422 
2423 /* Helper method to process synchronous requests */
2424 static json_t *janus_streaming_process_synchronous_request(janus_streaming_session *session, json_t *message) {
2425 	json_t *request = json_object_get(message, "request");
2426 	const char *request_text = json_string_value(request);
2427 
2428 	/* Parse the message */
2429 	int error_code = 0;
2430 	char error_cause[512];
2431 	json_t *root = message;
2432 	json_t *response = NULL;
2433 	struct ifaddrs *ifas = NULL;
2434 
2435 	if(!strcasecmp(request_text, "list")) {
2436 		JANUS_LOG(LOG_VERB, "Request for the list of mountpoints\n");
2437 		gboolean lock_mp_list = TRUE;
2438 		if(admin_key != NULL) {
2439 			json_t *admin_key_json = json_object_get(root, "admin_key");
2440 			/* Verify admin_key if it was provided */
2441 			if(admin_key_json != NULL && json_is_string(admin_key_json) && strlen(json_string_value(admin_key_json)) > 0) {
2442 				JANUS_CHECK_SECRET(admin_key, root, "admin_key", error_code, error_cause,
2443 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT, JANUS_STREAMING_ERROR_UNAUTHORIZED);
2444 				if(error_code != 0) {
2445 					goto prepare_response;
2446 				} else {
2447 					lock_mp_list = FALSE;
2448 				}
2449 			}
2450 		}
2451 		json_t *list = json_array();
2452 		/* Return a list of all available mountpoints */
2453 		janus_mutex_lock(&mountpoints_mutex);
2454 		GHashTableIter iter;
2455 		gpointer value;
2456 		g_hash_table_iter_init(&iter, mountpoints);
2457 		while(g_hash_table_iter_next(&iter, NULL, &value)) {
2458 			janus_streaming_mountpoint *mp = value;
2459 			if(mp->is_private && lock_mp_list) {
2460 				/* Skip private stream if no valid admin_key was provided */
2461 				JANUS_LOG(LOG_VERB, "Skipping private mountpoint '%s'\n", mp->description);
2462 				continue;
2463 			}
2464 			janus_refcount_increase(&mp->ref);
2465 			json_t *ml = json_object();
2466 			json_object_set_new(ml, "id", string_ids ? json_string(mp->id_str) : json_integer(mp->id));
2467 			json_object_set_new(ml, "type", json_string(mp->streaming_type == janus_streaming_type_live ? "live" : "on demand"));
2468 			json_object_set_new(ml, "description", json_string(mp->description));
2469 			if(mp->metadata) {
2470 				json_object_set_new(ml, "metadata", json_string(mp->metadata));
2471 			}
2472 			json_object_set_new(ml, "enabled", mp->enabled ? json_true() : json_false());
2473 			if(mp->streaming_source == janus_streaming_source_rtp) {
2474 				janus_streaming_rtp_source *source = mp->source;
2475 				gint64 now = janus_get_monotonic_time();
2476 				if(source->audio_fd != -1)
2477 					json_object_set_new(ml, "audio_age_ms", json_integer((now - source->last_received_audio) / 1000));
2478 				if(source->video_fd[0] != -1 || source->video_fd[1] != -1 || source->video_fd[2] != -1)
2479 					json_object_set_new(ml, "video_age_ms", json_integer((now - source->last_received_video) / 1000));
2480 			}
2481 			json_array_append_new(list, ml);
2482 			janus_refcount_decrease(&mp->ref);
2483 		}
2484 		janus_mutex_unlock(&mountpoints_mutex);
2485 		/* Send info back */
2486 		response = json_object();
2487 		json_object_set_new(response, "streaming", json_string("list"));
2488 		json_object_set_new(response, "list", list);
2489 		goto prepare_response;
2490 	} else if(!strcasecmp(request_text, "info")) {
2491 		JANUS_LOG(LOG_VERB, "Request info on a specific mountpoint\n");
2492 		/* Return info on a specific mountpoint */
2493 		if(!string_ids) {
2494 			JANUS_VALIDATE_JSON_OBJECT(root, id_parameters,
2495 				error_code, error_cause, TRUE,
2496 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2497 		} else {
2498 			JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters,
2499 				error_code, error_cause, TRUE,
2500 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2501 		}
2502 		if(error_code != 0)
2503 			goto prepare_response;
2504 		json_t *id = json_object_get(root, "id");
2505 		guint64 id_value = 0;
2506 		char id_num[30], *id_value_str = NULL;
2507 		if(!string_ids) {
2508 			id_value = json_integer_value(id);
2509 			g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id_value);
2510 			id_value_str = id_num;
2511 		} else {
2512 			id_value_str = (char *)json_string_value(id);
2513 		}
2514 		janus_mutex_lock(&mountpoints_mutex);
2515 		janus_streaming_mountpoint *mp = g_hash_table_lookup(mountpoints,
2516 			string_ids ? (gpointer)id_value_str : (gpointer)&id_value);
2517 		if(mp == NULL) {
2518 			janus_mutex_unlock(&mountpoints_mutex);
2519 			JANUS_LOG(LOG_VERB, "No such mountpoint/stream %s\n", id_value_str);
2520 			error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
2521 			g_snprintf(error_cause, 512, "No such mountpoint/stream %s", id_value_str);
2522 			goto prepare_response;
2523 		}
2524 		janus_refcount_increase(&mp->ref);
2525 		/* Return more info if the right secret is provided */
2526 		gboolean admin = FALSE;
2527 		if(mp->secret) {
2528 			json_t *secret = json_object_get(root, "secret");
2529 			if(secret && json_string_value(secret) && janus_strcmp_const_time(mp->secret, json_string_value(secret)))
2530 				admin = TRUE;
2531 		} else {
2532 			admin = TRUE;
2533 		}
2534 		json_t *ml = json_object();
2535 		json_object_set_new(ml, "id", string_ids ? json_string(mp->id_str) : json_integer(mp->id));
2536 		if(admin && mp->name)
2537 			json_object_set_new(ml, "name", json_string(mp->name));
2538 		if(mp->description)
2539 			json_object_set_new(ml, "description", json_string(mp->description));
2540 		if(mp->metadata)
2541 			json_object_set_new(ml, "metadata", json_string(mp->metadata));
2542 		if(admin && mp->secret)
2543 			json_object_set_new(ml, "secret", json_string(mp->secret));
2544 		if(admin && mp->pin)
2545 			json_object_set_new(ml, "pin", json_string(mp->pin));
2546 		if(admin && mp->is_private)
2547 			json_object_set_new(ml, "is_private", json_true());
2548 		json_object_set_new(ml, "enabled", mp->enabled ? json_true() : json_false());
2549 		if(admin)
2550 			json_object_set_new(ml, "viewers", json_integer(mp->viewers ? g_list_length(mp->viewers) : 0));
2551 		if(mp->audio) {
2552 			json_object_set_new(ml, "audio", json_true());
2553 			if(mp->codecs.audio_pt != -1)
2554 				json_object_set_new(ml, "audiopt", json_integer(mp->codecs.audio_pt));
2555 			if(mp->codecs.audio_rtpmap)
2556 				json_object_set_new(ml, "audiortpmap", json_string(mp->codecs.audio_rtpmap));
2557 			if(mp->codecs.audio_fmtp)
2558 				json_object_set_new(ml, "audiofmtp", json_string(mp->codecs.audio_fmtp));
2559 		}
2560 		if(mp->video) {
2561 			json_object_set_new(ml, "video", json_true());
2562 			if(mp->codecs.video_pt != -1)
2563 				json_object_set_new(ml, "videopt", json_integer(mp->codecs.video_pt));
2564 			if(mp->codecs.video_rtpmap)
2565 				json_object_set_new(ml, "videortpmap", json_string(mp->codecs.video_rtpmap));
2566 			if(mp->codecs.video_fmtp)
2567 				json_object_set_new(ml, "videofmtp", json_string(mp->codecs.video_fmtp));
2568 		}
2569 		if(mp->data) {
2570 			json_object_set_new(ml, "data", json_true());
2571 		}
2572 		json_object_set_new(ml, "type", json_string(mp->streaming_type == janus_streaming_type_live ? "live" : "on demand"));
2573 		if(mp->streaming_source == janus_streaming_source_file) {
2574 			janus_streaming_file_source *source = mp->source;
2575 			if(admin && source->filename)
2576 				json_object_set_new(ml, "filename", json_string(source->filename));
2577 		} else if(mp->streaming_source == janus_streaming_source_rtp) {
2578 			janus_streaming_rtp_source *source = mp->source;
2579 			if(source->is_srtp) {
2580 				json_object_set_new(ml, "srtp", json_true());
2581 			}
2582 			gint64 now = janus_get_monotonic_time();
2583 #ifdef HAVE_LIBCURL
2584 			if(source->rtsp) {
2585 				json_object_set_new(ml, "rtsp", json_true());
2586 				if(admin) {
2587 					if(source->rtsp_url)
2588 						json_object_set_new(ml, "url", json_string(source->rtsp_url));
2589 					if(source->rtsp_username)
2590 						json_object_set_new(ml, "rtsp_user", json_string(source->rtsp_username));
2591 					if(source->rtsp_password)
2592 						json_object_set_new(ml, "rtsp_pwd", json_string(source->rtsp_password));
2593 				}
2594 			}
2595 #endif
2596 			if(source->keyframe.enabled) {
2597 				json_object_set_new(ml, "videobufferkf", json_true());
2598 			}
2599 			if(source->simulcast) {
2600 				json_object_set_new(ml, "videosimulcast", json_true());
2601 			}
2602 			if(source->svc) {
2603 				json_object_set_new(ml, "videosvc", json_true());
2604 			}
2605 			if(source->askew)
2606 				json_object_set_new(ml, "audioskew", json_true());
2607 			if(source->vskew)
2608 				json_object_set_new(ml, "videoskew", json_true());
2609 			if(source->rtp_collision > 0)
2610 				json_object_set_new(ml, "collision", json_integer(source->rtp_collision));
2611 			if(mp->helper_threads > 0)
2612 				json_object_set_new(ml, "threads", json_integer(mp->helper_threads));
2613 			if(admin) {
2614 				if(mp->audio) {
2615 					if(source->audio_host)
2616 						json_object_set_new(ml, "audiohost", json_string(source->audio_host));
2617 					json_object_set_new(ml, "audioport", json_integer(source->audio_port));
2618 					if(source->audio_rtcp_port > -1)
2619 						json_object_set_new(ml, "audiortcpport", json_integer(source->audio_rtcp_port));
2620 				}
2621 				if(mp->video) {
2622 					if(source->video_host)
2623 						json_object_set_new(ml, "videohost", json_string(source->video_host));
2624 					json_object_set_new(ml, "videoport", json_integer(source->video_port[0]));
2625 					if(source->video_rtcp_port > -1)
2626 						json_object_set_new(ml, "videortcpport", json_integer(source->video_rtcp_port));
2627 					if(source->video_port[1] > -1)
2628 						json_object_set_new(ml, "videoport2", json_integer(source->video_port[1]));
2629 					if(source->video_port[2] > -1)
2630 						json_object_set_new(ml, "videoport3", json_integer(source->video_port[2]));
2631 				}
2632 				if(mp->data) {
2633 					if(source->data_host)
2634 						json_object_set_new(ml, "datahost", json_string(source->data_host));
2635 					json_object_set_new(ml, "dataport", json_integer(source->data_port));
2636 				}
2637 			}
2638 			if(source->audio_fd != -1)
2639 				json_object_set_new(ml, "audio_age_ms", json_integer((now - source->last_received_audio) / 1000));
2640 			if(source->video_fd[0] != -1 || source->video_fd[1] != -1 || source->video_fd[2] != -1)
2641 				json_object_set_new(ml, "video_age_ms", json_integer((now - source->last_received_video) / 1000));
2642 			if(source->data_fd != -1)
2643 				json_object_set_new(ml, "data_age_ms", json_integer((now - source->last_received_data) / 1000));
2644 			janus_mutex_lock(&source->rec_mutex);
2645 			if(admin && (source->arc || source->vrc || source->drc)) {
2646 				json_t *recording = json_object();
2647 				if(source->arc && source->arc->filename)
2648 					json_object_set_new(recording, "audio", json_string(source->arc->filename));
2649 				if(source->vrc && source->vrc->filename)
2650 					json_object_set_new(recording, "video", json_string(source->vrc->filename));
2651 				if(source->drc && source->drc->filename)
2652 					json_object_set_new(recording, "data", json_string(source->drc->filename));
2653 				json_object_set_new(ml, "recording", recording);
2654 			}
2655 			janus_mutex_unlock(&source->rec_mutex);
2656 		}
2657 		janus_refcount_decrease(&mp->ref);
2658 		janus_mutex_unlock(&mountpoints_mutex);
2659 		/* Send info back */
2660 		response = json_object();
2661 		json_object_set_new(response, "streaming", json_string("info"));
2662 		json_object_set_new(response, "info", ml);
2663 		goto prepare_response;
2664 	} else if(!strcasecmp(request_text, "create")) {
2665 		/* Create a new stream */
2666 		JANUS_VALIDATE_JSON_OBJECT(root, create_parameters,
2667 			error_code, error_cause, TRUE,
2668 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2669 		if(error_code != 0)
2670 			goto prepare_response;
2671 		if(!string_ids) {
2672 			JANUS_VALIDATE_JSON_OBJECT(root, idopt_parameters,
2673 				error_code, error_cause, TRUE,
2674 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2675 		} else {
2676 			JANUS_VALIDATE_JSON_OBJECT(root, idstropt_parameters,
2677 				error_code, error_cause, TRUE,
2678 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2679 		}
2680 		if(error_code != 0)
2681 			goto prepare_response;
2682 		if(admin_key != NULL) {
2683 			/* An admin key was specified: make sure it was provided, and that it's valid */
2684 			JANUS_VALIDATE_JSON_OBJECT(root, adminkey_parameters,
2685 				error_code, error_cause, TRUE,
2686 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2687 			if(error_code != 0)
2688 				goto prepare_response;
2689 			JANUS_CHECK_SECRET(admin_key, root, "admin_key", error_code, error_cause,
2690 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT, JANUS_STREAMING_ERROR_UNAUTHORIZED);
2691 			if(error_code != 0)
2692 				goto prepare_response;
2693 		}
2694 
2695 		if(getifaddrs(&ifas) == -1) {
2696 			JANUS_LOG(LOG_ERR, "Unable to acquire list of network devices/interfaces; some configurations may not work as expected... %d (%s)\n",
2697 				errno, g_strerror(errno));
2698 		}
2699 
2700 		json_t *type = json_object_get(root, "type");
2701 		const char *type_text = json_string_value(type);
2702 		json_t *secret = json_object_get(root, "secret");
2703 		json_t *pin = json_object_get(root, "pin");
2704 		json_t *permanent = json_object_get(root, "permanent");
2705 		gboolean save = permanent ? json_is_true(permanent) : FALSE;
2706 		if(save && config == NULL) {
2707 			JANUS_LOG(LOG_ERR, "No configuration file, can't create permanent mountpoint\n");
2708 			error_code = JANUS_STREAMING_ERROR_UNKNOWN_ERROR;
2709 			g_snprintf(error_cause, 512, "No configuration file, can't create permanent mountpoint");
2710 			goto prepare_response;
2711 		}
2712 		json_t *id = json_object_get(root, "id");
2713 		/* Check if an ID has been provided, or if we need to generate one ourselves */
2714 		janus_mutex_lock(&mountpoints_mutex);
2715 		guint64 mpid = string_ids ? 0 : json_integer_value(id);
2716 		char *mpid_str = (char *)(string_ids ? json_string_value(id) : NULL);
2717 		if((!string_ids && mpid > 0) || (string_ids && mpid_str != NULL)) {
2718 			/* Make sure the provided ID isn't already in use */
2719 			if(g_hash_table_lookup(mountpoints, string_ids ? (gpointer)mpid_str : (gpointer)&mpid) != NULL ||
2720 					g_hash_table_lookup(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid) != NULL) {
2721 				janus_mutex_unlock(&mountpoints_mutex);
2722 				JANUS_LOG(LOG_ERR, "A stream with the provided ID already exists\n");
2723 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
2724 				g_snprintf(error_cause, 512, "A stream with the provided ID already exists");
2725 				goto prepare_response;
2726 			}
2727 		} else if(!string_ids && mpid == 0) {
2728 			/* Generate a unique numeric ID */
2729 			JANUS_LOG(LOG_VERB, "Missing numeric id, will generate a random one...\n");
2730 			while(mpid == 0) {
2731 				mpid = janus_random_uint64();
2732 				if(g_hash_table_lookup(mountpoints, &mpid) != NULL ||
2733 						g_hash_table_lookup(mountpoints_temp, &mpid) != NULL) {
2734 					/* ID already in use, try another one */
2735 					mpid = 0;
2736 				}
2737 			}
2738 		} else if(string_ids && mpid_str == NULL) {
2739 			/* Generate a unique alphanumeric ID */
2740 			JANUS_LOG(LOG_VERB, "Missing alphanumeric id, will generate a random one...\n");
2741 			while(mpid_str == 0) {
2742 				mpid_str = janus_random_uuid();
2743 				if(g_hash_table_lookup(mountpoints, mpid_str) != NULL ||
2744 						g_hash_table_lookup(mountpoints_temp, mpid_str) != NULL) {
2745 					/* ID already in use, try another one */
2746 					g_free(mpid_str);
2747 					mpid_str = NULL;
2748 				}
2749 			}
2750 		}
2751 		g_hash_table_insert(mountpoints_temp,
2752 			string_ids ? (gpointer)g_strdup(mpid_str) : (gpointer)janus_uint64_dup(mpid),
2753 			GUINT_TO_POINTER(TRUE));
2754 		janus_mutex_unlock(&mountpoints_mutex);
2755 		janus_streaming_mountpoint *mp = NULL;
2756 		if(!strcasecmp(type_text, "rtp")) {
2757 			janus_network_address audio_iface, video_iface, data_iface;
2758 			/* RTP live source (e.g., from gstreamer/ffmpeg/vlc/etc.) */
2759 			JANUS_VALIDATE_JSON_OBJECT(root, rtp_parameters,
2760 				error_code, error_cause, TRUE,
2761 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2762 			if(error_code != 0) {
2763 				janus_mutex_lock(&mountpoints_mutex);
2764 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2765 				janus_mutex_unlock(&mountpoints_mutex);
2766 				goto prepare_response;
2767 			}
2768 			json_t *name = json_object_get(root, "name");
2769 			json_t *desc = json_object_get(root, "description");
2770 			json_t *md = json_object_get(root, "metadata");
2771 			json_t *is_private = json_object_get(root, "is_private");
2772 			json_t *audio = json_object_get(root, "audio");
2773 			json_t *video = json_object_get(root, "video");
2774 			json_t *data = json_object_get(root, "data");
2775 			json_t *rtpcollision = json_object_get(root, "collision");
2776 			json_t *threads = json_object_get(root, "threads");
2777 			json_t *ssuite = json_object_get(root, "srtpsuite");
2778 			json_t *scrypto = json_object_get(root, "srtpcrypto");
2779 			json_t *e2ee = json_object_get(root, "e2ee");
2780 			gboolean doaudio = audio ? json_is_true(audio) : FALSE, doaudiortcp = FALSE;
2781 			gboolean dovideo = video ? json_is_true(video) : FALSE, dovideortcp = FALSE;
2782 			gboolean dodata = data ? json_is_true(data) : FALSE;
2783 			gboolean doaskew = FALSE, dovskew = FALSE, dosvc = FALSE;
2784 			if(!doaudio && !dovideo && !dodata) {
2785 				JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, no audio, video or data have to be streamed...\n");
2786 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
2787 				g_snprintf(error_cause, 512, "Can't add 'rtp' stream, no audio or video have to be streamed...");
2788 				janus_mutex_lock(&mountpoints_mutex);
2789 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2790 				janus_mutex_unlock(&mountpoints_mutex);
2791 				goto prepare_response;
2792 			}
2793 			if(ssuite && json_integer_value(ssuite) != 32 && json_integer_value(ssuite) != 80) {
2794 				JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, invalid SRTP suite...\n");
2795 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
2796 				g_snprintf(error_cause, 512, "Can't add 'rtp' stream, invalid SRTP suite...");
2797 				janus_mutex_lock(&mountpoints_mutex);
2798 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2799 				janus_mutex_unlock(&mountpoints_mutex);
2800 				goto prepare_response;
2801 			}
2802 			uint16_t aport = 0;
2803 			uint16_t artcpport = 0;
2804 			uint8_t acodec = 0;
2805 			char *artpmap = NULL, *afmtp = NULL, *amcast = NULL;
2806 			if(doaudio) {
2807 				JANUS_VALIDATE_JSON_OBJECT(root, rtp_audio_parameters,
2808 					error_code, error_cause, TRUE,
2809 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2810 				if(error_code != 0) {
2811 					janus_mutex_lock(&mountpoints_mutex);
2812 					g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2813 					janus_mutex_unlock(&mountpoints_mutex);
2814 					goto prepare_response;
2815 				}
2816 				json_t *audiomcast = json_object_get(root, "audiomcast");
2817 				amcast = (char *)json_string_value(audiomcast);
2818 				json_t *audioport = json_object_get(root, "audioport");
2819 				aport = json_integer_value(audioport);
2820 				json_t *audiortcpport = json_object_get(root, "audiortcpport");
2821 				if(audiortcpport) {
2822 					doaudiortcp = TRUE;
2823 					artcpport = json_integer_value(audiortcpport);
2824 				}
2825 				json_t *audiopt = json_object_get(root, "audiopt");
2826 				acodec = json_integer_value(audiopt);
2827 				json_t *audiortpmap = json_object_get(root, "audiortpmap");
2828 				artpmap = (char *)json_string_value(audiortpmap);
2829 				json_t *audiofmtp = json_object_get(root, "audiofmtp");
2830 				afmtp = (char *)json_string_value(audiofmtp);
2831 				json_t *aiface = json_object_get(root, "audioiface");
2832 				if(aiface) {
2833 					const char *miface = (const char *)json_string_value(aiface);
2834 					if(janus_network_lookup_interface(ifas, miface, &audio_iface) != 0) {
2835 						JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream '%s', invalid network interface configuration for audio...\n", (const char *)json_string_value(name));
2836 						error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
2837 						g_snprintf(error_cause, 512, ifas ? "Invalid network interface configuration for audio" : "Unable to query network device information");
2838 						janus_mutex_lock(&mountpoints_mutex);
2839 						g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2840 						janus_mutex_unlock(&mountpoints_mutex);
2841 						goto prepare_response;
2842 					}
2843 				} else {
2844 					janus_network_address_nullify(&audio_iface);
2845 				}
2846 				json_t *askew = json_object_get(root, "audioskew");
2847 				doaskew = askew ? json_is_true(askew) : FALSE;
2848 			}
2849 			uint16_t vport = 0, vport2 = 0, vport3 = 0;
2850 			uint16_t vrtcpport = 0;
2851 			uint8_t vcodec = 0;
2852 			char *vrtpmap = NULL, *vfmtp = NULL, *vmcast = NULL;
2853 			gboolean bufferkf = FALSE, simulcast = FALSE;
2854 			if(dovideo) {
2855 				JANUS_VALIDATE_JSON_OBJECT(root, rtp_video_parameters,
2856 					error_code, error_cause, TRUE,
2857 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2858 				if(error_code != 0)
2859 					goto prepare_response;
2860 				json_t *videomcast = json_object_get(root, "videomcast");
2861 				vmcast = (char *)json_string_value(videomcast);
2862 				json_t *videoport = json_object_get(root, "videoport");
2863 				vport = json_integer_value(videoport);
2864 				json_t *videortcpport = json_object_get(root, "videortcpport");
2865 				if(videortcpport) {
2866 					dovideortcp = TRUE;
2867 					vrtcpport = json_integer_value(videortcpport);
2868 				}
2869 				json_t *videopt = json_object_get(root, "videopt");
2870 				vcodec = json_integer_value(videopt);
2871 				json_t *videortpmap = json_object_get(root, "videortpmap");
2872 				vrtpmap = (char *)json_string_value(videortpmap);
2873 				json_t *videofmtp = json_object_get(root, "videofmtp");
2874 				vfmtp = (char *)json_string_value(videofmtp);
2875 				json_t *vkf = json_object_get(root, "videobufferkf");
2876 				bufferkf = vkf ? json_is_true(vkf) : FALSE;
2877 				json_t *vsc = json_object_get(root, "videosimulcast");
2878 				simulcast = vsc ? json_is_true(vsc) : FALSE;
2879 				if(simulcast && bufferkf) {
2880 					/* FIXME We'll need to take care of this */
2881 					JANUS_LOG(LOG_WARN, "Simulcasting enabled, so disabling buffering of keyframes\n");
2882 					bufferkf = FALSE;
2883 				}
2884 				json_t *videoport2 = json_object_get(root, "videoport2");
2885 				vport2 = json_integer_value(videoport2);
2886 				json_t *videoport3 = json_object_get(root, "videoport3");
2887 				vport3 = json_integer_value(videoport3);
2888 				json_t *viface = json_object_get(root, "videoiface");
2889 				if(viface) {
2890 					const char *miface = (const char *)json_string_value(viface);
2891 					if(janus_network_lookup_interface(ifas, miface, &video_iface) != 0) {
2892 						JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream '%s', invalid network interface configuration for video...\n", (const char *)json_string_value(name));
2893 						error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
2894 						g_snprintf(error_cause, 512, ifas ? "Invalid network interface configuration for video" : "Unable to query network device information");
2895 						janus_mutex_lock(&mountpoints_mutex);
2896 						g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2897 						janus_mutex_unlock(&mountpoints_mutex);
2898 						goto prepare_response;
2899 					}
2900 				} else {
2901 					janus_network_address_nullify(&video_iface);
2902 				}
2903 				json_t *vskew = json_object_get(root, "videoskew");
2904 				dovskew = vskew ? json_is_true(vskew) : FALSE;
2905 				json_t *vsvc = json_object_get(root, "videosvc");
2906 				dosvc = vsvc ? json_is_true(vsvc) : FALSE;
2907 			}
2908 			uint16_t dport = 0;
2909 			gboolean textdata = TRUE, buffermsg = FALSE;
2910 			if(dodata) {
2911 				JANUS_VALIDATE_JSON_OBJECT(root, rtp_data_parameters,
2912 					error_code, error_cause, TRUE,
2913 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2914 				if(error_code != 0) {
2915 					janus_mutex_lock(&mountpoints_mutex);
2916 					g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2917 					janus_mutex_unlock(&mountpoints_mutex);
2918 					goto prepare_response;
2919 				}
2920 #ifdef HAVE_SCTP
2921 				json_t *dataport = json_object_get(root, "dataport");
2922 				dport = json_integer_value(dataport);
2923 				json_t *dbm = json_object_get(root, "databuffermsg");
2924 				buffermsg = dbm ? json_is_true(dbm) : FALSE;
2925 				json_t *dt = json_object_get(root, "datatype");
2926 				if(dt) {
2927 					const char *datatype = (const char *)json_string_value(dt);
2928 					if(!strcasecmp(datatype, "text"))
2929 						textdata = TRUE;
2930 					else if(!strcasecmp(datatype, "binary"))
2931 						textdata = FALSE;
2932 					else {
2933 						JANUS_LOG(LOG_ERR, "Invalid element (datatype can only be text or binary)\n");
2934 						error_code = JANUS_STREAMING_ERROR_INVALID_ELEMENT;
2935 						g_snprintf(error_cause, 512, "Invalid element (datatype can only be text or binary)");
2936 						janus_mutex_lock(&mountpoints_mutex);
2937 						g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2938 						janus_mutex_unlock(&mountpoints_mutex);
2939 						goto prepare_response;
2940 					}
2941 				}
2942 				json_t *diface = json_object_get(root, "dataiface");
2943 				if(diface) {
2944 					const char *miface = (const char *)json_string_value(diface);
2945 					if(janus_network_lookup_interface(ifas, miface, &data_iface) != 0) {
2946 						JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream '%s', invalid network interface configuration for data...\n", (const char *)json_string_value(name));
2947 						error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
2948 						g_snprintf(error_cause, 512, ifas ? "Invalid network interface configuration for data" : "Unable to query network device information");
2949 						janus_mutex_lock(&mountpoints_mutex);
2950 						g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2951 						janus_mutex_unlock(&mountpoints_mutex);
2952 						goto prepare_response;
2953 					}
2954 				} else {
2955 					janus_network_address_nullify(&data_iface);
2956 				}
2957 #else
2958 				JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream: no datachannels support...\n");
2959 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
2960 				g_snprintf(error_cause, 512, "Can't add 'rtp' stream: no datachannels support...");
2961 				janus_mutex_lock(&mountpoints_mutex);
2962 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2963 				janus_mutex_unlock(&mountpoints_mutex);
2964 				goto prepare_response;
2965 #endif
2966 			}
2967 			JANUS_LOG(LOG_VERB, "Audio %s, Video %s\n", doaudio ? "enabled" : "NOT enabled", dovideo ? "enabled" : "NOT enabled");
2968 			mp = janus_streaming_create_rtp_source(
2969 					mpid, mpid_str,
2970 					name ? (char *)json_string_value(name) : NULL,
2971 					desc ? (char *)json_string_value(desc) : NULL,
2972 					md ? (char *)json_string_value(md) : NULL,
2973 					ssuite ? json_integer_value(ssuite) : 0,
2974 					scrypto ? (char *)json_string_value(scrypto) : NULL,
2975 					threads ? json_integer_value(threads) : 0,
2976 					e2ee ? json_is_true(e2ee) : FALSE,
2977 					doaudio, doaudiortcp, amcast, &audio_iface, aport, artcpport, acodec, artpmap, afmtp, doaskew,
2978 					dovideo, dovideortcp, vmcast, &video_iface, vport, vrtcpport, vcodec, vrtpmap, vfmtp, bufferkf,
2979 					simulcast, vport2, vport3, dosvc, dovskew,
2980 					rtpcollision ? json_integer_value(rtpcollision) : 0,
2981 					dodata, &data_iface, dport, textdata, buffermsg);
2982 			janus_mutex_lock(&mountpoints_mutex);
2983 			g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
2984 			janus_mutex_unlock(&mountpoints_mutex);
2985 			if(mp == NULL) {
2986 				JANUS_LOG(LOG_ERR, "Error creating 'rtp' stream...\n");
2987 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
2988 				g_snprintf(error_cause, 512, "Error creating 'rtp' stream");
2989 				goto prepare_response;
2990 			}
2991 			mp->is_private = is_private ? json_is_true(is_private) : FALSE;
2992 		} else if(!strcasecmp(type_text, "live")) {
2993 			/* File-based live source */
2994 			JANUS_VALIDATE_JSON_OBJECT(root, live_parameters,
2995 				error_code, error_cause, TRUE,
2996 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
2997 			if(error_code != 0) {
2998 				janus_mutex_lock(&mountpoints_mutex);
2999 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3000 				janus_mutex_unlock(&mountpoints_mutex);
3001 				goto prepare_response;
3002 			}
3003 			json_t *name = json_object_get(root, "name");
3004 			json_t *desc = json_object_get(root, "description");
3005 			json_t *md = json_object_get(root, "metadata");
3006 			json_t *is_private = json_object_get(root, "is_private");
3007 			json_t *file = json_object_get(root, "filename");
3008 			json_t *audio = json_object_get(root, "audio");
3009 			json_t *video = json_object_get(root, "video");
3010 			gboolean doaudio = audio ? json_is_true(audio) : FALSE;
3011 			uint8_t acodec = 0;
3012 			char *artpmap = NULL, *afmtp = NULL;
3013 			if(doaudio) {
3014 				json_t *audiopt = json_object_get(root, "audiopt");
3015 				acodec = json_integer_value(audiopt);
3016 				json_t *audiortpmap = json_object_get(root, "audiortpmap");
3017 				artpmap = (char *)json_string_value(audiortpmap);
3018 				json_t *audiofmtp = json_object_get(root, "audiofmtp");
3019 				afmtp = (char *)json_string_value(audiofmtp);
3020 			}
3021 			gboolean dovideo = video ? json_is_true(video) : FALSE;
3022 			/* We only support audio for file-based streaming at the moment: for streaming
3023 			 * files using other codecs/formats an external tools should feed us RTP instead */
3024 			if(!doaudio || dovideo) {
3025 				JANUS_LOG(LOG_ERR, "Can't add 'live' stream, we only support audio file streaming right now...\n");
3026 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3027 				g_snprintf(error_cause, 512, "Can't add 'live' stream, we only support audio file streaming right now...");
3028 				janus_mutex_lock(&mountpoints_mutex);
3029 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3030 				janus_mutex_unlock(&mountpoints_mutex);
3031 				goto prepare_response;
3032 			}
3033 			char *filename = (char *)json_string_value(file);
3034 #ifdef HAVE_LIBOGG
3035 			if(!strstr(filename, ".opus") && !strstr(filename, ".alaw") && !strstr(filename, ".mulaw")) {
3036 				JANUS_LOG(LOG_ERR, "Can't add 'live' stream, unsupported format (we only support Opus and raw mu-Law/a-Law files right now)\n");
3037 #else
3038 			if(!strstr(filename, ".alaw") && !strstr(filename, ".mulaw")) {
3039 				JANUS_LOG(LOG_ERR, "Can't add 'live' stream, unsupported format (we only support raw mu-Law and a-Law files right now)\n");
3040 #endif
3041 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3042 				g_snprintf(error_cause, 512, "Can't add 'live' stream, unsupported format (we only support raw mu-Law and a-Law files right now)");
3043 				janus_mutex_lock(&mountpoints_mutex);
3044 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3045 				janus_mutex_unlock(&mountpoints_mutex);
3046 				goto prepare_response;
3047 			}
3048 			FILE *audiofile = fopen(filename, "rb");
3049 			if(!audiofile) {
3050 				JANUS_LOG(LOG_ERR, "Can't add 'live' stream, no such file '%s'...\n", filename);
3051 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3052 				g_snprintf(error_cause, 512, "Can't add 'live' stream, no such file '%s'\n", filename);
3053 				janus_mutex_lock(&mountpoints_mutex);
3054 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3055 				janus_mutex_unlock(&mountpoints_mutex);
3056 				goto prepare_response;
3057 			}
3058 			fclose(audiofile);
3059 			mp = janus_streaming_create_file_source(
3060 					mpid, mpid_str,
3061 					name ? (char *)json_string_value(name) : NULL,
3062 					desc ? (char *)json_string_value(desc) : NULL,
3063 					md ? (char *)json_string_value(md) : NULL,
3064 					filename, TRUE,
3065 					doaudio, acodec, artpmap, afmtp, dovideo);
3066 			janus_mutex_lock(&mountpoints_mutex);
3067 			g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3068 			janus_mutex_unlock(&mountpoints_mutex);
3069 			if(mp == NULL) {
3070 				JANUS_LOG(LOG_ERR, "Error creating 'live' stream...\n");
3071 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3072 				g_snprintf(error_cause, 512, "Error creating 'live' stream");
3073 				goto prepare_response;
3074 			}
3075 			mp->is_private = is_private ? json_is_true(is_private) : FALSE;
3076 		} else if(!strcasecmp(type_text, "ondemand")) {
3077 			/* File-based on demand source */
3078 			JANUS_VALIDATE_JSON_OBJECT(root, ondemand_parameters,
3079 				error_code, error_cause, TRUE,
3080 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3081 			if(error_code != 0) {
3082 				janus_mutex_lock(&mountpoints_mutex);
3083 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3084 				janus_mutex_unlock(&mountpoints_mutex);
3085 				goto prepare_response;
3086 			}
3087 			json_t *name = json_object_get(root, "name");
3088 			json_t *desc = json_object_get(root, "description");
3089 			json_t *md = json_object_get(root, "metadata");
3090 			json_t *is_private = json_object_get(root, "is_private");
3091 			json_t *file = json_object_get(root, "filename");
3092 			json_t *audio = json_object_get(root, "audio");
3093 			json_t *video = json_object_get(root, "video");
3094 			gboolean doaudio = audio ? json_is_true(audio) : FALSE;
3095 			uint8_t acodec = 0;
3096 			char *artpmap = NULL, *afmtp = NULL;
3097 			if(doaudio) {
3098 				json_t *audiopt = json_object_get(root, "audiopt");
3099 				acodec = json_integer_value(audiopt);
3100 				json_t *audiortpmap = json_object_get(root, "audiortpmap");
3101 				artpmap = (char *)json_string_value(audiortpmap);
3102 				json_t *audiofmtp = json_object_get(root, "audiofmtp");
3103 				afmtp = (char *)json_string_value(audiofmtp);
3104 			}
3105 			gboolean dovideo = video ? json_is_true(video) : FALSE;
3106 			/* We only support audio for file-based streaming at the moment: for streaming
3107 			 * files using other codecs/formats an external tools should feed us RTP instead */
3108 			if(!doaudio || dovideo) {
3109 				JANUS_LOG(LOG_ERR, "Can't add 'ondemand' stream, we only support audio file streaming right now...\n");
3110 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3111 				g_snprintf(error_cause, 512, "Can't add 'ondemand' stream, we only support audio file streaming right now...");
3112 				janus_mutex_lock(&mountpoints_mutex);
3113 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3114 				janus_mutex_unlock(&mountpoints_mutex);
3115 				goto prepare_response;
3116 			}
3117 			char *filename = (char *)json_string_value(file);
3118 #ifdef HAVE_LIBOGG
3119 			if(!strstr(filename, ".opus") && !strstr(filename, ".alaw") && !strstr(filename, ".mulaw")) {
3120 				JANUS_LOG(LOG_ERR, "Can't add 'live' stream, unsupported format (we only support Opus and raw mu-Law/a-Law files right now)\n");
3121 #else
3122 			if(!strstr(filename, ".alaw") && !strstr(filename, ".mulaw")) {
3123 				JANUS_LOG(LOG_ERR, "Can't add 'live' stream, unsupported format (we only support raw mu-Law and a-Law files right now)\n");
3124 #endif
3125 				JANUS_LOG(LOG_ERR, "Can't add 'ondemand' stream, unsupported format (we only support raw mu-Law and a-Law files right now)\n");
3126 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3127 				g_snprintf(error_cause, 512, "Can't add 'ondemand' stream, unsupported format (we only support raw mu-Law and a-Law files right now)");
3128 				janus_mutex_lock(&mountpoints_mutex);
3129 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3130 				janus_mutex_unlock(&mountpoints_mutex);
3131 				goto prepare_response;
3132 			}
3133 			FILE *audiofile = fopen(filename, "rb");
3134 			if(!audiofile) {
3135 				JANUS_LOG(LOG_ERR, "Can't add 'ondemand' stream, no such file '%s'...\n", filename);
3136 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3137 				g_snprintf(error_cause, 512, "Can't add 'ondemand' stream, no such file '%s'\n", filename);
3138 				janus_mutex_lock(&mountpoints_mutex);
3139 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3140 				janus_mutex_unlock(&mountpoints_mutex);
3141 				goto prepare_response;
3142 			}
3143 			fclose(audiofile);
3144 			mp = janus_streaming_create_file_source(
3145 					mpid, mpid_str,
3146 					name ? (char *)json_string_value(name) : NULL,
3147 					desc ? (char *)json_string_value(desc) : NULL,
3148 					md ? (char *)json_string_value(md) : NULL,
3149 					filename, FALSE,
3150 					doaudio, acodec, artpmap, afmtp, dovideo);
3151 			janus_mutex_lock(&mountpoints_mutex);
3152 			g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3153 			janus_mutex_unlock(&mountpoints_mutex);
3154 			if(mp == NULL) {
3155 				JANUS_LOG(LOG_ERR, "Error creating 'ondemand' stream...\n");
3156 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3157 				g_snprintf(error_cause, 512, "Error creating 'ondemand' stream");
3158 				goto prepare_response;
3159 			}
3160 			mp->is_private = is_private ? json_is_true(is_private) : FALSE;
3161 		} else if(!strcasecmp(type_text, "rtsp")) {
3162 #ifndef HAVE_LIBCURL
3163 			JANUS_LOG(LOG_ERR, "Can't create 'rtsp' mountpoint, libcurl support not compiled...\n");
3164 			error_code = JANUS_STREAMING_ERROR_INVALID_ELEMENT;
3165 			g_snprintf(error_cause, 512, "Can't create 'rtsp' mountpoint, libcurl support not compiled...\n");
3166 			goto prepare_response;
3167 #else
3168 			JANUS_VALIDATE_JSON_OBJECT(root, rtsp_parameters,
3169 				error_code, error_cause, TRUE,
3170 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3171 			if(error_code != 0) {
3172 				janus_mutex_lock(&mountpoints_mutex);
3173 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3174 				janus_mutex_unlock(&mountpoints_mutex);
3175 				goto prepare_response;
3176 			}
3177 			/* RTSP source*/
3178 			janus_network_address multicast_iface;
3179 			json_t *name = json_object_get(root, "name");
3180 			json_t *desc = json_object_get(root, "description");
3181 			json_t *md = json_object_get(root, "metadata");
3182 			json_t *is_private = json_object_get(root, "is_private");
3183 			json_t *audio = json_object_get(root, "audio");
3184 			json_t *audiopt = json_object_get(root, "audiopt");
3185 			json_t *audiortpmap = json_object_get(root, "audiortpmap");
3186 			json_t *audiofmtp = json_object_get(root, "audiofmtp");
3187 			json_t *video = json_object_get(root, "video");
3188 			json_t *videopt = json_object_get(root, "videopt");
3189 			json_t *videortpmap = json_object_get(root, "videortpmap");
3190 			json_t *videofmtp = json_object_get(root, "videofmtp");
3191 			json_t *videobufferkf = json_object_get(root, "videobufferkf");
3192 			json_t *url = json_object_get(root, "url");
3193 			json_t *username = json_object_get(root, "rtsp_user");
3194 			json_t *password = json_object_get(root, "rtsp_pwd");
3195 			json_t *iface = json_object_get(root, "rtspiface");
3196 			json_t *threads = json_object_get(root, "threads");
3197 			json_t *failerr = json_object_get(root, "rtsp_failcheck");
3198 			json_t *reconnect_delay = json_object_get(root, "rtsp_reconnect_delay");
3199 			json_t *session_timeout = json_object_get(root, "rtsp_session_timeout");
3200 			json_t *rtsp_timeout = json_object_get(root, "rtsp_timeout");
3201 			json_t *rtsp_conn_timeout = json_object_get(root, "rtsp_conn_timeout");
3202 			if(failerr == NULL)	/* For an old typo, we support the legacy syntax too */
3203 				failerr = json_object_get(root, "rtsp_check");
3204 			gboolean doaudio = audio ? json_is_true(audio) : FALSE;
3205 			gboolean dovideo = video ? json_is_true(video) : FALSE;
3206 			gboolean error_on_failure = failerr ? json_is_true(failerr) : TRUE;
3207 			if(!doaudio && !dovideo) {
3208 				JANUS_LOG(LOG_ERR, "Can't add 'rtsp' stream, no audio or video have to be streamed...\n");
3209 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3210 				g_snprintf(error_cause, 512, "Can't add 'rtsp' stream, no audio or video have to be streamed...");
3211 				janus_mutex_lock(&mountpoints_mutex);
3212 				g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3213 				janus_mutex_unlock(&mountpoints_mutex);
3214 				goto prepare_response;
3215 			} else {
3216 				if(iface) {
3217 					const char *miface = (const char *)json_string_value(iface);
3218 					if(janus_network_lookup_interface(ifas, miface, &multicast_iface) != 0) {
3219 						JANUS_LOG(LOG_ERR, "Can't add 'rtsp' stream '%s', invalid network interface configuration for stream...\n", (const char *)json_string_value(name));
3220 						error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3221 						g_snprintf(error_cause, 512, ifas ? "Invalid network interface configuration for stream" : "Unable to query network device information");
3222 						janus_mutex_lock(&mountpoints_mutex);
3223 						g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3224 						janus_mutex_unlock(&mountpoints_mutex);
3225 						goto prepare_response;
3226 					}
3227 				} else {
3228 					janus_network_address_nullify(&multicast_iface);
3229 				}
3230 			}
3231 			mp = janus_streaming_create_rtsp_source(
3232 					mpid, mpid_str,
3233 					name ? (char *)json_string_value(name) : NULL,
3234 					desc ? (char *)json_string_value(desc) : NULL,
3235 					md ? (char *)json_string_value(md) : NULL,
3236 					(char *)json_string_value(url),
3237 					username ? (char *)json_string_value(username) : NULL,
3238 					password ? (char *)json_string_value(password) : NULL,
3239 					doaudio, (audiopt ? json_integer_value(audiopt) : -1),
3240 						(char *)json_string_value(audiortpmap), (char *)json_string_value(audiofmtp),
3241 					dovideo, (videopt ? json_integer_value(videopt) : -1),
3242 						(char *)json_string_value(videortpmap), (char *)json_string_value(videofmtp),
3243 						videobufferkf ? json_is_true(videobufferkf) : FALSE,
3244 					&multicast_iface, (threads ? json_integer_value(threads) : 0),
3245 					((reconnect_delay ? json_integer_value(reconnect_delay) : JANUS_STREAMING_DEFAULT_RECONNECT_DELAY) * G_USEC_PER_SEC),
3246 					((session_timeout ? json_integer_value(session_timeout) : JANUS_STREAMING_DEFAULT_SESSION_TIMEOUT) * G_USEC_PER_SEC),
3247 					(rtsp_timeout ? json_integer_value(rtsp_timeout) : JANUS_STREAMING_DEFAULT_CURL_TIMEOUT),
3248 					(rtsp_conn_timeout ? json_integer_value(rtsp_conn_timeout) : JANUS_STREAMING_DEFAULT_CURL_CONNECT_TIMEOUT),
3249 					error_on_failure);
3250 			janus_mutex_lock(&mountpoints_mutex);
3251 			g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid);
3252 			janus_mutex_unlock(&mountpoints_mutex);
3253 			if(mp == NULL) {
3254 				JANUS_LOG(LOG_ERR, "Error creating 'rtsp' stream...\n");
3255 				error_code = JANUS_STREAMING_ERROR_CANT_CREATE;
3256 				g_snprintf(error_cause, 512, "Error creating 'RTSP' stream");
3257 				goto prepare_response;
3258 			}
3259 			mp->is_private = is_private ? json_is_true(is_private) : FALSE;
3260 #endif
3261 		} else {
3262 			JANUS_LOG(LOG_ERR, "Unknown stream type '%s'...\n", type_text);
3263 			error_code = JANUS_STREAMING_ERROR_INVALID_ELEMENT;
3264 			g_snprintf(error_cause, 512, "Unknown stream type '%s'...\n", type_text);
3265 			goto prepare_response;
3266 		}
3267 		/* Any secret? */
3268 		if(secret)
3269 			mp->secret = g_strdup(json_string_value(secret));
3270 		/* Any PIN? */
3271 		if(pin)
3272 			mp->pin = g_strdup(json_string_value(pin));
3273 		if(save) {
3274 			/* This mountpoint is permanent: save to the configuration file too
3275 			 * FIXME: We should check if anything fails... */
3276 			JANUS_LOG(LOG_VERB, "Saving mountpoint %s permanently in config file\n", mp->id_str);
3277 			janus_mutex_lock(&config_mutex);
3278 			char value[BUFSIZ];
3279 			/* The category to add is the mountpoint name */
3280 			janus_config_category *c = janus_config_get_create(config, NULL, janus_config_type_category, mp->name);
3281 			/* Now for the common values */
3282 			janus_config_add(config, c, janus_config_item_create("type", type_text));
3283 			janus_config_add(config, c, janus_config_item_create("id", mp->id_str));
3284 			janus_config_add(config, c, janus_config_item_create("description", mp->description));
3285 			if(mp->metadata)
3286 				janus_config_add(config, c, janus_config_item_create("metadata", mp->metadata));
3287 			if(mp->is_private)
3288 				janus_config_add(config, c, janus_config_item_create("is_private", "yes"));
3289 			/* Per type values */
3290 			if(!strcasecmp(type_text, "rtp")) {
3291 				janus_config_add(config, c, janus_config_item_create("audio", mp->codecs.audio_pt >= 0 ? "yes" : "no"));
3292 				janus_streaming_rtp_source *source = mp->source;
3293 				if(mp->codecs.audio_pt >= 0) {
3294 					g_snprintf(value, BUFSIZ, "%d", source->audio_port);
3295 					janus_config_add(config, c, janus_config_item_create("audioport", value));
3296 					if(source->audio_rtcp_port > 0) {
3297 						g_snprintf(value, BUFSIZ, "%d", source->audio_rtcp_port);
3298 						janus_config_add(config, c, janus_config_item_create("audiortcpport", value));
3299 					}
3300 					json_t *audiomcast = json_object_get(root, "audiomcast");
3301 					if(audiomcast)
3302 						janus_config_add(config, c, janus_config_item_create("audiomcast", json_string_value(audiomcast)));
3303 					g_snprintf(value, BUFSIZ, "%d", mp->codecs.audio_pt);
3304 					janus_config_add(config, c, janus_config_item_create("audiopt", value));
3305 					janus_config_add(config, c, janus_config_item_create("audiortpmap", mp->codecs.audio_rtpmap));
3306 					if(mp->codecs.audio_fmtp)
3307 						janus_config_add(config, c, janus_config_item_create("audiofmtp", mp->codecs.audio_fmtp));
3308 					json_t *aiface = json_object_get(root, "audioiface");
3309 					if(aiface)
3310 						janus_config_add(config, c, janus_config_item_create("audioiface", json_string_value(aiface)));
3311 					if(source->askew)
3312 						janus_config_add(config, c, janus_config_item_create("askew", "yes"));
3313 				}
3314 				janus_config_add(config, c, janus_config_item_create("video", mp->codecs.video_pt > 0 ? "yes" : "no"));
3315 				if(mp->codecs.video_pt > 0) {
3316 					g_snprintf(value, BUFSIZ, "%d", source->video_port[0]);
3317 					janus_config_add(config, c, janus_config_item_create("videoport", value));
3318 					if(source->video_rtcp_port > 0) {
3319 						g_snprintf(value, BUFSIZ, "%d", source->video_rtcp_port);
3320 						janus_config_add(config, c, janus_config_item_create("videortcpport", value));
3321 					}
3322 					json_t *videomcast = json_object_get(root, "videomcast");
3323 					if(videomcast)
3324 						janus_config_add(config, c, janus_config_item_create("videomcast", json_string_value(videomcast)));
3325 					g_snprintf(value, BUFSIZ, "%d", mp->codecs.video_pt);
3326 					janus_config_add(config, c, janus_config_item_create("videopt", value));
3327 					janus_config_add(config, c, janus_config_item_create("videortpmap", mp->codecs.video_rtpmap));
3328 					if(mp->codecs.video_fmtp)
3329 						janus_config_add(config, c, janus_config_item_create("videofmtp", mp->codecs.video_fmtp));
3330 					if(source->keyframe.enabled)
3331 						janus_config_add(config, c, janus_config_item_create("videobufferkf", "yes"));
3332 					if(source->simulcast) {
3333 						janus_config_add(config, c, janus_config_item_create("videosimulcast", "yes"));
3334 						if(source->video_port[1]) {
3335 							g_snprintf(value, BUFSIZ, "%d", source->video_port[1]);
3336 							janus_config_add(config, c, janus_config_item_create("videoport2", value));
3337 						}
3338 						if(source->video_port[2]) {
3339 							g_snprintf(value, BUFSIZ, "%d", source->video_port[2]);
3340 							janus_config_add(config, c, janus_config_item_create("videoport3", value));
3341 						}
3342 					}
3343 					if(source->svc)
3344 						janus_config_add(config, c, janus_config_item_create("videosvc", "yes"));
3345 					json_t *viface = json_object_get(root, "videoiface");
3346 					if(viface)
3347 						janus_config_add(config, c, janus_config_item_create("videoiface", json_string_value(viface)));
3348 					if(source->vskew)
3349 						janus_config_add(config, c, janus_config_item_create("videoskew", "yes"));
3350 				}
3351 				if(source->rtp_collision > 0) {
3352 					g_snprintf(value, BUFSIZ, "%d", source->rtp_collision);
3353 					janus_config_add(config, c, janus_config_item_create("collision", value));
3354 				}
3355 				janus_config_add(config, c, janus_config_item_create("data", mp->data ? "yes" : "no"));
3356 				if(source->data_port > -1) {
3357 					g_snprintf(value, BUFSIZ, "%d", source->data_port);
3358 					janus_config_add(config, c, janus_config_item_create("dataport", value));
3359 					if(source->buffermsg)
3360 						janus_config_add(config, c, janus_config_item_create("databuffermsg", "yes"));
3361 					json_t *diface = json_object_get(root, "dataiface");
3362 					if(diface)
3363 						janus_config_add(config, c, janus_config_item_create("dataiface", json_string_value(diface)));
3364 				}
3365 				if(source->srtpsuite > 0 && source->srtpcrypto) {
3366 					g_snprintf(value, BUFSIZ, "%d", source->srtpsuite);
3367 					janus_config_add(config, c, janus_config_item_create("srtpsuite", value));
3368 					janus_config_add(config, c, janus_config_item_create("srtpcrypto", source->srtpcrypto));
3369 				}
3370 				if(mp->helper_threads > 0) {
3371 					g_snprintf(value, BUFSIZ, "%d", mp->helper_threads);
3372 					janus_config_add(config, c, janus_config_item_create("threads", value));
3373 				}
3374 			} else if(!strcasecmp(type_text, "live") || !strcasecmp(type_text, "ondemand")) {
3375 				janus_streaming_file_source *source = mp->source;
3376 				janus_config_add(config, c, janus_config_item_create("filename", source->filename));
3377 				janus_config_add(config, c, janus_config_item_create("audio", mp->codecs.audio_pt >= 0 ? "yes" : "no"));
3378 				janus_config_add(config, c, janus_config_item_create("video", mp->codecs.video_pt > 0 ? "yes" : "no"));
3379 			} else if(!strcasecmp(type_text, "rtsp")) {
3380 #ifdef HAVE_LIBCURL
3381 				janus_streaming_rtp_source *source = mp->source;
3382 				if(source->rtsp_url)
3383 					janus_config_add(config, c, janus_config_item_create("url", source->rtsp_url));
3384 				if(source->rtsp_username)
3385 					janus_config_add(config, c, janus_config_item_create("rtsp_user", source->rtsp_username));
3386 				if(source->rtsp_password)
3387 					janus_config_add(config, c, janus_config_item_create("rtsp_pwd", source->rtsp_password));
3388 #endif
3389 				janus_config_add(config, c, janus_config_item_create("audio", mp->codecs.audio_pt >= 0 ? "yes" : "no"));
3390 				if(mp->codecs.audio_pt >= 0) {
3391 					if(mp->codecs.audio_rtpmap)
3392 						janus_config_add(config, c, janus_config_item_create("audiortpmap", mp->codecs.audio_rtpmap));
3393 					if(mp->codecs.audio_fmtp)
3394 						janus_config_add(config, c, janus_config_item_create("audiofmtp", mp->codecs.audio_fmtp));
3395 				}
3396 				janus_config_add(config, c, janus_config_item_create("video", mp->codecs.video_pt > 0 ? "yes" : "no"));
3397 				if(mp->codecs.video_pt > 0) {
3398 					if(mp->codecs.video_rtpmap)
3399 						janus_config_add(config, c, janus_config_item_create("videortpmap", mp->codecs.video_rtpmap));
3400 					if(mp->codecs.video_fmtp)
3401 						janus_config_add(config, c, janus_config_item_create("videofmtp", mp->codecs.video_fmtp));
3402 				}
3403 				json_t *iface = json_object_get(root, "rtspiface");
3404 				if(iface)
3405 					janus_config_add(config, c, janus_config_item_create("rtspiface", json_string_value(iface)));
3406 				if(mp->helper_threads > 0) {
3407 					g_snprintf(value, BUFSIZ, "%d", mp->helper_threads);
3408 					janus_config_add(config, c, janus_config_item_create("threads", value));
3409 				}
3410 			}
3411 			/* Some more common values */
3412 			if(mp->secret)
3413 				janus_config_add(config, c, janus_config_item_create("secret", mp->secret));
3414 			if(mp->pin)
3415 				janus_config_add(config, c, janus_config_item_create("pin", mp->pin));
3416 			/* Save modified configuration */
3417 			if(janus_config_save(config, config_folder, JANUS_STREAMING_PACKAGE) < 0)
3418 				save = FALSE;	/* This will notify the user the mountpoint is not permanent */
3419 			janus_mutex_unlock(&config_mutex);
3420 		}
3421 		/* Send info back */
3422 		response = json_object();
3423 		json_object_set_new(response, "streaming", json_string("created"));
3424 		json_object_set_new(response, "created", json_string(mp->name));
3425 		json_object_set_new(response, "permanent", save ? json_true() : json_false());
3426 		json_t *ml = json_object();
3427 		json_object_set_new(ml, "id", string_ids ? json_string(mp->id_str) : json_integer(mp->id));
3428 		json_object_set_new(ml, "type", json_string(mp->streaming_type == janus_streaming_type_live ? "live" : "on demand"));
3429 		json_object_set_new(ml, "description", json_string(mp->description));
3430 		json_object_set_new(ml, "is_private", mp->is_private ? json_true() : json_false());
3431 		if(!strcasecmp(type_text, "rtp")) {
3432 			janus_streaming_rtp_source *source = mp->source;
3433 			if(source->audio_fd != -1) {
3434 				if(source->audio_host)
3435 					json_object_set_new(ml, "audio_host", json_string(source->audio_host));
3436 				json_object_set_new(ml, "audio_port", json_integer(source->audio_port));
3437 			}
3438 			if(source->audio_rtcp_fd != -1) {
3439 				json_object_set_new(ml, "audio_rtcp_port", json_integer(source->audio_rtcp_port));
3440 			}
3441 			if(source->video_fd[0] != -1) {
3442 				if(source->video_host)
3443 					json_object_set_new(ml, "video_host", json_string(source->video_host));
3444 				json_object_set_new(ml, "video_port", json_integer(source->video_port[0]));
3445 			}
3446 			if(source->video_rtcp_fd != -1) {
3447 				json_object_set_new(ml, "video_rtcp_port", json_integer(source->video_rtcp_port));
3448 			}
3449 			if(source->video_fd[1] != -1) {
3450 				json_object_set_new(ml, "video_port_2", json_integer(source->video_port[1]));
3451 			}
3452 			if(source->video_fd[2] != -1) {
3453 				json_object_set_new(ml, "video_port_3", json_integer(source->video_port[2]));
3454 			}
3455 			if(source->data_fd != -1) {
3456 				if(source->data_host)
3457 					json_object_set_new(ml, "data_host", json_string(source->data_host));
3458 				json_object_set_new(ml, "data_port", json_integer(source->data_port));
3459 			}
3460 		}
3461 		json_object_set_new(response, "stream", ml);
3462 		/* Also notify event handlers */
3463 		if(notify_events && gateway->events_is_enabled()) {
3464 			json_t *info = json_object();
3465 			json_object_set_new(info, "event", json_string("created"));
3466 			json_object_set_new(info, "id", string_ids ? json_string(mp->id_str) : json_integer(mp->id));
3467 			json_object_set_new(info, "type", json_string(mp->streaming_type == janus_streaming_type_live ? "live" : "on demand"));
3468 			gateway->notify_event(&janus_streaming_plugin, session ? session->handle : NULL, info);
3469 		}
3470 		goto prepare_response;
3471 	} else if(!strcasecmp(request_text, "edit")) {
3472 		JANUS_LOG(LOG_VERB, "Attempt to edit an existing streaming mountpoint\n");
3473 		JANUS_VALIDATE_JSON_OBJECT(root, edit_parameters,
3474 			error_code, error_cause, TRUE,
3475 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3476 		if(error_code != 0)
3477 			goto prepare_response;
3478 		if(!string_ids) {
3479 			JANUS_VALIDATE_JSON_OBJECT(root, id_parameters,
3480 				error_code, error_cause, TRUE,
3481 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3482 		} else {
3483 			JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters,
3484 				error_code, error_cause, TRUE,
3485 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3486 		}
3487 		if(error_code != 0)
3488 			goto prepare_response;
3489 		/* We only allow for a limited set of properties to be edited */
3490 		json_t *id = json_object_get(root, "id");
3491 		json_t *desc = json_object_get(root, "new_description");
3492 		json_t *md = json_object_get(root, "new_metadata");
3493 		json_t *secret = json_object_get(root, "new_secret");
3494 		json_t *pin = json_object_get(root, "new_pin");
3495 		json_t *is_private = json_object_get(root, "new_is_private");
3496 		json_t *permanent = json_object_get(root, "permanent");
3497 		gboolean save = permanent ? json_is_true(permanent) : FALSE;
3498 		if(save && config == NULL) {
3499 			JANUS_LOG(LOG_ERR, "No configuration file, can't edit mountpoint permanently\n");
3500 			error_code = JANUS_STREAMING_ERROR_UNKNOWN_ERROR;
3501 			g_snprintf(error_cause, 512, "No configuration file, can't edit mountpoint permanently");
3502 			goto prepare_response;
3503 		}
3504 		guint64 id_value = 0;
3505 		char id_num[30], *id_value_str = NULL;
3506 		if(!string_ids) {
3507 			id_value = json_integer_value(id);
3508 			g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id_value);
3509 			id_value_str = id_num;
3510 		} else {
3511 			id_value_str = (char *)json_string_value(id);
3512 		}
3513 		janus_mutex_lock(&mountpoints_mutex);
3514 		janus_streaming_mountpoint *mp = g_hash_table_lookup(mountpoints,
3515 			string_ids ? (gpointer)id_value_str : (gpointer)&id_value);
3516 		if(mp == NULL) {
3517 			janus_mutex_unlock(&mountpoints_mutex);
3518 			JANUS_LOG(LOG_ERR, "No such mountpoint (%s)\n", id_value_str);
3519 			error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
3520 			g_snprintf(error_cause, 512, "No such mountpoint (%s)", id_value_str);
3521 			goto prepare_response;
3522 		}
3523 		janus_refcount_increase(&mp->ref);
3524 		janus_mutex_lock(&mp->mutex);
3525 		/* A secret may be required for this action */
3526 		JANUS_CHECK_SECRET(mp->secret, root, "secret", error_code, error_cause,
3527 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT, JANUS_STREAMING_ERROR_UNAUTHORIZED);
3528 		if(error_code != 0) {
3529 			janus_mutex_unlock(&mp->mutex);
3530 			janus_mutex_unlock(&mountpoints_mutex);
3531 			janus_refcount_decrease(&mp->ref);
3532 			goto prepare_response;
3533 		}
3534 		/* Edit the mountpoint properties that were provided */
3535 		if(desc != NULL && strlen(json_string_value(desc)) > 0) {
3536 			char *old_description = mp->description;
3537 			char *new_description = g_strdup(json_string_value(desc));
3538 			mp->description = new_description;
3539 			g_free(old_description);
3540 		}
3541 		if(md != NULL) {
3542 			char *old_metadata = mp->metadata;
3543 			char *new_metadata = g_strdup(json_string_value(md));
3544 			mp->metadata = new_metadata;
3545 			g_free(old_metadata);
3546 		}
3547 		if(is_private)
3548 			mp->is_private = json_is_true(is_private);
3549 		/* A secret may be required for this action */
3550 		JANUS_CHECK_SECRET(mp->secret, root, "secret", error_code, error_cause,
3551 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT, JANUS_STREAMING_ERROR_UNAUTHORIZED);
3552 		if(error_code != 0) {
3553 			janus_mutex_unlock(&mp->mutex);
3554 			janus_mutex_unlock(&mountpoints_mutex);
3555 			janus_refcount_decrease(&mp->ref);
3556 			goto prepare_response;
3557 		}
3558 		if(secret && strlen(json_string_value(secret)) > 0) {
3559 			char *old_secret = mp->secret;
3560 			char *new_secret = g_strdup(json_string_value(secret));
3561 			mp->secret = new_secret;
3562 			g_free(old_secret);
3563 		}
3564 		if(pin && strlen(json_string_value(pin)) > 0) {
3565 			char *old_pin = mp->pin;
3566 			char *new_pin = g_strdup(json_string_value(pin));
3567 			mp->pin = new_pin;
3568 			g_free(old_pin);
3569 		}
3570 		if(save) {
3571 			JANUS_LOG(LOG_VERB, "Saving edited mountpoint %s permanently in config file\n", mp->id_str);
3572 			janus_mutex_lock(&config_mutex);
3573 			char value[BUFSIZ];
3574 			/* Remove the old category first */
3575 			janus_config_remove(config, NULL, mp->name);
3576 			/* Now write the room details again */
3577 			janus_config_category *c = janus_config_get_create(config, NULL, janus_config_type_category, mp->name);
3578 			/* Now for the common values at top */
3579 			janus_config_add(config, c, janus_config_item_create("id", mp->id_str));
3580 			janus_config_add(config, c, janus_config_item_create("description", mp->description));
3581 			if(mp->metadata)
3582 				janus_config_add(config, c, janus_config_item_create("metadata", mp->metadata));
3583 			if(mp->is_private)
3584 				janus_config_add(config, c, janus_config_item_create("is_private", "yes"));
3585 			/* Per type values */
3586 			if(mp->streaming_source == janus_streaming_source_rtp) {
3587 				gboolean rtsp = FALSE;
3588 #ifdef HAVE_LIBCURL
3589 				janus_streaming_rtp_source *source = mp->source;
3590 				if(source->rtsp)
3591 						rtsp = TRUE;
3592 #endif
3593 				if(rtsp) {
3594 #ifdef HAVE_LIBCURL
3595 					janus_config_add(config, c, janus_config_item_create("type", "rtsp"));
3596 					if(source->rtsp_url)
3597 						janus_config_add(config, c, janus_config_item_create("url", source->rtsp_url));
3598 					if(source->rtsp_username)
3599 						janus_config_add(config, c, janus_config_item_create("rtsp_user", source->rtsp_username));
3600 					if(source->rtsp_password)
3601 						janus_config_add(config, c, janus_config_item_create("rtsp_pwd", source->rtsp_password));
3602 #endif
3603 					janus_config_add(config, c, janus_config_item_create("audio", mp->codecs.audio_pt >= 0 ? "yes" : "no"));
3604 					if(mp->codecs.audio_pt >= 0) {
3605 						if(mp->codecs.audio_rtpmap)
3606 							janus_config_add(config, c, janus_config_item_create("audiortpmap", mp->codecs.audio_rtpmap));
3607 						if(mp->codecs.audio_fmtp)
3608 							janus_config_add(config, c, janus_config_item_create("audiofmtp", mp->codecs.audio_fmtp));
3609 					}
3610 					janus_config_add(config, c, janus_config_item_create("video", mp->codecs.video_pt > 0 ? "yes" : "no"));
3611 					if(mp->codecs.video_pt > 0) {
3612 						if(mp->codecs.video_rtpmap)
3613 							janus_config_add(config, c, janus_config_item_create("videortpmap", mp->codecs.video_rtpmap));
3614 						if(mp->codecs.video_fmtp)
3615 							janus_config_add(config, c, janus_config_item_create("videofmtp", mp->codecs.video_fmtp));
3616 					}
3617 					json_t *iface = json_object_get(root, "rtspiface");
3618 					if(iface)
3619 						janus_config_add(config, c, janus_config_item_create("rtspiface", json_string_value(iface)));
3620 					if(mp->helper_threads > 0) {
3621 						g_snprintf(value, BUFSIZ, "%d", mp->helper_threads);
3622 						janus_config_add(config, c, janus_config_item_create("threads", value));
3623 					}
3624 				} else {
3625 					janus_config_add(config, c, janus_config_item_create("type", "rtp"));
3626 					janus_config_add(config, c, janus_config_item_create("audio", mp->codecs.audio_pt >= 0 ? "yes" : "no"));
3627 					janus_streaming_rtp_source *source = mp->source;
3628 					if(mp->codecs.audio_pt >= 0) {
3629 						g_snprintf(value, BUFSIZ, "%d", source->audio_port);
3630 						janus_config_add(config, c, janus_config_item_create("audioport", value));
3631 						if(source->audio_rtcp_port > 0) {
3632 							g_snprintf(value, BUFSIZ, "%d", source->audio_rtcp_port);
3633 							janus_config_add(config, c, janus_config_item_create("audiortcpport", value));
3634 						}
3635 						json_t *audiomcast = json_object_get(root, "audiomcast");
3636 						if(audiomcast)
3637 							janus_config_add(config, c, janus_config_item_create("audiomcast", json_string_value(audiomcast)));
3638 						g_snprintf(value, BUFSIZ, "%d", mp->codecs.audio_pt);
3639 						janus_config_add(config, c, janus_config_item_create("audiopt", value));
3640 						janus_config_add(config, c, janus_config_item_create("audiortpmap", mp->codecs.audio_rtpmap));
3641 						if(mp->codecs.audio_fmtp)
3642 							janus_config_add(config, c, janus_config_item_create("audiofmtp", mp->codecs.audio_fmtp));
3643 						json_t *aiface = json_object_get(root, "audioiface");
3644 						if(aiface)
3645 							janus_config_add(config, c, janus_config_item_create("audioiface", json_string_value(aiface)));
3646 						if(source->askew)
3647 							janus_config_add(config, c, janus_config_item_create("askew", "yes"));
3648 					}
3649 					janus_config_add(config, c, janus_config_item_create("video", mp->codecs.video_pt > 0 ? "yes" : "no"));
3650 					if(mp->codecs.video_pt > 0) {
3651 						g_snprintf(value, BUFSIZ, "%d", source->video_port[0]);
3652 						janus_config_add(config, c, janus_config_item_create("videoport", value));
3653 						if(source->video_rtcp_port > 0) {
3654 							g_snprintf(value, BUFSIZ, "%d", source->video_rtcp_port);
3655 							janus_config_add(config, c, janus_config_item_create("videortcpport", value));
3656 						}
3657 						json_t *videomcast = json_object_get(root, "videomcast");
3658 						if(videomcast)
3659 							janus_config_add(config, c, janus_config_item_create("videomcast", json_string_value(videomcast)));
3660 						g_snprintf(value, BUFSIZ, "%d", mp->codecs.video_pt);
3661 						janus_config_add(config, c, janus_config_item_create("videopt", value));
3662 						janus_config_add(config, c, janus_config_item_create("videortpmap", mp->codecs.video_rtpmap));
3663 						if(mp->codecs.video_fmtp)
3664 							janus_config_add(config, c, janus_config_item_create("videofmtp", mp->codecs.video_fmtp));
3665 						if(source->keyframe.enabled)
3666 							janus_config_add(config, c, janus_config_item_create("videobufferkf", "yes"));
3667 						if(source->simulcast) {
3668 							janus_config_add(config, c, janus_config_item_create("videosimulcast", "yes"));
3669 							if(source->video_port[1]) {
3670 								g_snprintf(value, BUFSIZ, "%d", source->video_port[1]);
3671 								janus_config_add(config, c, janus_config_item_create("videoport2", value));
3672 							}
3673 							if(source->video_port[2]) {
3674 								g_snprintf(value, BUFSIZ, "%d", source->video_port[2]);
3675 								janus_config_add(config, c, janus_config_item_create("videoport3", value));
3676 							}
3677 						}
3678 						if(source->svc)
3679 							janus_config_add(config, c, janus_config_item_create("videosvc", "yes"));
3680 						json_t *viface = json_object_get(root, "videoiface");
3681 						if(viface)
3682 							janus_config_add(config, c, janus_config_item_create("videoiface", json_string_value(viface)));
3683 						if(source->vskew)
3684 							janus_config_add(config, c, janus_config_item_create("videoskew", "yes"));
3685 					}
3686 					if(source->rtp_collision > 0) {
3687 						g_snprintf(value, BUFSIZ, "%d", source->rtp_collision);
3688 						janus_config_add(config, c, janus_config_item_create("collision", value));
3689 					}
3690 					janus_config_add(config, c, janus_config_item_create("data", mp->data ? "yes" : "no"));
3691 					if(source->data_port > -1) {
3692 						g_snprintf(value, BUFSIZ, "%d", source->data_port);
3693 						janus_config_add(config, c, janus_config_item_create("dataport", value));
3694 						if(source->buffermsg)
3695 							janus_config_add(config, c, janus_config_item_create("databuffermsg", "yes"));
3696 						json_t *diface = json_object_get(root, "dataiface");
3697 						if(diface)
3698 							janus_config_add(config, c, janus_config_item_create("dataiface", json_string_value(diface)));
3699 					}
3700 					if(source->srtpsuite > 0 && source->srtpcrypto) {
3701 						g_snprintf(value, BUFSIZ, "%d", source->srtpsuite);
3702 						janus_config_add(config, c, janus_config_item_create("srtpsuite", value));
3703 						janus_config_add(config, c, janus_config_item_create("srtpcrypto", source->srtpcrypto));
3704 					}
3705 					if(mp->helper_threads > 0) {
3706 						g_snprintf(value, BUFSIZ, "%d", mp->helper_threads);
3707 						janus_config_add(config, c, janus_config_item_create("threads", value));
3708 					}
3709 				}
3710 			} else {
3711 				janus_config_add(config, c, janus_config_item_create("type", (mp->streaming_type == janus_streaming_type_live) ? "live" : "ondemand"));
3712 				janus_streaming_file_source *source = mp->source;
3713 				janus_config_add(config, c, janus_config_item_create("filename", source->filename));
3714 				janus_config_add(config, c, janus_config_item_create("audio", mp->codecs.audio_pt >= 0 ? "yes" : "no"));
3715 				janus_config_add(config, c, janus_config_item_create("video", mp->codecs.video_pt > 0 ? "yes" : "no"));
3716 			}
3717 			/* Some more common values */
3718 			if(mp->secret)
3719 				janus_config_add(config, c, janus_config_item_create("secret", mp->secret));
3720 			if(mp->pin)
3721 				janus_config_add(config, c, janus_config_item_create("pin", mp->pin));
3722 			/* Save modified configuration */
3723 			if(janus_config_save(config, config_folder, JANUS_STREAMING_PACKAGE) < 0)
3724 				save = FALSE;	/* This will notify the user the mountpoint is not permanent */
3725 			janus_mutex_unlock(&config_mutex);
3726 		}
3727 		/* Prepare response/notification */
3728 		response = json_object();
3729 		json_object_set_new(response, "streaming", json_string("edited"));
3730 		json_object_set_new(response, "id", string_ids ? json_string(mp->id_str) : json_integer(mp->id));
3731 		json_object_set_new(response, "permanent", save ? json_true() : json_false());
3732 		/* Also notify event handlers */
3733 		if(notify_events && gateway->events_is_enabled()) {
3734 			json_t *info = json_object();
3735 			json_object_set_new(info, "event", json_string("edited"));
3736 			json_object_set_new(info, "id", string_ids ? json_string(mp->id_str) : json_integer(mp->id));
3737 			gateway->notify_event(&janus_streaming_plugin, session ? session->handle : NULL, info);
3738 		}
3739 		janus_mutex_unlock(&mp->mutex);
3740 		janus_mutex_unlock(&mountpoints_mutex);
3741 		janus_refcount_decrease(&mp->ref);
3742 		/* Done */
3743 		JANUS_LOG(LOG_VERB, "Streaming mountpoint edited\n");
3744 		goto prepare_response;
3745 	} else if(!strcasecmp(request_text, "destroy")) {
3746 		/* Get rid of an existing stream (notice this doesn't remove it from the config file, though) */
3747 		JANUS_VALIDATE_JSON_OBJECT(root, destroy_parameters,
3748 			error_code, error_cause, TRUE,
3749 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3750 		if(error_code != 0)
3751 			goto prepare_response;
3752 		if(!string_ids) {
3753 			JANUS_VALIDATE_JSON_OBJECT(root, id_parameters,
3754 				error_code, error_cause, TRUE,
3755 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3756 		} else {
3757 			JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters,
3758 				error_code, error_cause, TRUE,
3759 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3760 		}
3761 		if(error_code != 0)
3762 			goto prepare_response;
3763 		json_t *id = json_object_get(root, "id");
3764 		guint64 id_value = 0;
3765 		char id_num[30], *id_value_str = NULL;
3766 		if(!string_ids) {
3767 			id_value = json_integer_value(id);
3768 			g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id_value);
3769 			id_value_str = id_num;
3770 		} else {
3771 			id_value_str = (char *)json_string_value(id);
3772 		}
3773 		json_t *permanent = json_object_get(root, "permanent");
3774 		gboolean save = permanent ? json_is_true(permanent) : FALSE;
3775 		if(save && config == NULL) {
3776 			JANUS_LOG(LOG_ERR, "No configuration file, can't destroy mountpoint permanently\n");
3777 			error_code = JANUS_STREAMING_ERROR_UNKNOWN_ERROR;
3778 			g_snprintf(error_cause, 512, "No configuration file, can't destroy mountpoint permanently");
3779 			goto prepare_response;
3780 		}
3781 		janus_mutex_lock(&mountpoints_mutex);
3782 		janus_streaming_mountpoint *mp = g_hash_table_lookup(mountpoints,
3783 			string_ids ? (gpointer)id_value_str : (gpointer)&id_value);
3784 		if(mp == NULL) {
3785 			janus_mutex_unlock(&mountpoints_mutex);
3786 			JANUS_LOG(LOG_VERB, "No such mountpoint/stream %s\n", id_value_str);
3787 			error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
3788 			g_snprintf(error_cause, 512, "No such mountpoint/stream %s", id_value_str);
3789 			goto prepare_response;
3790 		}
3791 		janus_refcount_increase(&mp->ref);
3792 		/* A secret may be required for this action */
3793 		JANUS_CHECK_SECRET(mp->secret, root, "secret", error_code, error_cause,
3794 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT, JANUS_STREAMING_ERROR_UNAUTHORIZED);
3795 		if(error_code != 0) {
3796 			janus_refcount_decrease(&mp->ref);
3797 			janus_mutex_unlock(&mountpoints_mutex);
3798 			goto prepare_response;
3799 		}
3800 		JANUS_LOG(LOG_VERB, "Request to unmount mountpoint/stream %s\n", id_value_str);
3801 		/* Remove mountpoint from the hashtable: this will get it destroyed eventually */
3802 		g_hash_table_remove(mountpoints,
3803 			string_ids ? (gpointer)id_value_str : (gpointer)&id_value);
3804 		/* FIXME Should we kick the current viewers as well? */
3805 		janus_mutex_lock(&mp->mutex);
3806 		GList *viewer = g_list_first(mp->viewers);
3807 		/* Prepare JSON event */
3808 		json_t *event = json_object();
3809 		json_object_set_new(event, "streaming", json_string("event"));
3810 		json_t *result = json_object();
3811 		json_object_set_new(result, "status", json_string("stopped"));
3812 		json_object_set_new(event, "result", result);
3813 		while(viewer) {
3814 			janus_streaming_session *s = (janus_streaming_session *)viewer->data;
3815 			if(s == NULL) {
3816 				mp->viewers = g_list_remove_all(mp->viewers, s);
3817 				viewer = g_list_first(mp->viewers);
3818 				continue;
3819 			}
3820 			janus_mutex_lock(&session->mutex);
3821 			if(s->mountpoint != mp) {
3822 				mp->viewers = g_list_remove_all(mp->viewers, s);
3823 				viewer = g_list_first(mp->viewers);
3824 				janus_mutex_unlock(&session->mutex);
3825 				continue;
3826 			}
3827 			g_atomic_int_set(&s->stopping, 1);
3828 			g_atomic_int_set(&s->started, 0);
3829 			g_atomic_int_set(&s->paused, 0);
3830 			s->mountpoint = NULL;
3831 			/* Tell the core to tear down the PeerConnection, hangup_media will do the rest */
3832 			gateway->push_event(s->handle, &janus_streaming_plugin, NULL, event, NULL);
3833 			gateway->close_pc(s->handle);
3834 			janus_refcount_decrease(&s->ref);
3835 			janus_refcount_decrease(&mp->ref);
3836 			if(mp->streaming_source == janus_streaming_source_rtp) {
3837 				/* Remove the viewer from the helper threads too, if any */
3838 				if(mp->helper_threads > 0) {
3839 					GList *l = mp->threads;
3840 					while(l) {
3841 						janus_streaming_helper *ht = (janus_streaming_helper *)l->data;
3842 						janus_mutex_lock(&ht->mutex);
3843 						if(g_list_find(ht->viewers, s) != NULL) {
3844 							ht->num_viewers--;
3845 							ht->viewers = g_list_remove_all(ht->viewers, s);
3846 							janus_mutex_unlock(&ht->mutex);
3847 							JANUS_LOG(LOG_VERB, "Removing viewer from helper thread #%d (destroy)\n", ht->id);
3848 							break;
3849 						}
3850 						janus_mutex_unlock(&ht->mutex);
3851 						l = l->next;
3852 					}
3853 				}
3854 			}
3855 			mp->viewers = g_list_remove_all(mp->viewers, s);
3856 			viewer = g_list_first(mp->viewers);
3857 			janus_mutex_unlock(&session->mutex);
3858 		}
3859 		json_decref(event);
3860 		janus_mutex_unlock(&mp->mutex);
3861 		if(save) {
3862 			/* This change is permanent: save to the configuration file too
3863 			 * FIXME: We should check if anything fails... */
3864 			JANUS_LOG(LOG_VERB, "Destroying mountpoint %s (%s) permanently in config file\n", mp->id_str, mp->name);
3865 			janus_mutex_lock(&config_mutex);
3866 			/* The category to remove is the mountpoint name */
3867 			janus_config_remove(config, NULL, mp->name);
3868 			/* Save modified configuration */
3869 			if(janus_config_save(config, config_folder, JANUS_STREAMING_PACKAGE) < 0)
3870 				save = FALSE;	/* This will notify the user the mountpoint is not permanent */
3871 			janus_mutex_unlock(&config_mutex);
3872 		}
3873 		janus_refcount_decrease(&mp->ref);
3874 		/* Also notify event handlers */
3875 		if(notify_events && gateway->events_is_enabled()) {
3876 			json_t *info = json_object();
3877 			json_object_set_new(info, "event", json_string("destroyed"));
3878 			json_object_set_new(info, "id", string_ids ? json_string(id_value_str) : json_integer(id_value));
3879 			gateway->notify_event(&janus_streaming_plugin, session ? session->handle : NULL, info);
3880 		}
3881 		janus_mutex_unlock(&mountpoints_mutex);
3882 		/* Send info back */
3883 		response = json_object();
3884 		json_object_set_new(response, "streaming", json_string("destroyed"));
3885 		json_object_set_new(response, "destroyed", string_ids ? json_string(id_value_str) : json_integer(id_value));
3886 		goto prepare_response;
3887 	} else if(!strcasecmp(request_text, "recording")) {
3888 		/* We can start/stop recording a live, RTP-based stream */
3889 		JANUS_VALIDATE_JSON_OBJECT(root, recording_parameters,
3890 			error_code, error_cause, TRUE,
3891 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3892 		if(error_code != 0)
3893 			goto prepare_response;
3894 		json_t *action = json_object_get(root, "action");
3895 		const char *action_text = json_string_value(action);
3896 		if(strcasecmp(action_text, "start") && strcasecmp(action_text, "stop")) {
3897 			JANUS_LOG(LOG_ERR, "Invalid action (should be start|stop)\n");
3898 			error_code = JANUS_STREAMING_ERROR_INVALID_ELEMENT;
3899 			g_snprintf(error_cause, 512, "Invalid action (should be start|stop)");
3900 			goto prepare_response;
3901 		}
3902 		if(!string_ids) {
3903 			JANUS_VALIDATE_JSON_OBJECT(root, id_parameters,
3904 				error_code, error_cause, TRUE,
3905 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3906 		} else {
3907 			JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters,
3908 				error_code, error_cause, TRUE,
3909 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3910 		}
3911 		if(error_code != 0)
3912 			goto prepare_response;
3913 		json_t *id = json_object_get(root, "id");
3914 		guint64 id_value = 0;
3915 		char id_num[30], *id_value_str = NULL;
3916 		if(!string_ids) {
3917 			id_value = json_integer_value(id);
3918 			g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id_value);
3919 			id_value_str = id_num;
3920 		} else {
3921 			id_value_str = (char *)json_string_value(id);
3922 		}
3923 		janus_mutex_lock(&mountpoints_mutex);
3924 		janus_streaming_mountpoint *mp = g_hash_table_lookup(mountpoints,
3925 			string_ids ? (gpointer)id_value_str : (gpointer)&id_value);
3926 		if(mp == NULL) {
3927 			janus_mutex_unlock(&mountpoints_mutex);
3928 			JANUS_LOG(LOG_VERB, "No such mountpoint/stream %s\n", id_value_str);
3929 			error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
3930 			g_snprintf(error_cause, 512, "No such mountpoint/stream %s", id_value_str);
3931 			goto prepare_response;
3932 		}
3933 		janus_refcount_increase(&mp->ref);
3934 		if(mp->streaming_type != janus_streaming_type_live || mp->streaming_source != janus_streaming_source_rtp) {
3935 			janus_refcount_decrease(&mp->ref);
3936 			janus_mutex_unlock(&mountpoints_mutex);
3937 			JANUS_LOG(LOG_ERR, "Recording is only available on RTP-based live streams\n");
3938 			error_code = JANUS_STREAMING_ERROR_INVALID_REQUEST;
3939 			g_snprintf(error_cause, 512, "Recording is only available on RTP-based live streams");
3940 			goto prepare_response;
3941 		}
3942 		/* A secret may be required for this action */
3943 		JANUS_CHECK_SECRET(mp->secret, root, "secret", error_code, error_cause,
3944 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT, JANUS_STREAMING_ERROR_UNAUTHORIZED);
3945 		if(error_code != 0) {
3946 			janus_refcount_decrease(&mp->ref);
3947 			janus_mutex_unlock(&mountpoints_mutex);
3948 			goto prepare_response;
3949 		}
3950 		janus_streaming_rtp_source *source = mp->source;
3951 		if(!strcasecmp(action_text, "start")) {
3952 			/* Start a recording for audio and/or video */
3953 			JANUS_VALIDATE_JSON_OBJECT(root, recording_start_parameters,
3954 				error_code, error_cause, TRUE,
3955 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
3956 			if(error_code != 0) {
3957 				janus_refcount_decrease(&mp->ref);
3958 				janus_mutex_unlock(&mountpoints_mutex);
3959 				goto prepare_response;
3960 			}
3961 			json_t *audio = json_object_get(root, "audio");
3962 			json_t *video = json_object_get(root, "video");
3963 			json_t *data = json_object_get(root, "data");
3964 			janus_recorder *arc = NULL, *vrc = NULL, *drc = NULL;
3965 			if((audio && source->arc) || (video && source->vrc) || (data && source->drc)) {
3966 				janus_refcount_decrease(&mp->ref);
3967 				janus_mutex_unlock(&mountpoints_mutex);
3968 				JANUS_LOG(LOG_ERR, "Recording for audio, video and/or data already started for this stream\n");
3969 				error_code = JANUS_STREAMING_ERROR_INVALID_REQUEST;
3970 				g_snprintf(error_cause, 512, "Recording for audio, video and/or data already started for this stream");
3971 				goto prepare_response;
3972 			}
3973 			if(!audio && !video && !data) {
3974 				janus_refcount_decrease(&mp->ref);
3975 				janus_mutex_unlock(&mountpoints_mutex);
3976 				JANUS_LOG(LOG_ERR, "Missing audio, video and/or data\n");
3977 				error_code = JANUS_STREAMING_ERROR_INVALID_REQUEST;
3978 				g_snprintf(error_cause, 512, "Missing audio, video and/or data");
3979 				goto prepare_response;
3980 			}
3981 			if(audio) {
3982 				const char *codec = NULL;
3983 				if (!mp->codecs.audio_rtpmap)
3984 					JANUS_LOG(LOG_ERR, "[%s] Audio RTP map is uninitialized\n", mp->name);
3985 				else if(strstr(mp->codecs.audio_rtpmap, "opus") || strstr(mp->codecs.audio_rtpmap, "OPUS"))
3986 					codec = "opus";
3987 				else if(strstr(mp->codecs.audio_rtpmap, "pcma") || strstr(mp->codecs.audio_rtpmap, "PCMA"))
3988 					codec = "pcma";
3989 				else if(strstr(mp->codecs.audio_rtpmap, "pcmu") || strstr(mp->codecs.audio_rtpmap, "PCMU"))
3990 					codec = "pcmu";
3991 				else if(strstr(mp->codecs.audio_rtpmap, "g722") || strstr(mp->codecs.audio_rtpmap, "G722"))
3992 					codec = "g722";
3993 				const char *audiofile = json_string_value(audio);
3994 				arc = janus_recorder_create(NULL, codec, (char *)audiofile);
3995 				if(arc == NULL) {
3996 					JANUS_LOG(LOG_ERR, "[%s] Error starting recorder for audio\n", mp->name);
3997 					janus_refcount_decrease(&mp->ref);
3998 					janus_mutex_unlock(&mountpoints_mutex);
3999 					error_code = JANUS_STREAMING_ERROR_CANT_RECORD;
4000 					g_snprintf(error_cause, 512, "Error starting recorder for audio");
4001 					goto prepare_response;
4002 				}
4003 				/* If media is encrypted, mark it in the recording */
4004 				if(source->e2ee)
4005 					janus_recorder_encrypted(arc);
4006 				JANUS_LOG(LOG_INFO, "[%s] Audio recording started\n", mp->name);
4007 			}
4008 			if(video) {
4009 				const char *codec = NULL;
4010 				if (!mp->codecs.video_rtpmap)
4011 					JANUS_LOG(LOG_ERR, "[%s] Video RTP map is uninitialized\n", mp->name);
4012 				else if(strstr(mp->codecs.video_rtpmap, "vp8") || strstr(mp->codecs.video_rtpmap, "VP8"))
4013 					codec = "vp8";
4014 				else if(strstr(mp->codecs.video_rtpmap, "vp9") || strstr(mp->codecs.video_rtpmap, "VP9"))
4015 					codec = "vp9";
4016 				else if(strstr(mp->codecs.video_rtpmap, "h264") || strstr(mp->codecs.video_rtpmap, "H264"))
4017 					codec = "h264";
4018 				else if(strstr(mp->codecs.video_rtpmap, "av1") || strstr(mp->codecs.video_rtpmap, "AV1"))
4019 					codec = "av1";
4020 				else if(strstr(mp->codecs.video_rtpmap, "h265") || strstr(mp->codecs.video_rtpmap, "H265"))
4021 					codec = "h265";
4022 				const char *videofile = json_string_value(video);
4023 				vrc = janus_recorder_create(NULL, codec, (char *)videofile);
4024 				if(vrc == NULL) {
4025 					if(arc != NULL) {
4026 						janus_recorder_close(arc);
4027 						janus_recorder_destroy(arc);
4028 						arc = NULL;
4029 					}
4030 					JANUS_LOG(LOG_ERR, "[%s] Error starting recorder for video\n", mp->name);
4031 					janus_refcount_decrease(&mp->ref);
4032 					janus_mutex_unlock(&mountpoints_mutex);
4033 					error_code = JANUS_STREAMING_ERROR_CANT_RECORD;
4034 					g_snprintf(error_cause, 512, "Error starting recorder for video");
4035 					goto prepare_response;
4036 				}
4037 				/* If media is encrypted, mark it in the recording */
4038 				if(source->e2ee)
4039 					janus_recorder_encrypted(vrc);
4040 				JANUS_LOG(LOG_INFO, "[%s] Video recording started\n", mp->name);
4041 			}
4042 			if(data) {
4043 				const char *datafile = json_string_value(data);
4044 				drc = janus_recorder_create(NULL, "text", (char *)datafile);
4045 				if(drc == NULL) {
4046 					if(arc != NULL) {
4047 						janus_recorder_close(arc);
4048 						janus_recorder_destroy(arc);
4049 						arc = NULL;
4050 					}
4051 					if(vrc != NULL) {
4052 						janus_recorder_close(vrc);
4053 						janus_recorder_destroy(vrc);
4054 						vrc = NULL;
4055 					}
4056 					JANUS_LOG(LOG_ERR, "[%s] Error starting recorder for data\n", mp->name);
4057 					janus_refcount_decrease(&mp->ref);
4058 					janus_mutex_unlock(&mountpoints_mutex);
4059 					error_code = JANUS_STREAMING_ERROR_CANT_RECORD;
4060 					g_snprintf(error_cause, 512, "Error starting recorder for data");
4061 					goto prepare_response;
4062 				}
4063 				JANUS_LOG(LOG_INFO, "[%s] Data recording started\n", mp->name);
4064 			}
4065 			if(arc != NULL)
4066 				source->arc = arc;
4067 			if(vrc != NULL)
4068 				source->vrc = vrc;
4069 			if(drc != NULL)
4070 				source->drc = drc;
4071 			janus_refcount_decrease(&mp->ref);
4072 			janus_mutex_unlock(&mountpoints_mutex);
4073 			/* Send a success response back */
4074 			response = json_object();
4075 			json_object_set_new(response, "streaming", json_string("ok"));
4076 			goto prepare_response;
4077 		} else if(!strcasecmp(action_text, "stop")) {
4078 			/* Stop the recording */
4079 			JANUS_VALIDATE_JSON_OBJECT(root, recording_stop_parameters,
4080 				error_code, error_cause, TRUE,
4081 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4082 			if(error_code != 0) {
4083 				janus_mutex_unlock(&mountpoints_mutex);
4084 				goto prepare_response;
4085 			}
4086 			json_t *audio = json_object_get(root, "audio");
4087 			json_t *video = json_object_get(root, "video");
4088 			json_t *data = json_object_get(root, "data");
4089 			if(!audio && !video) {
4090 				janus_mutex_unlock(&mountpoints_mutex);
4091 				JANUS_LOG(LOG_ERR, "Missing audio and/or video\n");
4092 				error_code = JANUS_STREAMING_ERROR_INVALID_REQUEST;
4093 				g_snprintf(error_cause, 512, "Missing audio and/or video");
4094 				goto prepare_response;
4095 			}
4096 			janus_mutex_lock(&source->rec_mutex);
4097 			if(audio && json_is_true(audio) && source->arc) {
4098 				/* Close the audio recording */
4099 				janus_recorder_close(source->arc);
4100 				JANUS_LOG(LOG_INFO, "[%s] Closed audio recording %s\n", mp->name, source->arc->filename ? source->arc->filename : "??");
4101 				janus_recorder *tmp = source->arc;
4102 				source->arc = NULL;
4103 				janus_recorder_destroy(tmp);
4104 			}
4105 			if(video && json_is_true(video) && source->vrc) {
4106 				/* Close the video recording */
4107 				janus_recorder_close(source->vrc);
4108 				JANUS_LOG(LOG_INFO, "[%s] Closed video recording %s\n", mp->name, source->vrc->filename ? source->vrc->filename : "??");
4109 				janus_recorder *tmp = source->vrc;
4110 				source->vrc = NULL;
4111 				janus_recorder_destroy(tmp);
4112 			}
4113 			if(data && json_is_true(data) && source->drc) {
4114 				/* Close the data recording */
4115 				janus_recorder_close(source->drc);
4116 				JANUS_LOG(LOG_INFO, "[%s] Closed data recording %s\n", mp->name, source->drc->filename ? source->drc->filename : "??");
4117 				janus_recorder *tmp = source->drc;
4118 				source->drc = NULL;
4119 				janus_recorder_destroy(tmp);
4120 			}
4121 			janus_mutex_unlock(&source->rec_mutex);
4122 			janus_refcount_decrease(&mp->ref);
4123 			janus_mutex_unlock(&mountpoints_mutex);
4124 			/* Send a success response back */
4125 			response = json_object();
4126 			json_object_set_new(response, "streaming", json_string("ok"));
4127 			goto prepare_response;
4128 		}
4129 	} else if(!strcasecmp(request_text, "enable") || !strcasecmp(request_text, "disable")) {
4130 		/* A request to enable/disable a mountpoint */
4131 		if(!string_ids) {
4132 			JANUS_VALIDATE_JSON_OBJECT(root, id_parameters,
4133 				error_code, error_cause, TRUE,
4134 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4135 		} else {
4136 			JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters,
4137 				error_code, error_cause, TRUE,
4138 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4139 		}
4140 		if(error_code != 0)
4141 			goto prepare_response;
4142 		json_t *id = json_object_get(root, "id");
4143 		guint64 id_value = 0;
4144 		char id_num[30], *id_value_str = NULL;
4145 		if(!string_ids) {
4146 			id_value = json_integer_value(id);
4147 			g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id_value);
4148 			id_value_str = id_num;
4149 		} else {
4150 			id_value_str = (char *)json_string_value(id);
4151 		}
4152 		janus_mutex_lock(&mountpoints_mutex);
4153 		janus_streaming_mountpoint *mp = g_hash_table_lookup(mountpoints,
4154 			string_ids ? (gpointer)id_value_str : (gpointer)&id_value);
4155 		if(mp == NULL) {
4156 			janus_mutex_unlock(&mountpoints_mutex);
4157 			JANUS_LOG(LOG_VERB, "No such mountpoint/stream %s\n", id_value_str);
4158 			error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
4159 			g_snprintf(error_cause, 512, "No such mountpoint/stream %s", id_value_str);
4160 			goto prepare_response;
4161 		}
4162 		janus_refcount_increase(&mp->ref);
4163 		/* A secret may be required for this action */
4164 		JANUS_CHECK_SECRET(mp->secret, root, "secret", error_code, error_cause,
4165 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT, JANUS_STREAMING_ERROR_UNAUTHORIZED);
4166 		if(error_code != 0) {
4167 			janus_refcount_decrease(&mp->ref);
4168 			janus_mutex_unlock(&mountpoints_mutex);
4169 			goto prepare_response;
4170 		}
4171 		if(!strcasecmp(request_text, "enable")) {
4172 			/* Enable a previously disabled mountpoint */
4173 			JANUS_LOG(LOG_INFO, "[%s] Stream enabled\n", mp->name);
4174 			mp->enabled = TRUE;
4175 			/* FIXME: Should we notify the viewers, or is this up to the controller application? */
4176 		} else {
4177 			/* Disable a previously enabled mountpoint */
4178 			JANUS_VALIDATE_JSON_OBJECT(root, disable_parameters,
4179 				error_code, error_cause, TRUE,
4180 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4181 			if(error_code != 0) {
4182 				janus_refcount_decrease(&mp->ref);
4183 				janus_mutex_unlock(&mountpoints_mutex);
4184 				goto prepare_response;
4185 			}
4186 			mp->enabled = FALSE;
4187 			gboolean stop_recording = TRUE;
4188 			json_t *stop_rec = json_object_get(root, "stop_recording");
4189 			if (stop_rec) {
4190 				stop_recording = json_is_true(stop_rec);
4191 			}
4192 			JANUS_LOG(LOG_INFO, "[%s] Stream disabled (stop_recording=%s)\n", mp->name, stop_recording ? "yes" : "no");
4193 			/* Any recording to close? */
4194 			if(mp->streaming_source == janus_streaming_source_rtp && stop_recording) {
4195 				janus_streaming_rtp_source *source = mp->source;
4196 				janus_mutex_lock(&source->rec_mutex);
4197 				if(source->arc) {
4198 					janus_recorder_close(source->arc);
4199 					JANUS_LOG(LOG_INFO, "[%s] Closed audio recording %s\n", mp->name, source->arc->filename ? source->arc->filename : "??");
4200 					janus_recorder *tmp = source->arc;
4201 					source->arc = NULL;
4202 					janus_recorder_destroy(tmp);
4203 				}
4204 				if(source->vrc) {
4205 					janus_recorder_close(source->vrc);
4206 					JANUS_LOG(LOG_INFO, "[%s] Closed video recording %s\n", mp->name, source->vrc->filename ? source->vrc->filename : "??");
4207 					janus_recorder *tmp = source->vrc;
4208 					source->vrc = NULL;
4209 					janus_recorder_destroy(tmp);
4210 				}
4211 				if(source->drc) {
4212 					janus_recorder_close(source->drc);
4213 					JANUS_LOG(LOG_INFO, "[%s] Closed data recording %s\n", mp->name, source->drc->filename ? source->drc->filename : "??");
4214 					janus_recorder *tmp = source->drc;
4215 					source->drc = NULL;
4216 					janus_recorder_destroy(tmp);
4217 				}
4218 				janus_mutex_unlock(&source->rec_mutex);
4219 			}
4220 			/* FIXME: Should we notify the viewers, or is this up to the controller application? */
4221 		}
4222 		janus_refcount_decrease(&mp->ref);
4223 		janus_mutex_unlock(&mountpoints_mutex);
4224 		/* Send a success response back */
4225 		response = json_object();
4226 		json_object_set_new(response, "streaming", json_string("ok"));
4227 		goto prepare_response;
4228 	} else {
4229 		/* Not a request we recognize, don't do anything */
4230 		return NULL;
4231 	}
4232 
4233 prepare_response:
4234 		{
4235 			if(ifas) {
4236 				freeifaddrs(ifas);
4237 			}
4238 
4239 			if(error_code == 0 && !response) {
4240 				error_code = JANUS_STREAMING_ERROR_UNKNOWN_ERROR;
4241 				g_snprintf(error_cause, 512, "Invalid response");
4242 			}
4243 			if(error_code != 0) {
4244 				/* Prepare JSON error event */
4245 				response = json_object();
4246 				json_object_set_new(response, "streaming", json_string("event"));
4247 				json_object_set_new(response, "error_code", json_integer(error_code));
4248 				json_object_set_new(response, "error", json_string(error_cause));
4249 			}
4250 			return response;
4251 		}
4252 
4253 }
4254 
4255 struct janus_plugin_result *janus_streaming_handle_message(janus_plugin_session *handle, char *transaction, json_t *message, json_t *jsep) {
4256 	if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
4257 		return janus_plugin_result_new(JANUS_PLUGIN_ERROR, g_atomic_int_get(&stopping) ? "Shutting down" : "Plugin not initialized", NULL);
4258 
4259 	/* Pre-parse the message */
4260 	int error_code = 0;
4261 	char error_cause[512];
4262 	json_t *root = message;
4263 	json_t *response = NULL;
4264 
4265 	janus_mutex_lock(&sessions_mutex);
4266 	janus_streaming_session *session = janus_streaming_lookup_session(handle);
4267 	if(!session) {
4268 		janus_mutex_unlock(&sessions_mutex);
4269 		JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
4270 		error_code = JANUS_STREAMING_ERROR_UNKNOWN_ERROR;
4271 		g_snprintf(error_cause, 512, "%s", "No session associated with this handle...");
4272 		goto plugin_response;
4273 	}
4274 	/* Increase the reference counter for this session: we'll decrease it after we handle the message */
4275 	janus_refcount_increase(&session->ref);
4276 	janus_mutex_unlock(&sessions_mutex);
4277 	if(g_atomic_int_get(&session->destroyed)) {
4278 		JANUS_LOG(LOG_ERR, "Session has already been destroyed...\n");
4279 		error_code = JANUS_STREAMING_ERROR_UNKNOWN_ERROR;
4280 		g_snprintf(error_cause, 512, "%s", "Session has already been destroyed...");
4281 		goto plugin_response;
4282 	}
4283 
4284 	if(message == NULL) {
4285 		JANUS_LOG(LOG_ERR, "No message??\n");
4286 		error_code = JANUS_STREAMING_ERROR_NO_MESSAGE;
4287 		g_snprintf(error_cause, 512, "%s", "No message??");
4288 		goto plugin_response;
4289 	}
4290 	if(!json_is_object(root)) {
4291 		JANUS_LOG(LOG_ERR, "JSON error: not an object\n");
4292 		error_code = JANUS_STREAMING_ERROR_INVALID_JSON;
4293 		g_snprintf(error_cause, 512, "JSON error: not an object");
4294 		goto plugin_response;
4295 	}
4296 	/* Get the request first */
4297 	JANUS_VALIDATE_JSON_OBJECT(root, request_parameters,
4298 		error_code, error_cause, TRUE,
4299 		JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4300 	if(error_code != 0)
4301 		goto plugin_response;
4302 	json_t *request = json_object_get(root, "request");
4303 	/* Some requests ('create' and 'destroy') can be handled synchronously */
4304 	const char *request_text = json_string_value(request);
4305 	/* We have a separate method to process synchronous requests, as those may
4306 	 * arrive from the Admin API as well, and so we handle them the same way */
4307 	response = janus_streaming_process_synchronous_request(session, root);
4308 	if(response != NULL) {
4309 		/* We got a response, send it back */
4310 		goto plugin_response;
4311 	} else if(!strcasecmp(request_text, "watch") || !strcasecmp(request_text, "start")
4312 			|| !strcasecmp(request_text, "pause") || !strcasecmp(request_text, "stop")
4313 			|| !strcasecmp(request_text, "configure") || !strcasecmp(request_text, "switch")) {
4314 		/* These messages are handled asynchronously */
4315 		janus_streaming_message *msg = g_malloc(sizeof(janus_streaming_message));
4316 		msg->handle = handle;
4317 		msg->transaction = transaction;
4318 		msg->message = root;
4319 		msg->jsep = jsep;
4320 
4321 		g_async_queue_push(messages, msg);
4322 		return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL, NULL);
4323 	} else {
4324 		JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
4325 		error_code = JANUS_STREAMING_ERROR_INVALID_REQUEST;
4326 		g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
4327 	}
4328 
4329 plugin_response:
4330 		{
4331 			if(error_code == 0 && !response) {
4332 				error_code = JANUS_STREAMING_ERROR_UNKNOWN_ERROR;
4333 				g_snprintf(error_cause, 512, "Invalid response");
4334 			}
4335 			if(error_code != 0) {
4336 				/* Prepare JSON error event */
4337 				json_t *event = json_object();
4338 				json_object_set_new(event, "streaming", json_string("event"));
4339 				json_object_set_new(event, "error_code", json_integer(error_code));
4340 				json_object_set_new(event, "error", json_string(error_cause));
4341 				response = event;
4342 			}
4343 			if(root != NULL)
4344 				json_decref(root);
4345 			if(jsep != NULL)
4346 				json_decref(jsep);
4347 			g_free(transaction);
4348 
4349 			if(session != NULL)
4350 				janus_refcount_decrease(&session->ref);
4351 			return janus_plugin_result_new(JANUS_PLUGIN_OK, NULL, response);
4352 		}
4353 
4354 }
4355 
4356 json_t *janus_streaming_handle_admin_message(json_t *message) {
4357 	/* Some requests (e.g., 'create' and 'destroy') can be handled via Admin API */
4358 	int error_code = 0;
4359 	char error_cause[512];
4360 	json_t *response = NULL;
4361 
4362 	JANUS_VALIDATE_JSON_OBJECT(message, request_parameters,
4363 		error_code, error_cause, TRUE,
4364 		JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4365 	if(error_code != 0)
4366 		goto admin_response;
4367 	json_t *request = json_object_get(message, "request");
4368 	const char *request_text = json_string_value(request);
4369 	if((response = janus_streaming_process_synchronous_request(NULL, message)) != NULL) {
4370 		/* We got a response, send it back */
4371 		goto admin_response;
4372 	} else {
4373 		JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
4374 		error_code = JANUS_STREAMING_ERROR_INVALID_REQUEST;
4375 		g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
4376 	}
4377 
4378 admin_response:
4379 		{
4380 			if(!response) {
4381 				/* Prepare JSON error event */
4382 				response = json_object();
4383 				json_object_set_new(response, "streaming", json_string("event"));
4384 				json_object_set_new(response, "error_code", json_integer(error_code));
4385 				json_object_set_new(response, "error", json_string(error_cause));
4386 			}
4387 			return response;
4388 		}
4389 
4390 }
4391 
4392 void janus_streaming_setup_media(janus_plugin_session *handle) {
4393 	JANUS_LOG(LOG_INFO, "[%s-%p] WebRTC media is now available\n", JANUS_STREAMING_PACKAGE, handle);
4394 	if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
4395 		return;
4396 	janus_mutex_lock(&sessions_mutex);
4397 	janus_streaming_session *session = janus_streaming_lookup_session(handle);
4398 	if(!session) {
4399 		janus_mutex_unlock(&sessions_mutex);
4400 		JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
4401 		return;
4402 	}
4403 	if(g_atomic_int_get(&session->destroyed)) {
4404 		janus_mutex_unlock(&sessions_mutex);
4405 		return;
4406 	}
4407 	janus_refcount_increase(&session->ref);
4408 	janus_mutex_unlock(&sessions_mutex);
4409 	g_atomic_int_set(&session->hangingup, 0);
4410 	/* We only start streaming towards this user when we get this event */
4411 	janus_rtp_switching_context_reset(&session->context);
4412 	/* If this is related to a live RTP mountpoint, any keyframe we can shoot already? */
4413 	janus_streaming_mountpoint *mountpoint = session->mountpoint;
4414 	if (!mountpoint) {
4415 		janus_refcount_decrease(&session->ref);
4416 		JANUS_LOG(LOG_ERR, "No mountpoint associated with this session...\n");
4417 		return;
4418 	}
4419 	if(mountpoint->streaming_source == janus_streaming_source_rtp) {
4420 		janus_streaming_rtp_source *source = mountpoint->source;
4421 		if(source->keyframe.enabled) {
4422 			JANUS_LOG(LOG_HUGE, "Any keyframe to send?\n");
4423 			janus_mutex_lock(&source->keyframe.mutex);
4424 			if(source->keyframe.latest_keyframe != NULL) {
4425 				JANUS_LOG(LOG_HUGE, "Yep! %d packets\n", g_list_length(source->keyframe.latest_keyframe));
4426 				GList *temp = source->keyframe.latest_keyframe;
4427 				while(temp) {
4428 					janus_streaming_relay_rtp_packet(session, temp->data);
4429 					temp = temp->next;
4430 				}
4431 			}
4432 			janus_mutex_unlock(&source->keyframe.mutex);
4433 		}
4434 		if(source->buffermsg) {
4435 			JANUS_LOG(LOG_HUGE, "Any recent datachannel message to send?\n");
4436 			janus_mutex_lock(&source->buffermsg_mutex);
4437 			if(source->last_msg != NULL) {
4438 				JANUS_LOG(LOG_HUGE, "Yep!\n");
4439 				janus_streaming_relay_rtp_packet(session, source->last_msg);
4440 			}
4441 			janus_mutex_unlock(&source->buffermsg_mutex);
4442 		}
4443 		/* If this mountpoint has RTCP support, send a PLI */
4444 		janus_streaming_rtcp_pli_send(source);
4445 	}
4446 	g_atomic_int_set(&session->started, 1);
4447 	/* Prepare JSON event */
4448 	json_t *event = json_object();
4449 	json_object_set_new(event, "streaming", json_string("event"));
4450 	json_t *result = json_object();
4451 	json_object_set_new(result, "status", json_string("started"));
4452 	json_object_set_new(event, "result", result);
4453 	int ret = gateway->push_event(handle, &janus_streaming_plugin, NULL, event, NULL);
4454 	JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (%s)\n", ret, janus_get_api_error(ret));
4455 	json_decref(event);
4456 	janus_refcount_decrease(&session->ref);
4457 }
4458 
4459 void janus_streaming_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *packet) {
4460 	if(handle == NULL || g_atomic_int_get(&handle->stopped) || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
4461 		return;
4462 	/* FIXME We don't care about what the browser sends us, we're sendonly */
4463 }
4464 
4465 void janus_streaming_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp *packet) {
4466 	if(handle == NULL || g_atomic_int_get(&handle->stopped) || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
4467 		return;
4468 	janus_streaming_session *session = (janus_streaming_session *)handle->plugin_handle;
4469 	if(!session || g_atomic_int_get(&session->destroyed) || g_atomic_int_get(&session->stopping) ||
4470 			!g_atomic_int_get(&session->started) || g_atomic_int_get(&session->paused))
4471 		return;
4472 	janus_streaming_mountpoint *mp = (janus_streaming_mountpoint *)session->mountpoint;
4473 	if(mp->streaming_source != janus_streaming_source_rtp)
4474 		return;
4475 	janus_streaming_rtp_source *source = (janus_streaming_rtp_source *)mp->source;
4476 	gboolean video = packet->video;
4477 	char *buf = packet->buffer;
4478 	uint16_t len = packet->length;
4479 	if(!video && (source->audio_rtcp_fd > -1) && (source->audio_rtcp_addr.ss_family != 0)) {
4480 		JANUS_LOG(LOG_HUGE, "Got audio RTCP feedback from a viewer: SSRC %"SCNu32"\n",
4481 			janus_rtcp_get_sender_ssrc(buf, len));
4482 		/* FIXME We don't forward RR packets, so what should we check here? */
4483 	} else if(video && (source->video_rtcp_fd > -1) && (source->video_rtcp_addr.ss_family != 0)) {
4484 		JANUS_LOG(LOG_HUGE, "Got video RTCP feedback from a viewer: SSRC %"SCNu32"\n",
4485 			janus_rtcp_get_sender_ssrc(buf, len));
4486 		/* We only relay PLI/FIR and REMB packets, but in a selective way */
4487 		if(janus_rtcp_has_fir(buf, len) || janus_rtcp_has_pli(buf, len)) {
4488 			/* We got a PLI/FIR, pass it along unless we just sent one */
4489 			JANUS_LOG(LOG_HUGE, "  -- Keyframe request\n");
4490 			janus_streaming_rtcp_pli_send(source);
4491 		}
4492 		uint64_t bw = janus_rtcp_get_remb(buf, len);
4493 		if(bw > 0) {
4494 			/* Keep track of this value, if this is the lowest right now */
4495 			JANUS_LOG(LOG_HUGE, "  -- REMB for this PeerConnection: %"SCNu64"\n", bw);
4496 			if((0 == source->lowest_bitrate) || (source->lowest_bitrate > bw))
4497 				source->lowest_bitrate = bw;
4498 		}
4499 	}
4500 }
4501 
4502 void janus_streaming_data_ready(janus_plugin_session *handle) {
4503 	if(handle == NULL || g_atomic_int_get(&handle->stopped) ||
4504 			g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized) || !gateway)
4505 		return;
4506 	/* Data channels are writable: we shouldn't send any datachannel message before this happens */
4507 	janus_streaming_session *session = (janus_streaming_session *)handle->plugin_handle;
4508 	if(!session || g_atomic_int_get(&session->destroyed) || g_atomic_int_get(&session->hangingup))
4509 		return;
4510 	if(g_atomic_int_compare_and_exchange(&session->dataready, 0, 1)) {
4511 		JANUS_LOG(LOG_INFO, "[%s-%p] Data channel available\n", JANUS_STREAMING_PACKAGE, handle);
4512 	}
4513 }
4514 
4515 void janus_streaming_hangup_media(janus_plugin_session *handle) {
4516 	JANUS_LOG(LOG_INFO, "[%s-%p] No WebRTC media anymore\n", JANUS_STREAMING_PACKAGE, handle);
4517 	janus_mutex_lock(&sessions_mutex);
4518 	janus_streaming_hangup_media_internal(handle);
4519 	janus_mutex_unlock(&sessions_mutex);
4520 }
4521 
4522 static void janus_streaming_hangup_media_internal(janus_plugin_session *handle) {
4523 	if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
4524 		return;
4525 	janus_streaming_session *session = janus_streaming_lookup_session(handle);
4526 	if(!session) {
4527 		JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
4528 		return;
4529 	}
4530 	if(g_atomic_int_get(&session->destroyed))
4531 		return;
4532 	if(!g_atomic_int_compare_and_exchange(&session->hangingup, 0, 1))
4533 		return;
4534 	g_atomic_int_set(&session->dataready, 0);
4535 	g_atomic_int_set(&session->stopping, 1);
4536 	g_atomic_int_set(&session->started, 0);
4537 	g_atomic_int_set(&session->paused, 0);
4538 	session->audio_pt = -1;
4539 	session->video_pt = -1;
4540 	janus_rtp_switching_context_reset(&session->context);
4541 	janus_rtp_simulcasting_context_reset(&session->sim_context);
4542 	janus_vp8_simulcast_context_reset(&session->vp8_context);
4543 	session->spatial_layer = -1;
4544 	session->target_spatial_layer = 2;	/* FIXME Chrome sends 0, 1 and 2 (if using EnabledByFlag_3SL3TL) */
4545 	session->last_spatial_layer[0] = 0;
4546 	session->last_spatial_layer[1] = 0;
4547 	session->last_spatial_layer[2] = 0;
4548 	session->temporal_layer = -1;
4549 	session->target_temporal_layer = 2;	/* FIXME Chrome sends 0, 1 and 2 */
4550 	session->e2ee = FALSE;
4551 	janus_mutex_lock(&session->mutex);
4552 	janus_streaming_mountpoint *mp = session->mountpoint;
4553 	session->mountpoint = NULL;
4554 	janus_mutex_unlock(&session->mutex);
4555 	if(mp) {
4556 		janus_mutex_lock(&mp->mutex);
4557 		JANUS_LOG(LOG_VERB, "  -- Removing the session from the mountpoint viewers\n");
4558 		if(g_list_find(mp->viewers, session) != NULL) {
4559 			JANUS_LOG(LOG_VERB, "  -- -- Found!\n");
4560 			janus_refcount_decrease(&mp->ref);
4561 			janus_refcount_decrease(&session->ref);
4562 		}
4563 		mp->viewers = g_list_remove_all(mp->viewers, session);
4564 		if(mp->streaming_source == janus_streaming_source_rtp) {
4565 			/* Remove the viewer from the helper threads too, if any */
4566 			if(mp->helper_threads > 0) {
4567 				GList *l = mp->threads;
4568 				while(l) {
4569 					janus_streaming_helper *ht = (janus_streaming_helper *)l->data;
4570 					janus_mutex_lock(&ht->mutex);
4571 					if(g_list_find(ht->viewers, session) != NULL) {
4572 						ht->num_viewers--;
4573 						ht->viewers = g_list_remove_all(ht->viewers, session);
4574 						janus_mutex_unlock(&ht->mutex);
4575 						JANUS_LOG(LOG_VERB, "Removing viewer from helper thread #%d\n", ht->id);
4576 						break;
4577 					}
4578 					janus_mutex_unlock(&ht->mutex);
4579 					l = l->next;
4580 				}
4581 			}
4582 		}
4583 		janus_mutex_unlock(&mp->mutex);
4584 	}
4585 	g_atomic_int_set(&session->hangingup, 0);
4586 }
4587 
4588 /* Thread to handle incoming messages */
4589 static void *janus_streaming_handler(void *data) {
4590 	JANUS_LOG(LOG_VERB, "Joining Streaming handler thread\n");
4591 	janus_streaming_message *msg = NULL;
4592 	int error_code = 0;
4593 	char error_cause[512];
4594 	json_t *root = NULL;
4595 	while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
4596 		msg = g_async_queue_pop(messages);
4597 		if(msg == &exit_message)
4598 			break;
4599 		if(msg->handle == NULL) {
4600 			janus_streaming_message_free(msg);
4601 			continue;
4602 		}
4603 		janus_mutex_lock(&sessions_mutex);
4604 		janus_streaming_session *session = janus_streaming_lookup_session(msg->handle);
4605 		if(!session) {
4606 			janus_mutex_unlock(&sessions_mutex);
4607 			JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
4608 			janus_streaming_message_free(msg);
4609 			continue;
4610 		}
4611 		if(g_atomic_int_get(&session->destroyed)) {
4612 			janus_mutex_unlock(&sessions_mutex);
4613 			janus_streaming_message_free(msg);
4614 			continue;
4615 		}
4616 		janus_mutex_unlock(&sessions_mutex);
4617 		/* Handle request */
4618 		error_code = 0;
4619 		root = NULL;
4620 		if(msg->message == NULL) {
4621 			JANUS_LOG(LOG_ERR, "No message??\n");
4622 			error_code = JANUS_STREAMING_ERROR_NO_MESSAGE;
4623 			g_snprintf(error_cause, 512, "%s", "No message??");
4624 			goto error;
4625 		}
4626 		root = msg->message;
4627 		/* Get the request first */
4628 		JANUS_VALIDATE_JSON_OBJECT(root, request_parameters,
4629 			error_code, error_cause, TRUE,
4630 			JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4631 		if(error_code != 0)
4632 			goto error;
4633 		json_t *request = json_object_get(root, "request");
4634 		const char *request_text = json_string_value(request);
4635 		json_t *result = NULL;
4636 		const char *sdp_type = NULL;
4637 		char *sdp = NULL;
4638 		gboolean do_restart = FALSE;
4639 		/* All these requests can only be handled asynchronously */
4640 		if(!strcasecmp(request_text, "watch")) {
4641 			JANUS_VALIDATE_JSON_OBJECT(root, watch_parameters,
4642 				error_code, error_cause, TRUE,
4643 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4644 			if(error_code != 0)
4645 				goto error;
4646 			if(!string_ids) {
4647 				JANUS_VALIDATE_JSON_OBJECT(root, id_parameters,
4648 					error_code, error_cause, TRUE,
4649 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4650 			} else {
4651 				JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters,
4652 					error_code, error_cause, TRUE,
4653 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4654 			}
4655 			if(error_code != 0)
4656 				goto error;
4657 			json_t *id = json_object_get(root, "id");
4658 			guint64 id_value = 0;
4659 			char id_num[30], *id_value_str = NULL;
4660 			if(!string_ids) {
4661 				id_value = json_integer_value(id);
4662 				g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id_value);
4663 				id_value_str = id_num;
4664 			} else {
4665 				id_value_str = (char *)json_string_value(id);
4666 			}
4667 			json_t *offer_audio = json_object_get(root, "offer_audio");
4668 			json_t *offer_video = json_object_get(root, "offer_video");
4669 			json_t *offer_data = json_object_get(root, "offer_data");
4670 			json_t *restart = json_object_get(root, "restart");
4671 			do_restart = restart ? json_is_true(restart) : FALSE;
4672 			janus_mutex_lock(&mountpoints_mutex);
4673 			janus_streaming_mountpoint *mp = g_hash_table_lookup(mountpoints,
4674 				string_ids ? (gpointer)id_value_str : (gpointer)&id_value);
4675 			if(mp == NULL) {
4676 				janus_mutex_unlock(&mountpoints_mutex);
4677 				JANUS_LOG(LOG_VERB, "No such mountpoint/stream %s\n", id_value_str);
4678 				error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
4679 				g_snprintf(error_cause, 512, "No such mountpoint/stream %s", id_value_str);
4680 				goto error;
4681 			}
4682 			janus_refcount_increase(&mp->ref);
4683 			/* A secret may be required for this action */
4684 			JANUS_CHECK_SECRET(mp->pin, root, "pin", error_code, error_cause,
4685 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT, JANUS_STREAMING_ERROR_UNAUTHORIZED);
4686 			if(error_code != 0) {
4687 				janus_refcount_decrease(&mp->ref);
4688 				janus_mutex_unlock(&mountpoints_mutex);
4689 				goto error;
4690 			}
4691 			janus_mutex_lock(&mp->mutex);
4692 			janus_mutex_lock(&session->mutex);
4693 			janus_mutex_unlock(&mountpoints_mutex);
4694 			/* Check if this is a new viewer, or if an update is taking place (i.e., ICE restart) */
4695 			if(do_restart) {
4696 				/* User asked for an ICE restart: provide a new offer */
4697 				if(!g_atomic_int_compare_and_exchange(&session->renegotiating, 0, 1)) {
4698 					/* Already triggered a renegotiation, and still waiting for an answer */
4699 					janus_mutex_unlock(&session->mutex);
4700 					janus_mutex_unlock(&mp->mutex);
4701 					JANUS_LOG(LOG_ERR, "Already renegotiating mountpoint %s\n", session->mountpoint->id_str);
4702 					error_code = JANUS_STREAMING_ERROR_INVALID_STATE;
4703 					g_snprintf(error_cause, 512, "Already renegotiating mountpoint %s", session->mountpoint->id_str);
4704 					janus_refcount_decrease(&mp->ref);
4705 					goto error;
4706 				}
4707 				janus_refcount_decrease(&mp->ref);
4708 				JANUS_LOG(LOG_VERB, "Request to perform an ICE restart on mountpoint/stream %s subscription\n", id_value_str);
4709 				session->sdp_version++;	/* This needs to be increased when it changes */
4710 				goto done;
4711 			}
4712 			if(session->mountpoint != NULL) {
4713 				if(session->mountpoint != mp) {
4714 					/* Already watching something else */
4715 					janus_refcount_decrease(&mp->ref);
4716 					JANUS_LOG(LOG_ERR, "Already watching mountpoint %s\n", session->mountpoint->id_str);
4717 					error_code = JANUS_STREAMING_ERROR_INVALID_STATE;
4718 					g_snprintf(error_cause, 512, "Already watching mountpoint %s", session->mountpoint->id_str);
4719 					janus_mutex_unlock(&session->mutex);
4720 					janus_mutex_unlock(&mp->mutex);
4721 					goto error;
4722 				} else {
4723 					/* Make sure it's not an API error */
4724 					if(!g_atomic_int_get(&session->started)) {
4725 						/* Can't be a renegotiation, PeerConnection isn't up yet */
4726 						JANUS_LOG(LOG_ERR, "Already watching mountpoint %s\n", session->mountpoint->id_str);
4727 						error_code = JANUS_STREAMING_ERROR_INVALID_STATE;
4728 						g_snprintf(error_cause, 512, "Already watching mountpoint %s", session->mountpoint->id_str);
4729 						janus_refcount_decrease(&mp->ref);
4730 						janus_mutex_unlock(&session->mutex);
4731 						janus_mutex_unlock(&mp->mutex);
4732 						goto error;
4733 					}
4734 					if(!g_atomic_int_compare_and_exchange(&session->renegotiating, 0, 1)) {
4735 						/* Already triggered a renegotiation, and still waiting for an answer */
4736 						JANUS_LOG(LOG_ERR, "Already renegotiating mountpoint %s\n", session->mountpoint->id_str);
4737 						error_code = JANUS_STREAMING_ERROR_INVALID_STATE;
4738 						g_snprintf(error_cause, 512, "Already renegotiating mountpoint %s", session->mountpoint->id_str);
4739 						janus_refcount_decrease(&mp->ref);
4740 						janus_mutex_unlock(&session->mutex);
4741 						janus_mutex_unlock(&mp->mutex);
4742 						goto error;
4743 					}
4744 					/* Simple renegotiation, remove the extra uneeded reference */
4745 					janus_refcount_decrease(&mp->ref);
4746 					JANUS_LOG(LOG_VERB, "Request to update mountpoint/stream %s subscription (no restart)\n", id_value_str);
4747 					session->sdp_version++;	/* This needs to be increased when it changes */
4748 					goto done;
4749 				}
4750 			}
4751 			/* New viewer: we send an offer ourselves */
4752 			JANUS_LOG(LOG_VERB, "Request to watch mountpoint/stream %s\n", id_value_str);
4753 			if(session->mountpoint != NULL || g_list_find(mp->viewers, session) != NULL) {
4754 				janus_mutex_unlock(&session->mutex);
4755 				janus_mutex_unlock(&mp->mutex);
4756 				janus_refcount_decrease(&mp->ref);
4757 				JANUS_LOG(LOG_ERR, "Already watching a stream...\n");
4758 				error_code = JANUS_STREAMING_ERROR_UNKNOWN_ERROR;
4759 				g_snprintf(error_cause, 512, "Already watching a stream");
4760 				goto error;
4761 			}
4762 			g_atomic_int_set(&session->stopping, 0);
4763 			session->mountpoint = mp;
4764 			session->sdp_version = 1;	/* This needs to be increased when it changes */
4765 			session->sdp_sessid = janus_get_real_time();
4766 			/* Check what we should offer */
4767 			session->audio = offer_audio ? json_is_true(offer_audio) : TRUE;	/* True by default */
4768 			if(!mp->audio)
4769 				session->audio = FALSE;	/* ... unless the mountpoint isn't sending any audio */
4770 			session->video = offer_video ? json_is_true(offer_video) : TRUE;	/* True by default */
4771 			if(!mp->video)
4772 				session->video = FALSE;	/* ... unless the mountpoint isn't sending any video */
4773 			session->data = offer_data ? json_is_true(offer_data) : TRUE;	/* True by default */
4774 			if(!mp->data)
4775 				session->data = FALSE;	/* ... unless the mountpoint isn't sending any data */
4776 			if((!mp->audio || !session->audio) &&
4777 					(!mp->video || !session->video) &&
4778 					(!mp->data || !session->data)) {
4779 				session->mountpoint = NULL;
4780 				janus_mutex_unlock(&session->mutex);
4781 				janus_mutex_unlock(&mp->mutex);
4782 				janus_refcount_decrease(&mp->ref);
4783 				JANUS_LOG(LOG_ERR, "Can't offer an SDP with no audio, video or data for this mountpoint\n");
4784 				error_code = JANUS_STREAMING_ERROR_INVALID_REQUEST;
4785 				g_snprintf(error_cause, 512, "Can't offer an SDP with no audio, video or data for this mountpoint");
4786 				goto error;
4787 			}
4788 			if(mp->streaming_type == janus_streaming_type_on_demand) {
4789 				GError *error = NULL;
4790 				char tname[16];
4791 				g_snprintf(tname, sizeof(tname), "mp %s", mp->id_str);
4792 				janus_refcount_increase(&session->ref);
4793 				janus_refcount_increase(&mp->ref);
4794 				g_thread_try_new(tname, &janus_streaming_ondemand_thread, session, &error);
4795 				if(error != NULL) {
4796 					session->mountpoint = NULL;
4797 					janus_mutex_unlock(&session->mutex);
4798 					janus_refcount_decrease(&session->ref);	/* This is for the failed thread */
4799 					janus_mutex_unlock(&mp->mutex);
4800 					janus_refcount_decrease(&mp->ref);		/* This is for the failed thread */
4801 					janus_refcount_decrease(&mp->ref);
4802 					JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the on-demand thread...\n",
4803 						error->code, error->message ? error->message : "??");
4804 					error_code = JANUS_STREAMING_ERROR_UNKNOWN_ERROR;
4805 					g_snprintf(error_cause, 512, "Got error %d (%s) trying to launch the on-demand thread",
4806 						error->code, error->message ? error->message : "??");
4807 					g_error_free(error);
4808 					goto error;
4809 				}
4810 			} else if(mp->streaming_source == janus_streaming_source_rtp) {
4811 				janus_streaming_rtp_source *source = (janus_streaming_rtp_source *)mp->source;
4812 				if(source && source->simulcast) {
4813 					JANUS_VALIDATE_JSON_OBJECT(root, simulcast_parameters,
4814 						error_code, error_cause, TRUE,
4815 						JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4816 					if(error_code != 0) {
4817 						session->mountpoint = NULL;
4818 						janus_mutex_unlock(&session->mutex);
4819 						janus_mutex_unlock(&mp->mutex);
4820 						janus_refcount_decrease(&mp->ref);
4821 						goto error;
4822 					}
4823 					/* In case this mountpoint is simulcasting, let's aim high by default */
4824 					janus_rtp_switching_context_reset(&session->context);
4825 					janus_rtp_simulcasting_context_reset(&session->sim_context);
4826 					session->sim_context.substream_target = 2;
4827 					session->sim_context.templayer_target = 2;
4828 					janus_vp8_simulcast_context_reset(&session->vp8_context);
4829 					/* Unless the request contains a target for either layer */
4830 					json_t *substream = json_object_get(root, "substream");
4831 					if(substream) {
4832 						session->sim_context.substream_target = json_integer_value(substream);
4833 						JANUS_LOG(LOG_VERB, "Setting video substream to let through (simulcast): %d (was %d)\n",
4834 							session->sim_context.substream_target, session->sim_context.substream);
4835 					}
4836 					json_t *temporal = json_object_get(root, "temporal");
4837 					if(temporal) {
4838 						session->sim_context.templayer_target = json_integer_value(temporal);
4839 						JANUS_LOG(LOG_VERB, "Setting video temporal layer to let through (simulcast): %d (was %d)\n",
4840 							session->sim_context.templayer_target, session->sim_context.templayer);
4841 					}
4842 					/* Check if we need a custom fallback timer for the substream */
4843 					json_t *fallback = json_object_get(root, "fallback");
4844 					if(fallback) {
4845 						JANUS_LOG(LOG_VERB, "Setting fallback timer (simulcast): %lld (was %"SCNu32")\n",
4846 							json_integer_value(fallback) ? json_integer_value(fallback) : 250000,
4847 							session->sim_context.drop_trigger ? session->sim_context.drop_trigger : 250000);
4848 						session->sim_context.drop_trigger = json_integer_value(fallback);
4849 					}
4850 				} else if(source && source->svc) {
4851 					JANUS_VALIDATE_JSON_OBJECT(root, svc_parameters,
4852 						error_code, error_cause, TRUE,
4853 						JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
4854 					if(error_code != 0) {
4855 						session->mountpoint = NULL;
4856 						janus_mutex_unlock(&session->mutex);
4857 						janus_mutex_unlock(&mp->mutex);
4858 						janus_refcount_decrease(&mp->ref);
4859 						goto error;
4860 					}
4861 					/* In case this mountpoint is doing VP9-SVC, let's aim high by default */
4862 					session->spatial_layer = -1;
4863 					session->target_spatial_layer = 2;	/* FIXME Chrome sends 0, 1 and 2 (if using EnabledByFlag_3SL3TL) */
4864 					session->temporal_layer = -1;
4865 					session->target_temporal_layer = 2;	/* FIXME Chrome sends 0, 1 and 2 */
4866 					/* Unless the request contains a target for either layer */
4867 					json_t *spatial = json_object_get(root, "spatial_layer");
4868 					if(spatial) {
4869 						session->target_spatial_layer = json_integer_value(spatial);
4870 						JANUS_LOG(LOG_VERB, "Setting video spatial layer to let through (SVC): %d (was %d)\n",
4871 							session->target_spatial_layer, session->spatial_layer);
4872 					}
4873 					json_t *temporal = json_object_get(root, "temporal_layer");
4874 					if(temporal) {
4875 						session->target_temporal_layer = json_integer_value(temporal);
4876 						JANUS_LOG(LOG_VERB, "Setting video temporal layer to let through (SVC): %d (was %d)\n",
4877 							session->target_temporal_layer, session->temporal_layer);
4878 					}
4879 				}
4880 				/* Initialize the payload types this subscriber will expect */
4881 				session->audio_pt = -1;
4882 				if(mp->codecs.audio_pt >= 0 && session->audio)
4883 					session->audio_pt = mp->codecs.audio_pt;
4884 				if(mp->codecs.video_pt >= 0 && session->video)
4885 					session->video_pt = mp->codecs.video_pt;
4886 				/* If this mountpoint is broadcasting end-to-end encrypted media,
4887 				 * add the info to the JSEP offer we'll be sending them */
4888 				session->e2ee = source->e2ee;
4889 			}
4890 			janus_refcount_increase(&session->ref);
4891 done:
4892 			/* Let's prepare an offer now, but let's also check if there's something we need to skip */
4893 			sdp_type = "offer";	/* We're always going to do the offer ourselves, never answer */
4894 			char sdptemp[2048];
4895 			memset(sdptemp, 0, 2048);
4896 			gchar buffer[512];
4897 			memset(buffer, 0, 512);
4898 			g_snprintf(buffer, 512,
4899 				"v=0\r\no=%s %"SCNu64" %"SCNu64" IN IP4 127.0.0.1\r\n",
4900 					"-", session->sdp_sessid, session->sdp_version);
4901 			janus_strlcat(sdptemp, buffer, 2048);
4902 			g_snprintf(buffer, 512,
4903 				"s=Mountpoint %s\r\n", mp->id_str);
4904 			janus_strlcat(sdptemp, buffer, 2048);
4905 			janus_strlcat(sdptemp, "t=0 0\r\n", 2048);
4906 			if(mp->codecs.audio_pt >= 0 && session->audio) {
4907 				int pt = session->audio_pt >= 0 ? session->audio_pt : mp->codecs.audio_pt;
4908 				/* Add audio line */
4909 				g_snprintf(buffer, 512,
4910 					"m=audio 1 RTP/SAVPF %d\r\n"
4911 					"c=IN IP4 1.1.1.1\r\n", pt);
4912 				janus_strlcat(sdptemp, buffer, 2048);
4913 				if(mp->codecs.audio_rtpmap) {
4914 					g_snprintf(buffer, 512,
4915 						"a=rtpmap:%d %s\r\n",
4916 						pt, mp->codecs.audio_rtpmap);
4917 					janus_strlcat(sdptemp, buffer, 2048);
4918 				}
4919 				if(mp->codecs.audio_fmtp) {
4920 					g_snprintf(buffer, 512,
4921 						"a=fmtp:%d %s\r\n",
4922 						pt, mp->codecs.audio_fmtp);
4923 					janus_strlcat(sdptemp, buffer, 2048);
4924 				}
4925 				janus_strlcat(sdptemp, "a=sendonly\r\n", 2048);
4926 				g_snprintf(buffer, 512, "a=extmap:%d %s\r\n", 1, JANUS_RTP_EXTMAP_MID);
4927 				janus_strlcat(sdptemp, buffer, 2048);
4928 			}
4929 			if(mp->codecs.video_pt > 0 && session->video) {
4930 				int pt = session->video_pt > 0 ? session->video_pt : mp->codecs.video_pt;
4931 				/* Add video line */
4932 				g_snprintf(buffer, 512,
4933 					"m=video 1 RTP/SAVPF %d\r\n"
4934 					"c=IN IP4 1.1.1.1\r\n", pt);
4935 				janus_strlcat(sdptemp, buffer, 2048);
4936 				if(mp->codecs.video_rtpmap) {
4937 					g_snprintf(buffer, 512,
4938 						"a=rtpmap:%d %s\r\n",
4939 						pt, mp->codecs.video_rtpmap);
4940 					janus_strlcat(sdptemp, buffer, 2048);
4941 				}
4942 				if(mp->codecs.video_fmtp) {
4943 					g_snprintf(buffer, 512,
4944 						"a=fmtp:%d %s\r\n",
4945 						pt, mp->codecs.video_fmtp);
4946 					janus_strlcat(sdptemp, buffer, 2048);
4947 				}
4948 				g_snprintf(buffer, 512,
4949 					"a=rtcp-fb:%d nack\r\n", pt);
4950 				janus_strlcat(sdptemp, buffer, 2048);
4951 				g_snprintf(buffer, 512,
4952 					"a=rtcp-fb:%d nack pli\r\n", pt);
4953 				janus_strlcat(sdptemp, buffer, 2048);
4954 				g_snprintf(buffer, 512,
4955 					"a=rtcp-fb:%d goog-remb\r\n", pt);
4956 				janus_strlcat(sdptemp, buffer, 2048);
4957 				janus_strlcat(sdptemp, "a=sendonly\r\n", 2048);
4958 				g_snprintf(buffer, 512, "a=extmap:%d %s\r\n", 1, JANUS_RTP_EXTMAP_MID);
4959 				janus_strlcat(sdptemp, buffer, 2048);
4960 				g_snprintf(buffer, 512, "a=extmap:%d %s\r\n", 2, JANUS_RTP_EXTMAP_ABS_SEND_TIME);
4961 				janus_strlcat(sdptemp, buffer, 2048);
4962 			}
4963 #ifdef HAVE_SCTP
4964 			if(mp->data && session->data) {
4965 				/* Add data line */
4966 				g_snprintf(buffer, 512,
4967 					"m=application 1 UDP/DTLS/SCTP webrtc-datachannel\r\n"
4968 					"c=IN IP4 1.1.1.1\r\n"
4969 					"a=sctp-port:5000\r\n");
4970 				janus_strlcat(sdptemp, buffer, 2048);
4971 			}
4972 #endif
4973 			sdp = g_strdup(sdptemp);
4974 			JANUS_LOG(LOG_VERB, "Going to %s this SDP:\n%s\n", sdp_type, sdp);
4975 			result = json_object();
4976 			json_object_set_new(result, "status", json_string(do_restart ? "updating" : "preparing"));
4977 			/* Add the user to the list of watchers and we're done */
4978 			if(g_list_find(mp->viewers, session) == NULL) {
4979 				mp->viewers = g_list_append(mp->viewers, session);
4980 				if(mp->streaming_source == janus_streaming_source_rtp) {
4981 					/* If we're using helper threads, add the viewer to one of those */
4982 					if(mp->helper_threads > 0) {
4983 						int viewers = -1;
4984 						janus_streaming_helper *helper = NULL;
4985 						GList *l = mp->threads;
4986 						while(l) {
4987 							janus_streaming_helper *ht = (janus_streaming_helper *)l->data;
4988 							if(viewers == -1 || (helper == NULL && ht->num_viewers == 0) || ht->num_viewers < viewers) {
4989 								viewers = ht->num_viewers;
4990 								helper = ht;
4991 							}
4992 							l = l->next;
4993 						}
4994 						janus_mutex_lock(&helper->mutex);
4995 						helper->viewers = g_list_append(helper->viewers, session);
4996 						helper->num_viewers++;
4997 						janus_mutex_unlock(&helper->mutex);
4998 						JANUS_LOG(LOG_VERB, "Added viewer to helper thread #%d (%d viewers)\n",
4999 							helper->id, helper->num_viewers);
5000 					}
5001 				}
5002 			}
5003 			janus_mutex_unlock(&session->mutex);
5004 			janus_mutex_unlock(&mp->mutex);
5005 		} else if(!strcasecmp(request_text, "start")) {
5006 			if(session->mountpoint == NULL) {
5007 				JANUS_LOG(LOG_VERB, "Can't start: no mountpoint set\n");
5008 				error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
5009 				g_snprintf(error_cause, 512, "Can't start: no mountpoint set");
5010 				goto error;
5011 			}
5012 			JANUS_LOG(LOG_VERB, "Starting the streaming\n");
5013 			if(g_atomic_int_get(&session->paused) == 1) {
5014 				/* We were paused: reset the sequence number in RTP packets */
5015 				session->context.a_seq_reset = TRUE;
5016 				session->context.v_seq_reset = TRUE;
5017 			}
5018 			g_atomic_int_set(&session->paused, 0);
5019 			result = json_object();
5020 			/* We wait for the setup_media event to start: on the other hand, it may have already arrived */
5021 			json_object_set_new(result, "status", json_string(g_atomic_int_get(&session->started) ? "started" : "starting"));
5022 			/* Also notify event handlers */
5023 			if(notify_events && gateway->events_is_enabled()) {
5024 				json_t *info = json_object();
5025 				json_object_set_new(info, "status", json_string("starting"));
5026 				if(session->mountpoint != NULL)
5027 					json_object_set_new(info, "id", string_ids ?
5028 						json_string(session->mountpoint->id_str) :json_integer(session->mountpoint->id));
5029 				gateway->notify_event(&janus_streaming_plugin, session->handle, info);
5030 			}
5031 		} else if(!strcasecmp(request_text, "pause")) {
5032 			if(session->mountpoint == NULL) {
5033 				JANUS_LOG(LOG_VERB, "Can't pause: no mountpoint set\n");
5034 				error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
5035 				g_snprintf(error_cause, 512, "Can't start: no mountpoint set");
5036 				goto error;
5037 			}
5038 			JANUS_LOG(LOG_VERB, "Pausing the streaming\n");
5039 			g_atomic_int_set(&session->paused, 1);
5040 			result = json_object();
5041 			json_object_set_new(result, "status", json_string("pausing"));
5042 			/* Also notify event handlers */
5043 			if(notify_events && gateway->events_is_enabled()) {
5044 				json_t *info = json_object();
5045 				json_object_set_new(info, "status", json_string("pausing"));
5046 				if(session->mountpoint != NULL)
5047 					json_object_set_new(info, "id", string_ids ?
5048 						json_string(session->mountpoint->id_str) : json_integer(session->mountpoint->id));
5049 				gateway->notify_event(&janus_streaming_plugin, session->handle, info);
5050 			}
5051 		} else if(!strcasecmp(request_text, "configure")) {
5052 			janus_streaming_mountpoint *mp = session->mountpoint;
5053 			if(mp == NULL) {
5054 				JANUS_LOG(LOG_VERB, "Can't configure: not on a mountpoint\n");
5055 				error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
5056 				g_snprintf(error_cause, 512, "Can't configure: not on a mountpoint");
5057 				goto error;
5058 			}
5059 			JANUS_VALIDATE_JSON_OBJECT(root, configure_parameters,
5060 				error_code, error_cause, TRUE,
5061 				JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
5062 			json_t *audio = json_object_get(root, "audio");
5063 			if(audio)
5064 				session->audio = json_is_true(audio);
5065 			json_t *video = json_object_get(root, "video");
5066 			if(video)
5067 				session->video = json_is_true(video);
5068 			json_t *data = json_object_get(root, "data");
5069 			if(data)
5070 				session->data = json_is_true(data);
5071 			if(mp->streaming_source == janus_streaming_source_rtp) {
5072 				janus_streaming_rtp_source *source = (janus_streaming_rtp_source *)mp->source;
5073 				if(source && source->simulcast) {
5074 					/* Check if the viewer is requesting a different substream/temporal layer */
5075 					json_t *substream = json_object_get(root, "substream");
5076 					if(substream) {
5077 						session->sim_context.substream_target = json_integer_value(substream);
5078 						JANUS_LOG(LOG_VERB, "Setting video substream to let through (simulcast): %d (was %d)\n",
5079 							session->sim_context.substream_target, session->sim_context.substream);
5080 						if(session->sim_context.substream_target == session->sim_context.substream) {
5081 							/* No need to do anything, we're already getting the right substream, so notify the viewer */
5082 							json_t *event = json_object();
5083 							json_object_set_new(event, "streaming", json_string("event"));
5084 							json_t *result = json_object();
5085 							json_object_set_new(result, "substream", json_integer(session->sim_context.substream));
5086 							json_object_set_new(event, "result", result);
5087 							gateway->push_event(session->handle, &janus_streaming_plugin, NULL, event, NULL);
5088 							json_decref(event);
5089 						} else {
5090 							/* Schedule a PLI */
5091 							JANUS_LOG(LOG_VERB, "We need a PLI for the simulcast context\n");
5092 							g_atomic_int_set(&source->need_pli, 1);
5093 						}
5094 					}
5095 					json_t *temporal = json_object_get(root, "temporal");
5096 					if(temporal) {
5097 						session->sim_context.templayer_target = json_integer_value(temporal);
5098 						JANUS_LOG(LOG_VERB, "Setting video temporal layer to let through (simulcast): %d (was %d)\n",
5099 							session->sim_context.templayer_target, session->sim_context.templayer);
5100 						if(mp->codecs.video_codec == JANUS_VIDEOCODEC_VP8 && session->sim_context.templayer_target == session->sim_context.templayer) {
5101 							/* No need to do anything, we're already getting the right temporal layer, so notify the viewer */
5102 							json_t *event = json_object();
5103 							json_object_set_new(event, "streaming", json_string("event"));
5104 							json_t *result = json_object();
5105 							json_object_set_new(result, "temporal", json_integer(session->sim_context.templayer));
5106 							json_object_set_new(event, "result", result);
5107 							gateway->push_event(session->handle, &janus_streaming_plugin, NULL, event, NULL);
5108 							json_decref(event);
5109 						}
5110 					}
5111 					/* Check if we need to change the fallback timer for the substream */
5112 					json_t *fallback = json_object_get(root, "fallback");
5113 					if(fallback) {
5114 						JANUS_LOG(LOG_VERB, "Setting fallback timer (simulcast): %lld (was %"SCNu32")\n",
5115 							json_integer_value(fallback) ? json_integer_value(fallback) : 250000,
5116 							session->sim_context.drop_trigger ? session->sim_context.drop_trigger : 250000);
5117 						session->sim_context.drop_trigger = json_integer_value(fallback);
5118 					}
5119 				}
5120 				if(source && source->svc) {
5121 					/* Check if the viewer is requesting a different SVC spatial/temporal layer */
5122 					json_t *spatial = json_object_get(root, "spatial_layer");
5123 					if(spatial) {
5124 						int spatial_layer = json_integer_value(spatial);
5125 						if(spatial_layer > 1) {
5126 							JANUS_LOG(LOG_WARN, "Spatial layer higher than 1, will probably be ignored\n");
5127 						}
5128 						if(spatial_layer == session->spatial_layer) {
5129 							/* No need to do anything, we're already getting the right spatial layer, so notify the user */
5130 							json_t *event = json_object();
5131 							json_object_set_new(event, "streaming", json_string("event"));
5132 							json_t *result = json_object();
5133 							json_object_set_new(result, "spatial_layer", json_integer(session->spatial_layer));
5134 							json_object_set_new(event, "result", result);
5135 							gateway->push_event(msg->handle, &janus_streaming_plugin, NULL, event, NULL);
5136 							json_decref(event);
5137 						} else if(spatial_layer != session->target_spatial_layer) {
5138 							/* Send a FIR to the source, if RTCP is enabled */
5139 							g_atomic_int_set(&source->need_pli, 1);
5140 						}
5141 						session->target_spatial_layer = spatial_layer;
5142 					}
5143 					json_t *temporal = json_object_get(root, "temporal_layer");
5144 					if(temporal) {
5145 						int temporal_layer = json_integer_value(temporal);
5146 						if(temporal_layer > 2) {
5147 							JANUS_LOG(LOG_WARN, "Temporal layer higher than 2, will probably be ignored\n");
5148 						}
5149 						if(temporal_layer == session->temporal_layer) {
5150 							/* No need to do anything, we're already getting the right temporal layer, so notify the user */
5151 							json_t *event = json_object();
5152 							json_object_set_new(event, "streaming", json_string("event"));
5153 							json_t *result = json_object();
5154 							json_object_set_new(result, "temporal_layer", json_integer(session->temporal_layer));
5155 							json_object_set_new(event, "result", result);
5156 							gateway->push_event(msg->handle, &janus_streaming_plugin, NULL, event, NULL);
5157 							json_decref(event);
5158 						}
5159 						session->target_temporal_layer = temporal_layer;
5160 					}
5161 				}
5162 			}
5163 			/* Done */
5164 			result = json_object();
5165 			json_object_set_new(result, "event", json_string("configured"));
5166 		} else if(!strcasecmp(request_text, "switch")) {
5167 			/* This listener wants to switch to a different mountpoint
5168 			 * NOTE: this only works for live RTP streams as of now: you
5169 			 * cannot, for instance, switch from a live RTP mountpoint to
5170 			 * an on demand one or viceversa (TBD.) */
5171 			janus_mutex_lock(&session->mutex);
5172 			janus_streaming_mountpoint *oldmp = session->mountpoint;
5173 			if(oldmp == NULL) {
5174 				janus_mutex_unlock(&session->mutex);
5175 				JANUS_LOG(LOG_VERB, "Can't switch: not on a mountpoint\n");
5176 				error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
5177 				g_snprintf(error_cause, 512, "Can't switch: not on a mountpoint");
5178 				goto error;
5179 			}
5180 			if(oldmp->streaming_type != janus_streaming_type_live ||
5181 					oldmp->streaming_source != janus_streaming_source_rtp) {
5182 				janus_mutex_unlock(&session->mutex);
5183 				JANUS_LOG(LOG_VERB, "Can't switch: not on a live RTP mountpoint\n");
5184 				error_code = JANUS_STREAMING_ERROR_CANT_SWITCH;
5185 				g_snprintf(error_cause, 512, "Can't switch: not on a live RTP mountpoint");
5186 				goto error;
5187 			}
5188 			janus_refcount_increase(&oldmp->ref);
5189 			if(!string_ids) {
5190 				JANUS_VALIDATE_JSON_OBJECT(root, id_parameters,
5191 					error_code, error_cause, TRUE,
5192 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
5193 			} else {
5194 				JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters,
5195 					error_code, error_cause, TRUE,
5196 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
5197 			}
5198 			if(error_code != 0) {
5199 				janus_mutex_unlock(&session->mutex);
5200 				janus_refcount_decrease(&oldmp->ref);
5201 				goto error;
5202 			}
5203 			json_t *id = json_object_get(root, "id");
5204 			guint64 id_value = 0;
5205 			char id_num[30], *id_value_str = NULL;
5206 			if(!string_ids) {
5207 				id_value = json_integer_value(id);
5208 				g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id_value);
5209 				id_value_str = id_num;
5210 			} else {
5211 				id_value_str = (char *)json_string_value(id);
5212 			}
5213 			janus_mutex_lock(&mountpoints_mutex);
5214 			janus_streaming_mountpoint *mp = g_hash_table_lookup(mountpoints,
5215 				string_ids ? (gpointer)id_value_str : (gpointer)&id_value);
5216 			if(mp == NULL || g_atomic_int_get(&mp->destroyed)) {
5217 				janus_mutex_unlock(&mountpoints_mutex);
5218 				janus_mutex_unlock(&session->mutex);
5219 				JANUS_LOG(LOG_VERB, "No such mountpoint/stream %s\n", id_value_str);
5220 				error_code = JANUS_STREAMING_ERROR_NO_SUCH_MOUNTPOINT;
5221 				g_snprintf(error_cause, 512, "No such mountpoint/stream %s", id_value_str);
5222 				goto error;
5223 			}
5224 			janus_refcount_increase(&mp->ref);
5225 			if(mp->streaming_type != janus_streaming_type_live ||
5226 					mp->streaming_source != janus_streaming_source_rtp) {
5227 				janus_refcount_decrease(&oldmp->ref);
5228 				janus_refcount_decrease(&mp->ref);
5229 				janus_mutex_unlock(&mountpoints_mutex);
5230 				janus_mutex_unlock(&session->mutex);
5231 				JANUS_LOG(LOG_VERB, "Can't switch: target is not a live RTP mountpoint\n");
5232 				error_code = JANUS_STREAMING_ERROR_CANT_SWITCH;
5233 				g_snprintf(error_cause, 512, "Can't switch: target is not a live RTP mountpoint");
5234 				goto error;
5235 			}
5236 			janus_streaming_rtp_source *source = (janus_streaming_rtp_source *)mp->source;
5237 			if(source && source->simulcast) {
5238 				JANUS_VALIDATE_JSON_OBJECT(root, simulcast_parameters,
5239 					error_code, error_cause, TRUE,
5240 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
5241 				if(error_code != 0) {
5242 					janus_refcount_decrease(&oldmp->ref);
5243 					janus_refcount_decrease(&mp->ref);
5244 					janus_mutex_unlock(&mountpoints_mutex);
5245 					janus_mutex_unlock(&session->mutex);
5246 					goto error;
5247 				}
5248 				/* In case this mountpoint is simulcasting, let's aim high by default */
5249 				janus_rtp_simulcasting_context_reset(&session->sim_context);
5250 				session->sim_context.substream_target = 2;
5251 				session->sim_context.templayer_target = 2;
5252 				janus_vp8_simulcast_context_reset(&session->vp8_context);
5253 				/* Unless the request contains a target for either layer */
5254 				json_t *substream = json_object_get(root, "substream");
5255 				if(substream) {
5256 					session->sim_context.substream_target = json_integer_value(substream);
5257 					JANUS_LOG(LOG_VERB, "Setting video substream to let through (simulcast): %d (was %d)\n",
5258 						session->sim_context.substream_target, session->sim_context.substream);
5259 				}
5260 				json_t *temporal = json_object_get(root, "temporal");
5261 				if(temporal) {
5262 					session->sim_context.templayer_target = json_integer_value(temporal);
5263 					JANUS_LOG(LOG_VERB, "Setting video temporal layer to let through (simulcast): %d (was %d)\n",
5264 						session->sim_context.templayer_target, session->sim_context.templayer);
5265 				}
5266 				/* Check if we need a custom fallback timer for the substream */
5267 				json_t *fallback = json_object_get(root, "fallback");
5268 				if(fallback) {
5269 					JANUS_LOG(LOG_VERB, "Setting fallback timer (simulcast): %lld (was %"SCNu32")\n",
5270 						json_integer_value(fallback) ? json_integer_value(fallback) : 250000,
5271 						session->sim_context.drop_trigger ? session->sim_context.drop_trigger : 250000);
5272 					session->sim_context.drop_trigger = json_integer_value(fallback);
5273 				}
5274 			} else if(source && source->svc) {
5275 				JANUS_VALIDATE_JSON_OBJECT(root, svc_parameters,
5276 					error_code, error_cause, TRUE,
5277 					JANUS_STREAMING_ERROR_MISSING_ELEMENT, JANUS_STREAMING_ERROR_INVALID_ELEMENT);
5278 				if(error_code != 0) {
5279 					janus_refcount_decrease(&oldmp->ref);
5280 					janus_refcount_decrease(&mp->ref);
5281 					janus_mutex_unlock(&mountpoints_mutex);
5282 					janus_mutex_unlock(&session->mutex);
5283 					goto error;
5284 				}
5285 				/* In case this mountpoint is doing VP9-SVC, let's aim high by default */
5286 				session->spatial_layer = -1;
5287 				session->target_spatial_layer = 2;	/* FIXME Chrome sends 0, 1 and 2 (if using EnabledByFlag_3SL3TL) */
5288 				session->temporal_layer = -1;
5289 				session->target_temporal_layer = 2;	/* FIXME Chrome sends 0, 1 and 2 */
5290 				/* Unless the request contains a target for either layer */
5291 				json_t *spatial = json_object_get(root, "spatial_layer");
5292 				if(spatial) {
5293 					session->target_spatial_layer = json_integer_value(spatial);
5294 					JANUS_LOG(LOG_VERB, "Setting video spatial layer to let through (SVC): %d (was %d)\n",
5295 						session->target_spatial_layer, session->spatial_layer);
5296 				}
5297 				json_t *temporal = json_object_get(root, "temporal_layer");
5298 				if(temporal) {
5299 					session->target_temporal_layer = json_integer_value(temporal);
5300 					JANUS_LOG(LOG_VERB, "Setting video temporal layer to let through (SVC): %d (was %d)\n",
5301 						session->target_temporal_layer, session->temporal_layer);
5302 				}
5303 			}
5304 			janus_mutex_unlock(&mountpoints_mutex);
5305 			JANUS_LOG(LOG_VERB, "Request to switch to mountpoint/stream %s (old: %s)\n", mp->id_str, oldmp->id_str);
5306 			g_atomic_int_set(&session->paused, 1);
5307 			/* Unsubscribe from the previous mountpoint and subscribe to the new one */
5308 			session->mountpoint = NULL;
5309 			janus_mutex_unlock(&session->mutex);
5310 			janus_mutex_lock(&oldmp->mutex);
5311 			oldmp->viewers = g_list_remove_all(oldmp->viewers, session);
5312 			/* Remove the viewer from the helper threads too, if any */
5313 			if(oldmp->helper_threads > 0) {
5314 				GList *l = oldmp->threads;
5315 				while(l) {
5316 					janus_streaming_helper *ht = (janus_streaming_helper *)l->data;
5317 					janus_mutex_lock(&ht->mutex);
5318 					if(g_list_find(ht->viewers, session) != NULL) {
5319 						ht->num_viewers--;
5320 						ht->viewers = g_list_remove_all(ht->viewers, session);
5321 						janus_mutex_unlock(&ht->mutex);
5322 						JANUS_LOG(LOG_VERB, "Removing viewer from helper thread #%d (switching)\n", ht->id);
5323 						break;
5324 					}
5325 					janus_mutex_unlock(&ht->mutex);
5326 					l = l->next;
5327 				}
5328 			}
5329 			janus_refcount_decrease(&oldmp->ref);	/* This is for the user going away */
5330 			janus_mutex_unlock(&oldmp->mutex);
5331 			/* Subscribe to the new one */
5332 			janus_mutex_lock(&mp->mutex);
5333 			janus_mutex_lock(&session->mutex);
5334 			janus_refcount_increase(&mp->ref);
5335 			mp->viewers = g_list_append(mp->viewers, session);
5336 			/* If we're using helper threads, add the viewer to one of those */
5337 			if(mp->helper_threads > 0) {
5338 				int viewers = -1;
5339 				janus_streaming_helper *helper = NULL;
5340 				GList *l = mp->threads;
5341 				while(l) {
5342 					janus_streaming_helper *ht = (janus_streaming_helper *)l->data;
5343 					if(viewers == -1 || (helper == NULL && ht->num_viewers == 0) || ht->num_viewers < viewers) {
5344 						viewers = ht->num_viewers;
5345 						helper = ht;
5346 					}
5347 					l = l->next;
5348 				}
5349 				JANUS_LOG(LOG_VERB, "Adding viewer to helper thread #%d\n", helper->id);
5350 				janus_mutex_lock(&helper->mutex);
5351 				helper->viewers = g_list_append(helper->viewers, session);
5352 				helper->num_viewers++;
5353 				janus_mutex_unlock(&helper->mutex);
5354 			}
5355 			session->mountpoint = mp;
5356 			/* Send a PLI too, in case the mountpoint supports video and RTCP */
5357 			janus_streaming_rtcp_pli_send(mp->source);
5358 			g_atomic_int_set(&session->paused, 0);
5359 			janus_mutex_unlock(&session->mutex);
5360 			janus_mutex_unlock(&mp->mutex);
5361 			/* Done with the request, remove the references we took for that */
5362 			janus_refcount_decrease(&oldmp->ref);
5363 			janus_refcount_decrease(&mp->ref);
5364 			result = json_object();
5365 			json_object_set_new(result, "switched", json_string("ok"));
5366 			json_object_set_new(result, "id", string_ids ? json_string(id_value_str) : json_integer(id_value));
5367 			/* Also notify event handlers */
5368 			if(notify_events && gateway->events_is_enabled()) {
5369 				json_t *info = json_object();
5370 				json_object_set_new(info, "status", json_string("switching"));
5371 				json_object_set_new(info, "id", string_ids ? json_string(id_value_str) : json_integer(id_value));
5372 				gateway->notify_event(&janus_streaming_plugin, session->handle, info);
5373 			}
5374 		} else if(!strcasecmp(request_text, "stop")) {
5375 			if(g_atomic_int_get(&session->stopping) || !g_atomic_int_get(&session->started)) {
5376 				/* Been there, done that: ignore */
5377 				janus_streaming_message_free(msg);
5378 				continue;
5379 			}
5380 			JANUS_LOG(LOG_VERB, "Stopping the streaming\n");
5381 			result = json_object();
5382 			json_object_set_new(result, "status", json_string("stopping"));
5383 			/* Also notify event handlers */
5384 			if(notify_events && gateway->events_is_enabled()) {
5385 				json_t *info = json_object();
5386 				json_object_set_new(info, "status", json_string("stopping"));
5387 				janus_streaming_mountpoint *mp = session->mountpoint;
5388 				if(mp)
5389 					json_object_set_new(info, "id", string_ids ? json_string(mp->id_str) : json_integer(mp->id));
5390 				gateway->notify_event(&janus_streaming_plugin, session->handle, info);
5391 			}
5392 			/* Tell the core to tear down the PeerConnection, hangup_media will do the rest */
5393 			gateway->close_pc(session->handle);
5394 		} else {
5395 			JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
5396 			error_code = JANUS_STREAMING_ERROR_INVALID_REQUEST;
5397 			g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
5398 			goto error;
5399 		}
5400 
5401 		/* Any SDP to handle? */
5402 		const char *msg_sdp_type = json_string_value(json_object_get(msg->jsep, "type"));
5403 		const char *msg_sdp = json_string_value(json_object_get(msg->jsep, "sdp"));
5404 		if(msg_sdp) {
5405 			JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well (%s):\n%s\n",
5406 				do_restart ? "renegotiation occurring" : "but we really don't care", msg_sdp_type, msg_sdp);
5407 		}
5408 		g_atomic_int_set(&session->renegotiating, 0);
5409 
5410 		/* Prepare JSON event */
5411 		json_t *jsep = json_pack("{ssss}", "type", sdp_type, "sdp", sdp);
5412 		if(do_restart)
5413 			json_object_set_new(jsep, "restart", json_true());
5414 		if(session->e2ee)
5415 			json_object_set_new(jsep, "e2ee", json_true());
5416 		json_t *event = json_object();
5417 		json_object_set_new(event, "streaming", json_string("event"));
5418 		if(result != NULL)
5419 			json_object_set_new(event, "result", result);
5420 		int ret = gateway->push_event(msg->handle, &janus_streaming_plugin, msg->transaction, event, jsep);
5421 		JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (%s)\n", ret, janus_get_api_error(ret));
5422 		g_free(sdp);
5423 		json_decref(event);
5424 		json_decref(jsep);
5425 		janus_streaming_message_free(msg);
5426 		continue;
5427 
5428 error:
5429 		{
5430 			/* Prepare JSON error event */
5431 			json_t *event = json_object();
5432 			json_object_set_new(event, "streaming", json_string("event"));
5433 			json_object_set_new(event, "error_code", json_integer(error_code));
5434 			json_object_set_new(event, "error", json_string(error_cause));
5435 			int ret = gateway->push_event(msg->handle, &janus_streaming_plugin, msg->transaction, event, NULL);
5436 			JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (%s)\n", ret, janus_get_api_error(ret));
5437 			json_decref(event);
5438 			janus_streaming_message_free(msg);
5439 		}
5440 	}
5441 	JANUS_LOG(LOG_VERB, "Leaving Streaming handler thread\n");
5442 	return NULL;
5443 }
5444 
5445 /* Helpers to create a listener filedescriptor */
5446 static int janus_streaming_create_fd(int port, in_addr_t mcast, const janus_network_address *iface, char *host, size_t hostlen,
5447 		const char *listenername, const char *medianame, const char *mountpointname, gboolean quiet) {
5448 	janus_mutex_lock(&fd_mutex);
5449 	struct sockaddr_in address = { 0 };
5450 	struct sockaddr_in6 address6 = { 0 };
5451 	janus_network_address_string_buffer address_representation;
5452 
5453 	uint16_t rtp_port_next = rtp_range_slider; 					/* Read global slider */
5454 	uint16_t rtp_port_start = rtp_port_next;
5455 	gboolean use_range = (port == 0), rtp_port_wrap = FALSE;
5456 
5457 	int fd = -1, family = 0;
5458 	while(1) {
5459 		family = 0;	/* By default, we bind to both IPv4 and IPv6 */
5460 		if(use_range && rtp_port_wrap && rtp_port_next >= rtp_port_start) {
5461 			/* Full range scanned */
5462 			JANUS_LOG(LOG_ERR, "No ports available for RTP/RTCP in range: %u -- %u\n",
5463 				  rtp_range_min, rtp_range_max);
5464 			break;
5465 		}
5466 		if(!use_range) {
5467 			/* Use the port specified in the arguments */
5468 			if(IN_MULTICAST(ntohl(mcast))) {
5469 				fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
5470 				if(fd < 0) {
5471 					JANUS_LOG(LOG_ERR, "[%s] Cannot create socket for %s... %d (%s)\n",
5472 						mountpointname, medianame, errno, g_strerror(errno));
5473 					break;
5474 				}
5475 #ifdef IP_MULTICAST_ALL
5476 				int mc_all = 0;
5477 				if((setsockopt(fd, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all))) < 0) {
5478 					JANUS_LOG(LOG_ERR, "[%s] %s listener setsockopt IP_MULTICAST_ALL failed... %d (%s)\n",
5479 						mountpointname, listenername, errno, g_strerror(errno));
5480 					close(fd);
5481 					janus_mutex_unlock(&fd_mutex);
5482 					return -1;
5483 				}
5484 #endif
5485 				struct ip_mreq mreq;
5486 				memset(&mreq, '\0', sizeof(mreq));
5487 				mreq.imr_multiaddr.s_addr = mcast;
5488 				if(!janus_network_address_is_null(iface)) {
5489 					family = AF_INET;
5490 					if(iface->family == AF_INET) {
5491 						mreq.imr_interface = iface->ipv4;
5492 						(void) janus_network_address_to_string_buffer(iface, &address_representation); /* This is OK: if we get here iface must be non-NULL */
5493 						char *maddr = inet_ntoa(mreq.imr_multiaddr);
5494 						JANUS_LOG(LOG_INFO, "[%s] %s listener using interface address: %s (%s)\n", mountpointname, listenername,
5495 							janus_network_address_string_from_buffer(&address_representation), maddr);
5496 						if(maddr && host && hostlen > 0)
5497 							g_strlcpy(host, maddr, hostlen);
5498 					} else {
5499 						JANUS_LOG(LOG_ERR, "[%s] %s listener: invalid multicast address type (only IPv4 multicast is currently supported by this plugin)\n", mountpointname, listenername);
5500 						close(fd);
5501 						janus_mutex_unlock(&fd_mutex);
5502 						return -1;
5503 					}
5504 				} else {
5505 					JANUS_LOG(LOG_WARN, "[%s] No multicast interface for: %s. This may not work as expected if you have multiple network devices (NICs)\n", mountpointname, listenername);
5506 				}
5507 				if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
5508 					JANUS_LOG(LOG_ERR, "[%s] %s listener IP_ADD_MEMBERSHIP failed... %d (%s)\n",
5509 						mountpointname, listenername, errno, g_strerror(errno));
5510 					close(fd);
5511 					janus_mutex_unlock(&fd_mutex);
5512 					return -1;
5513 				}
5514 				JANUS_LOG(LOG_INFO, "[%s] %s listener IP_ADD_MEMBERSHIP ok\n", mountpointname, listenername);
5515 			}
5516 		} else {
5517 			/* Pick a port in the configured range */
5518 			port = rtp_port_next;
5519 			if((uint32_t)(rtp_port_next) < rtp_range_max) {
5520 				rtp_port_next++;
5521 			} else {
5522 				rtp_port_next = rtp_range_min;
5523 				rtp_port_wrap = TRUE;
5524 			}
5525 		}
5526 		address.sin_family = AF_INET;
5527 		address.sin_port = htons(port);
5528 		address.sin_addr.s_addr = INADDR_ANY;
5529 		address6.sin6_family = AF_INET6;
5530 		address6.sin6_port = htons(port);
5531 		address6.sin6_addr = in6addr_any;
5532 		/* If this is multicast, allow a re-use of the same ports (different groups may be used) */
5533 		if(!use_range && IN_MULTICAST(ntohl(mcast))) {
5534 			int reuse = 1;
5535 			if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
5536 				JANUS_LOG(LOG_ERR, "[%s] %s listener setsockopt SO_REUSEADDR failed... %d (%s)\n",
5537 					mountpointname, listenername, errno, g_strerror(errno));
5538 				close(fd);
5539 				janus_mutex_unlock(&fd_mutex);
5540 				return -1;
5541 			}
5542 			/* TODO IPv6 */
5543 			family = AF_INET;
5544 			address.sin_addr.s_addr = mcast;
5545 		} else {
5546 			if(!IN_MULTICAST(ntohl(mcast)) && !janus_network_address_is_null(iface)) {
5547 				family = iface->family;
5548 				if(iface->family == AF_INET) {
5549 					address.sin_addr = iface->ipv4;
5550 					(void) janus_network_address_to_string_buffer(iface, &address_representation); /* This is OK: if we get here iface must be non-NULL */
5551 					JANUS_LOG(LOG_INFO, "[%s] %s listener restricted to interface address: %s\n",
5552 						mountpointname, listenername, janus_network_address_string_from_buffer(&address_representation));
5553 					if(host && hostlen > 0)
5554 						g_strlcpy(host, janus_network_address_string_from_buffer(&address_representation), hostlen);
5555 				} else if(iface->family == AF_INET6) {
5556 					memcpy(&address6.sin6_addr, &iface->ipv6, sizeof(iface->ipv6));
5557 					(void) janus_network_address_to_string_buffer(iface, &address_representation); /* This is OK: if we get here iface must be non-NULL */
5558 					JANUS_LOG(LOG_INFO, "[%s] %s listener restricted to interface address: %s\n",
5559 						mountpointname, listenername, janus_network_address_string_from_buffer(&address_representation));
5560 					if(host && hostlen > 0)
5561 						g_strlcpy(host, janus_network_address_string_from_buffer(&address_representation), hostlen);
5562 				} else {
5563 					JANUS_LOG(LOG_ERR, "[%s] %s listener: invalid address/restriction type\n", mountpointname, listenername);
5564 					continue;
5565 				}
5566 			}
5567 		}
5568 		/* Bind to the specified port */
5569 		if(fd == -1) {
5570 			fd = socket(family == AF_INET ? AF_INET : AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
5571 			int v6only = 0;
5572 			if(fd < 0) {
5573 				JANUS_LOG(LOG_ERR, "[%s] Cannot create socket for %s... %d (%s)\n",
5574 					mountpointname, medianame, errno, g_strerror(errno));
5575 				break;
5576 			}
5577 			if(family != AF_INET && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) {
5578 				JANUS_LOG(LOG_ERR, "[%s] setsockopt on socket failed for %s... %d (%s)\n",
5579 					mountpointname, medianame, errno, g_strerror(errno));
5580 				break;
5581 			}
5582 		}
5583 		size_t addrlen = (family == AF_INET ? sizeof(address) : sizeof(address6));
5584 		if(bind(fd, (family == AF_INET ? (struct sockaddr *)&address : (struct sockaddr *)&address6), addrlen) < 0) {
5585 			close(fd);
5586 			fd = -1;
5587 			if(!quiet) {
5588 				JANUS_LOG(LOG_ERR, "[%s] Bind failed for %s (port %d)... %d (%s)\n",
5589 					mountpointname, medianame, port, errno, g_strerror(errno));
5590 			}
5591 			if(!use_range)	/* Asked for a specific port but it's not available, give up */
5592 				break;
5593 		} else {
5594 			if(use_range)
5595 				rtp_range_slider = port;	/* Update global slider */
5596 			break;
5597 		}
5598 	}
5599 	janus_mutex_unlock(&fd_mutex);
5600 	return fd;
5601 }
5602 /* Helper to bind RTP/RTCP port pair (for RTSP) */
5603 static int janus_streaming_allocate_port_pair(const char *name, const char *media,
5604 		in_addr_t mcast, const janus_network_address *iface, multiple_fds *fds, int ports[2]) {
5605 	/* Start from the global slider */
5606 	uint16_t rtp_port_next = rtp_range_slider;
5607 	if(rtp_port_next % 2 != 0)	/* We want an even port for RTP */
5608 		rtp_port_next++;
5609 	uint16_t rtp_port_start = rtp_port_next;
5610 	gboolean rtp_port_wrap = FALSE;
5611 
5612 	int rtp_fd = -1, rtcp_fd = -1;
5613 	while(1) {
5614 		if(rtp_port_wrap && rtp_port_next >= rtp_port_start) {
5615 			/* Full range scanned */
5616 			JANUS_LOG(LOG_ERR, "No ports available for audio/video channel in range: %u -- %u\n",
5617 				rtp_range_min, rtp_range_max);
5618 			break;
5619 		}
5620 		int rtp_port = rtp_port_next;
5621 		int rtcp_port = rtp_port+1;
5622 		if((uint32_t)(rtp_port_next + 2UL) < rtp_range_max) {
5623 			/* Advance to next pair */
5624 			rtp_port_next += 2;
5625 		} else {
5626 			rtp_port_next = rtp_range_min;
5627 			rtp_port_wrap = TRUE;
5628 		}
5629 		rtp_fd = janus_streaming_create_fd(rtp_port, mcast, iface, NULL, 0, media, media, name, TRUE);
5630 		if(rtp_fd != -1) {
5631 			rtcp_fd = janus_streaming_create_fd(rtcp_port, mcast, iface, NULL, 0, media, media, name, TRUE);
5632 			if(rtcp_fd != -1) {
5633 				/* Done */
5634 				fds->fd = rtp_fd;
5635 				fds->rtcp_fd = rtcp_fd;
5636 				ports[0] = rtp_port;
5637 				ports[1] = rtcp_port;
5638 				/* Update global slider */
5639 				rtp_range_slider = rtp_port_next;
5640 				return 0;
5641 			}
5642 		}
5643 		/* If we got here, something failed: try again */
5644 		if(rtp_fd != -1)
5645 			close(rtp_fd);
5646 	}
5647 	return -1;
5648 }
5649 
5650 /* Helper to return fd port */
5651 static int janus_streaming_get_fd_port(int fd) {
5652 	struct sockaddr_in6 server = { 0 };
5653 	socklen_t len = sizeof(server);
5654 	if(getsockname(fd, (struct sockaddr *)&server, &len) == -1) {
5655 		return -1;
5656 	}
5657 
5658 	return ntohs(server.sin6_port);
5659 }
5660 
5661 /* Helpers to destroy a streaming mountpoint. */
5662 static void janus_streaming_rtp_source_free(janus_streaming_rtp_source *source) {
5663 	if(source->audio_fd > -1) {
5664 		close(source->audio_fd);
5665 	}
5666 	if(source->video_fd[0] > -1) {
5667 		close(source->video_fd[0]);
5668 	}
5669 	if(source->video_fd[1] > -1) {
5670 		close(source->video_fd[1]);
5671 	}
5672 	if(source->video_fd[2] > -1) {
5673 		close(source->video_fd[2]);
5674 	}
5675 	if(source->data_fd > -1) {
5676 		close(source->data_fd);
5677 	}
5678 	if(source->audio_rtcp_fd > -1) {
5679 		close(source->audio_rtcp_fd);
5680 	}
5681 	if(source->video_rtcp_fd > -1) {
5682 		close(source->video_rtcp_fd);
5683 	}
5684 	if(source->pipefd[0] > -1) {
5685 		close(source->pipefd[0]);
5686 	}
5687 	if(source->pipefd[1] > -1) {
5688 		close(source->pipefd[1]);
5689 	}
5690 	g_free(source->audio_host);
5691 	g_free(source->video_host);
5692 	g_free(source->data_host);
5693 	janus_mutex_lock(&source->keyframe.mutex);
5694 	if(source->keyframe.latest_keyframe != NULL)
5695 		g_list_free_full(source->keyframe.latest_keyframe, (GDestroyNotify)janus_streaming_rtp_relay_packet_free);
5696 	source->keyframe.latest_keyframe = NULL;
5697 	janus_mutex_unlock(&source->keyframe.mutex);
5698 	janus_mutex_lock(&source->buffermsg_mutex);
5699 	if(source->last_msg != NULL)
5700 		janus_streaming_rtp_relay_packet_free((janus_streaming_rtp_relay_packet *)source->last_msg);
5701 	source->last_msg = NULL;
5702 	janus_mutex_unlock(&source->buffermsg_mutex);
5703 	if(source->is_srtp) {
5704 		g_free(source->srtpcrypto);
5705 		srtp_dealloc(source->srtp_ctx);
5706 		g_free(source->srtp_policy.key);
5707 	}
5708 #ifdef HAVE_LIBCURL
5709 	janus_mutex_lock(&source->rtsp_mutex);
5710 	if(source->curl) {
5711 		/* Send an RTSP TEARDOWN */
5712 		curl_easy_setopt(source->curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
5713 		int res = curl_easy_perform(source->curl);
5714 		if(res != CURLE_OK) {
5715 			JANUS_LOG(LOG_ERR, "Couldn't send TEARDOWN request: %s\n", curl_easy_strerror(res));
5716 		}
5717 		curl_easy_cleanup(source->curl);
5718 	}
5719 	janus_streaming_buffer *curldata = source->curldata;
5720 	if(curldata != NULL) {
5721 		g_free(curldata->buffer);
5722 		g_free(curldata);
5723 	}
5724 	g_free(source->rtsp_url);
5725 	g_free(source->rtsp_username);
5726 	g_free(source->rtsp_password);
5727 	g_free(source->rtsp_ahost);
5728 	g_free(source->rtsp_vhost);
5729 	janus_mutex_unlock(&source->rtsp_mutex);
5730 #endif
5731 	g_free(source);
5732 }
5733 
5734 static void janus_streaming_file_source_free(janus_streaming_file_source *source) {
5735 	g_free(source->filename);
5736 	g_free(source);
5737 }
5738 
5739 /* Helper to create an RTP live source (e.g., from gstreamer/ffmpeg/vlc/etc.) */
5740 janus_streaming_mountpoint *janus_streaming_create_rtp_source(
5741 		uint64_t id, char *id_str, char *name, char *desc, char *metadata,
5742 		int srtpsuite, char *srtpcrypto, int threads, gboolean e2ee,
5743 		gboolean doaudio, gboolean doaudiortcp, char *amcast, const janus_network_address *aiface, uint16_t aport, uint16_t artcpport, uint8_t acodec, char *artpmap, char *afmtp, gboolean doaskew,
5744 		gboolean dovideo, gboolean dovideortcp, char *vmcast, const janus_network_address *viface, uint16_t vport, uint16_t vrtcpport, uint8_t vcodec, char *vrtpmap, char *vfmtp, gboolean bufferkf,
5745 			gboolean simulcast, uint16_t vport2, uint16_t vport3, gboolean svc, gboolean dovskew, int rtp_collision,
5746 		gboolean dodata, const janus_network_address *diface, uint16_t dport, gboolean textdata, gboolean buffermsg) {
5747 	char id_num[30];
5748 	if(!string_ids) {
5749 		g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id);
5750 		id_str = id_num;
5751 	}
5752 	char tempname[255];
5753 	if(name == NULL) {
5754 		JANUS_LOG(LOG_VERB, "Missing name, will generate a random one...\n");
5755 		memset(tempname, 0, 255);
5756 		g_snprintf(tempname, 255, "mp-%s", id_str);
5757 	} else if(atoi(name) != 0) {
5758 		JANUS_LOG(LOG_VERB, "Names can't start with a number, prefixing it...\n");
5759 		memset(tempname, 0, 255);
5760 		g_snprintf(tempname, 255, "mp-%s", name);
5761 		name = NULL;
5762 	}
5763 	if(!doaudio && !dovideo && !dodata) {
5764 		JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, no audio, video or data have to be streamed...\n");
5765 		janus_mutex_lock(&mountpoints_mutex);
5766 		g_hash_table_remove(mountpoints_temp, &id);
5767 		janus_mutex_unlock(&mountpoints_mutex);
5768 		return NULL;
5769 	}
5770 	if(doaudio && (artpmap == NULL)) {
5771 		JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, missing mandatory information for audio...\n");
5772 		janus_mutex_lock(&mountpoints_mutex);
5773 		g_hash_table_remove(mountpoints_temp, &id);
5774 		janus_mutex_unlock(&mountpoints_mutex);
5775 		return NULL;
5776 	}
5777 	if(dovideo && (vcodec == 0 || vrtpmap == NULL)) {
5778 		JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, missing mandatory information for video...\n");
5779 		janus_mutex_lock(&mountpoints_mutex);
5780 		g_hash_table_remove(mountpoints_temp, &id);
5781 		janus_mutex_unlock(&mountpoints_mutex);
5782 		return NULL;
5783 	}
5784 	JANUS_LOG(LOG_VERB, "Audio %s, Video %s, Data %s\n",
5785 		doaudio ? "enabled" : "NOT enabled",
5786 		dovideo ? "enabled" : "NOT enabled",
5787 		dodata ? "enabled" : "NOT enabled");
5788 	/* First of all, let's check if the requested ports are free */
5789 	int audio_fd = -1;
5790 	int audio_rtcp_fd = -1;
5791 	char audiohost[46];
5792 	audiohost[0] = '\0';
5793 	if(doaudio) {
5794 		audio_fd = janus_streaming_create_fd(aport, amcast ? inet_addr(amcast) : INADDR_ANY, aiface,
5795 			audiohost, sizeof(audiohost), "Audio", "audio", name ? name : tempname, aport == 0);
5796 		if(audio_fd < 0) {
5797 			JANUS_LOG(LOG_ERR, "Can't bind to port %d for audio...\n", aport);
5798 			janus_mutex_lock(&mountpoints_mutex);
5799 			g_hash_table_remove(mountpoints_temp, &id);
5800 			janus_mutex_unlock(&mountpoints_mutex);
5801 			return NULL;
5802 		}
5803 		aport = janus_streaming_get_fd_port(audio_fd);
5804 		if(doaudiortcp) {
5805 			audio_rtcp_fd = janus_streaming_create_fd(artcpport, amcast ? inet_addr(amcast) : INADDR_ANY, aiface,
5806 				NULL, 0, "Audio", "audio", name ? name : tempname, artcpport == 0);
5807 			if(audio_rtcp_fd < 0) {
5808 				JANUS_LOG(LOG_ERR, "Can't bind to port %d for audio RTCP...\n", artcpport);
5809 				if(audio_fd > -1)
5810 					close(audio_fd);
5811 				janus_mutex_lock(&mountpoints_mutex);
5812 				g_hash_table_remove(mountpoints_temp, &id);
5813 				janus_mutex_unlock(&mountpoints_mutex);
5814 				return NULL;
5815 			}
5816 			artcpport = janus_streaming_get_fd_port(audio_rtcp_fd);
5817 		}
5818 	}
5819 	int video_fd[3] = {-1, -1, -1};
5820 	int video_rtcp_fd = -1;
5821 	char videohost[46];
5822 	videohost[0] = '\0';
5823 	if(dovideo) {
5824 		video_fd[0] = janus_streaming_create_fd(vport, vmcast ? inet_addr(vmcast) : INADDR_ANY, viface,
5825 			videohost, sizeof(videohost), "Video", "video", name ? name : tempname, vport == 0);
5826 		if(video_fd[0] < 0) {
5827 			JANUS_LOG(LOG_ERR, "Can't bind to port %d for video...\n", vport);
5828 			if(audio_fd > -1)
5829 				close(audio_fd);
5830 			if(audio_rtcp_fd > -1)
5831 				close(audio_rtcp_fd);
5832 			janus_mutex_lock(&mountpoints_mutex);
5833 			g_hash_table_remove(mountpoints_temp, &id);
5834 			janus_mutex_unlock(&mountpoints_mutex);
5835 			return NULL;
5836 		}
5837 		vport = janus_streaming_get_fd_port(video_fd[0]);
5838 		if(dovideortcp) {
5839 			video_rtcp_fd = janus_streaming_create_fd(vrtcpport, vmcast ? inet_addr(vmcast) : INADDR_ANY, viface,
5840 				NULL, 0, "Video", "video", name ? name : tempname, vrtcpport == 0);
5841 			if(video_rtcp_fd < 0) {
5842 				JANUS_LOG(LOG_ERR, "Can't bind to port %d for video RTCP...\n", vrtcpport);
5843 				if(audio_fd > -1)
5844 					close(audio_fd);
5845 				if(audio_rtcp_fd > -1)
5846 					close(audio_rtcp_fd);
5847 				if(video_fd[0] > -1)
5848 					close(video_fd[0]);
5849 				janus_mutex_lock(&mountpoints_mutex);
5850 				g_hash_table_remove(mountpoints_temp, &id);
5851 				janus_mutex_unlock(&mountpoints_mutex);
5852 				return NULL;
5853 			}
5854 			vrtcpport = janus_streaming_get_fd_port(video_rtcp_fd);
5855 		}
5856 		if(simulcast) {
5857 			video_fd[1] = janus_streaming_create_fd(vport2, vmcast ? inet_addr(vmcast) : INADDR_ANY, viface,
5858 				NULL, 0, "Video", "video", name ? name : tempname, FALSE);
5859 			if(video_fd[1] < 0) {
5860 				JANUS_LOG(LOG_ERR, "Can't bind to port %d for video (2nd port)...\n", vport2);
5861 				if(audio_fd > -1)
5862 					close(audio_fd);
5863 				if(audio_rtcp_fd > -1)
5864 					close(audio_rtcp_fd);
5865 				if(video_fd[0] > -1)
5866 					close(video_fd[0]);
5867 				if(video_rtcp_fd > -1)
5868 					close(video_rtcp_fd);
5869 				janus_mutex_lock(&mountpoints_mutex);
5870 				g_hash_table_remove(mountpoints_temp, &id);
5871 				janus_mutex_unlock(&mountpoints_mutex);
5872 				return NULL;
5873 			}
5874 			vport2 = janus_streaming_get_fd_port(video_fd[1]);
5875 			video_fd[2] = janus_streaming_create_fd(vport3, vmcast ? inet_addr(vmcast) : INADDR_ANY, viface,
5876 				NULL, 0, "Video", "video", name ? name : tempname, FALSE);
5877 			if(video_fd[2] < 0) {
5878 				JANUS_LOG(LOG_ERR, "Can't bind to port %d for video (3rd port)...\n", vport3);
5879 				if(audio_fd > -1)
5880 					close(audio_fd);
5881 				if(audio_rtcp_fd > -1)
5882 					close(audio_rtcp_fd);
5883 				if(video_rtcp_fd > -1)
5884 					close(video_rtcp_fd);
5885 				if(video_fd[0] > -1)
5886 					close(video_fd[0]);
5887 				if(video_fd[1] > -1)
5888 					close(video_fd[1]);
5889 				janus_mutex_lock(&mountpoints_mutex);
5890 				g_hash_table_remove(mountpoints_temp, &id);
5891 				janus_mutex_unlock(&mountpoints_mutex);
5892 				return NULL;
5893 			}
5894 			vport3 = janus_streaming_get_fd_port(video_fd[2]);
5895 		}
5896 	}
5897 	int data_fd = -1;
5898 	char datahost[46];
5899 	datahost[0] = '\0';
5900 	if(dodata) {
5901 #ifdef HAVE_SCTP
5902 		data_fd = janus_streaming_create_fd(dport, INADDR_ANY, diface,
5903 			datahost, sizeof(datahost), "Data", "data", name ? name : tempname, FALSE);
5904 		if(data_fd < 0) {
5905 			JANUS_LOG(LOG_ERR, "Can't bind to port %d for data...\n", dport);
5906 			if(audio_fd > -1)
5907 				close(audio_fd);
5908 			if(audio_rtcp_fd > -1)
5909 				close(audio_rtcp_fd);
5910 			if(video_rtcp_fd > -1)
5911 				close(video_rtcp_fd);
5912 			if(video_fd[0] > -1)
5913 				close(video_fd[0]);
5914 			if(video_fd[1] > -1)
5915 				close(video_fd[1]);
5916 			if(video_fd[2] > -1)
5917 				close(video_fd[2]);
5918 			janus_mutex_lock(&mountpoints_mutex);
5919 			g_hash_table_remove(mountpoints_temp, &id);
5920 			janus_mutex_unlock(&mountpoints_mutex);
5921 			return NULL;
5922 		}
5923 		dport = janus_streaming_get_fd_port(data_fd);
5924 #else
5925 		JANUS_LOG(LOG_WARN, "Mountpoint wants to do datachannel relaying, but datachannels support was not compiled...\n");
5926 		dodata = FALSE;
5927 #endif
5928 	}
5929 	/* Create the mountpoint */
5930 	janus_network_address nil;
5931 	janus_network_address_nullify(&nil);
5932 
5933 	janus_streaming_mountpoint *live_rtp = g_malloc0(sizeof(janus_streaming_mountpoint));
5934 	live_rtp->id = id;
5935 	live_rtp->id_str = g_strdup(id_str);
5936 	live_rtp->name = g_strdup(name ? name : tempname);
5937 	char *description = NULL;
5938 	if(desc != NULL)
5939 		description = g_strdup(desc);
5940 	else
5941 		description = g_strdup(name ? name : tempname);
5942 	live_rtp->description = description;
5943 	live_rtp->metadata = (metadata ? g_strdup(metadata) : NULL);
5944 	live_rtp->enabled = TRUE;
5945 	live_rtp->active = FALSE;
5946 	live_rtp->audio = doaudio;
5947 	live_rtp->video = dovideo;
5948 	live_rtp->data = dodata;
5949 	live_rtp->streaming_type = janus_streaming_type_live;
5950 	live_rtp->streaming_source = janus_streaming_source_rtp;
5951 	janus_streaming_rtp_source *live_rtp_source = g_malloc0(sizeof(janus_streaming_rtp_source));
5952 	/* First of all, let's check if we need to setup an SRTP mountpoint */
5953 	if(srtpsuite > 0 && srtpcrypto != NULL) {
5954 		/* Base64 decode the crypto string and set it as the SRTP context */
5955 		gsize len = 0;
5956 		guchar *decoded = g_base64_decode(srtpcrypto, &len);
5957 		if(len < SRTP_MASTER_LENGTH) {
5958 			JANUS_LOG(LOG_ERR, "Invalid SRTP crypto (%s)\n", srtpcrypto);
5959 			g_free(decoded);
5960 			if(audio_fd > -1)
5961 				close(audio_fd);
5962 			if(audio_rtcp_fd > -1)
5963 				close(audio_rtcp_fd);
5964 			if(video_rtcp_fd > -1)
5965 				close(video_rtcp_fd);
5966 			if(video_fd[0] > -1)
5967 				close(video_fd[0]);
5968 			if(video_fd[1] > -1)
5969 				close(video_fd[1]);
5970 			if(video_fd[2] > -1)
5971 				close(video_fd[2]);
5972 			if(data_fd > -1)
5973 				close(data_fd);
5974 			janus_mutex_lock(&mountpoints_mutex);
5975 			g_hash_table_remove(mountpoints_temp, &id);
5976 			janus_mutex_unlock(&mountpoints_mutex);
5977 			g_free(live_rtp_source);
5978 			g_free(live_rtp->name);
5979 			g_free(live_rtp->description);
5980 			g_free(live_rtp->metadata);
5981 			g_free(live_rtp);
5982 			return NULL;
5983 		}
5984 		/* Set SRTP policy */
5985 		srtp_policy_t *policy = &live_rtp_source->srtp_policy;
5986 		srtp_crypto_policy_set_rtp_default(&(policy->rtp));
5987 		if(srtpsuite == 32) {
5988 			srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&(policy->rtp));
5989 		} else if(srtpsuite == 80) {
5990 			srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&(policy->rtp));
5991 		}
5992 		policy->ssrc.type = ssrc_any_inbound;
5993 		policy->key = decoded;
5994 		policy->next = NULL;
5995 		/* Create SRTP context */
5996 		srtp_err_status_t res = srtp_create(&live_rtp_source->srtp_ctx, policy);
5997 		if(res != srtp_err_status_ok) {
5998 			/* Something went wrong... */
5999 			JANUS_LOG(LOG_ERR, "Error creating forwarder SRTP session: %d (%s)\n", res, janus_srtp_error_str(res));
6000 			g_free(decoded);
6001 			if(audio_fd > -1)
6002 				close(audio_fd);
6003 			if(audio_rtcp_fd > -1)
6004 				close(audio_rtcp_fd);
6005 			if(video_rtcp_fd > -1)
6006 				close(video_rtcp_fd);
6007 			if(video_fd[0] > -1)
6008 				close(video_fd[0]);
6009 			if(video_fd[1] > -1)
6010 				close(video_fd[1]);
6011 			if(video_fd[2] > -1)
6012 				close(video_fd[2]);
6013 			if(data_fd > -1)
6014 				close(data_fd);
6015 			janus_mutex_lock(&mountpoints_mutex);
6016 			g_hash_table_remove(mountpoints_temp, &id);
6017 			janus_mutex_unlock(&mountpoints_mutex);
6018 			g_free(live_rtp_source);
6019 			g_free(live_rtp->name);
6020 			g_free(live_rtp->description);
6021 			g_free(live_rtp->metadata);
6022 			g_free(live_rtp);
6023 			return NULL;
6024 		}
6025 		live_rtp_source->is_srtp = TRUE;
6026 		live_rtp_source->srtpsuite = srtpsuite;
6027 		live_rtp_source->srtpcrypto = g_strdup(srtpcrypto);
6028 	}
6029 	live_rtp_source->e2ee = e2ee;
6030 	live_rtp_source->audio_mcast = doaudio ? (amcast ? inet_addr(amcast) : INADDR_ANY) : INADDR_ANY;
6031 	live_rtp_source->audio_iface = doaudio && !janus_network_address_is_null(aiface) ? *aiface : nil;
6032 	live_rtp_source->audio_port = doaudio ? aport : -1;
6033 	live_rtp_source->audio_rtcp_port = artcpport;
6034 	live_rtp_source->askew = doaskew;
6035 	if(doaudio && strlen(audiohost) > 0)
6036 		live_rtp_source->audio_host = g_strdup(audiohost);
6037 	live_rtp_source->video_mcast = dovideo ? (vmcast ? inet_addr(vmcast) : INADDR_ANY) : INADDR_ANY;
6038 	live_rtp_source->video_port[0] = dovideo ? vport : -1;
6039 	live_rtp_source->video_rtcp_port = vrtcpport;
6040 	live_rtp_source->simulcast = dovideo && simulcast;
6041 	live_rtp_source->video_port[1] = live_rtp_source->simulcast ? vport2 : -1;
6042 	live_rtp_source->video_port[2] = live_rtp_source->simulcast ? vport3 : -1;
6043 	live_rtp_source->video_iface = dovideo && !janus_network_address_is_null(viface) ? *viface : nil;
6044 	live_rtp_source->vskew = dovskew;
6045 	if(dovideo && strlen(videohost) > 0)
6046 		live_rtp_source->video_host = g_strdup(videohost);
6047 	live_rtp_source->data_port = dodata ? dport : -1;
6048 	live_rtp_source->data_iface = dodata && !janus_network_address_is_null(diface) ? *diface : nil;
6049 	if(dodata && strlen(datahost) > 0)
6050 		live_rtp_source->data_host = g_strdup(datahost);
6051 	live_rtp_source->arc = NULL;
6052 	live_rtp_source->vrc = NULL;
6053 	live_rtp_source->drc = NULL;
6054 	janus_rtp_switching_context_reset(&live_rtp_source->context[0]);
6055 	janus_rtp_switching_context_reset(&live_rtp_source->context[1]);
6056 	janus_rtp_switching_context_reset(&live_rtp_source->context[2]);
6057 	janus_mutex_init(&live_rtp_source->rec_mutex);
6058 	live_rtp_source->audio_fd = audio_fd;
6059 	live_rtp_source->audio_rtcp_fd = audio_rtcp_fd;
6060 	live_rtp_source->video_rtcp_fd = video_rtcp_fd;
6061 	live_rtp_source->video_fd[0] = video_fd[0];
6062 	live_rtp_source->video_fd[1] = video_fd[1];
6063 	live_rtp_source->video_fd[2] = video_fd[2];
6064 	live_rtp_source->data_fd = data_fd;
6065 	live_rtp_source->pipefd[0] = -1;
6066 	live_rtp_source->pipefd[1] = -1;
6067 	pipe(live_rtp_source->pipefd);
6068 	live_rtp_source->last_received_audio = janus_get_monotonic_time();
6069 	live_rtp_source->last_received_video = janus_get_monotonic_time();
6070 	live_rtp_source->last_received_data = janus_get_monotonic_time();
6071 	live_rtp_source->keyframe.enabled = bufferkf;
6072 	live_rtp_source->keyframe.latest_keyframe = NULL;
6073 	live_rtp_source->keyframe.temp_keyframe = NULL;
6074 	live_rtp_source->keyframe.temp_ts = 0;
6075 	janus_mutex_init(&live_rtp_source->keyframe.mutex);
6076 	live_rtp_source->rtp_collision = rtp_collision;
6077 	live_rtp_source->textdata = textdata;
6078 	live_rtp_source->buffermsg = buffermsg;
6079 	live_rtp_source->last_msg = NULL;
6080 	janus_mutex_init(&live_rtp_source->buffermsg_mutex);
6081 	live_rtp->source = live_rtp_source;
6082 	live_rtp->source_destroy = (GDestroyNotify) janus_streaming_rtp_source_free;
6083 	live_rtp->codecs.audio_pt = doaudio ? acodec : -1;
6084 	live_rtp->codecs.audio_rtpmap = doaudio ? g_strdup(artpmap) : NULL;
6085 	live_rtp->codecs.audio_fmtp = doaudio ? (afmtp ? g_strdup(afmtp) : NULL) : NULL;
6086 	live_rtp->codecs.video_codec = JANUS_VIDEOCODEC_NONE;
6087 	if(dovideo) {
6088 		if(strstr(vrtpmap, "vp8") || strstr(vrtpmap, "VP8"))
6089 			live_rtp->codecs.video_codec = JANUS_VIDEOCODEC_VP8;
6090 		else if(strstr(vrtpmap, "vp9") || strstr(vrtpmap, "VP9"))
6091 			live_rtp->codecs.video_codec = JANUS_VIDEOCODEC_VP9;
6092 		else if(strstr(vrtpmap, "h264") || strstr(vrtpmap, "H264"))
6093 			live_rtp->codecs.video_codec = JANUS_VIDEOCODEC_H264;
6094 		else if(strstr(vrtpmap, "av1") || strstr(vrtpmap, "AV1"))
6095 			live_rtp->codecs.video_codec = JANUS_VIDEOCODEC_AV1;
6096 		else if(strstr(vrtpmap, "h265") || strstr(vrtpmap, "H265"))
6097 			live_rtp->codecs.video_codec = JANUS_VIDEOCODEC_H265;
6098 	}
6099 	if(svc) {
6100 		if(live_rtp->codecs.video_codec == JANUS_VIDEOCODEC_VP9) {
6101 			live_rtp_source->svc = TRUE;
6102 		} else {
6103 			JANUS_LOG(LOG_WARN, "SVC is only supported, in an experimental way, for VP9-SVC mountpoints: disabling it...\n");
6104 		}
6105 	}
6106 	live_rtp->codecs.video_pt = dovideo ? vcodec : -1;
6107 	live_rtp->codecs.video_rtpmap = dovideo ? g_strdup(vrtpmap) : NULL;
6108 	live_rtp->codecs.video_fmtp = dovideo ? (vfmtp ? g_strdup(vfmtp) : NULL) : NULL;
6109 	live_rtp->viewers = NULL;
6110 	g_atomic_int_set(&live_rtp->destroyed, 0);
6111 	janus_refcount_init(&live_rtp->ref, janus_streaming_mountpoint_free);
6112 	janus_mutex_init(&live_rtp->mutex);
6113 	janus_mutex_lock(&mountpoints_mutex);
6114 	g_hash_table_insert(mountpoints,
6115 		string_ids ? (gpointer)g_strdup(live_rtp->id_str) : (gpointer)janus_uint64_dup(live_rtp->id),
6116 		live_rtp);
6117 	g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)live_rtp->id_str : (gpointer)&live_rtp->id);
6118 	/* If we need helper threads, spawn them now */
6119 	GError *error = NULL;
6120 	char tname[16];
6121 	if(threads > 0) {
6122 		int i=0;
6123 		for(i=0; i<threads; i++) {
6124 			janus_streaming_helper *helper = g_malloc0(sizeof(janus_streaming_helper));
6125 			helper->id = i+1;
6126 			helper->mp = live_rtp;
6127 			helper->queued_packets = g_async_queue_new_full((GDestroyNotify)janus_streaming_rtp_relay_packet_free);
6128 			janus_mutex_init(&helper->mutex);
6129 			janus_refcount_init(&helper->ref, janus_streaming_helper_free);
6130 			live_rtp->helper_threads++;
6131 			/* Spawn a thread and add references */
6132 			g_snprintf(tname, sizeof(tname), "help %u-%"SCNu64, helper->id, live_rtp->id);
6133 			janus_refcount_increase(&live_rtp->ref);
6134 			janus_refcount_increase(&helper->ref);
6135 			helper->thread = g_thread_try_new(tname, &janus_streaming_helper_thread, helper, &error);
6136 			if(error != NULL) {
6137 				JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the helper thread...\n",
6138 					error->code, error->message ? error->message : "??");
6139 				g_error_free(error);
6140 				janus_refcount_decrease(&live_rtp->ref);	/* This is for the helper thread */
6141 				g_async_queue_unref(helper->queued_packets);
6142 				janus_refcount_decrease(&helper->ref);
6143 				/* This extra unref is for the init */
6144 				janus_refcount_decrease(&helper->ref);
6145 				janus_mutex_unlock(&mountpoints_mutex);
6146 				janus_streaming_mountpoint_destroy(live_rtp);
6147 				return NULL;
6148 			}
6149 			janus_refcount_increase(&helper->ref);
6150 			live_rtp->threads = g_list_append(live_rtp->threads, helper);
6151 		}
6152 	}
6153 	janus_mutex_unlock(&mountpoints_mutex);
6154 	/* Finally, create the mountpoint thread itself */
6155 	g_snprintf(tname, sizeof(tname), "mp %s", live_rtp->id_str);
6156 	janus_refcount_increase(&live_rtp->ref);
6157 	live_rtp->thread = g_thread_try_new(tname, &janus_streaming_relay_thread, live_rtp, &error);
6158 	if(error != NULL) {
6159 		JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the RTP thread...\n",
6160 			error->code, error->message ? error->message : "??");
6161 		g_error_free(error);
6162 		janus_refcount_decrease(&live_rtp->ref);	/* This is for the failed thread */
6163 		janus_streaming_mountpoint_destroy(live_rtp);
6164 		return NULL;
6165 	}
6166 	return live_rtp;
6167 }
6168 
6169 /* Helper to create a file/ondemand live source */
6170 janus_streaming_mountpoint *janus_streaming_create_file_source(
6171 		uint64_t id, char *id_str, char *name, char *desc, char *metadata, char *filename, gboolean live,
6172 		gboolean doaudio, uint8_t acodec, char *artpmap, char *afmtp, gboolean dovideo) {
6173 	char id_num[30];
6174 	if(!string_ids) {
6175 		g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id);
6176 		id_str = id_num;
6177 	}
6178 	if(filename == NULL) {
6179 		JANUS_LOG(LOG_ERR, "Can't add 'live' stream, missing filename...\n");
6180 		return NULL;
6181 	}
6182 	if(name == NULL) {
6183 		JANUS_LOG(LOG_VERB, "Missing name, will generate a random one...\n");
6184 	}
6185 	if(!doaudio && !dovideo) {
6186 		JANUS_LOG(LOG_ERR, "Can't add 'file' stream, no audio or video have to be streamed...\n");
6187 		janus_mutex_lock(&mountpoints_mutex);
6188 		g_hash_table_remove(mountpoints_temp, &id);
6189 		janus_mutex_unlock(&mountpoints_mutex);
6190 		return NULL;
6191 	}
6192 	/* FIXME We don't support video streaming from file yet */
6193 	if(!doaudio || dovideo) {
6194 		JANUS_LOG(LOG_ERR, "Can't add 'file' stream, we only support audio file streaming right now...\n");
6195 		janus_mutex_lock(&mountpoints_mutex);
6196 		g_hash_table_remove(mountpoints_temp, &id);
6197 		janus_mutex_unlock(&mountpoints_mutex);
6198 		return NULL;
6199 	}
6200 	/* TODO We should support something more than raw a-Law and mu-Law streams... */
6201 #ifdef HAVE_LIBOGG
6202 	if(!strstr(filename, ".opus") && !strstr(filename, ".alaw") && !strstr(filename, ".mulaw")) {
6203 		JANUS_LOG(LOG_ERR, "Can't add 'file' stream, unsupported format (we only support Opus and raw mu-Law/a-Law files right now)\n");
6204 #else
6205 	if(!strstr(filename, ".alaw") && !strstr(filename, ".mulaw")) {
6206 		JANUS_LOG(LOG_ERR, "Can't add 'file' stream, unsupported format (we only support raw mu-Law and a-Law files right now)\n");
6207 #endif
6208 		janus_mutex_lock(&mountpoints_mutex);
6209 		g_hash_table_remove(mountpoints_temp, &id);
6210 		janus_mutex_unlock(&mountpoints_mutex);
6211 		return NULL;
6212 	}
6213 #ifdef HAVE_LIBOGG
6214 	if(strstr(filename, ".opus") && (artpmap == NULL || strstr(artpmap, "opus/48000") == NULL)) {
6215 		JANUS_LOG(LOG_ERR, "Can't add 'file' stream, opus file is not associated with an opus rtpmap\n");
6216 		janus_mutex_lock(&mountpoints_mutex);
6217 		g_hash_table_remove(mountpoints_temp, &id);
6218 		janus_mutex_unlock(&mountpoints_mutex);
6219 		return NULL;
6220 	}
6221 #endif
6222 	janus_streaming_mountpoint *file_source = g_malloc0(sizeof(janus_streaming_mountpoint));
6223 	file_source->id = id;
6224 	file_source->id_str = g_strdup(id_str);
6225 	char tempname[255];
6226 	if(!name) {
6227 		memset(tempname, 0, 255);
6228 		g_snprintf(tempname, 255, "mp-%s", file_source->id_str);
6229 	} else if(atoi(name) != 0) {
6230 		memset(tempname, 0, 255);
6231 		g_snprintf(tempname, 255, "mp-%s", name);
6232 		name = NULL;
6233 	}
6234 	file_source->name = g_strdup(name ? name : tempname);
6235 	char *description = NULL;
6236 	if(desc != NULL)
6237 		description = g_strdup(desc);
6238 	else
6239 		description = g_strdup(name ? name : tempname);
6240 	file_source->description = description;
6241 	file_source->metadata = (metadata ? g_strdup(metadata) : NULL);
6242 	file_source->enabled = TRUE;
6243 	file_source->active = FALSE;
6244 	file_source->audio = TRUE;
6245 	file_source->video = FALSE;
6246 	file_source->data = FALSE;
6247 	file_source->streaming_type = live ? janus_streaming_type_live : janus_streaming_type_on_demand;
6248 	file_source->streaming_source = janus_streaming_source_file;
6249 	janus_streaming_file_source *file_source_source = g_malloc0(sizeof(janus_streaming_file_source));
6250 	file_source_source->filename = g_strdup(filename);
6251 	file_source->source = file_source_source;
6252 	file_source->source_destroy = (GDestroyNotify) janus_streaming_file_source_free;
6253 	if(strstr(filename, ".opus")) {
6254 		file_source_source->opus = TRUE;
6255 		file_source->codecs.audio_pt = acodec;
6256 		file_source->codecs.audio_rtpmap = g_strdup(artpmap);
6257 		file_source->codecs.audio_fmtp = afmtp ? g_strdup(afmtp) : NULL;
6258 	} else {
6259 		file_source->codecs.audio_pt = strstr(filename, ".alaw") ? 8 : 0;
6260 		file_source->codecs.audio_rtpmap = g_strdup(strstr(filename, ".alaw") ? "PCMA/8000" : "PCMU/8000");
6261 	}
6262 	file_source->codecs.video_pt = -1;	/* FIXME We don't support video for this type yet */
6263 	file_source->codecs.video_rtpmap = NULL;
6264 	file_source->viewers = NULL;
6265 	g_atomic_int_set(&file_source->destroyed, 0);
6266 	janus_refcount_init(&file_source->ref, janus_streaming_mountpoint_free);
6267 	janus_mutex_init(&file_source->mutex);
6268 	janus_mutex_lock(&mountpoints_mutex);
6269 	g_hash_table_insert(mountpoints,
6270 		string_ids ? (gpointer)g_strdup(file_source->id_str) : (gpointer)janus_uint64_dup(file_source->id),
6271 		file_source);
6272 	g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)file_source->id_str : (gpointer)&file_source->id);
6273 	janus_mutex_unlock(&mountpoints_mutex);
6274 	if(live) {
6275 		GError *error = NULL;
6276 		char tname[16];
6277 		g_snprintf(tname, sizeof(tname), "mp %s", file_source->id_str);
6278 		janus_refcount_increase(&file_source->ref);
6279 		file_source->thread = g_thread_try_new(tname, &janus_streaming_filesource_thread, file_source, &error);
6280 		if(error != NULL) {
6281 			JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the live filesource thread...\n",
6282 				error->code, error->message ? error->message : "??");
6283 			g_error_free(error);
6284 			janus_refcount_decrease(&file_source->ref);		/* This is for the failed thread */
6285 			janus_refcount_decrease(&file_source->ref);
6286 			return NULL;
6287 		}
6288 	}
6289 	return file_source;
6290 }
6291 
6292 #ifdef HAVE_LIBCURL
6293 static size_t janus_streaming_rtsp_curl_callback(void *payload, size_t size, size_t nmemb, void *data) {
6294 	size_t realsize = size * nmemb;
6295 	janus_streaming_buffer *buf = (struct janus_streaming_buffer *)data;
6296 	/* (Re)allocate if needed */
6297 	buf->buffer = realloc(buf->buffer, buf->size+realsize+1);
6298 	/* Update the buffer */
6299 	memcpy(&(buf->buffer[buf->size]), payload, realsize);
6300 	buf->size += realsize;
6301 	buf->buffer[buf->size] = 0;
6302 	/* Done! */
6303 	return realsize;
6304 }
6305 
6306 static int janus_streaming_rtsp_parse_sdp(const char *buffer, const char *name, const char *media, char *base, int *pt,
6307 		char *transport, char *host, char *rtpmap, char *fmtp, char *control, const janus_network_address *iface, multiple_fds *fds) {
6308 	/* Start by checking if there's any Content-Base header we should be aware of */
6309 	const char *cb = strstr(buffer, "Content-Base:");
6310 	if(cb == NULL)
6311 		cb = strstr(buffer, "content-base:");
6312 	if(cb != NULL) {
6313 		cb = strstr(cb, "rtsp://");
6314 		const char *crlf = (cb ? strstr(cb, "\r\n") : NULL);
6315 		if(crlf != NULL && base != NULL) {
6316 			gulong size = (crlf-cb)+1;
6317 			if(size > 256)
6318 				size = 256;
6319 			g_snprintf(base, size, "%s", cb);
6320 			if(base[size-2] == '/')
6321 				base[size-2] = '\0';
6322 		}
6323 	}
6324 	/* Parse the SDP now */
6325 	char pattern[256];
6326 	g_snprintf(pattern, sizeof(pattern), "m=%s", media);
6327 	char *m = strstr(buffer, pattern);
6328 	if(m == NULL) {
6329 		JANUS_LOG(LOG_VERB, "[%s] no media %s...\n", name, media);
6330 		return -1;
6331 	}
6332 	sscanf(m, "m=%*s %*d %*s %d", pt);
6333 	char *s = strstr(m, "a=control:");
6334 	if(s == NULL) {
6335 		JANUS_LOG(LOG_ERR, "[%s] no control for %s...\n", name, media);
6336 		return -1;
6337 	}
6338 	sscanf(s, "a=control:%2047s", control);
6339 	char *r = strstr(m, "a=rtpmap:");
6340 	if(r != NULL) {
6341 		if (sscanf(r, "a=rtpmap:%*d%*[ ]%2047[^\r\n]s", rtpmap) != 1) {
6342 			JANUS_LOG(LOG_ERR, "[%s] cannot parse %s rtpmap...\n", name, media);
6343 			return -1;
6344 		}
6345 	}
6346 	char *f = strstr(m, "a=fmtp:");
6347 	if(f != NULL) {
6348 		if (sscanf(f, "a=fmtp:%*d%*[ ]%2047[^\r\n]s", fmtp) != 1) {
6349 			JANUS_LOG(LOG_ERR, "[%s] cannot parse %s fmtp...\n", name, media);
6350 			return -1;
6351 		}
6352 	}
6353 	char *c = strstr(m, "c=IN IP4");
6354 	if(c == NULL) {
6355 		/* No m-line c= attribute? try in the whole SDP */
6356 		c = strstr(buffer, "c=IN IP4");
6357 	}
6358 	char ip[256];
6359 	in_addr_t mcast = INADDR_ANY;
6360 	if(c != NULL) {
6361 		if(sscanf(c, "c=IN IP4 %255[^/]", ip) != 0) {
6362 			memcpy(host, ip, sizeof(ip));
6363 			c = strstr(host, "\r\n");
6364 			if(c)
6365 				*c = '\0';
6366 			mcast = inet_addr(ip);
6367 		}
6368 	}
6369 	/* Bind two adjacent ports for RTP and RTCP */
6370 	int ports[2];
6371 	if(janus_streaming_allocate_port_pair(name, media, mcast, iface, fds, ports)) {
6372 		JANUS_LOG(LOG_ERR, "[%s] Bind failed for %s...\n", name, media);
6373 		return -1;
6374 	}
6375 
6376 	if(IN_MULTICAST(ntohl(mcast))) {
6377 		g_snprintf(transport, 1024, "RTP/AVP/UDP;multicast;client_port=%d-%d", ports[0], ports[1]);
6378 	} else {
6379 		g_snprintf(transport, 1024, "RTP/AVP/UDP;unicast;client_port=%d-%d", ports[0], ports[1]);
6380 	}
6381 
6382 	return 0;
6383 }
6384 
6385 /* Helper function to calculating the minimum value if 'a' is bigger than zero */
6386 static inline gint64 janus_streaming_min_if(gint64 a, gint64 b) {
6387 	return a > 0 ? (a > b ? b : a) : b;
6388 }
6389 
6390 /* Static helper to connect to an RTSP server, considering we might do this either
6391  * when creating a new mountpoint, or when reconnecting after some failure */
6392 static int janus_streaming_rtsp_connect_to_server(janus_streaming_mountpoint *mp) {
6393 	if(mp == NULL)
6394 		return -1;
6395 	janus_streaming_rtp_source *source = (janus_streaming_rtp_source *)mp->source;
6396 	if(source == NULL)
6397 		return -1;
6398 
6399 	char *name = mp->name;
6400 	gboolean doaudio = mp->audio;
6401 	gboolean dovideo = mp->video;
6402 
6403 	CURL *curl = curl_easy_init();
6404 	if(curl == NULL) {
6405 		JANUS_LOG(LOG_ERR, "Can't init CURL\n");
6406 		return -1;
6407 	}
6408 	if(janus_log_level > LOG_INFO)
6409 		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
6410 	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
6411 	curl_easy_setopt(curl, CURLOPT_URL, source->rtsp_url);
6412 	curl_easy_setopt(curl, CURLOPT_TIMEOUT, source->rtsp_timeout);
6413 	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, source->rtsp_conn_timeout);
6414 	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 0L);
6415 	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
6416 #if CURL_AT_LEAST_VERSION(7, 66, 0)
6417 	curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_RTSP);
6418 	curl_easy_setopt(curl, CURLOPT_HTTP09_ALLOWED, 1L);
6419 #endif
6420 	/* Any authentication to take into account? */
6421 	if(source->rtsp_username && source->rtsp_password) {
6422 		/* Point out that digest authentication is only available is libcurl >= 7.45.0 */
6423 		if(LIBCURL_VERSION_NUM < 0x072d00) {
6424 			JANUS_LOG(LOG_WARN, "RTSP digest authentication unsupported (needs libcurl >= 7.45.0)\n");
6425 		}
6426 		curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
6427 		curl_easy_setopt(curl, CURLOPT_USERNAME, source->rtsp_username);
6428 		curl_easy_setopt(curl, CURLOPT_PASSWORD, source->rtsp_password);
6429 	}
6430 	/* Send an RTSP DESCRIBE */
6431 	janus_streaming_buffer *curldata = g_malloc(sizeof(janus_streaming_buffer));
6432 	curldata->buffer = g_malloc0(1);
6433 	curldata->size = 0;
6434 	curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, source->rtsp_url);
6435 	curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_DESCRIBE);
6436 	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, janus_streaming_rtsp_curl_callback);
6437 	curl_easy_setopt(curl, CURLOPT_WRITEDATA, curldata);
6438 	curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, janus_streaming_rtsp_curl_callback);
6439 	curl_easy_setopt(curl, CURLOPT_HEADERDATA, curldata);
6440 	int res = curl_easy_perform(curl);
6441 	if(res != CURLE_OK) {
6442 		JANUS_LOG(LOG_ERR, "Couldn't send DESCRIBE request: %s\n", curl_easy_strerror(res));
6443 		curl_easy_cleanup(curl);
6444 		g_free(curldata->buffer);
6445 		g_free(curldata);
6446 		return -2;
6447 	}
6448 	long code = 0;
6449 	res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
6450 	if(res != CURLE_OK) {
6451 		JANUS_LOG(LOG_ERR, "Couldn't get DESCRIBE answer: %s\n", curl_easy_strerror(res));
6452 		curl_easy_cleanup(curl);
6453 		g_free(curldata->buffer);
6454 		g_free(curldata);
6455 		return -3;
6456 	} else if(code != 200) {
6457 		JANUS_LOG(LOG_ERR, "Couldn't get DESCRIBE code: %ld\n", code);
6458 		curl_easy_cleanup(curl);
6459 		g_free(curldata->buffer);
6460 		g_free(curldata);
6461 		return -4;
6462 	}
6463 	JANUS_LOG(LOG_VERB, "DESCRIBE answer:%s\n", curldata->buffer);
6464 	/* Parse the SDP we just got to figure out the negotiated media */
6465 	int vpt = -1;
6466 	char vrtpmap[2048];
6467 	vrtpmap[0] = '\0';
6468 	char vfmtp[2048];
6469 	vfmtp[0] = '\0';
6470 	char vcontrol[2048];
6471 	char uri[1024];
6472 	char vtransport[1024];
6473 	char vhost[256];
6474 	vhost[0] = '\0';
6475 	char vbase[256];
6476 	vbase[0] = '\0';
6477 	int vsport = 0, vsport_rtcp = 0;
6478 	multiple_fds video_fds = {-1, -1};
6479 
6480 	int apt = -1;
6481 	char artpmap[2048];
6482 	artpmap[0] = '\0';
6483 	char afmtp[2048];
6484 	afmtp[0] = '\0';
6485 	char acontrol[2048];
6486 	char atransport[1024];
6487 	char ahost[256];
6488 	ahost[0] = '\0';
6489 	char abase[256];
6490 	abase[0] = '\0';
6491 	int asport = 0, asport_rtcp = 0;
6492 	multiple_fds audio_fds = {-1, -1};
6493 
6494 	while (!janus_mutex_trylock(&mountpoints_mutex)) {
6495 		if(g_atomic_int_get(&mp->destroyed)) {
6496 			JANUS_LOG(LOG_WARN, "[%s] Destroying mountpoint while trying to reconnect, aborting\n", mp->name);
6497 			curl_easy_cleanup(curl);
6498 			g_free(curldata->buffer);
6499 			g_free(curldata);
6500 			return -8;
6501 		}
6502 
6503 		g_usleep(1000);
6504 	}
6505 
6506 	/* Parse both video and audio first before proceed to setup as curldata will be reused */
6507 	int vresult = -1;
6508 	if(dovideo) {
6509 		vresult = janus_streaming_rtsp_parse_sdp(curldata->buffer, name, "video", vbase, &vpt,
6510 			vtransport, vhost, vrtpmap, vfmtp, vcontrol, &source->video_iface, &video_fds);
6511 	}
6512 	int aresult = -1;
6513 	if(doaudio) {
6514 		aresult = janus_streaming_rtsp_parse_sdp(curldata->buffer, name, "audio", abase, &apt,
6515 			atransport, ahost, artpmap, afmtp, acontrol, &source->audio_iface, &audio_fds);
6516 	}
6517 	janus_mutex_unlock(&mountpoints_mutex);
6518 
6519 	if(vresult == -1 && aresult == -1) {
6520 		/* Both audio and video failed? Give up... */
6521 		curl_easy_cleanup(curl);
6522 		g_free(curldata->buffer);
6523 		g_free(curldata);
6524 		return -7;
6525 	}
6526 
6527 	/* Check if a query string is part of the URL, as that may impact the SETUP request */
6528 	char *rtsp_url = source->rtsp_url, *rtsp_querystring = NULL;
6529 	char **parts = g_strsplit(source->rtsp_url, "?", 2);
6530 	if(parts[0] != NULL) {
6531 		rtsp_url = parts[0];
6532 		rtsp_querystring = parts[1];
6533 	}
6534 
6535 	if(vresult != -1) {
6536 		/* Identify video codec (useful for keyframe detection) */
6537 		mp->codecs.video_codec = JANUS_VIDEOCODEC_NONE;
6538 		if(strstr(vrtpmap, "vp8") || strstr(vrtpmap, "VP8"))
6539 			mp->codecs.video_codec = JANUS_VIDEOCODEC_VP8;
6540 		else if(strstr(vrtpmap, "vp9") || strstr(vrtpmap, "VP9"))
6541 			mp->codecs.video_codec = JANUS_VIDEOCODEC_VP9;
6542 		else if(strstr(vrtpmap, "h264") || strstr(vrtpmap, "H264"))
6543 			mp->codecs.video_codec = JANUS_VIDEOCODEC_H264;
6544 
6545 		/* Send an RTSP SETUP for video */
6546 		g_free(curldata->buffer);
6547 		curldata->buffer = g_malloc0(1);
6548 		curldata->size = 0;
6549 		gboolean add_qs = (rtsp_querystring != NULL);
6550 		if(add_qs && strstr(vcontrol, rtsp_querystring) != NULL)
6551 			add_qs = FALSE;
6552 		if(strstr(vcontrol, (strlen(vbase) > 0 ? vbase : rtsp_url)) == vcontrol) {
6553 			/* The control attribute already contains the whole URL? */
6554 			g_snprintf(uri, sizeof(uri), "%s%s%s", vcontrol,
6555 				add_qs ? "?" : "", add_qs ? rtsp_querystring : "");
6556 		} else {
6557 			/* Append the control attribute to the URL */
6558 			g_snprintf(uri, sizeof(uri), "%s/%s%s%s", (strlen(vbase) > 0 ? vbase : rtsp_url),
6559 				vcontrol, add_qs ? "?" : "", add_qs ? rtsp_querystring : "");
6560 		}
6561 		curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri);
6562 		curl_easy_setopt(curl, CURLOPT_RTSP_TRANSPORT, vtransport);
6563 		curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
6564 		res = curl_easy_perform(curl);
6565 		if(res != CURLE_OK) {
6566 			JANUS_LOG(LOG_ERR, "Couldn't send SETUP request: %s\n", curl_easy_strerror(res));
6567 			g_strfreev(parts);
6568 			curl_easy_cleanup(curl);
6569 			g_free(curldata->buffer);
6570 			g_free(curldata);
6571 			if(video_fds.fd != -1) close(video_fds.fd);
6572 			if(video_fds.rtcp_fd != -1) close(video_fds.rtcp_fd);
6573 			if(audio_fds.fd != -1) close(audio_fds.fd);
6574 			if(audio_fds.rtcp_fd != -1) close(audio_fds.rtcp_fd);
6575 			return -5;
6576 		} else if(code != 200) {
6577 			JANUS_LOG(LOG_ERR, "Couldn't get SETUP code: %ld\n", code);
6578 			g_strfreev(parts);
6579 			curl_easy_cleanup(curl);
6580 			g_free(curldata->buffer);
6581 			g_free(curldata);
6582 			if(video_fds.fd != -1) close(video_fds.fd);
6583 			if(video_fds.rtcp_fd != -1) close(video_fds.rtcp_fd);
6584 			if(audio_fds.fd != -1) close(audio_fds.fd);
6585 			if(audio_fds.rtcp_fd != -1) close(audio_fds.rtcp_fd);
6586 			return -5;
6587 		}
6588 		JANUS_LOG(LOG_VERB, "SETUP answer:%s\n", curldata->buffer);
6589 		/* Parse the RTSP message: we may need Transport and Session */
6590 		gboolean success = TRUE;
6591 		gchar **parts = g_strsplit(curldata->buffer, "\n", -1);
6592 		if(parts) {
6593 			int index = 0;
6594 			char *line = NULL, *cr = NULL;
6595 			while(success && (line = parts[index]) != NULL) {
6596 				cr = strchr(line, '\r');
6597 				if(cr != NULL)
6598 					*cr = '\0';
6599 				if(*line == '\0') {
6600 					if(cr != NULL)
6601 						*cr = '\r';
6602 					index++;
6603 					continue;
6604 				}
6605 				if(strlen(line) < 3) {
6606 					JANUS_LOG(LOG_ERR, "Invalid RTSP line (%zu bytes): %s\n", strlen(line), line);
6607 					success = FALSE;
6608 					break;
6609 				}
6610 				/* Check if this is a Transport or Session header, and if so parse it */
6611 				gboolean is_transport = (strstr(line, "Transport:") == line || strstr(line, "transport:") == line);
6612 				gboolean is_session = (strstr(line, "Session:") == line || strstr(line, "session:") == line);
6613 				if(is_transport || is_session) {
6614 					/* There is, iterate on all params */
6615 					char *p = line, param[100], *pi = NULL;
6616 					int read = 0;
6617 					gboolean first = TRUE;
6618 					while(sscanf(p, "%99[^;]%n", param, &read) == 1) {
6619 						if(first) {
6620 							/* Skip */
6621 							first = FALSE;
6622 						} else {
6623 							pi = param;
6624 							while(*pi == ' ')
6625 								pi++;
6626 							char name[50], value[50];
6627 							if(sscanf(pi, "%49[a-zA-Z_0-9]=%49s", name, value) == 2) {
6628 								if(is_transport) {
6629 									if(!strcasecmp(name, "ssrc")) {
6630 										/* Take note of the video SSRC */
6631 										uint32_t ssrc = strtol(value, NULL, 16);
6632 										JANUS_LOG(LOG_VERB, "  -- SSRC (video): %"SCNu32"\n", ssrc);
6633 										source->video_ssrc = ssrc;
6634 									} else if(!strcasecmp(name, "source")) {
6635 										/* If we got an address via c-line, replace it */
6636 										g_snprintf(vhost, sizeof(vhost), "%s", value);
6637 										JANUS_LOG(LOG_VERB, "  -- Source (video): %s\n", vhost);
6638 									} else if(!strcasecmp(name, "server_port")) {
6639 										/* Take note of the server port */
6640 										char *dash = NULL;
6641 										vsport = strtol(value, &dash, 10);
6642 										vsport_rtcp = dash ? strtol(++dash, NULL, 10) : 0;
6643 										JANUS_LOG(LOG_VERB, "  -- RTP port (video): %d\n", vsport);
6644 										JANUS_LOG(LOG_VERB, "  -- RTCP port (video): %d\n", vsport_rtcp);
6645 									}
6646 								} else if(is_session) {
6647 									if(!strcasecmp(name, "timeout")) {
6648 										/* Take note of the timeout, for keep-alives */
6649 										source->ka_timeout = janus_streaming_min_if(source->session_timeout, (gint64)atoi(value) / 2 * G_USEC_PER_SEC);
6650 										JANUS_LOG(LOG_VERB, "  -- RTSP session timeout (video): %"SCNi64" ms\n", source->ka_timeout / 1000);
6651 									}
6652 								}
6653 							}
6654 						}
6655 						/* Move to the next param */
6656 						p += read;
6657 						if(*p != ';')
6658 							break;
6659 						while(*p == ';')
6660 							p++;
6661 					}
6662 				}
6663 				if(cr != NULL)
6664 					*cr = '\r';
6665 				index++;
6666 			}
6667 			if(cr != NULL)
6668 				*cr = '\r';
6669 			g_strfreev(parts);
6670 		}
6671 #ifdef HAVE_LIBCURL
6672 #if CURL_AT_LEAST_VERSION(7, 62, 0)
6673 		/* If we don't have a host yet (no c-line, no source in Transport), use the server address */
6674 		if(strlen(vhost) == 0 || !strcmp(vhost, "0.0.0.0")) {
6675 			JANUS_LOG(LOG_WARN, "No c-line or source for RTSP video address, resolving server address...\n");
6676 			CURLU *url = curl_url();
6677 			if(url != NULL) {
6678 				CURLUcode code = curl_url_set(url, CURLUPART_URL, source->rtsp_url, 0);
6679 				if(code == 0) {
6680 					char *host = NULL;
6681 					code = curl_url_get(url, CURLUPART_HOST, &host, 0);
6682 					if(code == 0) {
6683 						/* Resolve the address */
6684 						struct addrinfo *info = NULL, *start = NULL;
6685 						janus_network_address addr;
6686 						janus_network_address_string_buffer addr_buf;
6687 						if(getaddrinfo(host, NULL, NULL, &info) == 0) {
6688 							start = info;
6689 							while(info != NULL) {
6690 								if(janus_network_address_from_sockaddr(info->ai_addr, &addr) == 0 &&
6691 										janus_network_address_to_string_buffer(&addr, &addr_buf) == 0) {
6692 									/* Resolved */
6693 									g_snprintf(vhost, sizeof(vhost), "%s",
6694 										janus_network_address_string_from_buffer(&addr_buf));
6695 									JANUS_LOG(LOG_VERB, "   -- %s\n", vhost);
6696 									break;
6697 								}
6698 								info = info->ai_next;
6699 							}
6700 						}
6701 						if(start)
6702 							freeaddrinfo(start);
6703 						curl_free(host);
6704 					}
6705 				}
6706 				curl_url_cleanup(url);
6707 			}
6708 		}
6709 #endif
6710 #endif
6711 		if(strlen(vhost) == 0 || !strcmp(vhost, "0.0.0.0")) {
6712 			/* Still nothing... */
6713 			JANUS_LOG(LOG_WARN, "No host address for the RTSP video stream, no latching will be performed\n");
6714 		}
6715 	}
6716 
6717 	if(aresult != -1) {
6718 		/* Send an RTSP SETUP for audio */
6719 		g_free(curldata->buffer);
6720 		curldata->buffer = g_malloc0(1);
6721 		curldata->size = 0;
6722 		gboolean add_qs = (rtsp_querystring != NULL);
6723 		if(add_qs && strstr(acontrol, rtsp_querystring) != NULL)
6724 			add_qs = FALSE;
6725 		if(strstr(acontrol, (strlen(abase) > 0 ? abase : rtsp_url)) == acontrol) {
6726 			/* The control attribute already contains the whole URL? */
6727 			g_snprintf(uri, sizeof(uri), "%s%s%s", acontrol,
6728 				add_qs ? "?" : "", add_qs ? rtsp_querystring : "");
6729 		} else {
6730 			/* Append the control attribute to the URL */
6731 			g_snprintf(uri, sizeof(uri), "%s/%s%s%s", (strlen(abase) > 0 ? abase : rtsp_url),
6732 				acontrol, add_qs ? "?" : "", add_qs ? rtsp_querystring : "");
6733 		}
6734 		curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri);
6735 		curl_easy_setopt(curl, CURLOPT_RTSP_TRANSPORT, atransport);
6736 		curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
6737 		res = curl_easy_perform(curl);
6738 		if(res != CURLE_OK) {
6739 			JANUS_LOG(LOG_ERR, "Couldn't send SETUP request: %s\n", curl_easy_strerror(res));
6740 			g_strfreev(parts);
6741 			curl_easy_cleanup(curl);
6742 			g_free(curldata->buffer);
6743 			g_free(curldata);
6744 			if(video_fds.fd != -1) close(video_fds.fd);
6745 			if(video_fds.rtcp_fd != -1) close(video_fds.rtcp_fd);
6746 			if(audio_fds.fd != -1) close(audio_fds.fd);
6747 			if(audio_fds.rtcp_fd != -1) close(audio_fds.rtcp_fd);
6748 			return -6;
6749 		} else if(code != 200) {
6750 			JANUS_LOG(LOG_ERR, "Couldn't get SETUP code: %ld\n", code);
6751 			g_strfreev(parts);
6752 			curl_easy_cleanup(curl);
6753 			g_free(curldata->buffer);
6754 			g_free(curldata);
6755 			if(video_fds.fd != -1) close(video_fds.fd);
6756 			if(video_fds.rtcp_fd != -1) close(video_fds.rtcp_fd);
6757 			if(audio_fds.fd != -1) close(audio_fds.fd);
6758 			if(audio_fds.rtcp_fd != -1) close(audio_fds.rtcp_fd);
6759 			return -6;
6760 		}
6761 		JANUS_LOG(LOG_VERB, "SETUP answer:%s\n", curldata->buffer);
6762 		/* Parse the RTSP message: we may need Transport and Session */
6763 		gboolean success = TRUE;
6764 		gchar **parts = g_strsplit(curldata->buffer, "\n", -1);
6765 		if(parts) {
6766 			int index = 0;
6767 			char *line = NULL, *cr = NULL;
6768 			while(success && (line = parts[index]) != NULL) {
6769 				cr = strchr(line, '\r');
6770 				if(cr != NULL)
6771 					*cr = '\0';
6772 				if(*line == '\0') {
6773 					if(cr != NULL)
6774 						*cr = '\r';
6775 					index++;
6776 					continue;
6777 				}
6778 				if(strlen(line) < 3) {
6779 					JANUS_LOG(LOG_ERR, "Invalid RTSP line (%zu bytes): %s\n", strlen(line), line);
6780 					success = FALSE;
6781 					break;
6782 				}
6783 				/* Check if this is a Transport or Session header, and if so parse it */
6784 				gboolean is_transport = (strstr(line, "Transport:") == line || strstr(line, "transport:") == line);
6785 				gboolean is_session = (strstr(line, "Session:") == line || strstr(line, "session:") == line);
6786 				if(is_transport || is_session) {
6787 					/* There is, iterate on all params */
6788 					char *p = line, param[100], *pi = NULL;
6789 					int read = 0;
6790 					gboolean first = TRUE;
6791 					while(sscanf(p, "%99[^;]%n", param, &read) == 1) {
6792 						if(first) {
6793 							/* Skip */
6794 							first = FALSE;
6795 						} else {
6796 							pi = param;
6797 							while(*pi == ' ')
6798 								pi++;
6799 							char name[50], value[50];
6800 							if(sscanf(pi, "%49[a-zA-Z_0-9]=%49s", name, value) == 2) {
6801 								if(is_transport) {
6802 									if(!strcasecmp(name, "ssrc")) {
6803 										/* Take note of the audio SSRC */
6804 										uint32_t ssrc = strtol(value, NULL, 16);
6805 										JANUS_LOG(LOG_VERB, "  -- SSRC (audio): %"SCNu32"\n", ssrc);
6806 										source->audio_ssrc = ssrc;
6807 									} else if(!strcasecmp(name, "source")) {
6808 										/* If we got an address via c-line, replace it */
6809 										g_snprintf(ahost, sizeof(ahost), "%s", value);
6810 										JANUS_LOG(LOG_VERB, "  -- Source (audio): %s\n", ahost);
6811 									} else if(!strcasecmp(name, "server_port")) {
6812 										/* Take note of the server port */
6813 										char *dash = NULL;
6814 										asport = strtol(value, &dash, 10);
6815 										asport_rtcp = dash ? strtol(++dash, NULL, 10) : 0;
6816 										JANUS_LOG(LOG_VERB, "  -- RTP port (audio): %d\n", asport);
6817 										JANUS_LOG(LOG_VERB, "  -- RTCP port (audio): %d\n", asport_rtcp);
6818 									}
6819 								} else if(is_session) {
6820 									if(!strcasecmp(name, "timeout")) {
6821 										/* Take note of the timeout, for keep-alives */
6822 										source->ka_timeout = janus_streaming_min_if(source->session_timeout, (gint64)atoi(value) / 2 * G_USEC_PER_SEC);
6823 										JANUS_LOG(LOG_VERB, "  -- RTSP session timeout (audio): %"SCNi64" ms\n", source->ka_timeout / 1000);
6824 									}
6825 								}
6826 							}
6827 						}
6828 						/* Move to the next param */
6829 						p += read;
6830 						if(*p != ';')
6831 							break;
6832 						while(*p == ';')
6833 							p++;
6834 					}
6835 				}
6836 				if(cr != NULL)
6837 					*cr = '\r';
6838 				index++;
6839 			}
6840 			if(cr != NULL)
6841 				*cr = '\r';
6842 			g_strfreev(parts);
6843 		}
6844 		/* If we don't have a host yet (no c-line, no source in Transport), use the server address */
6845 		if(strlen(ahost) == 0 || !strcmp(ahost, "0.0.0.0")) {
6846 			if(strlen(vhost) > 0 && strcmp(vhost, "0.0.0.0")) {
6847 				JANUS_LOG(LOG_WARN, "No c-line or source for RTSP audio stream, copying the video address (%s)\n", vhost);
6848 				g_snprintf(ahost, sizeof(ahost), "%s", vhost);
6849 			} else {
6850 #ifdef HAVE_LIBCURL
6851 #if CURL_AT_LEAST_VERSION(7, 62, 0)
6852 				JANUS_LOG(LOG_WARN, "No c-line or source for RTSP audio stream, resolving server address...\n");
6853 				CURLU *url = curl_url();
6854 				if(url != NULL) {
6855 					CURLUcode code = curl_url_set(url, CURLUPART_URL, source->rtsp_url, 0);
6856 					if(code == 0) {
6857 						char *host = NULL;
6858 						code = curl_url_get(url, CURLUPART_HOST, &host, 0);
6859 						if(code == 0) {
6860 							/* Resolve the address */
6861 							struct addrinfo *info = NULL, *start = NULL;
6862 							janus_network_address addr;
6863 							janus_network_address_string_buffer addr_buf;
6864 							if(getaddrinfo(host, NULL, NULL, &info) == 0) {
6865 								start = info;
6866 								while(info != NULL) {
6867 									if(janus_network_address_from_sockaddr(info->ai_addr, &addr) == 0 &&
6868 											janus_network_address_to_string_buffer(&addr, &addr_buf) == 0) {
6869 										/* Resolved */
6870 										g_snprintf(ahost, sizeof(ahost), "%s",
6871 											janus_network_address_string_from_buffer(&addr_buf));
6872 										JANUS_LOG(LOG_VERB, "   -- %s\n", ahost);
6873 										break;
6874 									}
6875 									info = info->ai_next;
6876 								}
6877 							}
6878 							if(start)
6879 								freeaddrinfo(start);
6880 							curl_free(host);
6881 						}
6882 					}
6883 					curl_url_cleanup(url);
6884 				}
6885 #endif
6886 #endif
6887 			}
6888 		}
6889 		if(strlen(ahost) == 0 || !strcmp(ahost, "0.0.0.0")) {
6890 			/* Still nothing... */
6891 			JANUS_LOG(LOG_WARN, "No host address for the RTSP audio stream, no latching will be performed\n");
6892 		}
6893 	}
6894 	g_strfreev(parts);
6895 
6896 	/* Update the source (but check if ptype/rtpmap/fmtp need to be overridden) */
6897 	if(mp->codecs.audio_pt == -1)
6898 		mp->codecs.audio_pt = doaudio ? apt : -1;
6899 	if(mp->codecs.audio_rtpmap == NULL)
6900 		mp->codecs.audio_rtpmap = (doaudio && strlen(artpmap)) ? g_strdup(artpmap) : NULL;
6901 	if(mp->codecs.audio_fmtp == NULL)
6902 		mp->codecs.audio_fmtp = (doaudio && strlen(afmtp)) ? g_strdup(afmtp) : NULL;
6903 	if(mp->codecs.video_pt == -1)
6904 		mp->codecs.video_pt = dovideo ? vpt : -1;
6905 	if(mp->codecs.video_rtpmap == NULL)
6906 		mp->codecs.video_rtpmap = (dovideo && strlen(vrtpmap)) ? g_strdup(vrtpmap) : NULL;
6907 	if(mp->codecs.video_fmtp == NULL)
6908 		mp->codecs.video_fmtp = (dovideo && strlen(vfmtp)) ? g_strdup(vfmtp) : NULL;
6909 	source->audio_fd = audio_fds.fd;
6910 	source->audio_rtcp_fd = audio_fds.rtcp_fd;
6911 	source->remote_audio_port = asport;
6912 	source->remote_audio_rtcp_port = asport_rtcp;
6913 	g_free(source->rtsp_ahost);
6914 	if(asport > 0)
6915 		source->rtsp_ahost = g_strdup(ahost);
6916 	source->video_fd[0] = video_fds.fd;
6917 	source->video_rtcp_fd = video_fds.rtcp_fd;
6918 	source->remote_video_port = vsport;
6919 	source->remote_video_rtcp_port = vsport_rtcp;
6920 	g_free(source->rtsp_vhost);
6921 	if(vsport > 0)
6922 		source->rtsp_vhost = g_strdup(vhost);
6923 	source->curl = curl;
6924 	source->curldata = curldata;
6925 	return 0;
6926 }
6927 
6928 /* Helper method to send a latching packet on an RTSP media socket */
6929 static void janus_streaming_rtsp_latch(int fd, char *host, int port, struct sockaddr *remote) {
6930 	/* Resolve address to get an IP */
6931 	struct addrinfo *res = NULL;
6932 	janus_network_address addr;
6933 	janus_network_address_string_buffer addr_buf;
6934 	if(getaddrinfo(host, NULL, NULL, &res) != 0 ||
6935 			janus_network_address_from_sockaddr(res->ai_addr, &addr) != 0 ||
6936 			janus_network_address_to_string_buffer(&addr, &addr_buf) != 0) {
6937 		JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", host);
6938 		if(res)
6939 			freeaddrinfo(res);
6940 	} else {
6941 		freeaddrinfo(res);
6942 		/* Prepare the recipient */
6943 		struct sockaddr_in remote4 = { 0 };
6944 		struct sockaddr_in6 remote6 = { 0 };
6945 		socklen_t addrlen = 0;
6946 		if(addr.family == AF_INET) {
6947 			memset(&remote4, 0, sizeof(remote4));
6948 			remote4.sin_family = AF_INET;
6949 			remote4.sin_port = htons(port);
6950 			memcpy(&remote4.sin_addr, &addr.ipv4, sizeof(addr.ipv4));
6951 			remote = (struct sockaddr *)(&remote4);
6952 			addrlen = sizeof(remote4);
6953 		} else if(addr.family == AF_INET6) {
6954 			memset(&remote6, 0, sizeof(remote6));
6955 			remote6.sin6_family = AF_INET6;
6956 			remote6.sin6_port = htons(port);
6957 			memcpy(&remote6.sin6_addr, &addr.ipv6, sizeof(addr.ipv6));
6958 			remote6.sin6_addr = addr.ipv6;
6959 			remote = (struct sockaddr *)(&remote6);
6960 			addrlen = sizeof(remote6);
6961 		}
6962 		/* Prepare an empty RTP packet */
6963 		janus_rtp_header rtp;
6964 		memset(&rtp, 0, sizeof(rtp));
6965 		rtp.version = 2;
6966 		/* Send a couple of latching packets */
6967 		(void)sendto(fd, &rtp, 12, 0, remote, addrlen);
6968 		(void)sendto(fd, &rtp, 12, 0, remote, addrlen);
6969 	}
6970 }
6971 
6972 /* Helper to send an RTSP PLAY (either when we create the mountpoint, or when we try reconnecting) */
6973 static int janus_streaming_rtsp_play(janus_streaming_rtp_source *source) {
6974 	if(source == NULL || source->curldata == NULL)
6975 		return -1;
6976 	/* First of all, send a latching packet to the RTSP server port(s) */
6977 	struct sockaddr_in6 remote = { 0 };
6978 	if(source->remote_audio_port > 0 && source->audio_fd >= 0) {
6979 		JANUS_LOG(LOG_VERB, "RTSP audio latching: %s:%d\n", source->rtsp_ahost, source->remote_audio_port);
6980 		janus_streaming_rtsp_latch(source->audio_fd, source->rtsp_ahost,
6981 			source->remote_audio_port, (struct sockaddr *)&remote);
6982 		if(source->remote_audio_rtcp_port > 0 && source->audio_rtcp_fd >= 0) {
6983 			JANUS_LOG(LOG_VERB, "  -- RTCP: %s:%d\n", source->rtsp_ahost, source->remote_audio_rtcp_port);
6984 			janus_streaming_rtsp_latch(source->audio_rtcp_fd, source->rtsp_ahost,
6985 				source->remote_audio_rtcp_port, (struct sockaddr *)&source->audio_rtcp_addr);
6986 		}
6987 	}
6988 	if(source->remote_video_port > 0 && source->video_fd[0] >= 0) {
6989 		JANUS_LOG(LOG_VERB, "RTSP video latching: %s:%d\n", source->rtsp_vhost, source->remote_video_port);
6990 		janus_streaming_rtsp_latch(source->video_fd[0], source->rtsp_vhost,
6991 			source->remote_video_port, (struct sockaddr *)&remote);
6992 		if(source->remote_video_rtcp_port > 0 && source->video_rtcp_fd >= 0) {
6993 			JANUS_LOG(LOG_VERB, "  -- RTCP: %s:%d\n", source->rtsp_vhost, source->remote_video_rtcp_port);
6994 			janus_streaming_rtsp_latch(source->video_rtcp_fd, source->rtsp_vhost,
6995 				source->remote_video_rtcp_port, (struct sockaddr *)&source->video_rtcp_addr);
6996 		}
6997 	}
6998 	/* Send an RTSP PLAY */
6999 	janus_mutex_lock(&source->rtsp_mutex);
7000 	g_free(source->curldata->buffer);
7001 	source->curldata->buffer = g_malloc0(1);
7002 	source->curldata->size = 0;
7003 	JANUS_LOG(LOG_VERB, "Sending PLAY request...\n");
7004 	curl_easy_setopt(source->curl, CURLOPT_RTSP_STREAM_URI, source->rtsp_url);
7005 	curl_easy_setopt(source->curl, CURLOPT_RANGE, "npt=0.000-");
7006 	curl_easy_setopt(source->curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
7007 	int res = curl_easy_perform(source->curl);
7008 	if(res != CURLE_OK) {
7009 		JANUS_LOG(LOG_ERR, "Couldn't send PLAY request: %s\n", curl_easy_strerror(res));
7010 		janus_mutex_unlock(&source->rtsp_mutex);
7011 		return -1;
7012 	}
7013 	JANUS_LOG(LOG_VERB, "PLAY answer:%s\n", source->curldata->buffer);
7014 	janus_mutex_unlock(&source->rtsp_mutex);
7015 	return 0;
7016 }
7017 
7018 /* Helper to create an RTSP source */
7019 janus_streaming_mountpoint *janus_streaming_create_rtsp_source(
7020 		uint64_t id, char *id_str, char *name, char *desc, char *metadata,
7021 		char *url, char *username, char *password,
7022 		gboolean doaudio, int acodec, char *artpmap, char *afmtp,
7023 		gboolean dovideo, int vcodec, char *vrtpmap, char *vfmtp, gboolean bufferkf,
7024 		const janus_network_address *iface, int threads,
7025 		gint64 reconnect_delay, gint64 session_timeout, int rtsp_timeout, int rtsp_conn_timeout,
7026 		gboolean error_on_failure) {
7027 	char id_num[30];
7028 	if(!string_ids) {
7029 		g_snprintf(id_num, sizeof(id_num), "%"SCNu64, id);
7030 		id_str = id_num;
7031 	}
7032 	if(url == NULL) {
7033 		JANUS_LOG(LOG_ERR, "Can't add 'rtsp' stream, missing url...\n");
7034 		return NULL;
7035 	}
7036 	if(reconnect_delay < 0) {
7037 		JANUS_LOG(LOG_ERR, "rtsp_reconnect_delay can't be smaller than zero.\n");
7038 		return NULL;
7039 	}
7040 	if(session_timeout < 0) {
7041 		JANUS_LOG(LOG_ERR, "rtsp_session_timeout can't be smaller than zero.\n");
7042 		return NULL;
7043 	}
7044 	if(rtsp_timeout < 0) {
7045 		JANUS_LOG(LOG_ERR, "rtsp_timeout can't be smaller than zero.\n");
7046 		return NULL;
7047 	}
7048 	if(rtsp_conn_timeout < 0) {
7049 		JANUS_LOG(LOG_ERR, "rtsp_conn_timeout can't be smaller than zero.\n");
7050 		return NULL;
7051 	}
7052 
7053 	JANUS_LOG(LOG_VERB, "Audio %s, Video %s\n", doaudio ? "enabled" : "NOT enabled", dovideo ? "enabled" : "NOT enabled");
7054 
7055 	/* Create an RTP source for the media we'll get */
7056 	char tempname[255];
7057 	if(name == NULL) {
7058 		JANUS_LOG(LOG_VERB, "Missing name, will generate a random one...\n");
7059 		memset(tempname, 0, 255);
7060 		g_snprintf(tempname, 255, "%s", id_str);
7061 	} else if(name[0] == '0' || atoi(name) != 0) {
7062 		JANUS_LOG(LOG_VERB, "Names can't start with a number, prefixing it...\n");
7063 		memset(tempname, 0, 255);
7064 		g_snprintf(tempname, 255, "mp-%s", name);
7065 		name = NULL;
7066 	}
7067 	char *sourcename =  g_strdup(name ? name : tempname);
7068 	char *description = NULL;
7069 	if(desc != NULL) {
7070 		description = g_strdup(desc);
7071 	} else {
7072 		description = g_strdup(name ? name : tempname);
7073 	}
7074 
7075 	janus_network_address nil;
7076 	janus_network_address_nullify(&nil);
7077 
7078 	/* Create the mountpoint and prepare the source */
7079 	janus_streaming_mountpoint *live_rtsp = g_malloc0(sizeof(janus_streaming_mountpoint));
7080 	live_rtsp->id = id;
7081 	live_rtsp->id_str = g_strdup(id_str);
7082 	live_rtsp->name = sourcename;
7083 	live_rtsp->description = description;
7084 	live_rtsp->metadata = (metadata ? g_strdup(metadata) : NULL);
7085 	live_rtsp->enabled = TRUE;
7086 	live_rtsp->active = FALSE;
7087 	live_rtsp->audio = doaudio;
7088 	live_rtsp->video = dovideo;
7089 	live_rtsp->data = FALSE;
7090 	live_rtsp->streaming_type = janus_streaming_type_live;
7091 	live_rtsp->streaming_source = janus_streaming_source_rtp;
7092 	janus_streaming_rtp_source *live_rtsp_source = g_malloc0(sizeof(janus_streaming_rtp_source));
7093 	live_rtsp_source->rtsp = TRUE;
7094 	live_rtsp_source->rtsp_url = g_strdup(url);
7095 	live_rtsp_source->rtsp_username = username ? g_strdup(username) : NULL;
7096 	live_rtsp_source->rtsp_password = password ? g_strdup(password) : NULL;
7097 	live_rtsp_source->arc = NULL;
7098 	live_rtsp_source->vrc = NULL;
7099 	live_rtsp_source->drc = NULL;
7100 	live_rtsp_source->audio_fd = -1;
7101 	live_rtsp_source->audio_rtcp_fd = -1;
7102 	live_rtsp_source->audio_iface = iface ? *iface : nil;
7103 	live_rtsp_source->video_fd[0] = -1;
7104 	live_rtsp_source->video_fd[1] = -1;
7105 	live_rtsp_source->video_fd[2] = -1;
7106 	live_rtsp_source->video_rtcp_fd = -1;
7107 	live_rtsp_source->video_iface = iface ? *iface : nil;
7108 	live_rtsp_source->data_fd = -1;
7109 	live_rtsp_source->pipefd[0] = -1;
7110 	live_rtsp_source->pipefd[1] = -1;
7111 	pipe(live_rtsp_source->pipefd);
7112 	live_rtsp_source->data_iface = nil;
7113 	live_rtsp_source->keyframe.enabled = bufferkf;
7114 	live_rtsp_source->keyframe.latest_keyframe = NULL;
7115 	live_rtsp_source->keyframe.temp_keyframe = NULL;
7116 	live_rtsp_source->keyframe.temp_ts = 0;
7117 	live_rtsp_source->ka_timeout = session_timeout;
7118 	live_rtsp_source->reconnect_delay = reconnect_delay;
7119 	live_rtsp_source->session_timeout = session_timeout;
7120 	live_rtsp_source->rtsp_timeout = rtsp_timeout;
7121 	live_rtsp_source->rtsp_conn_timeout = rtsp_conn_timeout;
7122 	janus_mutex_init(&live_rtsp_source->keyframe.mutex);
7123 	live_rtsp_source->reconnect_timer = 0;
7124 	janus_mutex_init(&live_rtsp_source->rtsp_mutex);
7125 	live_rtsp->source = live_rtsp_source;
7126 	live_rtsp->source_destroy = (GDestroyNotify) janus_streaming_rtp_source_free;
7127 	live_rtsp->viewers = NULL;
7128 	g_atomic_int_set(&live_rtsp->destroyed, 0);
7129 	janus_refcount_init(&live_rtsp->ref, janus_streaming_mountpoint_free);
7130 	janus_mutex_init(&live_rtsp->mutex);
7131 	/* We may have to override the payload type and/or rtpmap and/or fmtp for audio and/or video */
7132 	live_rtsp->codecs.audio_pt = doaudio ? acodec : -1;
7133 	live_rtsp->codecs.audio_rtpmap = doaudio ? (artpmap ? g_strdup(artpmap) : NULL) : NULL;
7134 	live_rtsp->codecs.audio_fmtp = doaudio ? (afmtp ? g_strdup(afmtp) : NULL) : NULL;
7135 	live_rtsp->codecs.video_pt = dovideo ? vcodec : -1;
7136 	live_rtsp->codecs.video_rtpmap = dovideo ? (vrtpmap ? g_strdup(vrtpmap) : NULL) : NULL;
7137 	live_rtsp->codecs.video_fmtp = dovideo ? (vfmtp ? g_strdup(vfmtp) : NULL) : NULL;
7138 	/* If we need to return an error on failure, try connecting right now */
7139 	if(error_on_failure) {
7140 		/* Now connect to the RTSP server */
7141 		if(janus_streaming_rtsp_connect_to_server(live_rtsp) < 0) {
7142 			/* Error connecting, get rid of the mountpoint */
7143 			janus_mutex_lock(&mountpoints_mutex);
7144 			g_hash_table_remove(mountpoints_temp, &id);
7145 			janus_mutex_unlock(&mountpoints_mutex);
7146 			janus_refcount_decrease(&live_rtsp->ref);
7147 			return NULL;
7148 		}
7149 		/* Send an RTSP PLAY, now */
7150 		if(janus_streaming_rtsp_play(live_rtsp_source) < 0) {
7151 			/* Error trying to play, get rid of the mountpoint */
7152 			janus_mutex_lock(&mountpoints_mutex);
7153 			g_hash_table_remove(mountpoints_temp, &id);
7154 			janus_mutex_unlock(&mountpoints_mutex);
7155 			janus_refcount_decrease(&live_rtsp->ref);
7156 			return NULL;
7157 		}
7158 	}
7159 	/* If we need helper threads, spawn them now */
7160 	GError *error = NULL;
7161 	char tname[16];
7162 	if(threads > 0) {
7163 		int i=0;
7164 		for(i=0; i<threads; i++) {
7165 			janus_streaming_helper *helper = g_malloc0(sizeof(janus_streaming_helper));
7166 			helper->id = i+1;
7167 			helper->mp = live_rtsp;
7168 			helper->queued_packets = g_async_queue_new_full((GDestroyNotify)janus_streaming_rtp_relay_packet_free);
7169 			janus_mutex_init(&helper->mutex);
7170 			janus_refcount_init(&helper->ref, janus_streaming_helper_free);
7171 			live_rtsp->helper_threads++;
7172 			/* Spawn a thread and add references */
7173 			g_snprintf(tname, sizeof(tname), "help %u-%"SCNu64, helper->id, live_rtsp->id);
7174 			janus_refcount_increase(&live_rtsp->ref);
7175 			janus_refcount_increase(&helper->ref);
7176 			helper->thread = g_thread_try_new(tname, &janus_streaming_helper_thread, helper, &error);
7177 			if(error != NULL) {
7178 				JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the helper thread...\n",
7179 					error->code, error->message ? error->message : "??");
7180 				g_error_free(error);
7181 				janus_refcount_decrease(&live_rtsp->ref);	/* This is for the helper thread */
7182 				g_async_queue_unref(helper->queued_packets);
7183 				janus_refcount_decrease(&helper->ref);
7184 				/* This extra unref is for the init */
7185 				janus_refcount_decrease(&helper->ref);
7186 				janus_mutex_lock(&mountpoints_mutex);
7187 				g_hash_table_remove(mountpoints_temp, &id);
7188 				janus_mutex_unlock(&mountpoints_mutex);
7189 				janus_refcount_decrease(&live_rtsp->ref);
7190 				return NULL;
7191 			}
7192 			janus_refcount_increase(&helper->ref);
7193 			live_rtsp->threads = g_list_append(live_rtsp->threads, helper);
7194 		}
7195 	}
7196 	/* Finally, start the thread that will receive the media packets */
7197 	g_snprintf(tname, sizeof(tname), "mp %s", live_rtsp->id_str);
7198 	janus_refcount_increase(&live_rtsp->ref);
7199 	live_rtsp->thread = g_thread_try_new(tname, &janus_streaming_relay_thread, live_rtsp, &error);
7200 	if(error != NULL) {
7201 		JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the RTSP thread...\n",
7202 			error->code, error->message ? error->message : "??");
7203 		g_error_free(error);
7204 		janus_mutex_lock(&mountpoints_mutex);
7205 		g_hash_table_remove(mountpoints_temp, &id);
7206 		janus_mutex_unlock(&mountpoints_mutex);
7207 		janus_refcount_decrease(&live_rtsp->ref);	/* This is for the failed thread */
7208 		janus_refcount_decrease(&live_rtsp->ref);
7209 		return NULL;
7210 	}
7211 	janus_mutex_lock(&mountpoints_mutex);
7212 	g_hash_table_insert(mountpoints,
7213 		string_ids ? (gpointer)g_strdup(live_rtsp->id_str) : (gpointer)janus_uint64_dup(live_rtsp->id),
7214 		live_rtsp);
7215 	g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)live_rtsp->id_str : (gpointer)&live_rtsp->id);
7216 	janus_mutex_unlock(&mountpoints_mutex);
7217 	return live_rtsp;
7218 }
7219 #else
7220 /* Helper to create an RTSP source */
7221 janus_streaming_mountpoint *janus_streaming_create_rtsp_source(
7222 		uint64_t id, char *id_str, char *name, char *desc, char *metadata,
7223 		char *url, char *username, char *password,
7224 		gboolean doaudio, int acodec, char *audiortpmap, char *audiofmtp,
7225 		gboolean dovideo, int vcodec, char *videortpmap, char *videofmtp, gboolean bufferkf,
7226 		const janus_network_address *iface, int threads,
7227 		gint64 reconnect_delay, gint64 session_timeout, int rtsp_timeout, int rtsp_conn_timeout,
7228 		gboolean error_on_failure) {
7229 	JANUS_LOG(LOG_ERR, "RTSP need libcurl\n");
7230 	return NULL;
7231 }
7232 #endif
7233 
7234 /* Thread to send RTP packets from a file (on demand) */
7235 static void *janus_streaming_ondemand_thread(void *data) {
7236 	JANUS_LOG(LOG_VERB, "Filesource (on demand) RTP thread starting...\n");
7237 	janus_streaming_session *session = (janus_streaming_session *)data;
7238 	if(!session) {
7239 		JANUS_LOG(LOG_ERR, "Invalid session!\n");
7240 		g_thread_unref(g_thread_self());
7241 		return NULL;
7242 	}
7243 	janus_streaming_mountpoint *mountpoint = session->mountpoint;
7244 	if(!mountpoint) {
7245 		JANUS_LOG(LOG_ERR, "Invalid mountpoint!\n");
7246 		janus_refcount_decrease(&session->ref);
7247 		g_thread_unref(g_thread_self());
7248 		return NULL;
7249 	}
7250 	if(mountpoint->streaming_source != janus_streaming_source_file) {
7251 		JANUS_LOG(LOG_ERR, "[%s] Not an file source mountpoint!\n", mountpoint->name);
7252 		janus_refcount_decrease(&session->ref);
7253 		janus_refcount_decrease(&mountpoint->ref);
7254 		g_thread_unref(g_thread_self());
7255 		return NULL;
7256 	}
7257 	if(mountpoint->streaming_type != janus_streaming_type_on_demand) {
7258 		JANUS_LOG(LOG_ERR, "[%s] Not an on-demand file source mountpoint!\n", mountpoint->name);
7259 		janus_refcount_decrease(&session->ref);
7260 		janus_refcount_decrease(&mountpoint->ref);
7261 		g_thread_unref(g_thread_self());
7262 		return NULL;
7263 	}
7264 	janus_streaming_file_source *source = mountpoint->source;
7265 	if(source == NULL || source->filename == NULL) {
7266 		JANUS_LOG(LOG_ERR, "[%s] Invalid file source mountpoint!\n", mountpoint->name);
7267 		janus_refcount_decrease(&session->ref);
7268 		janus_refcount_decrease(&mountpoint->ref);
7269 		g_thread_unref(g_thread_self());
7270 		return NULL;
7271 	}
7272 	JANUS_LOG(LOG_VERB, "[%s] Opening file source %s...\n", mountpoint->name, source->filename);
7273 	FILE *audio = fopen(source->filename, "rb");
7274 	if(!audio) {
7275 		JANUS_LOG(LOG_ERR, "[%s] Ooops, audio file missing!\n", mountpoint->name);
7276 		janus_refcount_decrease(&session->ref);
7277 		janus_refcount_decrease(&mountpoint->ref);
7278 		g_thread_unref(g_thread_self());
7279 		return NULL;
7280 	}
7281 	char *name = g_strdup(mountpoint->name ? mountpoint->name : "??");
7282 	JANUS_LOG(LOG_VERB, "[%s] Streaming audio file: %s\n", name, source->filename);
7283 
7284 #ifdef HAVE_LIBOGG
7285 	/* Make sure that, if this is an .opus file, we can open it */
7286 	janus_streaming_opus_context opusctx = { 0 };
7287 	if(source->opus) {
7288 		opusctx.name = name;
7289 		opusctx.filename = source->filename;
7290 		opusctx.file = audio;
7291 		if(janus_streaming_opus_context_init(&opusctx) < 0) {
7292 			g_free(name);
7293 			fclose(audio);
7294 			janus_refcount_decrease(&session->ref);
7295 			janus_refcount_decrease(&mountpoint->ref);
7296 			g_thread_unref(g_thread_self());
7297 			return NULL;
7298 		}
7299 	}
7300 #endif
7301 
7302 	/* Buffer */
7303 	char buf[1500];
7304 	memset(buf, 0, sizeof(buf));
7305 	/* Set up RTP */
7306 	guint16 seq = 1;
7307 	guint32 ts = 0;
7308 	janus_rtp_header *header = (janus_rtp_header *)buf;
7309 	header->version = 2;
7310 	header->markerbit = 1;
7311 	header->type = mountpoint->codecs.audio_pt;
7312 	header->seq_number = htons(seq);
7313 	header->timestamp = htonl(ts);
7314 	header->ssrc = htonl(1);	/* The gateway will fix this anyway */
7315 	/* Timer */
7316 	struct timeval now, before;
7317 	gettimeofday(&before, NULL);
7318 	now.tv_sec = before.tv_sec;
7319 	now.tv_usec = before.tv_usec;
7320 	time_t passed, d_s, d_us;
7321 	/* Loop */
7322 	gint read = 0;
7323 #ifdef HAVE_LIBOGG
7324 	const gint plen = (sizeof(buf)-RTP_HEADER_SIZE);
7325 #endif
7326 	janus_streaming_rtp_relay_packet packet;
7327 	while(!g_atomic_int_get(&stopping) && !g_atomic_int_get(&mountpoint->destroyed) &&
7328 			!g_atomic_int_get(&session->stopping) && !g_atomic_int_get(&session->destroyed)) {
7329 		/* See if it's time to prepare a frame */
7330 		gettimeofday(&now, NULL);
7331 		d_s = now.tv_sec - before.tv_sec;
7332 		d_us = now.tv_usec - before.tv_usec;
7333 		if(d_us < 0) {
7334 			d_us += 1000000;
7335 			--d_s;
7336 		}
7337 		passed = d_s*1000000 + d_us;
7338 		if(passed < 18000) {	/* Let's wait about 18ms */
7339 			g_usleep(5000);
7340 			continue;
7341 		}
7342 		/* Update the reference time */
7343 		before.tv_usec += 20000;
7344 		if(before.tv_usec > 1000000) {
7345 			before.tv_sec++;
7346 			before.tv_usec -= 1000000;
7347 		}
7348 		/* If not started or paused, wait some more */
7349 		if(!g_atomic_int_get(&session->started) || g_atomic_int_get(&session->paused) || !mountpoint->enabled)
7350 			continue;
7351 		if(source->opus) {
7352 #ifdef HAVE_LIBOGG
7353 			/* Get the next frame from the Opus file */
7354 			read = janus_streaming_opus_context_read(&opusctx, buf + RTP_HEADER_SIZE, plen);
7355 #endif
7356 		} else {
7357 			/* Read frame from file... */
7358 			read = fread(buf + RTP_HEADER_SIZE, sizeof(char), 160, audio);
7359 			if(feof(audio)) {
7360 				/* FIXME We're doing this forever... should this be configurable? */
7361 				JANUS_LOG(LOG_VERB, "[%s] Rewind! (%s)\n", name, source->filename);
7362 				fseek(audio, 0, SEEK_SET);
7363 				continue;
7364 			}
7365 		}
7366 		if(read < 0)
7367 			break;
7368 		if(mountpoint->active == FALSE)
7369 			mountpoint->active = TRUE;
7370 		/* Relay to the listener */
7371 		packet.data = header;
7372 		packet.length = RTP_HEADER_SIZE + read;
7373 		packet.is_rtp = TRUE;
7374 		packet.is_video = FALSE;
7375 		packet.is_keyframe = FALSE;
7376 		/* Backup the actual payload type, timestamp and sequence number */
7377 		packet.ptype = packet.data->type;
7378 		packet.timestamp = ntohl(packet.data->timestamp);
7379 		packet.seq_number = ntohs(packet.data->seq_number);
7380 		/* Go! */
7381 		janus_streaming_relay_rtp_packet(session, &packet);
7382 		/* Update header */
7383 		seq++;
7384 		header->seq_number = htons(seq);
7385 		ts += (source->opus ? 960 : 160);
7386 		header->timestamp = htonl(ts);
7387 		header->markerbit = 0;
7388 	}
7389 	JANUS_LOG(LOG_VERB, "[%s] Leaving filesource (ondemand) thread\n", name);
7390 #ifdef HAVE_LIBOGG
7391 	if(source->opus)
7392 		janus_streaming_opus_context_cleanup(&opusctx);
7393 #endif
7394 	g_free(name);
7395 	fclose(audio);
7396 	janus_refcount_decrease(&session->ref);
7397 	janus_refcount_decrease(&mountpoint->ref);
7398 	g_thread_unref(g_thread_self());
7399 	return NULL;
7400 }
7401 
7402 /* Thread to send RTP packets from a file (live) */
7403 static void *janus_streaming_filesource_thread(void *data) {
7404 	JANUS_LOG(LOG_VERB, "Filesource (live) thread starting...\n");
7405 	janus_streaming_mountpoint *mountpoint = (janus_streaming_mountpoint *)data;
7406 	if(!mountpoint) {
7407 		JANUS_LOG(LOG_ERR, "Invalid mountpoint!\n");
7408 		return NULL;
7409 	}
7410 	if(mountpoint->streaming_source != janus_streaming_source_file) {
7411 		JANUS_LOG(LOG_ERR, "[%s] Not an file source mountpoint!\n", mountpoint->name);
7412 		janus_refcount_decrease(&mountpoint->ref);
7413 		return NULL;
7414 	}
7415 	if(mountpoint->streaming_type != janus_streaming_type_live) {
7416 		JANUS_LOG(LOG_ERR, "[%s] Not a live file source mountpoint!\n", mountpoint->name);
7417 		janus_refcount_decrease(&mountpoint->ref);
7418 		return NULL;
7419 	}
7420 	janus_streaming_file_source *source = mountpoint->source;
7421 	if(source == NULL || source->filename == NULL) {
7422 		JANUS_LOG(LOG_ERR, "[%s] Invalid file source mountpoint!\n", mountpoint->name);
7423 		janus_refcount_decrease(&mountpoint->ref);
7424 		return NULL;
7425 	}
7426 	JANUS_LOG(LOG_VERB, "[%s] Opening file source %s...\n", mountpoint->name, source->filename);
7427 	FILE *audio = fopen(source->filename, "rb");
7428 	if(!audio) {
7429 		JANUS_LOG(LOG_ERR, "[%s] Ooops, audio file missing!\n", mountpoint->name);
7430 		janus_refcount_decrease(&mountpoint->ref);
7431 		return NULL;
7432 	}
7433 	char *name = g_strdup(mountpoint->name ? mountpoint->name : "??");
7434 	JANUS_LOG(LOG_VERB, "[%s] Streaming audio file: %s\n", mountpoint->name, source->filename);
7435 
7436 #ifdef HAVE_LIBOGG
7437 	/* Make sure that, if this is an .opus file, we can open it */
7438 	janus_streaming_opus_context opusctx = { 0 };
7439 	if(source->opus) {
7440 		opusctx.name = name;
7441 		opusctx.filename = source->filename;
7442 		opusctx.file = audio;
7443 		if(janus_streaming_opus_context_init(&opusctx) < 0) {
7444 			g_free(name);
7445 			fclose(audio);
7446 			janus_refcount_decrease(&mountpoint->ref);
7447 			g_thread_unref(g_thread_self());
7448 			return NULL;
7449 		}
7450 	}
7451 #endif
7452 
7453 	/* Buffer */
7454 	char buf[1500];
7455 	memset(buf, 0, sizeof(buf));
7456 	/* Set up RTP */
7457 	guint16 seq = 1;
7458 	guint32 ts = 0;
7459 	janus_rtp_header *header = (janus_rtp_header *)buf;
7460 	header->version = 2;
7461 	header->markerbit = 1;
7462 	header->type = mountpoint->codecs.audio_pt;
7463 	header->seq_number = htons(seq);
7464 	header->timestamp = htonl(ts);
7465 	header->ssrc = htonl(1);	/* The Janus core will fix this anyway */
7466 	/* Timer */
7467 	struct timeval now, before;
7468 	gettimeofday(&before, NULL);
7469 	now.tv_sec = before.tv_sec;
7470 	now.tv_usec = before.tv_usec;
7471 	time_t passed, d_s, d_us;
7472 	/* Loop */
7473 	gint read = 0;
7474 #ifdef HAVE_LIBOGG
7475 	const gint plen = (sizeof(buf)-RTP_HEADER_SIZE);
7476 #endif
7477 	janus_streaming_rtp_relay_packet packet;
7478 	while(!g_atomic_int_get(&stopping) && !g_atomic_int_get(&mountpoint->destroyed)) {
7479 		/* See if it's time to prepare a frame */
7480 		gettimeofday(&now, NULL);
7481 		d_s = now.tv_sec - before.tv_sec;
7482 		d_us = now.tv_usec - before.tv_usec;
7483 		if(d_us < 0) {
7484 			d_us += 1000000;
7485 			--d_s;
7486 		}
7487 		passed = d_s*1000000 + d_us;
7488 		if(passed < 18000) {	/* Let's wait about 18ms */
7489 			g_usleep(5000);
7490 			continue;
7491 		}
7492 		/* Update the reference time */
7493 		before.tv_usec += 20000;
7494 		if(before.tv_usec > 1000000) {
7495 			before.tv_sec++;
7496 			before.tv_usec -= 1000000;
7497 		}
7498 		/* If paused, wait some more */
7499 		if(!mountpoint->enabled)
7500 			continue;
7501 		if(source->opus) {
7502 #ifdef HAVE_LIBOGG
7503 			/* Get the next frame from the Opus file */
7504 			read = janus_streaming_opus_context_read(&opusctx, buf + RTP_HEADER_SIZE, plen);
7505 #endif
7506 		} else {
7507 			/* Read frame from file... */
7508 			read = fread(buf + RTP_HEADER_SIZE, sizeof(char), 160, audio);
7509 			if(feof(audio)) {
7510 				/* FIXME We're doing this forever... should this be configurable? */
7511 				JANUS_LOG(LOG_VERB, "[%s] Rewind! (%s)\n", name, source->filename);
7512 				fseek(audio, 0, SEEK_SET);
7513 				continue;
7514 			}
7515 		}
7516 		if(read < 0)
7517 			break;
7518 		if(mountpoint->active == FALSE)
7519 			mountpoint->active = TRUE;
7520 		/* Relay on all sessions */
7521 		packet.data = header;
7522 		packet.length = RTP_HEADER_SIZE + read;
7523 		packet.is_rtp = TRUE;
7524 		packet.is_video = FALSE;
7525 		packet.is_keyframe = FALSE;
7526 		/* Backup the actual payload type, timestamp and sequence number */
7527 		packet.ptype = packet.data->type;
7528 		packet.timestamp = ntohl(packet.data->timestamp);
7529 		packet.seq_number = ntohs(packet.data->seq_number);
7530 		/* Go! */
7531 		janus_mutex_lock_nodebug(&mountpoint->mutex);
7532 		g_list_foreach(mountpoint->viewers, janus_streaming_relay_rtp_packet, &packet);
7533 		janus_mutex_unlock_nodebug(&mountpoint->mutex);
7534 		/* Update header */
7535 		seq++;
7536 		header->seq_number = htons(seq);
7537 		ts += (source->opus ? 960 : 160);
7538 		header->timestamp = htonl(ts);
7539 		header->markerbit = 0;
7540 	}
7541 	JANUS_LOG(LOG_VERB, "[%s] Leaving filesource (live) thread\n", name);
7542 #ifdef HAVE_LIBOGG
7543 	if(source->opus)
7544 		janus_streaming_opus_context_cleanup(&opusctx);
7545 #endif
7546 	g_free(name);
7547 	fclose(audio);
7548 	janus_refcount_decrease(&mountpoint->ref);
7549 	return NULL;
7550 }
7551 
7552 /* Thread to relay RTP frames coming from gstreamer/ffmpeg/others */
7553 static void *janus_streaming_relay_thread(void *data) {
7554 	JANUS_LOG(LOG_VERB, "Starting streaming relay thread\n");
7555 	janus_streaming_mountpoint *mountpoint = (janus_streaming_mountpoint *)data;
7556 	if(!mountpoint) {
7557 		JANUS_LOG(LOG_ERR, "Invalid mountpoint!\n");
7558 		return NULL;
7559 	}
7560 	if(mountpoint->streaming_source != janus_streaming_source_rtp) {
7561 		janus_refcount_decrease(&mountpoint->ref);
7562 		JANUS_LOG(LOG_ERR, "[%s] Not an RTP source mountpoint!\n", mountpoint->name);
7563 		return NULL;
7564 	}
7565 	janus_streaming_rtp_source *source = mountpoint->source;
7566 	if(source == NULL) {
7567 		JANUS_LOG(LOG_ERR, "[%s] Invalid RTP source mountpoint!\n", mountpoint->name);
7568 		janus_refcount_decrease(&mountpoint->ref);
7569 		return NULL;
7570 	}
7571 
7572 	/* Add a reference to the helper threads, if needed */
7573 	if(mountpoint->helper_threads > 0) {
7574 		GList *l = mountpoint->threads;
7575 		while(l) {
7576 			janus_streaming_helper *ht = (janus_streaming_helper *)l->data;
7577 			janus_refcount_increase(&ht->ref);
7578 			l = l->next;
7579 		}
7580 	}
7581 
7582 	int audio_fd = source->audio_fd;
7583 	int video_fd[3] = {source->video_fd[0], source->video_fd[1], source->video_fd[2]};
7584 	int data_fd = source->data_fd;
7585 	int pipe_fd = source->pipefd[0];
7586 	int audio_rtcp_fd = source->audio_rtcp_fd;
7587 	int video_rtcp_fd = source->video_rtcp_fd;
7588 	char *name = g_strdup(mountpoint->name ? mountpoint->name : "??");
7589 	/* Needed to fix seq and ts */
7590 	uint32_t ssrc = 0, a_last_ssrc = 0, v_last_ssrc[3] = {0, 0, 0};
7591 	/* File descriptors */
7592 	socklen_t addrlen;
7593 	struct sockaddr_storage remote;
7594 	int resfd = 0, bytes = 0;
7595 	struct pollfd fds[8];
7596 	char buffer[1500];
7597 	memset(buffer, 0, 1500);
7598 #ifdef HAVE_LIBCURL
7599 	/* In case this is an RTSP restreamer, we may have to send keep-alives from time to time */
7600 	gint64 now = janus_get_monotonic_time(), before = now, ka_timeout = 0;
7601 	if(source->rtsp) {
7602 		source->reconnect_timer = now;
7603 		ka_timeout = source->ka_timeout;
7604 	}
7605 #endif
7606 	/* Loop */
7607 	int num = 0;
7608 	janus_streaming_rtp_relay_packet packet;
7609 	while(!g_atomic_int_get(&stopping) && !g_atomic_int_get(&mountpoint->destroyed)) {
7610 #ifdef HAVE_LIBCURL
7611 		/* Let's check regularly if the RTSP server seems to be gone */
7612 		if(source->rtsp) {
7613 			if(source->reconnecting) {
7614 				/* We're still reconnecting, wait some more */
7615 				g_usleep(250000);
7616 				continue;
7617 			}
7618 			now = janus_get_monotonic_time();
7619 			if(!source->reconnecting && (now - source->reconnect_timer > source->reconnect_delay)) {
7620 				/*  Assume the RTSP server has gone and schedule a reconnect */
7621 				JANUS_LOG(LOG_WARN, "[%s] %"SCNi64"s passed with no media, trying to reconnect the RTSP stream\n",
7622 					name, (now - source->reconnect_timer)/G_USEC_PER_SEC);
7623 				audio_fd = -1;
7624 				video_fd[0] = -1;
7625 				video_fd[1] = -1;
7626 				video_fd[2] = -1;
7627 				data_fd = -1;
7628 				source->reconnect_timer = now;
7629 				source->reconnecting = TRUE;
7630 				/* Let's clean up the source first */
7631 				curl_easy_cleanup(source->curl);
7632 				source->curl = NULL;
7633 				if(source->curldata)
7634 					g_free(source->curldata->buffer);
7635 				g_free(source->curldata);
7636 				source->curldata = NULL;
7637 				if(source->audio_fd > -1) {
7638 					close(source->audio_fd);
7639 				}
7640 				source->audio_fd = -1;
7641 				if(source->video_fd[0] > -1) {
7642 					close(source->video_fd[0]);
7643 				}
7644 				source->video_fd[0] = -1;
7645 				if(source->video_fd[1] > -1) {
7646 					close(source->video_fd[1]);
7647 				}
7648 				source->video_fd[1] = -1;
7649 				if(source->video_fd[2] > -1) {
7650 					close(source->video_fd[2]);
7651 				}
7652 				source->video_fd[2] = -1;
7653 				if(source->data_fd > -1) {
7654 					close(source->data_fd);
7655 				}
7656 				source->data_fd = -1;
7657 				if(source->audio_rtcp_fd > -1) {
7658 					close(source->audio_rtcp_fd);
7659 				}
7660 				source->audio_rtcp_fd = -1;
7661 				if(source->video_rtcp_fd > -1) {
7662 					close(source->video_rtcp_fd);
7663 				}
7664 				source->video_rtcp_fd = -1;
7665 				if(g_atomic_int_get(&mountpoint->destroyed))
7666 					break;
7667 				/* Now let's try to reconnect */
7668 				if(janus_streaming_rtsp_connect_to_server(mountpoint) < 0) {
7669 					/* Reconnection failed? Let's try again later */
7670 					JANUS_LOG(LOG_WARN, "[%s] Reconnection of the RTSP stream failed, trying again in a few seconds...\n", name);
7671 				} else {
7672 					/* We're connected, let's send a PLAY */
7673 					if(janus_streaming_rtsp_play(source) < 0) {
7674 						/* Error trying to play? Let's try again later */
7675 						JANUS_LOG(LOG_WARN, "[%s] RTSP PLAY failed, trying again in a few seconds...\n", name);
7676 					} else {
7677 						/* Everything should be back to normal, let's update the file descriptors */
7678 						JANUS_LOG(LOG_INFO, "[%s] Reconnected to the RTSP server, streaming again\n", name);
7679 						audio_fd = source->audio_fd;
7680 						video_fd[0] = source->video_fd[0];
7681 						data_fd = source->data_fd;
7682 						audio_rtcp_fd = source->audio_rtcp_fd;
7683 						video_rtcp_fd = source->video_rtcp_fd;
7684 						ka_timeout = source->ka_timeout;
7685 					}
7686 				}
7687 				source->reconnect_timer = janus_get_monotonic_time();
7688 				source->reconnecting = FALSE;
7689 				continue;
7690 			}
7691 		}
7692 		if(audio_fd < 0 && video_fd[0] < 0 && video_fd[1] < 0 && video_fd[2] < 0 && data_fd < 0) {
7693 			/* No socket, we may be in the process of reconnecting, or waiting to reconnect */
7694 			g_usleep(source->reconnect_delay);
7695 			continue;
7696 		}
7697 		/* We may also need to occasionally send a OPTIONS request as a keep-alive */
7698 		if(ka_timeout > 0) {
7699 			/* Let's be conservative and send a OPTIONS when half of the timeout has passed */
7700 			now = janus_get_monotonic_time();
7701 			if(now-before > ka_timeout && source->curldata) {
7702 				JANUS_LOG(LOG_VERB, "[%s] %"SCNi64"s passed, sending OPTIONS\n", name, (now-before)/G_USEC_PER_SEC);
7703 				before = now;
7704 				/* Send an RTSP OPTIONS */
7705 				janus_mutex_lock(&source->rtsp_mutex);
7706 				g_free(source->curldata->buffer);
7707 				source->curldata->buffer = g_malloc0(1);
7708 				source->curldata->size = 0;
7709 				curl_easy_setopt(source->curl, CURLOPT_RTSP_STREAM_URI, source->rtsp_url);
7710 				curl_easy_setopt(source->curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
7711 				resfd = curl_easy_perform(source->curl);
7712 				if(resfd != CURLE_OK) {
7713 					JANUS_LOG(LOG_ERR, "[%s] Couldn't send OPTIONS request: %s\n", name, curl_easy_strerror(resfd));
7714 				}
7715 				janus_mutex_unlock(&source->rtsp_mutex);
7716 			}
7717 		}
7718 #endif
7719 		/* Any PLI and/or REMB we should send back to the source? */
7720 		if(g_atomic_int_get(&source->need_pli))
7721 			janus_streaming_rtcp_pli_send(source);
7722 		if(source->video_rtcp_fd > -1 && source->lowest_bitrate > 0) {
7723 			gint64 now = janus_get_monotonic_time();
7724 			if(source->remb_latest == 0)
7725 				source->remb_latest = now;
7726 			else if(now - source->remb_latest >= G_USEC_PER_SEC)
7727 				janus_streaming_rtcp_remb_send(source);
7728 		}
7729 		/* Prepare poll */
7730 		num = 0;
7731 		if(audio_fd != -1) {
7732 			fds[num].fd = audio_fd;
7733 			fds[num].events = POLLIN;
7734 			fds[num].revents = 0;
7735 			num++;
7736 		}
7737 		if(video_fd[0] != -1) {
7738 			fds[num].fd = video_fd[0];
7739 			fds[num].events = POLLIN;
7740 			fds[num].revents = 0;
7741 			num++;
7742 		}
7743 		if(video_fd[1] != -1) {
7744 			fds[num].fd = video_fd[1];
7745 			fds[num].events = POLLIN;
7746 			fds[num].revents = 0;
7747 			num++;
7748 		}
7749 		if(video_fd[2] != -1) {
7750 			fds[num].fd = video_fd[2];
7751 			fds[num].events = POLLIN;
7752 			fds[num].revents = 0;
7753 			num++;
7754 		}
7755 		if(data_fd != -1) {
7756 			fds[num].fd = data_fd;
7757 			fds[num].events = POLLIN;
7758 			fds[num].revents = 0;
7759 			num++;
7760 		}
7761 		if(pipe_fd != -1) {
7762 			fds[num].fd = pipe_fd;
7763 			fds[num].events = POLLIN;
7764 			fds[num].revents = 0;
7765 			num++;
7766 		}
7767 		if(audio_rtcp_fd != -1) {
7768 			fds[num].fd = audio_rtcp_fd;
7769 			fds[num].events = POLLIN;
7770 			fds[num].revents = 0;
7771 			num++;
7772 		}
7773 		if(video_rtcp_fd != -1) {
7774 			fds[num].fd = video_rtcp_fd;
7775 			fds[num].events = POLLIN;
7776 			fds[num].revents = 0;
7777 			num++;
7778 		}
7779 		/* Wait for some data */
7780 		resfd = poll(fds, num, 1000);
7781 		if(resfd < 0) {
7782 			if(errno == EINTR) {
7783 				JANUS_LOG(LOG_HUGE, "[%s] Got an EINTR (%s), ignoring...\n", name, g_strerror(errno));
7784 				continue;
7785 			}
7786 			JANUS_LOG(LOG_ERR, "[%s] Error polling... %d (%s)\n", name, errno, g_strerror(errno));
7787 			mountpoint->enabled = FALSE;
7788 			janus_mutex_lock(&source->rec_mutex);
7789 			if(source->arc) {
7790 				janus_recorder_close(source->arc);
7791 				JANUS_LOG(LOG_INFO, "[%s] Closed audio recording %s\n", mountpoint->name, source->arc->filename ? source->arc->filename : "??");
7792 				janus_recorder *tmp = source->arc;
7793 				source->arc = NULL;
7794 				janus_recorder_destroy(tmp);
7795 			}
7796 			if(source->vrc) {
7797 				janus_recorder_close(source->vrc);
7798 				JANUS_LOG(LOG_INFO, "[%s] Closed video recording %s\n", mountpoint->name, source->vrc->filename ? source->vrc->filename : "??");
7799 				janus_recorder *tmp = source->vrc;
7800 				source->vrc = NULL;
7801 				janus_recorder_destroy(tmp);
7802 			}
7803 			if(source->drc) {
7804 				janus_recorder_close(source->drc);
7805 				JANUS_LOG(LOG_INFO, "[%s] Closed data recording %s\n", mountpoint->name, source->drc->filename ? source->drc->filename : "??");
7806 				janus_recorder *tmp = source->drc;
7807 				source->drc = NULL;
7808 				janus_recorder_destroy(tmp);
7809 			}
7810 			janus_mutex_unlock(&source->rec_mutex);
7811 			break;
7812 		} else if(resfd == 0) {
7813 			/* No data, keep going */
7814 			continue;
7815 		}
7816 		int i = 0;
7817 		for(i=0; i<num; i++) {
7818 			if(fds[i].revents & (POLLERR | POLLHUP)) {
7819 				/* Socket error? */
7820 				JANUS_LOG(LOG_ERR, "[%s] Error polling: %s... %d (%s)\n", name,
7821 					fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP", errno, g_strerror(errno));
7822 				mountpoint->enabled = FALSE;
7823 				janus_mutex_lock(&source->rec_mutex);
7824 				if(source->arc) {
7825 					janus_recorder_close(source->arc);
7826 					JANUS_LOG(LOG_INFO, "[%s] Closed audio recording %s\n", mountpoint->name, source->arc->filename ? source->arc->filename : "??");
7827 					janus_recorder *tmp = source->arc;
7828 					source->arc = NULL;
7829 					janus_recorder_destroy(tmp);
7830 				}
7831 				if(source->vrc) {
7832 					janus_recorder_close(source->vrc);
7833 					JANUS_LOG(LOG_INFO, "[%s] Closed video recording %s\n", mountpoint->name, source->vrc->filename ? source->vrc->filename : "??");
7834 					janus_recorder *tmp = source->vrc;
7835 					source->vrc = NULL;
7836 					janus_recorder_destroy(tmp);
7837 				}
7838 				if(source->drc) {
7839 					janus_recorder_close(source->drc);
7840 					JANUS_LOG(LOG_INFO, "[%s] Closed data recording %s\n", mountpoint->name, source->drc->filename ? source->drc->filename : "??");
7841 					janus_recorder *tmp = source->drc;
7842 					source->drc = NULL;
7843 					janus_recorder_destroy(tmp);
7844 				}
7845 				janus_mutex_unlock(&source->rec_mutex);
7846 				break;
7847 			} else if(fds[i].revents & POLLIN) {
7848 				/* Got an RTP or data packet */
7849 				if(pipe_fd != -1 && fds[i].fd == pipe_fd) {
7850 					/* We're done here */
7851 					int code = 0;
7852 					bytes = read(pipe_fd, &code, sizeof(int));
7853 					JANUS_LOG(LOG_VERB, "[%s] Interrupting mountpoint\n", mountpoint->name);
7854 					break;
7855 				} else if(audio_fd != -1 && fds[i].fd == audio_fd) {
7856 					/* Got something audio (RTP) */
7857 					if(mountpoint->active == FALSE)
7858 						mountpoint->active = TRUE;
7859 					gint64 now = janus_get_monotonic_time();
7860 #ifdef HAVE_LIBCURL
7861 					source->reconnect_timer = now;
7862 #endif
7863 					addrlen = sizeof(remote);
7864 					bytes = recvfrom(audio_fd, buffer, 1500, 0, (struct sockaddr *)&remote, &addrlen);
7865 					if(bytes < 0 || !janus_is_rtp(buffer, bytes)) {
7866 						/* Failed to read or not an RTP packet? */
7867 						continue;
7868 					}
7869 					janus_rtp_header *rtp = (janus_rtp_header *)buffer;
7870 					ssrc = ntohl(rtp->ssrc);
7871 					if(source->rtp_collision > 0 && a_last_ssrc && ssrc != a_last_ssrc &&
7872 							(now-source->last_received_audio) < (gint64)1000*source->rtp_collision) {
7873 						JANUS_LOG(LOG_WARN, "[%s] RTP collision on audio mountpoint, dropping packet (ssrc=%"SCNu32")\n", name, ssrc);
7874 						continue;
7875 					}
7876 					source->last_received_audio = now;
7877 					//~ JANUS_LOG(LOG_VERB, "************************\nGot %d bytes on the audio channel...\n", bytes);
7878 					/* Do we have a new stream? */
7879 					if(ssrc != a_last_ssrc) {
7880 						source->audio_ssrc = a_last_ssrc = ssrc;
7881 						JANUS_LOG(LOG_INFO, "[%s] New audio stream! (ssrc=%"SCNu32")\n", name, a_last_ssrc);
7882 					}
7883 					/* If paused, ignore this packet */
7884 					if(!mountpoint->enabled && !source->arc)
7885 						continue;
7886 					/* Is this SRTP? */
7887 					if(source->is_srtp) {
7888 						int buflen = bytes;
7889 						srtp_err_status_t res = srtp_unprotect(source->srtp_ctx, buffer, &buflen);
7890 						//~ if(res != srtp_err_status_ok && res != srtp_err_status_replay_fail && res != srtp_err_status_replay_old) {
7891 						if(res != srtp_err_status_ok) {
7892 							guint32 timestamp = ntohl(rtp->timestamp);
7893 							guint16 seq = ntohs(rtp->seq_number);
7894 							JANUS_LOG(LOG_ERR, "[%s] Audio SRTP unprotect error: %s (len=%d-->%d, ts=%"SCNu32", seq=%"SCNu16")\n",
7895 								name, janus_srtp_error_str(res), bytes, buflen, timestamp, seq);
7896 							continue;
7897 						}
7898 						bytes = buflen;
7899 					}
7900 					//~ JANUS_LOG(LOG_VERB, " ... parsed RTP packet (ssrc=%u, pt=%u, seq=%u, ts=%u)...\n",
7901 						//~ ntohl(rtp->ssrc), rtp->type, ntohs(rtp->seq_number), ntohl(rtp->timestamp));
7902 					/* Relay on all sessions */
7903 					packet.data = rtp;
7904 					packet.length = bytes;
7905 					packet.is_rtp = TRUE;
7906 					packet.is_video = FALSE;
7907 					packet.is_keyframe = FALSE;
7908 					packet.data->type = mountpoint->codecs.audio_pt;
7909 					/* Is there a recorder? */
7910 					janus_rtp_header_update(packet.data, &source->context[0], FALSE, 0);
7911 					if(source->askew) {
7912 						int ret = janus_rtp_skew_compensate_audio(packet.data, &source->context[0], now);
7913 						if(ret < 0) {
7914 							JANUS_LOG(LOG_WARN, "[%s] Dropping %d packets, audio source clock is too fast (ssrc=%"SCNu32")\n",
7915 								name, -ret, a_last_ssrc);
7916 							continue;
7917 						} else if(ret > 0) {
7918 							JANUS_LOG(LOG_WARN, "[%s] Jumping %d RTP sequence numbers, audio source clock is too slow (ssrc=%"SCNu32")\n",
7919 								name, ret, a_last_ssrc);
7920 						}
7921 					}
7922 					if(source->arc) {
7923 						packet.data->ssrc = htonl((uint32_t)mountpoint->id);
7924 						janus_recorder_save_frame(source->arc, buffer, bytes);
7925 					}
7926 					if(mountpoint->enabled) {
7927 						packet.data->ssrc = htonl(ssrc);
7928 						/* Backup the actual payload type, timestamp and sequence number set by the restreamer, in case switching is involved */
7929 						packet.ptype = packet.data->type;
7930 						packet.timestamp = ntohl(packet.data->timestamp);
7931 						packet.seq_number = ntohs(packet.data->seq_number);
7932 						/* Go! */
7933 						janus_mutex_lock(&mountpoint->mutex);
7934 						g_list_foreach(mountpoint->helper_threads == 0 ? mountpoint->viewers : mountpoint->threads,
7935 							mountpoint->helper_threads == 0 ? janus_streaming_relay_rtp_packet : janus_streaming_helper_rtprtcp_packet,
7936 							&packet);
7937 						janus_mutex_unlock(&mountpoint->mutex);
7938 					}
7939 					continue;
7940 				} else if((video_fd[0] != -1 && fds[i].fd == video_fd[0]) ||
7941 						(video_fd[1] != -1 && fds[i].fd == video_fd[1]) ||
7942 						(video_fd[2] != -1 && fds[i].fd == video_fd[2])) {
7943 					/* Got something video (RTP) */
7944 					int index = -1;
7945 					if(fds[i].fd == video_fd[0])
7946 						index = 0;
7947 					else if(fds[i].fd == video_fd[1])
7948 						index = 1;
7949 					else if(fds[i].fd == video_fd[2])
7950 						index = 2;
7951 					if(mountpoint->active == FALSE)
7952 						mountpoint->active = TRUE;
7953 					gint64 now = janus_get_monotonic_time();
7954 #ifdef HAVE_LIBCURL
7955 					source->reconnect_timer = now;
7956 #endif
7957 					addrlen = sizeof(remote);
7958 					bytes = recvfrom(fds[i].fd, buffer, 1500, 0, (struct sockaddr *)&remote, &addrlen);
7959 					if(bytes < 0 || !janus_is_rtp(buffer, bytes)) {
7960 						/* Failed to read or not an RTP packet? */
7961 						continue;
7962 					}
7963 					janus_rtp_header *rtp = (janus_rtp_header *)buffer;
7964 					ssrc = ntohl(rtp->ssrc);
7965 					if(source->rtp_collision > 0 && v_last_ssrc[index] && ssrc != v_last_ssrc[index] &&
7966 							(now-source->last_received_video) < (gint64)1000*source->rtp_collision) {
7967 						JANUS_LOG(LOG_WARN, "[%s] RTP collision on video mountpoint, dropping packet (ssrc=%"SCNu32")\n",
7968 							name, ssrc);
7969 						continue;
7970 					}
7971 					source->last_received_video = now;
7972 					//~ JANUS_LOG(LOG_VERB, "************************\nGot %d bytes on the video channel...\n", bytes);
7973 					/* Do we have a new stream? */
7974 					if(ssrc != v_last_ssrc[index]) {
7975 						v_last_ssrc[index] = ssrc;
7976 						if(index == 0)
7977 							source->video_ssrc = ssrc;
7978 						JANUS_LOG(LOG_INFO, "[%s] New video stream! (ssrc=%"SCNu32", index %d)\n",
7979 							name, v_last_ssrc[index], index);
7980 					}
7981 					/* Is this SRTP? */
7982 					if(source->is_srtp) {
7983 						int buflen = bytes;
7984 						srtp_err_status_t res = srtp_unprotect(source->srtp_ctx, buffer, &buflen);
7985 						//~ if(res != srtp_err_status_ok && res != srtp_err_status_replay_fail && res != srtp_err_status_replay_old) {
7986 						if(res != srtp_err_status_ok) {
7987 							guint32 timestamp = ntohl(rtp->timestamp);
7988 							guint16 seq = ntohs(rtp->seq_number);
7989 							JANUS_LOG(LOG_ERR, "[%s] Video SRTP unprotect error: %s (len=%d-->%d, ts=%"SCNu32", seq=%"SCNu16")\n",
7990 								name, janus_srtp_error_str(res), bytes, buflen, timestamp, seq);
7991 							continue;
7992 						}
7993 						bytes = buflen;
7994 					}
7995 					/* First of all, let's check if this is (part of) a keyframe that we may need to save it for future reference */
7996 					if(source->keyframe.enabled) {
7997 						if(source->keyframe.temp_ts > 0 && ntohl(rtp->timestamp) != source->keyframe.temp_ts) {
7998 							/* We received the last part of the keyframe, get rid of the old one and use this from now on */
7999 							JANUS_LOG(LOG_HUGE, "[%s] ... ... last part of keyframe received! ts=%"SCNu32", %d packets\n",
8000 								name, source->keyframe.temp_ts, g_list_length(source->keyframe.temp_keyframe));
8001 							source->keyframe.temp_ts = 0;
8002 							janus_mutex_lock(&source->keyframe.mutex);
8003 							if(source->keyframe.latest_keyframe != NULL)
8004 								g_list_free_full(source->keyframe.latest_keyframe, (GDestroyNotify)janus_streaming_rtp_relay_packet_free);
8005 							source->keyframe.latest_keyframe = source->keyframe.temp_keyframe;
8006 							source->keyframe.temp_keyframe = NULL;
8007 							janus_mutex_unlock(&source->keyframe.mutex);
8008 						} else if(ntohl(rtp->timestamp) == source->keyframe.temp_ts) {
8009 							/* Part of the keyframe we're currently saving, store */
8010 							janus_mutex_lock(&source->keyframe.mutex);
8011 							JANUS_LOG(LOG_HUGE, "[%s] ... other part of keyframe received! ts=%"SCNu32"\n", name, source->keyframe.temp_ts);
8012 							janus_streaming_rtp_relay_packet *pkt = g_malloc0(sizeof(janus_streaming_rtp_relay_packet));
8013 							pkt->data = g_malloc(bytes);
8014 							memcpy(pkt->data, buffer, bytes);
8015 							pkt->data->ssrc = htons(1);
8016 							pkt->data->type = mountpoint->codecs.video_pt;
8017 							pkt->is_rtp = TRUE;
8018 							pkt->is_video = TRUE;
8019 							pkt->is_keyframe = TRUE;
8020 							pkt->length = bytes;
8021 							pkt->ptype = rtp->type;
8022 							pkt->timestamp = source->keyframe.temp_ts;
8023 							pkt->seq_number = ntohs(rtp->seq_number);
8024 							source->keyframe.temp_keyframe = g_list_append(source->keyframe.temp_keyframe, pkt);
8025 							janus_mutex_unlock(&source->keyframe.mutex);
8026 						} else {
8027 							gboolean kf = FALSE;
8028 							/* Parse RTP header first */
8029 							janus_rtp_header *header = (janus_rtp_header *)buffer;
8030 							guint32 timestamp = ntohl(header->timestamp);
8031 							guint16 seq = ntohs(header->seq_number);
8032 							JANUS_LOG(LOG_HUGE, "Checking if packet (size=%d, seq=%"SCNu16", ts=%"SCNu32") is a key frame...\n",
8033 								bytes, seq, timestamp);
8034 							int plen = 0;
8035 							char *payload = janus_rtp_payload(buffer, bytes, &plen);
8036 							if(payload) {
8037 								switch(mountpoint->codecs.video_codec) {
8038 									case JANUS_VIDEOCODEC_VP8:
8039 										kf = janus_vp8_is_keyframe(payload, plen);
8040 										break;
8041 									case JANUS_VIDEOCODEC_VP9:
8042 										kf = janus_vp9_is_keyframe(payload, plen);
8043 										break;
8044 									case JANUS_VIDEOCODEC_H264:
8045 										kf = janus_h264_is_keyframe(payload, plen);
8046 										break;
8047 									case JANUS_VIDEOCODEC_AV1:
8048 										kf = janus_av1_is_keyframe(payload, plen);
8049 										break;
8050 									case JANUS_VIDEOCODEC_H265:
8051 										kf = janus_h265_is_keyframe(payload, plen);
8052 										break;
8053 									default:
8054 										break;
8055 								}
8056 								if(kf) {
8057 									/* New keyframe, start saving it */
8058 									source->keyframe.temp_ts = ntohl(rtp->timestamp);
8059 									JANUS_LOG(LOG_HUGE, "[%s] New keyframe received! ts=%"SCNu32"\n", name, source->keyframe.temp_ts);
8060 									janus_mutex_lock(&source->keyframe.mutex);
8061 									janus_streaming_rtp_relay_packet *pkt = g_malloc0(sizeof(janus_streaming_rtp_relay_packet));
8062 									pkt->data = g_malloc(bytes);
8063 									memcpy(pkt->data, buffer, bytes);
8064 									pkt->data->ssrc = htons(1);
8065 									pkt->data->type = mountpoint->codecs.video_pt;
8066 									pkt->is_rtp = TRUE;
8067 									pkt->is_video = TRUE;
8068 									pkt->is_keyframe = TRUE;
8069 									pkt->length = bytes;
8070 									pkt->ptype = rtp->type;
8071 									pkt->timestamp = source->keyframe.temp_ts;
8072 									pkt->seq_number = ntohs(rtp->seq_number);
8073 									source->keyframe.temp_keyframe = g_list_append(source->keyframe.temp_keyframe, pkt);
8074 									janus_mutex_unlock(&source->keyframe.mutex);
8075 								}
8076 							}
8077 						}
8078 					}
8079 					/* If paused, ignore this packet */
8080 					if(!mountpoint->enabled && !source->vrc)
8081 						continue;
8082 					//~ JANUS_LOG(LOG_VERB, " ... parsed RTP packet (ssrc=%u, pt=%u, seq=%u, ts=%u)...\n",
8083 						//~ ntohl(rtp->ssrc), rtp->type, ntohs(rtp->seq_number), ntohl(rtp->timestamp));
8084 					/* Relay on all sessions */
8085 					packet.data = rtp;
8086 					packet.length = bytes;
8087 					packet.is_rtp = TRUE;
8088 					packet.is_video = TRUE;
8089 					packet.is_keyframe = FALSE;
8090 					packet.simulcast = source->simulcast;
8091 					packet.substream = index;
8092 					packet.codec = mountpoint->codecs.video_codec;
8093 					packet.svc = FALSE;
8094 					if(source->svc) {
8095 						/* We're doing SVC: let's parse this packet to see which layers are there */
8096 						int plen = 0;
8097 						char *payload = janus_rtp_payload(buffer, bytes, &plen);
8098 						if(payload) {
8099 							gboolean found = FALSE;
8100 							memset(&packet.svc_info, 0, sizeof(packet.svc_info));
8101 							if(janus_vp9_parse_svc(payload, plen, &found, &packet.svc_info) == 0) {
8102 								packet.svc = found;
8103 							}
8104 						}
8105 					}
8106 					packet.data->type = mountpoint->codecs.video_pt;
8107 					/* Is there a recorder? (FIXME notice we only record the first substream, if simulcasting) */
8108 					janus_rtp_header_update(packet.data, &source->context[index], TRUE, 0);
8109 					if(source->vskew) {
8110 						int ret = janus_rtp_skew_compensate_video(packet.data, &source->context[index], now);
8111 						if(ret < 0) {
8112 							JANUS_LOG(LOG_WARN, "[%s] Dropping %d packets, video source clock is too fast (ssrc=%"SCNu32", index %d)\n",
8113 								name, -ret, v_last_ssrc[index], index);
8114 							continue;
8115 						} else if(ret > 0) {
8116 							JANUS_LOG(LOG_WARN, "[%s] Jumping %d RTP sequence numbers, video source clock is too slow (ssrc=%"SCNu32", index %d)\n",
8117 								name, ret, v_last_ssrc[index], index);
8118 						}
8119 					}
8120 					if(index == 0 && source->vrc) {
8121 						packet.data->ssrc = htonl((uint32_t)mountpoint->id);
8122 						janus_recorder_save_frame(source->vrc, buffer, bytes);
8123 					}
8124 					if (mountpoint->enabled) {
8125 						packet.data->ssrc = htonl(ssrc);
8126 						/* Backup the actual payload type, timestamp and sequence number set by the restreamer, in case switching is involved */
8127 						packet.ptype = packet.data->type;
8128 						packet.timestamp = ntohl(packet.data->timestamp);
8129 						packet.seq_number = ntohs(packet.data->seq_number);
8130 						/* Take note of the simulcast SSRCs */
8131 						if(source->simulcast) {
8132 							packet.ssrc[0] = v_last_ssrc[0];
8133 							packet.ssrc[1] = v_last_ssrc[1];
8134 							packet.ssrc[2] = v_last_ssrc[2];
8135 						}
8136 						/* Go! */
8137 						janus_mutex_lock(&mountpoint->mutex);
8138 						g_list_foreach(mountpoint->helper_threads == 0 ? mountpoint->viewers : mountpoint->threads,
8139 							mountpoint->helper_threads == 0 ? janus_streaming_relay_rtp_packet : janus_streaming_helper_rtprtcp_packet,
8140 							&packet);
8141 						janus_mutex_unlock(&mountpoint->mutex);
8142 					}
8143 					continue;
8144 				} else if(data_fd != -1 && fds[i].fd == data_fd) {
8145 					/* Got something data (text) */
8146 					if(mountpoint->active == FALSE)
8147 						mountpoint->active = TRUE;
8148 					source->last_received_data = janus_get_monotonic_time();
8149 #ifdef HAVE_LIBCURL
8150 					source->reconnect_timer = janus_get_monotonic_time();
8151 #endif
8152 					addrlen = sizeof(remote);
8153 					bytes = recvfrom(data_fd, buffer, 1500, 0, (struct sockaddr *)&remote, &addrlen);
8154 					if(bytes < 1) {
8155 						/* Failed to read? */
8156 						continue;
8157 					}
8158 					if(!mountpoint->enabled && !source->drc)
8159 						continue;
8160 					/* Copy the data */
8161 					char *data = g_malloc(bytes);
8162 					memcpy(data, buffer, bytes);
8163 					/* Relay on all sessions */
8164 					packet.data = (janus_rtp_header *)data;
8165 					packet.length = bytes;
8166 					packet.is_rtp = FALSE;
8167 					packet.is_data = TRUE;
8168 					packet.textdata = source->textdata;
8169 					/* Is there a recorder? */
8170 					janus_recorder_save_frame(source->drc, data, bytes);
8171 					if(mountpoint->enabled) {
8172 						/* Are we keeping track of the last message being relayed? */
8173 						if(source->buffermsg) {
8174 							janus_mutex_lock(&source->buffermsg_mutex);
8175 							janus_streaming_rtp_relay_packet *pkt = g_malloc0(sizeof(janus_streaming_rtp_relay_packet));
8176 							pkt->data = g_malloc(bytes);
8177 							memcpy(pkt->data, data, bytes);
8178 							packet.is_rtp = FALSE;
8179 							packet.is_data = TRUE;
8180 							packet.textdata = source->textdata;
8181 							pkt->length = bytes;
8182 							janus_mutex_unlock(&source->buffermsg_mutex);
8183 						}
8184 						/* Go! */
8185 						janus_mutex_lock(&mountpoint->mutex);
8186 						g_list_foreach(mountpoint->helper_threads == 0 ? mountpoint->viewers : mountpoint->threads,
8187 							mountpoint->helper_threads == 0 ? janus_streaming_relay_rtp_packet : janus_streaming_helper_rtprtcp_packet,
8188 							&packet);
8189 						janus_mutex_unlock(&mountpoint->mutex);
8190 					}
8191 					g_free(packet.data);
8192 					packet.data = NULL;
8193 					continue;
8194 				} else if(audio_rtcp_fd != -1 && fds[i].fd == audio_rtcp_fd) {
8195 					addrlen = sizeof(remote);
8196 					bytes = recvfrom(audio_rtcp_fd, buffer, 1500, 0, (struct sockaddr *)&remote, &addrlen);
8197 					if(bytes < 0 || (!janus_is_rtp(buffer, bytes) && !janus_is_rtcp(buffer, bytes))) {
8198 						/* For latching we need an RTP or RTCP packet */
8199 						continue;
8200 					}
8201 					if(!mountpoint->enabled)
8202 						continue;
8203 					memcpy(&source->audio_rtcp_addr, &remote, addrlen);
8204 					if(!janus_is_rtcp(buffer, bytes)) {
8205 						/* Failed to read or not an RTCP packet? */
8206 						continue;
8207 					}
8208 					JANUS_LOG(LOG_HUGE, "[%s] Got audio RTCP feedback: SSRC %"SCNu32"\n",
8209 						name, janus_rtcp_get_sender_ssrc(buffer, bytes));
8210 					/* Relay on all sessions */
8211 					packet.is_rtp = FALSE;
8212 					packet.is_video = FALSE;
8213 					packet.data = (janus_rtp_header *)buffer;
8214 					packet.length = bytes;
8215 					/* Go! */
8216 					janus_mutex_lock(&mountpoint->mutex);
8217 					g_list_foreach(mountpoint->helper_threads == 0 ? mountpoint->viewers : mountpoint->threads,
8218 						mountpoint->helper_threads == 0 ? janus_streaming_relay_rtcp_packet : janus_streaming_helper_rtprtcp_packet,
8219 						&packet);
8220 					janus_mutex_unlock(&mountpoint->mutex);
8221 				} else if(video_rtcp_fd != -1 && fds[i].fd == video_rtcp_fd) {
8222 					addrlen = sizeof(remote);
8223 					bytes = recvfrom(video_rtcp_fd, buffer, 1500, 0, (struct sockaddr *)&remote, &addrlen);
8224 					if(bytes < 0 || (!janus_is_rtp(buffer, bytes) && !janus_is_rtcp(buffer, bytes))) {
8225 						/* For latching we need an RTP or RTCP packet */
8226 						continue;
8227 					}
8228 					if(!mountpoint->enabled)
8229 						continue;
8230 					memcpy(&source->video_rtcp_addr, &remote, addrlen);
8231 					if(!janus_is_rtcp(buffer, bytes)) {
8232 						/* Failed to read or not an RTCP packet? */
8233 						continue;
8234 					}
8235 					JANUS_LOG(LOG_HUGE, "[%s] Got video RTCP feedback: SSRC %"SCNu32"\n",
8236 						name, janus_rtcp_get_sender_ssrc(buffer, bytes));
8237 					/* Relay on all sessions */
8238 					packet.is_rtp = FALSE;
8239 					packet.is_video = TRUE;
8240 					packet.data = (janus_rtp_header *)buffer;
8241 					packet.length = bytes;
8242 					/* Go! */
8243 					janus_mutex_lock(&mountpoint->mutex);
8244 					g_list_foreach(mountpoint->helper_threads == 0 ? mountpoint->viewers : mountpoint->threads,
8245 						mountpoint->helper_threads == 0 ? janus_streaming_relay_rtcp_packet : janus_streaming_helper_rtprtcp_packet,
8246 						&packet);
8247 					janus_mutex_unlock(&mountpoint->mutex);
8248 				}
8249 			}
8250 		}
8251 	}
8252 
8253 	/* Notify users this mountpoint is done */
8254 	janus_mutex_lock(&mountpoint->mutex);
8255 	GList *viewer = g_list_first(mountpoint->viewers);
8256 	/* Prepare JSON event */
8257 	json_t *event = json_object();
8258 	json_object_set_new(event, "streaming", json_string("event"));
8259 	json_t *result = json_object();
8260 	json_object_set_new(result, "status", json_string("stopped"));
8261 	json_object_set_new(event, "result", result);
8262 	while(viewer) {
8263 		janus_streaming_session *session = (janus_streaming_session *)viewer->data;
8264 		if(session == NULL) {
8265 			mountpoint->viewers = g_list_remove_all(mountpoint->viewers, session);
8266 			viewer = g_list_first(mountpoint->viewers);
8267 			continue;
8268 		}
8269 		janus_mutex_lock(&session->mutex);
8270 		if(session->mountpoint != mountpoint) {
8271 			mountpoint->viewers = g_list_remove_all(mountpoint->viewers, session);
8272 			viewer = g_list_first(mountpoint->viewers);
8273 			janus_mutex_unlock(&session->mutex);
8274 			continue;
8275 		}
8276 		g_atomic_int_set(&session->stopping, 1);
8277 		g_atomic_int_set(&session->started, 0);
8278 		g_atomic_int_set(&session->paused, 0);
8279 		session->mountpoint = NULL;
8280 		/* Tell the core to tear down the PeerConnection, hangup_media will do the rest */
8281 		gateway->push_event(session->handle, &janus_streaming_plugin, NULL, event, NULL);
8282 		gateway->close_pc(session->handle);
8283 		janus_refcount_decrease(&session->ref);
8284 		janus_refcount_decrease(&mountpoint->ref);
8285 		mountpoint->viewers = g_list_remove_all(mountpoint->viewers, session);
8286 		viewer = g_list_first(mountpoint->viewers);
8287 		janus_mutex_unlock(&session->mutex);
8288 	}
8289 	json_decref(event);
8290 	janus_mutex_unlock(&mountpoint->mutex);
8291 
8292 	/* Unref the helper threads */
8293 	if(mountpoint->helper_threads > 0) {
8294 		GList *l = mountpoint->threads;
8295 		while(l) {
8296 			janus_streaming_helper *ht = (janus_streaming_helper *)l->data;
8297 			janus_refcount_decrease(&ht->ref);
8298 			l = l->next;
8299 		}
8300 	}
8301 
8302 	JANUS_LOG(LOG_VERB, "[%s] Leaving streaming relay thread\n", name);
8303 	g_free(name);
8304 	janus_refcount_decrease(&mountpoint->ref);
8305 	return NULL;
8306 }
8307 
8308 static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data) {
8309 	janus_streaming_rtp_relay_packet *packet = (janus_streaming_rtp_relay_packet *)user_data;
8310 	if(!packet || !packet->data || packet->length < 1) {
8311 		JANUS_LOG(LOG_ERR, "Invalid packet...\n");
8312 		return;
8313 	}
8314 	janus_streaming_session *session = (janus_streaming_session *)data;
8315 	if(!session || !session->handle) {
8316 		//~ JANUS_LOG(LOG_ERR, "Invalid session...\n");
8317 		return;
8318 	}
8319 	if(!packet->is_keyframe && (!g_atomic_int_get(&session->started) || g_atomic_int_get(&session->paused))) {
8320 		//~ JANUS_LOG(LOG_ERR, "Streaming not started yet for this session...\n");
8321 		return;
8322 	}
8323 
8324 	if(packet->is_rtp) {
8325 		/* Make sure there hasn't been a video source switch by checking the SSRC */
8326 		if(packet->is_video) {
8327 			if(!session->video)
8328 				return;
8329 			/* Check if there's any SVC info to take into account */
8330 			if(packet->svc) {
8331 				/* There is: check if this is a layer that can be dropped for this viewer
8332 				 * Note: Following core inspired by the excellent job done by Sergio Garcia Murillo here:
8333 				 * https://github.com/medooze/media-server/blob/master/src/vp9/VP9LayerSelector.cpp */
8334 				int plen = 0;
8335 				char *payload = janus_rtp_payload((char *)packet->data, packet->length, &plen);
8336 				gboolean keyframe = janus_vp9_is_keyframe((const char *)payload, plen);
8337 				gboolean override_mark_bit = FALSE, has_marker_bit = packet->data->markerbit;
8338 				int spatial_layer = session->spatial_layer;
8339 				gint64 now = janus_get_monotonic_time();
8340 				if(packet->svc_info.spatial_layer >= 0 && packet->svc_info.spatial_layer <= 2)
8341 					session->last_spatial_layer[packet->svc_info.spatial_layer] = now;
8342 				if(session->target_spatial_layer > session->spatial_layer) {
8343 					JANUS_LOG(LOG_HUGE, "We need to upscale spatially: (%d < %d)\n",
8344 						session->spatial_layer, session->target_spatial_layer);
8345 					/* We need to upscale: wait for a keyframe */
8346 					if(keyframe) {
8347 						int new_spatial_layer = session->target_spatial_layer;
8348 						while(new_spatial_layer > session->spatial_layer && new_spatial_layer > 0) {
8349 							if(now - session->last_spatial_layer[new_spatial_layer] >= 250000) {
8350 								/* We haven't received packets from this layer for a while, try a lower layer */
8351 								JANUS_LOG(LOG_HUGE, "Haven't received packets from layer %d for a while, trying %d instead...\n",
8352 									new_spatial_layer, new_spatial_layer-1);
8353 								new_spatial_layer--;
8354 							} else {
8355 								break;
8356 							}
8357 						}
8358 						if(new_spatial_layer > session->spatial_layer) {
8359 							JANUS_LOG(LOG_HUGE, "  -- Upscaling spatial layer: %d --> %d (need %d)\n",
8360 								session->spatial_layer, new_spatial_layer, session->target_spatial_layer);
8361 							session->spatial_layer = new_spatial_layer;
8362 							spatial_layer = session->spatial_layer;
8363 							/* Notify the viewer */
8364 							json_t *event = json_object();
8365 							json_object_set_new(event, "streaming", json_string("event"));
8366 							json_t *result = json_object();
8367 							json_object_set_new(result, "spatial_layer", json_integer(session->spatial_layer));
8368 							if(session->temporal_layer == -1) {
8369 								/* We just started: initialize the temporal layer and notify that too */
8370 								session->temporal_layer = 0;
8371 								json_object_set_new(result, "temporal_layer", json_integer(session->temporal_layer));
8372 							}
8373 							json_object_set_new(event, "result", result);
8374 							gateway->push_event(session->handle, &janus_streaming_plugin, NULL, event, NULL);
8375 							json_decref(event);
8376 						}
8377 					}
8378 				} else if(session->target_spatial_layer < session->spatial_layer) {
8379 					/* We need to downscale */
8380 					JANUS_LOG(LOG_HUGE, "We need to downscale spatially: (%d > %d)\n",
8381 						session->spatial_layer, session->target_spatial_layer);
8382 					gboolean downscaled = FALSE;
8383 					if(!packet->svc_info.fbit && keyframe) {
8384 						/* Non-flexible mode: wait for a keyframe */
8385 						downscaled = TRUE;
8386 					} else if(packet->svc_info.fbit && packet->svc_info.ebit) {
8387 						/* Flexible mode: check the E bit */
8388 						downscaled = TRUE;
8389 					}
8390 					if(downscaled) {
8391 						JANUS_LOG(LOG_HUGE, "  -- Downscaling spatial layer: %d --> %d\n",
8392 							session->spatial_layer, session->target_spatial_layer);
8393 						session->spatial_layer = session->target_spatial_layer;
8394 						/* Notify the viewer */
8395 						json_t *event = json_object();
8396 						json_object_set_new(event, "streaming", json_string("event"));
8397 						json_t *result = json_object();
8398 						json_object_set_new(result, "spatial_layer", json_integer(session->spatial_layer));
8399 						json_object_set_new(event, "result", result);
8400 						gateway->push_event(session->handle, &janus_streaming_plugin, NULL, event, NULL);
8401 						json_decref(event);
8402 					}
8403 				}
8404 				if(spatial_layer < packet->svc_info.spatial_layer) {
8405 					/* Drop the packet: update the context to make sure sequence number is increased normally later */
8406 					JANUS_LOG(LOG_HUGE, "Dropping packet (spatial layer %d < %d)\n", spatial_layer, packet->svc_info.spatial_layer);
8407 					session->context.v_base_seq++;
8408 					return;
8409 				} else if(packet->svc_info.ebit && spatial_layer == packet->svc_info.spatial_layer) {
8410 					/* If we stop at layer 0, we need a marker bit now, as the one from layer 1 will not be received */
8411 					override_mark_bit = TRUE;
8412 				}
8413 				int temporal_layer = session->temporal_layer;
8414 				if(session->target_temporal_layer > session->temporal_layer) {
8415 					/* We need to upscale */
8416 					JANUS_LOG(LOG_HUGE, "We need to upscale temporally: (%d < %d)\n",
8417 						session->temporal_layer, session->target_temporal_layer);
8418 					if(packet->svc_info.ubit && packet->svc_info.bbit &&
8419 							packet->svc_info.temporal_layer > session->temporal_layer &&
8420 							packet->svc_info.temporal_layer <= session->target_temporal_layer) {
8421 						JANUS_LOG(LOG_HUGE, "  -- Upscaling temporal layer: %d --> %d (want %d)\n",
8422 							session->temporal_layer, packet->svc_info.temporal_layer, session->target_temporal_layer);
8423 						session->temporal_layer = packet->svc_info.temporal_layer;
8424 						temporal_layer = session->temporal_layer;
8425 						/* Notify the viewer */
8426 						json_t *event = json_object();
8427 						json_object_set_new(event, "streaming", json_string("event"));
8428 						json_t *result = json_object();
8429 						json_object_set_new(result, "temporal_layer", json_integer(session->temporal_layer));
8430 						json_object_set_new(event, "result", result);
8431 						gateway->push_event(session->handle, &janus_streaming_plugin, NULL, event, NULL);
8432 						json_decref(event);
8433 					}
8434 				} else if(session->target_temporal_layer < session->temporal_layer) {
8435 					/* We need to downscale */
8436 					JANUS_LOG(LOG_HUGE, "We need to downscale temporally: (%d > %d)\n",
8437 						session->temporal_layer, session->target_temporal_layer);
8438 					if(packet->svc_info.ebit && packet->svc_info.temporal_layer == session->target_temporal_layer) {
8439 						JANUS_LOG(LOG_HUGE, "  -- Downscaling temporal layer: %d --> %d\n",
8440 							session->temporal_layer, session->target_temporal_layer);
8441 						session->temporal_layer = session->target_temporal_layer;
8442 						/* Notify the viewer */
8443 						json_t *event = json_object();
8444 						json_object_set_new(event, "streaming", json_string("event"));
8445 						json_t *result = json_object();
8446 						json_object_set_new(result, "temporal_layer", json_integer(session->temporal_layer));
8447 						json_object_set_new(event, "result", result);
8448 						gateway->push_event(session->handle, &janus_streaming_plugin, NULL, event, NULL);
8449 						json_decref(event);
8450 					}
8451 				}
8452 				if(temporal_layer < packet->svc_info.temporal_layer) {
8453 					/* Drop the packet: update the context to make sure sequence number is increased normally later */
8454 					JANUS_LOG(LOG_HUGE, "Dropping packet (temporal layer %d < %d)\n", temporal_layer, packet->svc_info.temporal_layer);
8455 					session->context.v_base_seq++;
8456 					return;
8457 				}
8458 				/* If we got here, we can send the frame: this doesn't necessarily mean it's
8459 				 * one of the layers the user wants, as there may be dependencies involved */
8460 				JANUS_LOG(LOG_HUGE, "Sending packet (spatial=%d, temporal=%d)\n",
8461 					packet->svc_info.spatial_layer, packet->svc_info.temporal_layer);
8462 				/* Fix sequence number and timestamp (publisher switching may be involved) */
8463 				janus_rtp_header_update(packet->data, &session->context, TRUE, 0);
8464 				if(override_mark_bit && !has_marker_bit) {
8465 					packet->data->markerbit = 1;
8466 				}
8467 				if(session->video_pt > 0)
8468 					packet->data->type = session->video_pt;
8469 				janus_plugin_rtp rtp = { .video = packet->is_video, .buffer = (char *)packet->data, .length = packet->length };
8470 				janus_plugin_rtp_extensions_reset(&rtp.extensions);
8471 				if(gateway != NULL)
8472 					gateway->relay_rtp(session->handle, &rtp);
8473 				if(override_mark_bit && !has_marker_bit) {
8474 					packet->data->markerbit = 0;
8475 				}
8476 				/* Restore the payload type, timestamp and sequence number to what the publisher set them to */
8477 				packet->data->type = packet->ptype;
8478 				packet->data->timestamp = htonl(packet->timestamp);
8479 				packet->data->seq_number = htons(packet->seq_number);
8480 			} else if(packet->simulcast) {
8481 				/* Handle simulcast: don't relay if it's not the substream we wanted to handle */
8482 				int plen = 0;
8483 				char *payload = janus_rtp_payload((char *)packet->data, packet->length, &plen);
8484 				if(payload == NULL)
8485 					return;
8486 				/* Process this packet: don't relay if it's not the SSRC/layer we wanted to handle */
8487 				gboolean relay = janus_rtp_simulcasting_context_process_rtp(&session->sim_context,
8488 					(char *)packet->data, packet->length, packet->ssrc, NULL, packet->codec, &session->context);
8489 				if(!relay) {
8490 					/* Did a lot of time pass before we could relay a packet? */
8491 					gint64 now = janus_get_monotonic_time();
8492 					if((now - session->sim_context.last_relayed) >= G_USEC_PER_SEC) {
8493 						g_atomic_int_set(&session->sim_context.need_pli, 1);
8494 					}
8495 				}
8496 				if(session->sim_context.need_pli) {
8497 					/* Schedule a PLI */
8498 					JANUS_LOG(LOG_VERB, "We need a PLI for the simulcast context\n");
8499 					if(session->mountpoint != NULL) {
8500 						janus_streaming_rtp_source *source = session->mountpoint->source;
8501 						if(source != NULL)
8502 							g_atomic_int_set(&source->need_pli, 1);
8503 					}
8504 				}
8505 				/* Do we need to drop this? */
8506 				if(!relay)
8507 					return;
8508 				/* Any event we should notify? */
8509 				if(session->sim_context.changed_substream) {
8510 					/* Notify the user about the substream change */
8511 					json_t *event = json_object();
8512 					json_object_set_new(event, "streaming", json_string("event"));
8513 					json_t *result = json_object();
8514 					json_object_set_new(result, "substream", json_integer(session->sim_context.substream));
8515 					json_object_set_new(event, "result", result);
8516 					gateway->push_event(session->handle, &janus_streaming_plugin, NULL, event, NULL);
8517 					json_decref(event);
8518 				}
8519 				if(session->sim_context.changed_temporal) {
8520 					/* Notify the user about the temporal layer change */
8521 					json_t *event = json_object();
8522 					json_object_set_new(event, "streaming", json_string("event"));
8523 					json_t *result = json_object();
8524 					json_object_set_new(result, "temporal", json_integer(session->sim_context.templayer));
8525 					json_object_set_new(event, "result", result);
8526 					gateway->push_event(session->handle, &janus_streaming_plugin, NULL, event, NULL);
8527 					json_decref(event);
8528 				}
8529 				/* If we got here, update the RTP header and send the packet */
8530 				janus_rtp_header_update(packet->data, &session->context, TRUE, 0);
8531 				char vp8pd[6];
8532 				if(packet->codec == JANUS_VIDEOCODEC_VP8) {
8533 					/* For VP8, we save the original payload descriptor, to restore it after */
8534 					memcpy(vp8pd, payload, sizeof(vp8pd));
8535 					janus_vp8_simulcast_descriptor_update(payload, plen, &session->vp8_context,
8536 						session->sim_context.changed_substream);
8537 				}
8538 				if(session->video_pt > 0)
8539 					packet->data->type = session->video_pt;
8540 				/* Send the packet */
8541 				janus_plugin_rtp rtp = { .video = packet->is_video, .buffer = (char *)packet->data, .length = packet->length };
8542 				janus_plugin_rtp_extensions_reset(&rtp.extensions);
8543 				if(gateway != NULL)
8544 					gateway->relay_rtp(session->handle, &rtp);
8545 				/* Restore the timestamp and sequence number to what the publisher set them to */
8546 				packet->data->type = packet->ptype;
8547 				packet->data->timestamp = htonl(packet->timestamp);
8548 				packet->data->seq_number = htons(packet->seq_number);
8549 				if(packet->codec == JANUS_VIDEOCODEC_VP8) {
8550 					/* Restore the original payload descriptor as well, as it will be needed by the next viewer */
8551 					memcpy(payload, vp8pd, sizeof(vp8pd));
8552 				}
8553 			} else {
8554 				/* Fix sequence number and timestamp (switching may be involved) */
8555 				janus_rtp_header_update(packet->data, &session->context, TRUE, 0);
8556 				if(session->video_pt > 0)
8557 					packet->data->type = session->video_pt;
8558 				janus_plugin_rtp rtp = { .video = packet->is_video, .buffer = (char *)packet->data, .length = packet->length };
8559 				janus_plugin_rtp_extensions_reset(&rtp.extensions);
8560 				if(gateway != NULL)
8561 					gateway->relay_rtp(session->handle, &rtp);
8562 				/* Restore the timestamp and sequence number to what the video source set them to */
8563 				packet->data->type = packet->ptype;
8564 				packet->data->timestamp = htonl(packet->timestamp);
8565 				packet->data->seq_number = htons(packet->seq_number);
8566 			}
8567 		} else {
8568 			if(!session->audio)
8569 				return;
8570 			/* Fix sequence number and timestamp (switching may be involved) */
8571 			janus_rtp_header_update(packet->data, &session->context, FALSE, 0);
8572 			if(session->audio_pt >= 0)
8573 				packet->data->type = session->audio_pt;
8574 			janus_plugin_rtp rtp = { .video = packet->is_video, .buffer = (char *)packet->data, .length = packet->length };
8575 			janus_plugin_rtp_extensions_reset(&rtp.extensions);
8576 			if(gateway != NULL)
8577 				gateway->relay_rtp(session->handle, &rtp);
8578 			/* Restore the timestamp and sequence number to what the video source set them to */
8579 			packet->data->type = packet->ptype;
8580 			packet->data->timestamp = htonl(packet->timestamp);
8581 			packet->data->seq_number = htons(packet->seq_number);
8582 		}
8583 	} else {
8584 		/* We're broadcasting a data channel message */
8585 		if(!session->data)
8586 			return;
8587 		if(gateway != NULL && packet->data != NULL && g_atomic_int_get(&session->dataready)) {
8588 			janus_plugin_data data = {
8589 				.label = NULL,
8590 				.protocol = NULL,
8591 				.binary = !packet->textdata,
8592 				.buffer = (char *)packet->data,
8593 				.length = packet->length
8594 			};
8595 			gateway->relay_data(session->handle, &data);
8596 		}
8597 	}
8598 
8599 	return;
8600 }
8601 
8602 static void janus_streaming_relay_rtcp_packet(gpointer data, gpointer user_data) {
8603 	janus_streaming_rtp_relay_packet *packet = (janus_streaming_rtp_relay_packet *)user_data;
8604 	if(!packet || !packet->data || packet->length < 1) {
8605 		JANUS_LOG(LOG_ERR, "Invalid packet...\n");
8606 		return;
8607 	}
8608 	janus_streaming_session *session = (janus_streaming_session *)data;
8609 	if(!session || !session->handle) {
8610 		//~ JANUS_LOG(LOG_ERR, "Invalid session...\n");
8611 		return;
8612 	}
8613 	if(!g_atomic_int_get(&session->started) || g_atomic_int_get(&session->paused)) {
8614 		//~ JANUS_LOG(LOG_ERR, "Streaming not started yet for this session...\n");
8615 		return;
8616 	}
8617 
8618 	janus_plugin_rtcp rtcp = { .video = packet->is_video, .buffer = (char *)packet->data, .length = packet->length };
8619 	if(gateway != NULL)
8620 		gateway->relay_rtcp(session->handle, &rtcp);
8621 
8622 	return;
8623 }
8624 
8625 static void janus_streaming_helper_rtprtcp_packet(gpointer data, gpointer user_data) {
8626 	janus_streaming_rtp_relay_packet *packet = (janus_streaming_rtp_relay_packet *)user_data;
8627 	if(!packet || !packet->data || packet->length < 1) {
8628 		JANUS_LOG(LOG_ERR, "Invalid packet...\n");
8629 		return;
8630 	}
8631 	janus_streaming_helper *helper = (janus_streaming_helper *)data;
8632 	if(!helper) {
8633 		//~ JANUS_LOG(LOG_ERR, "Invalid session...\n");
8634 		return;
8635 	}
8636 	/* Clone the packet and queue it for delivery on the helper thread */
8637 	janus_streaming_rtp_relay_packet *copy = g_malloc0(sizeof(janus_streaming_rtp_relay_packet));
8638 	copy->data = g_malloc(packet->length);
8639 	memcpy(copy->data, packet->data, packet->length);
8640 	copy->length = packet->length;
8641 	copy->is_rtp = packet->is_rtp;
8642 	copy->is_data = packet->is_data;
8643 	copy->textdata = packet->textdata;
8644 	copy->is_video = packet->is_video;
8645 	copy->is_keyframe = packet->is_keyframe;
8646 	copy->simulcast = packet->simulcast;
8647 	copy->ssrc[0] = packet->ssrc[0];
8648 	copy->ssrc[1] = packet->ssrc[1];
8649 	copy->ssrc[2] = packet->ssrc[2];
8650 	copy->codec = packet->codec;
8651 	copy->substream = packet->substream;
8652 	copy->ptype = packet->ptype;
8653 	copy->timestamp = packet->timestamp;
8654 	copy->seq_number = packet->seq_number;
8655 	g_async_queue_push(helper->queued_packets, copy);
8656 }
8657 
8658 static void *janus_streaming_helper_thread(void *data) {
8659 	janus_streaming_helper *helper = (janus_streaming_helper *)data;
8660 	janus_streaming_mountpoint *mp = helper->mp;
8661 	JANUS_LOG(LOG_INFO, "[%s/#%d] Joining Streaming helper thread\n", mp->name, helper->id);
8662 	janus_streaming_rtp_relay_packet *pkt = NULL;
8663 	while(!g_atomic_int_get(&stopping) && !g_atomic_int_get(&mp->destroyed) && !g_atomic_int_get(&helper->destroyed)) {
8664 		pkt = g_async_queue_pop(helper->queued_packets);
8665 		if(pkt == &exit_packet)
8666 			break;
8667 		janus_mutex_lock(&helper->mutex);
8668 		g_list_foreach(helper->viewers,
8669 			pkt->is_rtp || pkt->is_data ? janus_streaming_relay_rtp_packet : janus_streaming_relay_rtcp_packet,
8670 			pkt);
8671 		janus_mutex_unlock(&helper->mutex);
8672 		janus_streaming_rtp_relay_packet_free(pkt);
8673 	}
8674 	JANUS_LOG(LOG_INFO, "[%s/#%d] Leaving Streaming helper thread\n", mp->name, helper->id);
8675 	janus_refcount_decrease(&helper->ref);
8676 	janus_refcount_decrease(&mp->ref);
8677 	g_thread_unref(g_thread_self());
8678 	return NULL;
8679 }
8680