Github janus-gateway


1. Janus介绍

Janus:通用WebRTC服务器

Janus是Meetecho开发的一个WebRTC服务器,它被认为是一个通用服务器。因此,除了实现与浏览器建立WebRTC媒体通信、与浏览器交换JSON消息以及在浏览器和它们所连接的服务器端应用程序逻辑之间中继RTP/RTCP和消息之外,它本身不提供任何功能。任何特定的特性/应用程序都是由服务器端插件提供的,浏览器可以通过Janus联系这些插件来利用它们提供的功能。此类插件的示例可以是应用程序的实现,如回声测试、会议桥、媒体记录器、SIP网关等。


2. Janus安装

我基于CentOS 7.9 环境来安装

2.1 部署环境与依赖

$ sudo yum install epel-release
$ sudo yum update

# CentOS 7.9
$ sudo yum install libmicrohttpd-devel jansson-devel \
   openssl-devel glib2-devel \
   opus-devel libogg-devel libcurl-devel pkgconfig gengetopt \
   libconfig-devel libtool autoconf automake
# CentOS 8.3
$ sudo yum install libmicrohttpd jansson-devel \
   openssl-devel glib2-devel \
   opus-devel libogg-devel libcurl-devel pkgconfig gengetopt \
   libconfig libtool autoconf automake

$ sudo yum install doxygen graphviz

libnice

# CentOS 7.9
$ sudo yum install meson
# CentOS 8.3
$ sudo yum install python3 python3-pip
$ sudo pip3 install meson ninja

$ git clone https://gitlab.freedesktop.org/libnice/libnice
$ cd libnice
$ meson --prefix=/usr build && ninja -C build && sudo ninja -C build install

libsrtp

$ wget https://github.com/cisco/libsrtp/archive/v2.2.0.tar.gz
$ tar xfv v2.2.0.tar.gz
$ cd libsrtp-2.2.0
$ sudo yum install lua-devel
$ ./configure --prefix=/usr --enable-openssl
$ make && sudo make install

# CentOS 8.3
$ sudo yum install libsrtp

sofia-sip-devel

$ wget https://sourceforge.net/projects/sofia-sip/files/sofia-sip/1.12.11/sofia-sip-1.12.11.tar.gz
$ tar zxf sofia-sip-1.12.11.tar.gz
$ cd sofia-sip-1.12.11
$ ./configure --prefix=/usr CFLAGS=-fno-aggressive-loop-optimizations
$ make
$ sudo make install

usrsctp

$ git clone https://github.com/sctplab/usrsctp
$ cd usrsctp
$ ./bootstrap
$ ./configure --prefix=/usr --disable-programs --disable-inet --disable-inet6
$ make
$ sudo make install

libwebsockets

$ git clone https://libwebsockets.org/repo/libwebsockets
$ cd libwebsockets
# If you want the stable version of libwebsockets, uncomment the next line
# git checkout v3.2-stable
$ mkdir build
$ cd build
# See https://github.com/meetecho/janus-gateway/issues/732 re: LWS_MAX_SMP
# See https://github.com/meetecho/janus-gateway/issues/2476 re: LWS_WITHOUT_EXTENSIONS
$ cmake -DLWS_MAX_SMP=1 -DLWS_WITHOUT_EXTENSIONS=0 -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_C_FLAGS="-fpic" ..
$ make
$ sudo make install

paho.mqtt

$ git clone https://github.com/eclipse/paho.mqtt.c.git
$ cd paho.mqtt.c
$ make && sudo make install

libmicrohttpd

$ wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-0.9.59.tar.gz
$ tar -xvf libmicrohttpd-0.9.59.tar.gz
$ cd libmicrohttpd-0.9.59
$ sudo yum install gnutls-devel
$ ./configure --prefix=/usr --enable-https
$ make
$ sudo make install

rabbitmq-c

OpenSSL >= 1.1.1

$ git clone https://github.com/alanxz/rabbitmq-c
$ cd rabbitmq-c
$ git submodule init
$ git submodule update
$ mkdir build && cd build

$ sudo yum install xmlto

$ cmake -DCMAKE_INSTALL_PREFIX=/usr ..
$ make && sudo make install

2.2 编译安装

$ git clone https://github.com/meetecho/janus-gateway.git
$ cd janus-gateway
$ sh autogen.sh
$ export PKG_CONFIG_PATH=/usr/lib64/pkgconfig/:$PKG_CONFIG_PATH
$ ./configure --prefix=/opt/janus --enable-plugin-lua --disable-rabbitmq

Compiler:                  gcc
libsrtp version:           2.x
SSL/crypto library:        OpenSSL
DTLS set-timeout:          not available
Mutex implementation:      GMutex (native futex on Linux)
DataChannels support:      yes
Recordings post-processor: no
TURN REST API client:      yes
Doxygen documentation:     no
Transports:
    REST (HTTP/HTTPS):     yes
    WebSockets:            yes
    RabbitMQ:              no
    MQTT:                  yes
    Unix Sockets:          yes
    Nanomsg:               no
Plugins:
    Echo Test:             yes
    Streaming:             yes
    Video Call:            yes
    SIP Gateway:           yes
    NoSIP (RTP Bridge):    yes
    Audio Bridge:          yes
    Video Room:            yes
    Voice Mail:            yes
    Record&Play:           yes
    Text Room:             yes
    Lua Interpreter:       no
    Duktape Interpreter:   no
Event handlers:
    Sample event handler:  yes
    WebSocket ev. handler: yes
    RabbitMQ event handler:no
    MQTT event handler:    yes
    Nanomsg event handler: no
    GELF event handler:    yes
External loggers:
    JSON file logger:      no
JavaScript modules:        no

$ make
$ sudo mkdir -p /opt/janus
$ sudo chown wii:wii /opt/janus -R
$ make install

# ./configure --disable-websockets --disable-data-channels --disable-rabbitmq --disable-mqtt
# ./configure --enable-docs


3. 配置与运行

<installdir>/etc/janus/janus.jcfg

$ make configs
$ /opt/janus/bin/janus --help
Janus commit: 216d70c63f1fea629daf7b3c491f06e0d9448ffd
Compiled on:  2021? 04? 12? ??? 11:05:02 CST

Usage: janus [OPTION]...

  -h, --help                    Print help and exit
  -V, --version                 Print version and exit
  -b, --daemon                  Launch Janus in background as a daemon
                                  (default=off)
  -p, --pid-file=path           Open the specified PID file when starting Janus
                                  (default=none)
  -N, --disable-stdout          Disable stdout based logging  (default=off)
      --log-stdout              Log to stdout, even when the process is
                                  daemonized  (default=off)
  -L, --log-file=path           Log to the specified file (default=stdout only)
  -H, --cwd-path=path           Working directory for Janus daemon process
                                  (default=/)
  -i, --interface=ipaddress     Interface to use (will be the public IP)
  -P, --plugins-folder=path     Plugins folder (default=./plugins)
  -C, --config=filename         Configuration file to use
  -F, --configs-folder=path     Configuration files folder (default=./conf)
  -c, --cert-pem=filename       DTLS certificate
  -k, --cert-key=filename       DTLS certificate key
  -K, --cert-pwd=text           DTLS certificate key passphrase (if needed)
  -S, --stun-server=ip:port     STUN server(:port) to use, if needed (e.g.,
                                  Janus behind NAT, default=none)
  -1, --nat-1-1=ips             Comma-separated list of public IPs to put in
                                  all host candidates, assuming a 1:1 NAT is in
                                  place (e.g., Amazon EC2 instances,
                                  default=none)
  -2, --keep-private-host       When nat-1-1 is used (e.g., Amazon EC2
                                  instances), don't remove the private host,
                                  but keep both to simulate STUN  (default=off)
  -E, --ice-enforce-list=list   Comma-separated list of the only interfaces to
                                  use for ICE gathering; partial strings are
                                  supported (e.g., eth0 or eno1,wlan0,
                                  default=none)
  -X, --ice-ignore-list=list    Comma-separated list of interfaces or IP
                                  addresses to ignore for ICE gathering;
                                  partial strings are supported (e.g.,
                                  vmnet8,192.168.0.1,10.0.0.1 or
                                  vmnet,192.168., default=vmnet)
  -6, --ipv6-candidates         Whether to enable IPv6 candidates or not
                                  (experimental)  (default=off)
  -l, --libnice-debug           Whether to enable libnice debugging or not
                                  (default=off)
  -f, --full-trickle            Do full-trickle instead of half-trickle
                                  (default=off)
  -I, --ice-lite                Whether to enable the ICE Lite mode or not
                                  (default=off)
  -T, --ice-tcp                 Whether to enable ICE-TCP or not (warning: only
                                  works with ICE Lite)  (default=off)
  -Q, --min-nack-queue=number   Minimum size of the NACK queue (in ms) per user
                                  for retransmissions, no matter the RTT
  -t, --no-media-timer=number   Time (in s) that should pass with no media
                                  (audio or video) being received before Janus
                                  notifies you about this
  -W, --slowlink-threshold=number
                                Number of lost packets (per s) that should
                                  trigger a 'slowlink' Janus API event to users
  -r, --rtp-port-range=min-max  Port range to use for RTP/RTCP
  -B, --twcc-period=number      How often (in ms) to send TWCC feedback back to
                                  senders, if negotiated (default=200ms)
  -n, --server-name=name        Public name of this Janus instance
                                  (default=MyJanusInstance)
  -s, --session-timeout=number  Session timeout value, in seconds (default=60)
  -m, --reclaim-session-timeout=number
                                Reclaim session timeout value, in seconds
                                  (default=0)
  -d, --debug-level=1-7         Debug/logging level (0=disable debugging,
                                  7=maximum debug level; default=4)
  -D, --debug-timestamps        Enable debug/logging timestamps  (default=off)
  -o, --disable-colors          Disable color in the logging  (default=off)
  -M, --debug-locks             Enable debugging of locks/mutexes (very
                                  verbose!)  (default=off)
  -a, --apisecret=randomstring  API secret all requests need to pass in order
                                  to be accepted by Janus (useful when wrapping
                                  Janus API requests in a server, none by
                                  default)
  -A, --token-auth              Enable token-based authentication for all
                                  requests  (default=off)
      --token-auth-secret=randomstring
                                Secret to verify HMAC-signed tokens with, to be
                                  used with -A
  -e, --event-handlers          Enable event handlers  (default=off)
  -w, --no-webrtc-encryption    Disable WebRTC encryption, so no DTLS or SRTP
                                  (only for debugging!)  (default=off)

<installdir>/bin/janus

错误处理

$ /opt/janus/bin/janus

# 报错找不到libpaho-mqtt3as.so.1
[ERR] [janus.c:main:5391]       Couldn't load transport plugin 'libjanus_mqtt.so': libpaho-mqtt3as.so.1: cannot open shared object file: No such file or directory

# 配置路径/usr/local/lib到/etc/ld.so.conf
$ sudo ldconfig


4. 安装demo

$ openssl req -new -newkey rsa:4096 -nodes -keyout key.pem -out cert.csr
$ openssl x509 -req -sha256 -days 365 -in cert.csr -signkey key.pem -out cert.pem
$ chmod 600 cert.csr
$ chmod 600 cert.pem
$ chmod 600 key.pem
$ cd /opt/janus
$ vi etc/janus/janus.transport.http.jcfg
https = true

$ sudo yum install nginx
$ sudo vi /etc/nginx/nginx.conf 
    server {
        # listen       80 default_server;
        # listen       [::]:80 default_server;
        listen       443 ssl http2 default_server;
        listen       [::]:443 ssl http2 default_server;
        server_name  _;
        # root         /usr/share/nginx/html;
        root /opt/janus/share/janus/demos;

        ssl_certificate "/opt/janus/share/janus/certs/cert.pem";
        ssl_certificate_key "/opt/janus/share/janus/certs/cert.key";
        
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        index index.html index.htm index.php;
        }

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }

$ sudo systemctl start nginx

# 错误 Probably a network error, is the server down?: [object Object] 8089的问题,浏览器访问一下。
$ sudo firewall-cmd --zone=public --add-port=80/tcp --permanent
$ sudo firewall-cmd --zone=public --add-port=443/tcp --permanent
$ sudo firewall-cmd --zone=public --add-port=8088/tcp --permanent
$ sudo firewall-cmd --zone=public --add-port=8089/tcp --permanent
$ sudo firewall-cmd --reload

url: https://192.168.56.110

DEMO HTTP


5. janus-mobile-sdk

Github

# Makefile中定义了依赖包的下载
$ make

# 编译 4.8.5在编译时报错,用7编译通过
$ mkdir build
$ cd build
$ cmake ../
$ make


5. 抓包分析

Echo Test 演示的是发送给服务器网关的音频和视频,服务器会回传给你。

janus_http_handler(1979): url=/janus method=POST data={
   "janus": "create",
   "transaction": "gVpVzKJzlO91"
}
janus_http_send_message(1159): message={
   "janus": "success",
   "transaction": "gVpVzKJzlO91",
   "data": {
      "id": 4975254805420424
   }
}
Creating new session: 4975254805420424; 0x7f9fb0001320
janus_http_handler(1798): url=/janus/4975254805420424 method=GET data={
   "janus": "keepalive",
   "session_id": 4975254805420424,
   "transaction": "z5XlM4jxvsK"
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "z5XlM4jxvsK"
}
janus_http_handler(1979): url=/janus/4975254805420424 method=POST data={
   "janus": "attach",
   "plugin": "janus.plugin.echotest",
   "opaque_id": "echotest-Uk6M0r69TdGf",
   "transaction": "TRDHLwgzs4A2",
   "session_id": 4975254805420424
}
janus_http_send_message(1159): message={
   "janus": "success",
   "session_id": 4975254805420424,
   "transaction": "TRDHLwgzs4A2",
   "data": {
      "id": 5490525012024748
   }
}
Creating new handle in session 4975254805420424: 5490525012024748; 0x7f9fb0001320 0x7f9fb0001b10
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "message",
   "body": {
      "audio": true,
      "video": true
   },
   "transaction": "90sobcSPmKXl",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "90sobcSPmKXl",
   "hint": "I'm taking my time!"
}
janus_http_send_message(1159): message={
   "janus": "event",
   "session_id": 4975254805420424,
   "transaction": "90sobcSPmKXl",
   "sender": 5490525012024748,
   "plugindata": {
      "plugin": "janus.plugin.echotest",
      "data": {
         "echotest": "event",
         "result": "ok"
      }
   }
}
janus_http_handler(1798): url=/janus/4975254805420424 method=GET data={
   "janus": "keepalive",
   "session_id": 4975254805420424,
   "transaction": "SZTzatRlHn1"
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "SZTzatRlHn1"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "message",
   "body": {
      "audio": true,
      "video": true
   },
   "transaction": "2inURksqLqGW",
   "jsep": {
      "type": "offer",
      "sdp": "v=0\r\no=- 1298443446168106922 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1 2\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS bY3S0cVTCSQ1MEKrGLjFeoJZ6bvOnXpsAox8\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:OBYC\r\na=ice-pwd:glOqF413EKEaXEl5OKxkZoev\r\na=ice-options:trickle\r\na=fingerprint:sha-256 2E:A3:59:0D:6D:5A:65:5C:F8:12:B7:46:F5:3A:6A:72:33:BA:46:BF:03:2E:9E:2E:C2:FD:5B:52:B2:C2:85:A2\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\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:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=sendrecv\r\na=msid:bY3S0cVTCSQ1MEKrGLjFeoJZ6bvOnXpsAox8 7ecac6bd-b288-4510-97c7-887efc669c86\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:4085458354 cname:jnfRqpPdTG61m2cF\r\na=ssrc:4085458354 msid:bY3S0cVTCSQ1MEKrGLjFeoJZ6bvOnXpsAox8 7ecac6bd-b288-4510-97c7-887efc669c86\r\na=ssrc:4085458354 mslabel:bY3S0cVTCSQ1MEKrGLjFeoJZ6bvOnXpsAox8\r\na=ssrc:4085458354 label:7ecac6bd-b288-4510-97c7-887efc669c86\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:OBYC\r\na=ice-pwd:glOqF413EKEaXEl5OKxkZoev\r\na=ice-options:trickle\r\na=fingerprint:sha-256 2E:A3:59:0D:6D:5A:65:5C:F8:12:B7:46:F5:3A:6A:72:33:BA:46:BF:03:2E:9E:2E:C2:FD:5B:52:B2:C2:85:A2\r\na=setup:actpass\r\na=mid:1\r\na=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:13 urn:3gpp:video-orientation\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=sendrecv\r\na=msid:bY3S0cVTCSQ1MEKrGLjFeoJZ6bvOnXpsAox8 aebcd30c-df7a-4e68-9376-1db7884fa47e\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 red/90000\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 ulpfec/90000\r\na=ssrc-group:FID 2080201980 334907082\r\na=ssrc:2080201980 cname:jnfRqpPdTG61m2cF\r\na=ssrc:2080201980 msid:bY3S0cVTCSQ1MEKrGLjFeoJZ6bvOnXpsAox8 aebcd30c-df7a-4e68-9376-1db7884fa47e\r\na=ssrc:2080201980 mslabel:bY3S0cVTCSQ1MEKrGLjFeoJZ6bvOnXpsAox8\r\na=ssrc:2080201980 label:aebcd30c-df7a-4e68-9376-1db7884fa47e\r\na=ssrc:334907082 cname:jnfRqpPdTG61m2cF\r\na=ssrc:334907082 msid:bY3S0cVTCSQ1MEKrGLjFeoJZ6bvOnXpsAox8 aebcd30c-df7a-4e68-9376-1db7884fa47e\r\na=ssrc:334907082 mslabel:bY3S0cVTCSQ1MEKrGLjFeoJZ6bvOnXpsAox8\r\na=ssrc:334907082 label:aebcd30c-df7a-4e68-9376-1db7884fa47e\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\na=ice-ufrag:OBYC\r\na=ice-pwd:glOqF413EKEaXEl5OKxkZoev\r\na=ice-options:trickle\r\na=fingerprint:sha-256 2E:A3:59:0D:6D:5A:65:5C:F8:12:B7:46:F5:3A:6A:72:33:BA:46:BF:03:2E:9E:2E:C2:FD:5B:52:B2:C2:85:A2\r\na=setup:actpass\r\na=mid:2\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"
   },
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "2inURksqLqGW",
   "hint": "I'm taking my time!"
}
[5490525012024748] Creating ICE agent (ICE Full mode, controlled)
janus_http_send_message(1159): message={
   "janus": "event",
   "session_id": 4975254805420424,
   "transaction": "2inURksqLqGW",
   "sender": 5490525012024748,
   "plugindata": {
      "plugin": "janus.plugin.echotest",
      "data": {
         "echotest": "event",
         "result": "ok"
      }
   },
   "jsep": {
      "type": "answer",
      "sdp": "v=0\r\no=- 1298443446168106922 2 IN IP4 10.0.2.15\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1 2\r\na=msid-semantic: WMS janus\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111\r\nc=IN IP4 10.0.2.15\r\na=sendrecv\r\na=mid:0\r\na=rtcp-mux\r\na=ice-ufrag:XX/Y\r\na=ice-pwd:0KDtjKboxthTph4TmYfpHh\r\na=ice-options:trickle\r\na=fingerprint:sha-256 5E:1D:14:4C:B8:ED:EA:3B:C8:E1:D7:C2:7E:5F:68:43:4A:2E:2B:56:0E:1D:AE:5D:34:C0:A2:D2:A2:C0:41:E4\r\na=setup:active\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 useinbandfec=1\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\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:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=msid:janus janusa0\r\na=ssrc:141121634 cname:janus\r\na=ssrc:141121634 msid:janus janusa0\r\na=ssrc:141121634 mslabel:janus\r\na=ssrc:141121634 label:janusa0\r\na=candidate:1 1 udp 2015363327 10.0.2.15 36058 typ host\r\na=candidate:2 1 udp 2015363583 192.168.56.110 54571 typ host\r\na=end-of-candidates\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97\r\nc=IN IP4 10.0.2.15\r\na=sendrecv\r\na=mid:1\r\na=rtcp-mux\r\na=ice-ufrag:XX/Y\r\na=ice-pwd:0KDtjKboxthTph4TmYfpHh\r\na=ice-options:trickle\r\na=fingerprint:sha-256 5E:1D:14:4C:B8:ED:EA:3B:C8:E1:D7:C2:7E:5F:68:43:4A:2E:2B:56:0E:1D:AE:5D:34:C0:A2:D2:A2:C0:41:E4\r\na=setup:active\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=extmap:13 urn:3gpp:video-orientation\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:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=ssrc-group:FID 2027724451 3485931207\r\na=msid:janus janusv0\r\na=ssrc:2027724451 cname:janus\r\na=ssrc:2027724451 msid:janus janusv0\r\na=ssrc:2027724451 mslabel:janus\r\na=ssrc:2027724451 label:janusv0\r\na=ssrc:3485931207 cname:janus\r\na=ssrc:3485931207 msid:janus janusv0\r\na=ssrc:3485931207 mslabel:janus\r\na=ssrc:3485931207 label:janusv0\r\na=candidate:1 1 udp 2015363327 10.0.2.15 36058 typ host\r\na=candidate:2 1 udp 2015363583 192.168.56.110 54571 typ host\r\na=end-of-candidates\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 10.0.2.15\r\na=sendrecv\r\na=sctp-port:5000\r\na=mid:2\r\na=ice-ufrag:XX/Y\r\na=ice-pwd:0KDtjKboxthTph4TmYfpHh\r\na=ice-options:trickle\r\na=fingerprint:sha-256 5E:1D:14:4C:B8:ED:EA:3B:C8:E1:D7:C2:7E:5F:68:43:4A:2E:2B:56:0E:1D:AE:5D:34:C0:A2:D2:A2:C0:41:E4\r\na=setup:active\r\na=candidate:1 1 udp 2015363327 10.0.2.15 36058 typ host\r\na=candidate:2 1 udp 2015363583 192.168.56.110 54571 typ host\r\na=end-of-candidates\r\n"
   }
}
janus_http_handler(1798): url=/janus/4975254805420424 method=GET data={
   "janus": "keepalive",
   "session_id": 4975254805420424,
   "transaction": "1Vz9OOAz2Re"
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "1Vz9OOAz2Re"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "candidate": "candidate:2999745851 1 udp 2122194687 192.168.56.1 55007 typ host generation 0 ufrag OBYC network-id 2",
      "sdpMid": "0",
      "sdpMLineIndex": 0
   },
   "transaction": "ucnZdHetH1U5",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "ucnZdHetH1U5"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "candidate": "candidate:3304467501 1 udp 2122260223 192.168.1.71 54297 typ host generation 0 ufrag OBYC network-id 1",
      "sdpMid": "1",
      "sdpMLineIndex": 1
   },
   "transaction": "UgUvMHjiuvOB",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "UgUvMHjiuvOB"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "candidate": "candidate:2999745851 1 udp 2122194687 192.168.56.1 48592 typ host generation 0 ufrag OBYC network-id 2",
      "sdpMid": "2",
      "sdpMLineIndex": 2
   },
   "transaction": "bU8EW4N0FDhz",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "bU8EW4N0FDhz"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "candidate": "candidate:3304467501 1 udp 2122260223 192.168.1.71 42957 typ host generation 0 ufrag OBYC network-id 1",
      "sdpMid": "0",
      "sdpMLineIndex": 0
   },
   "transaction": "d6KUaFs8hwgt",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "d6KUaFs8hwgt"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "candidate": "candidate:2999745851 1 udp 2122194687 192.168.56.1 37981 typ host generation 0 ufrag OBYC network-id 2",
      "sdpMid": "1",
      "sdpMLineIndex": 1
   },
   "transaction": "6RmMZX6GIH2D",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "6RmMZX6GIH2D"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "candidate": "candidate:2322976989 1 tcp 1518280447 192.168.1.71 9 typ host tcptype active generation 0 ufrag OBYC network-id 1",
      "sdpMid": "0",
      "sdpMLineIndex": 0
   },
   "transaction": "8LNCIXu22B82",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "8LNCIXu22B82"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "candidate": "candidate:4233069003 1 tcp 1518214911 192.168.56.1 9 typ host tcptype active generation 0 ufrag OBYC network-id 2",
      "sdpMid": "0",
      "sdpMLineIndex": 0
   },
   "transaction": "E9Z8uurLdMXh",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "E9Z8uurLdMXh"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "candidate": "candidate:3304467501 1 udp 2122260223 192.168.1.71 34860 typ host generation 0 ufrag OBYC network-id 1",
      "sdpMid": "2",
      "sdpMLineIndex": 2
   },
   "transaction": "ZMVPHzJ6xxpE",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "ZMVPHzJ6xxpE"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "candidate": "candidate:853956089 1 udp 1686052607 111.197.112.16 14710 typ srflx raddr 192.168.1.71 rport 42957 generation 0 ufrag OBYC network-id 1",
      "sdpMid": "0",
      "sdpMLineIndex": 0
   },
   "transaction": "YfKAdIvNaSLW",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "YfKAdIvNaSLW"
}
janus_http_handler(1979): url=/janus/4975254805420424/5490525012024748 method=POST data={
   "janus": "trickle",
   "candidate": {
      "completed": true
   },
   "transaction": "ZSzNu1IgG124",
   "session_id": 4975254805420424,
   "handle_id": 5490525012024748
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "ZSzNu1IgG124"
}
janus_http_send_message(1159): message={
   "janus": "webrtcup",
   "session_id": 4975254805420424,
   "sender": 5490525012024748
}
[5490525012024748] The DTLS handshake has been completed
[janus.plugin.echotest-0x7f9fb0001650] WebRTC media is now available
janus_http_handler(1798): url=/janus/4975254805420424 method=GET data={
   "janus": "keepalive",
   "session_id": 4975254805420424,
   "transaction": "9RXXrLweqvj"
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "9RXXrLweqvj"
}
janus_http_send_message(1159): message={
   "janus": "media",
   "session_id": 4975254805420424,
   "sender": 5490525012024748,
   "type": "audio",
   "receiving": true
}
janus_http_handler(1798): url=/janus/4975254805420424 method=GET data={
   "janus": "keepalive",
   "session_id": 4975254805420424,
   "transaction": "nIW8K8sosKC"
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "nIW8K8sosKC"
}
janus_http_send_message(1159): message={
   "janus": "media",
   "session_id": 4975254805420424,
   "sender": 5490525012024748,
   "type": "video",
   "receiving": true
}
janus_http_handler(1798): url=/janus/4975254805420424 method=GET data={
   "janus": "keepalive",
   "session_id": 4975254805420424,
   "transaction": "HbMuqSQtaqn"
}
janus_http_send_message(1159): message={
   "janus": "ack",
   "session_id": 4975254805420424,
   "transaction": "HbMuqSQtaqn"
}
janus_http_handler(1979): url=/janus/4975254805420424 method=POST data={
   "janus": "destroy",
   "transaction": "9xiRaxbm1cU7",
   "session_id": 4975254805420424
}
janus_http_send_message(1159): message={
   "janus": "success",
   "session_id": 4975254805420424,
   "transaction": "9xiRaxbm1cU7"
}
Destroying session 4975254805420424; 0x7f9fb0001320
Detaching handle from JANUS EchoTest plugin; 0x7f9fb0001b10 0x7f9fb0001650 0x7f9fb0001b10 0x7f9fb0001760
[janus.plugin.echotest-0x7f9fb0001650] No WebRTC media anymore
[5490525012024748] WebRTC resources freed; 0x7f9fb0001b10 0x7f9fb0001320
[5490525012024748] Handle and related resources freed; 0x7f9fb0001b10 0x7f9fb0001320


6. 源码分析

6.1 在 Janus 中默认支持的插件包括以下几个

  1. SIP:这个插件使得 Janus 成了 SIP 用户的代理,从而允许 WebRTC 终端在 SIP 服务器(如 Asterisk)上注册,并向 SIP 服务器发送或接收音视频流。
  2. TextRoom:该插件使用 DataChannel 实现了一个文本聊天室应用。
  3. Streaming:它允许 WebRTC 终端观看 / 收听由其他工具生成的预先录制的文件或媒体。
  4. VideoRoom:它实现了视频会议的 SFU 服务,实际就是一个音 / 视频路由器。
  5. VideoCall:这是一个简单的视频呼叫的应用,允许两个 WebRTC 终端相互通信,它与 WebRTC 官网的例子相似(https://apprtc.appspot.com),不同点是这个插件要经过服务端进行音视频流中转,而 WebRTC 官网的例子走的是 P2P 直连。
  6. RecordPlay:该插件有两个功能,一是将发送给 WebRTC 的数据录制下来,二是可以通过 WebRTC 进行回放。