Janus-Gateway 는 HTTP Rest, WebSocket, RabbitMQ, MQTT, UnixSocket API를 제공한다. 각각 다른 API를 제공하는 것은 아니고, JSON 형태로 API를 제공하며 REST, WebSocket 등등은 이 JSON 값을 전달하기 위한 프로토콜이다.
Janus-Gateway의 동작은 다음과 같은 순서로 동작한다.
1. session creation
Janus-Gateway는 서비스(Plugin)을 이용하는 클라이언트를 세션으로 관리한다. 세션이 생성되면 이 세션으로 특정 plugin 을 이용하기 위한 요청을 보낼 수 있다. 세션으로 특정 plugin을 이용하기 위해서 생성된 것이 Handle_id 값이다. 이 handle_id 는 Janus-Gateway 와 Client간의 RTPPeerConnection을 관리하는 값이다. 즉 Plugin 에 하나의 PeerConnection이 생성되는 구조이며, 이 관리 값이 handle_id가 되는 것이다.
특정 Session_ID 값으로 여러 Handle_ID를 생성할 수 있다. 클라이언트에서는 하나의 Session_ID를 생성하고 여러 종류의 Plugin을 이용해서 여러 RTPPeerConnection을 생성할 수 있는 것이다.
이 세션값으로 keepalive 메시지를 보내며, 세션을 생성한 socket과 바인드 되어 있어서 API를 호출한 socket이 종료되면 해당 세션 그리고 여기에 attach 된 plugin들의 핸들도 사라진다.
Janus-Gateway와 연동되는 기본 API들은 모두 TransactionID를 설정해서 보내야 한다. 이는 Janus-Gateway가 비동기적으로 동작하기 때문에 이 Transaction 으로 응답을 구별하기 위함이다. 다음은 Transaction을 생성하는 Javascript 코드이다.
function getTrxId() { var len=12; var charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var randomString = ''; for (var i = 0; i < len; i++) { var randomPoz = Math.floor(Math.random() * charSet.length); randomString += charSet.substring(randomPoz,randomPoz+1); } return randomString; }; |
그리고 janus 라는 기본 명령어 필드가 존재하는데, session을 생성하는 명령은 "create" 이다.
다음은 Session 을 생성하는 Javascript 코드이다. (ws 는 websocket 연결을 가정한다.)
const janus={}; janus.send_create_session=(ws)=>{ let trxid=getTrxId(); let request = { "janus": "create", "transaction": trxid }; ws.send(JSON.stringify(request)); return trxid; }; |
다음은 요청-응답의 예이다.
요청> {"janus":"create","transaction":"TYuHYuCxLKid"} |
응답> {"janus":"success","transaction":"TYuHYuCxLKid","data":{"id":1078166167654140}} |
응답의 data.id 가 session_id가 된다.
2. session destroy
다음은 세션을 파괴하는 명령에 대한 코드이다. 이 세션에 연결된 핸들들도 같이 삭제된다.
janus.send_destroy_session=(ws,session_id)=>{ let trxid=getTrxId(); let request={ janus:"destroy", transaction:trxid, session_id:session_id }; ws.send(JSON.stringify(request); }; |
다음은 요청-응답의 예이다.
요청> {"janus":"destroy","transaction":"Ut2czjYHuAJe","session_id":5396131839672173} |
응답> {"janus":"success","session_id":5396131839672173,"transaction":"Ut2czjYHuAJe"} |
3. attach plugin (handle creation)
다음은 특정 plugin에 session을 attach 하는 코드이다.
janus.send_attach_plugin=(ws,opaqueId,session_id,plugin_name)=>{ let trxid=getTrxId(); let request = { "janus": "attach", "transaction": trxid, "opaqueId": opaqueId, "session_id": session_id, "plugin":"janus.plugin.streaming" }; console.log("attach_plugin_msg:"+JSON.stringify(request)); ws.send(JSON.stringify(request)); return trxid; }; |
opaqueId 는 handle을 Application 입장에서 사용하기 위함인데, 예를 들어 여러 session을 가진 특정 사용자를 구별하기 위해서 사용하거나, 같은 사용자의 handle 을 수집하기 위한 용도로 사용할 수 있다. janus-gateway에서는 내부적으로 이 값을 사용하지 않으며, admin api 를 통해서 핸들 정보를 조회하거나 handle event가 trigger 될 때 제공된다.
다음은 janus.plugin.audiobridge plugin를 attach 하는 요청-응답의 예이다.
요청> {"janus":"attach","transaction":"4uOOc9BEfqeb","opaqueId":"audiobridgetest-DpLzkETia8eX","session_id":4894477569154728,"plugin":"janus.plugin.streaming"} |
응답> {"janus":"success","session_id":4894477569154728,"transaction":"4uOOc9BEfqeb","data":{"id":8858769173674836}} |
응답의 data.id 가 handle_id가 된다.
4. detach plugin
특정 Plugin에 attach 된 handle을 해제한다. 다음은 그 코드이다.
janus.send_detach_plugin=(ws,session_id,handle_id)=>{ let trxid=getTrxId(); let request = { "janus": "detach", "transaction": trxid, "session_id": session_id, "handle_id":handle_id }; ws.send(JSON.stringify(request)); }; |
요청-응답은 다음과 같다. 응답의 경우 janus:success 와 janus:detached, 두가지 응답이 온다.
요청> {"janus":"detach","transaction":"AEzv9SsxLLZM","session_id":3486958638653612,"handle_id":6541525317175383} |
응답> {"janus":"detached","session_id":3486958638653612,"sender":6541525317175383} {"janus":"success","session_id":3486958638653612,"transaction":"AEzv9SsxLLZM"} |
5. plugin command
plugin의 command는 plugin의 종류에 따라 다르다. plugin command는 janus 웹 사이트에 정리되어 있지 않으며 plugin 소스 코드 또는 demo web page 코드를 보고 분석해야 한다. 향후 다른 포스팅에서 janus.plugin.audiobridge 와 janus.plugin.streaming에 대한 command를 분석해 보도록 하겠다.
6. tricle
tricle은 client에서 발생하는 ice candidate를 전송하는 API 이다. tricle 은 plugin 에 따라서 offer/answer 가 발생하고 난 다음 client에서 ice candidate가 발생하면 tricle api로 해당 candidate를 전송한다. (비동기) 다음은 tricle 메시지를 보내는 코드이다.
janus.send_icecandidate=(ws,session_id,handle_id,candidate)=>{ let trxid=getTrxId(); let s_candidate={ "candidate":candidate.candidate, "sdpMid":candidate.sdpMid, "sdpMLineIndex":candidate.sdpMLineIndex }; let request = { "janus": "trickle", "session_id":session_id, "handle_id":handle_id, "candidate": s_candidate, "transaction": trxid }; ws.send(JSON.stringify(request)); return trxid; }; |
다음은 tricle에 대한 응답-요청이다.
요청> {"janus":"trickle","session_id":2574473726807889,"handle_id":523990459844417,"candidate":{"candidate":"candidate:478132711 1 tcp 1518275327 2001::9d38:6abd:432:3f0d:2d86:4250 9 typ host tcptype active generation 0 ufrag YUP0 network-id 2 network-cost 50","sdpMid":"audio","sdpMLineIndex":0},"transaction":"6BUFmPJFp2Zx"} |
응답> {"janus":"ack","session_id":2574473726807889,"transaction":"6BUFmPJFp2Zx"} |
7. webrtc up event
webrtc channel이 생성되면 janus-gateway로 부터 webrtcup event가 전달된다. 다음은 webrtcup event 예이다.
{"janus":"webrtcup","session_id":2574473726807889,"sender":523990459844417} |
8. media event
webrtcup event가 전달되고 난 다음에 실제 media traffic이 발생하기 시작하면 media event가 전달된다. 다음은 그 예이다.
{"janus":"media","session_id":2574473726807889,"sender":523990459844417,"type":"audio","receiving":true} |
9. 기타 webrtc event
webrtc 관련으로 slowlink 및 hangup event가 발생할 수 있다.
(https://janus.conf.meetecho.com/docs/rest.html 참고)
10. keepalive
janus-gateway에서는 특정 g 생성되면 해당 세션에 60초 이내어 어떤 activity 가 없을 경우 session은 종료된다. 세션을 유지하기 위하여 keepalive message를 janus-gateway로 전송한다. 다음은 관련 코드이다.
janus.send_keep_alive=(ws,session_id)=>{ let trxid=getTrxId(); let request={ janus:"keepalive", session_id:session_id, transaction:trxid }; ws.send(JSON.stringify(request)); return trxid; }; |
다음은 요청-응답이다.
{"janus":"keepalive","session_id":5485723921011822,"transaction":"QZ6Wa2PrEOYj"} |
{"janus":"ack","session_id":5485723921011822,"transaction":"QZ6Wa2PrEOYj"} |