Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
RTM945 committed Apr 27, 2020
0 parents commit bcaa978
Show file tree
Hide file tree
Showing 56 changed files with 44,201 additions and 0 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## webrtc-cli test
1. run signal
2. run webrtc-cli, type signal server address and select a folder, click "connect", then get token
3. deploy simple-test-page, the easiest way is using [Web Server for Chrome](https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?utm_source=chrome-app-launcher-info-dialog)
4. open index.html, type token, select "offer", click "connect"
53 changes: 53 additions & 0 deletions signal/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>me.rtmsoft.webrtc</groupId>
<artifactId>signal</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>signal</name>
<description>webrtc signal server</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package me.rtmsoft.webrtc.signal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.messaging.SubProtocolWebSocketHandler;

public class CustomSubProtocolWebSocketHandler extends SubProtocolWebSocketHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomSubProtocolWebSocketHandler.class);

private SessionManager sessionManager;
private PeerManager peerManager;

public CustomSubProtocolWebSocketHandler(
MessageChannel clientInboundChannel,
SubscribableChannel clientOutboundChannel,
SessionManager sessionManager,
PeerManager peerManager) {
super(clientInboundChannel, clientOutboundChannel);
this.sessionManager = sessionManager;
this.peerManager = peerManager;
}

@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
LOGGER.info(session.getId() + " connection established");
sessionManager.add(session);
super.afterConnectionEstablished(session);
}

@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
LOGGER.info(session.getId() + " connection closed");
sessionManager.remove(session);
peerManager.remove(session.getId());
super.afterConnectionClosed(session, closeStatus);
}
}
39 changes: 39 additions & 0 deletions signal/src/main/java/me/rtmsoft/webrtc/signal/DTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package me.rtmsoft.webrtc.signal;

public class DTO{

private String remote;
private String value;

public DTO() {
}

public DTO(String remote, String value) {
this.remote = remote;
this.value = value;
}

public void setRemote(String remote) {
this.remote = remote;
}

public void setValue(String value) {
this.value = value;
}

public String getRemote() {
return remote;
}

public String getValue() {
return value;
}

@Override
public String toString() {
return "DTO{" +
"remote='" + remote + '\'' +
", value='" + value + '\'' +
'}';
}
}
51 changes: 51 additions & 0 deletions signal/src/main/java/me/rtmsoft/webrtc/signal/Peer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package me.rtmsoft.webrtc.signal;

import java.security.Principal;

public class Peer implements Principal {

public static final String OFFER_SUFFIX = "_offer";
public static final String ANSWER_SUFFIX = "_answer";

private final String token;

private final String type;

private final String sessionId;

@Override
public String toString() {
return "Peer{" +
"token='" + token + '\'' +
", type='" + type + '\'' +
", sessionId='" + sessionId + '\'' +
'}';
}

public Peer(String token, String type, String sessionId) {
this.token = token;
this.type = type;
this.sessionId = sessionId;
}

public String getToken() {
return token;
}

public String getType() {
return type;
}

public String getSessionId() {
return sessionId;
}

@Override
public String getName() {
if ("answer".equals(type)) {
return token + "_" + type;
}else{
return token + "_" + type + "_" + sessionId;
}
}
}
42 changes: 42 additions & 0 deletions signal/src/main/java/me/rtmsoft/webrtc/signal/PeerManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package me.rtmsoft.webrtc.signal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class PeerManager {

private static final Logger LOGGER = LoggerFactory.getLogger(PeerManager.class);

private Map<String, Peer> peerMap = new ConcurrentHashMap<>();

public boolean isRegistered(String name) {
return peerMap.get(name) != null;
}

public void add(Peer peer) {
peerMap.put(peer.getName(), peer);
}

public Peer pair(Peer peer, String remote) {
if ("offer".equals(peer.getType())) {
return peerMap.get(peer.getToken() + Peer.ANSWER_SUFFIX);
}else if ("answer".equals(peer.getType())){
return peerMap.get(peer.getToken() + Peer.OFFER_SUFFIX + "_" + remote);
}
return null;
}

public void remove(String sessionId) {
peerMap.forEach((k, v) -> {
if (v.getSessionId().equals(sessionId)){
peerMap.remove(k);
LOGGER.info(sessionId + " remove peer " + v.getName());
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package me.rtmsoft.webrtc.signal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.CloseStatus;

@Component
public class PrincipalChannelInterceptor implements ChannelInterceptor {

private static final Logger LOGGER = LoggerFactory.getLogger(PrincipalChannelInterceptor.class);

@Autowired
private PeerManager peerManager;

@Autowired
private SessionManager sessionManager;

@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (accessor != null && accessor.getCommand() == StompCommand.CONNECT) {
String sessionId = accessor.getSessionId();
try {
String token = accessor.getNativeHeader("token").get(0);
String type = accessor.getNativeHeader("type").get(0);
if (("offer".equals(type) || "answer".equals(type)) && !StringUtils.isEmpty(token)) {
if (!peerManager.isRegistered(token)) {
Peer peer = new Peer(token, type, sessionId);
peerManager.add(peer);
accessor.setUser(peer);
LOGGER.info(sessionId + " set principal " + peer.getName());
}else{
sessionManager.close(sessionId, CloseStatus.SERVICE_RESTARTED);
}
}else {
sessionManager.close(sessionId, CloseStatus.PROTOCOL_ERROR);
}
} catch (Exception e) {
e.printStackTrace();
sessionManager.close(sessionId, CloseStatus.PROTOCOL_ERROR);
}
}
return message;
}
}
39 changes: 39 additions & 0 deletions signal/src/main/java/me/rtmsoft/webrtc/signal/SessionManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package me.rtmsoft.webrtc.signal;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class SessionManager {

private Map<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();

public void add(WebSocketSession session) {
sessionMap.put(session.getId(), session);
}

public void remove(WebSocketSession session) {
sessionMap.remove(session.getId());
}

public WebSocketSession get(String sessionId) {
return sessionMap.get(sessionId);
}

public void close(String sessionId, CloseStatus status) {
WebSocketSession session = get(sessionId);
if (session != null) {
try {
session.close(status);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package me.rtmsoft.webrtc.signal;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SignalApplication {

public static void main(String[] args) {
SpringApplication.run(SignalApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package me.rtmsoft.webrtc.signal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;

import java.security.Principal;

@Controller
public class SignalController {

private static final Logger LOGGER = LoggerFactory.getLogger(SignalController.class);

@Autowired
private PeerManager peerManager;

@Autowired
private SimpMessagingTemplate messagingTemplate;

@MessageMapping("/sdp")
public void sdp(@Payload DTO data, Principal principal) {
Peer peer = (Peer) principal;
Peer pair = peerManager.pair(peer, data.getRemote());
LOGGER.info("pair:" + peer + ", " + pair);
if(pair != null) {
DTO dto = new DTO(peer.getSessionId(), data.getValue());
messagingTemplate.convertAndSendToUser(pair.getName(), "/queue/onsdp", dto);
}
}

@MessageMapping("/candidate")
public void candidate(@Payload DTO data, Principal principal) {
Peer peer = (Peer) principal;
Peer pair = peerManager.pair(peer, data.getRemote());
LOGGER.info("pair:" + peer + ", " + pair);
if(pair != null) {
DTO dto = new DTO(peer.getSessionId(), data.getValue());
messagingTemplate.convertAndSendToUser(pair.getName(), "/queue/oncandidate", dto);
}
}
}
Loading

0 comments on commit bcaa978

Please sign in to comment.