diff --git a/include/re_mbuf.h b/include/re_mbuf.h index feac6fd05..73b6290fd 100644 --- a/include/re_mbuf.h +++ b/include/re_mbuf.h @@ -41,6 +41,7 @@ struct pl; struct re_printf; struct mbuf *mbuf_alloc(size_t size); +struct mbuf *mbuf_dup(struct mbuf *mbd); struct mbuf *mbuf_alloc_ref(struct mbuf *mbr); void mbuf_init(struct mbuf *mb); void mbuf_reset(struct mbuf *mb); diff --git a/include/re_rtp.h b/include/re_rtp.h index 6fce3fa55..53b1c17eb 100644 --- a/include/re_rtp.h +++ b/include/re_rtp.h @@ -221,13 +221,19 @@ int rtp_hdr_encode(struct mbuf *mb, const struct rtp_header *hdr); int rtp_hdr_decode(struct rtp_header *hdr, struct mbuf *mb); int rtp_encode(struct rtp_sock *rs, bool ext, bool marker, uint8_t pt, uint32_t ts, struct mbuf *mb); +int rtp_encode_seq(struct rtp_sock *rs, uint16_t seq, bool ext, bool marker, + uint8_t pt, uint32_t ts, struct mbuf *mb); int rtp_decode(struct rtp_sock *rs, struct mbuf *mb, struct rtp_header *hdr); int rtp_send(struct rtp_sock *rs, const struct sa *dst, bool ext, bool marker, uint8_t pt, uint32_t ts, uint64_t jfs_rt, struct mbuf *mb); +int rtp_resend(struct rtp_sock *rs, uint16_t seq, const struct sa *dst, + bool ext, bool marker, uint8_t pt, uint32_t ts, + struct mbuf *mb); int rtp_debug(struct re_printf *pf, const struct rtp_sock *rs); void *rtp_sock(const struct rtp_sock *rs); uint32_t rtp_sess_ssrc(const struct rtp_sock *rs); +uint16_t rtp_sess_seq(const struct rtp_sock *rs); const struct sa *rtp_local(const struct rtp_sock *rs); int rtp_clear(struct rtp_sock *rs); diff --git a/src/mbuf/mbuf.c b/src/mbuf/mbuf.c index 6fe47bd00..572873557 100644 --- a/src/mbuf/mbuf.c +++ b/src/mbuf/mbuf.c @@ -48,6 +48,34 @@ struct mbuf *mbuf_alloc(size_t size) } +/** + * Duplicate memory buffer + * + * @param mbd Memory buffer to duplicate + * + * @return Duplicated memory buffer, NULL if no memory + */ +struct mbuf *mbuf_dup(struct mbuf *mbd) +{ + struct mbuf *mb; + + if (!mbd) + return NULL; + + mb = mbuf_alloc(mbd->size); + if (!mb) + return NULL; + + mb->size = mbd->size; + mb->pos = mbd->pos; + mb->end = mbd->end; + + memcpy(mb->buf, mbd->buf, mbd->size); + + return mb; +} + + /** * Allocate a new memory buffer with a reference to another mbuf * diff --git a/src/rtp/rtp.c b/src/rtp/rtp.c index e6b1c1b86..81d182211 100644 --- a/src/rtp/rtp.c +++ b/src/rtp/rtp.c @@ -378,6 +378,43 @@ int rtp_open(struct rtp_sock **rsp, int af) } +/** + * Encode a new RTP header with sequence into the beginning of the buffer + * + * @param rs RTP Socket + * @param seq Sequence Number + * @param ext Extension bit + * @param marker Marker bit + * @param pt Payload type + * @param ts Timestamp + * @param mb Memory buffer + * + * @return 0 for success, otherwise errorcode + * + * @note The buffer must have enough space for the RTP header + */ +int rtp_encode_seq(struct rtp_sock *rs, uint16_t seq, bool ext, bool marker, + uint8_t pt, uint32_t ts, struct mbuf *mb) +{ + struct rtp_header hdr; + + if (!rs || pt&~0x7f || !mb) + return EINVAL; + + hdr.ver = RTP_VERSION; + hdr.pad = false; + hdr.ext = ext; + hdr.cc = 0; + hdr.m = marker ? 1 : 0; + hdr.pt = pt; + hdr.seq = seq; + hdr.ts = ts; + hdr.ssrc = rs->enc.ssrc; + + return rtp_hdr_encode(mb, &hdr); +} + + /** * Encode a new RTP header into the beginning of the buffer * @@ -406,7 +443,7 @@ int rtp_encode(struct rtp_sock *rs, bool ext, bool marker, uint8_t pt, hdr.cc = 0; hdr.m = marker ? 1 : 0; hdr.pt = pt; - hdr.seq = rs->enc.seq++; + hdr.seq = ++rs->enc.seq; hdr.ts = ts; hdr.ssrc = rs->enc.ssrc; @@ -493,6 +530,50 @@ int rtp_send(struct rtp_sock *rs, const struct sa *dst, bool ext, } +/** + * Resend an RTP packet to a peer (no rtcp update) + * + * @param rs RTP Socket + * @param seq Sequence Number + * @param dst Destination address + * @param ext Extension bit + * @param marker Marker bit + * @param pt Payload type + * @param ts Timestamp + * @param mb Payload buffer + * + * @return 0 for success, otherwise errorcode + */ +int rtp_resend(struct rtp_sock *rs, uint16_t seq, const struct sa *dst, + bool ext, bool marker, uint8_t pt, uint32_t ts, struct mbuf *mb) +{ + size_t pos; + int err; + + if (!rs || !mb) + return EINVAL; + + if (mb->pos < RTP_HEADER_SIZE) { + DEBUG_WARNING("rtp_send: buffer must have space for" + " rtp header (pos=%u, end=%u)\n", + mb->pos, mb->end); + return EBADMSG; + } + + mbuf_advance(mb, -RTP_HEADER_SIZE); + + pos = mb->pos; + + err = rtp_encode_seq(rs, seq, ext, marker, pt, ts, mb); + if (err) + return err; + + mb->pos = pos; + + return udp_send(rs->sock_rtp, dst, mb); +} + + /** * Get the RTP transport socket from an RTP/RTCP Socket * @@ -545,6 +626,19 @@ uint32_t rtp_sess_ssrc(const struct rtp_sock *rs) } +/** + * Get the last Sequence number from an RTP/RTCP Socket + * + * @param rs RTP Socket + * + * @return Sequence number + */ +uint16_t rtp_sess_seq(const struct rtp_sock *rs) +{ + return rs ? rs->enc.seq : 0; +} + + /** * Get the RTCP-Session for an RTP/RTCP Socket *