blob: 0ba157d9e738398eb1470f650a9988742f224cb0 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file rtmp/amf_enc.c Real Time Messaging Protocol (RTMP) -- AMF Encoding
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <string.h>
7#include <re_types.h>
8#include <re_fmt.h>
9#include <re_mem.h>
10#include <re_mbuf.h>
11#include <re_net.h>
12#include <re_sa.h>
13#include <re_list.h>
14#include <re_sys.h>
15#include <re_odict.h>
16#include <re_rtmp.h>
17#include "rtmp.h"
18
19
20static int rtmp_amf_encode_key(struct mbuf *mb, const char *key)
21{
22 size_t len;
23 int err;
24
25 len = str_len(key);
26
27 if (len > 65535)
28 return EOVERFLOW;
29
30 err = mbuf_write_u16(mb, htons((uint16_t)len));
31 err |= mbuf_write_str(mb, key);
32
33 return err;
34}
35
36
37static int rtmp_amf_encode_object_start(struct mbuf *mb)
38{
39 return mbuf_write_u8(mb, RTMP_AMF_TYPE_OBJECT);
40}
41
42
43static int rtmp_amf_encode_array_start(struct mbuf *mb,
44 uint8_t type, uint32_t length)
45{
46 int err;
47
48 err = mbuf_write_u8(mb, type);
49 err |= mbuf_write_u32(mb, htonl(length));
50
51 return err;
52}
53
54
55static int rtmp_amf_encode_object_end(struct mbuf *mb)
56{
57 int err;
58
59 err = mbuf_write_u16(mb, 0);
60 err |= mbuf_write_u8(mb, RTMP_AMF_TYPE_OBJECT_END);
61
62 return err;
63}
64
65
66static bool container_has_key(enum rtmp_amf_type type)
67{
68 switch (type) {
69
70 case RTMP_AMF_TYPE_OBJECT: return true;
71 case RTMP_AMF_TYPE_ECMA_ARRAY: return true;
72 case RTMP_AMF_TYPE_STRICT_ARRAY: return false;
73 default: return false;
74 }
75}
76
77
78int rtmp_amf_encode_number(struct mbuf *mb, double val)
79{
80 const union {
81 uint64_t i;
82 double f;
83 } num = {
84 .f = val
85 };
86 int err;
87
88 if (!mb)
89 return EINVAL;
90
91 err = mbuf_write_u8(mb, RTMP_AMF_TYPE_NUMBER);
92 err |= mbuf_write_u64(mb, sys_htonll(num.i));
93
94 return err;
95}
96
97
98int rtmp_amf_encode_boolean(struct mbuf *mb, bool boolean)
99{
100 int err;
101
102 if (!mb)
103 return EINVAL;
104
105 err = mbuf_write_u8(mb, RTMP_AMF_TYPE_BOOLEAN);
106 err |= mbuf_write_u8(mb, !!boolean);
107
108 return err;
109}
110
111
112int rtmp_amf_encode_string(struct mbuf *mb, const char *str)
113{
114 size_t len;
115 int err;
116
117 if (!mb || !str)
118 return EINVAL;
119
120 len = str_len(str);
121
122 if (len > 65535)
123 return EOVERFLOW;
124
125 err = mbuf_write_u8(mb, RTMP_AMF_TYPE_STRING);
126 err |= mbuf_write_u16(mb, htons((uint16_t)len));
127 err |= mbuf_write_str(mb, str);
128
129 return err;
130}
131
132
133int rtmp_amf_encode_null(struct mbuf *mb)
134{
135 if (!mb)
136 return EINVAL;
137
138 return mbuf_write_u8(mb, RTMP_AMF_TYPE_NULL);
139}
140
141
142/*
143 * NUMBER double
144 * BOOLEAN bool
145 * STRING const char *
146 * OBJECT const char *key sub-count
147 * NULL NULL
148 * ARRAY const char *key sub-count
149 */
150int rtmp_amf_vencode_object(struct mbuf *mb, enum rtmp_amf_type container,
151 unsigned propc, va_list *ap)
152{
153 bool encode_key;
154 unsigned i;
155 int err = 0;
156
157 if (!mb || !propc || !ap)
158 return EINVAL;
159
160 encode_key = container_has_key(container);
161
162 switch (container) {
163
164 case RTMP_AMF_TYPE_OBJECT:
165 err = rtmp_amf_encode_object_start(mb);
166 break;
167
168 case RTMP_AMF_TYPE_ECMA_ARRAY:
169 case RTMP_AMF_TYPE_STRICT_ARRAY:
170 err = rtmp_amf_encode_array_start(mb, container, propc);
171 break;
172
173 case RTMP_AMF_TYPE_ROOT:
174 break;
175
176 default:
177 return ENOTSUP;
178 }
179
180 if (err)
181 return err;
182
183 for (i=0; i<propc; i++) {
184
185 int type = va_arg(*ap, int);
186 const char *str;
187 int subcount;
188 double dbl;
189 bool b;
190
191 /* add key if ARRAY or OBJECT container */
192 if (encode_key) {
193 const char *key;
194
195 key = va_arg(*ap, const char *);
196 if (!key)
197 return EINVAL;
198
199 err = rtmp_amf_encode_key(mb, key);
200 if (err)
201 return err;
202 }
203
204 switch (type) {
205
206 case RTMP_AMF_TYPE_NUMBER:
207 dbl = va_arg(*ap, double);
208 err = rtmp_amf_encode_number(mb, dbl);
209 break;
210
211 case RTMP_AMF_TYPE_BOOLEAN:
212 b = va_arg(*ap, int);
213 err = rtmp_amf_encode_boolean(mb, b);
214 break;
215
216 case RTMP_AMF_TYPE_STRING:
217 str = va_arg(*ap, const char *);
218 err = rtmp_amf_encode_string(mb, str);
219 break;
220
221 case RTMP_AMF_TYPE_NULL:
222 err = rtmp_amf_encode_null(mb);
223 break;
224
225 case RTMP_AMF_TYPE_OBJECT:
226 case RTMP_AMF_TYPE_ECMA_ARRAY:
227 case RTMP_AMF_TYPE_STRICT_ARRAY:
228 /* recursive */
229 subcount = va_arg(*ap, int);
230 err = rtmp_amf_vencode_object(mb, type, subcount, ap);
231 break;
232
233 default:
234 return ENOTSUP;
235 }
236
237 if (err)
238 return err;
239 }
240
241 if (encode_key)
242 err = rtmp_amf_encode_object_end(mb);
243
244 return err;
245}