From 33e40095458eba7268f1016904126084ff96c269 Mon Sep 17 00:00:00 2001 From: pabloFuente Date: Fri, 12 Jan 2018 20:46:37 +0100 Subject: [PATCH] CDR system --- .../io/openvidu/server/OpenViduServer.java | 13 +- .../openvidu/server/cdr/CDRTransmission.java | 96 ++++++++++++++ .../openvidu/server/cdr/CallDetailRecord.java | 109 ++++++++++++++++ .../server/config/OpenviduConfig.java | 7 + .../io/openvidu/server/core/Participant.java | 3 - .../SessionEventsHandler.java} | 121 +++++++++--------- .../openvidu/server/core/SessionManager.java | 12 +- .../server/kurento/core/KurentoSession.java | 6 +- .../core/KurentoSessionEventsHandler.java | 49 +++++++ .../kurento/core/KurentoSessionManager.java | 71 +++++----- .../src/main/resources/application.properties | 1 + .../src/main/resources/log4j.properties | 10 +- .../server/test/RoomProtocolTest.java | 4 +- .../server/test/core/RoomManagerTest.java | 8 +- 14 files changed, 392 insertions(+), 118 deletions(-) create mode 100644 openvidu-server/src/main/java/io/openvidu/server/cdr/CDRTransmission.java create mode 100644 openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java rename openvidu-server/src/main/java/io/openvidu/server/{kurento/core/KurentoSessionHandler.java => core/SessionEventsHandler.java} (82%) create mode 100644 openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionEventsHandler.java diff --git a/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java b/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java index e9433547..83c4329a 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java +++ b/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java @@ -37,11 +37,12 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonParser; +import io.openvidu.server.cdr.CallDetailRecord; import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.core.SessionManager; import io.openvidu.server.kurento.AutodiscoveryKurentoClientProvider; import io.openvidu.server.kurento.KurentoClientProvider; -import io.openvidu.server.kurento.core.KurentoSessionHandler; +import io.openvidu.server.kurento.core.KurentoSessionEventsHandler; import io.openvidu.server.kurento.core.KurentoSessionManager; import io.openvidu.server.kurento.kms.FixedOneKmsManager; import io.openvidu.server.rest.NgrokRestController; @@ -111,8 +112,14 @@ public class OpenViduServer implements JsonRpcConfigurer { @Bean @ConditionalOnMissingBean - public KurentoSessionHandler kurentoSessionHandler() { - return new KurentoSessionHandler(); + public KurentoSessionEventsHandler kurentoSessionEventsHandler() { + return new KurentoSessionEventsHandler(); + } + + @Bean + @ConditionalOnMissingBean + public CallDetailRecord cdr() { + return new CallDetailRecord(); } @Override diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRTransmission.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRTransmission.java new file mode 100644 index 00000000..412957e5 --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CDRTransmission.java @@ -0,0 +1,96 @@ +package io.openvidu.server.cdr; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import io.openvidu.server.core.MediaOptions; +import io.openvidu.server.core.Participant; + +public class CDRTransmission implements Comparable { + + private Participant participant; + private String sessionId; + private MediaOptions mediaOptions; + private Long timeOfStart; + private Long timeOfEnd; + private CDRTransmission receivingFrom; + + private SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd yyyy, HH:mm:ss"); + + public CDRTransmission(Participant participant, String sessionId, MediaOptions mediaOptions, CDRTransmission receivingFrom) { + this.participant = participant; + this.sessionId = sessionId; + this.mediaOptions = mediaOptions; + this.receivingFrom = receivingFrom; + this.timeOfStart = System.currentTimeMillis(); + } + + public Participant getParticipant() { + return this.participant; + } + + public String getSessionId() { + return this.sessionId; + } + + public MediaOptions getMediaOptions() { + return this.mediaOptions; + } + + public void endCall() { + this.timeOfEnd = System.currentTimeMillis(); + } + + public String getDateOfStart() { + return this.dateFormat.format(new Date(this.timeOfStart)); + } + + public String getDateOfEnd() { + return this.dateFormat.format(new Date(this.timeOfEnd)); + } + + public int totalCallDuration() { + return (int) ((this.timeOfEnd - this.timeOfStart) / 1000); + } + + public boolean getAudioEnabled() { + return this.mediaOptions.audioActive; + } + + public boolean getVideoEnabled() { + return this.mediaOptions.videoActive; + } + + public String typeOfVideo() { + if (!this.mediaOptions.videoActive) { + return "VIDEO_NOT_ENABLED"; + } else { + return this.mediaOptions.typeOfVideo; + } + } + + public CDRTransmission getReceivingFrom() { + return this.receivingFrom; + } + + @Override + public int compareTo(CDRTransmission other) { + if (this.participant.equals(other.participant)) { + if (this.receivingFrom != null && other.receivingFrom != null) { + if (this.receivingFrom.getParticipant().equals(other.receivingFrom.getParticipant())) { + return 0; + } else { + return 1; + } + } else { + if (this.receivingFrom == null && other.receivingFrom == null) { + return 0; + } else { + return 1; + } + } + } + return 1; + } + +} diff --git a/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java b/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java new file mode 100644 index 00000000..da5edc81 --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/cdr/CallDetailRecord.java @@ -0,0 +1,109 @@ +package io.openvidu.server.cdr; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openvidu.server.core.MediaOptions; +import io.openvidu.server.core.Participant; + +/** + * CDR logger to register all information of each WebRTC connection: + * + * - Participant unique identifier + * - Session unique identifier + * - Inbound or Outbound WebRTC connection + * - Sender unique identifier + * - Audio media stream enabled + * - Video media stream enabled + * - Video source [CAMERA, SCREEN] + * - Time of start of the call + * - Time of end of the call + * - Total time duration + * + * @author Pablo Fuente (pablofuenteperez@gmail.com) + */ +public class CallDetailRecord { + + private Logger log = LoggerFactory.getLogger(CallDetailRecord.class); + + private Map publications = new ConcurrentHashMap<>(); + private Map> subscriptions = new ConcurrentHashMap<>(); + + public void recordNewPublisher(Participant participant, String sessionId, MediaOptions mediaOptions) { + CDRTransmission publisher = new CDRTransmission(participant, sessionId, mediaOptions, null); + this.publications.put(participant.getParticipantPublicId(), publisher); + } + + public void recordNewSubscriber(Participant participant, String sessionId, String senderPublicId) { + CDRTransmission publisher = this.publications.get(senderPublicId); + CDRTransmission subscriber = new CDRTransmission(participant, sessionId, publisher.getMediaOptions(), publisher); + this.subscriptions.putIfAbsent(participant.getParticipantPublicId(), new ConcurrentSkipListSet<>()); + this.subscriptions.get(participant.getParticipantPublicId()).add(subscriber); + } + + public boolean stopPublisher(String participantPublicId) { + CDRTransmission publisher = this.publications.remove(participantPublicId); + if (publisher != null) { + publisher.endCall(); + log.info("{}", getTransmissionMessage(publisher)); + return true; + } + return false; + } + + public boolean stopSubscriber(String participantPublicId, String senderPublicId) { + Set participantSubscriptions = this.subscriptions.get(participantPublicId); + if (participantSubscriptions != null) { + CDRTransmission subscription; + for (Iterator it = participantSubscriptions.iterator(); it.hasNext();) { + subscription = it.next(); + if (subscription.getReceivingFrom().getParticipant().getParticipantPublicId().equals(senderPublicId)) { + it.remove(); + subscription.endCall(); + log.info("{}", getTransmissionMessage(subscription)); + return true; + } + } + } + return false; + } + + public void stopAllSubscriptions(String participantPublicId) { + Set participantSubscriptions = this.subscriptions.get(participantPublicId); + if (participantSubscriptions != null) { + CDRTransmission subscription; + for (Iterator it = participantSubscriptions.iterator(); it.hasNext();) { + subscription = it.next(); + subscription.endCall(); + log.info("{}", getTransmissionMessage(subscription)); + } + this.subscriptions.remove(participantPublicId).clear(); + } + } + + private String getTransmissionMessage(CDRTransmission cdr) { + StringBuffer sb = new StringBuffer(); + sb.append("\n"); + sb.append("\t").append(cdr.getParticipant().getParticipantPublicId()).append("\n"); + sb.append("\t").append(cdr.getSessionId()).append("\n"); + sb.append("\t").append((cdr.getReceivingFrom() != null) ? "INBOUND" : "OUTBOUND").append("\n"); + if (cdr.getReceivingFrom() != null) sb.append("\t").append((cdr.getReceivingFrom() != null) + ? cdr.getReceivingFrom().getParticipant().getParticipantPublicId() + : "").append("\n"); + sb.append("\t").append(cdr.getAudioEnabled()).append("\n"); + sb.append("\t").append(cdr.getVideoEnabled()).append("\n"); + if (cdr.getVideoEnabled()) sb.append("\t").append(cdr.typeOfVideo()).append("\n"); + sb.append("\t").append(cdr.getDateOfStart()).append("\n"); + sb.append("\t").append(cdr.getDateOfEnd()).append("\n"); + sb.append("\t").append(cdr.totalCallDuration()).append("\n"); + sb.append("\n"); + return sb.toString(); + } + +} diff --git a/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java b/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java index 2f3daf2e..f75fb3b3 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java +++ b/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java @@ -14,6 +14,9 @@ public class OpenviduConfig { @Value("${openvidu.secret}") private String openviduSecret; + + @Value("${openvidu.cdr}") + private boolean openviduCdr; public String getOpenViduPublicUrl() { return this.openviduPublicUrl; @@ -30,5 +33,9 @@ public class OpenviduConfig { public boolean isOpenViduSecret(String secret) { return secret.equals(this.getOpenViduSecret()); } + + public boolean isCdrEnabled() { + return this.openviduCdr; + } } diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java b/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java index 21fcee7b..91b445f6 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java @@ -17,9 +17,6 @@ public class Participant { private final String METADATA_SEPARATOR = "%/%"; - public Participant() { - } - public Participant(String participantPrivatetId, String participantPublicId, Token token, String clientMetadata) { this.participantPrivatetId = participantPrivatetId; this.participantPublicId = participantPublicId; diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionHandler.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java similarity index 82% rename from openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionHandler.java rename to openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java index 864aefe8..e1f0c2e6 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionHandler.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java @@ -1,11 +1,10 @@ -package io.openvidu.server.kurento.core; +package io.openvidu.server.core; import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import org.kurento.client.IceCandidate; import org.springframework.beans.factory.annotation.Autowired; import com.google.gson.JsonArray; @@ -15,21 +14,24 @@ import com.google.gson.JsonObject; import io.openvidu.client.OpenViduException; import io.openvidu.client.OpenViduException.Code; import io.openvidu.client.internal.ProtocolElements; +import io.openvidu.server.cdr.CallDetailRecord; import io.openvidu.server.config.InfoHandler; -import io.openvidu.server.core.MediaOptions; -import io.openvidu.server.core.Participant; +import io.openvidu.server.config.OpenviduConfig; import io.openvidu.server.rpc.RpcNotificationService; -public class KurentoSessionHandler { +public class SessionEventsHandler { @Autowired - private RpcNotificationService rpcNotificationService; + protected RpcNotificationService rpcNotificationService; @Autowired - private InfoHandler infoHandler; + protected InfoHandler infoHandler; - public KurentoSessionHandler() { - } + @Autowired + protected CallDetailRecord CDR; + + @Autowired + protected OpenviduConfig openviduConfig; public void onSessionClosed(String sessionId, Set participants) { JsonObject notifParams = new JsonObject(); @@ -103,12 +105,22 @@ public class KurentoSessionHandler { rpcNotificationService.sendErrorResponse(participant.getParticipantPrivateId(), transactionId, null, error); return; } + + boolean isPublishing = false; + if (openviduConfig.isCdrEnabled()) { + isPublishing = CDR.stopPublisher(participant.getParticipantPublicId()); + CDR.stopAllSubscriptions(participant.getParticipantPublicId()); + } JsonObject params = new JsonObject(); params.addProperty(ProtocolElements.PARTICIPANTLEFT_NAME_PARAM, participant.getParticipantPublicId()); for (Participant p : remainingParticipants) { rpcNotificationService.sendNotification(p.getParticipantPrivateId(), ProtocolElements.PARTICIPANTLEFT_METHOD, params); + + if (isPublishing && openviduConfig.isCdrEnabled()) { + CDR.stopSubscriber(p.getParticipantPublicId(), participant.getParticipantPublicId()); + } } if (transactionId != null) { @@ -117,9 +129,10 @@ public class KurentoSessionHandler { rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject()); } rpcNotificationService.closeRpcSession(participant.getParticipantPrivateId()); + } - public void onPublishMedia(Participant participant, Integer transactionId, MediaOptions mediaOptions, + public void onPublishMedia(Participant participant, String sessionId, Integer transactionId, MediaOptions mediaOptions, String sdpAnswer, Set participants, OpenViduException error) { if (error != null) { rpcNotificationService.sendErrorResponse(participant.getParticipantPrivateId(), transactionId, null, error); @@ -160,17 +173,42 @@ public class KurentoSessionHandler { ProtocolElements.PARTICIPANTPUBLISHED_METHOD, params); } } + + if (openviduConfig.isCdrEnabled()) { + CDR.recordNewPublisher(participant, sessionId, mediaOptions); + } } - public void onRecvIceCandidate(Participant participant, Integer transactionId, OpenViduException error) { + public void onUnpublishMedia(Participant participant, Set participants, Integer transactionId, + OpenViduException error) { if (error != null) { rpcNotificationService.sendErrorResponse(participant.getParticipantPrivateId(), transactionId, null, error); return; } rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject()); + + if (openviduConfig.isCdrEnabled()) { + CDR.stopPublisher(participant.getParticipantPublicId()); + } + + JsonObject params = new JsonObject(); + params.addProperty(ProtocolElements.PARTICIPANTUNPUBLISHED_NAME_PARAM, participant.getParticipantPublicId()); + + for (Participant p : participants) { + if (p.getParticipantPrivateId().equals(participant.getParticipantPrivateId())) { + continue; + } else { + rpcNotificationService.sendNotification(p.getParticipantPrivateId(), + ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD, params); + if (openviduConfig.isCdrEnabled()) { + CDR.stopSubscriber(p.getParticipantPublicId(), participant.getParticipantPublicId()); + } + } + } } - public void onSubscribe(Participant participant, String sdpAnswer, Integer transactionId, OpenViduException error) { + public void onSubscribe(Participant participant, String sessionId, String senderName, String sdpAnswer, Integer transactionId, + OpenViduException error) { if (error != null) { rpcNotificationService.sendErrorResponse(participant.getParticipantPrivateId(), transactionId, null, error); return; @@ -178,14 +216,22 @@ public class KurentoSessionHandler { JsonObject result = new JsonObject(); result.addProperty(ProtocolElements.RECEIVEVIDEO_SDPANSWER_PARAM, sdpAnswer); rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, result); + + if (openviduConfig.isCdrEnabled()) { + CDR.recordNewSubscriber(participant, sessionId, senderName); + } } - public void onUnsubscribe(Participant participant, Integer transactionId, OpenViduException error) { + public void onUnsubscribe(Participant participant, String senderName, Integer transactionId, OpenViduException error) { if (error != null) { rpcNotificationService.sendErrorResponse(participant.getParticipantPrivateId(), transactionId, null, error); return; } rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject()); + + if (openviduConfig.isCdrEnabled()) { + CDR.stopSubscriber(participant.getParticipantPublicId(), senderName); + } } public void onSendMessage(Participant participant, JsonObject message, Set participants, @@ -238,25 +284,12 @@ public class KurentoSessionHandler { rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject()); } - public void onUnpublishMedia(Participant participant, Set participants, Integer transactionId, - OpenViduException error) { + public void onRecvIceCandidate(Participant participant, Integer transactionId, OpenViduException error) { if (error != null) { rpcNotificationService.sendErrorResponse(participant.getParticipantPrivateId(), transactionId, null, error); return; } rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject()); - - JsonObject params = new JsonObject(); - params.addProperty(ProtocolElements.PARTICIPANTUNPUBLISHED_NAME_PARAM, participant.getParticipantPublicId()); - - for (Participant p : participants) { - if (p.getParticipantPrivateId().equals(participant.getParticipantPrivateId())) { - continue; - } else { - rpcNotificationService.sendNotification(p.getParticipantPrivateId(), - ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD, params); - } - } } public void onParticipantEvicted(Participant participant) { @@ -264,41 +297,7 @@ public class KurentoSessionHandler { ProtocolElements.PARTICIPANTEVICTED_METHOD, new JsonObject()); } - // ------------ EVENTS FROM ROOM HANDLER ----- - - public void onIceCandidate(String roomName, String participantId, String endpointName, IceCandidate candidate) { - JsonObject params = new JsonObject(); - params.addProperty(ProtocolElements.ICECANDIDATE_EPNAME_PARAM, endpointName); - params.addProperty(ProtocolElements.ICECANDIDATE_SDPMLINEINDEX_PARAM, candidate.getSdpMLineIndex()); - params.addProperty(ProtocolElements.ICECANDIDATE_SDPMID_PARAM, candidate.getSdpMid()); - params.addProperty(ProtocolElements.ICECANDIDATE_CANDIDATE_PARAM, candidate.getCandidate()); - rpcNotificationService.sendNotification(participantId, ProtocolElements.ICECANDIDATE_METHOD, params); - } - - public void onPipelineError(String roomName, Set participants, String description) { - JsonObject notifParams = new JsonObject(); - notifParams.addProperty(ProtocolElements.MEDIAERROR_ERROR_PARAM, description); - for (Participant p : participants) { - rpcNotificationService.sendNotification(p.getParticipantPrivateId(), ProtocolElements.MEDIAERROR_METHOD, - notifParams); - } - } - - public void onMediaElementError(String roomName, String participantId, String description) { - JsonObject notifParams = new JsonObject(); - notifParams.addProperty(ProtocolElements.MEDIAERROR_ERROR_PARAM, description); - rpcNotificationService.sendNotification(participantId, ProtocolElements.MEDIAERROR_METHOD, notifParams); - } - - public void updateFilter(String roomName, Participant participant, String filterId, String state) { - } - - public String getNextFilterState(String filterId, String state) { - return null; - } - public InfoHandler getInfoHandler() { return this.infoHandler; } - } diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java index 6d44281d..b17ca46e 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java @@ -39,21 +39,21 @@ public abstract class SessionManager { public void publishVideo(Participant participant, MediaOptions mediaOptions, Integer transactionId) { } - - public void onIceCandidate(Participant participant, String endpointName, String candidate, int sdpMLineIndex, - String sdpMid, Integer transactionId) { + + public void unpublishVideo(Participant participant, Integer transactionId) { } - + public void subscribe(Participant participant, String senderName, String sdpOffer, Integer transactionId) { } public void unsubscribe(Participant participant, String senderName, Integer transactionId) { } - + public void sendMessage(Participant participant, String message, Integer transactionId) { } - public void unpublishVideo(Participant participant, Integer transactionId) { + public void onIceCandidate(Participant participant, String endpointName, String candidate, int sdpMLineIndex, + String sdpMid, Integer transactionId) { } /** diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java index 997b3aa3..e8cdb725 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java @@ -37,7 +37,7 @@ public class KurentoSession implements Session { private CountDownLatch pipelineLatch = new CountDownLatch(1); private KurentoClient kurentoClient; - private KurentoSessionHandler kurentoSessionHandler; + private KurentoSessionEventsHandler kurentoSessionHandler; private volatile boolean closed = false; @@ -49,7 +49,7 @@ public class KurentoSession implements Session { private volatile boolean pipelineReleased = false; private boolean destroyKurentoClient; - public KurentoSession(String sessionId, KurentoClient kurentoClient, KurentoSessionHandler kurentoSessionHandler, + public KurentoSession(String sessionId, KurentoClient kurentoClient, KurentoSessionEventsHandler kurentoSessionHandler, boolean destroyKurentoClient) { this.sessionId = sessionId; this.kurentoClient = kurentoClient; @@ -119,7 +119,7 @@ public class KurentoSession implements Session { KurentoParticipant participant = participants.get(participantPrivateId); if (participant == null) { throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE, - "User #" + participantPrivateId + " not found in session '" + sessionId + "'"); + "Participant with private id " + participantPrivateId + " not found in session '" + sessionId + "'"); } participant.releaseAllFilters(); diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionEventsHandler.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionEventsHandler.java new file mode 100644 index 00000000..e6c33135 --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionEventsHandler.java @@ -0,0 +1,49 @@ +package io.openvidu.server.kurento.core; + +import java.util.Set; + +import org.kurento.client.IceCandidate; + +import com.google.gson.JsonObject; + +import io.openvidu.client.internal.ProtocolElements; +import io.openvidu.server.core.Participant; +import io.openvidu.server.core.SessionEventsHandler; + +public class KurentoSessionEventsHandler extends SessionEventsHandler { + + public KurentoSessionEventsHandler() { + } + + public void onIceCandidate(String roomName, String participantId, String endpointName, IceCandidate candidate) { + JsonObject params = new JsonObject(); + params.addProperty(ProtocolElements.ICECANDIDATE_EPNAME_PARAM, endpointName); + params.addProperty(ProtocolElements.ICECANDIDATE_SDPMLINEINDEX_PARAM, candidate.getSdpMLineIndex()); + params.addProperty(ProtocolElements.ICECANDIDATE_SDPMID_PARAM, candidate.getSdpMid()); + params.addProperty(ProtocolElements.ICECANDIDATE_CANDIDATE_PARAM, candidate.getCandidate()); + rpcNotificationService.sendNotification(participantId, ProtocolElements.ICECANDIDATE_METHOD, params); + } + + public void onPipelineError(String roomName, Set participants, String description) { + JsonObject notifParams = new JsonObject(); + notifParams.addProperty(ProtocolElements.MEDIAERROR_ERROR_PARAM, description); + for (Participant p : participants) { + rpcNotificationService.sendNotification(p.getParticipantPrivateId(), ProtocolElements.MEDIAERROR_METHOD, + notifParams); + } + } + + public void onMediaElementError(String roomName, String participantId, String description) { + JsonObject notifParams = new JsonObject(); + notifParams.addProperty(ProtocolElements.MEDIAERROR_ERROR_PARAM, description); + rpcNotificationService.sendNotification(participantId, ProtocolElements.MEDIAERROR_METHOD, notifParams); + } + + public void updateFilter(String roomName, Participant participant, String filterId, String state) { + } + + public String getNextFilterState(String filterId, String state) { + return null; + } + +} diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java index 7ebfdfb3..0b3bc12b 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java @@ -36,7 +36,7 @@ public class KurentoSessionManager extends SessionManager { private KurentoClientProvider kcProvider; @Autowired - private KurentoSessionHandler sessionHandler; + private KurentoSessionEventsHandler sessionHandler; @Override public synchronized void joinRoom(Participant participant, String sessionId, Integer transactionId) { @@ -190,7 +190,7 @@ public class KurentoSessionManager extends SessionManager { OpenViduException e = new OpenViduException(Code.MEDIA_SDP_ERROR_CODE, "Error generating SDP response for publishing user " + participant.getParticipantPublicId()); log.error("PARTICIPANT {}: Error publishing media", participant.getParticipantPublicId(), e); - sessionHandler.onPublishMedia(participant, transactionId, mediaOptions, sdpAnswer, participants, e); + sessionHandler.onPublishMedia(participant, session.getSessionId(), transactionId, mediaOptions, sdpAnswer, participants, e); } session.newPublisher(participant); @@ -202,35 +202,44 @@ public class KurentoSessionManager extends SessionManager { participants = kurentoParticipant.getSession().getParticipants(); if (sdpAnswer != null) { - sessionHandler.onPublishMedia(participant, transactionId, mediaOptions, sdpAnswer, participants, null); + sessionHandler.onPublishMedia(participant, session.getSessionId(), transactionId, mediaOptions, sdpAnswer, participants, null); } } - + @Override - public void onIceCandidate(Participant participant, String endpointName, String candidate, int sdpMLineIndex, - String sdpMid, Integer transactionId) { + public void unpublishVideo(Participant participant, Integer transactionId) { try { KurentoParticipant kParticipant = (KurentoParticipant) participant; - log.debug("Request [ICE_CANDIDATE] endpoint={} candidate={} " + "sdpMLineIdx={} sdpMid={} ({})", - endpointName, candidate, sdpMLineIndex, sdpMid, participant.getParticipantPublicId()); - kParticipant.addIceCandidate(endpointName, new IceCandidate(candidate, sdpMid, sdpMLineIndex)); - sessionHandler.onRecvIceCandidate(participant, transactionId, null); + KurentoSession session = kParticipant.getSession(); + + log.debug("Request [UNPUBLISH_MEDIA] ({})", participant.getParticipantPublicId()); + if (!participant.isStreaming()) { + throw new OpenViduException(Code.USER_NOT_STREAMING_ERROR_CODE, + "Participant '" + participant.getParticipantPublicId() + "' is not streaming media"); + } + kParticipant.unpublishMedia(); + session.cancelPublisher(participant); + + Set participants = session.getParticipants(); + + sessionHandler.onUnpublishMedia(participant, participants, transactionId, null); + } catch (OpenViduException e) { - log.error("PARTICIPANT {}: Error receiving ICE " + "candidate (epName={}, candidate={})", - participant.getParticipantPublicId(), endpointName, candidate, e); - sessionHandler.onRecvIceCandidate(participant, transactionId, e); + log.warn("PARTICIPANT {}: Error unpublishing media", participant.getParticipantPublicId(), e); + sessionHandler.onUnpublishMedia(participant, null, transactionId, e); } } - + @Override public void subscribe(Participant participant, String senderName, String sdpOffer, Integer transactionId) { String sdpAnswer = null; + Session session = null; try { log.debug("Request [SUBSCRIBE] remoteParticipant={} sdpOffer={} ({})", senderName, sdpOffer, participant.getParticipantPublicId()); KurentoParticipant kParticipant = (KurentoParticipant) participant; - Session session = ((KurentoParticipant) participant).getSession(); + session = ((KurentoParticipant) participant).getSession(); Participant senderParticipant = session.getParticipantByPublicId(senderName); if (senderParticipant == null) { @@ -258,10 +267,10 @@ public class KurentoSessionManager extends SessionManager { } } catch (OpenViduException e) { log.error("PARTICIPANT {}: Error subscribing to {}", participant.getParticipantPublicId(), senderName, e); - sessionHandler.onSubscribe(participant, null, transactionId, e); + sessionHandler.onSubscribe(participant, session.getSessionId(), senderName, null, transactionId, e); } if (sdpAnswer != null) { - sessionHandler.onSubscribe(participant, sdpAnswer, transactionId, null); + sessionHandler.onSubscribe(participant, session.getSessionId(), senderName, sdpAnswer, transactionId, null); } } @@ -284,7 +293,7 @@ public class KurentoSessionManager extends SessionManager { kParticipant.cancelReceivingMedia(senderName); - sessionHandler.onUnsubscribe(participant, transactionId, null); + sessionHandler.onUnsubscribe(participant, senderName, transactionId, null); } @Override @@ -301,28 +310,22 @@ public class KurentoSessionManager extends SessionManager { } @Override - public void unpublishVideo(Participant participant, Integer transactionId) { + public void onIceCandidate(Participant participant, String endpointName, String candidate, int sdpMLineIndex, + String sdpMid, Integer transactionId) { try { KurentoParticipant kParticipant = (KurentoParticipant) participant; - KurentoSession session = kParticipant.getSession(); - - log.debug("Request [UNPUBLISH_MEDIA] ({})", participant.getParticipantPublicId()); - if (!participant.isStreaming()) { - throw new OpenViduException(Code.USER_NOT_STREAMING_ERROR_CODE, - "Participant '" + participant.getParticipantPublicId() + "' is not streaming media"); - } - kParticipant.unpublishMedia(); - session.cancelPublisher(participant); - - Set participants = session.getParticipants(); - sessionHandler.onUnpublishMedia(participant, participants, transactionId, null); - + log.debug("Request [ICE_CANDIDATE] endpoint={} candidate={} " + "sdpMLineIdx={} sdpMid={} ({})", + endpointName, candidate, sdpMLineIndex, sdpMid, participant.getParticipantPublicId()); + kParticipant.addIceCandidate(endpointName, new IceCandidate(candidate, sdpMid, sdpMLineIndex)); + sessionHandler.onRecvIceCandidate(participant, transactionId, null); } catch (OpenViduException e) { - log.warn("PARTICIPANT {}: Error unpublishing media", participant.getParticipantPublicId(), e); - sessionHandler.onUnpublishMedia(participant, null, transactionId, e); + log.error("PARTICIPANT {}: Error receiving ICE " + "candidate (epName={}, candidate={})", + participant.getParticipantPublicId(), endpointName, candidate, e); + sessionHandler.onRecvIceCandidate(participant, transactionId, e); } } + /** * Creates a session if it doesn't already exist. The session's id will be * indicated by the session info bean. diff --git a/openvidu-server/src/main/resources/application.properties b/openvidu-server/src/main/resources/application.properties index beb60237..4e821b22 100644 --- a/openvidu-server/src/main/resources/application.properties +++ b/openvidu-server/src/main/resources/application.properties @@ -10,3 +10,4 @@ kms.uris=[\"ws://localhost:8888/kurento\"] openvidu.secret: MY_SECRET openvidu.publicurl: local +openvidu.cdr: false diff --git a/openvidu-server/src/main/resources/log4j.properties b/openvidu-server/src/main/resources/log4j.properties index e3f4e307..fd7ef3b4 100644 --- a/openvidu-server/src/main/resources/log4j.properties +++ b/openvidu-server/src/main/resources/log4j.properties @@ -1,4 +1,10 @@ -log4j.rootLogger=info, stdout +log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=[%p] %d [%.12t] %c (%M) - %m%n \ No newline at end of file +log4j.appender.stdout.layout.ConversionPattern=[%p] %d [%.12t] %c (%M) - %m%n + +log4j.logger.io.openvidu.server.cdr.CallDetailRecord=INFO, cdr +log4j.appender.cdr=org.apache.log4j.DailyRollingFileAppender +log4j.appender.cdr.File=log/CDR.log +log4j.appender.cdr.layout=org.apache.log4j.PatternLayout +log4j.appender.cdr.layout.ConversionPattern=%m\n \ No newline at end of file diff --git a/openvidu-server/src/test/java/io/openvidu/server/test/RoomProtocolTest.java b/openvidu-server/src/test/java/io/openvidu/server/test/RoomProtocolTest.java index 0604fd8b..c59fb0a4 100644 --- a/openvidu-server/src/test/java/io/openvidu/server/test/RoomProtocolTest.java +++ b/openvidu-server/src/test/java/io/openvidu/server/test/RoomProtocolTest.java @@ -60,7 +60,7 @@ import io.openvidu.client.internal.ProtocolElements; import io.openvidu.client.internal.Notification.Method; import io.openvidu.server.core.Participant; import io.openvidu.server.core.Token; -import io.openvidu.server.kurento.core.KurentoSessionHandler; +import io.openvidu.server.kurento.core.KurentoSessionEventsHandler; import io.openvidu.server.rpc.RpcConnection; import io.openvidu.server.rpc.RpcHandler; import io.openvidu.server.rpc.RpcNotificationService; @@ -83,7 +83,7 @@ public class RoomProtocolTest { @Mock private RpcHandler userControl; - private KurentoSessionHandler sessionHandler; + private KurentoSessionEventsHandler sessionHandler; private JsonRpcClientLocal localClient0; private OpenViduClient client0; diff --git a/openvidu-server/src/test/java/io/openvidu/server/test/core/RoomManagerTest.java b/openvidu-server/src/test/java/io/openvidu/server/test/core/RoomManagerTest.java index 83c78dda..b83ac702 100644 --- a/openvidu-server/src/test/java/io/openvidu/server/test/core/RoomManagerTest.java +++ b/openvidu-server/src/test/java/io/openvidu/server/test/core/RoomManagerTest.java @@ -92,7 +92,7 @@ import io.openvidu.server.core.SessionManager; import io.openvidu.server.core.Token; import io.openvidu.server.kurento.KurentoClientProvider; import io.openvidu.server.kurento.KurentoClientSessionInfo; -import io.openvidu.server.kurento.core.KurentoSessionHandler; +import io.openvidu.server.kurento.core.KurentoSessionEventsHandler; import io.openvidu.server.kurento.core.KurentoSessionManager; /** @@ -126,7 +126,7 @@ public class RoomManagerTest { @Mock private KurentoClientProvider kcProvider; @Mock - private KurentoSessionHandler roomHandler; + private KurentoSessionEventsHandler roomHandler; @Mock private KurentoClient kurentoClient; @@ -1351,7 +1351,7 @@ public class RoomManagerTest { private Set userJoinRoom(final String room, String user, String pid, boolean joinMustSucceed) { return userJoinRoom(room, user, pid, joinMustSucceed, true); - }*/ + } private Set userJoinRoom(final String room, String user, String pid, boolean joinMustSucceed) { @@ -1376,5 +1376,5 @@ public class RoomManagerTest { verify(kurentoClient, times(0)).createMediaPipeline(kurentoClientCaptor.capture()); return existingPeers; - } + }*/ }