This is quite a basic plugin, as it only takes care of acting as an RTP bridge. It is named "NoSIP" since, as the name suggests, signalling takes no place here, and is entirely up to the application. The typical usage of this application is something like this:
The same behaviour can be followed if the application is the callee instead, with the only difference being that the barebone offer will come from the peer in this case, and the application will ask the NoSIP plugin for a barebone answer instead.
As you can see, the behaviour is pretty much the same as the SIP plugin, with the key difference being that in this case there's no SIP stack in the plugin itself. All signalling is left to the application, and Janus (via the NoSIP plugin) is only responsible for bridging the media. This might be more appropriate than the SIP plugin in cases where developers want to keep control on the signalling layer, while still involving a server of sorts. Of course, SIP is just an example here: other signalling protocols may be involved as well (e.g., IAX, XMPP, others). The NoSIP plugin, though, will generate and expect plain SDP, so you'll need to take care of any adaptation that may be needed to make this work with the signalling protocol of your choice.
The plugin mainly supports two requests, generate and process, which are both asynchronous. The generate request take a JSEP offer or answer, and generates a barebone SDP the "legacy" application can use; the process request, on the other hand, processes a remote barebone SDP, and matches it to the plugin may have generated before, in order to then return a JSEP offer or answer that can be used to setup a PeerConnection.
The generate request must be formatted as follows:
{
"request" : "generate",
"info" : "<opaque string that the user can provide for context; optional>",
"srtp" : "<whether to mandate (sdes_mandatory) or offer (sdes_optional) SRTP support; optional>",
"srtp_profile" : "<SRTP profile to negotiate, in case SRTP is offered; optional>"
}
As anticipated, this requires a JSEP offer or answer passed via Janus API as part of a WebRTC PeerConnection negotiation. If the conversion of the WebRTC JSEP SDP to barebone SDP is successful, a generated event is sent back to the user:
{
"nosip" : "event",
"result" : {
"event" : "generated",
"type" : "<offer|answer, depending on the nature of the provided JSEP>",
"sdp" : "<barebone SDP content>",
"unique_id" : "<unique UUID of this session in this plugin, needed for some requests>
}
}
The process request, instead, must be formatted as follows:
{
"request" : "process",
"type" : "<offer|answer, depending on the nature of the provided SDP>",
"sdp" : "<barebone SDP to convert>"
"info" : "<opaque string that the user can provide for context; optional>",
"srtp" : "<whether to mandate (sdes_mandatory) or offer (sdes_optional) SRTP support; optional>",
"srtp_profile" : "<SRTP profile to negotiate, in case SRTP is offered; optional>"
}
As anticipated, this requires a "legacy" SDP offer or answer passed via NoSIP plugin messaging, which is why the caller must specify if it's an offer or answer. If the request is successful, a processed event is sent back to the user, along to the JSEP offer or answer that Janus generated out of the barebone SDP:
{
"nosip" : "event",
"result" : {
"event" : "processed",
"srtp" : "<whether the barebone SDP mandates (sdes_mandatory) or offers (sdes_optional) SRTP support; optional>",
"unique_id" : "<unique UUID of this session in this plugin, needed for some requests>
}
}
To close a session you can use the hangup request, which needs no additional arguments, as the whole context can be extracted from the current state of the session in the plugin:
{
"request" : "hangup"
}
An hangingup event will be sent back, as this is an asynchronous request.
As to other features, just as in the SIP plugin, the multimedia session can be recorded. Considering the NoSIP plugin also assumes two peers are in a call with each other (although it makes no assumptions on the signalling that ties them together), it works exactly the same way as the SIP plugin dooes when it comes to recording. Specifically, you make use of the recording request to either start or stop a recording, using the following syntax:
{
"request" : "recording",
"action" : "<start|stop, depending on whether you want to start or stop recording something>"
"audio" : <true|false; whether or not our audio should be recorded>,
"video" : <true|false; whether or not our video should be recorded>,
"peer_audio" : <true|false; whether or not our peer's audio should be recorded>,
"peer_video" : <true|false; whether or not our peer's video should be recorded>,
"filename" : "<base path/filename to use for all the recordings>"
}
As you can see, this means that the two sides of conversation are recorded separately, and so are the audio and video streams if available. You can choose which ones to record, in case you're interested in just a subset. The filename part is just a prefix, and dictates the actual filenames that will be used for the up-to-four recordings that may need to be enabled.
A recordingupdated event is sent back in case the request is successful.
To programmatically send a video keyframe request to either the WebRTC user or the SIP peer (or both), the keyframe request can be used. This request is particularly useful when the SIP peer doesn't support RTCP PLI, and so may use other mechanisms (e.g., via signalling) to ask for a keyframe to get video working. By using this request, the WebRTC user can ask Janus to originate a PLI programmatically. The direction of the keyframe request can be provided by using the user and peer properties: if user is TRUE a keyframe request will be sent by Janus to the WebRTC user; if peer is TRUE a keyframe request will be sent by Janus to the SIP peer. In both cases an RTCP PLI message will be sent. The syntax of the message is the following:
{
"request" : "keyframe",
"user" : <true|false; whether or not to send a keyframe request to the WebRTC user>,
"peer" : <true|false; whether or not to send a keyframe request to the SIP peer>
}
A keyframesent event is sent back in case the request is successful.
RTP forwarders are a quite useful functionality that a few plugins in Janus can take advantage of. As the name suggests, their main purpose is indeed forwarding/relaying RTP traffic to an external backend, for further processing or management of media packets outside of the context of the plugin that's responsible for it.
Within the context of the NoSIP plugin, RTP forwarders allow you to send the RTP traffic belonging to a specific call to an external backend, e.g., to a component implementing transcriptions, a remote recorder, a lawful interception application or whatever else may have a need for the content of a call in real-time. The RTP forwarder functionality is conceived in a way that allows you to separately forward individual RTP streams: this allows you to only forward, e.g., the audio packets of the local Janus user, only forward the video packets of the peer, forward everything, or any combination in between. For every media stream you're interested in forwarding, a separate RTP forwarder will be needed, which is what enables this flexibility. Multiple forwarders can be created for the same stream, in case the same RTP traffic should be sent to multiple backends at the same time.
Notice that no signalling protocol is used for RTP forwarders. RTP traffic is relayed out of context, using a specific API that is part of the NoSIP plugin itself. RTP forwarders will need an ongoing call to operate, though, as they'll be associated to existing media streams in an existing call; more specifically, forwarding requests must be performed on the handle that's handling the call that should be the target of its operations, which is why the related requests don't need any identifier (the scope is automatically obtained from the context of the handle). Forwarders that were created while a call was active will automatically be destroyed when the call is hung up
To setup new RTP forwarders, you can use the rtp_forward request, which must be formatted as follows:
{
"request" : "rtp_forward",
"streams" : [
{
"type": "<what we want forward: must be one of audio, video, peer_audio, peer_video>",
"host" : "<host address to forward the packets to>",
"host_family" : "<optional; ipv4 by default>",
"port" : <port to forward the packets to>,
"ssrc" : <SSRC to use to use when forwarding; optional>,
"pt" : <payload type to use when forwarding; optional>,
"srtp_suite" : <length of authentication tag (32 or 80); optional>,
"srtp_crypto" : "<key to use as crypto (base64 encoded key as in SDES); optional>"
},
{
.. other streams, if needed..
}
]
}
The syntax of the request makes it easy to set up multiple RTP forwarders for a call at the same time, by adding multiple objects as part of the streams array.
A successful request will result in an rtp_forward event, containing the relevant info associated to the new forwarder(s):
{
"nosip" : "event",
"result" : {
"event" : "rtp_forward",
"forwarders" : [
{
"stream_id" : <unique numeric ID assigned to this forwarder, if any>,
"type" : "<type of this forwarder, as configured in the request>",
"host" : "<host this forwarder is streaming to, same as request if not resolved>",
"port" : <port this forwarder is streaming to, same as request if configured>,
"media" : "<audio or video>",
"ssrc" : <SSRC this forwarder is using, if any>,
"pt" : <payload type this forwarder is using, if any>,
"srtp" : <true|false, whether the RTP stream is encrypted>
},
// Other forwarders, if configured
]
}
}
The stream_id property returned for each forwarder is what will need to be used for managing it, i.e., to destroy it once done.
To stop a previously created RTP forwarder and stop it, you can use the stop_rtp_forward request, which has to be formatted as follows:
{
"request" : "stop_rtp_forward",
"stream_id" : <unique numeric ID of the RTP forwarder>
}
A successful request will result in a stop_rtp_forward event:
{
"nosip" : "event",
"result" : {
"event" : "stop_rtp_forward",
"stream_id" : <unique numeric ID, same as request>
}
}
To get a list of all the forwarders for an active call, instead, you can make use of the listforwarders request, which has to be formatted as follows:
{
"request" : "listforwarders"
}
A successful request will produce a list of RTP forwarders in a forwarders event:
{
"nosip" : "event",
"result" : {
"event" : "forwarders",
"forwarders" : [ // Array of RTP forwarders
{ // RTP forwarder #1
"stream_id" : <unique numeric ID assigned to this forwarder, if any>,
"type" : "<type of this forwarder, as configured in the request>",
"host" : "<host this forwarder is streaming to, same as request if not resolved>",
"port" : <port this forwarder is streaming to, same as request if configured>,
"media" : "<audio or video>",
"ssrc" : <SSRC this forwarder is using, if any>,
"pt" : <payload type this forwarder is using, if any>,
"srtp" : <true|false, whether the RTP stream is encrypted>
},
// Other forwarders for this publisher
]
}
}