ngx_int_t ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) { ngx_rtmp_record_rec_ctx_t *rctx; ngx_int_t rc; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: #%ui manual close", n); rctx = ngx_rtmp_record_get_node_ctx(s, n); if (rctx == NULL) { return NGX_ERROR; } rc = ngx_rtmp_record_node_close(s, rctx); if (rc != NGX_OK) { return rc; } if (path) { ngx_rtmp_record_make_path(s, rctx, path); } return NGX_OK; }
static ngx_int_t ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx) { ngx_rtmp_record_app_conf_t *rracf; ngx_err_t err; void **app_conf; ngx_int_t rc; ngx_rtmp_record_done_t v; rracf = rctx->conf; if (rctx->file.fd == NGX_INVALID_FILE) { return NGX_AGAIN; } if (ngx_close_file(rctx->file.fd) == NGX_FILE_ERROR) { err = ngx_errno; ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, "record: %V error closing file", &rracf->id); ngx_rtmp_record_notify_error(s, rctx); } rctx->file.fd = NGX_INVALID_FILE; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V closed", &rracf->id); if (rracf->notify) { ngx_rtmp_send_status(s, "NetStream.Record.Stop", "status", rracf->id.data ? (char *) rracf->id.data : ""); } app_conf = s->app_conf; if (rracf->rec_conf) { s->app_conf = rracf->rec_conf; } v.recorder = rracf->id; ngx_rtmp_record_make_path(s, rctx, &v.path); rc = ngx_rtmp_record_done(s, &v); s->app_conf = app_conf; return rc; }
static ngx_int_t ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, ngx_rtmp_record_node_ctx_t *rctx) { ngx_rtmp_record_node_t *rc; ngx_err_t err; u_char *path; rc = rctx->conf; if (rctx->file.fd != NGX_INVALID_FILE) { return NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V opening", &rc->id); rctx->timestamp = ngx_cached_time->sec; path = ngx_rtmp_record_make_path(s, rctx); rctx->nframes = 0; ngx_memzero(&rctx->file, sizeof(rctx->file)); rctx->last = *ngx_cached_time; rctx->file.offset = 0; rctx->file.log = s->connection->log; rctx->file.fd = ngx_open_file(path, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); if (rctx->file.fd == NGX_INVALID_FILE) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, "record: %V failed to open file '%s'", &rc->id, path); } return NGX_OK; } ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V opened '%s'", &rc->id, path); return NGX_OK; }
static ngx_int_t ngx_rtmp_record_open(ngx_rtmp_session_t *s) { ngx_rtmp_record_ctx_t *ctx; ngx_err_t err; u_char *path; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); if (ctx == NULL || ctx->file.fd != NGX_INVALID_FILE) { return NGX_ERROR; } ctx->timestamp = ngx_cached_time->sec; path = ngx_rtmp_record_make_path(s); ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: path '%s'", path); /* open file */ ctx->nframes = 0; ngx_memzero(&ctx->file, sizeof(ctx->file)); ctx->file.offset = 0; ctx->file.log = s->connection->log; ctx->file.fd = ngx_open_file(path, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); ctx->last = *ngx_cached_time; if (ctx->file.fd == NGX_INVALID_FILE) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, "record: failed to open file '%s'", path); } return NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: opened '%s'", path); return NGX_OK; }
ngx_int_t ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, u_char **path) { ngx_rtmp_record_node_ctx_t *rctx; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: #%ui manual open", n); rctx = ngx_rtmp_record_get_node_ctx(s, n); if (rctx == NULL) { return NGX_ERROR; } if (ngx_rtmp_record_node_open(s, rctx) != NGX_OK) { return NGX_ERROR; } if (path) { *path = ngx_rtmp_record_make_path(s, rctx); } return NGX_OK; }
static ngx_int_t ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx) { ngx_rtmp_record_app_conf_t *rracf; ngx_rtmp_core_srv_conf_t *cscf; ngx_err_t err; ngx_str_t path; ngx_int_t mode, create_mode; u_char buf[8], *p; off_t file_size; uint32_t tag_size, mlen, timestamp; rracf = rctx->conf; tag_size = 0; if (rctx->file.fd != NGX_INVALID_FILE) { return NGX_AGAIN; } cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V opening", &rracf->id); ngx_memzero(rctx, sizeof(*rctx)); rctx->conf = rracf; rctx->last = *ngx_cached_time; rctx->timestamp = ngx_cached_time->sec; ngx_rtmp_record_make_path(s, rctx, &path); mode = rracf->append ? NGX_FILE_RDWR : NGX_FILE_WRONLY; create_mode = rracf->append ? NGX_FILE_CREATE_OR_OPEN : NGX_FILE_TRUNCATE; ngx_memzero(&rctx->file, sizeof(rctx->file)); rctx->file.offset = 0; rctx->file.log = s->connection->log; rctx->file.fd = ngx_open_file(path.data, mode, create_mode, cscf->file_access); ngx_str_set(&rctx->file.name, "recorded"); if (rctx->file.fd == NGX_INVALID_FILE) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, "record: %V failed to open file '%V'", &rracf->id, &path); } ngx_rtmp_record_notify_error(s, rctx); return NGX_OK; } #if !(NGX_WIN32) if (rracf->lock_file) { err = ngx_lock_fd(rctx->file.fd); if (err) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, "record: %V lock failed", &rracf->id); } } #endif ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V opened '%V'", &rracf->id, &path); if (rracf->notify) { ngx_rtmp_send_status(s, "NetStream.Record.Start", "status", rracf->id.data ? (char *) rracf->id.data : ""); } if (rracf->append) { file_size = 0; timestamp = 0; #if (NGX_WIN32) { LONG lo, hi; lo = 0; hi = 0; lo = SetFilePointer(rctx->file.fd, lo, &hi, FILE_END); file_size = (lo == INVALID_SET_FILE_POINTER ? (off_t) -1 : (off_t) hi << 32 | (off_t) lo); } #else file_size = lseek(rctx->file.fd, 0, SEEK_END); #endif if (file_size == (off_t) -1) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, "record: %V seek failed", &rracf->id); goto done; } if (file_size < 4) { goto done; } if (ngx_read_file(&rctx->file, buf, 4, file_size - 4) != 4) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, "record: %V tag size read failed", &rracf->id); goto done; } p = (u_char *) &tag_size; p[0] = buf[3]; p[1] = buf[2]; p[2] = buf[1]; p[3] = buf[0]; if (tag_size == 0 || tag_size + 4 > file_size) { file_size = 0; goto done; } if (ngx_read_file(&rctx->file, buf, 8, file_size - tag_size - 4) != 8) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, "record: %V tag read failed", &rracf->id); goto done; } p = (u_char *) &mlen; p[0] = buf[3]; p[1] = buf[2]; p[2] = buf[1]; p[3] = 0; if (tag_size != mlen + 11) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, "record: %V tag size mismatch: " "tag_size=%uD, mlen=%uD", &rracf->id, tag_size, mlen); goto done; } p = (u_char *) ×tamp; p[3] = buf[7]; p[0] = buf[6]; p[1] = buf[5]; p[2] = buf[4]; done: rctx->file.offset = file_size; rctx->time_shift = timestamp; ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: append offset=%O, time=%uD, tag_size=%uD", file_size, timestamp, tag_size); } return NGX_OK; }
static ngx_chain_t * ngx_rtmp_record_notify_create(ngx_rtmp_session_t *s, void *arg, ngx_pool_t *pool) { ngx_rtmp_record_app_conf_t *racf; ngx_rtmp_record_ctx_t *ctx; ngx_chain_t *hl, *cl, *pl; ngx_buf_t *b; ngx_str_t *addr_text; size_t path_len, name_len, args_len; u_char *path; racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); if (ctx == NULL) { return NULL; } /* common variables */ cl = ngx_rtmp_netcall_http_format_session(s, pool); if (cl == NULL) { return NULL; } /* publish variables */ pl = ngx_alloc_chain_link(pool); if (pl == NULL) { return NULL; } path = ngx_rtmp_record_make_path(s); path_len = ngx_strlen(path); name_len = ngx_strlen(ctx->name); args_len = ngx_strlen(ctx->args); addr_text = &s->connection->addr_text; b = ngx_create_temp_buf(pool, sizeof("&call=record_done") + sizeof("&addr=") + addr_text->len + sizeof("&name=") + name_len * 3 + sizeof("&path=") + path_len * 3 + + 1 + args_len); if (b == NULL) { return NULL; } pl->buf = b; b->last = ngx_cpymem(b->last, (u_char*)"&call=record_done", sizeof("&call=record_done") - 1); b->last = ngx_cpymem(b->last, (u_char*)"&addr=", sizeof("&addr=") -1); b->last = (u_char*)ngx_escape_uri(b->last, addr_text->data, addr_text->len, 0); b->last = ngx_cpymem(b->last, (u_char*)"&name=", sizeof("&name=") - 1); b->last = (u_char*)ngx_escape_uri(b->last, ctx->name, name_len, 0); b->last = ngx_cpymem(b->last, (u_char*)"&path=", sizeof("&path=") - 1); b->last = (u_char*)ngx_escape_uri(b->last, path, path_len, 0); if (args_len) { *b->last++ = '&'; b->last = (u_char *)ngx_cpymem(b->last, ctx->args, args_len); } /* HTTP header */ hl = ngx_rtmp_netcall_http_format_header(racf->url, pool, cl->buf->last - cl->buf->pos + (pl->buf->last - pl->buf->pos), &ngx_rtmp_netcall_content_type_urlencoded); if (hl == NULL) { return NULL; } hl->next = cl; cl->next = pl; pl->next = NULL; return hl; }
static ngx_int_t ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx) { ngx_rtmp_record_app_conf_t *rracf; ngx_err_t err; ngx_str_t path; rracf = rctx->conf; if (rctx->file.fd != NGX_INVALID_FILE) { return NGX_AGAIN; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V opening", &rracf->id); ngx_memzero(rctx, sizeof(*rctx)); rctx->conf = rracf; rctx->last = *ngx_cached_time; rctx->timestamp = ngx_cached_time->sec; ngx_rtmp_record_make_path(s, rctx, &path); ngx_memzero(&rctx->file, sizeof(rctx->file)); rctx->file.offset = 0; rctx->file.log = s->connection->log; rctx->file.fd = ngx_open_file(path.data, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); if (rctx->file.fd == NGX_INVALID_FILE) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, "record: %V failed to open file '%V'", &rracf->id, &path); } ngx_rtmp_record_notify_error(s, rctx); return NGX_OK; } if (rracf->lock_file) { err = ngx_lock_fd(rctx->file.fd); if (err) { ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, "record: %V lock failed", &rracf->id); } } ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V opened '%V'", &rracf->id, &path); if (rracf->notify) { ngx_rtmp_send_status(s, "NetStream.Record.Start", "status", rracf->id.data ? (char *) rracf->id.data : ""); } return NGX_OK; }