// Simple example of a mock IP camera. Answers WebRTC offer and streams H.264. #include #include #include #include #include #include "jsmn.h" #include "tinyrtc.h" // Helper function for parsing JSON static bool matches(const char *json, jsmntok_t *tok, const char *s) { if (JSMN_STRING != tok->type) return false; if (strlen(s) != tok->end - tok->start) return false; return 0 == strncmp(json + tok->start, s, tok->end - tok->start); } // Parses ICE candidate from stringified JSON struct trtc_ice_candidate_t parse_ice_candidate(const char *s) { struct trtc_ice_candidate_t c = { 0 }; int i, r; jsmn_parser p; jsmntok_t t[16]; jsmn_init(&p); r = jsmn_parse(&p, s, strlen(s), t, sizeof(t) / sizeof(t[0])); if (r < 0) { printf("%s:%d: failed to parse json", __func__, __LINE__); return c; } if (r < 1 || t[0].type != JSMN_OBJECT) { printf("%s:%d: object expected", __func__, __LINE__); return c; } for (i = 1; i < r; i++) { if (matches(s, &t[i], "candidate")) { strncpy(c.candidate, s + t[i + 1].start, t[i + 1].end - t[i + 1].start); i++; } else if (matches(s, &t[i], "sdpMid")) { strncpy(c.sdp_mid, s + t[i + 1].start, t[i + 1].end - t[i + 1].start); i++; } else if (matches(s, &t[i], "sdpMLineIndex")) { c.sdp_mline_index = atoi(s + t[i + 1].start); i++; } else if (matches(s, &t[i], "usernameFragment")) { strncpy(c.username_fragment, s + t[i + 1].start, t[i + 1].end - t[i + 1].start); i++; } } return c; } // (callback) Called for each discovered local ICE candidate int on_ice_candidate(const struct trtc_ice_candidate_t c, void *arg) { // send ice candidate over signaling channel printf("{" "\"candidate\":\"%s\"," "\"sdpMLineIndex\":%d," "\"sdpMid\":\"%s\"," "\"usernameFragment\":null" "}\n", c.candidate, c.sdp_mline_index, c.sdp_mid); return 0; } int main(int argc, char **argv) { // disable stdout buffering to ensure signaling messages send immediately setvbuf(stdout, NULL, _IONBF, 0); // create peer connection struct trtc_config_t cfg = { .ice_servers = { { .urls = { "stun:stun.liburtc.org", }, } } }; struct trtc_peerconn_t* pc = trtc_peer_connection(cfg); while (true) { int n; char *msg = NULL; size_t msglen = 0; if (n = getline(&msg, &msglen, stdin), -1 == n) { return -1; } 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"); } } return 0; }