Skip to content

SIP ​

janus.plugin.sip lets a browser register at a SIP server, place and receive SIP calls, send DTMF, and run SIP messaging, with Janus as the gateway: WebRTC on the browser side, SIP and plain RTP (or SDES-SRTP) on the other. You use it to put a web softphone in front of Asterisk, FreeSWITCH, Kamailio or a SIP trunk.

Every request is asynchronous. The POST answers ack, and the result arrives as an event with the same transaction, where plugindata.data.result.event names what happened. SIP errors from the network (a 403, a 486) are events too; mistakes in your request (wrong state, missing argument) are events with error_code.

Enable and configure ​

Build with plugin-sip. The SIP stack in this port is rsipstack (pure Rust), not Sofia-SIP. The plugin reads janus.plugin.sip.jcfg:

text
general: {
	local_ip = "127.0.0.1"
	keepalive_interval = 120
	register_ttl = 3600
	rtp_port_range = "20200-20300"
}

local_ip is the address the SIP socket and the SDP use; without it the plugin guesses the address of the default route. rtp_port_range is where the RTP and RTCP sockets of calls are taken from. All keys (sdp_ip, behind_nat, user_agent, admin_key, events, sip_timer_t1x64, DSCP…) are in the SIP config reference.

Try it ​

1. Without a SIP server: guest registration ​

Start the server, create a session, attach to janus.plugin.sip, and register as a guest. A guest registration sends no SIP REGISTER at all: it only sets the identity Janus will put in From for outgoing calls, so it works with nothing listening. This is what Janus Bench's sip.register check does.

sh
S=$(curl -s -d '{"janus":"create","transaction":"a"}' http://127.0.0.1:8088/janus | jq .data.id)
H=$(curl -s -d '{"janus":"attach","plugin":"janus.plugin.sip","transaction":"b"}' http://127.0.0.1:8088/janus/$S | jq .data.id)
curl -s -d '{"janus":"message","transaction":"c","body":{"request":"register","type":"guest","username":"sip:[email protected]","proxy":"sip:127.0.0.1:5060"}}' http://127.0.0.1:8088/janus/$S/$H
curl -s "http://127.0.0.1:8088/janus/$S?maxev=1"       # the registered event

2. Against a test peer: register, call, hold, transfer, hang up ​

The repository ships a small SIP peer for its parity tests: a registrar and user agent in Python (standard library only) at parity/sip-peer/peer.py. It wants digest authentication with the password secret. Start it, and point a registration at it:

sh
python3 -c "import sys, time; sys.path.insert(0, 'parity/sip-peer'); import peer; peer.Peer(5070, 6000); time.sleep(3600)"

(cargo run -p xtask -- parity-sip runs all its flows against both the C oracle and this server and diffs the SIP messages. That command needs Docker and was not run for this page.)

The transcripts below were recorded by docs-site/scripts/record-plugins-gateway.mjs against this peer. The browser offers are the canned SDPs of parity/sip-peer/sdp/: no PeerConnection is set up, so they show the signalling only. Lines marked SIP on the wire are the SIP messages the peer logged, with headers I could drop for space removed.

Register ​

A guest, a wrong secret (the peer answers 401, Janus retries with the digest, the peer answers 403), the right secret, and unregister:

jsonc
// SIP registration. A SIP peer (parity/sip-peer/peer.py, a registrar on 127.0.0.1:5070 that wants digest auth with password `secret`) runs on this machine.

// Config: general.local_ip = 127.0.0.1. Every request is answered with a Janus API ack; the result comes as an event.


// → POST /janus
{
  "janus": "create",
  "transaction": "t-create"
}

// ← 200 OK
{
  "janus": "success",
  "transaction": "t-create",
  "data": {
    "id": 4100001234567908
  }
}

// → POST /janus/4100001234567908
{
  "janus": "attach",
  "plugin": "janus.plugin.sip",
  "transaction": "t-attach"
}

// ← 200 OK
{
  "janus": "success",
  "session_id": 4100001234567908,
  "transaction": "t-attach",
  "data": {
    "id": 4100002469135799
  }
}

// 1. A guest registration: no SIP REGISTER is sent.

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-1",
  "body": {
    "request": "register",
    "type": "guest",
    "username": "sip:[email protected]:5070",
    "proxy": "sip:127.0.0.1:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-1"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-1",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "registered",
        "username": "guest",
        "register_sent": false,
        "master_id": 2007654332,
        "unique_id": "00a13bcf-3c1f-4d2a-9b5e-000000a13bcf"
      }
    }
  }
}

//    The peer saw 0 SIP messages from Janus while the guest registered.


// → POST /janus/4100001234567908
{
  "janus": "attach",
  "plugin": "janus.plugin.sip",
  "transaction": "t-attach"
}

// ← 200 OK
{
  "janus": "success",
  "session_id": 4100001234567908,
  "transaction": "t-attach",
  "data": {
    "id": 4100003703703690
  }
}

// 2. A registration with the wrong secret.

// → POST /janus/4100001234567908/4100003703703690
{
  "janus": "message",
  "transaction": "t-1",
  "body": {
    "request": "register",
    "username": "sip:[email protected]:5070",
    "secret": "wrong",
    "proxy": "sip:127.0.0.1:5070",
    "display_name": "Alice"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-1"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-1",
  "sender": 4100003703703690,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "registering",
        "unique_id": "00a15abe-3c1f-4d2a-9b5e-000000a15abe"
      }
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100003703703690,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "registration_failed",
        "code": 403,
        "reason": "Forbidden"
      }
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (wrong secret)
//   REGISTER sip:127.0.0.1:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs001
//   From: <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>
//   Call-ID: [email protected]
//   CSeq: 1 REGISTER
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Expires: 3600

// ⇠ SIP on the wire, peer to Janus (wrong secret)
//   SIP/2.0 401 Unauthorized
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs001
//   From: <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 1 REGISTER
//   WWW-Authenticate: Digest realm="janus-peer", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", algorithm=MD5

// ⇠ SIP on the wire, Janus to peer (wrong secret)
//   REGISTER sip:127.0.0.1:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs002
//   From: <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>
//   Call-ID: [email protected]
//   CSeq: 2 REGISTER
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Expires: 3600
//   Authorization: Digest username="alice", realm="janus-peer", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", algorithm=MD5, uri="sip:127.0.0.1:5070", response="88b3d8a180d157ffadfc6e2635bc329c"

// ⇠ SIP on the wire, peer to Janus (wrong secret)
//   SIP/2.0 403 Forbidden
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs002
//   From: <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 2 REGISTER


// → POST /janus/4100001234567908
{
  "janus": "attach",
  "plugin": "janus.plugin.sip",
  "transaction": "t-attach"
}

// ← 200 OK
{
  "janus": "success",
  "session_id": 4100001234567908,
  "transaction": "t-attach",
  "data": {
    "id": 4100004938271581
  }
}

// 3. A registration with the right secret: 401, then REGISTER with the digest, then 200.

// → POST /janus/4100001234567908/4100004938271581
{
  "janus": "message",
  "transaction": "t-1",
  "body": {
    "request": "register",
    "username": "sip:[email protected]:5070",
    "secret": "secret",
    "proxy": "sip:127.0.0.1:5070",
    "display_name": "Alice"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-1"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-1",
  "sender": 4100004938271581,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "registering",
        "unique_id": "00a179ad-3c1f-4d2a-9b5e-000000a179ad"
      }
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100004938271581,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "unique_id": "00a179ad-3c1f-4d2a-9b5e-000000a179ad",
      "result": {
        "event": "registered",
        "username": "alice",
        "register_sent": true,
        "master_id": 2015308653
      }
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (right secret)
//   REGISTER sip:127.0.0.1:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs003
//   From: <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5070>
//   Call-ID: [email protected]
//   CSeq: 1 REGISTER
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Expires: 3600

// ⇠ SIP on the wire, peer to Janus (right secret)
//   SIP/2.0 401 Unauthorized
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs003
//   From: <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5070>;tag=ta1989c
//   Call-ID: [email protected]
//   CSeq: 1 REGISTER
//   WWW-Authenticate: Digest realm="janus-peer", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", algorithm=MD5

// ⇠ SIP on the wire, Janus to peer (right secret)
//   REGISTER sip:127.0.0.1:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs004
//   From: <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5070>
//   Call-ID: [email protected]
//   CSeq: 2 REGISTER
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Expires: 3600
//   Authorization: Digest username="alice", realm="janus-peer", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", algorithm=MD5, uri="sip:127.0.0.1:5070", response="3461abbe2afef5e13152b140ec36ec36"

// ⇠ SIP on the wire, peer to Janus (right secret)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs004
//   From: <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5070>;tag=ta1989c
//   Call-ID: [email protected]
//   CSeq: 2 REGISTER
//   Contact: Alice <sip:[email protected]:5060;transport=udp>;expires=3600


// 4. The same handle registers again, then unregisters.

// → POST /janus/4100001234567908/4100004938271581
{
  "janus": "message",
  "transaction": "t-2",
  "body": {
    "request": "register",
    "username": "sip:[email protected]:5070",
    "secret": "secret",
    "proxy": "sip:127.0.0.1:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-2"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100004938271581,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "error_code": 445,
      "error": "Already registered (alice)"
    }
  }
}

// → POST /janus/4100001234567908/4100004938271581
{
  "janus": "message",
  "transaction": "t-3",
  "body": {
    "request": "unregister"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-3"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-3",
  "sender": 4100004938271581,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "unregistering"
      }
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100004938271581,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "unique_id": "00a179ad-3c1f-4d2a-9b5e-000000a179ad",
      "result": {
        "event": "unregistered",
        "username": "alice"
      }
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (unregister)
//   REGISTER sip:127.0.0.1:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs005
//   From: <sip:[email protected]:5070>;tag=ta1b78b
//   To: <sip:[email protected]:5070>
//   Call-ID: [email protected]
//   CSeq: 3 REGISTER
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Expires: 0

// ⇠ SIP on the wire, peer to Janus (unregister)
//   SIP/2.0 401 Unauthorized
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs005
//   From: <sip:[email protected]:5070>;tag=ta1b78b
//   To: <sip:[email protected]:5070>;tag=ta1989c
//   Call-ID: [email protected]
//   CSeq: 3 REGISTER
//   WWW-Authenticate: Digest realm="janus-peer", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", algorithm=MD5

// ⇠ SIP on the wire, Janus to peer (unregister)
//   REGISTER sip:127.0.0.1:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs006
//   From: <sip:[email protected]:5070>;tag=ta1b78b
//   To: <sip:[email protected]:5070>
//   Call-ID: [email protected]
//   CSeq: 4 REGISTER
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Expires: 0
//   Authorization: Digest username="alice", realm="janus-peer", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", algorithm=MD5, uri="sip:127.0.0.1:5070", response="3461abbe2afef5e13152b140ec36ec36"

// ⇠ SIP on the wire, peer to Janus (unregister)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs006
//   From: <sip:[email protected]:5070>;tag=ta1b78b
//   To: <sip:[email protected]:5070>;tag=ta1989c
//   Call-ID: [email protected]
//   CSeq: 4 REGISTER
//   Contact: Alice <sip:[email protected]:5060;transport=udp>;expires=0

Outgoing call ​

call needs a JSEP offer. The events are calling, ringing (the 180), proceeding, then accepted carrying the peer's answer as a JSEP. The rest of the transcript runs hold, unhold, dtmf_info, info, message, update, transfer and hangup during the call.

Outgoing call transcript (about 20 KB)
jsonc
// An outgoing call to the peer. The browser offer is the canned audio and video offer of parity/sip-peer/sdp;

// no PeerConnection is set up, so this shows the signalling only (see the Bench `sip.register` check for a browser).


// → POST /janus
{
  "janus": "create",
  "transaction": "t-create"
}

// ← 200 OK
{
  "janus": "success",
  "transaction": "t-create",
  "data": {
    "id": 4100001234567908
  }
}

// → POST /janus/4100001234567908
{
  "janus": "attach",
  "plugin": "janus.plugin.sip",
  "transaction": "t-attach"
}

// ← 200 OK
{
  "janus": "success",
  "session_id": 4100001234567908,
  "transaction": "t-attach",
  "data": {
    "id": 4100002469135799
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-1",
  "body": {
    "request": "register",
    "username": "sip:[email protected]:5070",
    "secret": "secret",
    "proxy": "sip:127.0.0.1:5070",
    "display_name": "Alice"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-1"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-1",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "registering",
        "unique_id": "00a13bcf-3c1f-4d2a-9b5e-000000a13bcf"
      }
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "unique_id": "00a13bcf-3c1f-4d2a-9b5e-000000a13bcf",
      "result": {
        "event": "registered",
        "username": "alice",
        "register_sent": true,
        "master_id": 2007654332
      }
    }
  }
}


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-2",
  "body": {
    "request": "call",
    "uri": "sip:[email protected]:5070"
  },
  "jsep": {
    "type": "offer",
    "sdp": "v=0\r\no=- 4611731400430051336 2 IN IP4 127.0.0.1\r\ns=-\r\n…"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-2"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "calling",
        "call_id": "call-1"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "ringing"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "proceeding",
        "code": 180
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "accepted",
        "username": "sip:[email protected]:5070"
      },
      "call_id": "call-1"
    }
  },
  "jsep": {
    "type": "answer",
    "sdp": "v=0\r\no=peer 1 1 IN IP4 192.0.2.10\r\ns=peer\r\n…"
  }
}

// ⇠ SIP on the wire, Janus to peer (the call)
//   INVITE sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs001
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>
//   Call-ID: call-1
//   CSeq: 1 INVITE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Content-Type: application/sdp
//   Content-Disposition: session
//   
//   m=audio 20216 RTP/AVP 111
//   c=IN IP4 127.0.0.1
//   a=rtpmap:111 opus/48000/2
//   m=video 20248 RTP/AVP 96
//   c=IN IP4 127.0.0.1
//   a=rtpmap:96 VP8/90000
//   ... (6 more SDP lines)

// ⇠ SIP on the wire, peer to Janus (the call)
//   SIP/2.0 100 Trying
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs001
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>
//   Call-ID: call-1
//   CSeq: 1 INVITE

// ⇠ SIP on the wire, peer to Janus (the call)
//   SIP/2.0 180 Ringing
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs001
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 1 INVITE
//   Contact: <sip:[email protected]:5070>

// ⇠ SIP on the wire, peer to Janus (the call)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs001
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 1 INVITE
//   Contact: <sip:[email protected]:5070>
//   Content-Type: application/sdp
//   
//   c=IN IP4 127.0.0.1
//   m=audio 6000 RTP/AVP 111
//   a=rtpmap:111 opus/48000/2
//   a=sendrecv
//   m=video 6002 RTP/AVP 96
//   a=rtpmap:96 VP8/90000
//   a=sendrecv
//   ... (4 more SDP lines)

// ⇠ SIP on the wire, Janus to peer (the call)
//   ACK sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs002
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 1 ACK


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-3",
  "body": {
    "request": "hold"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-3"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-3",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "holding"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (hold)
//   INVITE sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs003
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 2 INVITE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Content-Type: application/sdp
//   Content-Disposition: session
//   
//   m=audio 20216 RTP/AVP 111
//   c=IN IP4 127.0.0.1
//   a=rtpmap:111 opus/48000/2
//   a=sendonly
//   m=video 20248 RTP/AVP 96
//   c=IN IP4 127.0.0.1
//   a=rtpmap:96 VP8/90000
//   a=sendonly
//   ... (6 more SDP lines)

// ⇠ SIP on the wire, peer to Janus (hold)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs003
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 2 INVITE
//   Contact: <sip:[email protected]:5070>
//   Content-Type: application/sdp
//   
//   c=IN IP4 127.0.0.1
//   m=audio 6000 RTP/AVP 111
//   a=rtpmap:111 opus/48000/2
//   a=recvonly
//   m=video 6002 RTP/AVP 96
//   a=rtpmap:96 VP8/90000
//   a=recvonly
//   ... (4 more SDP lines)


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-4",
  "body": {
    "request": "unhold"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-4"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-4",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "resuming"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (unhold)
//   INVITE sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs004
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 3 INVITE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Content-Type: application/sdp
//   Content-Disposition: session
//   
//   m=audio 20216 RTP/AVP 111
//   c=IN IP4 127.0.0.1
//   a=rtpmap:111 opus/48000/2
//   m=video 20248 RTP/AVP 96
//   c=IN IP4 127.0.0.1
//   a=rtpmap:96 VP8/90000
//   ... (6 more SDP lines)

// ⇠ SIP on the wire, peer to Janus (unhold)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs004
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 3 INVITE
//   Contact: <sip:[email protected]:5070>
//   Content-Type: application/sdp
//   
//   c=IN IP4 127.0.0.1
//   m=audio 6000 RTP/AVP 111
//   a=rtpmap:111 opus/48000/2
//   a=sendrecv
//   m=video 6002 RTP/AVP 96
//   a=rtpmap:96 VP8/90000
//   a=sendrecv
//   ... (4 more SDP lines)


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-5",
  "body": {
    "request": "dtmf_info",
    "digit": "5",
    "duration": 160
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-5"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-5",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "dtmfsent"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (dtmf_info)
//   INFO sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs005
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 4 INFO
//   Content-Type: application/dtmf-relay
//   
//   Signal=5
//   Duration=160

// ⇠ SIP on the wire, peer to Janus (dtmf_info)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs005
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 4 INFO


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-6",
  "body": {
    "request": "info",
    "type": "application/x-test",
    "content": "hello=1"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-6"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-6",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "infosent"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (info)
//   INFO sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs006
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 5 INFO
//   Content-Type: application/x-test
//   
//   hello=1

// ⇠ SIP on the wire, peer to Janus (info)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs006
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 5 INFO


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-7",
  "body": {
    "request": "message",
    "content_type": "text/plain",
    "content": "hi bob"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-7"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-7",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "messagesent",
        "call_id": "call-1"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "messagedelivery",
        "code": 200,
        "reason": "OK"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (message)
//   MESSAGE sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs007
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 6 MESSAGE
//   Content-Type: text/plain
//   
//   hi bob

// ⇠ SIP on the wire, peer to Janus (message)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs007
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 6 MESSAGE


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-8",
  "body": {
    "request": "update"
  },
  "jsep": {
    "type": "offer",
    "sdp": "v=0\r\no=- 4611731400430051336 2 IN IP4 127.0.0.1\r\ns=-\r\n…"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-8"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-8",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "updating"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (update)
//   INVITE sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs008
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 7 INVITE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Content-Type: application/sdp
//   Content-Disposition: session
//   
//   m=audio 20216 RTP/AVP 111
//   c=IN IP4 127.0.0.1
//   a=rtpmap:111 opus/48000/2
//   m=video 20248 RTP/AVP 96
//   c=IN IP4 127.0.0.1
//   a=rtpmap:96 VP8/90000
//   ... (6 more SDP lines)

// ⇠ SIP on the wire, peer to Janus (update)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs008
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 7 INVITE
//   Contact: <sip:[email protected]:5070>
//   Content-Type: application/sdp
//   
//   c=IN IP4 127.0.0.1
//   m=audio 6000 RTP/AVP 111
//   a=rtpmap:111 opus/48000/2
//   a=sendrecv
//   m=video 6002 RTP/AVP 96
//   a=rtpmap:96 VP8/90000
//   a=sendrecv
//   ... (4 more SDP lines)


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-9",
  "body": {
    "request": "transfer",
    "uri": "sip:[email protected]:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-9"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-9",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "transferring"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "call_id": "call-1",
      "result": {
        "event": "notify",
        "notify": "refer",
        "substate": "terminated",
        "content-type": "message/sipfrag",
        "content": "SIP/2.0 200 OK\r\n"
      }
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (transfer)
//   REFER sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs009
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 8 REFER
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Refer-To: <sip:[email protected]:5070>
//   Referred-By: <sip:[email protected]:5060;transport=udp>

// ⇠ SIP on the wire, peer to Janus (transfer)
//   SIP/2.0 202 Accepted
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs009
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 8 REFER

// ⇠ SIP on the wire, peer to Janus (transfer)
//   NOTIFY sip:[email protected]:5060;transport=udp SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs010
//   From: <sip:[email protected]:5070>;tag=ta15abe
//   To: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   Call-ID: call-1
//   CSeq: 102 NOTIFY
//   Event: refer;id=8
//   Subscription-State: active;expires=60
//   Content-Type: message/sipfrag;version=2.0
//   Contact: <sip:[email protected]:5070>
//   
//   SIP/2.0 100 Trying

// ⇠ SIP on the wire, Janus to peer (transfer)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs010
//   From: <sip:[email protected]:5070>;tag=ta15abe
//   To: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   Call-ID: call-1
//   CSeq: 102 NOTIFY
//   Contact: Alice <sip:[email protected]:5060;transport=udp>

// ⇠ SIP on the wire, peer to Janus (transfer)
//   NOTIFY sip:[email protected]:5060;transport=udp SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs011
//   From: <sip:[email protected]:5070>;tag=ta15abe
//   To: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   Call-ID: call-1
//   CSeq: 104 NOTIFY
//   Event: refer;id=8
//   Subscription-State: terminated;reason=noresource
//   Content-Type: message/sipfrag;version=2.0
//   Contact: <sip:[email protected]:5070>
//   
//   SIP/2.0 200 OK

// ⇠ SIP on the wire, Janus to peer (transfer)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs011
//   From: <sip:[email protected]:5070>;tag=ta15abe
//   To: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   Call-ID: call-1
//   CSeq: 104 NOTIFY
//   Contact: Alice <sip:[email protected]:5060;transport=udp>


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-10",
  "body": {
    "request": "hangup"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-10"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-10",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "hangingup"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "hangup",
        "code": 200,
        "reason": "to BYE"
      },
      "call_id": "call-1"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (hangup)
//   BYE sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs012
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 9 BYE

// ⇠ SIP on the wire, peer to Janus (hangup)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs012
//   From: "Alice" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 9 BYE

Incoming call ​

The peer sends an INVITE to the contact Janus registered. You get incomingcall with a JSEP offer. Send progress (a 183) and accept (the 200) each with a JSEP answer. While the call is up the transcript starts and stops a recording, requests a keyframe, and adds, lists and stops RTP forwarders, then the peer sends an INFO (DTMF), a MESSAGE and a BYE. A second call is declined.

Incoming call transcript (about 17 KB)
jsonc
// An incoming call: the peer sends an INVITE to the contact that Janus registered. Janus API signalling only.


// → POST /janus
{
  "janus": "create",
  "transaction": "t-create"
}

// ← 200 OK
{
  "janus": "success",
  "transaction": "t-create",
  "data": {
    "id": 4100001234567908
  }
}

// → POST /janus/4100001234567908
{
  "janus": "attach",
  "plugin": "janus.plugin.sip",
  "transaction": "t-attach"
}

// ← 200 OK
{
  "janus": "success",
  "session_id": 4100001234567908,
  "transaction": "t-attach",
  "data": {
    "id": 4100002469135799
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-1",
  "body": {
    "request": "register",
    "username": "sip:[email protected]:5070",
    "secret": "secret",
    "proxy": "sip:127.0.0.1:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-1"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-1",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "registering",
        "unique_id": "00a13bcf-3c1f-4d2a-9b5e-000000a13bcf"
      }
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "unique_id": "00a13bcf-3c1f-4d2a-9b5e-000000a13bcf",
      "result": {
        "event": "registered",
        "username": "alice",
        "register_sent": true,
        "master_id": 2007654332
      }
    }
  }
}


// The peer sends an INVITE.

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "incomingcall",
        "username": "sip:[email protected]:5070",
        "call_id": "[email protected]",
        "displayname": "\"Peer\"",
        "callee": "sip:[email protected]:5060;transport=udp"
      },
      "call_id": "[email protected]"
    }
  },
  "jsep": {
    "type": "offer",
    "sdp": "v=0\r\no=peer 1 1 IN IP4 192.0.2.10\r\ns=peer\r\n…"
  }
}

// ⇠ SIP on the wire, peer to Janus (incoming INVITE)
//   INVITE sip:[email protected]:5060;transport=udp SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs001
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>
//   Call-ID: [email protected]
//   CSeq: 105 INVITE
//   Contact: <sip:[email protected]:5070>
//   Content-Type: application/sdp
//   
//   c=IN IP4 127.0.0.1
//   m=audio 6000 RTP/AVP 111 0 8 101
//   a=rtpmap:111 opus/48000/2
//   a=rtpmap:0 PCMU/8000
//   a=rtpmap:8 PCMA/8000
//   a=rtpmap:101 telephone-event/8000
//   a=sendrecv
//   ... (6 more SDP lines)

// ⇠ SIP on the wire, Janus to peer (incoming INVITE)
//   SIP/2.0 100 Trying
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs001
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>
//   Call-ID: [email protected]
//   CSeq: 105 INVITE

// ⇠ SIP on the wire, Janus to peer (incoming INVITE)
//   SIP/2.0 180 Ringing
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs001
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 105 INVITE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-2",
  "body": {
    "request": "progress"
  },
  "jsep": {
    "type": "answer",
    "sdp": "v=0\r\no=- 6100000000001000000 2 IN IP4 127.0.0.1\r\ns=-\r\n…"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-2"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "progressed"
      },
      "call_id": "[email protected]"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (progress)
//   SIP/2.0 183 Session Progress
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs001
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 105 INVITE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Content-Type: application/sdp
//   Content-Disposition: session
//   
//   m=audio 20220 RTP/AVP 111
//   c=IN IP4 127.0.0.1
//   a=rtpmap:111 opus/48000/2
//   ... (5 more SDP lines)


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-3",
  "body": {
    "request": "accept"
  },
  "jsep": {
    "type": "answer",
    "sdp": "v=0\r\no=- 6100000000001000000 2 IN IP4 127.0.0.1\r\ns=-\r\n…"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-3"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-3",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "accepted"
      },
      "call_id": "[email protected]"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (accept)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs001
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 105 INVITE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Content-Type: application/sdp
//   Content-Disposition: session
//   
//   m=audio 20220 RTP/AVP 111
//   c=IN IP4 127.0.0.1
//   a=rtpmap:111 opus/48000/2
//   ... (5 more SDP lines)

// ⇠ SIP on the wire, Janus to peer (accept)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs001
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 105 INVITE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Content-Type: application/sdp
//   Content-Disposition: session
//   
//   m=audio 20220 RTP/AVP 111
//   c=IN IP4 127.0.0.1
//   a=rtpmap:111 opus/48000/2
//   ... (5 more SDP lines)


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-4",
  "body": {
    "request": "recording",
    "action": "start",
    "audio": true,
    "video": true,
    "peer_audio": true,
    "peer_video": true,
    "filename": "docs-call"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-4"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-4",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "recordingupdated"
      },
      "call_id": "[email protected]"
    }
  }
}

// Files in the server's working directory now: docs-call-user-audio.mjr, docs-call-user-video.mjr


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-5",
  "body": {
    "request": "recording",
    "action": "stop",
    "audio": true,
    "video": true,
    "peer_audio": true,
    "peer_video": true
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-5"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-5",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "recordingupdated"
      },
      "call_id": "[email protected]"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-6",
  "body": {
    "request": "keyframe",
    "user": true,
    "peer": true
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-6"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-6",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "keyframesent"
      },
      "call_id": "[email protected]"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-7",
  "body": {
    "request": "rtp_forward",
    "streams": [
      {
        "type": "audio",
        "host": "127.0.0.1",
        "port": 5004
      }
    ]
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-7"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-7",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "forwarders": [
          {
            "stream_id": 2015308653,
            "type": "audio",
            "host": "127.0.0.1",
            "port": 5004,
            "media": "audio"
          }
        ],
        "event": "rtp_forward"
      },
      "call_id": "[email protected]"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-8",
  "body": {
    "request": "listforwarders"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-8"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-8",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "forwarders",
        "rtp_forwarders": [
          {
            "stream_id": 2015308653,
            "type": "audio",
            "host": "127.0.0.1",
            "port": 5004,
            "media": "audio"
          }
        ]
      },
      "call_id": "[email protected]"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-9",
  "body": {
    "request": "stop_rtp_forward",
    "streams": [
      2015308653
    ]
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-9"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-9",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "stop_rtp_forward",
        "streams": [
          2015308653
        ]
      },
      "call_id": "[email protected]"
    }
  }
}


// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "info",
        "sender": "sip:[email protected]:5070",
        "displayname": "\"Peer\"",
        "type": "application/dtmf-relay",
        "content": "Signal=7\r\nDuration=100\r\n"
      },
      "call_id": "[email protected]"
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "message",
        "sender": "sip:[email protected]:5070",
        "displayname": "\"Peer\"",
        "content": "hello janus",
        "content_type": "text/plain"
      },
      "call_id": "[email protected]"
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "hangup",
        "code": 200,
        "reason": "Session Terminated"
      },
      "call_id": "[email protected]"
    }
  }
}

// ⇠ SIP on the wire, peer to Janus (peer INFO, MESSAGE and BYE)
//   INFO sip:[email protected]:5060;transport=udp SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs002
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 107 INFO
//   Contact: <sip:[email protected]:5070>
//   Content-Type: application/dtmf-relay
//   
//   Signal=7
//   Duration=100

// ⇠ SIP on the wire, Janus to peer (peer INFO, MESSAGE and BYE)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs002
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 107 INFO

// ⇠ SIP on the wire, peer to Janus (peer INFO, MESSAGE and BYE)
//   MESSAGE sip:[email protected]:5060;transport=udp SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs003
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 108 MESSAGE
//   Contact: <sip:[email protected]:5070>
//   Content-Type: text/plain
//   
//   hello janus

// ⇠ SIP on the wire, Janus to peer (peer INFO, MESSAGE and BYE)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs003
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 108 MESSAGE

// ⇠ SIP on the wire, peer to Janus (peer INFO, MESSAGE and BYE)
//   BYE sip:[email protected]:5060;transport=udp SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs004
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 109 BYE
//   Contact: <sip:[email protected]:5070>

// ⇠ SIP on the wire, Janus to peer (peer INFO, MESSAGE and BYE)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs004
//   From: "Peer" <sip:[email protected]:5070>;tag=ta13bcf
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta15abe
//   Call-ID: [email protected]
//   CSeq: 109 BYE


// A second incoming call, declined with a 603.

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "incomingcall",
        "username": "sip:[email protected]:5070",
        "call_id": "[email protected]",
        "displayname": "\"Peer\"",
        "callee": "sip:[email protected]:5060;transport=udp"
      },
      "call_id": "[email protected]"
    }
  },
  "jsep": {
    "type": "offer",
    "sdp": "v=0\r\no=peer 1 1 IN IP4 192.0.2.10\r\ns=peer\r\n…"
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-10",
  "body": {
    "request": "decline",
    "code": 603
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-10"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-10",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "declining",
        "code": 603,
        "call_id": "[email protected]"
      },
      "call_id": "[email protected]"
    }
  }
}

// ⇠ SIP on the wire, peer to Janus (decline)
//   INVITE sip:[email protected]:5060;transport=udp SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs005
//   From: "Peer" <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5060;transport=udp>
//   Call-ID: [email protected]
//   CSeq: 110 INVITE
//   Contact: <sip:[email protected]:5070>
//   Content-Type: application/sdp
//   
//   c=IN IP4 127.0.0.1
//   m=audio 6000 RTP/AVP 111 0 8 101
//   a=rtpmap:111 opus/48000/2
//   a=rtpmap:0 PCMU/8000
//   a=rtpmap:8 PCMA/8000
//   a=rtpmap:101 telephone-event/8000
//   a=sendrecv
//   ... (6 more SDP lines)

// ⇠ SIP on the wire, Janus to peer (decline)
//   SIP/2.0 100 Trying
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs005
//   From: "Peer" <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5060;transport=udp>
//   Call-ID: [email protected]
//   CSeq: 110 INVITE

// ⇠ SIP on the wire, Janus to peer (decline)
//   SIP/2.0 180 Ringing
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs005
//   From: "Peer" <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta1989c
//   Call-ID: [email protected]
//   CSeq: 110 INVITE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>

// ⇠ SIP on the wire, Janus to peer (decline)
//   SIP/2.0 603 Decline
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs005
//   From: "Peer" <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta1989c
//   Call-ID: [email protected]
//   CSeq: 110 INVITE

Subscribe and message outside a call ​

jsonc
// SUBSCRIBE and NOTIFY, and a SIP MESSAGE outside a call (the account must be registered; `uri` is required).


// → POST /janus
{
  "janus": "create",
  "transaction": "t-create"
}

// ← 200 OK
{
  "janus": "success",
  "transaction": "t-create",
  "data": {
    "id": 4100001234567908
  }
}

// → POST /janus/4100001234567908
{
  "janus": "attach",
  "plugin": "janus.plugin.sip",
  "transaction": "t-attach"
}

// ← 200 OK
{
  "janus": "success",
  "session_id": 4100001234567908,
  "transaction": "t-attach",
  "data": {
    "id": 4100002469135799
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-1",
  "body": {
    "request": "register",
    "username": "sip:[email protected]:5070",
    "secret": "secret",
    "proxy": "sip:127.0.0.1:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-1"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-1",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "registering",
        "unique_id": "00a13bcf-3c1f-4d2a-9b5e-000000a13bcf"
      }
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "unique_id": "00a13bcf-3c1f-4d2a-9b5e-000000a13bcf",
      "result": {
        "event": "registered",
        "username": "alice",
        "register_sent": true,
        "master_id": 2007654332
      }
    }
  }
}


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-2",
  "body": {
    "request": "subscribe",
    "event": "message-summary",
    "accept": "application/simple-message-summary",
    "to": "sip:[email protected]:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-2"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "subscribing"
      }
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "call_id": "call-1",
      "result": {
        "event": "subscribe_succeeded",
        "code": 200,
        "expires": 3600,
        "reason": "OK"
      }
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "call_id": "call-1",
      "result": {
        "event": "notify",
        "notify": "message-summary",
        "substate": "active",
        "content-type": "application/simple-message-summary",
        "content": "Messages-Waiting: yes\r\nMessage-Account: sip:[email protected]\r\nVoice-Message: 2/8 (0/2)\r\n"
      }
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (subscribe)
//   SUBSCRIBE sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs001
//   From: <sip:[email protected]:5060;transport=udp>;tag=ta13bcf
//   To: <sip:[email protected]:5070>
//   Call-ID: call-1
//   CSeq: 1 SUBSCRIBE
//   Contact: Alice <sip:[email protected]:5060;transport=udp>
//   Expires: 3600
//   Event: message-summary

// ⇠ SIP on the wire, peer to Janus (subscribe)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs001
//   From: <sip:[email protected]:5060;transport=udp>;tag=ta13bcf
//   To: <sip:[email protected]:5070>;tag=ta15abe
//   Call-ID: call-1
//   CSeq: 1 SUBSCRIBE
//   Expires: 3600
//   Contact: <sip:[email protected]:5070>

// ⇠ SIP on the wire, peer to Janus (subscribe)
//   NOTIFY sip:[email protected]:5060;transport=udp SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs002
//   From: <sip:[email protected]:5070>;tag=ta15abe
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta13bcf
//   Call-ID: call-1
//   CSeq: 112 NOTIFY
//   Event: message-summary
//   Subscription-State: active;expires=3600
//   Content-Type: application/simple-message-summary
//   Contact: <sip:[email protected]:5070>
//   
//   Messages-Waiting: yes
//   Message-Account: sip:[email protected]
//   Voice-Message: 2/8 (0/2)

// ⇠ SIP on the wire, Janus to peer (subscribe)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5070;branch=z9hG4bKdocs002
//   From: <sip:[email protected]:5070>;tag=ta15abe
//   To: <sip:[email protected]:5060;transport=udp>;tag=ta13bcf
//   Call-ID: call-1
//   CSeq: 112 NOTIFY
//   Contact: Alice <sip:[email protected]:5060;transport=udp>


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-3",
  "body": {
    "request": "unsubscribe",
    "event": "message-summary",
    "to": "sip:[email protected]:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-3"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-3",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "unsubscribing"
      }
    }
  }
}


// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-4",
  "body": {
    "request": "message",
    "uri": "sip:[email protected]:5070",
    "content_type": "text/plain",
    "content": "hello outside a call"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-4"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-4",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "messagesent",
        "call_id": "call-2"
      }
    }
  }
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "messagedelivery",
        "code": 200,
        "reason": "OK"
      },
      "call_id": "call-2"
    }
  }
}

// ⇠ SIP on the wire, Janus to peer (MESSAGE outside a call)
//   MESSAGE sip:[email protected]:5070 SIP/2.0
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs003
//   From: <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5070>
//   Call-ID: call-2
//   CSeq: 1 MESSAGE
//   Content-Type: text/plain
//   
//   hello outside a call

// ⇠ SIP on the wire, peer to Janus (MESSAGE outside a call)
//   SIP/2.0 200 OK
//   Via: SIP/2.0/UDP 127.0.0.1:5060;rport;branch=z9hG4bKdocs003
//   From: <sip:[email protected]:5070>;tag=ta179ad
//   To: <sip:[email protected]:5070>;tag=ta1989c
//   Call-ID: call-2
//   CSeq: 1 MESSAGE

Errors ​

jsonc
// Requests in the wrong state or with missing parameters. Every error is an event with error_code and error.


// → POST /janus
{
  "janus": "create",
  "transaction": "t-create"
}

// ← 200 OK
{
  "janus": "success",
  "transaction": "t-create",
  "data": {
    "id": 4100001234567908
  }
}

// → POST /janus/4100001234567908
{
  "janus": "attach",
  "plugin": "janus.plugin.sip",
  "transaction": "t-attach"
}

// ← 200 OK
{
  "janus": "success",
  "session_id": 4100001234567908,
  "transaction": "t-attach",
  "data": {
    "id": 4100002469135799
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-1",
  "body": {
    "request": "call",
    "uri": "sip:[email protected]:5070"
  },
  "jsep": {
    "type": "offer",
    "sdp": "v=0\r\no=- 4611731400430051336 2 IN IP4 127.0.0.1\r\ns=-\r\n…"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-1"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-1",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "error_code": 447,
      "error": "Wrong state (register first)"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-2",
  "body": {
    "request": "register"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-2"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-2",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "error_code": 443,
      "error": "Missing mandatory element (username)"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-3",
  "body": {
    "request": "register",
    "username": "not a uri",
    "type": "guest"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-3"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-3",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "error_code": 446,
      "error": "Invalid user address not a uri\n"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-4",
  "body": {
    "request": "accept"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-4"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-4",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "error_code": 447,
      "error": "Wrong state (not invited or progress? status=idle)"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-5",
  "body": {
    "request": "hangup"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-5"
}

// (no event follows: the request is ignored)

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-6",
  "body": {
    "request": "recording"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-6"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-6",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "error_code": 0,
      "error": "Wrong state (not in a call?)"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-7",
  "body": {
    "request": "bogus"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-7"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-7",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "error_code": 442,
      "error": "Unknown request (bogus)"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-8",
  "body": {
    "request": "register",
    "type": "guest",
    "username": "sip:[email protected]:5070",
    "proxy": "sip:127.0.0.1:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-8"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-8",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "result": {
        "event": "registered",
        "username": "guest",
        "register_sent": false,
        "master_id": 2007654332,
        "unique_id": "00a13bcf-3c1f-4d2a-9b5e-000000a13bcf"
      }
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-9",
  "body": {
    "request": "call",
    "uri": "sip:[email protected]:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-9"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-9",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "error_code": 448,
      "error": "Missing SDP"
    }
  }
}

// → POST /janus/4100001234567908/4100002469135799
{
  "janus": "message",
  "transaction": "t-10",
  "body": {
    "request": "register",
    "type": "guest",
    "username": "sip:[email protected]:5070",
    "proxy": "sip:127.0.0.1:5070"
  }
}

// ← 200 OK
{
  "janus": "ack",
  "session_id": 4100001234567908,
  "transaction": "t-10"
}

// ⇠ event, long poll GET /janus/<session>
{
  "janus": "event",
  "session_id": 4100001234567908,
  "transaction": "t-10",
  "sender": 4100002469135799,
  "plugindata": {
    "plugin": "janus.plugin.sip",
    "data": {
      "sip": "event",
      "error_code": 445,
      "error": "Already registered (guest)"
    }
  }
}

3. Against Asterisk or FreeSWITCH ​

Point proxy at the PBX and register an extension:

json
{ "request": "register", "username": "sip:[email protected]", "secret": "1001-password",
  "proxy": "sip:pbx.example.com", "display_name": "Browser 1001" }

then call with "uri": "sip:[email protected]" and the browser's offer. This is written from the C documentation and the request reader of the Rust plugin: it was not run against a real PBX for this page. For media you also need the PBX to accept the browser's codecs (Opus, or PCMU and PCMA) and, if it does not terminate ICE, nothing else: Janus sends plain RTP to the SDP address of the peer. Set local_ip or sdp_ip to an address the PBX can reach.

Reference ​

Requests ​

All have "request": "<name>". Parameters not marked required are optional.

RequestParametersEvents
registerusername (SIP URI, required), type (guest or helper: no REGISTER is sent), send_register (false: no REGISTER), secret, ha1_secret, authuser, display_name, user_agent, proxy, outbound_proxy, headers (object), contact_params, incoming_header_prefixes (array), refresh, master_id (for helpers), register_ttl, force_udp, force_tcp, sips, rfc2543_cancel, automatic_ringingregistering (not for guests), then registered (username, register_sent, master_id, unique_id) or registration_failed (code, reason)
unregisternoneunregistering, unregistered
calluri (required, with a JSEP offer), call_id, refer_id, headers, srtp (sdes_optional or sdes_mandatory), srtp_profile, secret, ha1_secret, authuser, autoaccept_reinvitescalling (with call_id), ringing, proceeding (code), progress (early media, with a JSEP), accepted (with the JSEP answer), or hangup with a SIP code and reason
acceptJSEP answer (or offer, for an offerless INVITE), srtp, srtp_profile, headers, autoaccept_reinvitesaccepted, or accepting first for an offerless INVITE
progresslike acceptprogressed (a 183 to the caller)
declinecode (default 486), headersdeclining, then hangup
hangupheadershangingup, then hangup (code, reason)
holddirection (sendonly, recvonly, inactive)holding
unholdnoneresuming
updateJSEP offer (renegotiation, ICE restart) or answer (to a peer's re-INVITE)updating (offer) or updated (answer)
dtmf_infodigit, duration (ms)dtmfsent
infotype, content, headersinfosent
messagecontent, content_type, uri (send outside a call), call_id, headersmessagesent, then messagedelivery (code, reason)
subscribeevent (required), accept, to, call_id, subscribe_ttl, content, content_type, headerssubscribing, then subscribe_succeeded or subscribe_failed; NOTIFYs arrive as notify
unsubscribeevent, to, call_idunsubscribing, then subscribe_succeeded with expires: 0
transferuri (required), replace (Call-ID, for an attended transfer)transferring, then notify events with notify: "refer"
recordingaction (start, stop), audio, video, peer_audio, peer_video, send_peer_pli, filenamerecordingupdated
keyframeuser, peer (booleans)keyframesent
rtp_forwardstreams: array of {type (audio, video, peer_audio, peer_video), host, port, host_family, ssrc, pt, srtp_suite, srtp_crypto}; unique_id, admin_keyrtp_forward with forwarders (stream_id, type, host, port, media)
stop_rtp_forwardstreams (array of stream_id)stop_rtp_forward with streams
listforwardersunique_id, admin_keyforwarders with rtp_forwarders

Events pushed by the peer ​

result.eventWhenFields
incomingcallan INVITE arrives (with a JSEP offer when the INVITE had SDP)username, displayname, callee, call_id, referred_by, replaces, srtp, headers
missed_callan INVITE arrives while this handle is in a callcaller, callee, call_id
updatingcalla re-INVITE arrives and autoaccept_reinvites is falselike incomingcall; answer with update
infoa SIP INFO arrives (DTMF relay included)sender, displayname, type, content
messagea SIP MESSAGE arrivessender, displayname, content_type, content
notifya NOTIFY arrives (subscription or REFER progress)notify, substate, content-type, content
transfera REFER arrivesrefer_id, refer_to, referred_by, replaces; follow up with call and that refer_id
dtmfan RFC 2833 DTMF event reaches the mediasender, signal, duration
hangupthe call ended (peer BYE, a decline, or an error status)code, reason (and reason_header* when present)

After the plugin's hangup event, Janus also pushes its own {"janus": "hangup", "reason": "Close PC"} for the handle.

Error codes ​

CodeMeaning
440 to 444No message, invalid JSON, unknown request, missing element, invalid element
445Already registered
446Invalid address (not a SIP URI)
447Wrong state (register first, not in a call…)
448Missing SDP
449 to 456Stack error, I/O error, recording error, helper error, no such Call-ID, stream or unique_id
490Unauthorized (wrong admin_key)
499Other

recording with no call answers error_code: 0 and Wrong state (not in a call?). That is what the C plugin does too (it is in parity/traces/sip-requests).

Behaviour you may not expect ​

  • progress answers progressed. The C doxygen text says progressing; the C code (and this port) send progressed.
  • update with an offer answers updating and nothing more. updated is only for answering a peer's re-INVITE with a JSEP answer.
  • A wrong secret takes two round trips: the registrar's 401 is answered with the digest automatically, and only the second failure (here a 403) becomes registration_failed.
  • A call that ends adds a {"janus": "hangup", "reason": "Close PC"} event after the plugin's hangup event.
  • register again on a registered handle is refused: 445 Already registered (alice).
  • type: "guest" registration needs no peer, and registered has register_sent: false.

Known gaps ​

  • gap One SIP socket for every handle. All handles share the same local SIP port: the Contact of every registration is the same address and port. C gives each handle its own stack and port. Consequence, verified: if two handles register the same SIP URI, an incoming call goes to the first handle that registered, not the one you expected. Register each account on one handle (use type: "helper" for extra calls).
  • gap Peer recordings. recording with peer_audio or peer_video answers recordingupdated, but only the user's own files are created: after starting with all four flags the server's working directory held docs-call-user-audio.mjr and docs-call-user-video.mjr and no peer files. (NoSIP creates all four.)
  • gap No keep-alive OPTIONS after REGISTER. keepalive_interval is read but the plugin sends nothing (parity/sip-peer/README.md).
  • gap Open items from parity/status.json: Proxy-Authorization on BYE, the terminating NOTIFY for a pending REFER, provisional codes other than 180 and 183 in REFER progress, transport errors that C reports as 408 or 503, and an incoming INVITE going to a free helper while the master is busy.
  • Not exercised here: media (no PeerConnection was set up), SRTP (srtp, srtp_profile), TCP and SIPS, ha1_secret, helper sessions, refresh, and attended transfers. They are written from the C documentation and the Rust request reader.
  • The REGISTER's Call-ID has @restsend.com as its host part (the stack's default). C's Sofia writes a random id with the local address.

Test it in Janus Bench ​

Open the SIP page, or run sip.register from Run all checks. It registers as a guest (verified: verified). With a SIP peer configured (?sip=sip:[email protected]:5090 in the Bench URL) it also places a call and waits for accepted with an answer; that part needs a peer and has not been part of the recorded Bench results.

GPL-3.0-or-later, like the Janus gateway it ports.