static void print_rtp_stats(const struct stream *s) { bool started = s->metric_tx.n_packets>0 || s->metric_rx.n_packets>0; if (!started) return; info("\n%-9s Transmit: Receive:\n" "packets: %7u %7u\n" "avg. bitrate: %7.1f %7.1f (kbit/s)\n" "errors: %7d %7d\n" , sdp_media_name(s->sdp), s->metric_tx.n_packets, s->metric_rx.n_packets, 1.0*metric_avg_bitrate(&s->metric_tx)/1000, 1.0*metric_avg_bitrate(&s->metric_rx)/1000, s->metric_tx.n_err, s->metric_rx.n_err ); if (s->rtcp_stats.tx.sent || s->rtcp_stats.rx.sent) { info("pkt.report: %7u %7u\n" "lost: %7d %7d\n" "jitter: %7.1f %7.1f (ms)\n", s->rtcp_stats.tx.sent, s->rtcp_stats.rx.sent, s->rtcp_stats.tx.lost, s->rtcp_stats.rx.lost, 1.0*s->rtcp_stats.tx.jit/1000, 1.0*s->rtcp_stats.rx.jit/1000); } }
static int start_crypto(struct menc_st *st, const struct pl *key_info) { size_t olen; int err; /* key-info is BASE64 encoded */ olen = sizeof(st->key_rx); err = base64_decode(key_info->p, key_info->l, st->key_rx, &olen); if (err) return err; if (SRTP_MASTER_KEY_LEN != olen) { DEBUG_WARNING("srtp keylen is %u (should be 30)\n", olen); } err = start_srtp(st, st->crypto_suite); if (err) return err; info("srtp: %s: SRTP is Enabled (cryptosuite=%s)\n", sdp_media_name(st->sdpm), st->crypto_suite); return 0; }
static int media_alloc(struct mnat_media **mp, struct mnat_sess *sess, int proto, void *sock1, void *sock2, struct sdp_media *sdpm) { struct mnat_media *m; struct sa laddr; struct pcp_map map; unsigned i; int err = 0; if (!mp || !sess || !sdpm || proto != IPPROTO_UDP) return EINVAL; m = mem_zalloc(sizeof(*m), media_destructor); if (!m) return ENOMEM; m->compc = sock2 ? 2 : 1; list_append(&sess->medial, &m->le, m); m->sess = sess; m->sdpm = mem_ref(sdpm); for (i=0; i<m->compc; i++) { struct comp *comp = &m->compv[i]; comp->id = i+1; comp->media = m; err = udp_local_get(i==0 ? sock1 : sock2, &laddr); if (err) goto out; rand_bytes(map.nonce, sizeof(map.nonce)); map.proto = proto; map.int_port = sa_port(&laddr); /* note: using same address-family as the PCP server */ sa_init(&map.ext_addr, sa_af(&pcp_srv)); info("pcp: %s: internal port for %s is %u\n", sdp_media_name(sdpm), i==0 ? "RTP" : "RTCP", map.int_port); err = pcp_request(&comp->pcp, NULL, &pcp_srv, PCP_MAP, LIFETIME, &map, pcp_resp_handler, comp, 0); if (err) goto out; } out: if (err) mem_deref(m); else if (mp) { *mp = m; } return err; }
int stream_print(struct re_printf *pf, const struct stream *s) { if (!s) return 0; return re_hprintf(pf, " %s=%u/%u", sdp_media_name(s->sdp), s->stats.bitrate_tx, s->stats.bitrate_rx); }
int stream_print(struct re_printf *pf, const struct stream *s) { if (!s) return 0; return re_hprintf(pf, " %s=%u/%u", sdp_media_name(s->sdp), s->metric_tx.cur_bitrate, s->metric_rx.cur_bitrate); }
static int start_crypto(struct menc_st *st, const struct pl *key_info) { size_t olen, len; char buf[64] = ""; int err; len = get_master_keylen(resolve_suite(st->crypto_suite)); /* key-info is BASE64 encoded */ olen = sizeof(st->key_rx); err = base64_decode(key_info->p, key_info->l, st->key_rx, &olen); if (err) return err; if (len != olen) { warning("srtp: %s: srtp keylen is %u (should be %zu)\n", st->crypto_suite, olen, len); } err = start_srtp(st, st->crypto_suite); if (err) return err; info("srtp: %s: SRTP is Enabled (cryptosuite=%s)\n", sdp_media_name(st->sdpm), st->crypto_suite); if (st->sess->eventh) { if (re_snprintf(buf, sizeof(buf), "%s,%s", sdp_media_name(st->sdpm), st->crypto_suite)) st->sess->eventh(MENC_EVENT_SECURE, buf, st->sess->arg); else warning("srtp: failed to print secure" " event arguments\n"); } return 0; }
/* TODO: should we check RTP per stream, or should we have the * check in struct call instead? */ static void check_rtp_handler(void *arg) { struct stream *strm = arg; const uint64_t now = tmr_jiffies(); int diff_ms; tmr_start(&strm->tmr_rtp, RTP_CHECK_INTERVAL, check_rtp_handler, strm); /* If no RTP was received at all, check later */ if (!strm->ts_last) return; /* We are in sendrecv mode, check when the last RTP packet * was received. */ if (sdp_media_dir(strm->sdp) == SDP_SENDRECV) { diff_ms = (int)(now - strm->ts_last); debug("stream: last \"%s\" RTP packet: %d milliseconds\n", sdp_media_name(strm->sdp), diff_ms); if (diff_ms > (int)strm->rtp_timeout_ms) { info("stream: no %s RTP packets received for" " %d milliseconds\n", sdp_media_name(strm->sdp), diff_ms); stream_close(strm, ETIMEDOUT); } } else { re_printf("check_rtp: not checking (dir=%s)\n", sdp_dir_name(sdp_media_dir(strm->sdp))); } }
/* todo: detect multiple responses */ static void pcp_resp_handler(int err, struct pcp_msg *msg, void *arg) { struct comp *comp = arg; struct mnat_media *m = comp->media; const struct pcp_map *map; if (err) { warning("pcp: mapping error: %m\n", err); complete(m->sess, err, NULL); return; } else if (msg->hdr.result != PCP_SUCCESS) { warning("pcp: mapping error: %s\n", pcp_result_name(msg->hdr.result)); re_printf("%H\n", pcp_msg_print, msg); complete(m->sess, EPROTO, "pcp error"); return; } map = pcp_msg_payload(msg); info("pcp: %s: mapping granted for %s:" " internal_port=%u, external_addr=%J (lifetime %u seconds)\n", sdp_media_name(m->sdpm), comp->id==1 ? "RTP" : "RTCP", map->int_port, &map->ext_addr, msg->hdr.lifetime); /* Update SDP media with external IP-address mapping */ if (comp->id == 1) sdp_media_set_laddr(m->sdpm, &map->ext_addr); else sdp_media_set_laddr_rtcp(m->sdpm, &map->ext_addr); comp->granted = true; m->srv_epoch = msg->hdr.epoch; is_complete(m->sess); }
int stream_debug(struct re_printf *pf, const struct stream *s) { struct sa rrtcp; int err; if (!s) return 0; err = re_hprintf(pf, " %s dir=%s pt_enc=%d\n", sdp_media_name(s->sdp), sdp_dir_name(sdp_media_dir(s->sdp)), s->pt_enc); sdp_media_raddr_rtcp(s->sdp, &rrtcp); err |= re_hprintf(pf, " remote: %J/%J\n", sdp_media_raddr(s->sdp), &rrtcp); err |= rtp_debug(pf, s->rtp); err |= jbuf_debug(pf, s->jbuf); return err; }
int stream_jbuf_stat(struct re_printf *pf, const struct stream *s) { struct jbuf_stat stat; int err; if (!s) return EINVAL; err = re_hprintf(pf, " %s:", sdp_media_name(s->sdp)); err |= jbuf_stats(s->jbuf, &stat); if (err) { err = re_hprintf(pf, "Jbuf stat: (not available)"); } else { err = re_hprintf(pf, "Jbuf stat: put=%u get=%u or=%u ur=%u", stat.n_put, stat.n_get, stat.n_overflow, stat.n_underflow); } return err; }
static void stream_remote_set(struct stream *s) { struct sa rtcp; if (!s) return; /* RFC 5761 */ if (s->cfg.rtcp_mux && sdp_media_rattr(s->sdp, "rtcp-mux")) { if (!s->rtcp_mux) info("%s: RTP/RTCP multiplexing enabled\n", sdp_media_name(s->sdp)); s->rtcp_mux = true; } rtcp_enable_mux(s->rtp, s->rtcp_mux); sdp_media_raddr_rtcp(s->sdp, &rtcp); rtcp_start(s->rtp, s->cname, s->rtcp_mux ? sdp_media_raddr(s->sdp): &rtcp); }
static void stream_remote_set(struct stream *s, const char *cname) { struct sa rtcp; if (!s) return; /* RFC 5761 */ if (config.avt.rtcp_mux && sdp_media_rattr(s->sdp, "rtcp-mux")) { if (!s->rtcp_mux) (void)re_printf("%s: RTP/RTCP multiplexing enabled\n", sdp_media_name(s->sdp)); s->rtcp_mux = true; } rtcp_enable_mux(s->rtp, s->rtcp_mux); sdp_media_raddr_rtcp(s->sdp, &rtcp); rtcp_start(s->rtp, cname, s->rtcp_mux ? sdp_media_raddr(s->sdp): &rtcp); }
static int comp_alloc(struct comp *comp, void *sock) { struct sa laddr; int err; err = udp_local_get(sock, &laddr); if (err) goto out; comp->int_port = sa_port(&laddr); info("natpmp: `%s' stream comp %u local UDP port is %u\n", sdp_media_name(comp->media->sdpm), comp->id, comp->int_port); err = natpmp_mapping_request(&comp->natpmp, &natpmp_srv, comp->int_port, 0, comp->lifetime, natpmp_resp_handler, comp); if (err) goto out; out: return err; }
static void rtp_recv(const struct sa *src, const struct rtp_header *hdr, struct mbuf *mb, void *arg) { struct stream *s = arg; bool flush = false; int err; s->ts_last = tmr_jiffies(); if (!mbuf_get_left(mb)) return; if (!(sdp_media_ldir(s->sdp) & SDP_RECVONLY)) return; metric_add_packet(&s->metric_rx, mbuf_get_left(mb)); if (hdr->ssrc != s->ssrc_rx) { if (s->ssrc_rx) { flush = true; info("stream: %s: SSRC changed %x -> %x" " (%u bytes from %J)\n", sdp_media_name(s->sdp), s->ssrc_rx, hdr->ssrc, mbuf_get_left(mb), src); } s->ssrc_rx = hdr->ssrc; } if (s->jbuf) { struct rtp_header hdr2; void *mb2 = NULL; /* Put frame in Jitter Buffer */ if (flush) jbuf_flush(s->jbuf); err = jbuf_put(s->jbuf, hdr, mb); if (err) { info("%s: dropping %u bytes from %J (%m)\n", sdp_media_name(s->sdp), mb->end, src, err); s->metric_rx.n_err++; } if (jbuf_get(s->jbuf, &hdr2, &mb2)) { if (!s->jbuf_started) return; memset(&hdr2, 0, sizeof(hdr2)); } s->jbuf_started = true; if (lostcalc(s, hdr2.seq) > 0) s->rtph(hdr, NULL, s->arg); s->rtph(&hdr2, mb2, s->arg); mem_deref(mb2); } else { if (lostcalc(s, hdr->seq) > 0) s->rtph(hdr, NULL, s->arg); s->rtph(hdr, mb, s->arg); } }