Trigger recordingStarted event for new connected participants

pull/730/head
pabloFuente 2022-05-27 11:13:12 +02:00
parent df7bd5f202
commit 8d3fe2b681
10 changed files with 102 additions and 30 deletions

View File

@ -1436,6 +1436,10 @@ export class Session extends EventDispatcher {
this.ee.emitEvent('streamCreated', [new StreamEvent(false, this, 'streamCreated', stream, '')]);
});
if (!!response.recordingId && !!response.recordingName) {
this.ee.emitEvent('recordingStarted', [new RecordingEvent(this, 'recordingStarted', response.recordingId, response.recordingName)]);
}
return resolve();
}
});

View File

@ -36,5 +36,7 @@ export interface LocalConnectionOptions {
mediaServer: string;
videoSimulcast: boolean;
life: number;
customIceServers?: IceServerProperties[]
customIceServers?: IceServerProperties[];
recordingId?: string; // Defined if the session is being recorded and the client must be notified
recordingName?: string; // Defined if the session is being recorded and the client must be notified
}

View File

@ -166,6 +166,8 @@ public class ProtocolElements {
public static final String PARTICIPANTJOINED_CUSTOM_ICE_SERVERS = "customIceServers";
public static final String PARTICIPANTJOINED_TURNUSERNAME_PARAM = "turnUsername";
public static final String PARTICIPANTJOINED_TURNCREDENTIAL_PARAM = "turnCredential";
public static final String PARTICIPANTJOINED_RECORDINGID_PARAM = "recordingId";
public static final String PARTICIPANTJOINED_RECORDINGNAME_PARAM = "recordingName";
public static final String PARTICIPANTLEFT_METHOD = "participantLeft";
public static final String PARTICIPANTLEFT_NAME_PARAM = "connectionId";

View File

@ -32,10 +32,11 @@ import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Set;
import javax.annotation.PostConstruct;
@ -413,23 +414,26 @@ public class OpenviduConfig {
return this.mediaNodesPublicIps;
}
public OpenViduRole[] getRolesFromRecordingNotification() {
OpenViduRole[] roles;
public Set<OpenViduRole> getRolesFromRecordingNotification() {
Set<OpenViduRole> roles = new HashSet<>();
switch (this.openviduRecordingNotification) {
case none:
roles = new OpenViduRole[0];
break;
case moderator:
roles = new OpenViduRole[] { OpenViduRole.MODERATOR };
roles.add(OpenViduRole.MODERATOR);
break;
case publisher_moderator:
roles = new OpenViduRole[] { OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
roles.add(OpenViduRole.PUBLISHER);
roles.add(OpenViduRole.MODERATOR);
break;
case all:
roles = new OpenViduRole[] { OpenViduRole.SUBSCRIBER, OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
roles.add(OpenViduRole.SUBSCRIBER);
roles.add(OpenViduRole.PUBLISHER);
roles.add(OpenViduRole.MODERATOR);
break;
default:
roles = new OpenViduRole[] { OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
roles.add(OpenViduRole.PUBLISHER);
roles.add(OpenViduRole.MODERATOR);
}
return roles;
}
@ -547,7 +551,8 @@ public class OpenviduConfig {
protected List<String> getNonUserProperties() {
return Arrays.asList("server.port", "SERVER_PORT", "DOTENV_PATH", "COTURN_IP", "COTURN_PORT",
"COTURN_INTERNAL_RELAY", "COTURN_SHARED_SECRET_KEY", "OPENVIDU_RECORDING_IMAGE", "OPENVIDU_RECORDING_ENABLE_GPU");
"COTURN_INTERNAL_RELAY", "COTURN_SHARED_SECRET_KEY", "OPENVIDU_RECORDING_IMAGE",
"OPENVIDU_RECORDING_ENABLE_GPU");
}
protected List<String> getNonPrintablePropertiesIfEmpty() {

View File

@ -74,8 +74,8 @@ public class SessionEventsHandler {
CDR.recordSessionDestroyed(session, reason);
}
public void onParticipantJoined(Participant participant, String sessionId, String coturnIp, Set<Participant> existingParticipants,
Integer transactionId, OpenViduException error) {
public void onParticipantJoined(Participant participant, Recording recording, String coturnIp,
Set<Participant> existingParticipants, Integer transactionId, OpenViduException error) {
if (error != null) {
rpcNotificationService.sendErrorResponse(participant.getParticipantPrivateId(), transactionId, null, error);
return;
@ -179,7 +179,9 @@ public class SessionEventsHandler {
}
if (participant.getToken() != null) {
result.addProperty(ProtocolElements.PARTICIPANTJOINED_RECORD_PARAM, participant.getToken().record());
if (participant.getToken().getRole() != null) {
result.addProperty(ProtocolElements.PARTICIPANTJOINED_ROLE_PARAM,
participant.getToken().getRole().name());
@ -198,6 +200,11 @@ public class SessionEventsHandler {
result.addProperty(ProtocolElements.PARTICIPANTJOINED_TURNCREDENTIAL_PARAM,
participant.getToken().getTurnCredentials().getCredential());
}
if (recording != null) {
result.addProperty(ProtocolElements.PARTICIPANTJOINED_RECORDINGID_PARAM, recording.getId());
result.addProperty(ProtocolElements.PARTICIPANTJOINED_RECORDINGNAME_PARAM, recording.getName());
}
}
rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, result);
@ -680,18 +687,12 @@ public class SessionEventsHandler {
recordingsToSendClientEvents.put(recording.getSessionId(), recording);
}
protected Set<Participant> filterParticipantsByRole(OpenViduRole[] roles, Set<Participant> participants) {
protected Set<Participant> filterParticipantsByRole(Set<OpenViduRole> roles, Set<Participant> participants) {
return participants.stream().filter(part -> {
if (ProtocolElements.RECORDER_PARTICIPANT_PUBLICID.equals(part.getParticipantPublicId())) {
return false;
}
boolean isRole = false;
for (OpenViduRole role : roles) {
isRole = role.equals(part.getToken().getRole());
if (isRole)
break;
}
return isRole;
return roles.contains(part.getToken().getRole());
}).collect(Collectors.toSet());
}

View File

@ -136,7 +136,7 @@ public class KurentoSessionManager extends SessionManager {
String error = "Timeout of " + KmsManager.MAX_SECONDS_LOCK_WAIT
+ " seconds waiting to acquire lock";
log.error(error);
sessionEventsHandler.onParticipantJoined(participant, sessionId, null, null, transactionId,
sessionEventsHandler.onParticipantJoined(participant, null, null, null, transactionId,
new OpenViduException(Code.ROOM_CANNOT_BE_CREATED_ERROR_CODE, error));
return;
}
@ -169,7 +169,11 @@ public class KurentoSessionManager extends SessionManager {
existingParticipants = getParticipants(sessionId);
kSession.join(participant);
String coturnIp = openviduConfig.getCoturnIp(kSession.getKms().getUri());
sessionEventsHandler.onParticipantJoined(participant, sessionId, coturnIp, existingParticipants,
io.openvidu.server.recording.Recording recording = getActiveRecordingIfAllowedByParticipantRole(
participant);
sessionEventsHandler.onParticipantJoined(participant, recording, coturnIp, existingParticipants,
transactionId, null);
} finally {
kSession.joinLeaveLock.unlock();
@ -178,21 +182,21 @@ public class KurentoSessionManager extends SessionManager {
log.error(
"Timeout waiting for join-leave Session lock to be available for participant {} of session {} in joinRoom",
participant.getParticipantPublicId(), sessionId);
sessionEventsHandler.onParticipantJoined(participant, sessionId, null, null, transactionId,
sessionEventsHandler.onParticipantJoined(participant, null, null, null, transactionId,
new OpenViduException(Code.GENERIC_ERROR_CODE, "Timeout waiting for Session lock"));
}
} catch (InterruptedException e) {
log.error(
"InterruptedException waiting for join-leave Session lock to be available for participant {} of session {} in joinRoom",
participant.getParticipantPublicId(), sessionId);
sessionEventsHandler.onParticipantJoined(participant, sessionId, null,null, transactionId,
sessionEventsHandler.onParticipantJoined(participant, null, null, null, transactionId,
new OpenViduException(Code.GENERIC_ERROR_CODE,
"InterruptedException waiting for Session lock"));
}
} catch (OpenViduException e) {
log.error("PARTICIPANT {}: Error joining/creating session {}", participant.getParticipantPublicId(),
sessionId, e);
sessionEventsHandler.onParticipantJoined(participant, sessionId, null,null, transactionId, e);
sessionEventsHandler.onParticipantJoined(participant, null, null, null, transactionId, e);
}
}
@ -1406,6 +1410,16 @@ public class KurentoSessionManager extends SessionManager {
return lessLoadedKms;
}
private io.openvidu.server.recording.Recording getActiveRecordingIfAllowedByParticipantRole(
Participant participant) {
io.openvidu.server.recording.Recording recording = null;
if (participant.getToken() != null && this.recordingManager.sessionIsBeingRecorded(participant.getSessionId())
&& this.openviduConfig.getRolesFromRecordingNotification().contains(participant.getToken().getRole())) {
recording = this.recordingManager.getActiveRecordingForSession(participant.getSessionId());
}
return recording;
}
@PreDestroy
@Override
public void close() {

View File

@ -492,6 +492,14 @@ public class RecordingManager {
|| this.sessionsRecordingsStarting.get(sessionId) != null);
}
public Recording getActiveRecordingForSession(String sessionId) {
Recording recording = this.sessionsRecordings.get(sessionId);
if (recording == null) {
recording = this.sessionsRecordingsStarting.get(sessionId);
}
return recording;
}
public boolean sessionIsBeingRecordedIndividual(String sessionId) {
if (!sessionIsBeingRecorded(sessionId)) {
return false;

View File

@ -167,8 +167,8 @@ public class WebhookIntegrationTest {
// Client should have already received "connectionCreated" RPC response
// nonetheless
verify(sessionEventsHandler, times(1)).onParticipantJoined(refEq(participant), anyString(), anyString(), anySet(),
anyInt(), refEq(null));
verify(sessionEventsHandler, times(1)).onParticipantJoined(refEq(participant), refEq(null), anyString(),
anySet(), anyInt(), refEq(null));
// Now webhook response for event "participantJoined" should be received
CustomWebhook.waitForEvent("participantJoined", 1000, TimeUnit.MILLISECONDS);

View File

@ -255,7 +255,7 @@ public class OpenViduEventManager {
return success;
}
private AtomicInteger getNumEvents(String eventName) {
public AtomicInteger getNumEvents(String eventName) {
return this.eventNumbers.computeIfAbsent(eventName, k -> new AtomicInteger(0));
}

View File

@ -1185,7 +1185,43 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getEventManager().waitUntilEventReaches("recordingStarted", 1);
Thread.sleep(5000);
Thread.sleep(3000);
user.getDriver().findElement(By.id("close-dialog-btn")).click();
Thread.sleep(500);
// A new user with PUBLISHER role should trigger recordingStarted event
user.getDriver().findElement(By.id("add-user-btn")).click();
user.getDriver().findElement(By.id("session-name-input-1")).clear();
user.getDriver().findElement(By.id("session-name-input-1")).sendKeys(sessionName);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .publish-checkbox")).click();
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .subscribe-checkbox")).click();
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .join-btn")).click();
user.getEventManager().waitUntilEventReaches("connectionCreated", 4);
user.getEventManager().waitUntilEventReaches("streamCreated", 2);
user.getEventManager().waitUntilEventReaches("recordingStarted", 2);
// A new user with SUBSCRIBER role should not trigger recordingStarted event
user.getDriver().findElement(By.id("add-user-btn")).click();
user.getDriver().findElement(By.id("session-name-input-2")).clear();
user.getDriver().findElement(By.id("session-name-input-2")).sendKeys(sessionName);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-2 .publish-checkbox")).click();
user.getDriver().findElement(By.cssSelector("#openvidu-instance-2 .subscribe-checkbox")).click();
user.getDriver().findElement(By.id("session-settings-btn-2")).click();
Thread.sleep(500);
user.getDriver().findElement(By.id("radio-btn-sub")).click();
user.getDriver().findElement(By.id("save-btn")).click();
Thread.sleep(500);
user.getDriver().findElement(By.cssSelector("#openvidu-instance-2 .join-btn")).click();
user.getEventManager().waitUntilEventReaches("connectionCreated", 9);
user.getEventManager().waitUntilEventReaches("streamCreated", 3);
// No third recordingStarted event should be triggered for the SUBSCRIBER user
Thread.sleep(3000);
Assert.assertEquals(user.getEventManager().getNumEvents("recordingStarted").intValue(), 2);
user.getDriver().findElement(By.id("session-api-btn-0")).click();
Thread.sleep(500);
user.getDriver().findElement(By.id("recording-id-field")).clear();
user.getDriver().findElement(By.id("recording-id-field")).sendKeys(sessionName);
@ -1256,7 +1292,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getDriver().findElement(By.id("close-dialog-btn")).click();
Thread.sleep(500);
gracefullyLeaveParticipants(user, 1);
gracefullyLeaveParticipants(user, 3);
}
@Test