summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/index.js6
-rw-r--r--example/main.c35
-rw-r--r--tinyrtc.c143
-rw-r--r--tinyrtc.h46
4 files changed, 215 insertions, 15 deletions
diff --git a/example/index.js b/example/index.js
index a161a10..6eae9b3 100644
--- a/example/index.js
+++ b/example/index.js
@@ -1,4 +1,5 @@
window.onload = function demo() {
+
// create peer connection
let pc = new RTCPeerConnection({
iceCandidatePoolSize: 4
@@ -27,10 +28,13 @@ window.onload = function demo() {
if ('candidate' in d) {
if (d.candidate) {
console.log("remote candidate:\n%c%s", "color: blue;", d.candidate);
+ pc.addIceCandidate(d).catch((e) => {
+ console.log("addIceCandidate:\n%c%s", "color: red;", e);
+ });
}
} else if ('sdp' in d) {
pc.setRemoteDescription(d).catch((e) => {
- console.log("local error:\n%c%s", "color: red;", e);
+ console.log("setRemoteDescription:\n%c%s", "color: red;", e);
});
console.log("remote answer:\n%c%s", "color: blue;", d.sdp);
}
diff --git a/example/main.c b/example/main.c
index 33ef4bb..e850a40 100644
--- a/example/main.c
+++ b/example/main.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
#include <unistd.h>
#include "jsmn.h"
@@ -60,7 +61,7 @@ struct trtc_ice_candidate_t parse_ice_candidate(const char *s)
}
// (callback) Called for each discovered local ICE candidate
-int on_ice_candidate(const struct trtc_ice_candidate_t c, void *arg) {
+void on_ice_candidate(const struct trtc_ice_candidate_t c, void *arg) {
// send ice candidate over signaling channel
printf("{"
"\"candidate\":\"%s\","
@@ -68,15 +69,18 @@ int on_ice_candidate(const struct trtc_ice_candidate_t c, void *arg) {
"\"sdpMid\":\"%s\","
"\"usernameFragment\":null"
"}\n", c.candidate, c.sdp_mline_index, c.sdp_mid);
-
- return 0;
}
int main(int argc, char **argv)
{
+ openlog(NULL, LOG_PERROR, LOG_USER);
+
// disable stdout buffering to ensure signaling messages send immediately
setvbuf(stdout, NULL, _IONBF, 0);
+ // initialize tinyrtc library
+ trtc_init();
+
// create peer connection
struct trtc_config_t cfg = {
.ice_servers = {
@@ -88,6 +92,12 @@ int main(int argc, char **argv)
}
};
struct trtc_peerconn_t* pc = trtc_peer_connection(cfg);
+ if (!pc) {
+ syslog(LOG_ERR, "trtc_peer_connection() failed");
+ return -1;
+ }
+
+ trtc_set_on_ice_candidate(pc, on_ice_candidate, NULL);
while (true) {
int n;
@@ -96,21 +106,32 @@ int main(int argc, char **argv)
if (n = getline(&msg, &msglen, stdin), -1 == n) {
+ syslog(LOG_ERR, "%m");
return -1;
}
+ // case: sdp offer
if (strstr(msg, "\"sdp\"")) {
- // got offer. send answer.
- printf("{\"sdp\":\"%s\",\"type\":\"answer\"}\n", trtc_create_answer(pc));
+ // XXX trtc_set_remote_description(pc, offer);
+ const char *answer = trtc_create_answer(pc);
+
+ /* send SDP answer via stdout signaling channel */
+ printf("{\"sdp\":\"%s\",\"type\":\"answer\"}\n", answer);
+
+ trtc_set_local_description(pc, answer);
+
+ // case: ice candidate
} 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);
+
+ // case: error
} else {
printf("unrecognized signaling message\n");
}
-
}
+
+ syslog(LOG_ERR, "terminating");
return 0;
}
diff --git a/tinyrtc.c b/tinyrtc.c
index 2092224..2b74890 100644
--- a/tinyrtc.c
+++ b/tinyrtc.c
@@ -26,9 +26,16 @@
* OF SUCH DAMAGE.
*/
+#include <ifaddrs.h> // freeifaddrs, getifaddrs
#include <stdbool.h>
#include <stdio.h> // snprintf
#include <string.h> // memset
+#include <unistd.h> // close
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
#include "tinyrtc.h"
@@ -41,8 +48,21 @@ struct trtc_peerconn_t {
char offer[TRTC_MAX_SDP_SIZE];
char answer[TRTC_MAX_SDP_SIZE];
+ /* local description */
+ const char* ldesc;
+
+ /* remote description */
+ const char* rdesc;
+
char l_ice_pwd[TRTC_MAX_ICE_PWD_SIZE];
char l_ice_ufrag[TRTC_MAX_ICE_UFRAG_SIZE];
+
+ /* onIceCandidate callback */
+ trtc_on_ice_candidate_t* on_ice_candidate;
+ void* on_ice_candidate_arg;
+
+ /* tcp host candidate socket */
+ int host_tcp_fd;
};
@@ -53,20 +73,131 @@ static struct trtc_peerconn_t peer_connection_pool[TRTC_MAX_PEER_CONNECTIONS];
/// RTC PEER CONNECTION API ////////////////////////////////////////////////
-void rtc_init() {
+void trtc_init() {
memset(peer_connection_pool, 0, sizeof(peer_connection_pool));
}
+/**
+ * Get host candidates
+ *
+ * \return 0 on success, -1 on error.
+ */
+static int get_host_candidates(struct trtc_peerconn_t* pc) {
+ struct ifaddrs *ifaddr, *ifa;
+ socklen_t laddrlen;
+
+ /* sanity check */
+ if (!pc) return -1;
+
+ /* create tcp socket */
+ pc->host_tcp_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (-1 == pc->host_tcp_fd) {
+ return -1;
+ }
+
+ /* bind to arbitrary port */
+ struct sockaddr_in laddr = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = INADDR_ANY,
+ .sin_port = 0,
+ };
+ if (-1 == bind(pc->host_tcp_fd, (struct sockaddr*)&laddr, sizeof(laddr))) {
+ return -1;
+ }
+ laddrlen = sizeof(struct sockaddr_in);
+ if (-1 == getsockname(pc->host_tcp_fd, (struct sockaddr *)&laddr, &laddrlen)) {
+ return -1;
+ }
+
+ /* listen on socket */
+ if (-1 == listen(pc->host_tcp_fd, 0)) {
+ return -1;
+ }
+
+ /* get network interface addresses */
+ if (-1 == getifaddrs(&ifaddr)) {
+ return -1;
+ }
+
+ /* iterate over addresses */
+ for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr) continue;
+
+ /* skip loopback interface addresses */
+ if (IFF_LOOPBACK & ifa->ifa_flags) continue;
+
+ if (AF_INET == ifa->ifa_addr->sa_family) {
+ struct sockaddr_in *sa = (struct sockaddr_in*)ifa->ifa_addr;
+
+ /* host tcp candidate */
+ struct trtc_ice_candidate_t c = {
+ .sdp_mid = "0",
+ .sdp_mline_index = 0
+ };
+ snprintf(c.candidate, TRTC_MAX_ICE_CANDIDATE_SIZE,
+ "candidate:2894319779 1 tcp 212260223 %s %d typ host tcptype passive",
+ inet_ntoa(sa->sin_addr),
+ laddr.sin_port); // XXXX
+
+ /* callback */
+ if (pc->on_ice_candidate) {
+ pc->on_ice_candidate(c, pc->on_ice_candidate_arg);
+ }
+ }
+ }
+
+ freeifaddrs(ifaddr);
+
+ return 0;
+}
+
+/**
+ * Peer connection thread
+ *
+ * Each peer connection uses one background thread for stepping the ICE agent,
+ * handling timeouts, and sending/receiving packets.
+ *
+ * \param arg[in] User-specified argument.
+ *
+ * \return NULL.
+ */
+static void* peer_connection_thread(void *arg) {
+ return NULL;
+}
+
struct trtc_peerconn_t* trtc_peer_connection(struct trtc_config_t cfg) {
+ struct trtc_peerconn_t* pc = NULL;
+
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];
+ pc = &peer_connection_pool[i];
+ break;
}
}
- return NULL;
+ return pc;
+}
+
+void trtc_peer_connection_destroy(struct trtc_peerconn_t* pc) {
+ if (!pc) return;
+
+ close(pc->host_tcp_fd);
+
+ // XXX mark as available
+}
+
+int trtc_set_on_ice_candidate(
+ struct trtc_peerconn_t* pc,
+ trtc_on_ice_candidate_t* cb,
+ void* arg
+) {
+ if (!pc || !cb) return -1;
+
+ pc->on_ice_candidate = cb;
+ pc->on_ice_candidate_arg = arg;
+
+ return 0;
}
int trtc_add_ice_candidate(struct trtc_peerconn_t *pc, const struct trtc_ice_candidate_t c) {
@@ -83,6 +214,7 @@ const char * trtc_create_answer(struct trtc_peerconn_t *pc) {
"v=0\\r\\n"
"o=- 2210401696197537454 2 IN IP4 127.0.0.1\\r\\n" // XXX
"s=-\\r\\n"
+ "u=https://tinyrtc.org/\\r\\n"
"t=0 0\\r\\n"
"a=group:BUNDLE 0\\r\\n"
"a=msid-semantic: WMS\\r\\n"
@@ -118,9 +250,12 @@ const char * trtc_create_answer(struct trtc_peerconn_t *pc) {
};
int trtc_set_local_description(struct trtc_peerconn_t *pc, const char *sdp) {
+ pc->ldesc = sdp;
+ get_host_candidates(pc);
return -1;
};
int trtc_set_remote_description(struct trtc_peerconn_t *pc, const char *sdp) {
+ pc->rdesc = sdp;
return -1;
};
diff --git a/tinyrtc.h b/tinyrtc.h
index 205ae1b..ff29e15 100644
--- a/tinyrtc.h
+++ b/tinyrtc.h
@@ -70,21 +70,61 @@ struct trtc_ice_candidate_t {
/// CALLBACKS //////////////////////////////////////////////////////////////
-typedef int (trtc_on_ice_candidate_t)(const struct trtc_ice_candidate_t c, void *arg);
+typedef void (trtc_on_ice_candidate_t)(const struct trtc_ice_candidate_t c, void *arg);
/// RTC PEER CONNECTION API ////////////////////////////////////////////////
+/**
+ * Initialize library. Must call once before calling other functions.
+ */
+void trtc_init();
+
+/**
+ * Create new peer connection
+ *
+ * \param cfg[in] Configuration.
+ *
+ * \return Peer connection. NULL if all peer connections are already in use.
+ */
struct trtc_peerconn_t* trtc_peer_connection(struct trtc_config_t cfg);
+void trtc_peer_connection_destroy(struct trtc_peerconn_t* pc);
-int trtc_add_ice_candidate(struct trtc_peerconn_t *pc, const struct trtc_ice_candidate_t c);
+/**
+ * Adds remote ICE candidate to local ICE agent
+ *
+ * \param pc[in] Peer connection.
+ * \param c[in] ICE candidate from remote peer.
+ *
+ * \return 0 on success. -1 on error.
+ */
+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);
+/**
+ * Create SDP answer in response to a received SDP offer.
+ *
+ * \param pc[in] Peer connection.
+ *
+ * \return SDP answer. NULL on error.
+ */
const char * trtc_create_answer(struct trtc_peerconn_t *pc);
-int trtc_set_local_description(struct trtc_peerconn_t *pc, const char *sdp);
+/**
+ * Sets callback to call for each discovered local ICE candidate
+ *
+ * \param pc[in] Peer connection.
+ * \param cb[in] Callback function.
+ * \param arg[in] User-specified argument to pass to callback function.
+ *
+ * \return 0 on success. -1 on error.
+ */
+int trtc_set_on_ice_candidate(
+ struct trtc_peerconn_t* pc, trtc_on_ice_candidate_t* cb, void* arg);
+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