2012-03-08 16:21:22 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2012 Roman Arutyunyan
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ngx_rtmp_amf0.h"
|
2012-03-08 23:39:15 +01:00
|
|
|
#include "ngx_rtmp.h"
|
2012-03-08 16:21:22 +01:00
|
|
|
#include <string.h>
|
2012-03-08 23:39:15 +01:00
|
|
|
|
2012-03-09 22:49:09 +01:00
|
|
|
static inline void*
|
|
|
|
ngx_rtmp_amf0_reverse_copy(void *dst, void* src, size_t len)
|
|
|
|
{
|
|
|
|
size_t k;
|
|
|
|
|
|
|
|
if (dst == NULL || src == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(k = 0; k < len; ++k) {
|
|
|
|
((u_char*)dst)[k] = ((u_char*)src)[len - 1 - k];
|
|
|
|
}
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define NGX_RTMP_AMF0_DEBUG_SIZE 16
|
|
|
|
|
|
|
|
#ifdef NGX_DEBUG
|
|
|
|
static void
|
|
|
|
ngx_rtmp_amf0_debug(const char* op, ngx_log_t *log, u_char *p, size_t n)
|
|
|
|
{
|
|
|
|
u_char hstr[3 * NGX_RTMP_AMF0_DEBUG_SIZE + 1];
|
|
|
|
u_char str[NGX_RTMP_AMF0_DEBUG_SIZE + 1];
|
|
|
|
u_char *hp, *sp;
|
|
|
|
static u_char hex[] = "0123456789ABCDEF";
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
hp = hstr;
|
|
|
|
sp = str;
|
|
|
|
|
|
|
|
for(i = 0; i < n && i < NGX_RTMP_AMF0_DEBUG_SIZE; ++i) {
|
|
|
|
*hp++ = ' ';
|
|
|
|
*hp++ = hex[(*p & 0xf0) >> 4];
|
|
|
|
*hp++ = hex[*p & 0x0f];
|
|
|
|
*sp++ = (*p >= 0x20 && *p <= 0x7e) ?
|
|
|
|
*p : (u_char)'?';
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
*hp = *sp = '\0';
|
|
|
|
|
|
|
|
ngx_log_debug4(NGX_LOG_DEBUG_RTMP, log, 0,
|
|
|
|
"AMF0 %s (%d)%s '%s'", op, n, hstr, str);
|
|
|
|
}
|
|
|
|
#endif
|
2012-03-08 23:39:15 +01:00
|
|
|
|
2012-03-08 16:21:22 +01:00
|
|
|
static ngx_int_t
|
2012-03-08 23:39:15 +01:00
|
|
|
ngx_rtmp_amf0_get(ngx_rtmp_amf0_ctx_t *ctx, void *p, size_t n)
|
2012-03-08 16:21:22 +01:00
|
|
|
{
|
2012-03-08 23:39:15 +01:00
|
|
|
ngx_buf_t *b;
|
2012-03-08 18:45:10 +01:00
|
|
|
size_t size;
|
2012-03-13 06:41:51 +01:00
|
|
|
ngx_chain_t *l;
|
2012-03-08 23:39:15 +01:00
|
|
|
#ifdef NGX_DEBUG
|
|
|
|
void *op = p;
|
|
|
|
#endif
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
if (!n)
|
2012-03-08 18:45:10 +01:00
|
|
|
return NGX_OK;
|
2012-03-08 16:21:22 +01:00
|
|
|
|
2012-03-13 06:41:51 +01:00
|
|
|
for(l = ctx->link; l; l = l->next) {
|
2012-03-08 16:21:22 +01:00
|
|
|
|
2012-03-13 06:41:51 +01:00
|
|
|
b = l->buf;
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
if (b->last > n + b->pos) {
|
2012-03-08 23:39:15 +01:00
|
|
|
if (p) {
|
2012-03-08 16:21:22 +01:00
|
|
|
p = ngx_cpymem(p, b->pos, n);
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
b->pos += n;
|
2012-03-09 22:49:09 +01:00
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
#ifdef NGX_DEBUG
|
2012-03-09 22:49:09 +01:00
|
|
|
ngx_rtmp_amf0_debug("read", ctx->log, (u_char*)op, n);
|
2012-03-08 23:39:15 +01:00
|
|
|
#endif
|
2012-03-09 22:49:09 +01:00
|
|
|
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
2012-03-08 18:45:10 +01:00
|
|
|
size = b->last - b->pos;
|
|
|
|
|
2012-03-08 16:21:22 +01:00
|
|
|
if (p)
|
2012-03-08 18:45:10 +01:00
|
|
|
p = ngx_cpymem(p, b->pos, size);
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
n -= size;
|
|
|
|
}
|
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ctx->log, 0,
|
|
|
|
"AMF0 read eof (%d)", n);
|
|
|
|
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_int_t
|
2012-03-08 23:39:15 +01:00
|
|
|
ngx_rtmp_amf0_put(ngx_rtmp_amf0_ctx_t *ctx, void *p, size_t n)
|
2012-03-08 16:21:22 +01:00
|
|
|
{
|
2012-03-08 18:45:10 +01:00
|
|
|
ngx_buf_t *b;
|
|
|
|
size_t size;
|
2012-03-12 00:44:32 +01:00
|
|
|
ngx_chain_t *l, *ln;
|
2012-03-08 23:39:15 +01:00
|
|
|
|
2012-03-09 22:49:09 +01:00
|
|
|
#ifdef NGX_DEBUG
|
|
|
|
ngx_rtmp_amf0_debug("write", ctx->log, (u_char*)p, n);
|
|
|
|
#endif
|
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
l = ctx->link;
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
while(n) {
|
2012-03-12 00:44:32 +01:00
|
|
|
b = l ? l->buf : NULL;
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
if (b == NULL || b->last == b->end) {
|
2012-03-12 00:44:32 +01:00
|
|
|
|
|
|
|
ln = ctx->alloc(ctx->arg);
|
|
|
|
if (ln == NULL) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-12 00:44:32 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
|
2012-03-12 00:44:32 +01:00
|
|
|
if (l == NULL) {
|
|
|
|
l = ln;
|
|
|
|
ctx->first = l;
|
2012-03-08 16:21:22 +01:00
|
|
|
} else {
|
2012-03-12 00:44:32 +01:00
|
|
|
l->next = ln;
|
|
|
|
l = ln;
|
2012-03-08 16:21:22 +01:00
|
|
|
}
|
2012-03-12 00:44:32 +01:00
|
|
|
|
|
|
|
b = l->buf;
|
2012-03-08 16:21:22 +01:00
|
|
|
b->pos = b->last = b->start;
|
|
|
|
}
|
|
|
|
|
2012-03-08 18:45:10 +01:00
|
|
|
size = b->end - b->last;
|
|
|
|
|
2012-03-09 22:49:09 +01:00
|
|
|
if (size >= n) {
|
2012-03-08 16:21:22 +01:00
|
|
|
b->last = ngx_cpymem(b->last, p, n);
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
2012-03-08 18:45:10 +01:00
|
|
|
b->last = ngx_cpymem(b->last, p, size);
|
|
|
|
p = (u_char*)p + size;
|
|
|
|
n -= size;
|
2012-03-08 16:21:22 +01:00
|
|
|
}
|
2012-03-08 18:45:10 +01:00
|
|
|
|
|
|
|
return NGX_OK;
|
2012-03-08 16:21:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_int_t
|
2012-03-08 23:39:15 +01:00
|
|
|
ngx_rtmp_amf0_read_object(ngx_rtmp_amf0_ctx_t *ctx, ngx_rtmp_amf0_elt_t *elts,
|
2012-03-08 16:21:22 +01:00
|
|
|
size_t nelts)
|
|
|
|
{
|
|
|
|
uint8_t type;
|
|
|
|
uint16_t len;
|
|
|
|
size_t n, namelen, maxlen;
|
|
|
|
ngx_int_t rc;
|
|
|
|
|
|
|
|
maxlen = 0;
|
2012-03-08 18:45:10 +01:00
|
|
|
for(n = 0; n < nelts; ++n) {
|
|
|
|
namelen = strlen(elts[n].name);
|
2012-03-08 16:21:22 +01:00
|
|
|
if (namelen > maxlen)
|
|
|
|
maxlen = namelen;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
|
|
|
|
char name[maxlen + 1];
|
|
|
|
|
|
|
|
/* read key */
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_get(ctx, &len, sizeof(len)) != NGX_OK)
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
|
|
|
|
|
|
|
if (!len)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (len <= maxlen) {
|
2012-03-08 23:39:15 +01:00
|
|
|
rc = ngx_rtmp_amf0_get(ctx, name, len);
|
2012-03-08 16:21:22 +01:00
|
|
|
name[len] = 0;
|
|
|
|
|
|
|
|
} else {
|
2012-03-08 23:39:15 +01:00
|
|
|
rc = ngx_rtmp_amf0_get(ctx, name, maxlen);
|
2012-03-08 16:21:22 +01:00
|
|
|
if (rc != NGX_OK)
|
|
|
|
return NGX_ERROR;
|
|
|
|
name[maxlen] = 0;
|
2012-03-08 23:39:15 +01:00
|
|
|
rc = ngx_rtmp_amf0_get(ctx, 0, len - maxlen);
|
2012-03-08 16:21:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rc != NGX_OK)
|
|
|
|
return NGX_ERROR;
|
|
|
|
|
|
|
|
/* TODO: if we require array to be sorted on name
|
|
|
|
* then we could be able to use binary search */
|
|
|
|
for(n = 0; n < nelts && strcmp(name, elts[n].name); ++n);
|
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_read(ctx, n < nelts ? &elts[n] : NULL, 1) != NGX_OK)
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_get(ctx, &type, 1) != NGX_OK
|
2012-03-08 16:21:22 +01:00
|
|
|
|| type != NGX_RTMP_AMF0_END)
|
|
|
|
{
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
2012-03-08 18:45:10 +01:00
|
|
|
#define NGX_RTMP_AMF0_TILL_END_FLAG ((size_t)1 << (sizeof(size_t) * 8 - 1))
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
ngx_int_t
|
2012-03-08 23:39:15 +01:00
|
|
|
ngx_rtmp_amf0_read(ngx_rtmp_amf0_ctx_t *ctx, ngx_rtmp_amf0_elt_t *elts, size_t nelts)
|
2012-03-08 16:21:22 +01:00
|
|
|
{
|
|
|
|
void *data;
|
|
|
|
uint8_t type;
|
2012-03-08 18:45:10 +01:00
|
|
|
size_t n;
|
2012-03-08 16:21:22 +01:00
|
|
|
uint16_t len;
|
|
|
|
ngx_int_t rc;
|
|
|
|
int till_end;
|
2012-03-09 22:49:09 +01:00
|
|
|
u_char buf[8];
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
if (nelts & NGX_RTMP_AMF0_TILL_END_FLAG) {
|
|
|
|
till_end = 1;
|
|
|
|
nelts = nelts & ~NGX_RTMP_AMF0_TILL_END_FLAG;
|
|
|
|
} else {
|
|
|
|
till_end = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(n = 0; till_end || n < nelts; ++n) {
|
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_get(ctx, &type, sizeof(type)) != NGX_OK)
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
|
|
|
|
|
|
|
data = (n >= nelts || elts == NULL || elts->type != type)
|
|
|
|
? NULL
|
|
|
|
: elts->data;
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
case NGX_RTMP_AMF0_NUMBER:
|
2012-03-09 22:49:09 +01:00
|
|
|
if (ngx_rtmp_amf0_get(ctx, buf, 8) != NGX_OK) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-09 22:49:09 +01:00
|
|
|
ngx_rtmp_amf0_reverse_copy(data, buf, 0);
|
2012-03-08 16:21:22 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_BOOLEAN:
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_get(ctx, data, 1) != NGX_OK) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_STRING:
|
2012-03-09 22:49:09 +01:00
|
|
|
if (ngx_rtmp_amf0_get(ctx, buf, 2) != NGX_OK) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-09 22:49:09 +01:00
|
|
|
ngx_rtmp_amf0_reverse_copy(&len, buf, 2);
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
if (data == NULL) {
|
2012-03-08 23:39:15 +01:00
|
|
|
rc = ngx_rtmp_amf0_get(ctx, data, len);
|
2012-03-08 16:21:22 +01:00
|
|
|
|
2012-03-08 18:45:10 +01:00
|
|
|
} else if (elts->len <= len) {
|
2012-03-08 23:39:15 +01:00
|
|
|
rc = ngx_rtmp_amf0_get(ctx, data, elts->len - 1);
|
2012-03-08 16:21:22 +01:00
|
|
|
if (rc != NGX_OK)
|
|
|
|
return NGX_ERROR;
|
2012-03-08 18:45:10 +01:00
|
|
|
((char*)data)[elts->len - 1] = 0;
|
2012-03-08 23:39:15 +01:00
|
|
|
rc = ngx_rtmp_amf0_get(ctx, NULL, len - elts->len + 1);
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
} else {
|
2012-03-08 23:39:15 +01:00
|
|
|
rc = ngx_rtmp_amf0_get(ctx, data, len);
|
2012-03-08 18:45:10 +01:00
|
|
|
((char*)data)[len] = 0;
|
2012-03-08 16:21:22 +01:00
|
|
|
}
|
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
if (rc != NGX_OK) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_NULL:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_OBJECT:
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_read_object(ctx, data,
|
2012-03-08 16:21:22 +01:00
|
|
|
elts ? elts->len / sizeof(ngx_rtmp_amf0_elt_t) : 0
|
|
|
|
) != NGX_OK)
|
|
|
|
{
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_ARRAY:
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_read(ctx, data,
|
2012-03-08 16:21:22 +01:00
|
|
|
elts ? (elts->len / sizeof(ngx_rtmp_amf0_elt_t))
|
|
|
|
| NGX_RTMP_AMF0_TILL_END_FLAG : 0
|
|
|
|
) != NGX_OK)
|
|
|
|
{
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_END:
|
|
|
|
return NGX_OK;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
if (elts) {
|
2012-03-08 16:21:22 +01:00
|
|
|
++elts;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ngx_int_t
|
2012-03-08 23:39:15 +01:00
|
|
|
ngx_rtmp_amf0_write_object(ngx_rtmp_amf0_ctx_t *ctx,
|
2012-03-08 16:21:22 +01:00
|
|
|
ngx_rtmp_amf0_elt_t *elts, size_t nelts)
|
|
|
|
{
|
2012-03-09 22:49:09 +01:00
|
|
|
uint16_t len, len_sb;
|
2012-03-08 16:21:22 +01:00
|
|
|
size_t n;
|
|
|
|
char *name;
|
2012-03-09 22:49:09 +01:00
|
|
|
u_char buf[2];
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
for(n = 0; n < nelts; ++n) {
|
|
|
|
|
|
|
|
name = elts[n].name;
|
2012-03-09 22:49:09 +01:00
|
|
|
len_sb = len = strlen(name);
|
2012-03-08 16:21:22 +01:00
|
|
|
|
2012-03-09 22:49:09 +01:00
|
|
|
if (ngx_rtmp_amf0_put(ctx,
|
|
|
|
ngx_rtmp_amf0_reverse_copy(buf,
|
|
|
|
&len, 2), 2) != NGX_OK)
|
|
|
|
{
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ngx_rtmp_amf0_put(ctx, name, len) != NGX_OK) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_write(ctx, &elts[n], 1) != NGX_OK) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
|
2012-03-09 22:49:09 +01:00
|
|
|
if (ngx_rtmp_amf0_put(ctx, "\00\00", 2) != NGX_OK) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ngx_int_t
|
2012-03-08 23:39:15 +01:00
|
|
|
ngx_rtmp_amf0_write(ngx_rtmp_amf0_ctx_t *ctx,
|
2012-03-08 16:21:22 +01:00
|
|
|
ngx_rtmp_amf0_elt_t *elts, size_t nelts)
|
|
|
|
{
|
|
|
|
size_t n;
|
|
|
|
uint8_t type;
|
|
|
|
void *data;
|
|
|
|
uint16_t len;
|
2012-03-09 22:49:09 +01:00
|
|
|
u_char buf[8];
|
2012-03-08 16:21:22 +01:00
|
|
|
|
|
|
|
for(n = 0; n < nelts; ++n) {
|
|
|
|
|
|
|
|
type = elts[n].type;
|
|
|
|
data = elts[n].data;
|
|
|
|
len = elts[n].len;
|
|
|
|
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_put(ctx, &type, sizeof(type)) != NGX_OK)
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
case NGX_RTMP_AMF0_NUMBER:
|
2012-03-09 22:49:09 +01:00
|
|
|
if (ngx_rtmp_amf0_put(ctx,
|
|
|
|
ngx_rtmp_amf0_reverse_copy(buf,
|
|
|
|
data, 8), 8) != NGX_OK)
|
|
|
|
{
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_BOOLEAN:
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_put(ctx, data, 1) != NGX_OK) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
2012-03-08 23:39:15 +01:00
|
|
|
}
|
2012-03-08 16:21:22 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_STRING:
|
2012-03-09 22:49:09 +01:00
|
|
|
if (ngx_rtmp_amf0_put(ctx,
|
|
|
|
ngx_rtmp_amf0_reverse_copy(buf,
|
|
|
|
&len, 2), 2) != NGX_OK)
|
|
|
|
{
|
2012-03-08 23:39:15 +01:00
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ngx_rtmp_amf0_put(ctx, data, len) != NGX_OK) {
|
2012-03-08 16:21:22 +01:00
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_NULL:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_OBJECT:
|
|
|
|
type = NGX_RTMP_AMF0_END;
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_write_object(ctx, data,
|
2012-03-08 16:21:22 +01:00
|
|
|
elts[n].len / sizeof(ngx_rtmp_amf0_elt_t)) != NGX_OK
|
2012-03-08 23:39:15 +01:00
|
|
|
|| ngx_rtmp_amf0_put(ctx, &type,
|
2012-03-08 16:21:22 +01:00
|
|
|
sizeof(type)) != NGX_OK)
|
|
|
|
{
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_ARRAY:
|
|
|
|
type = NGX_RTMP_AMF0_END;
|
2012-03-08 23:39:15 +01:00
|
|
|
if (ngx_rtmp_amf0_write(ctx, data,
|
2012-03-08 16:21:22 +01:00
|
|
|
elts[n].len / sizeof(ngx_rtmp_amf0_elt_t)) != NGX_OK
|
2012-03-08 23:39:15 +01:00
|
|
|
|| ngx_rtmp_amf0_put(ctx, &type,
|
2012-03-08 16:21:22 +01:00
|
|
|
sizeof(type)) != NGX_OK)
|
|
|
|
{
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NGX_RTMP_AMF0_END:
|
|
|
|
return NGX_OK;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NGX_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|