My final solution (working with video and WebRTC a=mid:X markers:

Opensips Recording HOP:

route[setup_rec] {
        # https://www.opensips.org/Documentation/Tutorials-SIPREC-2-4

        # 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
        # temporary until fixed in RTPEngine
        $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";
        rtp_relay_engage("rtpengine");

        $avp(x-system) = $(ru{uri.param,x-system}); # without a x-system we do 
have a problem here. It MUST be present
        t_on_reply("setup_rec");
}

onreply_route[setup_rec] {
        if ($rs=="200") {
                # otherwise the recording would start right after the first 18x 
with SDP
                xlog("L_INFO", "Start recording on 200 OK for 
ctx(callid)=$rtp_relay_ctx(callid)");

                # 
https://opensips.org/docs/modules/3.6.x/siprec.html#func_siprec_start_recording
                $siprec(headers) = "X-Call-ID: "+$ci+"\r\n";

# the defaults do just fine. Otherwise we would need to store the values from 
INVITE request to have them here on the reply
#               $xml(caller_xml) = "<nameID></nameID>";
#               $xml(caller_xml/nameID.attr/aor) = $fU+"@"+$fd"; # remove any 
sip:, or ports
#               if ($(fn{s.len})) $xml(caller_xml/nameID) = 
"<name>"+$fn+"</name>";
#               $siprec(caller) = $xml(caller_xml/nameID);
#
#               $xml(callee_xml) = "<nameID></nameID>";
#               $xml(callee_xml/nameID.attr/aor) = $tU+"@"+$td"; # remove any 
sip:, or ports
#               #$xml(callee_xml/nameID) = "<name></name>";
#               $siprec(callee) = $xml(callee_xml/nameID);

                $siprec(from_uri) = $fu;
                $siprec(to_uri) = $tu;

                # not only IP address but also RTPEngine flags can be set for 
the SRS leg in
                # sdp-media-remove=video sends "sdp-media-remove": "video" 
instead of "sdp-media-remove": [ "video" ] -> video is not removed - see 
Conclusion

                # Alternative solution in rtpengine.conf:
                # [templates]
                # SIPREC = sdp-media-remove=[video text image]
                # 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
                # subscribe request = sdp-media-remove=[video text image]
                # subscribe answer = allow-transcoding asymmetric

                # either use directly:
                $siprec(media) = "allow-transcoding asymmetric";  # -> 
sdp-media-remove does not send ARRAY
                # or use a template:
                #$siprec(media) = "template=SIPREC";  # -> 
sdp-media-remove=[video text image] is ignored, but other parameters do work!
                # or use the default template for "subscribe request" and 
"subscribe answer"
                # -> still the sdp-media-remove does not work

                # Conclusion:
                # - do directly to avoid dependency in rtpengine.conf
                # - 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!
                # - rework the SDP body on the next-hop Hydra that has to 
manipulate the XMS anyway

                
siprec_start_recording("sip:[email protected]:5060;x-system=$avp(x-system),
 sip:[email protected]:5060;x-system=$avp(x-system)");
        }
}


Kamailio (sorry guys, but had it ready with xmlops although XML module looks 
good) next hop to SRS:

modparam("xmlops", "xml_ns", "ac=urn:ietf:params:xml:ns:recording")
modparam("xmlops", "xml_ns", "os=urn:ietf:params:xml:ns:recording:1")

# 
-----------------------------------------------------------------------------------
# Forward PCR INVITE to correct SRS
# Convert OpenSIPS XML Format to Audiocodes Format understood by our SRS
# 
-----------------------------------------------------------------------------------

route[PCR_OPENSIPS] {
        $var(boundary) = $(cT{param.value,boundary});

        get_body_part('application/sdp', "$var(SDP)");
        get_body_part('application/rs-metadata+xml', "$avp(X)");
        # do the changes ...

        avp_subst("$avp(X)", "/^Content-Disposition:.+//"); # why is this in 
the variable?
        avp_subst("$avp(X)", "/^\s+//g");   # remove any Spaces and Tabs
        avp_subst("$avp(X)", "/^\t/  /g");  # remove any empty lines - 
important for $xml(rec=>doc)

        xlog("L_DEBUG", ">>> INPUT: $avp(X)");

        $xml(rec=>doc) = $avp(X);           # first line MUST NOT be an empty 
line!

        # https://www.kamailio.org/docs/modules/devel/modules/xmlops.html
        # https://grantm.github.io/perl-libxml-by-example/xpath.html
        $var(groupId) = $xml(rec=>xpath:/os:recording/os:group/@group_id);
        $var(sessionId) = $xml(rec=>xpath:/os:recording/os:session/@session_id);
        $var(sipSession) = 
$xml(rec=>xpath:/os:recording/os:session/os:sipSessionID);
        $var(stime) = 
$xml(rec=>xpath:/os:recording/os:sessionrecordingassoc[@session_id="$var(sessionId)"]/os:associate-time);

        xlog("L_INFO", ">> ========== groupId=$var(groupId) 
sessionId=$var(sessionId) time=$var(stime)");

        $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"+
        "<session id=\""+$var(sessionId)+"\">\r\n"+
        "<group-ref>"+$var(groupId)+"</group-ref>\r\n"+
        $var(sipSession)+"\r\n"+
        $var(stime)+"\r\n</session>\r\n";

        xlog("L_INFO", ">> ========== partIDs: 
$xml(rec=>xpath:/os:recording/os:participant/@participant_id)");

        $var(str) = 
$xml(rec=>xpath:/os:recording/os:participant/@participant_id);
        $var(i) = 0;
        while ($(var(str){s.select,$var(i),,}{s.len})) {
                xlog("L_DEBUG", ">>> $var(i) - $var(str)");
                $var(id) = $(var(str){s.select,$var(i),,});
                $var(nameId) = 
$xml(rec=>xpath:/os:recording/os:participant[@participant_id="$var(id)"]/os:nameID);
                $var(name) = 
$xml(rec=>xpath:/os:recording/os:participant[@participant_id="$var(id)"]/os:nameID/os:name);
                $var(time) = 
$xml(rec=>xpath:/os:recording/os:participantsessionassoc[@participant_id="$var(id)"]/os:associate-time);
                $var(send) = 
$xml(rec=>xpath:/os:recording/os:participantstreamassoc[@participant_id="$var(id)"]/os:send);
                $var(recv) = 
$xml(rec=>xpath:/os:recording/os:participantstreamassoc[@participant_id="$var(id)"]/os:recv);

                xlog("L_DEBUG", ">>> PartID($var(i)): $var(id) - $var(nameId) - 
$var(time) - $var(send) - $var(recv)");

                $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";
                $var(i) = $var(i) + 1;
        }

        xlog("L_INFO", ">> ========== streamIDs: 
$xml(rec=>xpath:/os:recording/os:stream/@stream_id)");

        $var(label1) = "";
        $var(label2) = "";
        if (sdp_with_media("video")) {
                $var(in_audio) = 0;

                sdp_iterator_start("s1");
                while (sdp_iterator_next("s1")) {
                        # detect start of any media section
                        if ($sdpitval(s1) =~ "^m=") {
                                if ($sdpitval(s1) =~ "^m=audio[ \t]") {
                                        $var(in_audio) = 1;
                                } else {
                                        $var(in_audio) = 0;
                                }
                        } else {
                                # only evaluate attributes if we are inside 
audio section
                                if ($var(in_audio) == 1) {
                                        if ($sdpitval(s1) =~ "^a=label:") {
                                                $var(lbl) = 
$(sdpitval(s1){s.trim}{re.subst,/^a=label:(.+)/\1/});
                                                xlog("L_DEBUG", ">> found audio 
label: $var(lbl)");
                                                if ($var(label1) == "") {
                                                        $var(label1) = 
$var(lbl);
                                                } else if ($var(label2) == "") {
                                                        $var(label2) = 
$var(lbl);
                                                } else {
                                                        xlog("L_INFO", ">> 
found more than 2 labels! Ignoring!");
                                                }
                                        }
                                }
                        }
                }
                sdp_iterator_end("s1");
        }
        $var(str) = $xml(rec=>xpath:/os:recording/os:stream/@stream_id);
        $var(i) = 0;
        while ($(var(str){s.select,$var(i),,}{s.len})) {
                xlog("L_DEBUG", ">>> $var(i) - $var(str)");
                $var(id) = $(var(str){s.select,$var(i),,});
                $var(label) = 
$xml(rec=>xpath:/os:recording/os:stream[@stream_id="$var(id)"]/os:label/text());

                xlog("L_DEBUG", ">>> StreamID($var(i)): $var(id) - 
$var(label)");

                if ($var(i) == 0 && $var(label1) != "" && $var(label1) != 
$var(label)) {
                        xlog("L_INFO", ">> stream label not an audio label. 
replace $var(label) -> $var(label1)");
                        $var(label) = $var(label1);
                } else if ($var(i) == 1 && $var(label2) != "" && $var(label2) 
!= $var(label)) {
                        xlog("L_INFO", ">> stream label not an audio label. 
replace $var(label) -> $var(label2)");
                        $var(label) = $var(label2);
                }

                $var(out) = $var(out)+'<stream id="'+$var(id)+'" 
session="'+$var(sessionId)+"\">\r\n<label>"+$var(label)+"</label>\r\n</stream>\r\n";
                $var(i) = $var(i) + 1;
        }

        $var(out) = $var(out) + '</recording>';

        xlog("L_DEBUG", ">>> OUT $var(out)");

        # Content-Type Header is not adopted here
        set_body_multipart("$var(SDP)", "application/sdp", "$var(boundary)"); # 
default delimiter unique-boundary-1
        msg_apply_changes();
        append_body_part("$var(out)", "application/rs-metadata+xml", 
"recording-session");

        xlog("L_DEBUG", ">>> found first media IP: $sdp(c:ip)");
        $var(cFound) = 0;
        sdp_iterator_start("s1");
        while(sdp_iterator_next("s1")) {
                xlog("L_DEBUG", ">> found=$var(cFound) body line: 
$sdpitval(s1)");
                if ($sdpitval(s1) =~ "^c=IN IP4 ") {
                        xlog("L_INFO", ">> c-line found before m-line!");
                        $var(cFound) = 1;
                        break;
                }
                if ($sdpitval(s1) =~ "^m=audio [0-9]+ RTP" && $var(cFound) == 
0) {
                        xlog("L_INFO", ">> no session level c-line, inserting 
one");
                        sdp_iterator_insert("s1", "c=IN IP4 $sdp(c:ip)\r\n");
                        break;
                }
        }
        sdp_iterator_end("s1");
        add_rr_param(";siprec=os");
}

route[PCR]
{
        if ($rU=="opensips-srs" && uri==myself) {
                if (is_method("CANCEL")) {
                        if (!t_check_trans()) {
                                # we fwd the cancel anyway, restart of kamailio 
during transaction would cause problems on cancel otherwise
                                xlog("L_ERR", "CANCEL w/o matching 
transaction");
                        }
                        t_relay();
                        exit;
                }
                if (is_method("INVITE") && has_body("multipart/mixed")) {
                        route(PCR_OPENSIPS);
                }
                if (sdp_with_media("video")) {
                        # PCR_OPENSIPS replaces the labels from video to audio, 
PCR server strips it anyway
                        sdp_remove_media("video");
                        xlog("L_INFO", "Removed video from SRS call");
                }
                $rU = "c5-srs"; # continue below with Audiocodes Style Request 
Handling
        }
…

Might it help someone ….

Br Walter

_______________________________________________
Users mailing list
[email protected]
http://lists.opensips.org/cgi-bin/mailman/listinfo/users

Reply via email to