1.基础知识回顾
WebRTC 服务器之Janus概述和环境搭建-CSDN博客
WebRTC 服务器之Janus架构分析-CSDN博客
2.插件使用流程
我们要使⽤janus的功能时,通常要执⾏以下操作:
1. 在你的⽹⻚引入 Janus.js 库,即是包含janus.js;
<!– 网页头部或 body 底部引入 –>
<script src="https://your-cdn-path/janus.js"></script>
2. 初始化 Janus 库,并传递其依赖项(依赖项可选);
Janus.init({
debug: true, // 开启调试日志
dependencies: {
// 可选依赖(如 adapter.js 用于跨浏览器兼容)
adapter: adapter
},
callback: function() {
console.log("Janus 库初始化完成");
// 初始化完成后连接服务器
connectToJanusServer();
}
});
3. 连接服务器 & 创建会话 连接到janus server并创建create⼀个会话session;
let janusSession;
function connectToJanusServer() {
const serverUrl = "wss://your-janus-server:8989/janus";
new Janus({
server: serverUrl,
success: function(session) {
janusSession = session;
console.log("会话创建成功:", session.getId());
// 创建插件句柄(例如加入视频房间)
attachToVideoRoomPlugin();
},
error: function(error) {
console.error("连接失败:", error);
}
});
}
4. 创建插件句柄 (Handle) 创建⼀个或多个handle 以attach到插件(plugin)(例如videoroom、videocall等插件);
let pluginHandle;
function attachToVideoRoomPlugin() {
janusSession.attach({
plugin: "janus.plugin.videoroom", // 插件名称
success: function(handle) {
pluginHandle = handle;
console.log("成功附加到插件,句柄 ID:", handle.getId());
// 发送加入房间请求
joinVideoRoom();
},
error: function(error) {
console.error("附加插件失败:", error);
}
});
}
5. 信令交互示例 – 加入视频房间 与创建交互(发送/接收消息,协商PeerConnection);
function joinVideoRoom() {
const joinMsg = {
request: "join",
room: 1234, // 房间 ID
ptype: "publisher",
display: "用户1"
};
pluginHandle.send({ message: joinMsg });
}
// 处理服务器事件(如房间通知)
pluginHandle.on("message", (msg, jsep) => {
console.log("收到服务器消息:", msg);
if (msg["videoroom"] === "joined") {
console.log("成功加入房间!");
// 处理媒体协商(如创建 Offer)
startWebRTCNegotiation();
}
});
6. WebRTC 协商流程
function startWebRTCNegotiation() {
// 创建媒体配置
const mediaConfig = {
audio: true,
video: true,
data: true
};
// 准备 PeerConnection
pluginHandle.createOffer({
media: mediaConfig,
success: function(sdp) {
// 发送 SDP Offer
pluginHandle.sendSDP(sdp);
},
error: function(error) {
console.error("创建 Offer 失败:", error);
}
});
}
// 处理 ICE Candidate
pluginHandle.on("ice", (candidate) => {
// 发送候选到服务器
pluginHandle.trickle(candidate);
});
7. 最后 关闭所有的handles并关闭相关的相应的PeerConnections; 消耗destroy会话session。
function cleanup() {
// 1. 销毁插件句柄
if (pluginHandle) {
pluginHandle.detach();
pluginHandle = null;
}
// 2. 销毁会话
if (janusSession) {
janusSession.destroy();
janusSession = null;
}
}
// 页面关闭时触发清理
window.onbeforeunload = cleanup;
完整流程总结
初始化
Janus.init({ debug: true, callback: createJanusSession });
会话与插件
创建会话 (createSession) → 创建插件句柄 (createHandle) → 注册事件监听 (eventHandler).
信令交互
发送消息 (sendMessage) 加入房间 → 接收服务器事件 (handleEvent).
WebRTC 协商
创建 Offer (createOffer) → 发送 SDP (sendSDP) → 接收 Answer → 创建 Answer (createAnswer).
收发av数据
资源释放
销毁句柄 (destroyHandle) → 销毁会话 (destroySession).
2.1 协议基本类型
"janus"后⾯的字符串代表消息的类型,主要有:
3.videoroom插件信令交互分析
Janus中所有插件都遵循以下基本数据流程:
3.总体逻辑
- JBJ-WEBSOCKET RECV: {"janus":"create","transaction":"aAMxRfsTsVVQ"}
{
"janus": "success",
"transaction": "aAMxRfsTsVVQ",
"data": {
"id": 5109637625847547
}
}
) to janus.transport.websockets (0x7f5cd400d3c0)
"janus": "attach",
"plugin": "janus.plugin.videoroom",
"opaque_id": "videoroomtest-jIAzP2ZkPUrn",
"transaction": "2kuM6pzfX4Zh",
"session_id": 5109637625847547
}
"janus": "success",
"session_id": 5109637625847547,
"transaction": "2kuM6pzfX4Zh",
"data": {
"id": 6769547295474368
}
}) to janus.transport.websockets (0x7f5cd400d3c0)
"janus": "message",
"body": {
"request": "join",
"room": 1234,
"ptype": "publisher",
"display": "321"
},
"transaction": "11JDzIbsbK91",
"session_id": 5109637625847547,
"handle_id": 6769547295474368
}
JBJ-WEBSOCKET responses:Sending Janus API response({
"janus": "ack",
"session_id": 5109637625847547,
"transaction": "11JDzIbsbK91"
}) to janus.transport.websockets (0x7f5cd400d3c0)
JBJ-video.room.event: [6769547295474368] Sending event is: {
"janus": "event",
"session_id": 5109637625847547,
"transaction": "11JDzIbsbK91",
"sender": 6769547295474368,
"plugindata": {
"plugin": "janus.plugin.videoroom",
"data": {
"videoroom": "joined",
"room": 1234,
"description": "Demo Room",
"id": 6538458198168085,
"private_id": 1041514801,
"publishers": []
}
}} to transport…
Sending event to janus.transport.websockets (0x7f5cd400d3c0)
>> 0 (Success)
JBJ-WEBSOCKETRECV: {
"janus": "message",
"body": {
"request": "configure",
"audio": true,
"video": true
},
"transaction": "MHTliRCHqY5y",
"jsep": {
"type": "offer",
"sdp": "v=0\\r\\no=- 6239954181818903803 2 IN IP4 127.0.0.1\\r\\ns=-\\r\\nt=0 0\\r\\na=group:BUNDLE 0 1\\r\\na=extmap-allow-mixed\\r\\na=msid-semantic: WMS 900722df-7e7a-4951-b1bf-1902cb7fe6e0\\r\\nm=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 13 110 126\\r\\nc=IN IP4 0.0.0.0\\r\\na=rtcp:9 IN IP4 0.0.0.0\\r\\na=ice-ufrag:eHT/\\r\\na=ice-pwd:aAxznBSHiqTXMkZAzJs5xv3B\\r\\na=ice-options:trickle\\r\\na=fingerprint:sha-256 75:80:26:F9:EB:47:14:51:61:D3:CD:8B:60:C1:5E:F5:67:53:1E:88:9C:45:53:3B:32:D0:D2:5F:CD:45:63:7F\\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=sendonly\\r\\na=msid:900722df-7e7a-4951-b1bf-1902cb7fe6e0 9718362e-2152-4c32-9e79-da62a8a609c5\\r\\na=rtcp-mux\\r\\na=rtcp-rsize\\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:63 red/48000/2\\r\\na=fmtp:63 111/111\\r\\na=rtpmap:9 G722/8000\\r\\na=rtpmap:0 PCMU/8000\\r\\na=rtpmap:8 PCMA/8000\\r\\na=rtpmap:13 CN/8000\\r\\na=rtpmap:110 telephone-event/48000\\r\\na=rtpmap:126 telephone-event/8000\\r\\na=ssrc:2665350871 cname:+3Rknr5a6Axa5msx\\r\\na=ssrc:2665350871 msid:900722df-7e7a-4951-b1bf-1902cb7fe6e0 9718362e-2152-4c32-9e79-da62a8a609c5\\r\\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 103 104 107 108 109 114 115 116 117 118 39 40 45 46 98 99 100 101 119 120 123 124 125\\r\\nc=IN IP4 0.0.0.0\\r\\na=rtcp:9 IN IP4 0.0.0.0\\r\\na=ice-ufrag:eHT/\\r\\na=ice-pwd:aAxznBSHiqTXMkZAzJs5xv3B\\r\\na=ice-options:trickle\\r\\na=fingerprint:sha-256 75:80:26:F9:EB:47:14:51:61:D3:CD:8B:60:C1:5E:F5:67:53:1E:88:9C:45:53:3B:32:D0:D2:5F:CD:45:63:7F\\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:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\\r\\na=extmap:6 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:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\\r\\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\\r\\na=sendonly\\r\\na=msid:900722df-7e7a-4951-b1bf-1902cb7fe6e0 d97d2702-4a0f-4693-8499-71c66f8c03fe\\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:103 H264/90000\\r\\na=rtcp-fb:103 goog-remb\\r\\na=rtcp-fb:103 transport-cc\\r\\na=rtcp-fb:103 ccm fir\\r\\na=rtcp-fb:103 nack\\r\\na=rtcp-fb:103 nack pli\\r\\na=fmtp:103 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\\r\\na=rtpmap:104 rtx/90000\\r\\na=fmtp:104 apt=103\\r\\na=rtpmap:107 H264/90000\\r\\na=rtcp-fb:107 goog-remb\\r\\na=rtcp-fb:107 transport-cc\\r\\na=rtcp-fb:107 ccm fir\\r\\na=rtcp-fb:107 nack\\r\\na=rtcp-fb:107 nack pli\\r\\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\\r\\na=rtpmap:108 rtx/90000\\r\\na=fmtp:108 apt=107\\r\\na=rtpmap:109 H264/90000\\r\\na=rtcp-fb:109 goog-remb\\r\\na=rtcp-fb:109 transport-cc\\r\\na=rtcp-fb:109 ccm fir\\r\\na=rtcp-fb:109 nack\\r\\na=rtcp-fb:109 nack pli\\r\\na=fmtp:109 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\\r\\na=rtpmap:114 rtx/90000\\r\\na=fmtp:114 apt=109\\r\\na=rtpmap:115 H264/90000\\r\\na=rtcp-fb:115 goog-remb\\r\\na=rtcp-fb:115 transport-cc\\r\\na=rtcp-fb:115 ccm fir\\r\\na=rtcp-fb:115 nack\\r\\na=rtcp-fb:115 nack pli\\r\\na=fmtp:115 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\\r\\na=rtpmap:116 rt
}
JBJ-video.room.event: [6769547295474368] Sending event is: {
"janus": "event",
"session_id": 5109637625847547,
"transaction": "MHTliRCHqY5y",
"sender": 6769547295474368,
"plugindata": {
"plugin": "janus.plugin.videoroom",
"data": {
"videoroom": "event",
"room": 1234,
"configured": "ok",
"audio_codec": "opus",
"video_codec": "vp8"
}
},
"jsep": {
"type": "answer",
"sdp": "v=0\\r\\no=- 6239954181818903803 2 IN IP4 117.72.13.81\\r\\ns=VideoRoom 1234\\r\\nt=0 0\\r\\na=group:BUNDLE 0 1\\r\\na=msid-semantic: WMS janus\\r\\nm=audio 9 UDP/TLS/RTP/SAVPF 111\\r\\nc=IN IP4 117.72.13.81\\r\\na=recvonly\\r\\na=mid:0\\r\\na=rtcp-mux\\r\\na=ice-ufrag:0pFN\\r\\na=ice-pwd:wGcEE+9WQLoHULcXGP8KFn\\r\\na=ice-options:trickle\\r\\na=fingerprint:sha-256 C7:C1:43:EE:67:07:A0:6D:42:33:6A:CA:4E:EA:95:E0:55:17:03:CB:88:FD:B6:37:AB:1C:7B:85:65:9A:95:C6\\r\\na=setup:active\\r\\na=rtpmap:111 opus/48000/2\\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=msid:janus janusa0\\r\\na=ssrc:3338353236 cname:janus\\r\\na=ssrc:3338353236 msid:janus janusa0\\r\\na=ssrc:3338353236 mslabel:janus\\r\\na=ssrc:3338353236 label:janusa0\\r\\na=candidate:1 1 udp 2013266431 117.72.13.81 53576 typ host\\r\\na=candidate:2 1 udp 1677722111 117.72.13.81 53576 typ srflx raddr 172.16.0.4 rport 53576\\r\\na=candidate:3 1 udp 503316991 172.16.0.4 54497 typ relay raddr 172.16.0.4 rport 53576\\r\\na=end-of-candidates\\r\\nm=video 9 UDP/TLS/RTP/SAVPF 96 97\\r\\nc=IN IP4 117.72.13.81\\r\\na=recvonly\\r\\na=mid:1\\r\\na=rtcp-mux\\r\\na=ice-ufrag:0pFN\\r\\na=ice-pwd:wGcEE+9WQLoHULcXGP8KFn\\r\\na=ice-options:trickle\\r\\na=fingerprint:sha-256 C7:C1:43:EE:67:07:A0:6D:42:33:6A:CA:4E:EA:95:E0:55:17:03:CB:88:FD:B6:37:AB:1C:7B:85:65:9A:95:C6\\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:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\\r\\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\\r\\na=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\\r\\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\\r\\na=rtpmap:97 rtx/90000\\r\\na=fmtp:97 apt=96\\r\\na=msid:janus janusv0\\r\\na=ssrc:3467980833 cname:janus\\r\\na=ssrc:3467980833 msid:janus janusv0\\r\\na=ssrc:3467980833 mslabel:janus\\r\\na=ssrc:3467980833 label:janusv0\\r\\na=ssrc:3074101642 cname:janus\\r\\na=ssrc:3074101642 msid:janus janusv0\\r\\na=ssrc:3074101642 mslabel:janus\\r\\na=ssrc:3074101642 label:janusv0\\r\\na=candidate:1 1 udp 2013266431 117.72.13.81 53576 typ host\\r\\na=candidate:2 1 udp 1677722111 117.72.13.81 53576 typ srflx raddr 172.16.0.4 rport 53576\\r\\na=candidate:3 1 udp 503316991 172.16.0.4 54497 typ relay raddr 172.16.0.4 rport 53576\\r\\na=end-of-candidates\\r\\n"
}
}
#######################trickle
JBJ-WEBSOCKET RECV: {
"janus": "trickle",
"candidate": {
"candidate": "candidate:980779705 1 udp 2122260223 192.168.126.1 60475 typ host generation 0 ufrag eHT/ network-id 2",
"sdpMid": "0",
"sdpMLineIndex": 0
},
"transaction": "0WWSoZXbCxhA",
"session_id": 5109637625847547,
"handle_id": 6769547295474368
}
JBJ-WEBSOCKET RECV: {
"janus": "trickle",
"candidate": {
"candidate": "candidate:3993315412 1 udp 2122194687 192.168.248.1 60476 typ host generation 0 ufrag eHT/ network-id 3",
"sdpMid": "0",
"sdpMLineIndex": 0
},
"transaction": "DddvxlDlWuZN",
"session_id": 5109637625847547,
"handle_id": 6769547295474368
}
JBJ-WEBSOCKET RECV: {
"janus": "trickle",
"candidate": {
"candidate": "candidate:2923601174 1 udp 2122129151 172.25.0.107 60477 typ host generation 0 ufrag eHT/ network-id 1 network-cost 10",
"sdpMid": "0",
"sdpMLineIndex": 0
},
"transaction": "HCdvw7ihHaaZ",
"session_id": 5109637625847547,
"handle_id": 6769547295474368
}
"janus": "ack",
"session_id": 5109637625847547,
"transaction": "MHTliRCHqY5y"
}) to janus.transport.websockets (0x7f5cd400d3c0)
JBJ-WEBSOCKET responses:Sending Janus API response({
"janus": "ack",
"session_id": 5109637625847547,
"transaction": "0WWSoZXbCxhA"
}) to janus.transport.websockets (0x7f5cd400d3c0)
JBJ-WEBSOCKET responses:Sending Janus API response({
"janus": "ack",
"session_id": 5109637625847547,
"transaction": "DddvxlDlWuZN"
}) to janus.transport.websockets (0x7f5cd400d3c0)
学习资料分享
0voice · GitHub
评论前必须登录!
注册