openvidu-server: signalSent event

pull/559/head
pabloFuente 2020-11-15 01:15:52 +01:00
parent ce204c661d
commit e8dd9bd8f4
8 changed files with 126 additions and 56 deletions

View File

@ -21,6 +21,6 @@ public enum CDREventName {
sessionCreated, sessionDestroyed, participantJoined, participantLeft, webrtcConnectionCreated, sessionCreated, sessionDestroyed, participantJoined, participantLeft, webrtcConnectionCreated,
webrtcConnectionDestroyed, recordingStarted, recordingStopped, recordingStatusChanged, filterEventDispatched, webrtcConnectionDestroyed, recordingStarted, recordingStopped, recordingStatusChanged, filterEventDispatched,
mediaNodeStatusChanged, autoscaling signalSent, mediaNodeStatusChanged, autoscaling
} }

View File

@ -0,0 +1,52 @@
/*
* (C) Copyright 2017-2020 OpenVidu (https://openvidu.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package io.openvidu.server.cdr;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
public class CDREventSignal extends CDREvent {
private String from;
private String[] to;
private String type;
private String data;
public CDREventSignal(String sessionId, String from, String[] to, String type, String data) {
super(CDREventName.signalSent, sessionId, System.currentTimeMillis());
this.from = from;
this.to = to;
this.type = type;
this.data = data;
}
@Override
public JsonObject toJson() {
JsonObject json = super.toJson();
json.addProperty("from", this.from);
JsonArray toArray = new JsonArray();
for (String id : this.to) {
toArray.add(id);
}
json.add("to", toArray);
json.addProperty("type", this.type);
json.addProperty("data", this.data);
return json;
}
}

View File

@ -42,52 +42,8 @@ import io.openvidu.server.summary.SessionSummary;
import io.openvidu.server.webhook.CDRLoggerWebhook; import io.openvidu.server.webhook.CDRLoggerWebhook;
/** /**
* CDR logger to register all information of a Session. * CDR logger to register all information of a Session. Enabled by property
* Enabled by property 'OPENVIDU_CDR=true' * 'OPENVIDU_CDR=true'
*
* - 'sessionCreated': {sessionId, timestamp}
* - 'sessionDestroyed': {sessionId, timestamp, startTime, duration, reason}
* - 'participantJoined': {sessionId, timestamp, participantId, location, platform}
* - 'participantLeft': {sessionId, timestamp, participantId, startTime, duration, reason}
* - 'webrtcConnectionCreated' {sessionId, timestamp, participantId, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate]}
* - 'webrtcConnectionDestroyed' {sessionId, timestamp, participantId, startTime, duration, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate], reason}
* - 'recordingStarted' {sessionId, timestamp, id, name, hasAudio, hasVideo, resolution, recordingLayout, size}
* - 'recordingStopped' {sessionId, timestamp, id, name, hasAudio, hasVideo, resolution, recordingLayout, size}
* - 'recordingStatusChanged' {sessionId, timestamp, id, name, hasAudio, hasVideo, resolution, recordingLayout, size, status}
* - 'filterEventDispatched' {sessionId, timestamp, participantId, streamId, filterType, eventType, data}
*
* PROPERTIES VALUES:
*
* - sessionId: string
* - timestamp: number
* - startTime: number
* - duration: number
* - participantId: string
* - connection: "INBOUND", "OUTBOUND"
* - receivingFrom: string
* - audioEnabled: boolean
* - videoEnabled: boolean
* - videoSource: "CAMERA", "SCREEN", "CUSTOM", "IPCAM"
* - videoFramerate: number
* - videoDimensions: string
* - id: string
* - name: string
* - hasAudio: boolean
* - hasVideo: boolean
* - resolution string
* - recordingLayout: string
* - size: number
* - status: string
* - webrtcConnectionDestroyed.reason: "unsubscribe", "unpublish", "disconnect", "networkDisconnect", "mediaServerDisconnect", "openviduServerStopped"
* - participantLeft.reason: "unsubscribe", "unpublish", "disconnect", "networkDisconnect", "mediaServerDisconnect", "openviduServerStopped"
* - sessionDestroyed.reason: "lastParticipantLeft", "mediaServerDisconnect", "openviduServerStopped"
* - recordingStopped.reason: "recordingStoppedByServer", "lastParticipantLeft", "sessionClosedByServer", "automaticStop", "mediaServerDisconnect", "openviduServerStopped"
*
* [OPTIONAL_PROPERTIES]:
* - receivingFrom: only if connection = "INBOUND"
* - videoSource: only if videoEnabled = true
* - videoFramerate: only if videoEnabled = true
* - videoDimensions: only if videoEnabled = true
* *
* @author Pablo Fuente (pablofuenteperez@gmail.com) * @author Pablo Fuente (pablofuenteperez@gmail.com)
*/ */
@ -228,6 +184,13 @@ public class CallDetailRecord {
this.log(new CDREventFilterEvent(sessionId, participantId, streamId, filterType, event)); this.log(new CDREventFilterEvent(sessionId, participantId, streamId, filterType, event));
} }
public void recordSignalSent(String sessionId, String from, String[] to, String type, String data) {
if (from != null) {
type = type.replaceFirst("^signal:", "");
}
this.log(new CDREventSignal(sessionId, from, to, type, data));
}
protected void log(CDREvent event) { protected void log(CDREvent event) {
this.loggers.forEach(logger -> { this.loggers.forEach(logger -> {

View File

@ -321,7 +321,7 @@ public class SessionEventsHandler {
} }
public void onSendMessage(Participant participant, JsonObject message, Set<Participant> participants, public void onSendMessage(Participant participant, JsonObject message, Set<Participant> participants,
Integer transactionId, OpenViduException error) { String sessionId, Integer transactionId, OpenViduException error) {
boolean isRpcCall = transactionId != null; boolean isRpcCall = transactionId != null;
if (isRpcCall) { if (isRpcCall) {
@ -332,16 +332,22 @@ public class SessionEventsHandler {
} }
} }
String from = null;
String type = null;
String data = null;
JsonObject params = new JsonObject(); JsonObject params = new JsonObject();
if (message.has("data")) { if (message.has("data")) {
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_DATA_PARAM, message.get("data").getAsString()); data = message.get("data").getAsString();
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_DATA_PARAM, data);
} }
if (message.has("type")) { if (message.has("type")) {
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_TYPE_PARAM, message.get("type").getAsString()); type = message.get("type").getAsString();
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_TYPE_PARAM, type);
} }
if (participant != null) { if (participant != null) {
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_FROM_PARAM, from = participant.getParticipantPublicId();
participant.getParticipantPublicId()); params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_FROM_PARAM, from);
} }
Set<String> toSet = new HashSet<String>(); Set<String> toSet = new HashSet<String>();
@ -360,6 +366,7 @@ public class SessionEventsHandler {
if (toSet.isEmpty()) { if (toSet.isEmpty()) {
for (Participant p : participants) { for (Participant p : participants) {
toSet.add(p.getParticipantPublicId());
rpcNotificationService.sendNotification(p.getParticipantPrivateId(), rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
ProtocolElements.PARTICIPANTSENDMESSAGE_METHOD, params); ProtocolElements.PARTICIPANTSENDMESSAGE_METHOD, params);
} }
@ -382,6 +389,8 @@ public class SessionEventsHandler {
if (isRpcCall) { if (isRpcCall) {
rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject()); rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject());
} }
CDR.recordSignalSent(sessionId, from, toSet.toArray(new String[toSet.size()]), type, data);
} }
public void onStreamPropertyChanged(Participant participant, Integer transactionId, Set<Participant> participants, public void onStreamPropertyChanged(Participant participant, Integer transactionId, Set<Participant> participants,

View File

@ -116,7 +116,7 @@ public abstract class SessionManager {
public void sendMessage(String message, String sessionId) { public void sendMessage(String message, String sessionId) {
try { try {
JsonObject messageJson = JsonParser.parseString(message).getAsJsonObject(); JsonObject messageJson = JsonParser.parseString(message).getAsJsonObject();
sessionEventsHandler.onSendMessage(null, messageJson, getParticipants(sessionId), null, null); sessionEventsHandler.onSendMessage(null, messageJson, getParticipants(sessionId), sessionId, null, null);
} catch (JsonSyntaxException | IllegalStateException e) { } catch (JsonSyntaxException | IllegalStateException e) {
throw new OpenViduException(Code.SIGNAL_FORMAT_INVALID_ERROR_CODE, throw new OpenViduException(Code.SIGNAL_FORMAT_INVALID_ERROR_CODE,
"Provided signal object '" + message + "' has not a valid JSON format"); "Provided signal object '" + message + "' has not a valid JSON format");
@ -127,7 +127,7 @@ public abstract class SessionManager {
try { try {
JsonObject messageJson = JsonParser.parseString(message).getAsJsonObject(); JsonObject messageJson = JsonParser.parseString(message).getAsJsonObject();
sessionEventsHandler.onSendMessage(participant, messageJson, getParticipants(participant.getSessionId()), sessionEventsHandler.onSendMessage(participant, messageJson, getParticipants(participant.getSessionId()),
transactionId, null); participant.getSessionId(), transactionId, null);
} catch (JsonSyntaxException | IllegalStateException e) { } catch (JsonSyntaxException | IllegalStateException e) {
throw new OpenViduException(Code.SIGNAL_FORMAT_INVALID_ERROR_CODE, throw new OpenViduException(Code.SIGNAL_FORMAT_INVALID_ERROR_CODE,
"Provided signal object '" + message + "' has not a valid JSON format"); "Provided signal object '" + message + "' has not a valid JSON format");

View File

@ -24,7 +24,7 @@ OPENVIDU_CDR_PATH=/opt/openvidu/cdr
OPENVIDU_WEBHOOK=false OPENVIDU_WEBHOOK=false
OPENVIDU_WEBHOOK_ENDPOINT= OPENVIDU_WEBHOOK_ENDPOINT=
OPENVIDU_WEBHOOK_HEADERS=[] OPENVIDU_WEBHOOK_HEADERS=[]
OPENVIDU_WEBHOOK_EVENTS=["sessionCreated","sessionDestroyed","participantJoined","participantLeft","webrtcConnectionCreated","webrtcConnectionDestroyed","recordingStatusChanged","filterEventDispatched","mediaNodeStatusChanged","autoscaling"] OPENVIDU_WEBHOOK_EVENTS=["sessionCreated","sessionDestroyed","participantJoined","participantLeft","webrtcConnectionCreated","webrtcConnectionDestroyed","recordingStatusChanged","filterEventDispatched","signalSent","mediaNodeStatusChanged","autoscaling"]
OPENVIDU_RECORDING=false OPENVIDU_RECORDING=false
OPENVIDU_RECORDING_DEBUG=false OPENVIDU_RECORDING_DEBUG=false

View File

@ -1,9 +1,11 @@
node('container') { node('container') {
sh 'docker rm -f e2e chrome firefox opera || true' sh 'docker rm -f e2e chrome firefox opera || true'
sh 'rm -rf /opt/openvidu/* || true' sh 'rm -rf /opt/openvidu/* || true'
sh 'wget https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/barcode.y4m -P /opt/openvidu' sh 'wget https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/barcode.y4m -P /opt/openvidu'
sh 'wget https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/fakeaudio.wav -P /opt/openvidu' sh 'wget https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/fakeaudio.wav -P /opt/openvidu'
sh 'wget --directory-prefix=/opt/openvidu/test-layouts/layout1 https://raw.githubusercontent.com/OpenVidu/openvidu/master/openvidu-test-e2e/docker/my-custom-layout/index.html' sh 'wget --directory-prefix=/opt/openvidu/test-layouts/layout1 https://raw.githubusercontent.com/OpenVidu/openvidu/master/openvidu-test-e2e/docker/my-custom-layout/index.html'
docker.image('openvidu/openvidu-test-e2e:$DISTRO').pull() docker.image('openvidu/openvidu-test-e2e:$DISTRO').pull()
docker.image('selenium/standalone-chrome:latest').pull() docker.image('selenium/standalone-chrome:latest').pull()
docker.image('selenium/standalone-firefox:latest').pull() docker.image('selenium/standalone-firefox:latest').pull()

View File

@ -48,6 +48,7 @@ import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.ExpectedConditions;
import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.google.gson.JsonArray;
import com.google.gson.JsonNull; import com.google.gson.JsonNull;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
@ -3217,6 +3218,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
event = CustomWebhook.waitForEvent("webrtcConnectionCreated", 2); event = CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
Assert.assertEquals("Wrong number of properties in event 'webrtcConnectionCreated'", 10 + 1, Assert.assertEquals("Wrong number of properties in event 'webrtcConnectionCreated'", 10 + 1,
event.keySet().size()); event.keySet().size());
String connectionId1 = event.get("participantId").getAsString();
event = CustomWebhook.waitForEvent("recordingStatusChanged", 10); event = CustomWebhook.waitForEvent("recordingStatusChanged", 10);
Assert.assertEquals("Wrong number of properties in event 'recordingStatusChanged'", 11 + 1, Assert.assertEquals("Wrong number of properties in event 'recordingStatusChanged'", 11 + 1,
@ -3258,11 +3260,53 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
user.getDriver().findElement(By.id("add-user-btn")).click(); user.getDriver().findElement(By.id("add-user-btn")).click();
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .join-btn")).click(); user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .join-btn")).click();
CustomWebhook.waitForEvent("participantJoined", 2); event = CustomWebhook.waitForEvent("participantJoined", 2);
CustomWebhook.waitForEvent("webrtcConnectionCreated", 2); CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
CustomWebhook.waitForEvent("webrtcConnectionCreated", 2); CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
CustomWebhook.waitForEvent("webrtcConnectionCreated", 2); CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
String connectionId2 = event.get("participantId").getAsString();
// signalSent from client
long timestamp = System.currentTimeMillis();
user.getDriver().findElement(By.cssSelector(("#openvidu-instance-0 .message-btn"))).click();
user.getEventManager().waitUntilEventReaches("signal:chat", 2);
event = CustomWebhook.waitForEvent("signalSent", 1);
Assert.assertEquals("Wrong number of properties in event 'signalSent'", 6 + 1, event.keySet().size());
Assert.assertEquals("Wrong sessionId in webhook event", "TestSession",
event.get("sessionId").getAsString());
Assert.assertTrue("Wrong timestamp in webhook event", event.get("timestamp").getAsLong() > timestamp);
Assert.assertEquals("Wrong from in webhook event", connectionId1, event.get("from").getAsString());
Assert.assertEquals("Wrong type in webhook event", "chat", event.get("type").getAsString());
Assert.assertTrue("Wrong data in webhook event", !event.get("data").getAsString().isEmpty());
Assert.assertEquals("Wrong event name in webhook event", "signalSent", event.get("event").getAsString());
JsonArray toArray = event.get("to").getAsJsonArray();
Assert.assertEquals("Wrong to array size", 2, toArray.size());
Assert.assertTrue("Wrong to array content in webhook event",
toArray.contains(JsonParser.parseString(connectionId1)));
Assert.assertTrue("Wrong to array content in webhook event",
toArray.contains(JsonParser.parseString(connectionId2)));
// signalSent from server
CustomHttpClient restClient = new CustomHttpClient(OPENVIDU_URL, "OPENVIDUAPP", OPENVIDU_SECRET);
restClient.rest(HttpMethod.POST, "/openvidu/api/signal",
"{'session':'TestSession','type':'chat','to':['" + connectionId1 + "'],'data':'SERVER_DATA'}",
HttpStatus.SC_OK);
user.getEventManager().waitUntilEventReaches("signal:chat", 3);
event = CustomWebhook.waitForEvent("signalSent", 1);
Assert.assertEquals("Wrong number of properties in event 'signalSent'", 6 + 1, event.keySet().size());
Assert.assertEquals("Wrong sessionId in webhook event", "TestSession",
event.get("sessionId").getAsString());
Assert.assertTrue("Wrong timestamp in webhook event", event.get("timestamp").getAsLong() > timestamp);
Assert.assertTrue("Wrong from in webhook event", event.get("from").isJsonNull());
Assert.assertEquals("Wrong type in webhook event", "chat", event.get("type").getAsString());
Assert.assertEquals("Wrong data in webhook event", "SERVER_DATA", event.get("data").getAsString());
Assert.assertEquals("Wrong event name in webhook event", "signalSent", event.get("event").getAsString());
toArray = event.get("to").getAsJsonArray();
Assert.assertEquals("Wrong to array size", 1, toArray.size());
Assert.assertTrue("Wrong to array content in webhook event",
toArray.contains(JsonParser.parseString(connectionId1)));
user.getDriver().findElement(By.id("session-api-btn-0")).click(); user.getDriver().findElement(By.id("session-api-btn-0")).click();
Thread.sleep(1000); Thread.sleep(1000);
user.getDriver().findElement(By.id("close-session-btn")).click(); user.getDriver().findElement(By.id("close-session-btn")).click();