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