diff --git a/modules/media_exchange/media_utils.c b/modules/media_exchange/media_utils.c index 0b98288ed88..e7057cf1122 100644 --- a/modules/media_exchange/media_utils.c +++ b/modules/media_exchange/media_utils.c @@ -235,7 +235,7 @@ int media_fork_offer(struct media_session_leg *msl, { if (media_rtp.copy_offer(msl->ms->rtp, &media_exchange_name, NULL, mf->flags, - mf->streams, body) < 0) { + mf->streams, body, NULL) < 0) { LM_ERR("could not get copy SDP\n"); return -1; } @@ -290,7 +290,7 @@ int media_fork_pause_resume(struct media_session_leg *msl, int medianum, int res flags |= RTP_COPY_MODE_DISABLE; if (media_rtp.copy_offer(msl->ms->rtp, - &media_exchange_name, NULL, flags, todo, &body) < 0) { + &media_exchange_name, NULL, flags, todo, &body, NULL) < 0) { LM_ERR("could not get copy SDP\n"); MEDIA_LEG_STATE_SET_UNSAFE(msl, MEDIA_SESSION_STATE_RUNNING); return -1; diff --git a/modules/rtp_relay/rtp_relay.h b/modules/rtp_relay/rtp_relay.h index c7ce07650e6..d971f0cc7c1 100644 --- a/modules/rtp_relay/rtp_relay.h +++ b/modules/rtp_relay/rtp_relay.h @@ -57,7 +57,8 @@ struct rtp_relay_funcs { int (*copy_offer)(struct rtp_relay_session *sess, struct rtp_relay_server *server, void **ctx, str *flags, - unsigned int copy_flags, unsigned int streams, str *ret); + unsigned int copy_flags, unsigned int streams, str *ret, + struct rtp_relay_streams *streams_map); int (*copy_answer)(struct rtp_relay_session *sess, struct rtp_relay_server *server, void *ctx, str *flags, str *body); diff --git a/modules/rtp_relay/rtp_relay_common.h b/modules/rtp_relay/rtp_relay_common.h index 441f00e62bb..d260d02b8b7 100644 --- a/modules/rtp_relay/rtp_relay_common.h +++ b/modules/rtp_relay/rtp_relay_common.h @@ -32,5 +32,17 @@ #define RTP_COPY_LEG_CALLEE (1<<3) #define RTP_COPY_LEG_BOTH \ (RTP_COPY_LEG_CALLER|RTP_COPY_LEG_CALLEE) +#define RTP_COPY_MAX_STREAMS 32 + +struct rtp_relay_stream { + int leg; + int medianum; + int label; +}; + +struct rtp_relay_streams { + int count; + struct rtp_relay_stream streams[RTP_COPY_MAX_STREAMS]; +}; #endif /* _RTP_RELAY_COMMON_H_ */ diff --git a/modules/rtp_relay/rtp_relay_ctx.c b/modules/rtp_relay/rtp_relay_ctx.c index 31005d1926b..9b779087bd8 100644 --- a/modules/rtp_relay/rtp_relay_ctx.c +++ b/modules/rtp_relay/rtp_relay_ctx.c @@ -2701,7 +2701,8 @@ int rtp_relay_api_delete(rtp_ctx _ctx, str *id, unsigned int flags) } int rtp_relay_copy_offer(rtp_ctx _ctx, str *id, str *flags, - unsigned int copy_flags, unsigned int streams, str *ret_body) + unsigned int copy_flags, unsigned int streams, str *ret_body, + struct rtp_relay_streams *ret_streams) { int release = 0; struct rtp_relay_session info; @@ -2742,7 +2743,8 @@ int rtp_relay_copy_offer(rtp_ctx _ctx, str *id, str *flags, info.to_tag = &ctx->to_tag; info.branch = sess->index; if (sess->relay->funcs.copy_offer(&info, &sess->server, - &rtp_copy->ctx, flags, copy_flags, streams, ret_body) < 0) { + &rtp_copy->ctx, flags, copy_flags, streams, ret_body, + ret_streams) < 0) { if (release) { list_del(&rtp_copy->list); shm_free(rtp_copy); diff --git a/modules/rtp_relay/rtp_relay_load.h b/modules/rtp_relay/rtp_relay_load.h index be1fa68ea5b..19c2677761f 100644 --- a/modules/rtp_relay/rtp_relay_load.h +++ b/modules/rtp_relay/rtp_relay_load.h @@ -37,7 +37,8 @@ struct rtp_relay_binds { int (*answer)(rtp_ctx ctx, str *id, unsigned int flags, str *body); int (*delete)(rtp_ctx ctx, str *id, unsigned int flags); int (*copy_offer)(rtp_ctx ctx, str *id, str *flags, - unsigned int copy_flags, unsigned int streams, str *ret_body); + unsigned int copy_flags, unsigned int streams, str *ret_body, + struct rtp_relay_streams *ret_streams); int (*copy_answer)(rtp_ctx ctx, str *id, str *flags, str *body); int (*copy_delete)(rtp_ctx ctx, str *id, @@ -68,7 +69,8 @@ int rtp_relay_api_offer(rtp_ctx ctx, str *id, unsigned int flags, str *body); int rtp_relay_api_answer(rtp_ctx ctx, str *id, unsigned int flags, str *body); int rtp_relay_api_delete(rtp_ctx ctx, str *id, unsigned int flags); int rtp_relay_copy_offer(rtp_ctx ctx, str *id, str *flags, - unsigned int copy_flags, unsigned int streams, str *ret_body); + unsigned int copy_flags, unsigned int streams, str *ret_body, + struct rtp_relay_streams *ret_streams); int rtp_relay_copy_answer(rtp_ctx ctx, str *id, str *flags, str *body); int rtp_relay_copy_delete(rtp_ctx ctx, str *id, diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index 7b82e7bb86e..e457850eed8 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -298,7 +298,8 @@ static int rtpengine_api_delete(struct rtp_relay_session *sess, struct rtp_relay str *flags, str *extra); static int rtpengine_api_copy_offer(struct rtp_relay_session *sess, struct rtp_relay_server *server, void **_ctx, str *flags, - unsigned int copy_flags, unsigned int streams, str *body); + unsigned int copy_flags, unsigned int streams, str *body, + struct rtp_relay_streams *streams_map); static int rtpengine_api_copy_answer(struct rtp_relay_session *sess, struct rtp_relay_server *server, void *_ctx, str *flags, str *body); static int rtpengine_api_copy_delete(struct rtp_relay_session *sess, @@ -4401,9 +4402,63 @@ static str *rtpengine_new_subs(str *tag) return to_tag; } +static void rtpengine_copy_streams(bencode_item_t *streams, struct rtp_relay_streams *ret) +{ + bencode_item_t *item, *medias; + str tmp; + struct dlg_cell *dlg; + int leg = RTP_RELAY_CALLER, medianum, label, s; + if (!ret || !streams) + return; + ret->count = 0; + dlg = dlgb.get_dlg(); + if (!dlg) + LM_WARN("could not fetch dialog - legs might not match\n"); + s = 0; + for (item = streams->child; item; item = item->sibling) { + if (dlg) { + tmp.s = bencode_dictionary_get_string(item, "tag", &tmp.len); + if (!tmp.s) { + LM_WARN("could not retrieve tag - placing to %s\n", + (leg == RTP_RELAY_CALLER?"caller":"callee")); + } + if (!str_match(&tmp, &dlg->legs[DLG_CALLER_LEG].tag)) + leg = RTP_RELAY_CALLEE; + else + leg = RTP_RELAY_CALLER; + } else if (leg == RTP_RELAY_CALLER) { + /* first try caller, then callee */ + leg = RTP_RELAY_CALLEE; + } + medias = bencode_dictionary_get_expect(item, "medias", BENCODE_LIST); + if (!medias) + continue; + for (medias = medias->child; medias; medias = medias->sibling) { + s = ret->count; + if (s == RTP_COPY_MAX_STREAMS) { + LM_WARN("maximum amount of streams %d reached!\n", + RTP_COPY_MAX_STREAMS); + return; + } + medianum = bencode_dictionary_get_integer(item, "index", 0); + tmp.s = bencode_dictionary_get_string(medias, "label", &tmp.len); + if (str2sint(&tmp, &label) < 0) { + LM_WARN("invalid label %.*s - not integer - skipping\n", + tmp.len, tmp.s); + continue; + } + ret->streams[s].leg = leg; + ret->streams[s].label = label; + ret->streams[s].medianum = medianum; + ret->count++; + } + } +} + static int rtpengine_api_copy_offer(struct rtp_relay_session *sess, struct rtp_relay_server *server, void **_ctx, str *flags, - unsigned int copy_flags, unsigned int streams, str *ret_body) + unsigned int copy_flags, unsigned int streams, str *ret_body, + struct rtp_relay_streams *ret_streams) { str tmp, *to_tag; bencode_item_t *ret; @@ -4415,6 +4470,8 @@ static int rtpengine_api_copy_offer(struct rtp_relay_session *sess, LM_ERR("failed to extract sdp body from proxy reply\n"); if (!bencode_dictionary_get_str(ret, "to-tag", &tmp)) LM_ERR("failed to extract to-tag from proxy reply\n"); + if (ret_streams) + rtpengine_copy_streams(bencode_dictionary_get(ret, "tag-medias"), ret_streams); to_tag = rtpengine_new_subs(&tmp); *_ctx = to_tag; bencode_buffer_free(bencode_item_buffer(ret)); diff --git a/modules/rtpproxy/rtpproxy.c b/modules/rtpproxy/rtpproxy.c index 6843272cf66..f8960817cc1 100644 --- a/modules/rtpproxy/rtpproxy.c +++ b/modules/rtpproxy/rtpproxy.c @@ -188,7 +188,6 @@ #include "rtpproxy_vcmd.h" #include "rtppn_connect.h" #include "../rtp_relay/rtp_relay.h" - #define NH_TABLE_VERSION 0 #define DEFAULT_RTPP_SET_ID 0 @@ -322,7 +321,8 @@ static int rtpproxy_api_delete(struct rtp_relay_session *sess, struct rtp_relay_ str *flags, str *extra); static int rtpproxy_api_copy_offer(struct rtp_relay_session *sess, struct rtp_relay_server *server, void **_ctx, str *flags, - unsigned int copy_flags, unsigned int streams, str *body); + unsigned int copy_flags, unsigned int streams, str *body, + struct rtp_relay_streams *streams_map); static int rtpproxy_api_copy_answer(struct rtp_relay_session *sess, struct rtp_relay_server *server, void *_ctx, str *flags, str *body); static int rtpproxy_api_copy_delete(struct rtp_relay_session *sess, @@ -331,6 +331,7 @@ static int rtpproxy_api_copy_serialize(void *_ctx, bin_packet_t *packet); static int rtpproxy_api_copy_deserialize(void **_ctx, bin_packet_t *packet); static void rtpproxy_api_copy_release(void **_ctx); + int connect_rtpproxies(struct rtpp_set *filter); int update_rtpp_proxies(struct rtpp_set *filter); @@ -5594,9 +5595,34 @@ static int rtpproxy_gen_sdp_medias(struct rtpproxy_sdp_buf *buf, return 0; } +static void rtpproxy_api_copy_fill_streams( + struct rtpproxy_copy_ctx *ctx, struct rtp_relay_streams* streams) +{ + struct rtpproxy_copy_stream *stream; + struct list_head *it; + int leg, s; + streams->count = 0; + for (leg = RTP_RELAY_CALLER; leg <= RTP_RELAY_CALLEE; leg++) { + list_for_each(it, &ctx->streams[leg]) { + stream = list_entry(it, struct rtpproxy_copy_stream, list); + s = streams->count; + if (s == RTP_COPY_MAX_STREAMS) { + LM_WARN("maximum amount of streams %d reached!\n", + RTP_COPY_MAX_STREAMS); + return; + } + streams->streams[s].leg = leg; + streams->streams[s].label = stream->index; + streams->streams[s].medianum = stream->medianum; + streams->count++; + } + } +} + static int rtpproxy_api_copy_offer(struct rtp_relay_session *sess, struct rtp_relay_server *server, void **_ctx, str *flags, - unsigned int copy_flags, unsigned int streams, str *body) + unsigned int copy_flags, unsigned int streams, str *body, + struct rtp_relay_streams *streams_map) { str *media_ip; struct rtpproxy_sdp_buf *buf; @@ -5621,6 +5647,9 @@ static int rtpproxy_api_copy_offer(struct rtp_relay_session *sess, if (rtpproxy_gen_sdp_medias(buf, ctx, sess) < 0) goto error; + if (streams_map) + rtpproxy_api_copy_fill_streams(ctx, streams_map); + *body = buf->buffer; *_ctx = ctx; return 0; diff --git a/modules/siprec/siprec_body.c b/modules/siprec/siprec_body.c index eb0bf4b3f7d..654daf0eeb8 100644 --- a/modules/siprec/siprec_body.c +++ b/modules/siprec/siprec_body.c @@ -38,11 +38,34 @@ void srs_free_stream(struct srs_sdp_stream *stream) shm_free(stream); } -int srs_add_raw_sdp_stream(int label, int medianum, siprec_uuid *uuid, +int srs_fill_sdp_stream(int label, int medianum, siprec_uuid *uuid, struct src_sess *sess, struct src_part *part) { + struct list_head *it; struct srs_sdp_stream *stream = NULL; + /* first, search for a corresponding stream */ + list_for_each(it, &part->streams) { + stream = list_entry(it, struct srs_sdp_stream, list); + /* if we have a uuid, it is possible that we've already + * created it */ + if (uuid) { + if (siprec_cmp_uuid(uuid, &stream->uuid) == 0) + break; + } else if (stream->medianum == medianum) { + /* if not, we might have the same medianum, so we need + * to update it */ + break; + } + stream = NULL; + } + if (stream) { + if (uuid) + memcpy(stream->uuid, uuid, sizeof *uuid); + stream->label = label; + return 0; + } + stream = shm_malloc(sizeof *stream); if (!stream) { LM_ERR("cannot allocate memory for new stream!\n"); @@ -52,7 +75,10 @@ int srs_add_raw_sdp_stream(int label, int medianum, siprec_uuid *uuid, stream->label = label; stream->medianum = medianum; - memcpy(stream->uuid, uuid, sizeof *uuid); + if (uuid) + memcpy(stream->uuid, uuid, sizeof *uuid); + else + siprec_build_uuid(stream->uuid); list_add_tail(&stream->list, &part->streams); sess->streams_no++; diff --git a/modules/siprec/siprec_body.h b/modules/siprec/siprec_body.h index 0e5326d57d3..66f51899a33 100644 --- a/modules/siprec/siprec_body.h +++ b/modules/siprec/siprec_body.h @@ -51,7 +51,7 @@ struct srs_sdp_stream { void srs_free_stream(struct srs_sdp_stream *stream); -int srs_add_raw_sdp_stream(int label, int medianum, siprec_uuid *uuid, +int srs_fill_sdp_stream(int label, int medianum, siprec_uuid *uuid, struct src_sess *sess, struct src_part *part); int srs_build_body(struct src_sess *sess, str *sdp, str *body); diff --git a/modules/siprec/siprec_logic.c b/modules/siprec/siprec_logic.c index b26821abb99..36757d146b4 100644 --- a/modules/siprec/siprec_logic.c +++ b/modules/siprec/siprec_logic.c @@ -245,6 +245,27 @@ int srec_reply(struct src_sess *ss, int method, int code, str *body) return srec_b2b.send_reply(&reply_data); } +static int srec_get_body(struct src_sess *sess, str *body) +{ + unsigned int flags = RTP_COPY_MODE_SIPREC|RTP_COPY_LEG_BOTH; + struct rtp_relay_streams streams; + struct rtp_relay_stream *stream; + int s; + + if (srec_rtp.copy_offer(sess->rtp, &mod_name, + &sess->media, flags, -1, body, &streams) < 0) { + LM_ERR("could not start recording!\n"); + return -3; + } + for (s = 0; s < streams.count; s++) { + stream = &streams.streams[s]; + srs_fill_sdp_stream(stream->label, stream->medianum, + NULL, sess, &sess->participants[stream->leg]); + } + return 0; +} + + static int srec_b2b_req(struct sip_msg *msg, struct src_sess *ss) { str body = str_init(""); @@ -261,8 +282,7 @@ static int srec_b2b_req(struct sip_msg *msg, struct src_sess *ss) code = 488; goto reply; } - if (srec_rtp.copy_offer(ss->rtp, &mod_name, &ss->media, - RTP_COPY_MODE_SIPREC|RTP_COPY_LEG_BOTH, -1, &body) < 0) { + if (srec_get_body(ss, &body) < 0) { LM_ERR("could not refresh recording!\n"); goto reply; } @@ -518,7 +538,6 @@ static int srs_send_invite(struct src_sess *sess) /* starts the recording to the srs */ static int src_start_recording(struct sip_msg *msg, struct src_sess *sess) { - unsigned int flags = RTP_COPY_MODE_SIPREC|RTP_COPY_LEG_BOTH; union sockaddr_union tmp; int ret; str sdp; @@ -532,11 +551,11 @@ static int src_start_recording(struct sip_msg *msg, struct src_sess *sess) } } - if (srec_rtp.copy_offer(sess->rtp, &mod_name, - &sess->media, flags, -1, &sdp) < 0) { + if (srec_get_body(sess, &sdp) < 0) { LM_ERR("could not start recording!\n"); return -3; } + if (shm_str_dup(&sess->initial_sdp, &sdp) < 0) { pkg_free(sdp.s); srec_rtp.copy_delete(sess->rtp, &mod_name, &sess->media); @@ -610,8 +629,7 @@ static int src_update_recording(struct sip_msg *msg, struct src_sess *sess) if (sess->flags & SIPREC_PAUSED) flags |= RTP_COPY_MODE_DISABLE; - if (srec_rtp.copy_offer(sess->rtp, &mod_name, - &sess->media, flags, -1, &sdp) < 0) { + if (srec_get_body(sess, &sdp) < 0) { LM_ERR("could not refresh recording!\n"); goto error; } diff --git a/modules/siprec/siprec_sess.c b/modules/siprec/siprec_sess.c index 24c9dd269c8..7c7c7ba3842 100644 --- a/modules/siprec/siprec_sess.c +++ b/modules/siprec/siprec_sess.c @@ -445,7 +445,7 @@ static int srec_pop_sess(struct dlg_cell *dlg, bin_packet_t *packet) goto error; } memcpy(&uuid, tmp.s, tmp.len); - if (srs_add_raw_sdp_stream(label, medianum, &uuid, sess, + if (srs_fill_sdp_stream(label, medianum, &uuid, sess, &sess->participants[sess->participants_no - 1]) < 0) { LM_ERR("cannot add new media stream!\n"); goto error; diff --git a/modules/siprec/siprec_uuid.h b/modules/siprec/siprec_uuid.h index 3814d04730e..26292d43ab7 100644 --- a/modules/siprec/siprec_uuid.h +++ b/modules/siprec/siprec_uuid.h @@ -38,5 +38,8 @@ static inline void siprec_build_uuid(siprec_uuid uuid) base64encode(uuid, tmp_uuid, sizeof(tmp_uuid)); } +#define siprec_cmp_uuid(a, b) \ + memcmp(a, b, SIPREC_UUID_LEN) + #endif /* _SIPREC_UUID_H_ */