<html aria-label="message body">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">
My final solution (working with video and WebRTC a=mid:X markers:
<div><br>
</div>
<div>Opensips Recording HOP:</div>
<div><br>
</div>
<div>
<div><font face="Courier New">route[setup_rec] {</font></div>
<div><font face="Courier New">        # https://www.opensips.org/Documentation/Tutorials-SIPREC-2-4</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><span style="font-family: "Courier New";">        # remove mid:0 - https://support.sipwise.com/view.php?id=64475 - offer/answer w/ same mid:0 mixes up labels and returns single m= line</span></div>
<div><font face="Courier New">        # temporary until fixed in RTPEngine</font></div>
<div><font face="Courier New">        $rtp_relay_ctx(flags) = "sdp-attr-remove-audio-mid sdp-attr-remove-video-mid sdp-attr-remove-audio-msid sdp-attr-remove-video-msid sdp-attr-remove-none-msid-semantic";</font></div>
<div><font face="Courier New">        rtp_relay_engage("rtpengine");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        $avp(x-system) = $(ru{uri.param,x-system}); # without a x-system we do have a problem here. It MUST be present</font></div>
<div><font face="Courier New">        t_on_reply("setup_rec");</font></div>
<div><font face="Courier New">}</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">onreply_route[setup_rec] {</font></div>
<div><font face="Courier New">        if ($rs=="200") {</font></div>
<div><font face="Courier New">                # otherwise the recording would start right after the first 18x with SDP</font></div>
<div><font face="Courier New">                xlog("L_INFO", "Start recording on 200 OK for ctx(callid)=$rtp_relay_ctx(callid)");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                # https://opensips.org/docs/modules/3.6.x/siprec.html#func_siprec_start_recording</font></div>
<div><font face="Courier New">                $siprec(headers) = "X-Call-ID: "+$ci+"\r\n";</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New"># the defaults do just fine. Otherwise we would need to store the values from INVITE request to have them here on the reply</font></div>
<div><font face="Courier New">#               $xml(caller_xml) = "<nameID></nameID>";</font></div>
<div><font face="Courier New">#               $xml(caller_xml/nameID.attr/aor) = $fU+"@"+$fd"; # remove any sip:, or ports</font></div>
<div><font face="Courier New">#               if ($(fn{s.len})) $xml(caller_xml/nameID) = "<name>"+$fn+"</name>";</font></div>
<div><font face="Courier New">#               $siprec(caller) = $xml(caller_xml/nameID);</font></div>
<div><font face="Courier New">#</font></div>
<div><font face="Courier New">#               $xml(callee_xml) = "<nameID></nameID>";</font></div>
<div><font face="Courier New">#               $xml(callee_xml/nameID.attr/aor) = $tU+"@"+$td"; # remove any sip:, or ports</font></div>
<div><font face="Courier New">#               #$xml(callee_xml/nameID) = "<name></name>";</font></div>
<div><font face="Courier New">#               $siprec(callee) = $xml(callee_xml/nameID);</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                $siprec(from_uri) = $fu;</font></div>
<div><font face="Courier New">                $siprec(to_uri) = $tu;</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                # not only IP address but also RTPEngine flags can be set for the SRS leg in </font></div>
<div><font face="Courier New">                # sdp-media-remove=video sends "sdp-media-remove": "video" instead of "sdp-media-remove": [ "video" ] -> video is not removed - see Conclusion</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                # Alternative solution in rtpengine.conf:</font></div>
<div><font face="Courier New">                # [templates]</font></div>
<div><font face="Courier New">                # SIPREC = sdp-media-remove=[video text image]</font></div>
<div><font face="Courier New">                # RemMid = sdp-attr-remove-audio-mid sdp-attr-remove-video-mid sdp-attr-remove-audio-msid sdp-attr-remove-video-msid sdp-attr-remove-none-msid-semantic</font></div>
<div><font face="Courier New">                # subscribe request = sdp-media-remove=[video text image]</font></div>
<div><font face="Courier New">                # subscribe answer = allow-transcoding asymmetric</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                # either use directly:</font></div>
<div><font face="Courier New">                $siprec(media) = "allow-transcoding asymmetric";  # -> sdp-media-remove does not send ARRAY</font></div>
<div><font face="Courier New">                # or use a template:</font></div>
<div><font face="Courier New">                #$siprec(media) = "template=SIPREC";  # -> sdp-media-remove=[video text image] is ignored, but other parameters do work!</font></div>
<div><font face="Courier New">                # or use the default template for "subscribe request" and "subscribe answer"</font></div>
<div><font face="Courier New">                # -> still the sdp-media-remove does not work</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                # Conclusion:</font></div>
<div><font face="Courier New">                # - do directly to avoid dependency in rtpengine.conf</font></div>
<div><font face="Courier New">                # - sdp-media-remove would work for the „offer-style" request, but not for the „offer-style" reply, so it is not done on the subscribe request reply!</font></div>
<div><font face="Courier New">                # - rework the SDP body on the next-hop Hydra that has to manipulate the XMS anyway</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                siprec_start_recording("sip:opensips-srs@192.168.48.161:5060;x-system=$avp(x-system), sip:opensips-srs@192.168.48.162:5060;x-system=$avp(x-system)");</font></div>
<div><font face="Courier New">        }</font></div>
<div><font face="Courier New">}</font></div>
</div>
<div><br>
</div>
<div><br>
</div>
<div>Kamailio (sorry guys, but had it ready with xmlops although XML module looks good) next hop to SRS:</div>
<div><font face="Courier New"><br>
</font></div>
<div>
<div>
<div><font face="Courier New">modparam("xmlops", "xml_ns", "ac=urn:ietf:params:xml:ns:recording")</font></div>
<div><font face="Courier New">modparam("xmlops", "xml_ns", "os=urn:ietf:params:xml:ns:recording:1")</font></div>
</div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New"># -----------------------------------------------------------------------------------</font></div>
<div><font face="Courier New"># Forward PCR INVITE to correct SRS</font></div>
<div><font face="Courier New"># Convert OpenSIPS XML Format to Audiocodes Format understood by our SRS</font></div>
<div><font face="Courier New"># -----------------------------------------------------------------------------------</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">route[PCR_OPENSIPS] {</font></div>
<div><font face="Courier New">        $var(boundary) = $(cT{param.value,boundary});</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        get_body_part('application/sdp', "$var(SDP)");</font></div>
<div><font face="Courier New">        get_body_part('application/rs-metadata+xml', "$avp(X)");</font></div>
<div><font face="Courier New">        # do the changes ...</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        avp_subst("$avp(X)", "/^Content-Disposition:.+//"); # why is this in the variable?</font></div>
<div><font face="Courier New">        avp_subst("$avp(X)", "/^\s+//g");   # remove any Spaces and Tabs</font></div>
<div><font face="Courier New">        avp_subst("$avp(X)", "/^\t/  /g");  # remove any empty lines - important for $xml(rec=>doc)</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        xlog("L_DEBUG", ">>> INPUT: $avp(X)");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        $xml(rec=>doc) = $avp(X);           # first line MUST NOT be an empty line!</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        # https://www.kamailio.org/docs/modules/devel/modules/xmlops.html</font></div>
<div><font face="Courier New">        # https://grantm.github.io/perl-libxml-by-example/xpath.html</font></div>
<div><font face="Courier New">        $var(groupId) = $xml(rec=>xpath:/os:recording/os:group/@group_id);</font></div>
<div><font face="Courier New">        $var(sessionId) = $xml(rec=>xpath:/os:recording/os:session/@session_id);</font></div>
<div><font face="Courier New">        $var(sipSession) = $xml(rec=>xpath:/os:recording/os:session/os:sipSessionID);</font></div>
<div><font face="Courier New">        $var(stime) = $xml(rec=>xpath:/os:recording/os:sessionrecordingassoc[@session_id="$var(sessionId)"]/os:associate-time);</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        xlog("L_INFO", ">> ========== groupId=$var(groupId) sessionId=$var(sessionId) time=$var(stime)");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        $var(out) = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<recording xmlns=\"urn:ietf:params:xml:ns:recording\">\r\n<datamode>complete</datamode>\r\n<group id=\""+$var(groupId)+"\">\r\n"+$var(stime)+"\r\n</group>\r\n"+</font></div>
<div><font face="Courier New">        "<session id=\""+$var(sessionId)+"\">\r\n"+</font></div>
<div><font face="Courier New">        "<group-ref>"+$var(groupId)+"</group-ref>\r\n"+</font></div>
<div><font face="Courier New">        $var(sipSession)+"\r\n"+</font></div>
<div><font face="Courier New">        $var(stime)+"\r\n</session>\r\n";</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        xlog("L_INFO", ">> ========== partIDs: $xml(rec=>xpath:/os:recording/os:participant/@participant_id)");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        $var(str) = $xml(rec=>xpath:/os:recording/os:participant/@participant_id);</font></div>
<div><font face="Courier New">        $var(i) = 0;</font></div>
<div><font face="Courier New">        while ($(var(str){s.select,$var(i),,}{s.len})) {</font></div>
<div><font face="Courier New">                xlog("L_DEBUG", ">>> $var(i) - $var(str)");</font></div>
<div><font face="Courier New">                $var(id) = $(var(str){s.select,$var(i),,});</font></div>
<div><font face="Courier New">                $var(nameId) = $xml(rec=>xpath:/os:recording/os:participant[@participant_id="$var(id)"]/os:nameID);</font></div>
<div><font face="Courier New">                $var(name) = $xml(rec=>xpath:/os:recording/os:participant[@participant_id="$var(id)"]/os:nameID/os:name);</font></div>
<div><font face="Courier New">                $var(time) = $xml(rec=>xpath:/os:recording/os:participantsessionassoc[@participant_id="$var(id)"]/os:associate-time);</font></div>
<div><font face="Courier New">                $var(send) = $xml(rec=>xpath:/os:recording/os:participantstreamassoc[@participant_id="$var(id)"]/os:send);</font></div>
<div><font face="Courier New">                $var(recv) = $xml(rec=>xpath:/os:recording/os:participantstreamassoc[@participant_id="$var(id)"]/os:recv);</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                xlog("L_DEBUG", ">>> PartID($var(i)): $var(id) - $var(nameId) - $var(time) - $var(send) - $var(recv)");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                $var(out) = $var(out)+'<participant id="'+$var(id)+'" session="'+$var(sessionId)+"\">\r\n"+$var(nameId)+"\r\n"+$var(time)+"\r\n"+$var(send)+"\r\n"+$var(recv)+"\r\n</participant>\r\n";</font></div>
<div><font face="Courier New">                $var(i) = $var(i) + 1;</font></div>
<div><font face="Courier New">        }</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        xlog("L_INFO", ">> ========== streamIDs: $xml(rec=>xpath:/os:recording/os:stream/@stream_id)");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        $var(label1) = "";</font></div>
<div><font face="Courier New">        $var(label2) = "";</font></div>
<div><font face="Courier New">        if (sdp_with_media("video")) {</font></div>
<div><font face="Courier New">                $var(in_audio) = 0;</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                sdp_iterator_start("s1");</font></div>
<div><font face="Courier New">                while (sdp_iterator_next("s1")) {</font></div>
<div><font face="Courier New">                        # detect start of any media section</font></div>
<div><font face="Courier New">                        if ($sdpitval(s1) =~ "^m=") {</font></div>
<div><font face="Courier New">                                if ($sdpitval(s1) =~ "^m=audio[ \t]") {</font></div>
<div><font face="Courier New">                                        $var(in_audio) = 1;</font></div>
<div><font face="Courier New">                                } else {</font></div>
<div><font face="Courier New">                                        $var(in_audio) = 0;</font></div>
<div><font face="Courier New">                                }</font></div>
<div><font face="Courier New">                        } else {</font></div>
<div><font face="Courier New">                                # only evaluate attributes if we are inside audio section</font></div>
<div><font face="Courier New">                                if ($var(in_audio) == 1) {</font></div>
<div><font face="Courier New">                                        if ($sdpitval(s1) =~ "^a=label:") {</font></div>
<div><font face="Courier New">                                                $var(lbl) = $(sdpitval(s1){s.trim}{re.subst,/^a=label:(.+)/\1/});</font></div>
<div><font face="Courier New">                                                xlog("L_DEBUG", ">> found audio label: $var(lbl)");</font></div>
<div><font face="Courier New">                                                if ($var(label1) == "") {</font></div>
<div><font face="Courier New">                                                        $var(label1) = $var(lbl);</font></div>
<div><font face="Courier New">                                                } else if ($var(label2) == "") {</font></div>
<div><font face="Courier New">                                                        $var(label2) = $var(lbl);</font></div>
<div><font face="Courier New">                                                } else {</font></div>
<div><font face="Courier New">                                                        xlog("L_INFO", ">> found more than 2 labels! Ignoring!");</font></div>
<div><font face="Courier New">                                                }</font></div>
<div><font face="Courier New">                                        }</font></div>
<div><font face="Courier New">                                }</font></div>
<div><font face="Courier New">                        }</font></div>
<div><font face="Courier New">                }</font></div>
<div><font face="Courier New">                sdp_iterator_end("s1");</font></div>
<div><font face="Courier New">        }</font></div>
<div><font face="Courier New">        $var(str) = $xml(rec=>xpath:/os:recording/os:stream/@stream_id);</font></div>
</div>
<div>
<div><font face="Courier New">        $var(i) = 0;</font></div>
<div><font face="Courier New">        while ($(var(str){s.select,$var(i),,}{s.len})) {</font></div>
<div><font face="Courier New">                xlog("L_DEBUG", ">>> $var(i) - $var(str)");</font></div>
<div><font face="Courier New">                $var(id) = $(var(str){s.select,$var(i),,});</font></div>
<div><font face="Courier New">                $var(label) = $xml(rec=>xpath:/os:recording/os:stream[@stream_id="$var(id)"]/os:label/text());</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                xlog("L_DEBUG", ">>> StreamID($var(i)): $var(id) - $var(label)");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                if ($var(i) == 0 && $var(label1) != "" && $var(label1) != $var(label)) {</font></div>
<div><font face="Courier New">                        xlog("L_INFO", ">> stream label not an audio label. replace $var(label) -> $var(label1)");</font></div>
<div><font face="Courier New">                        $var(label) = $var(label1);</font></div>
<div><font face="Courier New">                } else if ($var(i) == 1 && $var(label2) != "" && $var(label2) != $var(label)) {</font></div>
<div><font face="Courier New">                        xlog("L_INFO", ">> stream label not an audio label. replace $var(label) -> $var(label2)");</font></div>
<div><font face="Courier New">                        $var(label) = $var(label2);</font></div>
<div><font face="Courier New">                }</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">                $var(out) = $var(out)+'<stream id="'+$var(id)+'" session="'+$var(sessionId)+"\">\r\n<label>"+$var(label)+"</label>\r\n</stream>\r\n";</font></div>
<div><font face="Courier New">                $var(i) = $var(i) + 1;</font></div>
<div><font face="Courier New">        }</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        $var(out) = $var(out) + '</recording>';</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        xlog("L_DEBUG", ">>> OUT $var(out)");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        # Content-Type Header is not adopted here</font></div>
<div><font face="Courier New">        set_body_multipart("$var(SDP)", "application/sdp", "$var(boundary)"); # default delimiter unique-boundary-1</font></div>
<div><font face="Courier New">        msg_apply_changes();</font></div>
<div><font face="Courier New">        append_body_part("$var(out)", "application/rs-metadata+xml", "recording-session");</font></div>
<div><font face="Courier New"><br>
</font></div>
<div><font face="Courier New">        xlog("L_DEBUG", ">>> found first media IP: $sdp(c:ip)");</font></div>
<div><font face="Courier New">        $var(cFound) = 0;</font></div>
<div><font face="Courier New">        sdp_iterator_start("s1");</font></div>
<div><font face="Courier New">        while(sdp_iterator_next("s1")) {</font></div>
<div><font face="Courier New">                xlog("L_DEBUG", ">> found=$var(cFound) body line: $sdpitval(s1)");</font></div>
<div><font face="Courier New">                if ($sdpitval(s1) =~ "^c=IN IP4 ") {</font></div>
<div><font face="Courier New">                        xlog("L_INFO", ">> c-line found before m-line!");</font></div>
<div><font face="Courier New">                        $var(cFound) = 1;</font></div>
<div><font face="Courier New">                        break;</font></div>
<div><font face="Courier New">                }</font></div>
<div><font face="Courier New">                if ($sdpitval(s1) =~ "^m=audio [0-9]+ RTP" && $var(cFound) == 0) {</font></div>
<div><font face="Courier New">                        xlog("L_INFO", ">> no session level c-line, inserting one");</font></div>
<div><font face="Courier New">                        sdp_iterator_insert("s1", "c=IN IP4 $sdp(c:ip)\r\n");</font></div>
<div><font face="Courier New">                        break;</font></div>
<div><font face="Courier New">                }</font></div>
<div><font face="Courier New">        }</font></div>
<div><font face="Courier New">        sdp_iterator_end("s1");</font></div>
<div><font face="Courier New">        add_rr_param(";siprec=os");</font></div>
<div><font face="Courier New">}</font></div>
</div>
<div><font face="Courier New"><br>
</font></div>
<div>
<div><font face="Courier New">route[PCR]</font></div>
<div><font face="Courier New">{</font></div>
<div><font face="Courier New">        if ($rU=="opensips-srs" && uri==myself) {</font></div>
<div><font face="Courier New">                if (is_method("CANCEL")) {</font></div>
<div><font face="Courier New">                        if (!t_check_trans()) {</font></div>
<div><font face="Courier New">                                # we fwd the cancel anyway, restart of kamailio during transaction would cause problems on cancel otherwise</font></div>
<div><font face="Courier New">                                xlog("L_ERR", "CANCEL w/o matching transaction");</font></div>
<div><font face="Courier New">                        }</font></div>
<div><font face="Courier New">                        t_relay();</font></div>
<div><font face="Courier New">                        exit;</font></div>
<div><font face="Courier New">                }</font></div>
<div><font face="Courier New">                if (is_method("INVITE") && has_body("multipart/mixed")) {</font></div>
<div><font face="Courier New">                        route(PCR_OPENSIPS);</font></div>
<div><font face="Courier New">                }</font></div>
<div><font face="Courier New">                if (sdp_with_media("video")) {</font></div>
<div><font face="Courier New">                        # PCR_OPENSIPS replaces the labels from video to audio, PCR server strips it anyway</font></div>
<div><font face="Courier New">                        sdp_remove_media("video");</font></div>
<div><font face="Courier New">                        xlog("L_INFO", "Removed video from SRS call");</font></div>
<div><font face="Courier New">                }</font></div>
<div><font face="Courier New">                $rU = "c5-srs"; # continue below with Audiocodes Style Request Handling</font></div>
<div><font face="Courier New">        }</font></div>
</div>
<div><font face="Courier New">…</font></div>
<div><br>
</div>
<div>Might it help someone ….</div>
<div><br>
</div>
<div>Br Walter</div>
<div><br>
</div>
</body>
</html>