mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server: filters support
parent
ccd8d7a8b9
commit
c6f80c153a
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
package io.openvidu.server.cdr;
|
package io.openvidu.server.cdr;
|
||||||
|
|
||||||
import org.json.simple.JSONObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.java.client.RecordingLayout;
|
import io.openvidu.java.client.RecordingLayout;
|
||||||
import io.openvidu.server.core.MediaOptions;
|
import io.openvidu.server.core.MediaOptions;
|
||||||
|
@ -45,12 +45,14 @@ public class CDREvent implements Comparable<CDREvent> {
|
||||||
private RecordingLayout recordingLayout;
|
private RecordingLayout recordingLayout;
|
||||||
|
|
||||||
public CDREvent(CDREventName eventName, CDREvent event) {
|
public CDREvent(CDREventName eventName, CDREvent event) {
|
||||||
this(eventName, event.participant, event.sessionId, event.mediaOptions, event.receivingFrom, event.startTime, event.reason);
|
this(eventName, event.participant, event.sessionId, event.mediaOptions, event.receivingFrom, event.startTime,
|
||||||
|
event.reason);
|
||||||
this.duration = (int) (this.timeStamp - this.startTime / 1000);
|
this.duration = (int) (this.timeStamp - this.startTime / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CDREvent(CDREventName eventName, CDREvent event, String reason) {
|
public CDREvent(CDREventName eventName, CDREvent event, String reason) {
|
||||||
this(eventName, event.participant, event.sessionId, event.mediaOptions, event.receivingFrom, event.startTime, reason);
|
this(eventName, event.participant, event.sessionId, event.mediaOptions, event.receivingFrom, event.startTime,
|
||||||
|
reason);
|
||||||
this.duration = (int) (this.timeStamp - this.startTime / 1000);
|
this.duration = (int) (this.timeStamp - this.startTime / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,60 +114,59 @@ public class CDREvent implements Comparable<CDREvent> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
JSONObject json = new JSONObject();
|
JsonObject json = new JsonObject();
|
||||||
json.put("sessionId", this.sessionId);
|
json.addProperty("sessionId", this.sessionId);
|
||||||
json.put("timestamp", this.timeStamp);
|
json.addProperty("timestamp", this.timeStamp);
|
||||||
|
|
||||||
if (this.participant != null) {
|
if (this.participant != null) {
|
||||||
json.put("participantId", this.participant.getParticipantPublicId());
|
json.addProperty("participantId", this.participant.getParticipantPublicId());
|
||||||
}
|
}
|
||||||
if (this.mediaOptions != null) {
|
if (this.mediaOptions != null) {
|
||||||
json.put("connection", this.receivingFrom != null ? "INBOUND" : "OUTBOUND");
|
json.addProperty("connection", this.receivingFrom != null ? "INBOUND" : "OUTBOUND");
|
||||||
json.put("audioEnabled", this.mediaOptions.hasAudio());
|
json.addProperty("audioEnabled", this.mediaOptions.hasAudio());
|
||||||
json.put("videoEnabled", this.mediaOptions.hasVideo());
|
json.addProperty("videoEnabled", this.mediaOptions.hasVideo());
|
||||||
if (this.mediaOptions.hasVideo()) {
|
if (this.mediaOptions.hasVideo()) {
|
||||||
json.put("videoSource", this.mediaOptions.getTypeOfVideo());
|
json.addProperty("videoSource", this.mediaOptions.getTypeOfVideo());
|
||||||
json.put("videoFramerate", this.mediaOptions.getFrameRate());
|
json.addProperty("videoFramerate", this.mediaOptions.getFrameRate());
|
||||||
}
|
}
|
||||||
if (this.receivingFrom != null) {
|
if (this.receivingFrom != null) {
|
||||||
json.put("receivingFrom", this.receivingFrom);
|
json.addProperty("receivingFrom", this.receivingFrom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.startTime != null && this.duration != null) {
|
if (this.startTime != null && this.duration != null) {
|
||||||
json.put("startTime", this.startTime);
|
json.addProperty("startTime", this.startTime);
|
||||||
json.put("endTime", this.timeStamp);
|
json.addProperty("endTime", this.timeStamp);
|
||||||
json.put("duration", (this.timeStamp - this.startTime) / 1000);
|
json.addProperty("duration", (this.timeStamp - this.startTime) / 1000);
|
||||||
} else if (this.duration != null) {
|
} else if (this.duration != null) {
|
||||||
json.put("duration", duration);
|
json.addProperty("duration", duration);
|
||||||
}
|
}
|
||||||
if (this.reason != null) {
|
if (this.reason != null) {
|
||||||
json.put("reason", this.reason);
|
json.addProperty("reason", this.reason);
|
||||||
}
|
}
|
||||||
if (this.id != null) {
|
if (this.id != null) {
|
||||||
json.put("id", this.id);
|
json.addProperty("id", this.id);
|
||||||
}
|
}
|
||||||
if (this.name != null) {
|
if (this.name != null) {
|
||||||
json.put("name", this.name);
|
json.addProperty("name", this.name);
|
||||||
}
|
}
|
||||||
if (this.size != null) {
|
if (this.size != null) {
|
||||||
json.put("size", this.size);
|
json.addProperty("size", this.size);
|
||||||
}
|
}
|
||||||
if (this.hasAudio != null) {
|
if (this.hasAudio != null) {
|
||||||
json.put("hasAudio", this.hasAudio);
|
json.addProperty("hasAudio", this.hasAudio);
|
||||||
}
|
}
|
||||||
if (this.hasVideo != null) {
|
if (this.hasVideo != null) {
|
||||||
json.put("hasVideo", this.hasVideo);
|
json.addProperty("hasVideo", this.hasVideo);
|
||||||
}
|
}
|
||||||
if (this.recordingLayout != null) {
|
if (this.recordingLayout != null) {
|
||||||
json.put("recordingLayout", this.recordingLayout.name());
|
json.addProperty("recordingLayout", this.recordingLayout.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject root = new JSONObject();
|
JsonObject root = new JsonObject();
|
||||||
root.put(this.eventName.name(), json);
|
root.add(this.eventName.name(), json);
|
||||||
|
|
||||||
return root.toJSONString();
|
return root.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
|
|
||||||
package io.openvidu.server.core;
|
package io.openvidu.server.core;
|
||||||
|
|
||||||
import org.json.simple.JSONObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import io.openvidu.server.kurento.KurentoFilter;
|
||||||
|
|
||||||
public class MediaOptions {
|
public class MediaOptions {
|
||||||
|
|
||||||
|
@ -28,9 +30,10 @@ public class MediaOptions {
|
||||||
protected String typeOfVideo;
|
protected String typeOfVideo;
|
||||||
protected Integer frameRate;
|
protected Integer frameRate;
|
||||||
protected String videoDimensions;
|
protected String videoDimensions;
|
||||||
|
protected KurentoFilter filter;
|
||||||
|
|
||||||
public MediaOptions(Boolean hasAudio, Boolean hasVideo, Boolean audioActive, Boolean videoActive,
|
public MediaOptions(Boolean hasAudio, Boolean hasVideo, Boolean audioActive, Boolean videoActive,
|
||||||
String typeOfVideo, Integer frameRate, String videoDimensions) {
|
String typeOfVideo, Integer frameRate, String videoDimensions, KurentoFilter filter) {
|
||||||
this.hasAudio = hasAudio;
|
this.hasAudio = hasAudio;
|
||||||
this.hasVideo = hasVideo;
|
this.hasVideo = hasVideo;
|
||||||
this.audioActive = audioActive;
|
this.audioActive = audioActive;
|
||||||
|
@ -38,6 +41,7 @@ public class MediaOptions {
|
||||||
this.typeOfVideo = typeOfVideo;
|
this.typeOfVideo = typeOfVideo;
|
||||||
this.frameRate = frameRate;
|
this.frameRate = frameRate;
|
||||||
this.videoDimensions = videoDimensions;
|
this.videoDimensions = videoDimensions;
|
||||||
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasAudio() {
|
public boolean hasAudio() {
|
||||||
|
@ -68,18 +72,31 @@ public class MediaOptions {
|
||||||
return this.videoDimensions;
|
return this.videoDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
public KurentoFilter getFilter() {
|
||||||
public JSONObject toJSON() {
|
return this.filter;
|
||||||
JSONObject json = new JSONObject();
|
}
|
||||||
json.put("hasAudio", this.hasAudio);
|
|
||||||
|
public void setFilter(KurentoFilter filter) {
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonObject toJson() {
|
||||||
|
JsonObject json = new JsonObject();
|
||||||
|
json.addProperty("hasAudio", this.hasAudio);
|
||||||
if (hasAudio)
|
if (hasAudio)
|
||||||
json.put("audioActive", this.audioActive);
|
json.addProperty("audioActive", this.audioActive);
|
||||||
json.put("hasVideo", this.hasVideo);
|
json.addProperty("hasVideo", this.hasVideo);
|
||||||
if (hasVideo) {
|
if (hasVideo) {
|
||||||
json.put("videoActive", this.videoActive);
|
json.addProperty("videoActive", this.videoActive);
|
||||||
json.put("typeOfVideo", this.typeOfVideo);
|
json.addProperty("typeOfVideo", this.typeOfVideo);
|
||||||
json.put("frameRate", this.frameRate);
|
json.addProperty("frameRate", this.frameRate);
|
||||||
json.put("videoDimensions", this.videoDimensions);
|
json.addProperty("videoDimensions", this.videoDimensions);
|
||||||
|
}
|
||||||
|
json.add("filter", this.filter != null ? this.filter.toJson() : new JsonObject());
|
||||||
|
if (this.filter != null) {
|
||||||
|
((JsonObject) json.get("filter")).add("lastExecMethod",
|
||||||
|
this.filter.getLastExecMethod() != null ? this.filter.getLastExecMethod().toJson()
|
||||||
|
: new JsonObject());
|
||||||
}
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
package io.openvidu.server.core;
|
package io.openvidu.server.core;
|
||||||
|
|
||||||
import org.json.simple.JSONObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
public class Participant {
|
public class Participant {
|
||||||
|
|
||||||
|
@ -163,14 +163,13 @@ public class Participant {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
public JsonObject toJson() {
|
||||||
public JSONObject toJSON() {
|
JsonObject json = new JsonObject();
|
||||||
JSONObject json = new JSONObject();
|
json.addProperty("connectionId", this.participantPublicId);
|
||||||
json.put("connectionId", this.participantPublicId);
|
json.addProperty("token", this.token.getToken());
|
||||||
json.put("token", this.token.getToken());
|
json.addProperty("role", this.token.getRole().name());
|
||||||
json.put("role", this.token.getRole().name());
|
json.addProperty("serverData", this.serverMetadata);
|
||||||
json.put("serverData", this.serverMetadata);
|
json.addProperty("clientData", this.clientMetadata);
|
||||||
json.put("clientData", this.clientMetadata);
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ package io.openvidu.server.core;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.json.simple.JSONObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.java.client.SessionProperties;
|
import io.openvidu.java.client.SessionProperties;
|
||||||
|
|
||||||
|
@ -45,8 +45,8 @@ public interface Session {
|
||||||
|
|
||||||
int getActivePublishers();
|
int getActivePublishers();
|
||||||
|
|
||||||
JSONObject toJSON();
|
JsonObject toJson();
|
||||||
|
|
||||||
JSONObject withStatsToJSON();
|
JsonObject withStatsToJson();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import io.openvidu.client.internal.ProtocolElements;
|
||||||
import io.openvidu.server.cdr.CallDetailRecord;
|
import io.openvidu.server.cdr.CallDetailRecord;
|
||||||
import io.openvidu.server.config.InfoHandler;
|
import io.openvidu.server.config.InfoHandler;
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
|
import io.openvidu.server.kurento.KurentoFilter;
|
||||||
import io.openvidu.server.kurento.core.KurentoParticipant;
|
import io.openvidu.server.kurento.core.KurentoParticipant;
|
||||||
import io.openvidu.server.recording.Recording;
|
import io.openvidu.server.recording.Recording;
|
||||||
import io.openvidu.server.rpc.RpcNotificationService;
|
import io.openvidu.server.rpc.RpcNotificationService;
|
||||||
|
@ -113,6 +114,10 @@ public class SessionEventsHandler {
|
||||||
kParticipant.getPublisherMediaOptions().frameRate);
|
kParticipant.getPublisherMediaOptions().frameRate);
|
||||||
stream.addProperty(ProtocolElements.JOINROOM_PEERSTREAMVIDEODIMENSIONS_PARAM,
|
stream.addProperty(ProtocolElements.JOINROOM_PEERSTREAMVIDEODIMENSIONS_PARAM,
|
||||||
kParticipant.getPublisherMediaOptions().videoDimensions);
|
kParticipant.getPublisherMediaOptions().videoDimensions);
|
||||||
|
JsonElement filter = kParticipant.getPublisherMediaOptions().getFilter() != null
|
||||||
|
? kParticipant.getPublisherMediaOptions().getFilter().toJson()
|
||||||
|
: new JsonObject();
|
||||||
|
stream.add(ProtocolElements.JOINROOM_PEERSTREAMFILTER_PARAM, filter);
|
||||||
|
|
||||||
JsonArray streamsArray = new JsonArray();
|
JsonArray streamsArray = new JsonArray();
|
||||||
streamsArray.add(stream);
|
streamsArray.add(stream);
|
||||||
|
@ -199,6 +204,8 @@ public class SessionEventsHandler {
|
||||||
stream.addProperty(ProtocolElements.PARTICIPANTPUBLISHED_TYPEOFVIDEO_PARAM, mediaOptions.typeOfVideo);
|
stream.addProperty(ProtocolElements.PARTICIPANTPUBLISHED_TYPEOFVIDEO_PARAM, mediaOptions.typeOfVideo);
|
||||||
stream.addProperty(ProtocolElements.PARTICIPANTPUBLISHED_FRAMERATE_PARAM, mediaOptions.frameRate);
|
stream.addProperty(ProtocolElements.PARTICIPANTPUBLISHED_FRAMERATE_PARAM, mediaOptions.frameRate);
|
||||||
stream.addProperty(ProtocolElements.PARTICIPANTPUBLISHED_VIDEODIMENSIONS_PARAM, mediaOptions.videoDimensions);
|
stream.addProperty(ProtocolElements.PARTICIPANTPUBLISHED_VIDEODIMENSIONS_PARAM, mediaOptions.videoDimensions);
|
||||||
|
JsonElement filter = mediaOptions.getFilter() != null ? mediaOptions.getFilter().toJson() : new JsonObject();
|
||||||
|
stream.add(ProtocolElements.JOINROOM_PEERSTREAMFILTER_PARAM, filter);
|
||||||
|
|
||||||
JsonArray streamsArray = new JsonArray();
|
JsonArray streamsArray = new JsonArray();
|
||||||
streamsArray.add(stream);
|
streamsArray.add(stream);
|
||||||
|
@ -234,6 +241,7 @@ public class SessionEventsHandler {
|
||||||
|
|
||||||
for (Participant p : participants) {
|
for (Participant p : participants) {
|
||||||
if (p.getParticipantPrivateId().equals(participant.getParticipantPrivateId())) {
|
if (p.getParticipantPrivateId().equals(participant.getParticipantPrivateId())) {
|
||||||
|
// Send response to the affected participant
|
||||||
if (!isRpcFromOwner) {
|
if (!isRpcFromOwner) {
|
||||||
rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
|
rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
|
||||||
ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD, params);
|
ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD, params);
|
||||||
|
@ -247,6 +255,8 @@ public class SessionEventsHandler {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
|
// Send response to every other user in the session different than the affected
|
||||||
|
// participant
|
||||||
rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
|
rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
|
||||||
ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD, params);
|
ProtocolElements.PARTICIPANTUNPUBLISHED_METHOD, params);
|
||||||
}
|
}
|
||||||
|
@ -440,6 +450,63 @@ public class SessionEventsHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onFilterChanged(Participant participant, Participant moderator, Integer transactionId,
|
||||||
|
Set<Participant> participants, String streamId, KurentoFilter filter, OpenViduException error,
|
||||||
|
String reason) {
|
||||||
|
boolean isRpcFromModerator = transactionId != null && moderator != null;
|
||||||
|
boolean isRpcFromOwner = transactionId != null && moderator == null;
|
||||||
|
|
||||||
|
if (isRpcFromModerator) {
|
||||||
|
if (error != null) {
|
||||||
|
rpcNotificationService.sendErrorResponse(moderator.getParticipantPrivateId(), transactionId, null,
|
||||||
|
error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject params = new JsonObject();
|
||||||
|
params.addProperty(ProtocolElements.STREAMPROPERTYCHANGED_CONNECTIONID_PARAM,
|
||||||
|
participant.getParticipantPublicId());
|
||||||
|
params.addProperty(ProtocolElements.STREAMPROPERTYCHANGED_STREAMID_PARAM, streamId);
|
||||||
|
params.addProperty(ProtocolElements.STREAMPROPERTYCHANGED_PROPERTY_PARAM, "filter");
|
||||||
|
JsonObject filterJson = new JsonObject();
|
||||||
|
if (filter != null) {
|
||||||
|
filterJson.addProperty(ProtocolElements.FILTER_TYPE_PARAM, filter.getType());
|
||||||
|
filterJson.add(ProtocolElements.FILTER_OPTIONS_PARAM, filter.getOptions());
|
||||||
|
if (filter.getLastExecMethod() != null) {
|
||||||
|
filterJson.add(ProtocolElements.EXECFILTERMETHOD_LASTEXECMETHOD_PARAM,
|
||||||
|
filter.getLastExecMethod().toJson());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params.add(ProtocolElements.STREAMPROPERTYCHANGED_NEWVALUE_PARAM, filterJson);
|
||||||
|
params.addProperty(ProtocolElements.STREAMPROPERTYCHANGED_REASON_PARAM, reason);
|
||||||
|
|
||||||
|
for (Participant p : participants) {
|
||||||
|
if (p.getParticipantPrivateId().equals(participant.getParticipantPrivateId())) {
|
||||||
|
// Send response to the affected participant
|
||||||
|
if (!isRpcFromOwner) {
|
||||||
|
rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
|
||||||
|
ProtocolElements.STREAMPROPERTYCHANGED_METHOD, params);
|
||||||
|
} else {
|
||||||
|
if (error != null) {
|
||||||
|
rpcNotificationService.sendErrorResponse(p.getParticipantPrivateId(), transactionId, null,
|
||||||
|
error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rpcNotificationService.sendResponse(p.getParticipantPrivateId(), transactionId, new JsonObject());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Send response to every other user in the session different than the affected
|
||||||
|
// participant
|
||||||
|
if (error == null) {
|
||||||
|
rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
|
||||||
|
ProtocolElements.STREAMPROPERTYCHANGED_METHOD, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void closeRpcSession(String participantPrivateId) {
|
public void closeRpcSession(String participantPrivateId) {
|
||||||
this.rpcNotificationService.closeRpcSession(participantPrivateId);
|
this.rpcNotificationService.closeRpcSession(participantPrivateId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import io.openvidu.server.cdr.CallDetailRecord;
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
import io.openvidu.server.coturn.CoturnCredentialsService;
|
import io.openvidu.server.coturn.CoturnCredentialsService;
|
||||||
import io.openvidu.server.coturn.TurnCredentials;
|
import io.openvidu.server.coturn.TurnCredentials;
|
||||||
|
import io.openvidu.server.kurento.core.KurentoTokenOptions;
|
||||||
import io.openvidu.server.recording.ComposedRecordingService;
|
import io.openvidu.server.recording.ComposedRecordingService;
|
||||||
|
|
||||||
public abstract class SessionManager {
|
public abstract class SessionManager {
|
||||||
|
@ -79,7 +80,8 @@ public abstract class SessionManager {
|
||||||
|
|
||||||
public abstract void publishVideo(Participant participant, MediaOptions mediaOptions, Integer transactionId);
|
public abstract void publishVideo(Participant participant, MediaOptions mediaOptions, Integer transactionId);
|
||||||
|
|
||||||
public abstract void unpublishVideo(Participant participant, Participant moderator, Integer transactionId, String reason);
|
public abstract void unpublishVideo(Participant participant, Participant moderator, Integer transactionId,
|
||||||
|
String reason);
|
||||||
|
|
||||||
public abstract void subscribe(Participant participant, String senderName, String sdpOffer, Integer transactionId);
|
public abstract void subscribe(Participant participant, String senderName, String sdpOffer, Integer transactionId);
|
||||||
|
|
||||||
|
@ -93,11 +95,21 @@ public abstract class SessionManager {
|
||||||
public abstract void onIceCandidate(Participant participant, String endpointName, String candidate,
|
public abstract void onIceCandidate(Participant participant, String endpointName, String candidate,
|
||||||
int sdpMLineIndex, String sdpMid, Integer transactionId);
|
int sdpMLineIndex, String sdpMid, Integer transactionId);
|
||||||
|
|
||||||
public abstract boolean unpublishStream(Session session, String streamId, Participant moderator, Integer transactionId, String reason);
|
public abstract boolean unpublishStream(Session session, String streamId, Participant moderator,
|
||||||
|
Integer transactionId, String reason);
|
||||||
|
|
||||||
public abstract void evictParticipant(Participant evictedParticipant, Participant moderator, Integer transactionId,
|
public abstract void evictParticipant(Participant evictedParticipant, Participant moderator, Integer transactionId,
|
||||||
String reason);
|
String reason);
|
||||||
|
|
||||||
|
public abstract void applyFilter(Session session, String streamId, String filterType, JsonObject filterOptions,
|
||||||
|
Participant moderator, Integer transactionId, String reason);
|
||||||
|
|
||||||
|
public abstract void execFilterMethod(Session session, String streamId, String filterMethod, JsonObject filterParams,
|
||||||
|
Participant moderator, Integer transactionId, String reason);
|
||||||
|
|
||||||
|
public abstract void removeFilter(Session session, String streamId, Participant moderator, Integer transactionId,
|
||||||
|
String reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Session given its id
|
* Returns a Session given its id
|
||||||
*
|
*
|
||||||
|
@ -200,7 +212,8 @@ public abstract class SessionManager {
|
||||||
showTokens();
|
showTokens();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String newToken(String sessionId, ParticipantRole role, String serverMetadata) throws OpenViduException {
|
public String newToken(String sessionId, ParticipantRole role, String serverMetadata,
|
||||||
|
KurentoTokenOptions kurentoTokenOptions) throws OpenViduException {
|
||||||
|
|
||||||
ConcurrentHashMap<String, Token> map = this.sessionidTokenTokenobj.putIfAbsent(sessionId,
|
ConcurrentHashMap<String, Token> map = this.sessionidTokenTokenobj.putIfAbsent(sessionId,
|
||||||
new ConcurrentHashMap<>());
|
new ConcurrentHashMap<>());
|
||||||
|
@ -224,7 +237,7 @@ public abstract class SessionManager {
|
||||||
token += "&turnCredential=" + turnCredentials.getCredential();
|
token += "&turnCredential=" + turnCredentials.getCredential();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token t = new Token(token, role, serverMetadata, turnCredentials);
|
Token t = new Token(token, role, serverMetadata, turnCredentials, kurentoTokenOptions);
|
||||||
|
|
||||||
map.putIfAbsent(token, t);
|
map.putIfAbsent(token, t);
|
||||||
showTokens();
|
showTokens();
|
||||||
|
@ -252,7 +265,8 @@ public abstract class SessionManager {
|
||||||
new Token(token, ParticipantRole.PUBLISHER, "",
|
new Token(token, ParticipantRole.PUBLISHER, "",
|
||||||
this.coturnCredentialsService.isCoturnAvailable()
|
this.coturnCredentialsService.isCoturnAvailable()
|
||||||
? this.coturnCredentialsService.createUser()
|
? this.coturnCredentialsService.createUser()
|
||||||
: null));
|
: null,
|
||||||
|
null));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
|
|
||||||
package io.openvidu.server.core;
|
package io.openvidu.server.core;
|
||||||
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
import io.openvidu.server.coturn.TurnCredentials;
|
import io.openvidu.server.coturn.TurnCredentials;
|
||||||
|
import io.openvidu.server.kurento.core.KurentoTokenOptions;
|
||||||
|
|
||||||
public class Token {
|
public class Token {
|
||||||
|
|
||||||
|
@ -28,15 +27,19 @@ public class Token {
|
||||||
private String serverMetadata = "";
|
private String serverMetadata = "";
|
||||||
private TurnCredentials turnCredentials;
|
private TurnCredentials turnCredentials;
|
||||||
|
|
||||||
|
private KurentoTokenOptions kurentoTokenOptions;
|
||||||
|
|
||||||
public Token(String token) {
|
public Token(String token) {
|
||||||
this.token = token;
|
this.token = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Token(String token, ParticipantRole role, String serverMetadata, TurnCredentials turnCredentials) {
|
public Token(String token, ParticipantRole role, String serverMetadata, TurnCredentials turnCredentials,
|
||||||
|
KurentoTokenOptions kurentoTokenOptions) {
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.role = role;
|
this.role = role;
|
||||||
this.serverMetadata = serverMetadata;
|
this.serverMetadata = serverMetadata;
|
||||||
this.turnCredentials = turnCredentials;
|
this.turnCredentials = turnCredentials;
|
||||||
|
this.kurentoTokenOptions = kurentoTokenOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getToken() {
|
public String getToken() {
|
||||||
|
@ -55,6 +58,10 @@ public class Token {
|
||||||
return turnCredentials;
|
return turnCredentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KurentoTokenOptions getKurentoTokenOptions() {
|
||||||
|
return kurentoTokenOptions;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (this.role != null)
|
if (this.role != null)
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2017-2018 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.kurento;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class KurentoFilter {
|
||||||
|
|
||||||
|
public class KurentoFilterMethod {
|
||||||
|
|
||||||
|
String method;
|
||||||
|
JsonObject params;
|
||||||
|
|
||||||
|
protected KurentoFilterMethod(String method, JsonObject params) {
|
||||||
|
this.method = method;
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonObject toJson() {
|
||||||
|
JsonObject json = new JsonObject();
|
||||||
|
json.addProperty("method", lastExecMethod.method);
|
||||||
|
json.add("params", lastExecMethod.params);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String type;
|
||||||
|
JsonObject options;
|
||||||
|
KurentoFilterMethod lastExecMethod;
|
||||||
|
|
||||||
|
public KurentoFilter(String type, JsonObject options) {
|
||||||
|
this.type = type;
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KurentoFilter(String type, JsonObject options, String method, JsonObject params) {
|
||||||
|
this.type = type;
|
||||||
|
this.options = options;
|
||||||
|
this.lastExecMethod = new KurentoFilterMethod(method, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public KurentoFilter(JsonElement json) {
|
||||||
|
JsonObject jsonObject = json.getAsJsonObject();
|
||||||
|
this.type = jsonObject.get("type").getAsString();
|
||||||
|
this.options = jsonObject.get("options").getAsJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonObject getOptions() {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KurentoFilterMethod getLastExecMethod() {
|
||||||
|
return this.lastExecMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonObject toJson() {
|
||||||
|
JsonObject json = new JsonObject();
|
||||||
|
json.addProperty("type", type);
|
||||||
|
json.add("options", options);
|
||||||
|
json.add("lastExecMethod", this.lastExecMethod != null ? this.lastExecMethod.toJson() : new JsonObject());
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ import org.kurento.client.MediaElement;
|
||||||
import org.kurento.client.MediaType;
|
import org.kurento.client.MediaType;
|
||||||
|
|
||||||
import io.openvidu.server.core.MediaOptions;
|
import io.openvidu.server.core.MediaOptions;
|
||||||
|
import io.openvidu.server.kurento.KurentoFilter;
|
||||||
|
|
||||||
public class KurentoMediaOptions extends MediaOptions {
|
public class KurentoMediaOptions extends MediaOptions {
|
||||||
|
|
||||||
|
@ -33,9 +34,9 @@ public class KurentoMediaOptions extends MediaOptions {
|
||||||
|
|
||||||
public KurentoMediaOptions(boolean isOffer, String sdpOffer, MediaElement loopbackAlternativeSrc,
|
public KurentoMediaOptions(boolean isOffer, String sdpOffer, MediaElement loopbackAlternativeSrc,
|
||||||
MediaType loopbackConnectionType, Boolean hasAudio, Boolean hasVideo, Boolean audioActive,
|
MediaType loopbackConnectionType, Boolean hasAudio, Boolean hasVideo, Boolean audioActive,
|
||||||
Boolean videoActive, String typeOfVideo, Integer frameRate, String videoDimensions, boolean doLoopback,
|
Boolean videoActive, String typeOfVideo, Integer frameRate, String videoDimensions, KurentoFilter filter,
|
||||||
MediaElement... mediaElements) {
|
boolean doLoopback, MediaElement... mediaElements) {
|
||||||
super(hasAudio, hasVideo, audioActive, videoActive, typeOfVideo, frameRate, videoDimensions);
|
super(hasAudio, hasVideo, audioActive, videoActive, typeOfVideo, frameRate, videoDimensions, filter);
|
||||||
this.isOffer = isOffer;
|
this.isOffer = isOffer;
|
||||||
this.sdpOffer = sdpOffer;
|
this.sdpOffer = sdpOffer;
|
||||||
this.loopbackAlternativeSrc = loopbackAlternativeSrc;
|
this.loopbackAlternativeSrc = loopbackAlternativeSrc;
|
||||||
|
|
|
@ -26,11 +26,10 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.json.simple.JSONArray;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
import org.kurento.client.Continuation;
|
import org.kurento.client.Continuation;
|
||||||
import org.kurento.client.ErrorEvent;
|
import org.kurento.client.ErrorEvent;
|
||||||
import org.kurento.client.Filter;
|
import org.kurento.client.Filter;
|
||||||
|
import org.kurento.client.GenericMediaElement;
|
||||||
import org.kurento.client.IceCandidate;
|
import org.kurento.client.IceCandidate;
|
||||||
import org.kurento.client.MediaElement;
|
import org.kurento.client.MediaElement;
|
||||||
import org.kurento.client.MediaPipeline;
|
import org.kurento.client.MediaPipeline;
|
||||||
|
@ -40,6 +39,9 @@ import org.kurento.client.internal.server.KurentoServerException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.client.OpenViduException;
|
import io.openvidu.client.OpenViduException;
|
||||||
import io.openvidu.client.OpenViduException.Code;
|
import io.openvidu.client.OpenViduException.Code;
|
||||||
import io.openvidu.client.internal.ProtocolElements;
|
import io.openvidu.client.internal.ProtocolElements;
|
||||||
|
@ -115,7 +117,7 @@ public class KurentoParticipant extends Participant {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shapePublisherMedia(MediaElement element, MediaType type) {
|
public void shapePublisherMedia(GenericMediaElement element, MediaType type) {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
this.publisher.apply(element);
|
this.publisher.apply(element);
|
||||||
} else {
|
} else {
|
||||||
|
@ -127,38 +129,25 @@ public class KurentoParticipant extends Participant {
|
||||||
return filters.get(id);
|
return filters.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void addFilterElement(String id, Filter filter) {
|
/*
|
||||||
filters.put(id, filter);
|
* public synchronized void addFilterElement(String id, Filter filter) {
|
||||||
shapePublisherMedia(filter, null);
|
* filters.put(id, filter); shapePublisherMedia(filter, null); }
|
||||||
}
|
*
|
||||||
|
* public synchronized void disableFilterelement(String filterID, boolean
|
||||||
public synchronized void disableFilterelement(String filterID, boolean releaseElement) {
|
* releaseElement) { Filter filter = getFilterElement(filterID);
|
||||||
Filter filter = getFilterElement(filterID);
|
*
|
||||||
|
* if (filter != null) { try { publisher.revert(filter, releaseElement); } catch
|
||||||
if (filter != null) {
|
* (OpenViduException e) { // Ignore error } } }
|
||||||
try {
|
*
|
||||||
publisher.revert(filter, releaseElement);
|
* public synchronized void enableFilterelement(String filterID) { Filter filter
|
||||||
} catch (OpenViduException e) {
|
* = getFilterElement(filterID);
|
||||||
// Ignore error
|
*
|
||||||
}
|
* if (filter != null) { try { publisher.apply(filter); } catch
|
||||||
}
|
* (OpenViduException e) { // Ignore exception if element is already used } } }
|
||||||
}
|
*/
|
||||||
|
|
||||||
public synchronized void enableFilterelement(String filterID) {
|
|
||||||
Filter filter = getFilterElement(filterID);
|
|
||||||
|
|
||||||
if (filter != null) {
|
|
||||||
try {
|
|
||||||
publisher.apply(filter);
|
|
||||||
} catch (OpenViduException e) {
|
|
||||||
// Ignore exception if element is already used
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void removeFilterElement(String id) {
|
public synchronized void removeFilterElement(String id) {
|
||||||
Filter filter = getFilterElement(id);
|
Filter filter = getFilterElement(id);
|
||||||
|
|
||||||
filters.remove(id);
|
filters.remove(id);
|
||||||
if (filter != null) {
|
if (filter != null) {
|
||||||
publisher.revert(filter);
|
publisher.revert(filter);
|
||||||
|
@ -166,10 +155,11 @@ public class KurentoParticipant extends Participant {
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void releaseAllFilters() {
|
public synchronized void releaseAllFilters() {
|
||||||
|
|
||||||
// Check this, mutable array?
|
// Check this, mutable array?
|
||||||
|
|
||||||
filters.forEach((s, filter) -> removeFilterElement(s));
|
filters.forEach((s, filter) -> removeFilterElement(s));
|
||||||
|
if(this.publisher.getFilter() != null) {
|
||||||
|
this.publisher.revert(this.publisher.getFilter());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PublisherEndpoint getPublisher() {
|
public PublisherEndpoint getPublisher() {
|
||||||
|
@ -544,8 +534,9 @@ public class KurentoParticipant extends Participant {
|
||||||
* event.getPadName() + " | MEDIATYPE: " + event.getMediaType() +
|
* event.getPadName() + " | MEDIATYPE: " + event.getMediaType() +
|
||||||
* " | TIMESTAMP: " + System.currentTimeMillis();
|
* " | TIMESTAMP: " + System.currentTimeMillis();
|
||||||
*
|
*
|
||||||
* endpoint.flowOutMedia.put(event.getSource().getName() + "/" +
|
* endpoint.flowOutMedia. @SuppressWarnings("unchecked")
|
||||||
* event.getMediaType(), event.getSource());
|
* put(event.getSource().getName() + "/" + event.getMediaType(),
|
||||||
|
* event.getSource());
|
||||||
*
|
*
|
||||||
* String msg2;
|
* String msg2;
|
||||||
*
|
*
|
||||||
|
@ -661,35 +652,38 @@ public class KurentoParticipant extends Participant {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MediaPipeline getPipeline() {
|
||||||
|
return this.pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPublisherStreamId() {
|
public String getPublisherStreamId() {
|
||||||
return this.publisher.getEndpoint().getTag("name");
|
return this.publisher.getEndpoint().getTag("name");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject toJSON() {
|
public JsonObject toJson() {
|
||||||
return this.sharedJSON(MediaEndpoint::toJSON);
|
return this.sharedJson(MediaEndpoint::toJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject withStatsToJSON() {
|
public JsonObject withStatsToJson() {
|
||||||
return this.sharedJSON(MediaEndpoint::withStatsToJSON);
|
return this.sharedJson(MediaEndpoint::withStatsToJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
private JsonObject sharedJson(Function<MediaEndpoint, JsonObject> toJsonFunction) {
|
||||||
private JSONObject sharedJSON(Function<MediaEndpoint, JSONObject> toJsonFunction) {
|
JsonObject json = super.toJson();
|
||||||
JSONObject json = super.toJSON();
|
JsonArray publisherEnpoints = new JsonArray();
|
||||||
JSONArray publisherEnpoints = new JSONArray();
|
|
||||||
if (this.streaming && this.publisher.getEndpoint() != null) {
|
if (this.streaming && this.publisher.getEndpoint() != null) {
|
||||||
publisherEnpoints.add(toJsonFunction.apply(this.publisher));
|
publisherEnpoints.add(toJsonFunction.apply(this.publisher));
|
||||||
}
|
}
|
||||||
JSONArray subscriberEndpoints = new JSONArray();
|
JsonArray subscriberEndpoints = new JsonArray();
|
||||||
for (MediaEndpoint sub : this.subscribers.values()) {
|
for (MediaEndpoint sub : this.subscribers.values()) {
|
||||||
if (sub.getEndpoint() != null) {
|
if (sub.getEndpoint() != null) {
|
||||||
subscriberEndpoints.add(toJsonFunction.apply(sub));
|
subscriberEndpoints.add(toJsonFunction.apply(sub));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
json.put("publishers", publisherEnpoints);
|
json.add("publishers", publisherEnpoints);
|
||||||
json.put("subscribers", subscriberEndpoints);
|
json.add("subscribers", subscriberEndpoints);
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,6 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.json.simple.JSONArray;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
import org.kurento.client.Continuation;
|
import org.kurento.client.Continuation;
|
||||||
import org.kurento.client.ErrorEvent;
|
import org.kurento.client.ErrorEvent;
|
||||||
import org.kurento.client.EventListener;
|
import org.kurento.client.EventListener;
|
||||||
|
@ -37,6 +35,9 @@ import org.kurento.client.MediaPipeline;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.client.OpenViduException;
|
import io.openvidu.client.OpenViduException;
|
||||||
import io.openvidu.client.OpenViduException.Code;
|
import io.openvidu.client.OpenViduException.Code;
|
||||||
import io.openvidu.client.internal.ProtocolElements;
|
import io.openvidu.client.internal.ProtocolElements;
|
||||||
|
@ -361,35 +362,34 @@ public class KurentoSession implements Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject toJSON() {
|
public JsonObject toJson() {
|
||||||
return this.sharedJSON(KurentoParticipant::toJSON);
|
return this.sharedJson(KurentoParticipant::toJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject withStatsToJSON() {
|
public JsonObject withStatsToJson() {
|
||||||
return this.sharedJSON(KurentoParticipant::withStatsToJSON);
|
return this.sharedJson(KurentoParticipant::withStatsToJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
private JsonObject sharedJson(Function<KurentoParticipant, JsonObject> toJsonFunction) {
|
||||||
private JSONObject sharedJSON(Function<KurentoParticipant, JSONObject> toJsonFunction) {
|
JsonObject json = new JsonObject();
|
||||||
JSONObject json = new JSONObject();
|
json.addProperty("sessionId", this.sessionId);
|
||||||
json.put("sessionId", this.sessionId);
|
json.addProperty("mediaMode", this.sessionProperties.mediaMode().name());
|
||||||
json.put("mediaMode", this.sessionProperties.mediaMode().name());
|
json.addProperty("recordingMode", this.sessionProperties.recordingMode().name());
|
||||||
json.put("recordingMode", this.sessionProperties.recordingMode().name());
|
json.addProperty("defaultRecordingLayout", this.sessionProperties.defaultRecordingLayout().name());
|
||||||
json.put("defaultRecordingLayout", this.sessionProperties.defaultRecordingLayout().name());
|
|
||||||
if (RecordingLayout.CUSTOM.equals(this.sessionProperties.defaultRecordingLayout())) {
|
if (RecordingLayout.CUSTOM.equals(this.sessionProperties.defaultRecordingLayout())) {
|
||||||
json.put("defaultCustomLayout", this.sessionProperties.defaultCustomLayout());
|
json.addProperty("defaultCustomLayout", this.sessionProperties.defaultCustomLayout());
|
||||||
}
|
}
|
||||||
JSONObject connections = new JSONObject();
|
JsonObject connections = new JsonObject();
|
||||||
JSONArray participants = new JSONArray();
|
JsonArray participants = new JsonArray();
|
||||||
this.participants.values().forEach(p -> {
|
this.participants.values().forEach(p -> {
|
||||||
if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(p.getParticipantPublicId())) {
|
if (!ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(p.getParticipantPublicId())) {
|
||||||
participants.add(toJsonFunction.apply(p));
|
participants.add(toJsonFunction.apply(p));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connections.put("numberOfElements", participants.size());
|
connections.addProperty("numberOfElements", participants.size());
|
||||||
connections.put("content", participants);
|
connections.add("content", participants);
|
||||||
json.put("connections", connections);
|
json.add("connections", connections);
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,10 @@ import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.kurento.client.GenericMediaElement;
|
||||||
import org.kurento.client.IceCandidate;
|
import org.kurento.client.IceCandidate;
|
||||||
import org.kurento.client.KurentoClient;
|
import org.kurento.client.KurentoClient;
|
||||||
import org.kurento.client.MediaElement;
|
import org.kurento.jsonrpc.Props;
|
||||||
import org.kurento.jsonrpc.message.Request;
|
import org.kurento.jsonrpc.message.Request;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -49,9 +50,11 @@ import io.openvidu.server.core.Session;
|
||||||
import io.openvidu.server.core.SessionManager;
|
import io.openvidu.server.core.SessionManager;
|
||||||
import io.openvidu.server.kurento.KurentoClientProvider;
|
import io.openvidu.server.kurento.KurentoClientProvider;
|
||||||
import io.openvidu.server.kurento.KurentoClientSessionInfo;
|
import io.openvidu.server.kurento.KurentoClientSessionInfo;
|
||||||
|
import io.openvidu.server.kurento.KurentoFilter;
|
||||||
import io.openvidu.server.kurento.OpenViduKurentoClientSessionInfo;
|
import io.openvidu.server.kurento.OpenViduKurentoClientSessionInfo;
|
||||||
import io.openvidu.server.kurento.endpoint.SdpType;
|
import io.openvidu.server.kurento.endpoint.SdpType;
|
||||||
import io.openvidu.server.rpc.RpcHandler;
|
import io.openvidu.server.rpc.RpcHandler;
|
||||||
|
import io.openvidu.server.utils.JsonUtils;
|
||||||
|
|
||||||
public class KurentoSessionManager extends SessionManager {
|
public class KurentoSessionManager extends SessionManager {
|
||||||
|
|
||||||
|
@ -63,6 +66,8 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
@Autowired
|
@Autowired
|
||||||
private KurentoSessionEventsHandler kurentoSessionEventsHandler;
|
private KurentoSessionEventsHandler kurentoSessionEventsHandler;
|
||||||
|
|
||||||
|
private KurentoClient kurentoClient;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void joinRoom(Participant participant, String sessionId, Integer transactionId) {
|
public synchronized void joinRoom(Participant participant, String sessionId, Integer transactionId) {
|
||||||
Set<Participant> existingParticipants = null;
|
Set<Participant> existingParticipants = null;
|
||||||
|
@ -91,7 +96,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
log.warn("'{}' is trying to join session '{}' but it is closing", participant.getParticipantPublicId(),
|
log.warn("'{}' is trying to join session '{}' but it is closing", participant.getParticipantPublicId(),
|
||||||
sessionId);
|
sessionId);
|
||||||
throw new OpenViduException(Code.ROOM_CLOSED_ERROR_CODE, "'" + participant.getParticipantPublicId()
|
throw new OpenViduException(Code.ROOM_CLOSED_ERROR_CODE, "'" + participant.getParticipantPublicId()
|
||||||
+ "' is trying to join room '" + sessionId + "' but it is closing");
|
+ "' is trying to join session '" + sessionId + "' but it is closing");
|
||||||
}
|
}
|
||||||
existingParticipants = getParticipants(sessionId);
|
existingParticipants = getParticipants(sessionId);
|
||||||
session.join(participant);
|
session.join(participant);
|
||||||
|
@ -216,7 +221,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
String sdpAnswer = null;
|
String sdpAnswer = null;
|
||||||
|
|
||||||
KurentoMediaOptions kurentoOptions = (KurentoMediaOptions) mediaOptions;
|
KurentoMediaOptions kurentoOptions = (KurentoMediaOptions) mediaOptions;
|
||||||
KurentoParticipant kurentoParticipant = (KurentoParticipant) participant;
|
KurentoParticipant kParticipant = (KurentoParticipant) participant;
|
||||||
|
|
||||||
log.debug(
|
log.debug(
|
||||||
"Request [PUBLISH_MEDIA] isOffer={} sdp={} "
|
"Request [PUBLISH_MEDIA] isOffer={} sdp={} "
|
||||||
|
@ -226,15 +231,22 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
participant.getParticipantPublicId());
|
participant.getParticipantPublicId());
|
||||||
|
|
||||||
SdpType sdpType = kurentoOptions.isOffer ? SdpType.OFFER : SdpType.ANSWER;
|
SdpType sdpType = kurentoOptions.isOffer ? SdpType.OFFER : SdpType.ANSWER;
|
||||||
KurentoSession session = kurentoParticipant.getSession();
|
KurentoSession session = kParticipant.getSession();
|
||||||
|
|
||||||
kurentoParticipant.createPublishingEndpoint(mediaOptions);
|
kParticipant.createPublishingEndpoint(mediaOptions);
|
||||||
|
|
||||||
for (MediaElement elem : kurentoOptions.mediaElements) {
|
/*
|
||||||
kurentoParticipant.getPublisher().apply(elem);
|
* for (MediaElement elem : kurentoOptions.mediaElements) {
|
||||||
|
* kurentoParticipant.getPublisher().apply(elem); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
KurentoTokenOptions kurentoTokenOptions = participant.getToken().getKurentoTokenOptions();
|
||||||
|
if (kurentoOptions.getFilter() != null && kurentoTokenOptions != null
|
||||||
|
&& kurentoTokenOptions.isFilterAllowed(kurentoOptions.getFilter().getType())) {
|
||||||
|
this.applyFilterInPublisher(kParticipant, kurentoOptions.getFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
sdpAnswer = kurentoParticipant.publishToRoom(sdpType, kurentoOptions.sdpOffer, kurentoOptions.doLoopback,
|
sdpAnswer = kParticipant.publishToRoom(sdpType, kurentoOptions.sdpOffer, kurentoOptions.doLoopback,
|
||||||
kurentoOptions.loopbackAlternativeSrc, kurentoOptions.loopbackConnectionType);
|
kurentoOptions.loopbackAlternativeSrc, kurentoOptions.loopbackConnectionType);
|
||||||
|
|
||||||
if (sdpAnswer == null) {
|
if (sdpAnswer == null) {
|
||||||
|
@ -261,7 +273,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
|
|
||||||
session.newPublisher(participant);
|
session.newPublisher(participant);
|
||||||
|
|
||||||
participants = kurentoParticipant.getSession().getParticipants();
|
participants = kParticipant.getSession().getParticipants();
|
||||||
|
|
||||||
if (sdpAnswer != null) {
|
if (sdpAnswer != null) {
|
||||||
sessionEventsHandler.onPublishMedia(participant, participant.getPublisherStreamId(), session.getSessionId(),
|
sessionEventsHandler.onPublishMedia(participant, participant.getPublisherStreamId(), session.getSessionId(),
|
||||||
|
@ -277,6 +289,11 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
|
|
||||||
log.debug("Request [UNPUBLISH_MEDIA] ({})", participant.getParticipantPublicId());
|
log.debug("Request [UNPUBLISH_MEDIA] ({})", participant.getParticipantPublicId());
|
||||||
if (!participant.isStreaming()) {
|
if (!participant.isStreaming()) {
|
||||||
|
log.warn(
|
||||||
|
"PARTICIPANT {}: Requesting to unpublish video of user {} "
|
||||||
|
+ "in session {} but user is not streaming media",
|
||||||
|
moderator != null ? moderator.getParticipantPublicId() : participant.getParticipantPublicId(),
|
||||||
|
participant.getParticipantPublicId(), session.getSessionId());
|
||||||
throw new OpenViduException(Code.USER_NOT_STREAMING_ERROR_CODE,
|
throw new OpenViduException(Code.USER_NOT_STREAMING_ERROR_CODE,
|
||||||
"Participant '" + participant.getParticipantPublicId() + "' is not streaming media");
|
"Participant '" + participant.getParticipantPublicId() + "' is not streaming media");
|
||||||
}
|
}
|
||||||
|
@ -309,18 +326,18 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
if (senderParticipant == null) {
|
if (senderParticipant == null) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"PARTICIPANT {}: Requesting to recv media from user {} "
|
"PARTICIPANT {}: Requesting to recv media from user {} "
|
||||||
+ "in room {} but user could not be found",
|
+ "in session {} but user could not be found",
|
||||||
participant.getParticipantPublicId(), senderName, session.getSessionId());
|
participant.getParticipantPublicId(), senderName, session.getSessionId());
|
||||||
throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE,
|
throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE,
|
||||||
"User '" + senderName + " not found in room '" + session.getSessionId() + "'");
|
"User '" + senderName + " not found in session '" + session.getSessionId() + "'");
|
||||||
}
|
}
|
||||||
if (!senderParticipant.isStreaming()) {
|
if (!senderParticipant.isStreaming()) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"PARTICIPANT {}: Requesting to recv media from user {} "
|
"PARTICIPANT {}: Requesting to recv media from user {} "
|
||||||
+ "in room {} but user is not streaming media",
|
+ "in session {} but user is not streaming media",
|
||||||
participant.getParticipantPublicId(), senderName, session.getSessionId());
|
participant.getParticipantPublicId(), senderName, session.getSessionId());
|
||||||
throw new OpenViduException(Code.USER_NOT_STREAMING_ERROR_CODE,
|
throw new OpenViduException(Code.USER_NOT_STREAMING_ERROR_CODE,
|
||||||
"User '" + senderName + " not streaming media in room '" + session.getSessionId() + "'");
|
"User '" + senderName + " not streaming media in session '" + session.getSessionId() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
sdpAnswer = kParticipant.receiveMediaFrom(senderParticipant, sdpOffer);
|
sdpAnswer = kParticipant.receiveMediaFrom(senderParticipant, sdpOffer);
|
||||||
|
@ -349,10 +366,10 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
if (sender == null) {
|
if (sender == null) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"PARTICIPANT {}: Requesting to unsubscribe from user {} "
|
"PARTICIPANT {}: Requesting to unsubscribe from user {} "
|
||||||
+ "in room {} but user could not be found",
|
+ "in session {} but user could not be found",
|
||||||
participant.getParticipantPublicId(), senderName, session.getSessionId());
|
participant.getParticipantPublicId(), senderName, session.getSessionId());
|
||||||
throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE,
|
throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE,
|
||||||
"User " + senderName + " not found in room " + session.getSessionId());
|
"User " + senderName + " not found in session " + session.getSessionId());
|
||||||
}
|
}
|
||||||
|
|
||||||
kParticipant.cancelReceivingMedia(senderName, "unsubscribe");
|
kParticipant.cancelReceivingMedia(senderName, "unsubscribe");
|
||||||
|
@ -363,9 +380,9 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(Participant participant, String message, Integer transactionId) {
|
public void sendMessage(Participant participant, String message, Integer transactionId) {
|
||||||
try {
|
try {
|
||||||
JsonObject messageJSON = new JsonParser().parse(message).getAsJsonObject();
|
JsonObject messageJson = new JsonParser().parse(message).getAsJsonObject();
|
||||||
KurentoParticipant kParticipant = (KurentoParticipant) participant;
|
KurentoParticipant kParticipant = (KurentoParticipant) participant;
|
||||||
sessionEventsHandler.onSendMessage(participant, messageJSON,
|
sessionEventsHandler.onSendMessage(participant, messageJson,
|
||||||
getParticipants(kParticipant.getSession().getSessionId()), transactionId, null);
|
getParticipants(kParticipant.getSession().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,
|
||||||
|
@ -387,6 +404,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
String typeOfVideo = streamProperties.getTypeOfVideo();
|
String typeOfVideo = streamProperties.getTypeOfVideo();
|
||||||
Integer frameRate = streamProperties.getFrameRate();
|
Integer frameRate = streamProperties.getFrameRate();
|
||||||
String videoDimensions = streamProperties.getVideoDimensions();
|
String videoDimensions = streamProperties.getVideoDimensions();
|
||||||
|
KurentoFilter filter = streamProperties.getFilter();
|
||||||
|
|
||||||
switch (property) {
|
switch (property) {
|
||||||
case "audioActive":
|
case "audioActive":
|
||||||
|
@ -401,7 +419,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
kParticipant.setPublisherMediaOptions(new MediaOptions(hasAudio, hasVideo, audioActive, videoActive,
|
kParticipant.setPublisherMediaOptions(new MediaOptions(hasAudio, hasVideo, audioActive, videoActive,
|
||||||
typeOfVideo, frameRate, videoDimensions));
|
typeOfVideo, frameRate, videoDimensions, filter));
|
||||||
|
|
||||||
sessionEventsHandler.onStreamPropertyChanged(participant, transactionId,
|
sessionEventsHandler.onStreamPropertyChanged(participant, transactionId,
|
||||||
kParticipant.getSession().getParticipants(), streamId, property, newValue, reason);
|
kParticipant.getSession().getParticipants(), streamId, property, newValue, reason);
|
||||||
|
@ -442,7 +460,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
throw new OpenViduException(Code.ROOM_CANNOT_BE_CREATED_ERROR_CODE,
|
throw new OpenViduException(Code.ROOM_CANNOT_BE_CREATED_ERROR_CODE,
|
||||||
"Session '" + sessionId + "' already exists");
|
"Session '" + sessionId + "' already exists");
|
||||||
}
|
}
|
||||||
KurentoClient kurentoClient = kcProvider.getKurentoClient(kcSessionInfo);
|
this.kurentoClient = kcProvider.getKurentoClient(kcSessionInfo);
|
||||||
session = new KurentoSession(sessionId, sessionProperties, kurentoClient, kurentoSessionEventsHandler,
|
session = new KurentoSession(sessionId, sessionProperties, kurentoClient, kurentoSessionEventsHandler,
|
||||||
kcProvider.destroyWhenUnused(), this.CDR, this.openviduConfig);
|
kcProvider.destroyWhenUnused(), this.CDR, this.openviduConfig);
|
||||||
|
|
||||||
|
@ -482,7 +500,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MediaOptions generateMediaOptions(Request<JsonObject> request) {
|
public KurentoMediaOptions generateMediaOptions(Request<JsonObject> request) {
|
||||||
|
|
||||||
String sdpOffer = RpcHandler.getStringParam(request, ProtocolElements.PUBLISHVIDEO_SDPOFFER_PARAM);
|
String sdpOffer = RpcHandler.getStringParam(request, ProtocolElements.PUBLISHVIDEO_SDPOFFER_PARAM);
|
||||||
boolean hasAudio = RpcHandler.getBooleanParam(request, ProtocolElements.PUBLISHVIDEO_HASAUDIO_PARAM);
|
boolean hasAudio = RpcHandler.getBooleanParam(request, ProtocolElements.PUBLISHVIDEO_HASAUDIO_PARAM);
|
||||||
|
@ -491,6 +509,7 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
Boolean audioActive = null, videoActive = null;
|
Boolean audioActive = null, videoActive = null;
|
||||||
String typeOfVideo = null, videoDimensions = null;
|
String typeOfVideo = null, videoDimensions = null;
|
||||||
Integer frameRate = null;
|
Integer frameRate = null;
|
||||||
|
KurentoFilter kurentoFilter = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
audioActive = RpcHandler.getBooleanParam(request, ProtocolElements.PUBLISHVIDEO_AUDIOACTIVE_PARAM);
|
audioActive = RpcHandler.getBooleanParam(request, ProtocolElements.PUBLISHVIDEO_AUDIOACTIVE_PARAM);
|
||||||
|
@ -512,11 +531,18 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
frameRate = RpcHandler.getIntParam(request, ProtocolElements.PUBLISHVIDEO_FRAMERATE_PARAM);
|
frameRate = RpcHandler.getIntParam(request, ProtocolElements.PUBLISHVIDEO_FRAMERATE_PARAM);
|
||||||
} catch (RuntimeException noParameterFound) {
|
} catch (RuntimeException noParameterFound) {
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
JsonObject kurentoFilterJson = (JsonObject) RpcHandler.getParam(request,
|
||||||
|
ProtocolElements.PUBLISHVIDEO_KURENTOFILTER_PARAM);
|
||||||
|
kurentoFilter = new KurentoFilter(kurentoFilterJson.get("type").getAsString(),
|
||||||
|
kurentoFilterJson.get("options").getAsJsonObject());
|
||||||
|
} catch (RuntimeException noParameterFound) {
|
||||||
|
}
|
||||||
|
|
||||||
boolean doLoopback = RpcHandler.getBooleanParam(request, ProtocolElements.PUBLISHVIDEO_DOLOOPBACK_PARAM);
|
boolean doLoopback = RpcHandler.getBooleanParam(request, ProtocolElements.PUBLISHVIDEO_DOLOOPBACK_PARAM);
|
||||||
|
|
||||||
return new KurentoMediaOptions(true, sdpOffer, null, null, hasAudio, hasVideo, audioActive, videoActive,
|
return new KurentoMediaOptions(true, sdpOffer, null, null, hasAudio, hasVideo, audioActive, videoActive,
|
||||||
typeOfVideo, frameRate, videoDimensions, doLoopback);
|
typeOfVideo, frameRate, videoDimensions, kurentoFilter, doLoopback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -536,4 +562,167 @@ public class KurentoSessionManager extends SessionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyFilter(Session session, String streamId, String filterType, JsonObject filterOptions,
|
||||||
|
Participant moderator, Integer transactionId, String reason) {
|
||||||
|
String participantPrivateId = ((KurentoSession) session).getParticipantPrivateIdFromStreamId(streamId);
|
||||||
|
if (participantPrivateId != null) {
|
||||||
|
Participant participant = this.getParticipant(participantPrivateId);
|
||||||
|
log.debug("Request [APPLY_FILTER] over stream [{}] for reason [{}]", streamId, reason);
|
||||||
|
KurentoParticipant kParticipant = (KurentoParticipant) participant;
|
||||||
|
if (!participant.isStreaming()) {
|
||||||
|
log.warn(
|
||||||
|
"PARTICIPANT {}: Requesting to applyFilter to user {} "
|
||||||
|
+ "in session {} but user is not streaming media",
|
||||||
|
moderator != null ? moderator.getParticipantPublicId() : participant.getParticipantPublicId(),
|
||||||
|
participant.getParticipantPublicId(), session.getSessionId());
|
||||||
|
throw new OpenViduException(Code.USER_NOT_STREAMING_ERROR_CODE,
|
||||||
|
"User '" + participant.getParticipantPublicId() + " not streaming media in session '"
|
||||||
|
+ session.getSessionId() + "'");
|
||||||
|
} else if (kParticipant.getPublisher().getFilter() != null) {
|
||||||
|
log.warn(
|
||||||
|
"PARTICIPANT {}: Requesting to applyFilter to user {} "
|
||||||
|
+ "in session {} but user already has a filter",
|
||||||
|
moderator != null ? moderator.getParticipantPublicId() : participant.getParticipantPublicId(),
|
||||||
|
participant.getParticipantPublicId(), session.getSessionId());
|
||||||
|
throw new OpenViduException(Code.EXISTING_FILTER_ALREADY_APPLIED_ERROR_CODE,
|
||||||
|
"User '" + participant.getParticipantPublicId() + " already has a filter applied in session '"
|
||||||
|
+ session.getSessionId() + "'");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
KurentoFilter filter = new KurentoFilter(filterType, filterOptions);
|
||||||
|
this.applyFilterInPublisher(kParticipant, filter);
|
||||||
|
Set<Participant> participants = kParticipant.getSession().getParticipants();
|
||||||
|
sessionEventsHandler.onFilterChanged(participant, moderator, transactionId, participants, streamId,
|
||||||
|
filter, null, reason);
|
||||||
|
} catch (OpenViduException e) {
|
||||||
|
log.warn("PARTICIPANT {}: Error applying filter", participant.getParticipantPublicId(), e);
|
||||||
|
sessionEventsHandler.onFilterChanged(participant, moderator, transactionId, new HashSet<>(),
|
||||||
|
streamId, null, e, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("PARTICIPANT {}: Requesting to applyFilter to stream {} "
|
||||||
|
+ "in session {} but the owner cannot be found", streamId, session.getSessionId());
|
||||||
|
throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE,
|
||||||
|
"Owner of stream '" + streamId + "' not found in session '" + session.getSessionId() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execFilterMethod(Session session, String streamId, String filterMethod, JsonObject filterParams,
|
||||||
|
Participant moderator, Integer transactionId, String reason) {
|
||||||
|
String participantPrivateId = ((KurentoSession) session).getParticipantPrivateIdFromStreamId(streamId);
|
||||||
|
if (participantPrivateId != null) {
|
||||||
|
Participant participant = this.getParticipant(participantPrivateId);
|
||||||
|
log.debug("Request [EXEC_FILTER_MTEHOD] over stream [{}] for reason [{}]", streamId, reason);
|
||||||
|
KurentoParticipant kParticipant = (KurentoParticipant) participant;
|
||||||
|
if (!participant.isStreaming()) {
|
||||||
|
log.warn(
|
||||||
|
"PARTICIPANT {}: Requesting to execFilterMethod to user {} "
|
||||||
|
+ "in session {} but user is not streaming media",
|
||||||
|
moderator != null ? moderator.getParticipantPublicId() : participant.getParticipantPublicId(),
|
||||||
|
participant.getParticipantPublicId(), session.getSessionId());
|
||||||
|
throw new OpenViduException(Code.USER_NOT_STREAMING_ERROR_CODE,
|
||||||
|
"User '" + participant.getParticipantPublicId() + " not streaming media in session '"
|
||||||
|
+ session.getSessionId() + "'");
|
||||||
|
} else if (kParticipant.getPublisher().getFilter() == null) {
|
||||||
|
log.warn(
|
||||||
|
"PARTICIPANT {}: Requesting to execFilterMethod to user {} "
|
||||||
|
+ "in session {} but user does NOT have a filter",
|
||||||
|
moderator != null ? moderator.getParticipantPublicId() : participant.getParticipantPublicId(),
|
||||||
|
participant.getParticipantPublicId(), session.getSessionId());
|
||||||
|
throw new OpenViduException(Code.FILTER_NOT_APPLIED_ERROR_CODE,
|
||||||
|
"User '" + participant.getParticipantPublicId() + " has no filter applied in session '"
|
||||||
|
+ session.getSessionId() + "'");
|
||||||
|
} else {
|
||||||
|
KurentoFilter updatedFilter = this.execFilterMethodInPublisher(kParticipant, filterMethod,
|
||||||
|
filterParams);
|
||||||
|
Set<Participant> participants = kParticipant.getSession().getParticipants();
|
||||||
|
sessionEventsHandler.onFilterChanged(participant, moderator, transactionId, participants, streamId,
|
||||||
|
updatedFilter, null, reason);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("PARTICIPANT {}: Requesting to removeFilter to stream {} "
|
||||||
|
+ "in session {} but the owner cannot be found", streamId, session.getSessionId());
|
||||||
|
throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE,
|
||||||
|
"Owner of stream '" + streamId + "' not found in session '" + session.getSessionId() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeFilter(Session session, String streamId, Participant moderator, Integer transactionId,
|
||||||
|
String reason) {
|
||||||
|
String participantPrivateId = ((KurentoSession) session).getParticipantPrivateIdFromStreamId(streamId);
|
||||||
|
if (participantPrivateId != null) {
|
||||||
|
Participant participant = this.getParticipant(participantPrivateId);
|
||||||
|
log.debug("Request [REMOVE_FILTER] over stream [{}] for reason [{}]", streamId, reason);
|
||||||
|
KurentoParticipant kParticipant = (KurentoParticipant) participant;
|
||||||
|
if (!participant.isStreaming()) {
|
||||||
|
log.warn(
|
||||||
|
"PARTICIPANT {}: Requesting to removeFilter to user {} "
|
||||||
|
+ "in session {} but user is not streaming media",
|
||||||
|
moderator != null ? moderator.getParticipantPublicId() : participant.getParticipantPublicId(),
|
||||||
|
participant.getParticipantPublicId(), session.getSessionId());
|
||||||
|
throw new OpenViduException(Code.USER_NOT_STREAMING_ERROR_CODE,
|
||||||
|
"User '" + participant.getParticipantPublicId() + " not streaming media in session '"
|
||||||
|
+ session.getSessionId() + "'");
|
||||||
|
} else if (kParticipant.getPublisher().getFilter() == null) {
|
||||||
|
log.warn(
|
||||||
|
"PARTICIPANT {}: Requesting to removeFilter to user {} "
|
||||||
|
+ "in session {} but user does NOT have a filter",
|
||||||
|
moderator != null ? moderator.getParticipantPublicId() : participant.getParticipantPublicId(),
|
||||||
|
participant.getParticipantPublicId(), session.getSessionId());
|
||||||
|
throw new OpenViduException(Code.FILTER_NOT_APPLIED_ERROR_CODE,
|
||||||
|
"User '" + participant.getParticipantPublicId() + " has no filter applied in session '"
|
||||||
|
+ session.getSessionId() + "'");
|
||||||
|
} else {
|
||||||
|
this.removeFilterInPublisher(kParticipant);
|
||||||
|
Set<Participant> participants = kParticipant.getSession().getParticipants();
|
||||||
|
sessionEventsHandler.onFilterChanged(participant, moderator, transactionId, participants, streamId,
|
||||||
|
null, null, reason);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("PARTICIPANT {}: Requesting to removeFilter to stream {} "
|
||||||
|
+ "in session {} but the owner cannot be found", streamId, session.getSessionId());
|
||||||
|
throw new OpenViduException(Code.USER_NOT_FOUND_ERROR_CODE,
|
||||||
|
"Owner of stream '" + streamId + "' not found in session '" + session.getSessionId() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyFilterInPublisher(KurentoParticipant kParticipant, KurentoFilter filter)
|
||||||
|
throws OpenViduException {
|
||||||
|
GenericMediaElement.Builder builder = new GenericMediaElement.Builder(kParticipant.getPipeline(),
|
||||||
|
filter.getType());
|
||||||
|
Props props = new JsonUtils().fromJsonObjectToProps(filter.getOptions());
|
||||||
|
props.forEach(prop -> {
|
||||||
|
builder.withConstructorParam(prop.getName(), prop.getValue());
|
||||||
|
});
|
||||||
|
kParticipant.getPublisher().apply(builder.build());
|
||||||
|
kParticipant.getPublisher().getMediaOptions().setFilter(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private KurentoFilter execFilterMethodInPublisher(KurentoParticipant kParticipant, String method,
|
||||||
|
JsonObject params) {
|
||||||
|
kParticipant.getPublisher().execMethod(method, params);
|
||||||
|
KurentoFilter filter = kParticipant.getPublisher().getMediaOptions().getFilter();
|
||||||
|
KurentoFilter updatedFilter = new KurentoFilter(filter.getType(), filter.getOptions(), method, params);
|
||||||
|
kParticipant.getPublisher().getMediaOptions().setFilter(updatedFilter);
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeFilterInPublisher(KurentoParticipant kParticipant) {
|
||||||
|
kParticipant.getPublisher().revert(kParticipant.getPublisher().getFilter());
|
||||||
|
kParticipant.getPublisher().getMediaOptions().setFilter(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* private void addFilterEventListenerInPublisher(KurentoParticipant
|
||||||
|
* kParticipant) { this.listener =
|
||||||
|
* kParticipant.getPublisher().getFilter().addEventListener("CodeFound", event
|
||||||
|
* -> { System.out.println(event.getData()); }); } private void
|
||||||
|
* removeFilterEventListenerInPublisher(KurentoParticipant kParticipant) {
|
||||||
|
* kParticipant.getPublisher().getFilter().removeEventListener(this.listener); }
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2017-2018 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.kurento.core;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class KurentoTokenOptions {
|
||||||
|
|
||||||
|
private Integer videoMaxRecvBandwidth;
|
||||||
|
private Integer videoMinRecvBandwidth;
|
||||||
|
private Integer videoMaxSendBandwidth;
|
||||||
|
private Integer videoMinSendBandwidth;
|
||||||
|
private Map<String, Boolean> allowedFilters = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public KurentoTokenOptions(JsonObject options) {
|
||||||
|
if (options.has("videoMaxRecvBandwidth")) {
|
||||||
|
this.videoMaxRecvBandwidth = options.get("videoMaxRecvBandwidth").getAsInt();
|
||||||
|
}
|
||||||
|
if (options.has("videoMinRecvBandwidth")) {
|
||||||
|
this.videoMinRecvBandwidth = options.get("videoMinRecvBandwidth").getAsInt();
|
||||||
|
}
|
||||||
|
if (options.has("videoMaxSendBandwidth")) {
|
||||||
|
this.videoMaxSendBandwidth = options.get("videoMaxSendBandwidth").getAsInt();
|
||||||
|
}
|
||||||
|
if (options.has("videoMinSendBandwidth")) {
|
||||||
|
this.videoMinSendBandwidth = options.get("videoMinSendBandwidth").getAsInt();
|
||||||
|
}
|
||||||
|
if (options.has("allowedFilters")) {
|
||||||
|
JsonArray filters = options.get("allowedFilters").getAsJsonArray();
|
||||||
|
Iterator<JsonElement> it = filters.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
this.allowedFilters.put(it.next().getAsString(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVideoMaxRecvBandwidth() {
|
||||||
|
return videoMaxRecvBandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVideoMinRecvBandwidth() {
|
||||||
|
return videoMinRecvBandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVideoMaxSendBandwidth() {
|
||||||
|
return videoMaxSendBandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVideoMinSendBandwidth() {
|
||||||
|
return videoMinSendBandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getAllowedFilters() {
|
||||||
|
return allowedFilters.keySet().stream().toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFilterAllowed(String filterType) {
|
||||||
|
return this.allowedFilters.containsKey(filterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -25,8 +25,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
import org.json.simple.JSONArray;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
import org.kurento.client.Continuation;
|
import org.kurento.client.Continuation;
|
||||||
import org.kurento.client.ErrorEvent;
|
import org.kurento.client.ErrorEvent;
|
||||||
import org.kurento.client.EventListener;
|
import org.kurento.client.EventListener;
|
||||||
|
@ -42,11 +40,16 @@ import org.kurento.client.WebRtcEndpoint;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.client.OpenViduException;
|
import io.openvidu.client.OpenViduException;
|
||||||
import io.openvidu.client.OpenViduException.Code;
|
import io.openvidu.client.OpenViduException.Code;
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
import io.openvidu.server.core.Participant;
|
import io.openvidu.server.core.Participant;
|
||||||
import io.openvidu.server.kurento.core.KurentoParticipant;
|
import io.openvidu.server.kurento.core.KurentoParticipant;
|
||||||
|
import io.openvidu.server.kurento.core.KurentoTokenOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link WebRtcEndpoint} wrapper that supports buffering of
|
* {@link WebRtcEndpoint} wrapper that supports buffering of
|
||||||
|
@ -108,11 +111,28 @@ public abstract class MediaEndpoint {
|
||||||
this.setMediaPipeline(pipeline);
|
this.setMediaPipeline(pipeline);
|
||||||
|
|
||||||
this.openviduConfig = openviduConfig;
|
this.openviduConfig = openviduConfig;
|
||||||
|
|
||||||
|
KurentoTokenOptions kurentoTokenOptions = this.owner.getToken().getKurentoTokenOptions();
|
||||||
|
if (kurentoTokenOptions != null) {
|
||||||
|
this.maxRecvKbps = kurentoTokenOptions.getVideoMaxRecvBandwidth() != null
|
||||||
|
? kurentoTokenOptions.getVideoMaxRecvBandwidth()
|
||||||
|
: this.openviduConfig.getVideoMaxRecvBandwidth();
|
||||||
|
this.minRecvKbps = kurentoTokenOptions.getVideoMinRecvBandwidth() != null
|
||||||
|
? kurentoTokenOptions.getVideoMinRecvBandwidth()
|
||||||
|
: this.openviduConfig.getVideoMinRecvBandwidth();
|
||||||
|
this.maxSendKbps = kurentoTokenOptions.getVideoMaxSendBandwidth() != null
|
||||||
|
? kurentoTokenOptions.getVideoMaxSendBandwidth()
|
||||||
|
: this.openviduConfig.getVideoMaxSendBandwidth();
|
||||||
|
this.minSendKbps = kurentoTokenOptions.getVideoMinSendBandwidth() != null
|
||||||
|
? kurentoTokenOptions.getVideoMinSendBandwidth()
|
||||||
|
: this.openviduConfig.getVideoMinSendBandwidth();
|
||||||
|
} else {
|
||||||
this.maxRecvKbps = this.openviduConfig.getVideoMaxRecvBandwidth();
|
this.maxRecvKbps = this.openviduConfig.getVideoMaxRecvBandwidth();
|
||||||
this.minRecvKbps = this.openviduConfig.getVideoMinRecvBandwidth();
|
this.minRecvKbps = this.openviduConfig.getVideoMinRecvBandwidth();
|
||||||
this.maxSendKbps = this.openviduConfig.getVideoMaxSendBandwidth();
|
this.maxSendKbps = this.openviduConfig.getVideoMaxSendBandwidth();
|
||||||
this.minSendKbps = this.openviduConfig.getVideoMinSendBandwidth();
|
this.minSendKbps = this.openviduConfig.getVideoMinSendBandwidth();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isWeb() {
|
public boolean isWeb() {
|
||||||
return web;
|
return web;
|
||||||
|
@ -464,28 +484,26 @@ public abstract class MediaEndpoint {
|
||||||
|
|
||||||
public abstract PublisherEndpoint getPublisher();
|
public abstract PublisherEndpoint getPublisher();
|
||||||
|
|
||||||
public JSONObject toJSON() {
|
public JsonObject toJson() {
|
||||||
JSONObject json = new JSONObject();
|
JsonObject json = new JsonObject();
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
public JsonObject withStatsToJson() {
|
||||||
public JSONObject withStatsToJSON() {
|
JsonObject json = new JsonObject();
|
||||||
JSONObject json = new JSONObject();
|
json.addProperty("webrtcTagName", this.getEndpoint().getTag("name"));
|
||||||
json.put("webrtcTagName", this.getEndpoint().getTag("name"));
|
json.add("receivedCandidates", new GsonBuilder().create().toJsonTree(this.receivedCandidateList));
|
||||||
json.put("receivedCandidates", this.receivedCandidateList);
|
json.addProperty("localCandidate", this.selectedLocalIceCandidate);
|
||||||
json.put("localCandidate", this.selectedLocalIceCandidate);
|
json.addProperty("remoteCandidate", this.selectedRemoteIceCandidate);
|
||||||
json.put("remoteCandidate", this.selectedRemoteIceCandidate);
|
|
||||||
|
|
||||||
JSONArray jsonArray = new JSONArray();
|
|
||||||
|
|
||||||
|
JsonArray jsonArray = new JsonArray();
|
||||||
for (KmsEvent event : this.kmsEvents) {
|
for (KmsEvent event : this.kmsEvents) {
|
||||||
JSONObject jsonKmsEvent = new JSONObject();
|
JsonObject jsonKmsEvent = new JsonObject();
|
||||||
jsonKmsEvent.put(event.event.getType(), event.timestamp);
|
jsonKmsEvent.addProperty(event.event.getType(), event.timestamp);
|
||||||
jsonArray.add(jsonKmsEvent);
|
jsonArray.add(jsonKmsEvent);
|
||||||
}
|
}
|
||||||
|
json.add("events", jsonArray);
|
||||||
|
|
||||||
json.put("events", jsonArray);
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,25 +21,31 @@ import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
import org.kurento.client.Continuation;
|
import org.kurento.client.Continuation;
|
||||||
|
import org.kurento.client.GenericMediaElement;
|
||||||
import org.kurento.client.ListenerSubscription;
|
import org.kurento.client.ListenerSubscription;
|
||||||
import org.kurento.client.MediaElement;
|
import org.kurento.client.MediaElement;
|
||||||
import org.kurento.client.MediaPipeline;
|
import org.kurento.client.MediaPipeline;
|
||||||
import org.kurento.client.MediaType;
|
import org.kurento.client.MediaType;
|
||||||
import org.kurento.client.PassThrough;
|
import org.kurento.client.PassThrough;
|
||||||
import org.kurento.client.WebRtcEndpoint;
|
import org.kurento.client.WebRtcEndpoint;
|
||||||
|
import org.kurento.jsonrpc.Props;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.client.OpenViduException;
|
import io.openvidu.client.OpenViduException;
|
||||||
import io.openvidu.client.OpenViduException.Code;
|
import io.openvidu.client.OpenViduException.Code;
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
import io.openvidu.server.core.MediaOptions;
|
import io.openvidu.server.core.MediaOptions;
|
||||||
import io.openvidu.server.kurento.TrackType;
|
import io.openvidu.server.kurento.TrackType;
|
||||||
import io.openvidu.server.kurento.core.KurentoParticipant;
|
import io.openvidu.server.kurento.core.KurentoParticipant;
|
||||||
|
import io.openvidu.server.utils.JsonUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publisher aspect of the {@link MediaEndpoint}.
|
* Publisher aspect of the {@link MediaEndpoint}.
|
||||||
|
@ -55,13 +61,15 @@ public class PublisherEndpoint extends MediaEndpoint {
|
||||||
private PassThrough passThru = null;
|
private PassThrough passThru = null;
|
||||||
private ListenerSubscription passThruSubscription = null;
|
private ListenerSubscription passThruSubscription = null;
|
||||||
|
|
||||||
|
private GenericMediaElement filter;
|
||||||
private Map<String, MediaElement> elements = new HashMap<String, MediaElement>();
|
private Map<String, MediaElement> elements = new HashMap<String, MediaElement>();
|
||||||
private LinkedList<String> elementIds = new LinkedList<String>();
|
private LinkedList<String> elementIds = new LinkedList<String>();
|
||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
|
|
||||||
private Map<String, ListenerSubscription> elementsErrorSubscriptions = new HashMap<String, ListenerSubscription>();
|
private Map<String, ListenerSubscription> elementsErrorSubscriptions = new HashMap<String, ListenerSubscription>();
|
||||||
|
|
||||||
public PublisherEndpoint(boolean web, KurentoParticipant owner, String endpointName, MediaPipeline pipeline, OpenviduConfig openviduConfig) {
|
public PublisherEndpoint(boolean web, KurentoParticipant owner, String endpointName, MediaPipeline pipeline,
|
||||||
|
OpenviduConfig openviduConfig) {
|
||||||
super(web, owner, endpointName, pipeline, openviduConfig, log);
|
super(web, owner, endpointName, pipeline, openviduConfig, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +100,10 @@ public class PublisherEndpoint extends MediaEndpoint {
|
||||||
return elements.values();
|
return elements.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GenericMediaElement getFilter() {
|
||||||
|
return this.filter;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes this media endpoint for publishing media and processes the SDP
|
* Initializes this media endpoint for publishing media and processes the SDP
|
||||||
* offer or answer. If the internal endpoint is an {@link WebRtcEndpoint}, it
|
* offer or answer. If the internal endpoint is an {@link WebRtcEndpoint}, it
|
||||||
|
@ -180,7 +192,7 @@ public class PublisherEndpoint extends MediaEndpoint {
|
||||||
* @throws OpenViduException
|
* @throws OpenViduException
|
||||||
* if thrown, the media element was not added
|
* if thrown, the media element was not added
|
||||||
*/
|
*/
|
||||||
public String apply(MediaElement shaper) throws OpenViduException {
|
public String apply(GenericMediaElement shaper) throws OpenViduException {
|
||||||
return apply(shaper, null);
|
return apply(shaper, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +210,7 @@ public class PublisherEndpoint extends MediaEndpoint {
|
||||||
* @throws OpenViduException
|
* @throws OpenViduException
|
||||||
* if thrown, the media element was not added
|
* if thrown, the media element was not added
|
||||||
*/
|
*/
|
||||||
public synchronized String apply(MediaElement shaper, MediaType type) throws OpenViduException {
|
public synchronized String apply(GenericMediaElement shaper, MediaType type) throws OpenViduException {
|
||||||
String id = shaper.getId();
|
String id = shaper.getId();
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
throw new OpenViduException(Code.MEDIA_WEBRTC_ENDPOINT_ERROR_CODE,
|
throw new OpenViduException(Code.MEDIA_WEBRTC_ENDPOINT_ERROR_CODE,
|
||||||
|
@ -222,6 +234,9 @@ public class PublisherEndpoint extends MediaEndpoint {
|
||||||
}
|
}
|
||||||
elementIds.addFirst(id);
|
elementIds.addFirst(id);
|
||||||
elements.put(id, shaper);
|
elements.put(id, shaper);
|
||||||
|
|
||||||
|
this.filter = shaper;
|
||||||
|
|
||||||
elementsErrorSubscriptions.put(id, registerElemErrListener(shaper));
|
elementsErrorSubscriptions.put(id, registerElemErrListener(shaper));
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -283,6 +298,12 @@ public class PublisherEndpoint extends MediaEndpoint {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.filter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonElement execMethod(String method, JsonObject params) throws OpenViduException {
|
||||||
|
Props props = new JsonUtils().fromJsonObjectToProps(params);
|
||||||
|
return (JsonElement) ((GenericMediaElement) this.filter).invoke(method, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void mute(TrackType muteType) {
|
public synchronized void mute(TrackType muteType) {
|
||||||
|
@ -488,22 +509,20 @@ public class PublisherEndpoint extends MediaEndpoint {
|
||||||
this.mediaOptions = mediaOptions;
|
this.mediaOptions = mediaOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject toJSON() {
|
public JsonObject toJson() {
|
||||||
JSONObject json = super.toJSON();
|
JsonObject json = super.toJson();
|
||||||
json.put("streamId", this.getEndpoint().getTag("name"));
|
json.addProperty("streamId", this.getEndpoint().getTag("name"));
|
||||||
json.put("mediaOptions", this.mediaOptions.toJSON());
|
json.add("mediaOptions", this.mediaOptions.toJson());
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject withStatsToJSON() {
|
public JsonObject withStatsToJson() {
|
||||||
JSONObject json = super.withStatsToJSON();
|
JsonObject json = super.withStatsToJson();
|
||||||
JSONObject toJSON = this.toJSON();
|
JsonObject toJson = this.toJson();
|
||||||
for (Object key : toJSON.keySet()) {
|
for (Entry<String, JsonElement> entry : toJson.entrySet()) {
|
||||||
json.put(key, toJSON.get(key));
|
json.add(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,15 @@
|
||||||
|
|
||||||
package io.openvidu.server.kurento.endpoint;
|
package io.openvidu.server.kurento.endpoint;
|
||||||
|
|
||||||
import org.json.simple.JSONObject;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import org.kurento.client.MediaPipeline;
|
import org.kurento.client.MediaPipeline;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.server.config.OpenviduConfig;
|
import io.openvidu.server.config.OpenviduConfig;
|
||||||
import io.openvidu.server.kurento.core.KurentoParticipant;
|
import io.openvidu.server.kurento.core.KurentoParticipant;
|
||||||
|
|
||||||
|
@ -37,7 +41,8 @@ public class SubscriberEndpoint extends MediaEndpoint {
|
||||||
|
|
||||||
private PublisherEndpoint publisher = null;
|
private PublisherEndpoint publisher = null;
|
||||||
|
|
||||||
public SubscriberEndpoint(boolean web, KurentoParticipant owner, String endpointName, MediaPipeline pipeline, OpenviduConfig openviduConfig) {
|
public SubscriberEndpoint(boolean web, KurentoParticipant owner, String endpointName, MediaPipeline pipeline,
|
||||||
|
OpenviduConfig openviduConfig) {
|
||||||
super(web, owner, endpointName, pipeline, openviduConfig, log);
|
super(web, owner, endpointName, pipeline, openviduConfig, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,22 +73,20 @@ public class SubscriberEndpoint extends MediaEndpoint {
|
||||||
this.publisher = publisher;
|
this.publisher = publisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject toJSON() {
|
public JsonObject toJson() {
|
||||||
JSONObject json = super.toJSON();
|
JsonObject json = super.toJson();
|
||||||
json.put("streamId", this.publisher.getEndpoint().getTag("name"));
|
json.addProperty("streamId", this.publisher.getEndpoint().getTag("name"));
|
||||||
json.put("publisher", this.publisher.getEndpointName());
|
json.addProperty("publisher", this.publisher.getEndpointName());
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject withStatsToJSON() {
|
public JsonObject withStatsToJson() {
|
||||||
JSONObject json = super.withStatsToJSON();
|
JsonObject json = super.withStatsToJson();
|
||||||
JSONObject toJSON = this.toJSON();
|
JsonObject toJson = this.toJson();
|
||||||
for (Object key : toJSON.keySet()) {
|
for (Entry<String, JsonElement> entry : toJson.entrySet()) {
|
||||||
json.put(key, toJSON.get(key));
|
json.add(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,6 @@ import java.util.stream.Collectors;
|
||||||
import javax.ws.rs.ProcessingException;
|
import javax.ws.rs.ProcessingException;
|
||||||
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
import org.json.simple.parser.JSONParser;
|
|
||||||
import org.json.simple.parser.ParseException;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -61,6 +58,8 @@ import com.github.dockerjava.core.DockerClientBuilder;
|
||||||
import com.github.dockerjava.core.DockerClientConfig;
|
import com.github.dockerjava.core.DockerClientConfig;
|
||||||
import com.github.dockerjava.core.command.ExecStartResultCallback;
|
import com.github.dockerjava.core.command.ExecStartResultCallback;
|
||||||
import com.github.dockerjava.core.command.PullImageResultCallback;
|
import com.github.dockerjava.core.command.PullImageResultCallback;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
import io.openvidu.client.OpenViduException;
|
import io.openvidu.client.OpenViduException;
|
||||||
import io.openvidu.client.OpenViduException.Code;
|
import io.openvidu.client.OpenViduException.Code;
|
||||||
|
@ -137,9 +136,9 @@ public class ComposedRecordingService {
|
||||||
envs.add("VIDEO_NAME=" + properties.name());
|
envs.add("VIDEO_NAME=" + properties.name());
|
||||||
envs.add("VIDEO_FORMAT=mp4");
|
envs.add("VIDEO_FORMAT=mp4");
|
||||||
envs.add("USER_ID=" + uid);
|
envs.add("USER_ID=" + uid);
|
||||||
envs.add("RECORDING_JSON=" + recording.toJson().toJSONString());
|
envs.add("RECORDING_JSON=" + recording.toJson().toString());
|
||||||
|
|
||||||
log.info(recording.toJson().toJSONString());
|
log.info(recording.toJson().toString());
|
||||||
log.info("Recorder connecting to url {}", layoutUrl);
|
log.info("Recorder connecting to url {}", layoutUrl);
|
||||||
|
|
||||||
String containerId = this.runRecordingContainer(envs, "recording_" + recordingId);
|
String containerId = this.runRecordingContainer(envs, "recording_" + recordingId);
|
||||||
|
@ -212,7 +211,7 @@ public class ComposedRecordingService {
|
||||||
recording.setUrl(this.openviduConfig.getFinalUrl() + "recordings/" + recording.getName() + ".mp4");
|
recording.setUrl(this.openviduConfig.getFinalUrl() + "recordings/" + recording.getName() + ".mp4");
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException | ParseException e) {
|
} catch (IOException e) {
|
||||||
throw new OpenViduException(Code.RECORDING_REPORT_ERROR_CODE,
|
throw new OpenViduException(Code.RECORDING_REPORT_ERROR_CODE,
|
||||||
"There was an error generating the metadata report file for the recording");
|
"There was an error generating the metadata report file for the recording");
|
||||||
}
|
}
|
||||||
|
@ -417,11 +416,10 @@ public class ComposedRecordingService {
|
||||||
|
|
||||||
private Recording getRecordingFromEntityFile(File file) {
|
private Recording getRecordingFromEntityFile(File file) {
|
||||||
if (file.isFile() && file.getName().startsWith(RECORDING_ENTITY_FILE)) {
|
if (file.isFile() && file.getName().startsWith(RECORDING_ENTITY_FILE)) {
|
||||||
JSONParser parser = new JSONParser();
|
JsonObject json = null;
|
||||||
JSONObject json = null;
|
|
||||||
try {
|
try {
|
||||||
json = (JSONObject) parser.parse(new FileReader(file));
|
json = new JsonParser().parse(new FileReader(file)).getAsJsonObject();
|
||||||
} catch (IOException | ParseException e) {
|
} catch (IOException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new Recording(json);
|
return new Recording(json);
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
package io.openvidu.server.recording;
|
package io.openvidu.server.recording;
|
||||||
|
|
||||||
import org.json.simple.JSONObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import io.openvidu.java.client.RecordingLayout;
|
import io.openvidu.java.client.RecordingLayout;
|
||||||
import io.openvidu.java.client.RecordingProperties;
|
import io.openvidu.java.client.RecordingProperties;
|
||||||
|
@ -53,22 +53,26 @@ public class Recording {
|
||||||
this.recordingProperties = recordingProperties;
|
this.recordingProperties = recordingProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Recording(JSONObject json) {
|
public Recording(JsonObject json) {
|
||||||
this.id = (String) json.get("id");
|
this.id = json.get("id").getAsString();
|
||||||
this.sessionId = (String) json.get("sessionId");
|
this.sessionId = json.get("sessionId").getAsString();
|
||||||
this.createdAt = (long) json.get("createdAt");
|
this.createdAt = json.get("createdAt").getAsLong();
|
||||||
this.size = (long) json.get("size");
|
this.size = json.get("size").getAsLong();
|
||||||
try {
|
try {
|
||||||
this.duration = (double) json.get("duration");
|
this.duration = json.get("duration").getAsDouble();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.duration = new Long((long) json.get("duration")).doubleValue();
|
this.duration = new Long((long) json.get("duration").getAsLong()).doubleValue();
|
||||||
}
|
}
|
||||||
this.url = (String) json.get("url");
|
if (json.get("url").isJsonNull()) {
|
||||||
this.hasAudio = (boolean) json.get("hasAudio");
|
this.url = null;
|
||||||
this.hasVideo = (boolean) json.get("hasVideo");
|
} else {
|
||||||
this.status = Status.valueOf((String) json.get("status"));
|
this.url = json.get("url").getAsString();
|
||||||
this.recordingProperties = new RecordingProperties.Builder().name((String) json.get("name"))
|
}
|
||||||
.recordingLayout(RecordingLayout.valueOf((String) json.get("recordingLayout"))).build();
|
this.hasAudio = json.get("hasAudio").getAsBoolean();
|
||||||
|
this.hasVideo = json.get("hasVideo").getAsBoolean();
|
||||||
|
this.status = Status.valueOf(json.get("status").getAsString());
|
||||||
|
this.recordingProperties = new RecordingProperties.Builder().name(json.get("name").getAsString())
|
||||||
|
.recordingLayout(RecordingLayout.valueOf(json.get("recordingLayout").getAsString())).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Status getStatus() {
|
public Status getStatus() {
|
||||||
|
@ -155,23 +159,22 @@ public class Recording {
|
||||||
this.hasVideo = hasVideo;
|
this.hasVideo = hasVideo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
public JsonObject toJson() {
|
||||||
public JSONObject toJson() {
|
JsonObject json = new JsonObject();
|
||||||
JSONObject json = new JSONObject();
|
json.addProperty("id", this.id);
|
||||||
json.put("id", this.id);
|
json.addProperty("name", this.recordingProperties.name());
|
||||||
json.put("name", this.recordingProperties.name());
|
json.addProperty("recordingLayout", this.recordingProperties.recordingLayout().name());
|
||||||
json.put("recordingLayout", this.recordingProperties.recordingLayout().name());
|
|
||||||
if (RecordingLayout.CUSTOM.equals(this.recordingProperties.recordingLayout())) {
|
if (RecordingLayout.CUSTOM.equals(this.recordingProperties.recordingLayout())) {
|
||||||
json.put("customLayout", this.recordingProperties.customLayout());
|
json.addProperty("customLayout", this.recordingProperties.customLayout());
|
||||||
}
|
}
|
||||||
json.put("sessionId", this.sessionId);
|
json.addProperty("sessionId", this.sessionId);
|
||||||
json.put("createdAt", this.createdAt);
|
json.addProperty("createdAt", this.createdAt);
|
||||||
json.put("size", this.size);
|
json.addProperty("size", this.size);
|
||||||
json.put("duration", this.duration);
|
json.addProperty("duration", this.duration);
|
||||||
json.put("url", this.url);
|
json.addProperty("url", this.url);
|
||||||
json.put("hasAudio", this.hasAudio);
|
json.addProperty("hasAudio", this.hasAudio);
|
||||||
json.put("hasVideo", this.hasVideo);
|
json.addProperty("hasVideo", this.hasVideo);
|
||||||
json.put("status", this.status.toString());
|
json.addProperty("status", this.status.toString());
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,39 +21,45 @@ import java.io.FileNotFoundException;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.json.simple.JSONArray;
|
import com.google.gson.JsonArray;
|
||||||
import org.json.simple.JSONObject;
|
import com.google.gson.JsonIOException;
|
||||||
import org.json.simple.parser.JSONParser;
|
import com.google.gson.JsonObject;
|
||||||
import org.json.simple.parser.ParseException;
|
import com.google.gson.JsonParser;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
import io.openvidu.client.OpenViduException;
|
import io.openvidu.client.OpenViduException;
|
||||||
import io.openvidu.client.OpenViduException.Code;
|
import io.openvidu.client.OpenViduException.Code;
|
||||||
|
|
||||||
public class RecordingInfoUtils {
|
public class RecordingInfoUtils {
|
||||||
|
|
||||||
private JSONParser parser;
|
private JsonParser parser;
|
||||||
private JSONObject json;
|
private JsonObject json;
|
||||||
private JSONObject jsonFormat;
|
private JsonObject jsonFormat;
|
||||||
private JSONObject videoStream;
|
private JsonObject videoStream;
|
||||||
private JSONObject audioStream;
|
private JsonObject audioStream;
|
||||||
|
|
||||||
public RecordingInfoUtils(String fullVideoPath)
|
public RecordingInfoUtils(String fullVideoPath) throws FileNotFoundException, IOException, OpenViduException {
|
||||||
throws FileNotFoundException, IOException, ParseException, OpenViduException {
|
|
||||||
|
|
||||||
this.parser = new JSONParser();
|
this.parser = new JsonParser();
|
||||||
this.json = (JSONObject) parser.parse(new FileReader(fullVideoPath));
|
|
||||||
|
|
||||||
if (json.isEmpty()) {
|
try {
|
||||||
// Recording metadata from ffprobe is empty: video file is corrupted or empty
|
this.json = parser.parse(new FileReader(fullVideoPath)).getAsJsonObject();
|
||||||
throw new OpenViduException(Code.RECORDING_FILE_EMPTY_ERROR, "The recording file is empty or corrupted");
|
} catch (JsonIOException | JsonSyntaxException e) {
|
||||||
|
// Recording metadata from ffprobe is not a JSON: video file is corrupted
|
||||||
|
throw new OpenViduException(Code.RECORDING_FILE_EMPTY_ERROR, "The recording file is corrupted");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.jsonFormat = (JSONObject) json.get("format");
|
if (this.json.size() == 0) {
|
||||||
|
// Recording metadata from ffprobe is an emtpy JSON
|
||||||
|
throw new OpenViduException(Code.RECORDING_FILE_EMPTY_ERROR, "The recording file is empty");
|
||||||
|
}
|
||||||
|
|
||||||
JSONArray streams = (JSONArray) json.get("streams");
|
this.jsonFormat = json.get("format").getAsJsonObject();
|
||||||
|
|
||||||
|
JsonArray streams = json.get("streams").getAsJsonArray();
|
||||||
|
|
||||||
for (int i = 0; i < streams.size(); i++) {
|
for (int i = 0; i < streams.size(); i++) {
|
||||||
JSONObject stream = (JSONObject) streams.get(i);
|
JsonObject stream = streams.get(i).getAsJsonObject();
|
||||||
if ("video".equals(stream.get("codec_type").toString())) {
|
if ("video".equals(stream.get("codec_type").toString())) {
|
||||||
this.videoStream = stream;
|
this.videoStream = stream;
|
||||||
} else if ("audio".equals(stream.get("codec_type").toString())) {
|
} else if ("audio".equals(stream.get("codec_type").toString())) {
|
||||||
|
@ -64,19 +70,19 @@ public class RecordingInfoUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getDurationInSeconds() {
|
public double getDurationInSeconds() {
|
||||||
return Double.parseDouble(jsonFormat.get("duration").toString());
|
return jsonFormat.get("duration").getAsDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSizeInBytes() {
|
public int getSizeInBytes() {
|
||||||
return Integer.parseInt(jsonFormat.get("size").toString());
|
return jsonFormat.get("size").getAsInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfStreams() {
|
public int getNumberOfStreams() {
|
||||||
return Integer.parseInt(jsonFormat.get("nb_streams").toString());
|
return jsonFormat.get("nb_streams").getAsInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBitRate() {
|
public int getBitRate() {
|
||||||
return (Integer.parseInt(jsonFormat.get("bit_rate").toString()) / 1000);
|
return ((jsonFormat.get("bit_rate").getAsInt()) / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasVideo() {
|
public boolean hasVideo() {
|
||||||
|
@ -88,11 +94,11 @@ public class RecordingInfoUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int videoWidth() {
|
public int videoWidth() {
|
||||||
return Integer.parseInt(videoStream.get("width").toString());
|
return videoStream.get("width").getAsInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int videoHeight() {
|
public int videoHeight() {
|
||||||
return Integer.parseInt(videoStream.get("height").toString());
|
return videoStream.get("height").getAsInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getVideoFramerate() {
|
public int getVideoFramerate() {
|
||||||
|
|
|
@ -22,10 +22,10 @@ import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.json.simple.JSONArray;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
@ -35,6 +35,10 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
import io.openvidu.client.OpenViduException;
|
import io.openvidu.client.OpenViduException;
|
||||||
import io.openvidu.client.internal.ProtocolElements;
|
import io.openvidu.client.internal.ProtocolElements;
|
||||||
import io.openvidu.java.client.MediaMode;
|
import io.openvidu.java.client.MediaMode;
|
||||||
|
@ -47,6 +51,7 @@ import io.openvidu.server.core.Participant;
|
||||||
import io.openvidu.server.core.ParticipantRole;
|
import io.openvidu.server.core.ParticipantRole;
|
||||||
import io.openvidu.server.core.Session;
|
import io.openvidu.server.core.Session;
|
||||||
import io.openvidu.server.core.SessionManager;
|
import io.openvidu.server.core.SessionManager;
|
||||||
|
import io.openvidu.server.kurento.core.KurentoTokenOptions;
|
||||||
import io.openvidu.server.recording.ComposedRecordingService;
|
import io.openvidu.server.recording.ComposedRecordingService;
|
||||||
import io.openvidu.server.recording.Recording;
|
import io.openvidu.server.recording.Recording;
|
||||||
|
|
||||||
|
@ -68,9 +73,8 @@ public class SessionRestController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private OpenviduConfig openviduConfig;
|
private OpenviduConfig openviduConfig;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@RequestMapping(value = "/sessions", method = RequestMethod.POST)
|
@RequestMapping(value = "/sessions", method = RequestMethod.POST)
|
||||||
public ResponseEntity<JSONObject> getSessionId(@RequestBody(required = false) Map<?, ?> params) {
|
public ResponseEntity<?> getSessionId(@RequestBody(required = false) Map<?, ?> params) {
|
||||||
|
|
||||||
SessionProperties.Builder builder = new SessionProperties.Builder();
|
SessionProperties.Builder builder = new SessionProperties.Builder();
|
||||||
String customSessionId = null;
|
String customSessionId = null;
|
||||||
|
@ -130,45 +134,43 @@ public class SessionRestController {
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionManager.storeSessionId(sessionId, sessionProperties);
|
sessionManager.storeSessionId(sessionId, sessionProperties);
|
||||||
JSONObject responseJson = new JSONObject();
|
JsonObject responseJson = new JsonObject();
|
||||||
responseJson.put("id", sessionId);
|
responseJson.addProperty("id", sessionId);
|
||||||
|
|
||||||
return new ResponseEntity<>(responseJson, HttpStatus.OK);
|
return new ResponseEntity<>(responseJson.toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@RequestMapping(value = "/sessions/{sessionId}", method = RequestMethod.GET)
|
@RequestMapping(value = "/sessions/{sessionId}", method = RequestMethod.GET)
|
||||||
public ResponseEntity<JSONObject> getSession(@PathVariable("sessionId") String sessionId,
|
public ResponseEntity<?> getSession(@PathVariable("sessionId") String sessionId,
|
||||||
@RequestParam(value = "webRtcStats", defaultValue = "false", required = false) boolean webRtcStats) {
|
@RequestParam(value = "webRtcStats", defaultValue = "false", required = false) boolean webRtcStats) {
|
||||||
Session session = this.sessionManager.getSession(sessionId);
|
Session session = this.sessionManager.getSession(sessionId);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
JSONObject response = (webRtcStats == true) ? session.withStatsToJSON() : session.toJSON();
|
JsonObject response = (webRtcStats == true) ? session.withStatsToJson() : session.toJson();
|
||||||
response.put("recording", this.recordingService.sessionIsBeingRecorded(sessionId));
|
response.addProperty("recording", this.recordingService.sessionIsBeingRecorded(sessionId));
|
||||||
return new ResponseEntity<>(response, HttpStatus.OK);
|
return new ResponseEntity<>(response.toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
} else {
|
} else {
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@RequestMapping(value = "/sessions", method = RequestMethod.GET)
|
@RequestMapping(value = "/sessions", method = RequestMethod.GET)
|
||||||
public ResponseEntity<JSONObject> listSessions(
|
public ResponseEntity<?> listSessions(
|
||||||
@RequestParam(value = "webRtcStats", defaultValue = "false", required = false) boolean webRtcStats) {
|
@RequestParam(value = "webRtcStats", defaultValue = "false", required = false) boolean webRtcStats) {
|
||||||
Collection<Session> sessions = this.sessionManager.getSessionObjects();
|
Collection<Session> sessions = this.sessionManager.getSessionObjects();
|
||||||
JSONObject json = new JSONObject();
|
JsonObject json = new JsonObject();
|
||||||
JSONArray jsonArray = new JSONArray();
|
JsonArray jsonArray = new JsonArray();
|
||||||
sessions.forEach(s -> {
|
sessions.forEach(s -> {
|
||||||
JSONObject sessionJson = (webRtcStats == true) ? s.withStatsToJSON() : s.toJSON();
|
JsonObject sessionJson = (webRtcStats == true) ? s.withStatsToJson() : s.toJson();
|
||||||
sessionJson.put("recording", this.recordingService.sessionIsBeingRecorded(s.getSessionId()));
|
sessionJson.addProperty("recording", this.recordingService.sessionIsBeingRecorded(s.getSessionId()));
|
||||||
jsonArray.add(sessionJson);
|
jsonArray.add(sessionJson);
|
||||||
});
|
});
|
||||||
json.put("numberOfElements", sessions.size());
|
json.addProperty("numberOfElements", sessions.size());
|
||||||
json.put("content", jsonArray);
|
json.add("content", jsonArray);
|
||||||
return new ResponseEntity<>(json, HttpStatus.OK);
|
return new ResponseEntity<>(json.toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/sessions/{sessionId}", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/sessions/{sessionId}", method = RequestMethod.DELETE)
|
||||||
public ResponseEntity<JSONObject> closeSession(@PathVariable("sessionId") String sessionId) {
|
public ResponseEntity<?> closeSession(@PathVariable("sessionId") String sessionId) {
|
||||||
Session session = this.sessionManager.getSession(sessionId);
|
Session session = this.sessionManager.getSession(sessionId);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
this.sessionManager.closeSession(sessionId, "sessionClosedByServer");
|
this.sessionManager.closeSession(sessionId, "sessionClosedByServer");
|
||||||
|
@ -179,7 +181,7 @@ public class SessionRestController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/sessions/{sessionId}/connection/{connectionId}", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/sessions/{sessionId}/connection/{connectionId}", method = RequestMethod.DELETE)
|
||||||
public ResponseEntity<JSONObject> disconnectParticipant(@PathVariable("sessionId") String sessionId,
|
public ResponseEntity<?> disconnectParticipant(@PathVariable("sessionId") String sessionId,
|
||||||
@PathVariable("connectionId") String participantPublicId) {
|
@PathVariable("connectionId") String participantPublicId) {
|
||||||
Session session = this.sessionManager.getSession(sessionId);
|
Session session = this.sessionManager.getSession(sessionId);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
|
@ -196,7 +198,7 @@ public class SessionRestController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/sessions/{sessionId}/stream/{streamId}", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/sessions/{sessionId}/stream/{streamId}", method = RequestMethod.DELETE)
|
||||||
public ResponseEntity<JSONObject> unpublishStream(@PathVariable("sessionId") String sessionId,
|
public ResponseEntity<?> unpublishStream(@PathVariable("sessionId") String sessionId,
|
||||||
@PathVariable("streamId") String streamId) {
|
@PathVariable("streamId") String streamId) {
|
||||||
Session session = this.sessionManager.getSession(sessionId);
|
Session session = this.sessionManager.getSession(sessionId);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
|
@ -210,51 +212,81 @@ public class SessionRestController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @RequestMapping(value = "/sessions/{sessionId}/stream/{streamId}", method =
|
|
||||||
* RequestMethod.PUT) public ResponseEntity<JSONObject>
|
|
||||||
* muteMedia(@PathVariable("sessionId") String sessionId,
|
|
||||||
*
|
|
||||||
* @PathVariable("streamId") String streamId, @RequestBody Map<?, ?> params) { }
|
|
||||||
*/
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@RequestMapping(value = "/tokens", method = RequestMethod.POST)
|
@RequestMapping(value = "/tokens", method = RequestMethod.POST)
|
||||||
public ResponseEntity<JSONObject> newToken(@RequestBody Map<?, ?> params) {
|
public ResponseEntity<String> newToken(@RequestBody Map<?, ?> params) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
String sessionId = (String) params.get("session");
|
String sessionId = (String) params.get("session");
|
||||||
String roleString = (String) params.get("role");
|
String roleString = (String) params.get("role");
|
||||||
String metadata = (String) params.get("data");
|
String metadata = (String) params.get("data");
|
||||||
|
JsonObject kurentoOptions = new JsonParser().parse(params.get("kurentoOptions").toString()).getAsJsonObject();
|
||||||
|
|
||||||
ParticipantRole role;
|
ParticipantRole role;
|
||||||
|
try {
|
||||||
if (roleString != null) {
|
if (roleString != null) {
|
||||||
role = ParticipantRole.valueOf(roleString);
|
role = ParticipantRole.valueOf(roleString);
|
||||||
} else {
|
} else {
|
||||||
role = ParticipantRole.PUBLISHER;
|
role = ParticipantRole.PUBLISHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata = (metadata != null) ? metadata : "";
|
|
||||||
|
|
||||||
String token = sessionManager.newToken(sessionId, role, metadata);
|
|
||||||
JSONObject responseJson = new JSONObject();
|
|
||||||
responseJson.put("id", token);
|
|
||||||
responseJson.put("session", sessionId);
|
|
||||||
responseJson.put("role", role.toString());
|
|
||||||
responseJson.put("data", metadata);
|
|
||||||
responseJson.put("token", token);
|
|
||||||
return new ResponseEntity<>(responseJson, HttpStatus.OK);
|
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
return this.generateErrorResponse("Role " + params.get("role") + " is not defined", "/api/tokens",
|
return this.generateErrorResponse("Role " + params.get("role") + " is not defined", "/api/tokens",
|
||||||
HttpStatus.BAD_REQUEST);
|
HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
KurentoTokenOptions kurentoTokenOptions = null;
|
||||||
|
if (kurentoOptions != null) {
|
||||||
|
try {
|
||||||
|
kurentoTokenOptions = new KurentoTokenOptions(kurentoOptions);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return this.generateErrorResponse("Error in some parameter of 'kurentoOptions'", "/api/tokens",
|
||||||
|
HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata = (metadata != null) ? metadata : "";
|
||||||
|
|
||||||
|
String token = sessionManager.newToken(sessionId, role, metadata, kurentoTokenOptions);
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
responseJson.addProperty("id", token);
|
||||||
|
responseJson.addProperty("session", sessionId);
|
||||||
|
responseJson.addProperty("role", role.toString());
|
||||||
|
responseJson.addProperty("data", metadata);
|
||||||
|
responseJson.addProperty("token", token);
|
||||||
|
|
||||||
|
if (kurentoOptions != null) {
|
||||||
|
JsonObject kurentoOptsResponse = new JsonObject();
|
||||||
|
if (kurentoTokenOptions.getVideoMaxRecvBandwidth() != null) {
|
||||||
|
kurentoOptsResponse.addProperty("videoMaxRecvBandwidth",
|
||||||
|
kurentoTokenOptions.getVideoMaxRecvBandwidth());
|
||||||
|
}
|
||||||
|
if (kurentoTokenOptions.getVideoMinRecvBandwidth() != null) {
|
||||||
|
kurentoOptsResponse.addProperty("videoMinRecvBandwidth",
|
||||||
|
kurentoTokenOptions.getVideoMinRecvBandwidth());
|
||||||
|
}
|
||||||
|
if (kurentoTokenOptions.getVideoMaxSendBandwidth() != null) {
|
||||||
|
kurentoOptsResponse.addProperty("videoMaxSendBandwidth",
|
||||||
|
kurentoTokenOptions.getVideoMaxSendBandwidth());
|
||||||
|
}
|
||||||
|
if (kurentoTokenOptions.getVideoMinSendBandwidth() != null) {
|
||||||
|
kurentoOptsResponse.addProperty("videoMinSendBandwidth",
|
||||||
|
kurentoTokenOptions.getVideoMinSendBandwidth());
|
||||||
|
}
|
||||||
|
if (kurentoTokenOptions.getAllowedFilters().length > 0) {
|
||||||
|
JsonArray filters = new JsonArray();
|
||||||
|
for (String filter : kurentoTokenOptions.getAllowedFilters()) {
|
||||||
|
filters.add(filter);
|
||||||
|
}
|
||||||
|
kurentoOptsResponse.add("allowedFilters", filters);
|
||||||
|
}
|
||||||
|
responseJson.add("kurentoOptions", kurentoOptsResponse);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(responseJson.toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
} catch (OpenViduException e) {
|
} catch (OpenViduException e) {
|
||||||
return this.generateErrorResponse(e.getMessage(), "/api/tokens", HttpStatus.BAD_REQUEST);
|
return this.generateErrorResponse(e.getMessage(), "/api/tokens", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/recordings/start", method = RequestMethod.POST)
|
@RequestMapping(value = "/recordings/start", method = RequestMethod.POST)
|
||||||
public ResponseEntity<JSONObject> startRecordingSession(@RequestBody Map<?, ?> params) {
|
public ResponseEntity<?> startRecordingSession(@RequestBody Map<?, ?> params) {
|
||||||
|
|
||||||
String sessionId = (String) params.get("session");
|
String sessionId = (String) params.get("session");
|
||||||
String name = (String) params.get("name");
|
String name = (String) params.get("name");
|
||||||
|
@ -290,8 +322,8 @@ public class SessionRestController {
|
||||||
RecordingLayout recordingLayout;
|
RecordingLayout recordingLayout;
|
||||||
if (recordingLayoutString == null || recordingLayoutString.isEmpty()) {
|
if (recordingLayoutString == null || recordingLayoutString.isEmpty()) {
|
||||||
// "recordingLayout" parameter not defined. Use global layout from
|
// "recordingLayout" parameter not defined. Use global layout from
|
||||||
// SessionProperties
|
// SessionProperties (it is always configured as it has RecordingLayout.BEST_FIT
|
||||||
// (it is always configured as it has RecordingLayout.BEST_FIT as default value)
|
// as default value)
|
||||||
recordingLayout = session.getSessionProperties().defaultRecordingLayout();
|
recordingLayout = session.getSessionProperties().defaultRecordingLayout();
|
||||||
} else {
|
} else {
|
||||||
recordingLayout = RecordingLayout.valueOf(recordingLayoutString);
|
recordingLayout = RecordingLayout.valueOf(recordingLayoutString);
|
||||||
|
@ -301,11 +333,11 @@ public class SessionRestController {
|
||||||
|
|
||||||
Recording startedRecording = this.recordingService.startRecording(session, new RecordingProperties.Builder()
|
Recording startedRecording = this.recordingService.startRecording(session, new RecordingProperties.Builder()
|
||||||
.name(name).recordingLayout(recordingLayout).customLayout(customLayout).build());
|
.name(name).recordingLayout(recordingLayout).customLayout(customLayout).build());
|
||||||
return new ResponseEntity<>(startedRecording.toJson(), HttpStatus.OK);
|
return new ResponseEntity<>(startedRecording.toJson().toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/recordings/stop/{recordingId}", method = RequestMethod.POST)
|
@RequestMapping(value = "/recordings/stop/{recordingId}", method = RequestMethod.POST)
|
||||||
public ResponseEntity<JSONObject> stopRecordingSession(@PathVariable("recordingId") String recordingId) {
|
public ResponseEntity<?> stopRecordingSession(@PathVariable("recordingId") String recordingId) {
|
||||||
|
|
||||||
if (recordingId == null) {
|
if (recordingId == null) {
|
||||||
// "recordingId" parameter not found
|
// "recordingId" parameter not found
|
||||||
|
@ -335,11 +367,11 @@ public class SessionRestController {
|
||||||
session.getParticipantByPublicId(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID), null, null,
|
session.getParticipantByPublicId(ProtocolElements.RECORDER_PARTICIPANT_PUBLICID), null, null,
|
||||||
"EVICT_RECORDER");
|
"EVICT_RECORDER");
|
||||||
|
|
||||||
return new ResponseEntity<>(stoppedRecording.toJson(), HttpStatus.OK);
|
return new ResponseEntity<>(stoppedRecording.toJson().toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/recordings/{recordingId}", method = RequestMethod.GET)
|
@RequestMapping(value = "/recordings/{recordingId}", method = RequestMethod.GET)
|
||||||
public ResponseEntity<JSONObject> getRecording(@PathVariable("recordingId") String recordingId) {
|
public ResponseEntity<?> getRecording(@PathVariable("recordingId") String recordingId) {
|
||||||
try {
|
try {
|
||||||
Recording recording = this.recordingService.getAllRecordings().stream()
|
Recording recording = this.recordingService.getAllRecordings().stream()
|
||||||
.filter(rec -> rec.getId().equals(recordingId)).findFirst().get();
|
.filter(rec -> rec.getId().equals(recordingId)).findFirst().get();
|
||||||
|
@ -347,18 +379,17 @@ public class SessionRestController {
|
||||||
&& recordingService.getStartingRecording(recording.getId()) != null) {
|
&& recordingService.getStartingRecording(recording.getId()) != null) {
|
||||||
recording.setStatus(Recording.Status.starting);
|
recording.setStatus(Recording.Status.starting);
|
||||||
}
|
}
|
||||||
return new ResponseEntity<>(recording.toJson(), HttpStatus.OK);
|
return new ResponseEntity<>(recording.toJson().toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@RequestMapping(value = "/recordings", method = RequestMethod.GET)
|
@RequestMapping(value = "/recordings", method = RequestMethod.GET)
|
||||||
public ResponseEntity<JSONObject> getAllRecordings() {
|
public ResponseEntity<?> getAllRecordings() {
|
||||||
Collection<Recording> recordings = this.recordingService.getAllRecordings();
|
Collection<Recording> recordings = this.recordingService.getAllRecordings();
|
||||||
JSONObject json = new JSONObject();
|
JsonObject json = new JsonObject();
|
||||||
JSONArray jsonArray = new JSONArray();
|
JsonArray jsonArray = new JsonArray();
|
||||||
recordings.forEach(rec -> {
|
recordings.forEach(rec -> {
|
||||||
if (Recording.Status.started.equals(rec.getStatus())
|
if (Recording.Status.started.equals(rec.getStatus())
|
||||||
&& recordingService.getStartingRecording(rec.getId()) != null) {
|
&& recordingService.getStartingRecording(rec.getId()) != null) {
|
||||||
|
@ -366,24 +397,29 @@ public class SessionRestController {
|
||||||
}
|
}
|
||||||
jsonArray.add(rec.toJson());
|
jsonArray.add(rec.toJson());
|
||||||
});
|
});
|
||||||
json.put("count", recordings.size());
|
json.addProperty("count", recordings.size());
|
||||||
json.put("items", jsonArray);
|
json.add("items", jsonArray);
|
||||||
return new ResponseEntity<>(json, HttpStatus.OK);
|
return new ResponseEntity<>(json.toString(), getResponseHeaders(), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/recordings/{recordingId}", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/recordings/{recordingId}", method = RequestMethod.DELETE)
|
||||||
public ResponseEntity<JSONObject> deleteRecording(@PathVariable("recordingId") String recordingId) {
|
public ResponseEntity<?> deleteRecording(@PathVariable("recordingId") String recordingId) {
|
||||||
return new ResponseEntity<>(this.recordingService.deleteRecordingFromHost(recordingId));
|
return new ResponseEntity<>(this.recordingService.deleteRecordingFromHost(recordingId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
private ResponseEntity<String> generateErrorResponse(String errorMessage, String path, HttpStatus status) {
|
||||||
private ResponseEntity<JSONObject> generateErrorResponse(String errorMessage, String path, HttpStatus status) {
|
JsonObject responseJson = new JsonObject();
|
||||||
JSONObject responseJson = new JSONObject();
|
responseJson.addProperty("timestamp", System.currentTimeMillis());
|
||||||
responseJson.put("timestamp", System.currentTimeMillis());
|
responseJson.addProperty("status", status.value());
|
||||||
responseJson.put("status", status.value());
|
responseJson.addProperty("error", status.getReasonPhrase());
|
||||||
responseJson.put("error", status.getReasonPhrase());
|
responseJson.addProperty("message", errorMessage);
|
||||||
responseJson.put("message", errorMessage);
|
responseJson.addProperty("path", path);
|
||||||
responseJson.put("path", path);
|
return new ResponseEntity<>(responseJson.toString(), getResponseHeaders(), status);
|
||||||
return new ResponseEntity<>(responseJson, status);
|
}
|
||||||
|
|
||||||
|
private HttpHeaders getResponseHeaders() {
|
||||||
|
HttpHeaders responseHeaders = new HttpHeaders();
|
||||||
|
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
return responseHeaders;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
import io.openvidu.client.OpenViduException;
|
import io.openvidu.client.OpenViduException;
|
||||||
import io.openvidu.client.OpenViduException.Code;
|
import io.openvidu.client.OpenViduException.Code;
|
||||||
|
@ -131,6 +132,23 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
||||||
case ProtocolElements.FORCEUNPUBLISH_METHOD:
|
case ProtocolElements.FORCEUNPUBLISH_METHOD:
|
||||||
forceUnpublish(rpcConnection, request);
|
forceUnpublish(rpcConnection, request);
|
||||||
break;
|
break;
|
||||||
|
case ProtocolElements.APPLYFILTER_METHOD:
|
||||||
|
applyFilter(rpcConnection, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.EXECFILTERMETHOD_METHOD:
|
||||||
|
execFilterMethod(rpcConnection, request);
|
||||||
|
break;
|
||||||
|
case ProtocolElements.REMOVEFILTER_METHOD:
|
||||||
|
removeFilter(rpcConnection, request);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* case ProtocolElements.FORCEAPPLYFILTER_METHOD:
|
||||||
|
* forceApplyFilter(rpcConnection, request); break; case
|
||||||
|
* ProtocolElements.FORCEEXECFILTERMETHOD_METHOD:
|
||||||
|
* forceExecFilterMethod(rpcConnection, request); break; case
|
||||||
|
* ProtocolElements.FORCEREMOVEFILTER_METHOD: forceRemoveFilter(rpcConnection,
|
||||||
|
* request); break;
|
||||||
|
*/
|
||||||
default:
|
default:
|
||||||
log.error("Unrecognized request {}", request);
|
log.error("Unrecognized request {}", request);
|
||||||
break;
|
break;
|
||||||
|
@ -291,6 +309,22 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
||||||
sessionManager.unpublishVideo(participant, null, request.getId(), "unpublish");
|
sessionManager.unpublishVideo(participant, null, request.getId(), "unpublish");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void streamPropertyChanged(RpcConnection rpcConnection, Request<JsonObject> request) {
|
||||||
|
Participant participant;
|
||||||
|
try {
|
||||||
|
participant = sanityCheckOfSession(rpcConnection, "onStreamPropertyChanged");
|
||||||
|
} catch (OpenViduException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String streamId = getStringParam(request, ProtocolElements.STREAMPROPERTYCHANGED_STREAMID_PARAM);
|
||||||
|
String property = getStringParam(request, ProtocolElements.STREAMPROPERTYCHANGED_PROPERTY_PARAM);
|
||||||
|
JsonElement newValue = getParam(request, ProtocolElements.STREAMPROPERTYCHANGED_NEWVALUE_PARAM);
|
||||||
|
String reason = getStringParam(request, ProtocolElements.STREAMPROPERTYCHANGED_REASON_PARAM);
|
||||||
|
|
||||||
|
sessionManager.streamPropertyChanged(participant, request.getId(), streamId, property, newValue, reason);
|
||||||
|
}
|
||||||
|
|
||||||
private void forceDisconnect(RpcConnection rpcConnection, Request<JsonObject> request) {
|
private void forceDisconnect(RpcConnection rpcConnection, Request<JsonObject> request) {
|
||||||
Participant participant;
|
Participant participant;
|
||||||
try {
|
try {
|
||||||
|
@ -331,20 +365,51 @@ public class RpcHandler extends DefaultJsonRpcHandler<JsonObject> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void streamPropertyChanged(RpcConnection rpcConnection, Request<JsonObject> request) {
|
private void applyFilter(RpcConnection rpcConnection, Request<JsonObject> request) {
|
||||||
Participant participant;
|
Participant participant;
|
||||||
try {
|
try {
|
||||||
participant = sanityCheckOfSession(rpcConnection, "onStreamPropertyChanged");
|
participant = sanityCheckOfSession(rpcConnection, "applyFilter");
|
||||||
} catch (OpenViduException e) {
|
} catch (OpenViduException e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String streamId = getStringParam(request, ProtocolElements.STREAMPROPERTYCHANGED_STREAMID_PARAM);
|
String filterType = getStringParam(request, ProtocolElements.FILTER_TYPE_PARAM);
|
||||||
String property = getStringParam(request, ProtocolElements.STREAMPROPERTYCHANGED_PROPERTY_PARAM);
|
if (participant.getToken().getKurentoTokenOptions().isFilterAllowed(filterType)) {
|
||||||
JsonElement newValue = getParam(request, ProtocolElements.STREAMPROPERTYCHANGED_NEWVALUE_PARAM);
|
JsonObject filterOptions = new JsonParser().parse(getStringParam(request, ProtocolElements.FILTER_OPTIONS_PARAM))
|
||||||
String reason = getStringParam(request, ProtocolElements.STREAMPROPERTYCHANGED_REASON_PARAM);
|
.getAsJsonObject();
|
||||||
|
String streamId = getStringParam(request, ProtocolElements.FILTER_STREAMID_PARAM);
|
||||||
|
sessionManager.applyFilter(sessionManager.getSession(rpcConnection.getSessionId()), streamId, filterType,
|
||||||
|
filterOptions, null, request.getId(), "applyFilter");
|
||||||
|
} else {
|
||||||
|
log.error("Error: participant {} is not a moderator", participant.getParticipantPublicId());
|
||||||
|
throw new OpenViduException(Code.USER_UNAUTHORIZED_ERROR_CODE,
|
||||||
|
"Unable to apply filter. The user does not have a valid token");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sessionManager.streamPropertyChanged(participant, request.getId(), streamId, property, newValue, reason);
|
private void execFilterMethod(RpcConnection rpcConnection, Request<JsonObject> request) {
|
||||||
|
try {
|
||||||
|
sanityCheckOfSession(rpcConnection, "applyFilter");
|
||||||
|
} catch (OpenViduException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String filterMethod = getStringParam(request, ProtocolElements.FILTER_METHOD_PARAM);
|
||||||
|
JsonObject filterParams = new JsonParser().parse(getStringParam(request, ProtocolElements.FILTER_PARAMS_PARAM))
|
||||||
|
.getAsJsonObject();
|
||||||
|
String streamId = getStringParam(request, ProtocolElements.FILTER_STREAMID_PARAM);
|
||||||
|
sessionManager.execFilterMethod(sessionManager.getSession(rpcConnection.getSessionId()), streamId, filterMethod,
|
||||||
|
filterParams, null, request.getId(), "execFilterMethod");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeFilter(RpcConnection rpcConnection, Request<JsonObject> request) {
|
||||||
|
try {
|
||||||
|
sanityCheckOfSession(rpcConnection, "removeFilter");
|
||||||
|
} catch (OpenViduException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String streamId = getStringParam(request, ProtocolElements.FILTER_STREAMID_PARAM);
|
||||||
|
sessionManager.removeFilter(sessionManager.getSession(rpcConnection.getSessionId()), streamId, null,
|
||||||
|
request.getId(), "removeFilter");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void leaveRoomAfterConnClosed(String participantPrivateId, String reason) {
|
public void leaveRoomAfterConnClosed(String participantPrivateId, String reason) {
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2017-2018 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.utils;
|
||||||
|
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.kurento.jsonrpc.Props;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class JsonUtils {
|
||||||
|
|
||||||
|
public Props fromJsonObjectToProps(JsonObject params) {
|
||||||
|
Props props = new Props();
|
||||||
|
for (Entry<String, JsonElement> entry : params.entrySet()) {
|
||||||
|
if (entry.getValue().isJsonPrimitive()) {
|
||||||
|
props.add(entry.getKey(), entry.getValue().getAsString());
|
||||||
|
} else if (entry.getValue().isJsonObject()) {
|
||||||
|
props.add(entry.getKey(), fromJsonObjectToProps(entry.getValue().getAsJsonObject()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue