nginx-mod-rtmp/ngx_rtmp.h

475 lines
14 KiB
C
Raw Normal View History

2012-03-08 16:21:22 +01:00
/*
* Copyright (c) 2012 Roman Arutyunyan
*/
#ifndef _NGX_RTMP_H_INCLUDED_
#define _NGX_RTMP_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_event_connect.h>
2012-03-29 14:10:11 +02:00
#include "ngx_rtmp_amf.h"
2012-03-13 06:41:51 +01:00
2012-03-08 16:21:22 +01:00
typedef struct {
void **main_conf;
void **srv_conf;
2012-03-23 13:03:32 +01:00
void **app_conf;
2012-03-08 16:21:22 +01:00
} ngx_rtmp_conf_ctx_t;
typedef struct {
u_char sockaddr[NGX_SOCKADDRLEN];
socklen_t socklen;
/* server ctx */
ngx_rtmp_conf_ctx_t *ctx;
unsigned bind:1;
unsigned wildcard:1;
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
unsigned ipv6only:2;
#endif
unsigned so_keepalive:2;
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
int tcp_keepidle;
int tcp_keepintvl;
int tcp_keepcnt;
#endif
} ngx_rtmp_listen_t;
typedef struct {
ngx_rtmp_conf_ctx_t *ctx;
ngx_str_t addr_text;
} ngx_rtmp_addr_conf_t;
typedef struct {
in_addr_t addr;
ngx_rtmp_addr_conf_t conf;
} ngx_rtmp_in_addr_t;
#if (NGX_HAVE_INET6)
typedef struct {
struct in6_addr addr6;
ngx_rtmp_addr_conf_t conf;
} ngx_rtmp_in6_addr_t;
#endif
typedef struct {
void *addrs;
ngx_uint_t naddrs;
} ngx_rtmp_port_t;
typedef struct {
int family;
in_port_t port;
ngx_array_t addrs; /* array of ngx_rtmp_conf_addr_t */
} ngx_rtmp_conf_port_t;
typedef struct {
struct sockaddr *sockaddr;
socklen_t socklen;
ngx_rtmp_conf_ctx_t *ctx;
unsigned bind:1;
unsigned wildcard:1;
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
unsigned ipv6only:2;
#endif
unsigned so_keepalive:2;
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
int tcp_keepidle;
int tcp_keepintvl;
int tcp_keepcnt;
#endif
} ngx_rtmp_conf_addr_t;
2012-03-15 07:23:49 +01:00
#define NGX_RTMP_VERSION 3
#define NGX_LOG_DEBUG_RTMP NGX_LOG_DEBUG_CORE
#define NGX_RTMP_HANDSHAKE_SIZE 1536
#define NGX_RTMP_DEFAULT_CHUNK_SIZE 128
2012-03-15 07:23:49 +01:00
/* RTMP handshake stages */
#define NGX_RTMP_HS_READ_DATA 0
#define NGX_RTMP_HS_WRITE_DATA 1
#define NGX_RTMP_HS_WRITE_ECHO 2
#define NGX_RTMP_HS_READ_ECHO 3
2012-03-15 07:23:49 +01:00
/* RTMP message types */
#define NGX_RTMP_MSG_CHUNK_SIZE 1
#define NGX_RTMP_MSG_ABORT 2
#define NGX_RTMP_MSG_ACK 3
#define NGX_RTMP_MSG_USER 4
#define NGX_RTMP_MSG_ACK_SIZE 5
#define NGX_RTMP_MSG_BANDWIDTH 6
#define NGX_RTMP_MSG_EDGE 7
#define NGX_RTMP_MSG_AUDIO 8
#define NGX_RTMP_MSG_VIDEO 9
#define NGX_RTMP_MSG_AMF3_META 15
#define NGX_RTMP_MSG_AMF3_SHARED 16
#define NGX_RTMP_MSG_AMF3_CMD 17
2012-04-05 19:26:46 +02:00
#define NGX_RTMP_MSG_AMF_META 18
#define NGX_RTMP_MSG_AMF_SHARED 19
#define NGX_RTMP_MSG_AMF_CMD 20
#define NGX_RTMP_MSG_AGGREGATE 22
2012-03-21 16:08:59 +01:00
#define NGX_RTMP_MSG_MAX 22
#define NGX_RTMP_CONNECT NGX_RTMP_MSG_MAX + 1
#define NGX_RTMP_DISCONNECT NGX_RTMP_MSG_MAX + 2
#define NGX_RTMP_MAX_EVENT NGX_RTMP_MSG_MAX + 3
/* RMTP control message types */
#define NGX_RTMP_USER_STREAM_BEGIN 0
#define NGX_RTMP_USER_STREAM_EOF 1
#define NGX_RTMP_USER_STREAM_DRY 2
#define NGX_RTMP_USER_SET_BUFLEN 3
#define NGX_RTMP_USER_RECORDED 4
#define NGX_RTMP_USER_PING_REQUEST 6
#define NGX_RTMP_USER_PING_RESPONSE 7
2012-03-17 23:16:59 +01:00
#define NGX_RTMP_USER_UNKNOWN 8
/* Chunk header:
* max 3 basic header
* + max 11 message header
* + max 4 extended header (timestamp) */
#define NGX_RTMP_MAX_CHUNK_HEADER 18
2012-03-08 16:21:22 +01:00
2012-04-20 07:01:04 +02:00
/* Output buffer queue */
#define NGX_RTMP_OUT_QUEUE 256
2012-04-20 16:03:00 +02:00
#define NGX_RTMP_OUT_QUEUE_LOWAT 32
2012-04-20 07:01:04 +02:00
2012-03-08 16:21:22 +01:00
typedef struct {
uint32_t csid; /* chunk stream id */
2012-03-15 07:23:49 +01:00
uint32_t timestamp; /* timestamp (delta) */
uint32_t mlen; /* message length */
uint8_t type; /* message type id */
uint32_t msid; /* message stream id */
} ngx_rtmp_header_t;
2012-03-08 16:21:22 +01:00
typedef struct {
ngx_rtmp_header_t hdr;
2012-04-26 12:13:07 +02:00
uint32_t dtime;
uint32_t len; /* current fragment length */
2012-03-11 17:17:17 +01:00
ngx_chain_t *in;
} ngx_rtmp_stream_t;
typedef struct {
uint32_t signature; /* "RTMP" */ /* <-- FIXME wtf */
2012-03-08 16:21:22 +01:00
2012-04-07 23:44:57 +02:00
ngx_event_t close;
2012-03-08 16:21:22 +01:00
void **ctx;
void **main_conf;
void **srv_conf;
2012-03-23 13:03:32 +01:00
void **app_conf;
2012-03-08 16:21:22 +01:00
2012-03-08 18:45:10 +01:00
ngx_str_t *addr_text;
2012-03-23 13:03:32 +01:00
int connected;
/* connection parameters */
ngx_str_t app;
ngx_str_t flashver;
ngx_str_t swf_url;
ngx_str_t tc_url;
uint32_t acodecs;
uint32_t vcodecs;
ngx_str_t page_url;
2012-03-08 18:45:10 +01:00
/* TODO: allocate this bufs from shared pool */
ngx_buf_t hs_in_buf;
ngx_buf_t hs_out_buf;
2012-03-08 16:21:22 +01:00
ngx_uint_t hs_stage;
2012-03-15 07:23:49 +01:00
/* connection timestamps */
uint32_t epoch;
uint32_t peer_epoch;
/* input stream 0 (reserved by RTMP spec)
2012-03-15 07:23:49 +01:00
* is used as free chain link */
ngx_rtmp_stream_t *in_streams;
2012-03-11 17:17:17 +01:00
uint32_t in_csid;
ngx_uint_t in_chunk_size;
ngx_pool_t *in_pool;
uint32_t in_bytes;
uint32_t in_last_ack;
2012-03-08 16:21:22 +01:00
2012-04-05 19:28:41 +02:00
ngx_pool_t *in_old_pool;
ngx_int_t in_chunk_size_changing;
2012-04-19 10:31:36 +02:00
ngx_connection_t *connection;
2012-04-18 14:37:18 +02:00
/* circular buffer of RTMP message pointers */
2012-04-19 10:31:36 +02:00
ngx_msec_t timeout;
2012-04-19 07:53:18 +02:00
size_t out_pos, out_last;
2012-04-18 14:37:18 +02:00
ngx_chain_t *out_chain;
u_char *out_bpos;
2012-04-20 16:03:00 +02:00
unsigned out_buffer:1;
2012-04-19 10:31:36 +02:00
ngx_chain_t *out[NGX_RTMP_OUT_QUEUE];
} ngx_rtmp_session_t;
2012-03-08 16:21:22 +01:00
2012-03-08 18:45:10 +01:00
2012-03-21 16:08:59 +01:00
/* handler result code:
* NGX_ERROR - error
* NGX_OK - success, may continue
* NGX_DONE - success, input parsed, reply sent; need no
* more calls on this event */
2012-03-21 16:08:59 +01:00
typedef ngx_int_t (*ngx_rtmp_handler_pt)(ngx_rtmp_session_t *s,
ngx_rtmp_header_t *h, ngx_chain_t *in);
2012-03-21 16:08:59 +01:00
typedef struct {
ngx_str_t name;
ngx_rtmp_handler_pt handler;
2012-03-29 14:10:11 +02:00
} ngx_rtmp_amf_handler_t;
2012-03-08 16:21:22 +01:00
typedef struct {
ngx_array_t servers; /* ngx_rtmp_core_srv_conf_t */
ngx_array_t listen; /* ngx_rtmp_listen_t */
2012-03-21 16:08:59 +01:00
ngx_array_t events[NGX_RTMP_MAX_EVENT];
2012-03-29 14:10:11 +02:00
ngx_hash_t amf_hash;
ngx_array_t amf_arrays;
ngx_array_t amf;
} ngx_rtmp_core_main_conf_t;
2012-03-08 16:21:22 +01:00
typedef struct ngx_rtmp_core_srv_conf_s {
2012-03-23 13:03:32 +01:00
ngx_array_t applications; /* ngx_rtmp_core_app_conf_t */
2012-03-08 16:21:22 +01:00
ngx_msec_t timeout;
ngx_flag_t so_keepalive;
2012-03-11 17:17:17 +01:00
ngx_int_t max_streams;
ngx_uint_t ack_window;
2012-03-18 14:09:19 +01:00
ngx_int_t chunk_size;
ngx_pool_t *pool;
ngx_chain_t *free;
2012-04-18 14:37:18 +02:00
size_t max_queue;
2012-03-21 16:32:18 +01:00
size_t max_message;
ngx_flag_t play_time_fix;
ngx_flag_t publish_time_fix;
ngx_rtmp_conf_ctx_t *ctx;
2012-03-08 16:21:22 +01:00
} ngx_rtmp_core_srv_conf_t;
2012-03-23 13:03:32 +01:00
typedef struct {
ngx_str_t name;
void **app_conf;
} ngx_rtmp_core_app_conf_t;
2012-03-08 16:21:22 +01:00
typedef struct {
ngx_str_t *client;
ngx_rtmp_session_t *session;
} ngx_rtmp_log_ctx_t;
typedef struct {
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
2012-03-08 16:21:22 +01:00
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
2012-03-23 13:03:32 +01:00
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
void *conf);
void *(*create_app_conf)(ngx_conf_t *cf);
char *(*merge_app_conf)(ngx_conf_t *cf, void *prev,
void *conf);
2012-03-08 16:21:22 +01:00
} ngx_rtmp_module_t;
#define NGX_RTMP_MODULE 0x504D5452 /* "RTMP" */
2012-03-08 16:21:22 +01:00
#define NGX_RTMP_MAIN_CONF 0x02000000
#define NGX_RTMP_SRV_CONF 0x04000000
2012-03-23 13:03:32 +01:00
#define NGX_RTMP_APP_CONF 0x08000000
2012-03-08 16:21:22 +01:00
#define NGX_RTMP_MAIN_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, main_conf)
#define NGX_RTMP_SRV_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, srv_conf)
2012-03-23 13:03:32 +01:00
#define NGX_RTMP_APP_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, app_conf)
2012-03-08 16:21:22 +01:00
#define ngx_rtmp_get_module_ctx(s, module) (s)->ctx[module.ctx_index]
#define ngx_rtmp_set_ctx(s, c, module) s->ctx[module.ctx_index] = c;
#define ngx_rtmp_delete_ctx(s, module) s->ctx[module.ctx_index] = NULL;
#define ngx_rtmp_get_module_main_conf(s, module) \
(s)->main_conf[module.ctx_index]
#define ngx_rtmp_get_module_srv_conf(s, module) (s)->srv_conf[module.ctx_index]
2012-03-23 13:03:32 +01:00
#define ngx_rtmp_get_module_app_conf(s, module) ((s)->app_conf ? \
(s)->app_conf[module.ctx_index] : NULL)
2012-03-08 16:21:22 +01:00
#define ngx_rtmp_conf_get_module_main_conf(cf, module) \
((ngx_rtmp_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
#define ngx_rtmp_conf_get_module_srv_conf(cf, module) \
((ngx_rtmp_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index]
#define ngx_rtmp_conf_get_module_app_conf(cf, module) \
((ngx_rtmp_conf_ctx_t *) cf->ctx)->app_conf[module.ctx_index]
2012-03-08 16:21:22 +01:00
#ifdef NGX_DEBUG
char* ngx_rtmp_message_type(uint8_t type);
char* ngx_rtmp_user_message_type(uint16_t evt);
#endif
2012-03-08 16:21:22 +01:00
void ngx_rtmp_init_connection(ngx_connection_t *c);
2012-04-07 23:44:57 +02:00
void ngx_rtmp_finalize_session(ngx_rtmp_session_t *s);
2012-03-08 16:21:22 +01:00
u_char * ngx_rtmp_log_error(ngx_log_t *log, u_char *buf, size_t len);
2012-04-05 19:28:41 +02:00
ngx_int_t ngx_rtmp_set_chunk_size(ngx_rtmp_session_t *s, ngx_uint_t size);
2012-03-08 16:21:22 +01:00
2012-03-20 15:06:19 +01:00
/* Bit reverse: we need big-endians in many places */
void * ngx_rtmp_rmemcpy(void *dst, void* src, size_t n);
#define ngx_rtmp_rcpymem(dst, src, n) \
(((u_char*)ngx_rtmp_rmemcpy(dst, src, n)) + (n))
/* Receiving messages */
2012-03-13 06:41:51 +01:00
ngx_int_t ngx_rtmp_protocol_message_handler(ngx_rtmp_session_t *s,
ngx_rtmp_header_t *h, ngx_chain_t *in);
2012-03-13 06:41:51 +01:00
ngx_int_t ngx_rtmp_user_message_handler(ngx_rtmp_session_t *s,
ngx_rtmp_header_t *h, ngx_chain_t *in);
2012-03-29 14:10:11 +02:00
ngx_int_t ngx_rtmp_amf_message_handler(ngx_rtmp_session_t *s,
ngx_rtmp_header_t *h, ngx_chain_t *in);
ngx_int_t ngx_rtmp_amf_shared_object_handler(ngx_rtmp_session_t *s,
ngx_rtmp_header_t *h, ngx_chain_t *in);
/* Shared output buffers */
2012-04-19 07:53:18 +02:00
/* Store refcount in negative bytes of shared buffer */
#define NGX_RTMP_REFCOUNT_TYPE uint32_t
#define NGX_RTMP_REFCOUNT_BYTES sizeof(NGX_RTMP_REFCOUNT_TYPE)
#define ngx_rtmp_ref(b) \
*((NGX_RTMP_REFCOUNT_TYPE*)(b) - 1)
#define ngx_rtmp_ref_set(b, v) \
ngx_rtmp_ref(b) = v
#define ngx_rtmp_ref_get(b) \
++ngx_rtmp_ref(b)
#define ngx_rtmp_ref_put(b) \
--ngx_rtmp_ref(b)
ngx_chain_t * ngx_rtmp_alloc_shared_buf(ngx_rtmp_core_srv_conf_t *cscf);
2012-04-18 14:37:18 +02:00
void ngx_rtmp_free_shared_chain(ngx_rtmp_core_srv_conf_t *cscf,
ngx_chain_t *in);
ngx_chain_t * ngx_rtmp_append_shared_bufs(ngx_rtmp_core_srv_conf_t *cscf,
ngx_chain_t *head, ngx_chain_t *in);
2012-04-19 07:53:18 +02:00
#define ngx_rtmp_acquire_shared_chain(in) \
ngx_rtmp_ref_get(in); \
/* Sending messages */
2012-03-13 14:51:41 +01:00
void ngx_rtmp_prepare_message(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
ngx_rtmp_header_t *lh, ngx_chain_t *out);
2012-03-18 14:09:19 +01:00
ngx_int_t ngx_rtmp_send_message(ngx_rtmp_session_t *s, ngx_chain_t *out,
ngx_uint_t priority);
/* Note on priorities:
* the bigger value the lower the priority.
* priority=0 is the highest */
2012-04-18 14:37:18 +02:00
#define NGX_RTMP_LIMIT_SOFT 0
#define NGX_RTMP_LIMIT_HARD 1
#define NGX_RTMP_LIMIT_DYNAMIC 2
/* Protocol control messages */
ngx_int_t ngx_rtmp_send_chunk_size(ngx_rtmp_session_t *s,
uint32_t chunk_size);
ngx_int_t ngx_rtmp_send_abort(ngx_rtmp_session_t *s,
uint32_t csid);
ngx_int_t ngx_rtmp_send_ack(ngx_rtmp_session_t *s,
uint32_t seq);
ngx_int_t ngx_rtmp_send_ack_size(ngx_rtmp_session_t *s,
uint32_t ack_size);
2012-03-13 06:41:51 +01:00
ngx_int_t ngx_rtmp_send_bandwidth(ngx_rtmp_session_t *s,
uint32_t ack_size, uint8_t limit_type);
/* User control messages */
ngx_int_t ngx_rtmp_send_user_stream_begin(ngx_rtmp_session_t *s,
uint32_t msid);
ngx_int_t ngx_rtmp_send_user_stream_eof(ngx_rtmp_session_t *s,
uint32_t msid);
ngx_int_t ngx_rtmp_send_user_stream_dry(ngx_rtmp_session_t *s,
uint32_t msid);
ngx_int_t ngx_rtmp_send_user_set_buflen(ngx_rtmp_session_t *s,
uint32_t msid, uint32_t buflen_msec);
ngx_int_t ngx_rtmp_send_user_recorded(ngx_rtmp_session_t *s,
uint32_t msid);
ngx_int_t ngx_rtmp_send_user_ping_request(ngx_rtmp_session_t *s,
uint32_t timestamp);
ngx_int_t ngx_rtmp_send_user_ping_response(ngx_rtmp_session_t *s,
uint32_t timestamp);
2012-03-17 23:16:59 +01:00
ngx_int_t ngx_rtmp_send_user_unknown(ngx_rtmp_session_t *s,
uint32_t timestamp);
2012-03-29 14:10:11 +02:00
/* AMF sender/receiver */
2012-04-06 15:49:30 +02:00
ngx_int_t ngx_rtmp_append_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,
ngx_chain_t **first, ngx_chain_t **last,
ngx_rtmp_amf_elt_t *elts, size_t nelts);
2012-03-29 14:10:11 +02:00
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);
ngx_int_t ngx_rtmp_receive_amf(ngx_rtmp_session_t *s, ngx_chain_t *in,
ngx_rtmp_amf_elt_t *elts, size_t nelts);
2012-04-11 15:07:06 +02:00
/* Frame types */
#define NGX_RTMP_VIDEO_KEY_FRAME 1
#define NGX_RTMP_VIDEO_INTER_FRAME 2
#define NGX_RTMP_VIDEO_DISPOSABLE_FRAME 3
static inline ngx_int_t
ngx_rtmp_get_video_frame_type(ngx_chain_t *in)
{
return (in->buf->pos[0] & 0xf0) >> 4;
}
2012-03-08 16:21:22 +01:00
extern ngx_uint_t ngx_rtmp_max_module;
extern ngx_module_t ngx_rtmp_core_module;
#endif /* _NGX_RTMP_H_INCLUDED_ */