1 
2 /*
3  * Copyright (C) Roman Arutyunyan
4  */
5 
6 #include <ngx_config.h>
7 #include <ngx_core.h>
8 #include "ngx_rtmp.h"
9 #include "ngx_rtmp_amf.h"
10 #include "ngx_rtmp_streams.h"
11 
12 
13 #define NGX_RTMP_USER_START(s, tp)                                          \
14     ngx_rtmp_header_t               __h;                                    \
15     ngx_chain_t                    *__l;                                    \
16     ngx_buf_t                      *__b;                                    \
17     ngx_rtmp_core_srv_conf_t       *__cscf;                                 \
18                                                                             \
19     __cscf = ngx_rtmp_get_module_srv_conf(                                  \
20             s, ngx_rtmp_core_module);                                       \
21     memset(&__h, 0, sizeof(__h));                                           \
22     __h.type = tp;                                                          \
23     __h.csid = 2;                                                           \
24     __l = ngx_rtmp_alloc_shared_buf(__cscf);                                \
25     if (__l == NULL) {                                                      \
26         return NULL;                                                        \
27     }                                                                       \
28     __b = __l->buf;
29 
30 #define NGX_RTMP_UCTL_START(s, type, utype)                                 \
31     NGX_RTMP_USER_START(s, type);                                           \
32     *(__b->last++) = (u_char)((utype) >> 8);                                \
33     *(__b->last++) = (u_char)(utype);
34 
35 #define NGX_RTMP_USER_OUT1(v)                                               \
36     *(__b->last++) = ((u_char*)&v)[0];
37 
38 #define NGX_RTMP_USER_OUT4(v)                                               \
39     *(__b->last++) = ((u_char*)&v)[3];                                      \
40     *(__b->last++) = ((u_char*)&v)[2];                                      \
41     *(__b->last++) = ((u_char*)&v)[1];                                      \
42     *(__b->last++) = ((u_char*)&v)[0];
43 
44 #define NGX_RTMP_USER_END(s)                                                \
45     ngx_rtmp_prepare_message(s, &__h, NULL, __l);                           \
46     return __l;
47 
48 
49 static ngx_int_t
ngx_rtmp_send_shared_packet(ngx_rtmp_session_t * s,ngx_chain_t * cl)50 ngx_rtmp_send_shared_packet(ngx_rtmp_session_t *s, ngx_chain_t *cl)
51 {
52     ngx_rtmp_core_srv_conf_t       *cscf;
53     ngx_int_t                       rc;
54 
55     if (cl == NULL) {
56         return NGX_ERROR;
57     }
58 
59     cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
60 
61     rc = ngx_rtmp_send_message(s, cl, 0);
62 
63     ngx_rtmp_free_shared_chain(cscf, cl);
64 
65     return rc;
66 }
67 
68 
69 /* Protocol control messages */
70 
71 ngx_chain_t *
ngx_rtmp_create_chunk_size(ngx_rtmp_session_t * s,uint32_t chunk_size)72 ngx_rtmp_create_chunk_size(ngx_rtmp_session_t *s, uint32_t chunk_size)
73 {
74     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
75                    "chunk_size=%uD", chunk_size);
76 
77     {
78         NGX_RTMP_USER_START(s, NGX_RTMP_MSG_CHUNK_SIZE);
79 
80         NGX_RTMP_USER_OUT4(chunk_size);
81 
82         NGX_RTMP_USER_END(s);
83     }
84 }
85 
86 
87 ngx_int_t
ngx_rtmp_send_chunk_size(ngx_rtmp_session_t * s,uint32_t chunk_size)88 ngx_rtmp_send_chunk_size(ngx_rtmp_session_t *s, uint32_t chunk_size)
89 {
90     return ngx_rtmp_send_shared_packet(s,
91            ngx_rtmp_create_chunk_size(s, chunk_size));
92 }
93 
94 
95 ngx_chain_t *
ngx_rtmp_create_abort(ngx_rtmp_session_t * s,uint32_t csid)96 ngx_rtmp_create_abort(ngx_rtmp_session_t *s, uint32_t csid)
97 {
98     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
99                    "create: abort csid=%uD", csid);
100 
101     {
102         NGX_RTMP_USER_START(s, NGX_RTMP_MSG_ABORT);
103 
104         NGX_RTMP_USER_OUT4(csid);
105 
106         NGX_RTMP_USER_END(s);
107     }
108 }
109 
110 
111 ngx_int_t
ngx_rtmp_send_abort(ngx_rtmp_session_t * s,uint32_t csid)112 ngx_rtmp_send_abort(ngx_rtmp_session_t *s, uint32_t csid)
113 {
114     return ngx_rtmp_send_shared_packet(s,
115            ngx_rtmp_create_abort(s, csid));
116 }
117 
118 
119 ngx_chain_t *
ngx_rtmp_create_ack(ngx_rtmp_session_t * s,uint32_t seq)120 ngx_rtmp_create_ack(ngx_rtmp_session_t *s, uint32_t seq)
121 {
122     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
123                    "create: ack seq=%uD", seq);
124 
125     {
126         NGX_RTMP_USER_START(s, NGX_RTMP_MSG_ACK);
127 
128         NGX_RTMP_USER_OUT4(seq);
129 
130         NGX_RTMP_USER_END(s);
131     }
132 }
133 
134 
135 ngx_int_t
ngx_rtmp_send_ack(ngx_rtmp_session_t * s,uint32_t seq)136 ngx_rtmp_send_ack(ngx_rtmp_session_t *s, uint32_t seq)
137 {
138     return ngx_rtmp_send_shared_packet(s,
139            ngx_rtmp_create_ack(s, seq));
140 }
141 
142 
143 ngx_chain_t *
ngx_rtmp_create_ack_size(ngx_rtmp_session_t * s,uint32_t ack_size)144 ngx_rtmp_create_ack_size(ngx_rtmp_session_t *s, uint32_t ack_size)
145 {
146     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
147                    "create: ack_size=%uD", ack_size);
148 
149     {
150         NGX_RTMP_USER_START(s, NGX_RTMP_MSG_ACK_SIZE);
151 
152         NGX_RTMP_USER_OUT4(ack_size);
153 
154         NGX_RTMP_USER_END(s);
155     }
156 }
157 
158 
159 ngx_int_t
ngx_rtmp_send_ack_size(ngx_rtmp_session_t * s,uint32_t ack_size)160 ngx_rtmp_send_ack_size(ngx_rtmp_session_t *s, uint32_t ack_size)
161 {
162     return ngx_rtmp_send_shared_packet(s,
163            ngx_rtmp_create_ack_size(s, ack_size));
164 }
165 
166 
167 ngx_chain_t *
ngx_rtmp_create_bandwidth(ngx_rtmp_session_t * s,uint32_t ack_size,uint8_t limit_type)168 ngx_rtmp_create_bandwidth(ngx_rtmp_session_t *s, uint32_t ack_size,
169                           uint8_t limit_type)
170 {
171     ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
172                    "create: bandwidth ack_size=%uD limit=%d",
173                    ack_size, (int)limit_type);
174 
175     {
176         NGX_RTMP_USER_START(s, NGX_RTMP_MSG_BANDWIDTH);
177 
178         NGX_RTMP_USER_OUT4(ack_size);
179         NGX_RTMP_USER_OUT1(limit_type);
180 
181         NGX_RTMP_USER_END(s);
182     }
183 }
184 
185 
186 ngx_int_t
ngx_rtmp_send_bandwidth(ngx_rtmp_session_t * s,uint32_t ack_size,uint8_t limit_type)187 ngx_rtmp_send_bandwidth(ngx_rtmp_session_t *s, uint32_t ack_size,
188                         uint8_t limit_type)
189 {
190     return ngx_rtmp_send_shared_packet(s,
191            ngx_rtmp_create_bandwidth(s, ack_size, limit_type));
192 }
193 
194 
195 /* User control messages */
196 
197 ngx_chain_t *
ngx_rtmp_create_stream_begin(ngx_rtmp_session_t * s,uint32_t msid)198 ngx_rtmp_create_stream_begin(ngx_rtmp_session_t *s, uint32_t msid)
199 {
200     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
201                    "create: stream_begin msid=%uD", msid);
202 
203     {
204         NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_STREAM_BEGIN);
205 
206         NGX_RTMP_USER_OUT4(msid);
207 
208         NGX_RTMP_USER_END(s);
209     }
210 }
211 
212 
213 ngx_int_t
ngx_rtmp_send_stream_begin(ngx_rtmp_session_t * s,uint32_t msid)214 ngx_rtmp_send_stream_begin(ngx_rtmp_session_t *s, uint32_t msid)
215 {
216     return ngx_rtmp_send_shared_packet(s,
217            ngx_rtmp_create_stream_begin(s, msid));
218 }
219 
220 
221 ngx_chain_t *
ngx_rtmp_create_stream_eof(ngx_rtmp_session_t * s,uint32_t msid)222 ngx_rtmp_create_stream_eof(ngx_rtmp_session_t *s, uint32_t msid)
223 {
224     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
225                    "create: stream_end msid=%uD", msid);
226 
227     {
228         NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_STREAM_EOF);
229 
230         NGX_RTMP_USER_OUT4(msid);
231 
232         NGX_RTMP_USER_END(s);
233     }
234 }
235 
236 
237 ngx_int_t
ngx_rtmp_send_stream_eof(ngx_rtmp_session_t * s,uint32_t msid)238 ngx_rtmp_send_stream_eof(ngx_rtmp_session_t *s, uint32_t msid)
239 {
240     return ngx_rtmp_send_shared_packet(s,
241            ngx_rtmp_create_stream_eof(s, msid));
242 }
243 
244 
245 ngx_chain_t *
ngx_rtmp_create_stream_dry(ngx_rtmp_session_t * s,uint32_t msid)246 ngx_rtmp_create_stream_dry(ngx_rtmp_session_t *s, uint32_t msid)
247 {
248     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
249                    "create: stream_dry msid=%uD", msid);
250 
251     {
252         NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_STREAM_DRY);
253 
254         NGX_RTMP_USER_OUT4(msid);
255 
256         NGX_RTMP_USER_END(s);
257     }
258 }
259 
260 
261 ngx_int_t
ngx_rtmp_send_stream_dry(ngx_rtmp_session_t * s,uint32_t msid)262 ngx_rtmp_send_stream_dry(ngx_rtmp_session_t *s, uint32_t msid)
263 {
264     return ngx_rtmp_send_shared_packet(s,
265            ngx_rtmp_create_stream_dry(s, msid));
266 }
267 
268 
269 ngx_chain_t *
ngx_rtmp_create_set_buflen(ngx_rtmp_session_t * s,uint32_t msid,uint32_t buflen_msec)270 ngx_rtmp_create_set_buflen(ngx_rtmp_session_t *s, uint32_t msid,
271                            uint32_t buflen_msec)
272 {
273     ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
274                    "create: set_buflen msid=%uD buflen=%uD",
275                    msid, buflen_msec);
276 
277     {
278         NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_SET_BUFLEN);
279 
280         NGX_RTMP_USER_OUT4(msid);
281         NGX_RTMP_USER_OUT4(buflen_msec);
282 
283         NGX_RTMP_USER_END(s);
284     }
285 }
286 
287 
288 ngx_int_t
ngx_rtmp_send_set_buflen(ngx_rtmp_session_t * s,uint32_t msid,uint32_t buflen_msec)289 ngx_rtmp_send_set_buflen(ngx_rtmp_session_t *s, uint32_t msid,
290         uint32_t buflen_msec)
291 {
292     return ngx_rtmp_send_shared_packet(s,
293            ngx_rtmp_create_set_buflen(s, msid, buflen_msec));
294 }
295 
296 
297 ngx_chain_t *
ngx_rtmp_create_recorded(ngx_rtmp_session_t * s,uint32_t msid)298 ngx_rtmp_create_recorded(ngx_rtmp_session_t *s, uint32_t msid)
299 {
300     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
301                    "create: recorded msid=%uD", msid);
302 
303     {
304         NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_RECORDED);
305 
306         NGX_RTMP_USER_OUT4(msid);
307 
308         NGX_RTMP_USER_END(s);
309     }
310 }
311 
312 
313 ngx_int_t
ngx_rtmp_send_recorded(ngx_rtmp_session_t * s,uint32_t msid)314 ngx_rtmp_send_recorded(ngx_rtmp_session_t *s, uint32_t msid)
315 {
316     return ngx_rtmp_send_shared_packet(s,
317            ngx_rtmp_create_recorded(s, msid));
318 }
319 
320 
321 ngx_chain_t *
ngx_rtmp_create_ping_request(ngx_rtmp_session_t * s,uint32_t timestamp)322 ngx_rtmp_create_ping_request(ngx_rtmp_session_t *s, uint32_t timestamp)
323 {
324     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
325                    "create: ping_request timestamp=%uD", timestamp);
326 
327     {
328         NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_PING_REQUEST);
329 
330         NGX_RTMP_USER_OUT4(timestamp);
331 
332         NGX_RTMP_USER_END(s);
333     }
334 }
335 
336 
337 ngx_int_t
ngx_rtmp_send_ping_request(ngx_rtmp_session_t * s,uint32_t timestamp)338 ngx_rtmp_send_ping_request(ngx_rtmp_session_t *s, uint32_t timestamp)
339 {
340     return ngx_rtmp_send_shared_packet(s,
341            ngx_rtmp_create_ping_request(s, timestamp));
342 }
343 
344 
345 ngx_chain_t *
ngx_rtmp_create_ping_response(ngx_rtmp_session_t * s,uint32_t timestamp)346 ngx_rtmp_create_ping_response(ngx_rtmp_session_t *s, uint32_t timestamp)
347 {
348     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
349                    "create: ping_response timestamp=%uD", timestamp);
350 
351     {
352         NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_PING_RESPONSE);
353 
354         NGX_RTMP_USER_OUT4(timestamp);
355 
356         NGX_RTMP_USER_END(s);
357     }
358 }
359 
360 
361 ngx_int_t
ngx_rtmp_send_ping_response(ngx_rtmp_session_t * s,uint32_t timestamp)362 ngx_rtmp_send_ping_response(ngx_rtmp_session_t *s, uint32_t timestamp)
363 {
364     return ngx_rtmp_send_shared_packet(s,
365            ngx_rtmp_create_ping_response(s, timestamp));
366 }
367 
368 
369 static ngx_chain_t *
ngx_rtmp_alloc_amf_buf(void * arg)370 ngx_rtmp_alloc_amf_buf(void *arg)
371 {
372     return ngx_rtmp_alloc_shared_buf((ngx_rtmp_core_srv_conf_t *)arg);
373 }
374 
375 
376 /* AMF sender */
377 
378 /* NOTE: this function does not free shared bufs on error */
379 ngx_int_t
ngx_rtmp_append_amf(ngx_rtmp_session_t * s,ngx_chain_t ** first,ngx_chain_t ** last,ngx_rtmp_amf_elt_t * elts,size_t nelts)380 ngx_rtmp_append_amf(ngx_rtmp_session_t *s,
381                     ngx_chain_t **first, ngx_chain_t **last,
382                     ngx_rtmp_amf_elt_t *elts, size_t nelts)
383 {
384     ngx_rtmp_amf_ctx_t          act;
385     ngx_rtmp_core_srv_conf_t   *cscf;
386     ngx_int_t                   rc;
387 
388     cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
389 
390     memset(&act, 0, sizeof(act));
391     act.arg = cscf;
392     act.alloc = ngx_rtmp_alloc_amf_buf;
393     act.log = s->connection->log;
394 
395     if (first) {
396         act.first = *first;
397     }
398 
399     if (last) {
400         act.link = *last;
401     }
402 
403     rc = ngx_rtmp_amf_write(&act, elts, nelts);
404 
405     if (first) {
406         *first = act.first;
407     }
408 
409     if (last) {
410         *last = act.link;
411     }
412 
413     return rc;
414 }
415 
416 
417 ngx_chain_t *
ngx_rtmp_create_amf(ngx_rtmp_session_t * s,ngx_rtmp_header_t * h,ngx_rtmp_amf_elt_t * elts,size_t nelts)418 ngx_rtmp_create_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
419                     ngx_rtmp_amf_elt_t *elts, size_t nelts)
420 {
421     ngx_chain_t                *first;
422     ngx_int_t                   rc;
423     ngx_rtmp_core_srv_conf_t   *cscf;
424 
425     ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
426                    "create: amf nelts=%ui", nelts);
427 
428     cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
429 
430     first = NULL;
431 
432     rc = ngx_rtmp_append_amf(s, &first, NULL, elts, nelts);
433 
434     if (rc != NGX_OK && first) {
435         ngx_rtmp_free_shared_chain(cscf, first);
436         first = NULL;
437     }
438 
439     if (first) {
440         ngx_rtmp_prepare_message(s, h, NULL, first);
441     }
442 
443     return first;
444 }
445 
446 
447 ngx_int_t
ngx_rtmp_send_amf(ngx_rtmp_session_t * s,ngx_rtmp_header_t * h,ngx_rtmp_amf_elt_t * elts,size_t nelts)448 ngx_rtmp_send_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
449                   ngx_rtmp_amf_elt_t *elts, size_t nelts)
450 {
451     return ngx_rtmp_send_shared_packet(s,
452            ngx_rtmp_create_amf(s, h, elts, nelts));
453 }
454 
455 
456 ngx_chain_t *
ngx_rtmp_create_status(ngx_rtmp_session_t * s,char * code,char * level,char * desc)457 ngx_rtmp_create_status(ngx_rtmp_session_t *s, char *code, char* level,
458                        char *desc)
459 {
460     ngx_rtmp_header_t               h;
461     static double                   trans;
462 
463     static ngx_rtmp_amf_elt_t       out_inf[] = {
464 
465         { NGX_RTMP_AMF_STRING,
466           ngx_string("level"),
467           NULL, 0 },
468 
469         { NGX_RTMP_AMF_STRING,
470           ngx_string("code"),
471           NULL, 0 },
472 
473         { NGX_RTMP_AMF_STRING,
474           ngx_string("description"),
475           NULL, 0 },
476     };
477 
478     static ngx_rtmp_amf_elt_t       out_elts[] = {
479 
480         { NGX_RTMP_AMF_STRING,
481           ngx_null_string,
482           "onStatus", 0 },
483 
484         { NGX_RTMP_AMF_NUMBER,
485           ngx_null_string,
486           &trans, 0 },
487 
488         { NGX_RTMP_AMF_NULL,
489           ngx_null_string,
490           NULL, 0 },
491 
492         { NGX_RTMP_AMF_OBJECT,
493           ngx_null_string,
494           out_inf,
495           sizeof(out_inf) },
496     };
497 
498     ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
499                    "create: status code='%s' level='%s' desc='%s'",
500                    code, level, desc);
501 
502     out_inf[0].data = level;
503     out_inf[1].data = code;
504     out_inf[2].data = desc;
505     trans = 0;
506 
507     memset(&h, 0, sizeof(h));
508 
509     h.type = NGX_RTMP_MSG_AMF_CMD;
510     h.csid = NGX_RTMP_CSID_AMF;
511     h.msid = NGX_RTMP_MSID;
512 
513     return ngx_rtmp_create_amf(s, &h, out_elts,
514                                sizeof(out_elts) / sizeof(out_elts[0]));
515 }
516 
517 
518 ngx_int_t
ngx_rtmp_send_status(ngx_rtmp_session_t * s,char * code,char * level,char * desc)519 ngx_rtmp_send_status(ngx_rtmp_session_t *s, char *code, char* level, char *desc)
520 {
521     return ngx_rtmp_send_shared_packet(s,
522            ngx_rtmp_create_status(s, code, level, desc));
523 }
524 
525 
526 ngx_chain_t *
ngx_rtmp_create_play_status(ngx_rtmp_session_t * s,char * code,char * level,ngx_uint_t duration,ngx_uint_t bytes)527 ngx_rtmp_create_play_status(ngx_rtmp_session_t *s, char *code, char* level,
528                             ngx_uint_t duration, ngx_uint_t bytes)
529 {
530     ngx_rtmp_header_t               h;
531     static double                   dduration;
532     static double                   dbytes;
533 
534     static ngx_rtmp_amf_elt_t       out_inf[] = {
535 
536         { NGX_RTMP_AMF_STRING,
537           ngx_string("code"),
538           NULL, 0 },
539 
540         { NGX_RTMP_AMF_STRING,
541           ngx_string("level"),
542           NULL, 0 },
543 
544         { NGX_RTMP_AMF_NUMBER,
545           ngx_string("duration"),
546           &dduration, 0 },
547 
548         { NGX_RTMP_AMF_NUMBER,
549           ngx_string("bytes"),
550           &dbytes, 0 },
551     };
552 
553     static ngx_rtmp_amf_elt_t       out_elts[] = {
554 
555         { NGX_RTMP_AMF_STRING,
556           ngx_null_string,
557           "onPlayStatus", 0 },
558 
559         { NGX_RTMP_AMF_OBJECT,
560           ngx_null_string,
561           out_inf,
562           sizeof(out_inf) },
563     };
564 
565     ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
566                    "create: play_status code='%s' level='%s' "
567                    "duration=%ui bytes=%ui",
568                    code, level, duration, bytes);
569 
570     out_inf[0].data = code;
571     out_inf[1].data = level;
572 
573     dduration = duration;
574     dbytes = bytes;
575 
576     memset(&h, 0, sizeof(h));
577 
578     h.type = NGX_RTMP_MSG_AMF_META;
579     h.csid = NGX_RTMP_CSID_AMF;
580     h.msid = NGX_RTMP_MSID;
581     h.timestamp = duration;
582 
583     return ngx_rtmp_create_amf(s, &h, out_elts,
584                                sizeof(out_elts) / sizeof(out_elts[0]));
585 }
586 
587 
588 ngx_int_t
ngx_rtmp_send_play_status(ngx_rtmp_session_t * s,char * code,char * level,ngx_uint_t duration,ngx_uint_t bytes)589 ngx_rtmp_send_play_status(ngx_rtmp_session_t *s, char *code, char* level,
590                           ngx_uint_t duration, ngx_uint_t bytes)
591 {
592     return ngx_rtmp_send_shared_packet(s,
593            ngx_rtmp_create_play_status(s, code, level, duration, bytes));
594 }
595 
596 
597 // ----------- Based on Adobe FMS 3 application.redirectConnection description --------- //
598 
599 ngx_chain_t *
ngx_rtmp_create_redirect_status(ngx_rtmp_session_t * s,char * callMethod,char * desc,ngx_str_t to_url)600 ngx_rtmp_create_redirect_status(ngx_rtmp_session_t *s, char *callMethod, char *desc, ngx_str_t to_url)
601 {
602     ngx_rtmp_header_t               h;
603     static double                   dtrans;
604     static double                   dcode;
605 
606     ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0,
607                    "create redirect status: got data");
608 
609     ngx_log_debug5(NGX_LOG_DEBUG, s->connection->log, 0,
610                    "create redirect status: method='%s', status code='%s' level='%s' "
611                    "ex.code=%ui ex.redirect='%s'", callMethod,
612                    "NetConnection.Connect.Rejected", "error", 302, to_url.data);
613 
614     static ngx_rtmp_amf_elt_t       out_inf_ex_data[] = {
615 
616         { NGX_RTMP_AMF_NUMBER,
617           ngx_string("code"),
618           &dcode, 0 },
619 
620         { NGX_RTMP_AMF_STRING,
621           ngx_string("redirect"),
622           NULL, 0 },
623     };
624 
625     static ngx_rtmp_amf_elt_t       out_inf[] = {
626 
627         { NGX_RTMP_AMF_STRING,
628           ngx_string("level"),
629           "error", 0 },
630 
631         { NGX_RTMP_AMF_STRING,
632           ngx_string("code"),
633           "NetConnection.Connect.Rejected", 0 },
634 
635         { NGX_RTMP_AMF_STRING,
636           ngx_string("description"),
637           NULL, 0 },
638 
639         { NGX_RTMP_AMF_OBJECT,
640           ngx_string("ex"),
641           out_inf_ex_data,
642           sizeof(out_inf_ex_data) },
643     };
644 
645     static ngx_rtmp_amf_elt_t       out_elts[] = {
646 
647         { NGX_RTMP_AMF_STRING,
648           ngx_null_string,
649           NULL, 0 },
650 
651         { NGX_RTMP_AMF_NUMBER,
652           ngx_null_string,
653           &dtrans, 0 },
654 
655         { NGX_RTMP_AMF_NULL,
656           ngx_null_string,
657           NULL, 0 },
658 
659         { NGX_RTMP_AMF_OBJECT,
660           ngx_null_string,
661           out_inf,
662           sizeof(out_inf) },
663     };
664 
665     ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0,
666                    "create redirect status: set structure data");
667 
668     out_elts[0].data = callMethod;
669     out_inf[2].data = desc;
670     dcode = 302;
671     dtrans = 0;
672     out_inf_ex_data[1].data = to_url.data;
673 
674     ngx_memzero(&h, sizeof(h));
675 
676     h.type = NGX_RTMP_MSG_AMF_CMD;
677     h.csid = NGX_RTMP_CSID_AMF;
678     h.msid = NGX_RTMP_MSID;
679 
680     return ngx_rtmp_create_amf(s, &h, out_elts,
681                                sizeof(out_elts) / sizeof(out_elts[0]));
682 }
683 
684 
685 ngx_int_t
ngx_rtmp_send_redirect_status(ngx_rtmp_session_t * s,char * callMethod,char * desc,ngx_str_t to_url)686 ngx_rtmp_send_redirect_status(ngx_rtmp_session_t *s,
687                           char *callMethod, char *desc, ngx_str_t to_url)
688 {
689     return ngx_rtmp_send_shared_packet(s,
690            ngx_rtmp_create_redirect_status(s, callMethod, desc, to_url));
691 }
692 
693 
694 ngx_chain_t *
ngx_rtmp_create_close_method(ngx_rtmp_session_t * s,char * methodName)695 ngx_rtmp_create_close_method(ngx_rtmp_session_t *s, char *methodName)
696 {
697     ngx_rtmp_header_t               h;
698     static double                   dtrans;
699 
700     static ngx_rtmp_amf_elt_t       out_elts[] = {
701 
702         { NGX_RTMP_AMF_STRING,
703           ngx_null_string,
704           NULL, 0 },
705 
706         { NGX_RTMP_AMF_NUMBER,
707           ngx_null_string,
708           &dtrans, 0 },
709     };
710 
711     ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0,
712                    "create close method: set structure data");
713 
714     out_elts[0].data = methodName;
715     dtrans = 0;
716 
717     ngx_memzero(&h, sizeof(h));
718 
719     h.type = NGX_RTMP_MSG_AMF_CMD;
720     h.csid = NGX_RTMP_CSID_AMF;
721     h.msid = NGX_RTMP_MSID;
722 
723     return ngx_rtmp_create_amf(s, &h, out_elts,
724                                sizeof(out_elts) / sizeof(out_elts[0]));
725 }
726 
727 
728 ngx_int_t
ngx_rtmp_send_close_method(ngx_rtmp_session_t * s,char * methodName)729 ngx_rtmp_send_close_method(ngx_rtmp_session_t *s, char *methodName)
730 {
731     return ngx_rtmp_send_shared_packet(s,
732            ngx_rtmp_create_close_method(s, methodName));
733 }
734 
735 
736 ngx_chain_t *
ngx_rtmp_create_fcpublish(ngx_rtmp_session_t * s,u_char * desc)737 ngx_rtmp_create_fcpublish(ngx_rtmp_session_t *s, u_char *desc)
738 {
739     ngx_rtmp_header_t               h;
740     static double                   trans;
741 
742     static ngx_rtmp_amf_elt_t       out_inf[] = {
743 
744         { NGX_RTMP_AMF_STRING,
745           ngx_string("level"),
746           "status", 0 },
747 
748         { NGX_RTMP_AMF_STRING,
749           ngx_string("code"),
750           "NetStream.Publish.Start", 0 },
751 
752         { NGX_RTMP_AMF_STRING,
753           ngx_string("description"),
754           NULL, 0 },
755     };
756 
757     static ngx_rtmp_amf_elt_t       out_elts[] = {
758 
759         { NGX_RTMP_AMF_STRING,
760           ngx_null_string,
761           "onFCPublish", 0 },
762 
763         { NGX_RTMP_AMF_NUMBER,
764           ngx_null_string,
765           &trans, 0 },
766 
767         { NGX_RTMP_AMF_NULL,
768           ngx_null_string,
769           NULL, 0 },
770 
771         { NGX_RTMP_AMF_OBJECT,
772           ngx_null_string,
773           out_inf,
774           sizeof(out_inf) },
775     };
776 
777     ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0,
778                    "create: fcpublish - set structure data");
779 
780     out_inf[2].data = desc;
781 //    trans = 3.0;                // magick from ffmpeg
782     trans = 0;
783 
784     memset(&h, 0, sizeof(h));
785 
786     h.type = NGX_RTMP_MSG_AMF_CMD;
787     h.csid = NGX_RTMP_CSID_AMF;
788     h.msid = NGX_RTMP_MSID;
789 
790     return ngx_rtmp_create_amf(s, &h, out_elts,
791                                sizeof(out_elts) / sizeof(out_elts[0]));
792 }
793 
794 
795 ngx_int_t
ngx_rtmp_send_fcpublish(ngx_rtmp_session_t * s,u_char * desc)796 ngx_rtmp_send_fcpublish(ngx_rtmp_session_t *s, u_char *desc)
797 {
798     return ngx_rtmp_send_shared_packet(s,
799            ngx_rtmp_create_fcpublish(s, desc));
800 }
801 
802 
803 ngx_chain_t *
ngx_rtmp_create_fcunpublish(ngx_rtmp_session_t * s,u_char * desc)804 ngx_rtmp_create_fcunpublish(ngx_rtmp_session_t *s, u_char *desc)
805 {
806     ngx_rtmp_header_t               h;
807     static double                   trans;
808 
809     static ngx_rtmp_amf_elt_t       out_inf[] = {
810 
811         { NGX_RTMP_AMF_STRING,
812           ngx_string("level"),
813           "status", 0 },
814 
815         { NGX_RTMP_AMF_STRING,
816           ngx_string("code"),
817           "NetStream.Unpublish.Success", 0 },
818 
819         { NGX_RTMP_AMF_STRING,
820           ngx_string("description"),
821           NULL, 0 },
822     };
823 
824     static ngx_rtmp_amf_elt_t       out_elts[] = {
825 
826         { NGX_RTMP_AMF_STRING,
827           ngx_null_string,
828           "onFCUnpublish", 0 },
829 
830         { NGX_RTMP_AMF_NUMBER,
831           ngx_null_string,
832           &trans, 0 },
833 
834         { NGX_RTMP_AMF_NULL,
835           ngx_null_string,
836           NULL, 0 },
837 
838         { NGX_RTMP_AMF_OBJECT,
839           ngx_null_string,
840           out_inf,
841           sizeof(out_inf) },
842     };
843 
844     ngx_log_debug0(NGX_LOG_DEBUG, s->connection->log, 0,
845                    "create: fcunpublish - set structure data");
846 
847     out_inf[2].data = desc;
848 //    trans = 5.0;                // magick from ffmpeg
849     trans = 0;
850 
851     memset(&h, 0, sizeof(h));
852 
853     h.type = NGX_RTMP_MSG_AMF_CMD;
854     h.csid = NGX_RTMP_CSID_AMF;
855     h.msid = NGX_RTMP_MSID;
856 
857     return ngx_rtmp_create_amf(s, &h, out_elts,
858                                sizeof(out_elts) / sizeof(out_elts[0]));
859 }
860 
861 
862 ngx_int_t
ngx_rtmp_send_fcunpublish(ngx_rtmp_session_t * s,u_char * desc)863 ngx_rtmp_send_fcunpublish(ngx_rtmp_session_t *s, u_char *desc)
864 {
865     return ngx_rtmp_send_shared_packet(s,
866            ngx_rtmp_create_fcunpublish(s, desc));
867 }
868 
869 
870 ngx_chain_t *
ngx_rtmp_create_fi(ngx_rtmp_session_t * s)871 ngx_rtmp_create_fi(ngx_rtmp_session_t *s)
872 {
873     ngx_rtmp_header_t               h;
874     static double                   trans;
875 
876     struct tm                       tm;
877     struct timeval                  tv;
878 
879     static u_char                   buf_time[NGX_TIME_T_LEN*2 + 1];
880     static u_char                   buf_date[NGX_TIME_T_LEN + 1];
881 
882 
883     static ngx_rtmp_amf_elt_t       out_inf[] = {
884 
885         { NGX_RTMP_AMF_STRING,
886           ngx_string("st"),
887           NULL, 0 },
888 
889         { NGX_RTMP_AMF_STRING,
890           ngx_string("sd"),
891           NULL, 0 },
892     };
893 
894     static ngx_rtmp_amf_elt_t       out_elts[] = {
895 
896         { NGX_RTMP_AMF_STRING,
897           ngx_null_string,
898           "onFI", 0 },
899 
900         { NGX_RTMP_AMF_NUMBER,
901           ngx_null_string,
902           &trans, 0 },
903 
904         { NGX_RTMP_AMF_NULL,
905           ngx_null_string,
906           NULL, 0 },
907 
908         { NGX_RTMP_AMF_OBJECT,
909           ngx_null_string,
910           out_inf,
911           sizeof(out_inf) },
912     };
913 
914     trans = 0;
915 
916     ngx_gettimeofday(&tv);
917 
918     ngx_libc_localtime((time_t)tv.tv_sec, &tm);
919 
920     ngx_memzero(buf_time, sizeof(buf_time));
921     ngx_memzero(buf_date, sizeof(buf_date));
922 
923     ngx_sprintf(buf_time, "%02d:%02d:%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, (int)tv.tv_usec);
924     // Strange order, but FMLE send like this
925     ngx_sprintf(buf_date, "%02d-%02d-%04d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
926 
927     out_inf[0].data = buf_time;
928     out_inf[1].data = buf_date;
929 
930     memset(&h, 0, sizeof(h));
931 
932     h.type = NGX_RTMP_MSG_AMF_CMD;
933     h.csid = NGX_RTMP_CSID_AMF;
934     h.msid = NGX_RTMP_MSID;
935 
936     return ngx_rtmp_create_amf(s, &h, out_elts,
937                                sizeof(out_elts) / sizeof(out_elts[0]));
938 }
939 
940 
941 ngx_int_t
ngx_rtmp_send_fi(ngx_rtmp_session_t * s)942 ngx_rtmp_send_fi(ngx_rtmp_session_t *s)
943 {
944     return ngx_rtmp_send_shared_packet(s,
945            ngx_rtmp_create_fi(s));
946 }
947 
948 
949 ngx_chain_t *
ngx_rtmp_create_sample_access(ngx_rtmp_session_t * s)950 ngx_rtmp_create_sample_access(ngx_rtmp_session_t *s)
951 {
952     ngx_rtmp_header_t               h;
953 
954     static int                      access = 1;
955 
956     static ngx_rtmp_amf_elt_t       access_elts[] = {
957 
958         { NGX_RTMP_AMF_STRING,
959           ngx_null_string,
960           "|RtmpSampleAccess", 0 },
961 
962         { NGX_RTMP_AMF_BOOLEAN,
963           ngx_null_string,
964           &access, 0 },
965 
966         { NGX_RTMP_AMF_BOOLEAN,
967           ngx_null_string,
968           &access, 0 },
969     };
970 
971     memset(&h, 0, sizeof(h));
972 
973     h.type = NGX_RTMP_MSG_AMF_META;
974     h.csid = NGX_RTMP_CSID_AMF;
975     h.msid = NGX_RTMP_MSID;
976 
977     return ngx_rtmp_create_amf(s, &h, access_elts,
978                                sizeof(access_elts) / sizeof(access_elts[0]));
979 }
980 
981 
982 ngx_int_t
ngx_rtmp_send_sample_access(ngx_rtmp_session_t * s)983 ngx_rtmp_send_sample_access(ngx_rtmp_session_t *s)
984 {
985     return ngx_rtmp_send_shared_packet(s,
986            ngx_rtmp_create_sample_access(s));
987 }
988