WebRTC, short for Web Real-time Communication, is an API that enables Web browsers to conduct real-time voice or video conversations. It became open source on June 1, 2011 and was incorporated into the World Wide Web Consortium’s W3C recommendation with support from Google, Mozilla, and Opera

WebRTC can realize point-to-point video transmission, and can be effectively used to build video communication stations.

demo

Video presentation

The fundamentals of WebRTC

The key of WebRTC video communication lies in the real-time sharing of communication equipment signaling. Assuming that there are two devices A and B, the flow chart of A successful communication is shown in the figure below.

Technology stack

Server: Use Java Spring Boot to realize webSocket signaling server front-end: vue.js

Code implementation (the complete code has been uploaded to the public number [HackDev], background reply “call” can be obtained.)

Signaling Server Setup

As mentioned above, real-time sharing of signaling is the key to realize call, so I used Java Spring Boot to build a signaling server based on WebSocket. Of course, you can also use the lighter and more convenient Node.js to build, which will be much more convenient.

@Configuration
@EnableWebSocketMessageBroker
/ / by EnableWebSocketMessageBroker use STOMP protocol to transmit messages based on agent (message broker), the browser support using the @ MessageMapping like support @ RequestMapping.
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) { //endPoint registers the protocol node and maps the specified URl

        // Register an endpoint named "endpointChat" and specify the SockJS protocol. Point to point. - Yeah
        registry.addEndpoint("/endpointChat").setAllowedOrigins("*").withSockJS();

    }
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {// Configure message Broker
        // Add a point-to-point /queue message broker
        registry.enableSimpleBroker("/queue"."/topic"); }}Copy the code
// Private chat controller
@RestController
public class WebSocketController {
    @Autowired
    private SimpMessagingTemplate messagingTemplate;
    @Autowired
    UserService userService;

    @MessageMapping("/api/chat")
    // In SpringMVC you can get the Principal directly, and the Principal contains information about the current user
    public void handleChat(Principal principal, MessagePara messagePara) {
        System.out.println(messagePara.getUsername());
        System.out.println(messagePara.getContent());
        String currentUserName = principal.getName();
        System.out.println(currentUserName);

        try {
            messagePara.setFrom(principal.getName());
            System.out.println("from" + messagePara.getFrom());
            Integer u_id = userService.getIdByName(currentUserName);
            messagingTemplate.convertAndSendToUser(messagePara.getUsername(),
                    "/queue/notifications",
                    messagePara);
        } catch (Exception e) {
            // Print exceptione.printStackTrace(); }}@MessageMapping(value = "/api/entrance")
    @SendTo(value = "/topic/users/list")// When the server has a message, it sends it to the browser that subscribed to the path in @sendto
    public User[] say(){
        System.out.println("+ + + + + + + + + + + + +");
        User[] users = userService.getAllUser();
        System.out.println(users[0].getUsername());
        System.out.println("+ + + + + + + + + + + + +");
        returnusers; }}Copy the code

Front-end WEBRTC implementation

The front end defines events such as signaling creation and sharing. Here I choose the VUE framework to build.

  • Connect to the signaling server
this.sock = new SockJS("/root/endpointChat")
this.stomp = Stomp.over(this.sock)
Copy the code
  • dial
let _self = this
_self.targetUsername = targetUsername
_self.stomp.send("/api/chat", {}, JSON.stringify({'username': targetUsername,
  'type': 'tryCall'.'content': JSON.stringify(_self.option) 
}))
Copy the code
  • B agrees to answer
_self.stomp.send("/api/chat", {}, JSON.stringify({'username': _self.targetUsername,
  'type': 'accept'.'content': ' '  
}))
// Get the media stream
const videoTracks = _self.localStream.getVideoTracks();
const audioTracks = _self.localStream.getAudioTracks();
// Define a local connection
_self.localPeerConnection = new RTCPeerConnection({});
// Define a remote connection
_self.remotePeerConnection = new RTCPeerConnection({});
Copy the code
  • A learns that B agrees to answer
async call(targetUsername) {
  let _self = this
  trace('localPeerConnection createOffer start.');
  const description = await _self.localPeerConnection.createOffer({offerToReceiveVideo: 1})
  trace(`Offer from localPeerConnection:\n${description.sdp}`);

  trace('localPeerConnection setLocalDescription start.');
  console.log("= = = = = = = = = = = = = =")
  console.log(description)
  console.log("= = = = = = = = = = = = = =")
  _self.localPeerConnection.setLocalDescription(description)
  console.log("send websocket")
  _self.stomp.send("/api/chat", {}, JSON.stringify({'username': targetUsername,
  'type': 'send'.'content':  JSON.stringify(description)}))
},
Copy the code

The complete code has been uploaded to the public account [z students who can program], and you can get it by replying to “call” in the background.