Janus ReST interface

The transport layer is the one used for all kind of communication (even http).
We use the HTTP (rest transport) in the following.

All the messages must be in JSON format, and they must contain a field "transaction", a random string and a field "janus" which specifies a janus command like ping:

curl -X POST http://localhost:8088/janus --data "{\"transaction\": \"ciao\", \"janus\": \"ping\"}" 

CORE commands

All the janus commands:
  • ping
  • info
  • create -> create a new session, returns session_id
curl -X POST http://localhost:8088/janus --data "{\"transaction\": \"ciao\", \"janus\": \"create\"}" 

To force a particular session id:
curl -X POST http://localhost:8088/janus --data "{\"transaction\": \"ciao\", \"janus\": \"create\", \"id\":5}" 

SESSION commands

Once you have a session id you can call the related commands using the path
/janus/<id>
E.g.,

curl -X POST http://localhost:8088/janus/5 --data "{\"transaction\": \"ciao\", \"janus\": \"keepalive\"}" 

Where janus is again the label specifying the command which can be
  • keepalive
  • attach
  • destroy
  • detach
  • hangup
  • message
  • trickle

Once a session is created, one can create a plugin handle with:

curl -X POST http://localhost:8088/janus/5 --data "{\"transaction\": \"ciao\", \"janus\": \"attach\", \"plugin\":\"janus.plugin.echotest\"}" 

This returns a data id that can be used to send messages to the plugin (see next)
handle_id=$(curl -X POST http://localhost:8088/janus/5 --data "{\"transaction\": \"ciao\", \"janus\": \"attach\", \"plugin\": \"janus.plugin.echotest\"}" 2>&1| awk -F ' ' '/\"id\"/ {print $2}')

PLUGIN commands

Once a plugin handle is created one can send messages to it, each messages can have the following parameters:
body, jsep
both of them are supposed to be JSON objects, the first related to the plugin specific interface, the latter specifying SDP parameters

Example with the echotest plugin (it enables audio):

curl -X POST http://localhost:8088/janus/5/$handle --data "{\"transaction\": \"ciao\", \"janus\": \"message\", \"body\": {\"audio\": \"true\"}}" 

Janus architecture

________________    session    ___________________                  _________________                  ______________________
|               | <----------- |                  |   app_handle    |                |  plugin_handle  |                     |
| janus_session |  ice_handles | janus_ice_handle | <-------------> | plugin_session | --------------> | plugin_specific_obj |
----------------- <>---------- --------------------   gw_handle     ------------------                 |                     |
| - id          |              | - id             |                 | - stopped      |                 |                     |
-----------------              --------------------                 ------------------                 -----------------------
                                        |
                                        V
                                 ________________
                                 |               |-----|creates the plugin_session instances
                                 | janus_plugin  |
                                 |               |
                                 -----------------

Janus streaming plugin interface interface

  1. Let's create an RTP streaming mount point
    Mountpoints are bound to the streaming plugin itself and not to session.
    Nevertheless, in order to create/destroy/list them we need (fictional) session and handle.
    ## create session
    curl -X POST http://localhost:8088/janus --data "{\"transaction\": \"ciao\", \"janus\": \"create\", \"id\":5}" 
    
    ## create handle
    handle=$(curl -X POST http://localhost:8088/janus/5 --data "{\"transaction\": \"ciao\", \"janus\": \"attach\", \"plugin\": \"janus.plugin.streaming\"}" 2>&1| awk -F ' ' '/\"id\"/ {print $2}')
    echo "Handle received: $handle" 
    
    ## create mountpoint
    curl -X POST http://localhost:8088/janus/5/$handle --data "{\"transaction\": \"ciao\", \"janus\": \"message\", \"body\": {\"request\": \"create\", \"type\": \"rtp\",\
    \"audio\": true, \"audioport\": 5000, \"audiopt\": 111, \"audiortpmap\": \"opus/48000/2\",\
    \"video\": true, \"videoport\": 5002, \"videopt\": 100, \"videortpmap\": \"VP8/90000\",\
    \"id\": 7\
    }}" 
    

    ## list mountpoints
    curl -X POST http://localhost:8088/janus/5/$handle --data "{\"transaction\": \"ciao\", \"janus\": \"message\", \"body\": {\"request\": \"list\"}}" 
    
  2. Destroy a streaming mount point
    If the session expires (60 seconds without keepalive) we cannot access anymore to the plugin but the mountpoint is still active :-/
    If we want to be sure to destroy we need to create another session/handle
    curl -X POST http://localhost:8088/janus --data "{\"transaction\": \"ciao\", \"janus\": \"create\", \"id\":5}" 
    ## create handle
    handle=$(curl -X POST http://localhost:8088/janus/5 --data "{\"transaction\": \"ciao\", \"janus\": \"attach\", \"plugin\": \"janus.plugin.streaming\"}" 2>&1| awk -F ' ' '/\"id\"/ {print $2}')
    echo "Handle received: $handle" 
    
    ## destroy mountpoint
    curl -X POST http://localhost:8088/janus/5/$handle --data "{\"transaction\": \"ciao\", \"janus\": \"message\", \"body\": {\"request\": \"destroy\", \"id\": 7}}" 
    
  3. Interact with an RTP stream
    RTP stream operations are handled asynchronously, this means the commands:
    • watch
    • start
    • configure
    • switch
    • stop
    • pause
      answer with a ACK/NACK json message but their execution is provided through a separate thread (janus_streaming_handler).
      This is implemented with a GAsyncQueue which provide the push and pop methods.
      (As in the destroy case, one needs one session and one handle ids, but not necessarily the original ones).
      With 'watch' command one associates the current plugin streaming session to a mountpoint.
      At the same time a mountpoint is associated to one (or more sessions), so that whenever the RTP thread of a mountpoint detects a ready RTP packet it can deliver it to all the interested sessions.
      curl -X POST http://localhost:8088/janus/5/$handle --data "{\"transaction\": \"ciao\", \"janus\": \"message\", \"body\": {\"request\": \"watch\", \"id\": 7}}" 
      

Architecture

_________________                  ______________________               _______________________
|                |  plugin_handle  |                     |  listeners   |                      |
| plugin_session | --------------> | streaming_session   |------------<>| streaming_mountpoint |
------------------    handle       |                     |  mountpoint  |                      |
| - stopped      | <-------------- |                     |------------->|                      |
------------------                 -----------------------              ------------------------

Janus videoroom plugin interface interface

We use this plugin to realize a WebRTC2RTP bridge but it has been designed to support video conferencing.

  1. Let's first creat valid session and handle
    session_id=$(curl -X POST -d '{"janus": "create", "transaction": "ciao"}' http://localhost:8088/janus 2>/dev/null  | awk -F ' ' '/\"id\"/ {print $2}')
    echo "Session id: $session_id" 
    
    handle_id=$(curl -X POST http://localhost:8088/janus/$session_id --data "{\"transaction\": \"ciao\", \"janus\": \"attach\", \"plugin\":\"janus.plugin.videoroom\"}" 2>/dev/null | awk -F ' ' '/\"id\"/ {print $2}') 
    echo "Handle id: $handle_id" 
    
  1. we can now create a "room".
    curl -X POST http://localhost:8088/janus/$session_id/$handle_id --data "{\"transaction\": \"ciao\", \"janus\": \"message\", \"body\": {\"request\": \"create\", \"room\": 1234, \"publishers\": 1, \"bitrate\":128000, \"record\": false, \"description\": \"culo\", \"fir_freq\": 100}}"  2>/dev/null
    
  1. We can now create an RTP forward output with:
    room_id=$(curl -X POST http://localhost:8088/janus/$session_id/$handle_id --data "{\"transaction\": \"ciao\", \"janus\": \"message\", \"body\": {\"request\": \"list\"}}"  2>/dev/null | awk -F ' ' '/\"room\"/ {print $2}' | cut -d ',' -f 1 | tail -n1)  
    echo "Room id: $room_id" 
    
    user_id=$(curl -X POST http://localhost:8088/janus/$session_id/$handle_id --data "{\"transaction\": \"ciao\", \"janus\": \"message\", \"body\": {\"request\": \"listparticipants\", \"room\": $room_id}}" 2>/dev/null | awk -F ' ' '/\"id\"/ {print $2}' | cut -d ',' -f 1)  
    echo "User id: $user_id" 
    
    curl -X POST http://localhost:8088/janus/$session_id/$handle_id --data "{\"transaction\": \"ciao\", \"janus\": \"message\", \"body\": {\"request\": \"rtp_forward\", \"room\": $room_id, \"publisher_id\": $user_id, \"host\": \"127.0.0.1\", \"audio_port\": 5000, \"video_port\": 5002, \"audio_pt\": 111, \"video_pt\": 98, \"secret\": \"adminpwd\"}}" 
    
  1. Optionally, we can do the play out with FFmpeg:
    cat <<EOF > janus.sdp
    v=0
    o=- 0 0 IN IP4 127.0.0.1
    s=RTP Video
    c=IN IP4 127.0.0.1
    t=0 0
    a=tool:libavformat 56.15.102
    m=audio 5000 RTP/AVP 111
    a=rtpmap:111 OPUS/48000/2
    m=video 5002 RTP/AVP 98
    a=rtpmap:98 VP8/90000
    a=fmtp:98
    EOF
    
    ffmpeg -strict -2 -i janus.sdp -c:v libx264 -c:a mp2 janus.mp4
    

Plugin2Janus internals

Plugins are initialized with a Janus structure called janus_callbacks providing the interface plugins can use to communicate with the core.
This interface includes:
  • push_event(session, janus_plugin, message)
  • relay_rtp(session, rtp_pkt)
  • close_pc(session)
  • end_session(session)