Skip to content

RTPEngine offer answer in opensips

Eric Tamme edited this page Mar 12, 2015 · 11 revisions

RTPEngine offer/answer for interop between DTLS-SRTP capable, and non DTLS-SRTP capable user agents

We need to know if the UAC is DTLS capabe, if the UAS is DTLS capable, and what type of offer/answer scenario this is to be able to pass the correct flags to rtpengine, and to call the appropriate function.

To detect if a UAC is a DTLS capable user agent, we look for the ws, or wss transport in its Via header, then set a flag:

# Detect if UAC is websockets client and set flag for later processing
if ($(hdr(Via){via.transport}{s.tolower}) == "ws" || $(hdr(Via){via.transport}{s.tolower}) == "wss") {
  setflag(uac_ws);
}

To detect if a UAS is DTLS capable, we do the same check, but when they register. We then set an attribute AVP which is restored on lookup().

# If the client is using websocket (webrtc) and save the attribute for detection later on location lookup
if ( isflagset(uac_ws) ) {
  $avp(attr)="websocket";
}
if (!save("location","p0v")) {
  sl_reply_error();
} 

Now for each branch, we must check the attribute avp, so you must have a branch route for processing rtpengine handling.

branch_route[rtpengine] {
  $var(branch_log)="branch[" + $T_branch_idx + "]                 :";
  # set a branch flag based on the attribute avp
  if( $(avp(attr)[$T_branch_idx]) == "websocket" ) {
    setbflag(uas_ws);
  }

  xlog("L_INFO","$var(branch_log) $cs: $rm: message flags: $mf\n");
  xlog("L_INFO","$var(branch_log) $cs: $rm: branch flags: $bf\n");

  # handle rtp proxying for both initial and sequential requests
  if ( (is_method("INVITE") || is_method("ACK") || is_method("PRACK")) && has_body("application/sdp") ) {
    # set rtpengine flags based on whether uac or uas are websockets
    if (isflagset(uac_ws) && isbflagset(uas_ws)) {
      $var(rtpengine_flags) = "ICE=force-relay DTLS=passive";
      xlog("L_INFO","$var(branch_log) $cs: $rm: uac and uas are both websockets\n");
    }
    else if (isflagset(uac_ws) && !isbflagset(uas_ws)) {
      $var(rtpengine_flags) = "RTP/AVP replace-session-connection replace-origin ICE=remove";
      xlog("L_INFO","$var(branch_log) $cs: $rm: uac is ws uas is not\n");
    }
    else if (!isflagset(uac_ws) && isbflagset(uas_ws)) {
      $var(rtpengine_flags) = "UDP/TLS/RTP/SAVPF ICE=force";
      xlog("L_INFO","$var(branch_log) $cs: $rm: uas is ws uac is not\n");
    }
    else if (!isflagset(uac_ws) && !isbflagset(uas_ws)) {
      $var(rtpengine_flags) = "RTP/AVP replace-session-connection replace-origin ICE=remove";
      xlog("L_INFO","$var(branch_log) $cs: $rm: neither uac or uas are websocket\n");
    }

    if( is_method("ACK") || is_method("PRACK") ){
      xlog("L_INFO","$var(branch_log) $cs: $rm: rtpengine answer $var(rtpengine_flags)\n");
      rtpengine_answer("$var(rtpengine_flags)");
    } else {
      rtpengine_offer("$var(rtpengine_flags)");
      xlog("L_INFO","$var(branch_log) $cs: $rm: rtpengine offer $var(rtpengine_flags)\n");
    }
  }
}

Likewise, we must process all responses individually in reply route.

onreply_route["reply"] {
  $var(reply_log)="onreply_route             :";
  xlog("L_INFO","$var(reply_log) $cs: $rs: response\n");
  xlog("L_INFO","$var(reply_log) $cs: $rs: message flags: $mf\n");
  xlog("L_INFO","$var(reply_log) $cs: $rs: branch flags: $bf\n");

  # rtp proxying for responses
  if ( has_body("application/sdp") ) {
    # set rtpengine flags based on whether uac or uas are websockets
    if (isflagset(uac_ws) && isbflagset(uas_ws)) {
      $var(rtpengine_flags) = "ICE=force-relay DTLS=passive";
      xlog("L_INFO","$var(reply_log) $cs: $rs: uac and uas are both websockets\n");
    }
    else if (isflagset(uac_ws) && !isbflagset(uas_ws)) {
      $var(rtpengine_flags) = "UDP/TLS/RTP/SAVPF ICE=force";
      xlog("L_INFO","$var(reply_log) $cs: $rs: uac is ws uas is not\n");
    }
    else if (!isflagset(uac_ws) && isbflagset(uas_ws)) {
      $var(rtpengine_flags) = "RTP/AVP replace-session-connection replace-origin ICE=remove";
      xlog("L_INFO","$var(reply_log) $cs: $rs: uas is ws uac is not\n");
    }
    else if (!isflagset(uac_ws) && !isbflagset(uas_ws)) {
      $var(rtpengine_flags) = "RTP/AVP replace-session-connection replace-origin ICE=remove";
      xlog("L_INFO","$var(reply_log) $cs: $rs: neither uac or uas are websocket\n");
    }

    if ( $rs=="183" ) {
      xlog("L_INFO","$var(reply_log) $cs: $rs: rtpengine offer $var(rtpengine_flags)\n");
      rtpengine_offer("$var(rtpengine_flags)");
    } else if ( $rs=="200" ) {
      xlog("L_INFO","$var(reply_log) $cs: $rs: rtpengine answer $var(rtpengine_flags)\n");
      rtpengine_answer("$var(rtpengine_flags)");
    }
  }
Clone this wiki locally