blob: fe8748dc5e4e35201e122ebbbe4d7eff36f9ec0f [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file rtmp/stream.c Real Time Messaging Protocol (RTMP) -- NetStream
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_tcp.h>
15#include <re_sys.h>
16#include <re_odict.h>
17#include <re_rtmp.h>
18#include "rtmp.h"
19
20
21static void destructor(void *data)
22{
23 struct rtmp_stream *strm = data;
24
25 list_unlink(&strm->le);
26
27 if (strm->created) {
28
29 rtmp_amf_command(strm->conn, 0, "deleteStream",
30 3,
31 RTMP_AMF_TYPE_NUMBER, 0.0,
32 RTMP_AMF_TYPE_NULL,
33 RTMP_AMF_TYPE_NUMBER, (double)strm->stream_id);
34 }
35}
36
37
38/**
39 * Allocate a new RTMP Stream object
40 *
41 * @param strmp Pointer to allocated RTMP Stream
42 * @param conn RTMP Connection
43 * @param stream_id Stream id
44 * @param cmdh Command handler
45 * @param ctrlh Control handler
46 * @param auh Audio handler
47 * @param vidh Video handler
48 * @param datah Data handler
49 * @param arg Handler argument
50 *
51 * @return 0 if success, otherwise errorcode
52 */
53int rtmp_stream_alloc(struct rtmp_stream **strmp, struct rtmp_conn *conn,
54 uint32_t stream_id, rtmp_command_h *cmdh,
55 rtmp_control_h *ctrlh, rtmp_audio_h *auh,
56 rtmp_video_h *vidh, rtmp_command_h *datah,
57 void *arg)
58{
59 struct rtmp_stream *strm;
60
61 if (!strmp || !conn)
62 return EINVAL;
63
64 strm = mem_zalloc(sizeof(*strm), destructor);
65 if (!strm)
66 return ENOMEM;
67
68 strm->conn = conn;
69 strm->stream_id = stream_id;
70
71 strm->cmdh = cmdh;
72 strm->ctrlh = ctrlh;
73 strm->auh = auh;
74 strm->vidh = vidh;
75 strm->datah = datah;
76 strm->arg = arg;
77
78 strm->chunk_id_audio = rtmp_conn_assign_chunkid(conn);
79 strm->chunk_id_video = rtmp_conn_assign_chunkid(conn);
80 strm->chunk_id_data = rtmp_conn_assign_chunkid(conn);
81
82 list_append(&conn->streaml, &strm->le, strm);
83
84 *strmp = strm;
85
86 return 0;
87}
88
89
90static void createstream_handler(bool success, const struct odict *msg,
91 void *arg)
92{
93 struct rtmp_stream *strm = arg;
94 uint64_t num;
95
96 if (!success)
97 goto out;
98
99 if (!odict_get_number(msg, &num, "3")) {
100 success = false;
101 goto out;
102 }
103
104 strm->stream_id = (uint32_t)num;
105 if (strm->stream_id == 0) {
106 success = false;
107 goto out;
108 }
109
110 strm->created = true;
111
112 out:
113 if (strm->resph)
114 strm->resph(success, msg, strm->arg);
115}
116
117
118/**
119 * Create a new RTMP Stream by sending "createStream" to the RTMP Server.
120 *
121 * @param strmp Pointer to allocated RTMP Stream
122 * @param conn RTMP Connection
123 * @param resph RTMP Response handler
124 * @param cmdh Command handler
125 * @param ctrlh Control handler
126 * @param auh Audio handler
127 * @param vidh Video handler
128 * @param datah Data handler
129 * @param arg Handler argument
130 *
131 * @return 0 if success, otherwise errorcode
132 */
133int rtmp_stream_create(struct rtmp_stream **strmp, struct rtmp_conn *conn,
134 rtmp_resp_h *resph, rtmp_command_h *cmdh,
135 rtmp_control_h *ctrlh, rtmp_audio_h *auh,
136 rtmp_video_h *vidh, rtmp_command_h *datah,
137 void *arg)
138{
139 struct rtmp_stream *strm;
140 int err;
141
142 if (!strmp || !conn)
143 return EINVAL;
144
145 err = rtmp_stream_alloc(&strm, conn, (uint32_t)-1,
146 cmdh, ctrlh, auh, vidh, datah, arg);
147 if (err)
148 return err;
149
150 strm->resph = resph;
151
152 err = rtmp_amf_request(conn, 0,
153 "createStream", createstream_handler, strm,
154 1,
155 RTMP_AMF_TYPE_NULL);
156 if (err)
157 goto out;
158
159 out:
160 if (err)
161 mem_deref(strm);
162 else
163 *strmp = strm;
164
165 return err;
166}
167
168
169/**
170 * Start playing an RTMP Stream by sending "play" to the RTMP Server
171 *
172 * @param strm RTMP Stream
173 * @param name Stream name
174 *
175 * @return 0 if success, otherwise errorcode
176 */
177int rtmp_play(struct rtmp_stream *strm, const char *name)
178{
179 if (!strm || !name)
180 return EINVAL;
181
182 return rtmp_amf_command(strm->conn, strm->stream_id, "play",
183 4,
184 RTMP_AMF_TYPE_NUMBER, 0.0,
185 RTMP_AMF_TYPE_NULL,
186 RTMP_AMF_TYPE_STRING, name,
187 RTMP_AMF_TYPE_NUMBER, -2000.0);
188}
189
190
191/**
192 * Start publishing an RTMP Stream by sending "publish" to the RTMP Server
193 *
194 * @param strm RTMP Stream
195 * @param name Stream name
196 *
197 * @return 0 if success, otherwise errorcode
198 */
199int rtmp_publish(struct rtmp_stream *strm, const char *name)
200{
201 if (!strm || !name)
202 return EINVAL;
203
204 return rtmp_amf_command(strm->conn, strm->stream_id, "publish",
205 4,
206 RTMP_AMF_TYPE_NUMBER, 0.0,
207 RTMP_AMF_TYPE_NULL,
208 RTMP_AMF_TYPE_STRING, name,
209 RTMP_AMF_TYPE_STRING, "live");
210}
211
212
213/**
214 * Send metadata on the stream to the RTMP Server
215 *
216 * @param strm RTMP Stream
217 *
218 * @return 0 if success, otherwise errorcode
219 */
220int rtmp_meta(struct rtmp_stream *strm)
221{
222 if (!strm)
223 return EINVAL;
224
225 return rtmp_amf_data(strm->conn, strm->stream_id, "@setDataFrame",
226 2,
227 RTMP_AMF_TYPE_STRING, "onMetaData",
228 RTMP_AMF_TYPE_ECMA_ARRAY, 2,
229 RTMP_AMF_TYPE_NUMBER, "audiocodecid", 10.0,
230 RTMP_AMF_TYPE_NUMBER, "videocodecid", 7.0);
231}
232
233
234/**
235 * Send audio packet on the RTMP Stream
236 *
237 * @param strm RTMP Stream
238 * @param timestamp Timestamp in [milliseconds]
239 * @param pld Audio payload
240 * @param len Payload length
241 *
242 * @return 0 if success, otherwise errorcode
243 */
244int rtmp_send_audio(struct rtmp_stream *strm, uint32_t timestamp,
245 const uint8_t *pld, size_t len)
246{
247 uint32_t chunk_id;
248
249 if (!strm || !pld || !len)
250 return EINVAL;
251
252 chunk_id = strm->chunk_id_audio;
253
254 return rtmp_conn_send_msg(strm->conn, 0, chunk_id, timestamp, 0,
255 RTMP_TYPE_AUDIO, strm->stream_id, pld, len);
256}
257
258
259/**
260 * Send video packet on the RTMP Stream
261 *
262 * @param strm RTMP Stream
263 * @param timestamp Timestamp in [milliseconds]
264 * @param pld Video payload
265 * @param len Payload length
266 *
267 * @return 0 if success, otherwise errorcode
268 */
269int rtmp_send_video(struct rtmp_stream *strm, uint32_t timestamp,
270 const uint8_t *pld, size_t len)
271{
272 uint32_t chunk_id;
273
274 if (!strm || !pld || !len)
275 return EINVAL;
276
277 chunk_id = strm->chunk_id_video;
278
279 return rtmp_conn_send_msg(strm->conn, 0, chunk_id, timestamp, 0,
280 RTMP_TYPE_VIDEO, strm->stream_id, pld, len);
281}
282
283
284/**
285 * Find an RTMP Stream by stream id
286 *
287 * @param conn RTMP Connection
288 * @param stream_id Stream id
289 *
290 * @return RTMP Stream if found, or NULL if not found
291 */
292struct rtmp_stream *rtmp_stream_find(const struct rtmp_conn *conn,
293 uint32_t stream_id)
294{
295 struct le *le;
296
297 if (!conn)
298 return NULL;
299
300 for (le = list_head(&conn->streaml); le; le = le->next) {
301
302 struct rtmp_stream *strm = le->data;
303
304 if (stream_id == strm->stream_id)
305 return strm;
306 }
307
308 return NULL;
309}