Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b

Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/rtmp/stream.c b/src/rtmp/stream.c
new file mode 100644
index 0000000..fe8748d
--- /dev/null
+++ b/src/rtmp/stream.c
@@ -0,0 +1,309 @@
+/**
+ * @file rtmp/stream.c  Real Time Messaging Protocol (RTMP) -- NetStream
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_net.h>
+#include <re_sa.h>
+#include <re_list.h>
+#include <re_tcp.h>
+#include <re_sys.h>
+#include <re_odict.h>
+#include <re_rtmp.h>
+#include "rtmp.h"
+
+
+static void destructor(void *data)
+{
+	struct rtmp_stream *strm = data;
+
+	list_unlink(&strm->le);
+
+	if (strm->created) {
+
+		rtmp_amf_command(strm->conn, 0, "deleteStream",
+				 3,
+				RTMP_AMF_TYPE_NUMBER, 0.0,
+				RTMP_AMF_TYPE_NULL,
+				RTMP_AMF_TYPE_NUMBER, (double)strm->stream_id);
+	}
+}
+
+
+/**
+ * Allocate a new RTMP Stream object
+ *
+ * @param strmp     Pointer to allocated RTMP Stream
+ * @param conn      RTMP Connection
+ * @param stream_id Stream id
+ * @param cmdh      Command handler
+ * @param ctrlh     Control handler
+ * @param auh       Audio handler
+ * @param vidh      Video handler
+ * @param datah     Data handler
+ * @param arg       Handler argument
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int rtmp_stream_alloc(struct rtmp_stream **strmp, struct rtmp_conn *conn,
+		      uint32_t stream_id, rtmp_command_h *cmdh,
+		      rtmp_control_h *ctrlh, rtmp_audio_h *auh,
+		      rtmp_video_h *vidh, rtmp_command_h *datah,
+		      void *arg)
+{
+	struct rtmp_stream *strm;
+
+	if (!strmp || !conn)
+		return EINVAL;
+
+	strm = mem_zalloc(sizeof(*strm), destructor);
+	if (!strm)
+		return ENOMEM;
+
+	strm->conn      = conn;
+	strm->stream_id = stream_id;
+
+	strm->cmdh   = cmdh;
+	strm->ctrlh  = ctrlh;
+	strm->auh    = auh;
+	strm->vidh   = vidh;
+	strm->datah  = datah;
+	strm->arg    = arg;
+
+	strm->chunk_id_audio = rtmp_conn_assign_chunkid(conn);
+	strm->chunk_id_video = rtmp_conn_assign_chunkid(conn);
+	strm->chunk_id_data  = rtmp_conn_assign_chunkid(conn);
+
+	list_append(&conn->streaml, &strm->le, strm);
+
+	*strmp = strm;
+
+	return 0;
+}
+
+
+static void createstream_handler(bool success, const struct odict *msg,
+				 void *arg)
+{
+	struct rtmp_stream *strm = arg;
+	uint64_t num;
+
+	if (!success)
+		goto out;
+
+	if (!odict_get_number(msg, &num, "3")) {
+		success = false;
+		goto out;
+	}
+
+	strm->stream_id = (uint32_t)num;
+	if (strm->stream_id == 0) {
+		success = false;
+		goto out;
+	}
+
+	strm->created = true;
+
+ out:
+	if (strm->resph)
+		strm->resph(success, msg, strm->arg);
+}
+
+
+/**
+ * Create a new RTMP Stream by sending "createStream" to the RTMP Server.
+ *
+ * @param strmp     Pointer to allocated RTMP Stream
+ * @param conn      RTMP Connection
+ * @param resph     RTMP Response handler
+ * @param cmdh      Command handler
+ * @param ctrlh     Control handler
+ * @param auh       Audio handler
+ * @param vidh      Video handler
+ * @param datah     Data handler
+ * @param arg       Handler argument
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int rtmp_stream_create(struct rtmp_stream **strmp, struct rtmp_conn *conn,
+		       rtmp_resp_h *resph, rtmp_command_h *cmdh,
+		       rtmp_control_h *ctrlh, rtmp_audio_h *auh,
+		       rtmp_video_h *vidh, rtmp_command_h *datah,
+		       void *arg)
+{
+	struct rtmp_stream *strm;
+	int err;
+
+	if (!strmp || !conn)
+		return EINVAL;
+
+	err = rtmp_stream_alloc(&strm, conn, (uint32_t)-1,
+				cmdh, ctrlh, auh, vidh, datah, arg);
+	if (err)
+		return err;
+
+	strm->resph = resph;
+
+	err = rtmp_amf_request(conn, 0,
+			       "createStream", createstream_handler, strm,
+			       1,
+			       RTMP_AMF_TYPE_NULL);
+	if (err)
+		goto out;
+
+ out:
+	if (err)
+		mem_deref(strm);
+	else
+		*strmp = strm;
+
+	return err;
+}
+
+
+/**
+ * Start playing an RTMP Stream by sending "play" to the RTMP Server
+ *
+ * @param strm RTMP Stream
+ * @param name Stream name
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int rtmp_play(struct rtmp_stream *strm, const char *name)
+{
+	if (!strm || !name)
+		return EINVAL;
+
+	return rtmp_amf_command(strm->conn, strm->stream_id, "play",
+				4,
+				RTMP_AMF_TYPE_NUMBER, 0.0,
+				RTMP_AMF_TYPE_NULL,
+				RTMP_AMF_TYPE_STRING, name,
+				RTMP_AMF_TYPE_NUMBER, -2000.0);
+}
+
+
+/**
+ * Start publishing an RTMP Stream by sending "publish" to the RTMP Server
+ *
+ * @param strm RTMP Stream
+ * @param name Stream name
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int rtmp_publish(struct rtmp_stream *strm, const char *name)
+{
+	if (!strm || !name)
+		return EINVAL;
+
+	return rtmp_amf_command(strm->conn, strm->stream_id, "publish",
+				4,
+				RTMP_AMF_TYPE_NUMBER, 0.0,
+				RTMP_AMF_TYPE_NULL,
+				RTMP_AMF_TYPE_STRING, name,
+				RTMP_AMF_TYPE_STRING, "live");
+}
+
+
+/**
+ * Send metadata on the stream to the RTMP Server
+ *
+ * @param strm RTMP Stream
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int rtmp_meta(struct rtmp_stream *strm)
+{
+	if (!strm)
+		return EINVAL;
+
+	return rtmp_amf_data(strm->conn, strm->stream_id, "@setDataFrame",
+			     2,
+			     RTMP_AMF_TYPE_STRING, "onMetaData",
+			     RTMP_AMF_TYPE_ECMA_ARRAY, 2,
+			         RTMP_AMF_TYPE_NUMBER, "audiocodecid", 10.0,
+			         RTMP_AMF_TYPE_NUMBER, "videocodecid",  7.0);
+}
+
+
+/**
+ * Send audio packet on the RTMP Stream
+ *
+ * @param strm      RTMP Stream
+ * @param timestamp Timestamp in [milliseconds]
+ * @param pld       Audio payload
+ * @param len       Payload length
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int rtmp_send_audio(struct rtmp_stream *strm, uint32_t timestamp,
+		    const uint8_t *pld, size_t len)
+{
+	uint32_t chunk_id;
+
+	if (!strm || !pld || !len)
+		return EINVAL;
+
+	chunk_id = strm->chunk_id_audio;
+
+	return rtmp_conn_send_msg(strm->conn, 0, chunk_id, timestamp, 0,
+				  RTMP_TYPE_AUDIO, strm->stream_id, pld, len);
+}
+
+
+/**
+ * Send video packet on the RTMP Stream
+ *
+ * @param strm      RTMP Stream
+ * @param timestamp Timestamp in [milliseconds]
+ * @param pld       Video payload
+ * @param len       Payload length
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int rtmp_send_video(struct rtmp_stream *strm, uint32_t timestamp,
+		    const uint8_t *pld, size_t len)
+{
+	uint32_t chunk_id;
+
+	if (!strm || !pld || !len)
+		return EINVAL;
+
+	chunk_id = strm->chunk_id_video;
+
+	return rtmp_conn_send_msg(strm->conn, 0, chunk_id, timestamp, 0,
+				  RTMP_TYPE_VIDEO, strm->stream_id, pld, len);
+}
+
+
+/**
+ * Find an RTMP Stream by stream id
+ *
+ * @param conn      RTMP Connection
+ * @param stream_id Stream id
+ *
+ * @return RTMP Stream if found, or NULL if not found
+ */
+struct rtmp_stream *rtmp_stream_find(const struct rtmp_conn *conn,
+				     uint32_t stream_id)
+{
+	struct le *le;
+
+	if (!conn)
+		return NULL;
+
+	for (le = list_head(&conn->streaml); le; le = le->next) {
+
+		struct rtmp_stream *strm = le->data;
+
+		if (stream_id == strm->stream_id)
+			return strm;
+	}
+
+	return NULL;
+}