Janus 서버를 이용한 다자간 영상 공유 서비스 구축

 

WebRTC는 기본적으로 P2P(peer-to-peer) 통신을 지원하여 브라우저 간에 오디오 및 비디오 데이터를 교환할 수 있습니다. 하지만 P2P 방식만으로는 다자간 영상 공유 시 대역폭 문제, 성능 및 확장성 문제, 방화벽 문제 등이 발생 할 수 있습니다.

 

관련 소스


서버 구성 : https://github.com/namkyu/docker_config/tree/master/test_janus

프로젝트 소스 : https://github.com/namkyu/test_spring_janus

 

 

환경 구성 및 테스트 방법


rabbitmq, janus 서버를 구동하기 위한 방법에 대해서 설명해 드립니다.

우선 윈도우 기준입니다.

  1. docker desktop 설치
  2. test_janus 환경 설정 파일 clone 받기
  3. up_docker_compose.sh 파일 실행 (파일 내용을 확인해 보시면 init_rabbit.sh 파일을 실행하는 구간이 있습니다.)
  4. janus, rabbitmq 서버가 기동됩니다.
  5. init_rabbit.sh 파일이 실행됩니다. (유저 생성, virtual host 생성, exchange 생성, queue 생성)
  6. janus 서버가 재기동 됩니다.

이후 test_spring_janus 프로젝트를 clone 받으신 후 서버를 실행하시면 됩니다. MyApplication.java 를 실행하시면 됩니다.

http://localhost:8080/chat/rooms 페이지에 접속하신 후 방을 생성합니다.

채팅 방에 접속하시면 두 개의 영상이 보여집니다.

 

왼쪽의 비디오는 Janus로 송출되고, 오른쪽의 비디오는 Janus로 부터 수신 받은 비디오입니다.

 

chrome://webrtc-internals/ 로 접속해 보시면 두 개의 WebRTC 연결 정보가 보입니다.

 

 

미디어 서버가 필요한 이유?


Mesh 구조와 미디어 서버를 이용한 구조를 비교해 보겠습니다.

 

WebRTC Mesh 구조

janus 서버는 SFU(Selective Forwarding Unit) 방식의 WebRTC 미디어 서버로 다자간 영상 공유를 원활하게 지원합니다.
만약 다자간 영상 공유 서비스를 설계할 때 janus 와 같은 미디어 서버를 사용하지 않고, P2P 방식으로만 처리한다면 어떻게 될까요?

WebRTC Mesh 구조

 

김씨, 이씨, 박씨, 홍씨 4명의 사람이 있습니다.
김씨가 이씨, 박씨, 홍씨에게 자신의 영상을 전달하기 위해서 몇 개의 WebRTC 연결이 필요할까요?
네, 3개 생성해야 합니다.
이씨에게 영상을 송신하기 위한 WebRTC 연결 1개
박씨에게 영상을 송신하기 위한 WebRTC 연결 1개
홍씨에게 영상을 송신하기 위한 WebRTC 연결 1개
이와 같은 구조는 사람이 많아질수록 부하가 심해지는 단점이 있습니다. (대역폭, 로컬 PC 성능 저하, 방화벽으로 인한 TURN 서버 사용량 증가 등)
4명의 사용자가 서로의 영상을 송신/수신 하기 위해서 연결되는 커넥션은 다음과 같습니다.

4 * (4 - 1) / 2 = 6

 

총 6개의 WebRTC 연결이 생성되었네요.

 

 

미디어 서버를 이용한 구조

미디어 서버 도입

미디어 서버를 도입하면 김씨, 이씨, 박씨, 홍씨가 서로 영상을 전달하는 구조가 위처럼 변경됩니다.
김씨는 janus 서버에 영상을 한 번만 송출하면 됩니다.
이씨, 박씨, 홍씨는 janus 서버로부터 김씨의 영상을 수신 받으면 됩니다.
이처럼 미디어 서버가 중간에 개입이 되면 자신의 스트림을 딱 한 번만 전송해 주면 됩니다.
참여인원이 10명, 20명, 100명이 되어도 이씨는 자신의 스트림을 딱 한 번만 전송해도 됩니다.
수신은 사람의 인원수 만큼 WebRTC 커넥션을 생성해야 합니다. (위의 도식처럼 다른 사람의 영상을 수신 받기 위해서는 WebRTC 커넥션을 각각 생성해야 함)
janus 영상 수신에 대한  부하는 Multistream 기능이 도입되면서 해소되었습니다.
janus 1.x 버전부터 Multistream이 적용되었으므로 해당 기능을 사용하면 이씨는 송신을 위한 WebRTC 커넥션 1개, 수신을 위한 WebRTC 커넥션 1개를 유지하면 됩니다.

Janus Multistream 적용


수신 전용 RTCPeerConnection을 통해 여러 사람의 미디어 스트림을 동시에 수신 받을 수 있습니다.

RTCPeerConnection 하나만 관리 하기에 코드가 단순해지고 유지보수가 쉬워집니다.


미디어 서버를 사용하게 됨으로써 얻는 장점은 대역폭을 최적화 할 수 있습니다.
각 클라이언트에서 자신의 영상/음성 스트림을 janus 서버에 한 번만 전송하고, janus 서버가 여러 클라이언트들에게 스트림을 전달합니다.
이와 같은 아키텍처는 클라이언트의 네트워크 사용량과 리소스를 절약하여 원활한 다자간 통신을 가능하게 합니다.
자신의 영상/음성 스트림을 janus 서버에 딱 한 번만 전송한다. 이 부분이 미디어 서버를 사용하는 핵심입니다.

 

시스템 구성도


미디어 서버의 필요성을 인지했으니 이제 슬슬 구현을 해보겠습니다.

구현을 하기 전에 시스템 구성도를 한번 살펴보겠습니다.

 

API 서버의 역할

API 서버의 역할은 janus 서버와의 WebRTC 연결을 위한 시그널링 역할을 합니다.

시그널링이란? 두 개의 피어를 WebRTC로 연결하기 위해 필요한 정보들을 교환하는 과정을 말합니다. offer, answer, candidate 정보들을 서로 교환하게 됩니다.

또한, 브라우저와 API 서버와 실시간 메시지를 주고 받기 위한 WebSocket 기능을 제공합니다. 

 

RabbitMQ 서버의 역할

janus 서버에서 발생하는 모든 이벤트를 실시간으로 처리합니다. 대표적으로 janus에서 생성하는 SDP offer, answer 메시지는 비동기적으로 처리되며 해당 메시지를 큐에 적재하고, 분배하기 위해서 RabbitMQ 와 같은 메시지 브로커를 사용합니다.

 

Janus 서버의 역할

janus 는 다자간 영상 공유를 처리하기 위한 미디어 서버입니다.

 

 

시스템 환경 구축


테스트를 위해 docker 환경에서 janus와 rabbitmq를 구축해 보겠습니다.

 

RabbitMQ 서버 구성

docker-compose.yml

services:

  rabbit:
    image: nklee-rabbitmq:3.13.3-management
    container_name: rabbit
    ports:
      - "5672:5672" # AMQP 프로토콜 포트
      - "15672:15672" # RabbitMQ 관리 웹 UI
      - "61613:61613" # STOMP 프로토콜 포트
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:15672"]
      interval: 10s
      timeout: 5s
      retries: 10
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=admin
    volumes:
      - "./rabbitmq/init_rabbit.sh:/init_rabbit.sh"    
    restart: on-failure

  janus:
    image: canyan/janus-gateway:master
    command: ["/usr/local/bin/janus", "-F", "/usr/local/etc/janus"]
    container_name: janus
    depends_on:         
      - rabbit
    links:
      - rabbit
    ports:
      - "8088:8088" # HTTP REST API 연동
      - "7088:7088" # HTTP Admin API 연동
      - "20000-20100:20000-20100/udp" # ICE 후보 포트
    volumes:
      - "./janus/config/janus.jcfg:/usr/local/etc/janus/janus.jcfg"
      - "./janus/config/janus.transport.http.jcfg:/usr/local/etc/janus/janus.transport.http.jcfg"
      - "./janus/config/janus.plugin.audiobridge.jcfg:/usr/local/etc/janus/janus.plugin.audiobridge.jcfg"      
      - "./janus/config/janus.plugin.videoroom.jcfg:/usr/local/etc/janus/janus.plugin.videoroom.jcfg"      
      - "./janus/config/janus.plugin.streaming.jcfg:/usr/local/etc/janus/janus.plugin.streaming.jcfg"      
      - "./janus/config/janus.plugin.textroom.jcfg:/usr/local/etc/janus/janus.plugin.textroom.jcfg"      
      - "./janus/config/janus.eventhandler.rabbitmqevh.jcfg:/usr/local/etc/janus/janus.eventhandler.rabbitmqevh.jcfg"            
      - "./janus/janus.log:/var/log/janus.log"
    restart: on-failure

 

nklee-rabbitmq:3.13.3-management 이미지를 사용하였는데요.

rabbitmq:3.13.3-management 이미지에는 curl과 stomp plugin 이 설치되어 있지 않아서 rabbitmq:3.13.3-management 컨테이너에서 curl과 stomp plugin을 설치한 후 새로운 docker 이미지 nklee-rabbitmq:3.13.3-management를 생성하였습니다.

[curl 설치 방법]
# sudo apt update
# sudo apt install curl -y

[stomp plugin 설치 방법]
우선 아래 명령어를 실행하여 stomp 플러그인이 설치되어 있는지를 확인해 봅니다.
# rabbitmq-plugins list | grep stomp 
설치되어 있지 않다면 아래 명령어를 실행하여 활성화 합니다.
# rabbitmq-plugins enable rabbitmq_stomp

 

rabbitmq 에 stomp 플러그인을 활성화 하는 이유?

클라이언트에서 전송한 STOMP 메시지를 AMQP 메시지로 변환하거나 반대로 AMQP 메시지를 STOMP 메시지로 변환하기 위해서 사용됩니다.

클라이언트에서 rabbitmq 로 stomp 메시지를 전송할 때에는 다음과 같이 처리합니다.
Client → STOMP 메시지 전송 → RabbitMQ STOMP Plugin → AMQP 메시지로 변환 → RabbitMQ Exchange → Queue

클라이언트에서 메시지를 받을 때는 다음과 같은 처리됩니다.
Queue → 메시지 발행 → RabbitMQ STOMP Plugin → STOMP 메시지로 변환 → Client

 

Janus 의 이벤트 메시지를 수신 받기 위한 exchange, queue

이제 janus 로부터 이벤트 메시지를 수신 받기 위한 exchange, queue 를 생성해야 합니다.

docker-compose.yml 파일의 volumes 에 보시면 init_rabbit.sh 파일을 copy 하는 설정이 보입니다.

init_rabbit.sh 스크립트 파일이 하는 역할은 유저를 생성하고, virtual host를 만듦니다.  그리고 exchange와 queue를 생성한 후 이 둘을 연결하는 bind 작업을 처리합니다.

#!/bin/bash

rabbitmqctl await_startup

USER=nklee
PW=1234
VHOST=test

create_user() {
	rabbitmqctl add_vhost $VHOST
	rabbitmqctl add_user $USER $PW
	rabbitmqctl set_user_tags $USER administrator
	rabbitmqctl set_permissions -p $VHOST $USER ".*" ".*" ".*"
}

create_exchanges() {
	curl -i -u $USER:$PW -H "content-type:application/json" \
	-XPUT -d'{"type":"fanout","durable":false}' \
	http://localhost:15672/api/exchanges/$VHOST/janus-exchange
}

create_queues() {
	curl -i -u $USER:$PW -H "content-type:application/json" \
	-XPUT -d'{"auto_delete":false,"durable":false}' \
	http://localhost:15672/api/queues/$VHOST/janus-events
}

create_bind() {
	curl -i -u $USER:$PW -H "content-type:application/json" \
	-XPOST -d'{}' \
	http://localhost:15672/api/bindings/$VHOST/e/janus-exchange/q/janus-events
}

echo "========================================="
echo "create_user"
echo "========================================="
create_user
sleep 3

echo "========================================="
echo "create_exchanges"
echo "========================================="
create_exchanges
sleep 3

echo "========================================="
echo "create_queues"
echo "========================================="
create_queues
sleep 3

echo "========================================="
echo "create_bind"
echo "========================================="
create_bind

여기까지 rabbitmq 환경 설정이 마무리 되었습니다.

 

RabbitMQ 관리자 UI 에서 janus-exchange와 janus-events 가 잘 생성되었는지 확인해 보겠습니다.

janus-events 도 잘 생성되어 있고, janus-exchange 도 잘 생성되어 있네요.

 

Janus 서버 구성

이제 janus 서버 구성을 해보겠습니다.
janus WebRTC 서버의 설정 파일들은 .jcfg 형식으로 되어 있으며, 각각의 설정 파일에 대해서 설명하겠습니다.

 

janus.jcfg
janus WebRTC 서버의 기본 설정 파일
ICE 설정, 미디어 처리 방식, 로그 레벨, Session Timeout 등이 포함되어 있습니다.

general: {
    loglevel = "info"  # 로그 레벨 (debug, info, warn, error)
    debug_level = 4
    session_timeout = 0  # 세션 타임아웃 (밀리초)
}

media: {
    rtp_port_range = "20000-20100"  # RTP 포트 범위
}

저는 session_timeout 을 0으로 지정하였습니다.

default 값이 60초인데 0으로 셋팅한 이유가 있습니다.

실제 서비스에서 session 을 계속 유지하기 위해서 janus 서버의 keep_alive api 를 호출해 줘야 합니다. keep_alive 가 누락되면 세션이 만료되어 janus 서버와 연동 시 session not found 오류가 발생합니다.

시스템을 단순화 하고, 코드 복잡도를 줄이기 위해서 session timeout 설정을 0으로 하였고, 대신 공유방이 폭파될 때 참여한 사용자들의 sessionId 를 모두 제거하게 처리하였습니다. 만약 제거되지 않은 sessionId 가 있을 시에는 배치를 통해 일괄 삭제하였습니다.

 

janus.transport.http.jcfg
janus WebRTC 서버와 HTTP 클라이언트(WebRTC JS, REST API 등)를 연결하는 설정을 담당합니다.

http = true  # HTTP 트랜스포트 활성화
port = 8088  # HTTP 포트 설정
admin_http = true  # 관리자 API 활성화
admin_port = 7088  # 관리자 API 포트


janus.plugin.videoroom.jcfg
다자간 영상 채팅을 위한 비디오룸 기능 설정
SFU(Selective Forwarding Unit) 방식을 사용하여 브라우저 <-> 브라우저 영상 통화 가능하게 해줍니다.

general: {
	admin_key = "videoroomsecret"
	events = true				
}

room-1234: {
	description = "Demo Room"
	publishers = 8
	bitrate = 512000
	fir_freq = 10
	audiocodec = "opus"
	videocodec = "vp9"
	opus_fec = true
	video_svc = true
	transport_wide_cc_ext = true
	record = false
}


janus.plugin.streaming.jcfg
외부에서 미리 정의된 RTSP, RTP 스트림을 가져와 WebRTC로 전달할 때 사용됩니다.

janus.plugin.textroom.jcfg
WebRTC 데이터 채널을 이용하여 텍스트 채팅을 지원하는 플러그인입니다.
실시간 텍스트 채팅 및 파일 전송 기능을 구현할 수 있습니다.

janus.eventhandler.rabbitmqevh.jcfg
janus WebRTC 서버에서 발생하는 이벤트를 RabbitMQ로 전송하는 역할을 합니다.
WebRTC 세션 생성, 스트리밍 시작/종료 등의 이벤트를 RabbitMQ 메시지 큐로 전달할 수 있습니다.

general: {
	enabled = true					
	events = "sessions,handles,jsep,webrtc,plugins,core"
	grouping = false				
	json = "indented"										
	host = "rabbit"				
	port = 5672					
	username = "nklee"			
	password = "1234"			
	vhost = "test"				
	exchange = "janus-exchange"
	route_key = "janus-events"	
}

rabbitmq 서버 구성할 때 user, virtual host, exchange, queue 생성한 정보를 기입하면 됩니다.

janus.plugin.audiobridge.jcfg
오디오 컨퍼런스(다자간 음성 채팅) 기능을 제공하는 AudioBridge 플러그인 설정입니다.

janus 컨테이너가 정상적으로 실행되었는지를 확인해 보기 위해서 http://localhost:7088/admin/info URL 호출해 보겠습니다.

{
  "janus": "server_info",
  "transaction": "ddRNddcRgIj",
  "name": "janus WebRTC Server",
  "version": 1203,
  "version_string": "1.2.3",
  "author": "Meetecho s.r.l.",
  "commit-hash": "cefca79700bdadd32d759ce65ba3805552a4d312",
  "compile-time": "Mon May  6 04:05:10 UTC 2024",
  "log-to-stdout": true,
  "log-to-file": true,
  "log-path": "/var/log/janus.log",
  "data_channels": true,
  "accepting-new-sessions": true,
  "session-timeout": 0,
  "reclaim-session-timeout": 0,
  "candidates-timeout": 45,
  "server-name": "MyjanusInstance",
  "local-ip": "172.18.0.3",
  "ipv6": false,
  "ice-lite": false,
  "ice-tcp": false,
  .... 생략
}

버전과 기타 정보들이 출력됩니다. 

 

Janus 연동 시퀀스 다이어그램


janus 를 이용한 다자간 영상 공유는 어떻게 구현해야 할까요?
시퀀스 다이어그램을 통해서 자세히 알아보겠습니다.

가독성을 높이기 위해서 응답은 생략하였습니다.

오~ 좀 복잡해 보이네요.

맞습니다. 저도 janus 서버와의 연동을 구현할 때 땀 좀 뺐습니다. (학습하고, 개발하고, 삽질하고, 문제 해결의 반복)

사실 WebRTC 핸드쉐이킹 단계만 잘 이해하고 있다면 그렇게 어렵지 않습니다.

 

영상을 송출하는 브라우저와 janus가 WebRTC 를 연결하는 과정

영상을 수신받는 브라우저와 janus가 WebRTC 를 연결하는 과정

이 두 개의 과정이 핵심 내용입니다.

janus 서버와 연동할 때 어렵게 느껴지는 부분은 janus 가 언제 offer와 answer를 발행하는지를 잘 몰라서 입니다.

 

Janus 비동기 이벤트 메시지


위의 시퀀스 다이어그램을 보시면 REST API 호출하는 구간들이 보입니다. (session 생성, handleId 생성, join, publish, start)

session 생성 및 handleId 생성은 API 호출하면 response 에서 관련 데이터를 추출할 수 있습니다.

하지만 join, publish, subscribe 등은 response 로 넘어오는 데이터가 "ack" 로 되어 있을 뿐입니다.

{
  "janus": "ack",
  "transaction": "123456"
}

janus 는 일부 API 요청에 대한 응답을 비동기로 전달합니다.

비동기 이벤트를 client 에서 수신 할 수 있는 방법은 websocket, HTTP Long Polling, RabbitMQ 를 이용하면 됩니다.

저는 RabbitMQ 를 이용한 비동기 이벤트 메시지를 수신하도록 처리하였습니다.

RabbitMQ를 통해서 비동기 이벤트를 수신 받은 이유는 브라우저와 Janus 서버간의 REST API 통신을 허용하지 않았기 때문입니다. 이는 다양한 엔드포인트 디바이스에서 다자간 서비스를 구현할 때 좀 더 쉽고 간편하게 구현하고, 안정성과 유지보수성을 높이기 위해서입니다.

 

이제 join, publish, subscribe 에 해당하는 janus API 를 호출하게 되면 어떤 비동기 메시지가 생성되어 RabbitMQ로 전달되는지 알아보겠습니다. 참고로 join, publish, start 외에도 수많은 API 들을 janus 서버에서 제공하고 있습니다. 실제 서비스를 만들 때에는 제공하는 API를 적극 활용하시면 좋습니다. (simulcast, 모니터링, WebRTC 연결 성공/실패 등)

 

join 을 먼저 알아보겠습니다. server -> janus 로 join API 를 호출하게 되면 janus는 rabbitMQ에 다음과 같은 메시지를 발행합니다.

{
  "emitter": "MyJanusInstance",
  "type": 64,
  "timestamp": 1739889463249214,
  "session_id": 4539196060902786,
  "handle_id": 4389208518839099,
  "event": {
    "plugin": "janus.plugin.videoroom",
    "data": {
      "event": "joined",
      "room": 1234,
      "id": 5328575960580022,
      "private_id": 3574680294,
      "display": "1111"
    }
  }
}

 

publish 는 다음과 같습니다.

published 이벤트 발생 후 answer 이벤트도 함께 발행됩니다.

publish 할 때 offer 를 전달해 주었기 때문에 answer 이벤트가 발행되는 것입니다.

{
  "emitter": "MyJanusInstance",
  "type": 64,
  "timestamp": 1739889463249215,
  "session_id": 4539196060902786,
  "handle_id": 4389208518839099,
  "event": {
    "plugin": "janus.plugin.videoroom",
    "data": {
      "event": "published",
      "room": 1234,
      "publishers": [
        {
          "id": 5328575960580022,
          "display": "1111",
          "audio_codec": "opus",
          "video_codec": "VP8"
        }
      ]
    }
  }
}

 

이 과정을 거치면 비디오를 송출하는 브라우저와 janus 서버간에 WebRTC 연결이 가능해집니다.

 

이제 구독을 위한 비동기 이벤트를 알아보겠습니다.

janus 서버의 join api를 호출 할 때 ptype을 "subscriber" 로 전달하게 되면 offer 이벤트가 발행됩니다.

{
  "emitter": "MyJanusInstance",
  "type": 8,
  "timestamp": 1739889466424065,
  "session_id": 2725101316474987,
  "handle_id": 9000733027062833,
  "event": {
    "owner": "local",
    "jsep": {
      "type": "offer",
      "sdp": "v=0\r\no=- 1739889466418430 1 IN IP4 172.28.0.10\r\ns=VideoRoom 1234\r\nt=0 0\r\na=group:BUNDLE 0 1\r\na=ice-options:trickle\r\na=fingerprint:sha-256 3E:66:82:30:FF:40:E6:6B:8D:1A:F0:D0:BF:D7:58:4F:11:B6:10:F9:D2:C3:78:48:82:31:B2:01:58:11:60:5C\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS *\r\nm=video 9 UDP/TLS/RTP/SAVPF 101 102\r\nc=IN IP4 172.28.0.10\r\na=sendonly\r\na=mid:0\r\na=rtcp-mux\r\na=ice-ufrag:jscR\r\na=ice-pwd:QLiXsKlCNd+HR7Vkmk8E4a\r\na=ice-options:trickle\r\na=setup:actpass\r\na=rtpmap:101 VP9/90000\r\na=rtcp-fb:101 ccm fir\r\na=rtcp-fb:101 nack\r\na=rtcp-fb:101 nack pli\r\na=rtcp-fb:101 goog-remb\r\na=rtcp-fb:101 transport-cc\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:13 urn:3gpp:video-orientation\r\na=fmtp:101 profile-id=0\r\na=rtpmap:102 rtx/90000\r\na=fmtp:102 apt=101\r\na=ssrc-group:FID 733389480 4175246779\r\na=msid:janus janus0\r\na=ssrc:733389480 cname:janus\r\na=ssrc:4175246779 cname:janus\r\na=candidate:2 1 udp 2015363327 172.28.0.10 20011 typ host\r\na=end-of-candidates\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111\r\nc=IN IP4 172.28.0.10\r\na=inactive\r\na=mid:1\r\na=rtcp-mux\r\na=ice-ufrag:jscR\r\na=ice-pwd:QLiXsKlCNd+HR7Vkmk8E4a\r\na=ice-options:trickle\r\na=setup:actpass\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=fmtp:111 useinbandfec=1\r\na=candidate:2 1 udp 2015363327 172.28.0.10 20011 typ host\r\na=end-of-candidates\r\n"
    }
  }
}

janus 에서 발급한 offer 메세지를 브라우저가 받으면 answer를 생성하고, janus의 start api 로 전달해 줍니다.

이 과정을 거치면 비디오를 수신받는 브라우저와 janus 서버간에 WebRTC 연결이 가능해집니다.

 

offer, answer 비동기 메시지가 언제 발행되는지를 잘 이해하고 계시면 크게 어려움 없이 다자간 영상공유 서비스를 구축하실 수 있습니다. janus 에서 발행되는 모든 비동기 메시지를 글로 담아내고 싶지만, 너무 많아서.......이 부분은 독자님들께 위임하겠습니다. ^^

 

 

소스 코드


비디오 영상을 janus로 송출하고, janus로부터 영상을 수신 받는 핵심 기능만 구현한 상태이기 때문에 예외 처리, 테스트 코드는 없습니다.

 

코드에서 잘 보셔야 하는 부분은 JanusEventListener 클래스입니다.

janus의 비동기 메시지를 rabbitmq로 부터 수신 받아서 처리하는 부분입니다.

 

브라우저를 구분하기 위해서는 SessionRepository 클래스를 생성하였습니다. Map 자료 구조를 이용해서 세션 저장을 하고 있습니다.

 

 

이상으로 글을 마치겠습니다.

감사합니다.

 

 

'WebRTC' 카테고리의 다른 글

WebRTC의 ICE Candidate 처리 순서 문제  (0) 2024.12.26
NAS에 TURN 서버 구축하기  (1) 2024.12.20
TURN 서버를 통한 Relay 통신 원리  (0) 2024.12.10
NAT 종류에 따른 홀펀칭  (3) 2024.11.12
NAT 종류  (0) 2024.11.03
WebRTC 테스트를 위한 Docker 환경 구성  (0) 2024.09.22