后端netty websocket作为 信令服务器。
研究了2天 代码是写死的 但是可以跑起来不用改什么东西。
这里直接粘贴上来吧。。 因为是demo 所以随便写的咯。
package webrtc;
import com.ContextSSLFactory;
import com.alibaba.fastjson.JSON;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import javax.net.ssl.SSLEngine;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class NettyWebRtcSvr {
public static Map<String,Channel> users=new ConcurrentHashMap<>();
public static void main(String[] args) throws InterruptedException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
NioEventLoopGroup b = new NioEventLoopGroup(1);
NioEventLoopGroup w = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap
.group(b,w)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
System.out.println("connect");
channel.pipeline()
.addLast(new HttpServerCodec())
.addLast(new HttpObjectAggregator(65536))
.addLast(new ChunkedWriteHandler())
.addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {
cyclicBarrier.await();
FullHttpRequest request=(FullHttpRequest)msg;
//拿到请求地址
String uri = request.uri();
//判断是不是websocket请求,如果是拿出我们传递的参数(我的是token)
String origin = request.headers().get("Origin");
if (null == origin) {
ctx.close();
} else {
if (null != uri && uri.contains("/ws") && uri.contains("?")) {
String[] uriArray = uri.split("\\?");
if (null != uriArray && uriArray.length > 1) {
String[] paramsArray = uriArray[1].split("=");
if (null != paramsArray && paramsArray.length > 1) {
String uid = paramsArray[1];
Attribute<Object> uid1 = ctx.channel().attr(AttributeKey.valueOf("uid"));
uid1.set(uid);
users.put(uid,ctx.channel());
}
}
//重新设置请求地址
request.setUri("/ws");
}
}
}
super.channelRead(ctx, msg);
}
})
.addLast(new WebSocketServerProtocolHandler("/ws"))
.addLast(new SimpleChannelInboundHandler<TextWebSocketFrame>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
ByteBuf content = msg.content();
String msgstr = content.toString(Charset.defaultCharset());
//System.out.println(msgstr);
WebRtcMsg rtcState = JSON.parseObject(msgstr, WebRtcMsg.class);
if (rtcState.getState() == RtcState.answer.state) {
System.out.println("用户1收到 用户2 返回的 answer");
Channel channel1 = users.get("1");
TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(msgstr);
channel1.writeAndFlush(textWebSocketFrame);
}else if (rtcState.getState() == RtcState.offer.state) {
System.out.println("用户1像 用户2 发送 offer");
Channel channel1 = users.get("2");
TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(msgstr);
channel1.writeAndFlush(textWebSocketFrame);
}else if (rtcState.getState() == RtcState.offer_condidate.state) {
System.out.println("用户1像 用户2发送 condidate");
Channel channel1 = users.get("2");
TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(msgstr);
channel1.writeAndFlush(textWebSocketFrame);
}
}
});
}
});
ChannelFuture future = bootstrap.bind(2333).sync();
future.channel().closeFuture().sync();
}
}
上面是服务端。 cyclicBarrier 主要是为了 我前端懒得 写。。
等2个都连接了 在发offer 免得发的时候 user2 client不在 。。
随便写 莫见怪。 主要是网上没有一个demo 能直接跑起来的。。差东差西。
我也看了好多 - -
package webrtc;
public enum RtcState {
offer_condidate(1),
offer(2),
answer(3),
;
public final int state;
RtcState(Integer state){
this.state=state;
}
public Integer getState() {
return state;
}
}
package webrtc;
public class WebRtcMsg {
private Integer state;
private String uid;
private String condidate;
private String desc;
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public String getCondidate() {
return condidate;
}
public void setCondidate(String condidate) {
this.condidate = condidate;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
下面是前端 这个是 发起端。 正常是一个页面就行 我就写死了
在这里插入代码片
```<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<script src="https://webrtc.github.io/adapter/adapter.js" type="text/javascript"></script>
<body>
<video id="bend" controls="controls"> </video>
<video id="remoteVideo" controls="controls"> </video>
</body>
<script>
var bend = document.getElementById("bend");
var remoteVideo = document.getElementById("remoteVideo");
client = new RTCPeerConnection();
socket = new WebSocket("ws://localhost:2333/ws?uid=1");
client.ontrack=function(event){
remoteVideo.srcObject=event.streams[0];
}
socket.onmessage = function(event){
var msg=event.data;
var parse = JSON.parse(msg);
console.info("当前用户为 2"+msg)
console.info(msg)
if (parse.state==3) {//answer
client.setRemoteDescription(parse.desc)
}else if (parse.state==2) {//offer
// 当前用户是被发起用户 则setRemote后 再次发送 answer
client.setRemoteDescription(parse.desc);
client.createAnswer().then(desc=>{
client.setLocalDescription(desc);
var userInfo={"desc":desc,"uid":"2","state":"3"};
socket.send(JSON.stringify(userInfo));
})
}else if (parse.state=1) {//offer_condidate
console.info(" 收到 用户1 的condidate"+parse.condidate)
client.addIceCandidate(new RTCIceCandidate(parse.condidate))
}
};
socket.onopen=function (event){
navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
}).then((stream) => {
bend.srcObject=stream;
stream.getTracks().forEach(function (track) {
client.addTrack(track,stream);
})
client.createOffer().then((desc)=>{
client.setLocalDescription(desc)
//send server
var userInfo={"desc":desc,"uid":"1","state":"2"};
socket.send(JSON.stringify(userInfo))
})
client.onicecandidate=function (event) {
var iceCandidate = event.candidate;
var userInfo={"uid":"1","state":"1","condidate":iceCandidate};
socket.send(JSON.stringify(userInfo))
}
})
}
</script>
</html>
下面是接受端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<script src="https://webrtc.github.io/adapter/adapter.js" type="text/javascript"></script>
<body>
<video id="bend" controls="controls"> </video>
<video id="remoteVideo" controls="controls"> </video>
</body>
<script>
var bend = document.getElementById("bend");
var remoteVideo = document.getElementById("remoteVideo");
client = new RTCPeerConnection();
socket = new WebSocket("ws://localhost:2333/ws?uid=2");
client.ontrack=function(event){
remoteVideo.srcObject=event.streams[0];
}
socket.onmessage = function(event){
var msg=event.data;
var parse = JSON.parse(msg);
console.info("当前用户为 2"+msg)
console.info(msg)
if (parse.state==3) {//answer
client.setRemoteDescription(parse.desc)
}else if (parse.state==2) {//offer
// 当前用户是被发起用户 则setRemote后 再次发送 answer
client.setRemoteDescription(parse.desc);
client.createAnswer().then(desc=>{
client.setLocalDescription(desc);
var userInfo={"desc":desc,"uid":"2","state":"3"};
socket.send(JSON.stringify(userInfo));
})
}else if (parse.state=1) {//offer_condidate
console.info(" 收到 用户1 的condidate"+parse.condidate)
client.addIceCandidate(new RTCIceCandidate(parse.condidate))
}
};
socket.onopen=function (event){
navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
}).then((stream) => {
bend.srcObject=stream;
stream.getTracks().forEach(function (track) {
client.addTrack(track,stream);
})
})
}
</script>
</html>
turnserver 没有搞。 我不晓得为什么百度那么多 我就是跑不起来 。。。
配置一个样 都跑不起来 所以 内网玩玩 算了。。。