webRTC demo


准备:

  1. 信令服务
  2. 前端页面用于视频通话

demo github 地址。

前端页面

为了使 demo 尽量简单,功能页面如下,即包含登录、通过对方手机号拨打电话的功能。在实际生成过程中,未必使用的手机号,可能是任何能代表用户身份的字符串。

代码如下:

  
  
  
      
    Title  
  
  
录制格式:

信令服务

基于 JDK 1.8 Spring Boot、Netty 搭建,主要用于解决两个问题:

  1. 确认参与人,即拨打视频电话的人和接通视频电话的人
  2. 提供功能按钮 API,比如:发起视频通话、挂电话、以及 webRTC 建立通信通道

主要功能如下:

switch (event.getType()) {  
    case "connect": {  
        USER_MAP.put(event.getFrom(), ctx);  
        break;  
    }  
    case "watch": {  
        WebRtcEvent watchRequest = new WebRtcEvent();  
        if (USER_MAP.containsKey(event.getTo())) {  
            watchRequest.setType("watch");  
            watchRequest.setFrom(event.getFrom());  
            watchRequest.setTo(event.getTo());  
            USER_MAP.get(event.getTo()).writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(watchRequest)));  
        } else {  
            watchRequest.setType("offline");  
            USER_MAP.get(event.getFrom()).writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(watchRequest)));  
        }  
        break;  
    }  
    case "offer": {  
        WebRtcEvent offerRequest = new WebRtcEvent();  
        offerRequest.setType("offer");  
        offerRequest.setFrom(event.getFrom());  
        offerRequest.setTo(event.getTo());  
        offerRequest.setData(event.getData());  
        USER_MAP.get(event.getTo()).writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(offerRequest)));  
        break;  
    }  
    case "answer": {  
        WebRtcEvent answerRequest = new WebRtcEvent();  
        answerRequest.setType("answer");  
        answerRequest.setFrom(event.getFrom());  
        answerRequest.setData(event.getData());  
        USER_MAP.get(event.getTo()).writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(answerRequest)));  
        break;  
    }  
    case "candidate": {  
        WebRtcEvent candidateRequest = new WebRtcEvent();  
        candidateRequest.setType("candidate");  
        candidateRequest.setFrom(event.getFrom());  
        candidateRequest.setData(event.getData());  
        USER_MAP.get(event.getTo()).writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(candidateRequest)));  
        break;  
    }  
    case "hangup": {  
        WebRtcEvent hangupRequest = new WebRtcEvent();  
        hangupRequest.setType("hangup");  
        hangupRequest.setFrom(event.getFrom());  
        hangupRequest.setTo(event.getTo());  
        USER_MAP.get(event.getTo()).writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(hangupRequest)));  
        break;  
    }  
}

connect -> 登录

与 html 页面中的“登录”按钮对应,当输入手机号后,点击登录,手机号将会在信令服务中存到 map 中,以待后续操作使用。

如下图所示,至少两个客户端登录以后,才能正常视频通话。

watch -> 请求视频通话

点击 watch 按钮后,前端将发送一个事件到信令服务中,结构如下:

{  
    type: 'watch',      //事件类型
    from: 13789122381,  // 我的账号,比如 13789122381
    to: 1323493929      // 对方的账号,比如 1323493929
}

此时输入的对方账号对应 “to” 字段。

信令服务器收到 watch 事件后,从 map 中找出对应的在线客户端,将该事件转发至相应的客户端中。

offer -> 接通

对于接收者来说,点击“接通”按钮以后,webRTC 将开始建立通信隧道。

接通的 json 结构如下:

{  
    type: 'offer',  
    from: myId,  
    to: toId,  
    data: offer  
}

整个拨打电话、接通的流程如下:

总结

在 html 中还需要配置 coturn TURN 服务 地址,我在 demo 中使用的地址是测试地址,所以请不要在生产中使用。