int stream_alloc(struct stream **sp, const struct config_avt *cfg, struct call *call, struct sdp_session *sdp_sess, const char *name, int label, const struct mnat *mnat, struct mnat_sess *mnat_sess, const struct menc *menc, struct menc_sess *menc_sess, const char *cname, stream_rtp_h *rtph, stream_rtcp_h *rtcph, void *arg) { struct stream *s; int err; if (!sp || !cfg || !call || !rtph) return EINVAL; s = mem_zalloc(sizeof(*s), stream_destructor); if (!s) return ENOMEM; s->cfg = *cfg; s->call = call; s->rtph = rtph; s->rtcph = rtcph; s->arg = arg; s->pseq = -1; s->rtcp = s->cfg.rtcp_enable; err = stream_sock_alloc(s, call_af(call)); if (err) { warning("stream: failed to create socket for media '%s'" " (%m)\n", name, err); goto out; } err = str_dup(&s->cname, cname); if (err) goto out; /* Jitter buffer */ if (cfg->jbuf_del.min && cfg->jbuf_del.max) { err = jbuf_alloc(&s->jbuf, cfg->jbuf_del.min, cfg->jbuf_del.max); if (err) goto out; } err = sdp_media_add(&s->sdp, sdp_sess, name, sa_port(rtp_local(s->rtp)), (menc && menc->sdp_proto) ? menc->sdp_proto : sdp_proto_rtpavp); if (err) goto out; if (label) { err |= sdp_media_set_lattr(s->sdp, true, "label", "%d", label); } /* RFC 5506 */ if (s->rtcp) err |= sdp_media_set_lattr(s->sdp, true, "rtcp-rsize", NULL); /* RFC 5576 */ if (s->rtcp) { err |= sdp_media_set_lattr(s->sdp, true, "ssrc", "%u cname:%s", rtp_sess_ssrc(s->rtp), cname); } /* RFC 5761 */ if (cfg->rtcp_mux) err |= sdp_media_set_lattr(s->sdp, true, "rtcp-mux", NULL); if (err) goto out; if (mnat) { err = mnat->mediah(&s->mns, mnat_sess, IPPROTO_UDP, rtp_sock(s->rtp), s->rtcp ? rtcp_sock(s->rtp) : NULL, s->sdp); if (err) goto out; } if (menc) { s->menc = menc; s->mencs = mem_ref(menc_sess); err = menc->mediah(&s->mes, menc_sess, s->rtp, IPPROTO_UDP, rtp_sock(s->rtp), s->rtcp ? rtcp_sock(s->rtp) : NULL, s->sdp); if (err) goto out; } if (err) goto out; s->pt_enc = -1; metric_init(&s->metric_tx); metric_init(&s->metric_rx); list_append(call_streaml(call), &s->le, s); out: if (err) mem_deref(s); else *sp = s; return err; }
int stream_alloc(struct stream **sp, struct call *call, struct sdp_session *sdp_sess, const char *name, int label, const struct mnat *mnat, struct mnat_sess *mnat_sess, const struct menc *menc, struct menc_sess *menc_sess, stream_rtp_h *rtph, stream_rtcp_h *rtcph, void *arg) { struct stream *s; int err; if (!sp || !call || !rtph) return EINVAL; s = mem_zalloc(sizeof(*s), stream_destructor); if (!s) return ENOMEM; MAGIC_INIT(s); tmr_init(&s->tmr_stats); s->call = call; if (!str_casecmp(name, "audio")) s->type = STREAM_AUDIO; else if (!str_casecmp(name, "video")) s->type = STREAM_VIDEO; else s->type = STREAM_UNKNOWN; s->rtph = rtph; s->rtcph = rtcph; s->arg = arg; s->pseq = -1; s->rtcp = config.avt.rtcp_enable; err = stream_sock_alloc(s, call_af(call)); if (err) goto out; /* Jitter buffer */ if (config.avt.jbuf_del.min && config.avt.jbuf_del.max) { err = jbuf_alloc(&s->jbuf, config.avt.jbuf_del.min, config.avt.jbuf_del.max); if (err) goto out; } err = sdp_media_add(&s->sdp, sdp_sess, name, sa_port(rtp_local(s->rtp)), (menc && menc->sdp_proto) ? menc->sdp_proto : sdp_proto_rtpavp); if (err) goto out; if (label) { err |= sdp_media_set_lattr(s->sdp, true, "label", "%d", label); } /* RFC 5761 */ if (config.avt.rtcp_mux) err |= sdp_media_set_lattr(s->sdp, true, "rtcp-mux", NULL); if (mnat) { err |= mnat->mediah(&s->mns, mnat_sess, IPPROTO_UDP, rtp_sock(s->rtp), (s->rtcp && !config.avt.rtcp_mux) ? rtcp_sock(s->rtp) : NULL, s->sdp); } if (menc) { s->menc = menc; s->mencs = mem_ref(menc_sess); err |= menc->mediah(&s->mes, menc_sess, IPPROTO_UDP, rtp_sock(s->rtp), s->rtcp ? rtcp_sock(s->rtp) : NULL, s->sdp); } if (err) goto out; s->pt_enc = -1; list_append(call_streaml(call), &s->le, s); out: if (err) mem_deref(s); else *sp = s; return err; }