summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Hiszpanski <chris.hiszpanski@verkada.com>2022-05-21 15:25:35 -0700
committerChris Hiszpanski <chris.hiszpanski@verkada.com>2022-05-21 15:45:26 -0700
commit97261b79b20e4e53ef3a5b7a37d1ffb0b5665bcb (patch)
tree809099efc2ac9ccfb440776eda5c63b6a1970931
parent12df87e791ee6e468df31a6c468595b8c124a2b4 (diff)
* Added trtc_ prefixes
* Split into tinyrtc.c/h * Sending answer * Answer validates
-rw-r--r--.gitignore2
-rw-r--r--Makefile13
-rw-r--r--README.md5
-rw-r--r--example/index.js7
-rw-r--r--example/main.c32
-rw-r--r--example/tinyrtc.pngbin0 -> 4707 bytes
-rw-r--r--tinyrtc.c126
-rw-r--r--tinyrtc.h74
8 files changed, 208 insertions, 51 deletions
diff --git a/.gitignore b/.gitignore
index e383139..258d911 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
example/webrtcd
+tinyrtc.o
+*.swp
diff --git a/Makefile b/Makefile
index 4d82061..be9ee9f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,13 @@
-example/webrtcd: example/main.c tinyrtc.h
- $(CC) $(CFLAGS) -I. -o $@ example/main.c
+example/webrtcd: example/main.c tinyrtc.o
+ $(CC) $(CFLAGS) -I. -o $@ example/main.c tinyrtc.o
+
+tinyrtc.o: tinyrtc.c tinyrtc.h
+ $(CC) $(CFLAGS) -I. -o $@ -c tinyrtc.c
.PHONY: clean
clean:
- rm -f example/webrtcd
+ rm -f tinyrtc.o example/webrtcd
+
+.PHONY: run
+run:
+ websocketd --port=8080 --staticdir=example ./example/webrtcd
diff --git a/README.md b/README.md
index 095d825..c30f1a0 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
-TinyRTC
-=======
+# ![tinyrtc logo](example/tinyrtc.png) TinyRTC
-A header-only implementation of WebRTC for small systems like IP cameras
+WebRTC implementation in C for tiny things like IP cameras
Build
-----
diff --git a/example/index.js b/example/index.js
index 35fdbba..a161a10 100644
--- a/example/index.js
+++ b/example/index.js
@@ -26,10 +26,13 @@ window.onload = function demo() {
let d = JSON.parse(event.data);
if ('candidate' in d) {
if (d.candidate) {
- console.log("remote candidate:\n%c%s", "color: blue;", event.data);
+ console.log("remote candidate:\n%c%s", "color: blue;", d.candidate);
}
} else if ('sdp' in d) {
- console.log("remote answer:\n%c%s", "color: blue;", event.data);
+ pc.setRemoteDescription(d).catch((e) => {
+ console.log("local error:\n%c%s", "color: red;", e);
+ });
+ console.log("remote answer:\n%c%s", "color: blue;", d.sdp);
}
} catch(e) {
console.log("remote error:\n%c%s", "color: red;", event.data);
diff --git a/example/main.c b/example/main.c
index 6223898..33ef4bb 100644
--- a/example/main.c
+++ b/example/main.c
@@ -17,9 +17,9 @@ static bool matches(const char *json, jsmntok_t *tok, const char *s) {
}
// Parses ICE candidate from stringified JSON
-struct ice_candidate_t parse_ice_candidate(const char *s)
+struct trtc_ice_candidate_t parse_ice_candidate(const char *s)
{
- struct ice_candidate_t c = { 0 };
+ struct trtc_ice_candidate_t c = { 0 };
int i, r;
jsmn_parser p;
@@ -60,7 +60,7 @@ struct ice_candidate_t parse_ice_candidate(const char *s)
}
// (callback) Called for each discovered local ICE candidate
-int on_ice_candidate(const struct ice_candidate_t c, void *arg) {
+int on_ice_candidate(const struct trtc_ice_candidate_t c, void *arg) {
// send ice candidate over signaling channel
printf("{"
"\"candidate\":\"%s\","
@@ -78,7 +78,7 @@ int main(int argc, char **argv)
setvbuf(stdout, NULL, _IONBF, 0);
// create peer connection
- struct configuration_t cfg = {
+ struct trtc_config_t cfg = {
.ice_servers = {
{
.urls = {
@@ -87,25 +87,29 @@ int main(int argc, char **argv)
}
}
};
- struct peerconn_t* pc = rtc_peer_connection(cfg);
-
- printf("alert! starting\n");
+ struct trtc_peerconn_t* pc = trtc_peer_connection(cfg);
while (true) {
int n;
- char *m = NULL;
- size_t len = 0;
+ char *msg = NULL;
+ size_t msglen = 0;
- if (n = getline(&m, &len, stdin), -1 == n) {
+ if (n = getline(&msg, &msglen, stdin), -1 == n) {
return -1;
}
- struct ice_candidate_t c = parse_ice_candidate(m);
-
- on_ice_candidate(c, NULL);
+ if (strstr(msg, "\"sdp\"")) {
+ // got offer. send answer.
+ printf("{\"sdp\":\"%s\",\"type\":\"answer\"}\n", trtc_create_answer(pc));
+ } else if (strstr(msg, "\"candidate\"")) {
+ struct trtc_ice_candidate_t c = parse_ice_candidate(msg);
+ on_ice_candidate(c, NULL);
+ trtc_add_ice_candidate(pc, c);
+ } else {
+ printf("unrecognized signaling message\n");
+ }
- add_ice_candidate(pc, c);
}
return 0;
diff --git a/example/tinyrtc.png b/example/tinyrtc.png
new file mode 100644
index 0000000..127dd06
--- /dev/null
+++ b/example/tinyrtc.png
Binary files differ
diff --git a/tinyrtc.c b/tinyrtc.c
new file mode 100644
index 0000000..2092224
--- /dev/null
+++ b/tinyrtc.c
@@ -0,0 +1,126 @@
+/**
+ * WebRTC implementation for tiny devices
+ *
+ * Copyright (c) 2022 Chris Hiszpanski. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include <stdbool.h>
+#include <stdio.h> // snprintf
+#include <string.h> // memset
+
+#include "tinyrtc.h"
+
+
+/// OPAQUE TYPE DEFINITIONS ////////////////////////////////////////////////
+
+struct trtc_peerconn_t {
+ bool active;
+
+ char offer[TRTC_MAX_SDP_SIZE];
+ char answer[TRTC_MAX_SDP_SIZE];
+
+ char l_ice_pwd[TRTC_MAX_ICE_PWD_SIZE];
+ char l_ice_ufrag[TRTC_MAX_ICE_UFRAG_SIZE];
+};
+
+
+/// STATIC ALLOCATIONS /////////////////////////////////////////////////////
+
+static struct trtc_peerconn_t peer_connection_pool[TRTC_MAX_PEER_CONNECTIONS];
+
+
+/// RTC PEER CONNECTION API ////////////////////////////////////////////////
+
+void rtc_init() {
+ memset(peer_connection_pool, 0, sizeof(peer_connection_pool));
+}
+
+struct trtc_peerconn_t* trtc_peer_connection(struct trtc_config_t cfg) {
+ for (int i = 0; i < TRTC_MAX_PEER_CONNECTIONS; i++) {
+ if (!peer_connection_pool[i].active) {
+ memset(&peer_connection_pool[i], 0, sizeof(struct trtc_peerconn_t));
+ peer_connection_pool[i].active = true;
+ return &peer_connection_pool[i];
+ }
+ }
+
+ return NULL;
+}
+
+int trtc_add_ice_candidate(struct trtc_peerconn_t *pc, const struct trtc_ice_candidate_t c) {
+ return -1;
+};
+
+const char * trtc_create_answer(struct trtc_peerconn_t *pc) {
+ unsigned char fp[32];
+
+ snprintf(pc->l_ice_ufrag, TRTC_MAX_ICE_UFRAG_SIZE, "xxxx"); // XXX
+ snprintf(pc->l_ice_pwd, TRTC_MAX_ICE_PWD_SIZE, "xxxxxxxxxxxxxxxxxxxxxx"); // XXX
+
+ snprintf(pc->answer, TRTC_MAX_SDP_SIZE,
+ "v=0\\r\\n"
+ "o=- 2210401696197537454 2 IN IP4 127.0.0.1\\r\\n" // XXX
+ "s=-\\r\\n"
+ "t=0 0\\r\\n"
+ "a=group:BUNDLE 0\\r\\n"
+ "a=msid-semantic: WMS\\r\\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 98\\r\\n" // XXX
+ "c=IN IP4 0.0.0.0\\r\\n"
+ "a=rtcp:9 IN IP4 0.0.0.0\\r\\n"
+ "a=ice-ufrag:%s\\r\\n"
+ "a=ice-pwd:%s\\r\\n"
+ "a=ice-options:trickle\\r\\n"
+ "a=fingerprint:sha-256 "
+ "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:"
+ "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:"
+ "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:"
+ "%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX\\r\\n"
+ "a=setup:passive\\r\\n"
+ "a=mid:0\\r\\n"
+ "a=sendonly\\r\\n"
+ "a=rtcp-mux\\r\\n"
+ "a=rtcp-rsize\\r\\n"
+ "a=rtpmap:98 H264/90000\\r\\n"
+ "a=rtcp-fb:98 nack\\r\\n"
+ "a=rtcp-fb:98 nack pli\\r\\n"
+ "a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\\r\\n",
+ pc->l_ice_ufrag,
+ pc->l_ice_pwd,
+ fp[ 0], fp[ 1], fp[ 2], fp[ 3], fp[ 4], fp[ 5], fp[ 6], fp[ 7],
+ fp[ 8], fp[ 9], fp[10], fp[11], fp[12], fp[13], fp[14], fp[15],
+ fp[16], fp[17], fp[18], fp[19], fp[20], fp[21], fp[22], fp[23],
+ fp[24], fp[25], fp[26], fp[27], fp[28], fp[29], fp[30], fp[31]
+ );
+
+ return pc->answer;
+};
+
+int trtc_set_local_description(struct trtc_peerconn_t *pc, const char *sdp) {
+ return -1;
+};
+
+int trtc_set_remote_description(struct trtc_peerconn_t *pc, const char *sdp) {
+ return -1;
+};
diff --git a/tinyrtc.h b/tinyrtc.h
index 1d66b78..205ae1b 100644
--- a/tinyrtc.h
+++ b/tinyrtc.h
@@ -29,46 +29,62 @@
#ifndef TINYRTC_H
#define TINYRTC_H
-struct peerconn_t {
-};
+#define TRTC_MAX_ICE_CANDIDATE_SIZE 256
+#define TRTC_MAX_ICE_SERVER_CREDENTIAL_SIZE 128
+#define TRTC_MAX_ICE_SERVERS 2
+#define TRTC_MAX_ICE_SERVER_URL_SIZE 128
+#define TRTC_MAX_ICE_SERVER_URLS 3
+#define TRTC_MAX_ICE_SERVER_USERNAME_SIZE 128
+#define TRTC_MAX_ICE_CANDIDATE_USERNAME_FRAGMENT_SIZE 8
+#define TRTC_MAX_ICE_CANDIDATE_SDP_MID_SIZE 32
+#define TRTC_MAX_PEER_CONNECTIONS 5
+#define TRTC_MAX_SDP_SIZE 4096
+#define TRTC_MAX_ICE_UFRAG_SIZE 5
+#define TRTC_MAX_ICE_PWD_SIZE 32
-struct rtc_ice_server_t {
- char credential[128]; // XXX only password type supported
- char urls[3][128];
- char username[128];
-};
-struct configuration_t {
- struct rtc_ice_server_t ice_servers[3];
-};
+/// PRIVATE TYPE DEFINITIONS ///////////////////////////////////////////////
-struct ice_candidate_t {
- char candidate[256];
- int sdp_mline_index;
- char sdp_mid[32];
- char username_fragment[8];
-};
+struct trtc_peerconn_t;
-typedef int (on_ice_candidate_t)(const struct ice_candidate_t c, void *arg);
-struct peerconn_t* rtc_peer_connection(struct configuration_t cfg) {
- return 0;
-}
+/// PUBLIC TYPE DEFINITIONS ////////////////////////////////////////////////
-int add_ice_candidate(struct peerconn_t *pc, const struct ice_candidate_t c) {
- return -1;
+struct trtc_ice_server_t {
+ char credential[TRTC_MAX_ICE_SERVER_CREDENTIAL_SIZE];
+ char urls[3][TRTC_MAX_ICE_SERVER_URL_SIZE];
+ char username[TRTC_MAX_ICE_SERVER_USERNAME_SIZE];
};
-int create_answer(struct peerconn_t *pc) {
- return -1;
+struct trtc_config_t {
+ struct trtc_ice_server_t ice_servers[TRTC_MAX_ICE_SERVERS];
};
-int set_local_description(struct peerconn_t *pc, const char *sdp) {
- return -1;
+struct trtc_ice_candidate_t {
+ char candidate[TRTC_MAX_ICE_CANDIDATE_SIZE];
+ int sdp_mline_index;
+ char sdp_mid[TRTC_MAX_ICE_CANDIDATE_SDP_MID_SIZE];
+ char username_fragment[TRTC_MAX_ICE_CANDIDATE_USERNAME_FRAGMENT_SIZE];
};
-int set_remote_description(struct peerconn_t *pc, const char *sdp) {
- return -1;
-};
+
+/// CALLBACKS //////////////////////////////////////////////////////////////
+
+typedef int (trtc_on_ice_candidate_t)(const struct trtc_ice_candidate_t c, void *arg);
+
+
+/// RTC PEER CONNECTION API ////////////////////////////////////////////////
+
+struct trtc_peerconn_t* trtc_peer_connection(struct trtc_config_t cfg);
+
+int trtc_add_ice_candidate(struct trtc_peerconn_t *pc, const struct trtc_ice_candidate_t c);
+
+int trtc_add_track(struct trtc_peerconn_t *pc);
+
+const char * trtc_create_answer(struct trtc_peerconn_t *pc);
+
+int trtc_set_local_description(struct trtc_peerconn_t *pc, const char *sdp);
+
+int trtc_set_remote_description(struct trtc_peerconn_t *pc, const char *sdp);
#endif