diff --git a/openvidu-browser/src/OpenVidu/OpenVidu.ts b/openvidu-browser/src/OpenVidu/OpenVidu.ts index 1c7d3a99..7fba9b27 100644 --- a/openvidu-browser/src/OpenVidu/OpenVidu.ts +++ b/openvidu-browser/src/OpenVidu/OpenVidu.ts @@ -866,6 +866,8 @@ export class OpenVidu { participantEvicted: this.session.onParticipantEvicted.bind(this.session), recordingStarted: this.session.onRecordingStarted.bind(this.session), recordingStopped: this.session.onRecordingStopped.bind(this.session), + broadcastStarted: this.session.onBroadcastStarted.bind(this.session), + broadcastStopped: this.session.onBroadcastStopped.bind(this.session), sendMessage: this.session.onNewMessage.bind(this.session), streamPropertyChanged: this.session.onStreamPropertyChanged.bind(this.session), connectionPropertyChanged: this.session.onConnectionPropertyChanged.bind(this.session), diff --git a/openvidu-browser/src/OpenVidu/Session.ts b/openvidu-browser/src/OpenVidu/Session.ts index 06293a65..ed87035e 100644 --- a/openvidu-browser/src/OpenVidu/Session.ts +++ b/openvidu-browser/src/OpenVidu/Session.ts @@ -1184,11 +1184,7 @@ export class Session extends EventDispatcher { logger.error('Media error: ' + JSON.stringify(event)); const err = event.error; if (err) { - this.ee.emitEvent('error-media', [ - { - error: err - } - ]); + this.ee.emitEvent('error-media', [{ error: err }]); } else { logger.warn('Received undefined media error:', event); } @@ -1208,6 +1204,20 @@ export class Session extends EventDispatcher { this.ee.emitEvent('recordingStopped', [new RecordingEvent(this, 'recordingStopped', event.id, event.name, event.reason)]); } + /** + * @hidden + */ + onBroadcastStarted(): void { + this.ee.emitEvent('broadcastStarted', []); + } + + /** + * @hidden + */ + onBroadcastStopped(): void { + this.ee.emitEvent('broadcastStopped', []); + } + /** * @hidden */ diff --git a/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts b/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts index dedc5094..b52b116e 100644 --- a/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts +++ b/openvidu-browser/src/OpenViduInternal/Events/EventMap/SessionEventMap.ts @@ -143,7 +143,7 @@ export interface SessionEventMap extends EventMap { /** * Event dispatched when the session has started being recorded. * - * Property **`OPENVIDU_RECORDING_NOTIFICATION`** of [OpenVidu Server configuration](/en/stable/reference-docs/openvidu-config/) + * Property **`OPENVIDU_RECORDING_NOTIFICATION`** of [the OpenVidu deployment configuration](/en/stable/reference-docs/openvidu-config/) * defines which users should receive this events (by default, only users with role `PUBLISHER` or `MODERATOR`) */ recordingStarted: RecordingEvent; @@ -151,11 +151,33 @@ export interface SessionEventMap extends EventMap { /** * Event dispatched when the session has stopped being recorded. * - * Property **`OPENVIDU_RECORDING_NOTIFICATION`** of [OpenVidu Server configuration](/en/stable/reference-docs/openvidu-config/) + * Property **`OPENVIDU_RECORDING_NOTIFICATION`** of [the OpenVidu deployment configuration](/en/stable/reference-docs/openvidu-config/) * defines which users should receive this events (by default, only users with role `PUBLISHER` or `MODERATOR`) */ recordingStopped: RecordingEvent; + /** + * **This feature is part of OpenVidu + * PRO + * and + * ENTERPRISE + * editions** + * + * Event dispatched when the session has started being broadcasted. See [Broadcasting to YouTube/Twitch](/en/stable/advanced-features/broadcasting/) + */ + broadcastStarted: never; + + /** + * **This feature is part of OpenVidu + * PRO + * and + * ENTERPRISE + * editions** + * + * Event dispatched when the session has stopped being broadcasted. See [Broadcasting to YouTube/Twitch](/en/stable/advanced-features/broadcasting/) + */ + broadcastStopped: never; + /** * **This feature is part of OpenVidu * PRO diff --git a/openvidu-client/src/main/java/io/openvidu/client/OpenViduException.java b/openvidu-client/src/main/java/io/openvidu/client/OpenViduException.java index b2445129..aaa9e96e 100644 --- a/openvidu-client/src/main/java/io/openvidu/client/OpenViduException.java +++ b/openvidu-client/src/main/java/io/openvidu/client/OpenViduException.java @@ -50,7 +50,7 @@ public class OpenViduException extends JsonRpcErrorException { SIGNAL_FORMAT_INVALID_ERROR_CODE(600), SIGNAL_TO_INVALID_ERROR_CODE(601), - RTMP_START_ERROR_CODE(710), DOCKER_NOT_FOUND(709), RECORDING_PATH_NOT_VALID(708), RECORDING_FILE_EMPTY_ERROR(707), + BROADCAST_START_ERROR_CODE(710), DOCKER_NOT_FOUND(709), RECORDING_PATH_NOT_VALID(708), RECORDING_FILE_EMPTY_ERROR(707), RECORDING_DELETE_ERROR_CODE(706), RECORDING_LIST_ERROR_CODE(705), RECORDING_STOP_ERROR_CODE(704), RECORDING_START_ERROR_CODE(703), RECORDING_REPORT_ERROR_CODE(702), RECORDING_COMPLETION_ERROR_CODE(701), diff --git a/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java b/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java index f9853d32..a5e2ea99 100644 --- a/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java +++ b/openvidu-client/src/main/java/io/openvidu/client/internal/ProtocolElements.java @@ -229,6 +229,10 @@ public class ProtocolElements { public static final String RECORDINGSTOPPED_METHOD = "recordingStopped"; public static final String RECORDINGSTOPPED_ID_PARAM = "id"; + public static final String BROADCASTSTARTED_METHOD = "broadcastStarted"; + + public static final String BROADCASTSTOPPED_METHOD = "broadcastStopped"; + public static final String SPEECHTOTEXTMESSAGE_METHOD = "speechToTextMessage"; public static final String SPEECHTOTEXTMESSAGE_TIMESTAMP_PARAM = "timestamp"; public static final String SPEECHTOTEXTMESSAGE_SESSIONID_PARAM = "sessionId"; diff --git a/openvidu-server/docker/openvidu-recording/Dockerfile b/openvidu-server/docker/openvidu-recording/Dockerfile index 10a04940..19f28c2e 100644 --- a/openvidu-server/docker/openvidu-recording/Dockerfile +++ b/openvidu-server/docker/openvidu-recording/Dockerfile @@ -31,12 +31,12 @@ RUN adduser root pulse-access # Clean RUN apt clean && apt autoclean && apt autoremove -COPY entrypoint.sh scripts/composed.sh scripts/composed_quick_start.sh scripts/rtmp.sh ./ +COPY entrypoint.sh scripts/composed.sh scripts/composed_quick_start.sh scripts/broadcast.sh ./ COPY utils/xvfb-run-safe /usr/local/bin COPY utils/headless-chrome.sh ./ # Prepare scripts and folders -RUN chmod +x /entrypoint.sh /composed.sh /composed_quick_start.sh /rtmp.sh /headless-chrome.sh \ +RUN chmod +x /entrypoint.sh /composed.sh /composed_quick_start.sh /broadcast.sh /headless-chrome.sh \ && chmod +x /usr/local/bin/xvfb-run-safe \ && mkdir /recordings \ && chmod 777 /recordings diff --git a/openvidu-server/docker/openvidu-recording/create_image.sh b/openvidu-server/docker/openvidu-recording/create_image.sh index bfea44fe..1f8b531a 100755 --- a/openvidu-server/docker/openvidu-recording/create_image.sh +++ b/openvidu-server/docker/openvidu-recording/create_image.sh @@ -1,6 +1,6 @@ #!/bin/bash -x -# eg: $ ./create_image.sh 109.0.5414.74-1 2.25.0 +# eg: $ ./create_image.sh 109.0.5414.119-1 2.25.0 OPENVIDU_RECORDING_CHROME_VERSION=$1 # https://www.ubuntuupdates.org/package_logs?noppa=&page=1&type=ppas&vals=8# OPENVIDU_RECORDING_DOCKER_TAG=$2 docker build --rm --pull --no-cache \ diff --git a/openvidu-server/docker/openvidu-recording/entrypoint.sh b/openvidu-server/docker/openvidu-recording/entrypoint.sh index 07453464..d2fca7a6 100755 --- a/openvidu-server/docker/openvidu-recording/entrypoint.sh +++ b/openvidu-server/docker/openvidu-recording/entrypoint.sh @@ -14,8 +14,8 @@ else ./composed.sh elif [[ "${CONTAINER_WORKING_MODE}" == "COMPOSED_QUICK_START" ]]; then ./composed_quick_start.sh - elif [[ "${CONTAINER_WORKING_MODE}" == "RTMP" ]]; then - ./rtmp.sh + elif [[ "${CONTAINER_WORKING_MODE}" == "BROADCAST" ]]; then + ./broadcast.sh fi fi \ No newline at end of file diff --git a/openvidu-server/docker/openvidu-recording/scripts/rtmp.sh b/openvidu-server/docker/openvidu-recording/scripts/broadcast.sh similarity index 88% rename from openvidu-server/docker/openvidu-recording/scripts/rtmp.sh rename to openvidu-server/docker/openvidu-recording/scripts/broadcast.sh index 1bf7a1df..7c1c602c 100644 --- a/openvidu-server/docker/openvidu-recording/scripts/rtmp.sh +++ b/openvidu-server/docker/openvidu-recording/scripts/broadcast.sh @@ -10,14 +10,14 @@ fi ### Variables ### - RTMP_URL=${RTMP_URL} + BROADCAST_URL=${BROADCAST_URL} URL=${URL:-https://www.youtube.com/watch?v=JMuzlEQz3uo} RESOLUTION=${RESOLUTION:-1920x1080} FRAMERATE=${FRAMERATE:-25} WIDTH="$(cut -d'x' -f1 <<<$RESOLUTION)" HEIGHT="$(cut -d'x' -f2 <<<$RESOLUTION)" - export RTMP_URL + export BROADCAST_URL export URL export RESOLUTION export FRAMERATE @@ -34,9 +34,9 @@ fi source /headless-chrome.sh - ### Run RTMP command ### + ### Run broadcast command ### - eval "$RTMP_COMMAND" + eval "$BROADCAST_COMMAND" } 2>&1 | tee -a /tmp/container.log diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java b/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java index 82095363..7ca7a250 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/Participant.java @@ -229,12 +229,12 @@ public class Participant { return ProtocolElements.STT_PARTICIPANT_PUBLICID.equals(this.participantPublicId); } - public boolean isRtmpParticipant() { + public boolean isBroadcastParticipant() { return isRecorderParticipant(); } - public boolean isRecorderOrSttOrRtmpParticipant() { - return (this.isRecorderParticipant() || this.isSttParticipant() || this.isRtmpParticipant()); + public boolean isRecorderOrSttOrBroadcastParticipant() { + return (this.isRecorderParticipant() || this.isSttParticipant() || this.isBroadcastParticipant()); } public String getPublisherStreamId() { diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/Session.java b/openvidu-server/src/main/java/io/openvidu/server/core/Session.java index c291b445..24100d3e 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/Session.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/Session.java @@ -139,8 +139,8 @@ public class Session implements SessionInterface { return null; } - public boolean onlyRecorderAndOrSttAndOrRtmpParticipant() { - return this.participants.values().stream().allMatch(p -> p.isRecorderOrSttOrRtmpParticipant()); + public boolean onlyRecorderAndOrSttAndOrBroadcastParticipant() { + return this.participants.values().stream().allMatch(p -> p.isRecorderOrSttOrBroadcastParticipant()); } public int getActivePublishers() { @@ -218,8 +218,8 @@ public class Session implements SessionInterface { Set snapshotOfActiveConnections = this.getParticipants().stream().collect(Collectors.toSet()); JsonArray jsonArray = new JsonArray(); snapshotOfActiveConnections.forEach(participant -> { - // Filter RECORDER/STT/RTMP participants - if (!participant.isRecorderOrSttOrRtmpParticipant()) { + // Filter RECORDER/STT/BROADCAST participants + if (!participant.isRecorderOrSttOrBroadcastParticipant()) { jsonArray.add(withWebrtcStats ? participant.withStatsToJson() : participant.toJson()); } }); diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java index 427fe45f..91d8b55e 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionEventsHandler.java @@ -130,16 +130,16 @@ public class SessionEventsHandler { participantJson.add(ProtocolElements.JOINROOM_PEERSTREAMS_PARAM, streamsArray); } - // Avoid emitting 'connectionCreated' event of existing RECORDER/STT/RTMP + // Avoid emitting 'connectionCreated' event of existing RECORDER/STT/BROADCAST // participant in openvidu-browser in newly joined participants - if (!existingParticipant.isRecorderOrSttOrRtmpParticipant()) { + if (!existingParticipant.isRecorderOrSttOrBroadcastParticipant()) { resultArray.add(participantJson); } - // If RECORDER/STT/RTMP participant has joined do NOT send 'participantJoined' + // If RECORDER/STT/BROADCAST participant has joined do NOT send 'participantJoined' // notification to existing participants. 'recordingStarted' will be sent to all // existing participants when recorder first subscribe to a stream - if (!participant.isRecorderOrSttOrRtmpParticipant()) { + if (!participant.isRecorderOrSttOrBroadcastParticipant()) { JsonObject notifParams = new JsonObject(); // Metadata associated to new participant @@ -519,8 +519,8 @@ public class SessionEventsHandler { evictedParticipant.getParticipantPublicId()); params.addProperty(ProtocolElements.PARTICIPANTEVICTED_REASON_PARAM, reason != null ? reason.name() : ""); - if (evictedParticipant.isRecorderOrSttOrRtmpParticipant()) { - // Do not send a message when evicting RECORDER/STT/RTMP participant + if (evictedParticipant.isRecorderOrSttOrBroadcastParticipant()) { + // Do not send a message when evicting RECORDER/STT/BROADCAST participant rpcNotificationService.sendNotification(evictedParticipant.getParticipantPrivateId(), ProtocolElements.PARTICIPANTEVICTED_METHOD, params); } @@ -719,7 +719,7 @@ public class SessionEventsHandler { protected Set filterParticipantsByRole(Set roles, Set participants) { return participants.stream().filter(part -> { - if (part.isRecorderOrSttOrRtmpParticipant()) { + if (part.isRecorderOrSttOrBroadcastParticipant()) { return false; } return roles.contains(part.getToken().getRole()); diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java index 83040a84..6bf5fbdb 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java @@ -192,7 +192,7 @@ public abstract class SessionManager { public abstract void onUnsubscribeFromSpeechToText(Participant participant, Integer transactionId, String connectionId); - public abstract void stopRtmpIfNecessary(Session session); + public abstract void stopBroadcastIfNecessary(Session session); public void onEcho(String participantPrivateId, Integer requestId) { sessionEventsHandler.onEcho(participantPrivateId, requestId); diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java index 3d274bcb..add645eb 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java @@ -283,7 +283,7 @@ public class KurentoParticipant extends Participant { String sdpAnswer = subscriber.subscribe(sdpString, kSender.getPublisher()); log.info("PARTICIPANT {}: Is now receiving video from {} in room {}", this.getParticipantPublicId(), senderName, this.session.getSessionId()); - if (!silent && !this.isRecorderOrSttOrRtmpParticipant()) { + if (!silent && !this.isRecorderOrSttOrBroadcastParticipant()) { endpointConfig.getCdr().recordNewSubscriber(this, sender.getPublisherStreamId(), sender.getParticipantPublicId(), subscriber.createdAt()); } @@ -589,7 +589,7 @@ public class KurentoParticipant extends Participant { } } - if (!this.isRecorderOrSttOrRtmpParticipant()) { + if (!this.isRecorderOrSttOrBroadcastParticipant()) { endpointConfig.getCdr().stopSubscriber(this.getParticipantPublicId(), senderName, subscriber.getStreamId(), reason); } diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java index 689b3147..a097606e 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java @@ -86,7 +86,7 @@ public class KurentoSession extends Session { log.info("SESSION {}: Added participant {}", sessionId, participant); - if (!participant.isRecorderOrSttOrRtmpParticipant()) { + if (!participant.isRecorderOrSttOrBroadcastParticipant()) { kurentoEndpointConfig.getCdr().recordParticipantJoined(participant, sessionId); } } @@ -386,7 +386,7 @@ public class KurentoSession extends Session { public int getNumberOfWebrtcConnections() { return this.getActivePublishers() - + this.participants.values().stream().filter(p -> !p.isRecorderOrSttOrRtmpParticipant()) + + this.participants.values().stream().filter(p -> !p.isRecorderOrSttOrBroadcastParticipant()) .mapToInt(p -> ((KurentoParticipant) p).getSubscribers().size()).reduce(0, Integer::sum); } diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java index f3609098..ae737af1 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java +++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java @@ -300,7 +300,7 @@ public class KurentoSessionManager extends SessionManager { boolean recordingParticipantLeft = remainingParticipants.size() > 0 && remainingParticipants.stream() - .allMatch(p -> p.isRecorderOrSttOrRtmpParticipant()) + .allMatch(p -> p.isRecorderOrSttOrBroadcastParticipant()) && remainingParticipants.stream().anyMatch(p -> p.isRecorderParticipant()); if (recordingParticipantLeft) { @@ -323,13 +323,13 @@ public class KurentoSessionManager extends SessionManager { } } - boolean rtmpParticipantLeft = remainingParticipants.size() > 0 + boolean broadcastParticipantLeft = remainingParticipants.size() > 0 && remainingParticipants.stream() - .allMatch(p -> p.isRecorderOrSttOrRtmpParticipant()) - && remainingParticipants.stream().anyMatch(p -> p.isRtmpParticipant()); + .allMatch(p -> p.isRecorderOrSttOrBroadcastParticipant()) + && remainingParticipants.stream().anyMatch(p -> p.isBroadcastParticipant()); - if (rtmpParticipantLeft) { - this.stopRtmpIfNecessary(session); + if (broadcastParticipantLeft) { + this.stopBroadcastIfNecessary(session); } } } @@ -1425,7 +1425,7 @@ public class KurentoSessionManager extends SessionManager { } @Override - public void stopRtmpIfNecessary(Session session) { + public void stopBroadcastIfNecessary(Session session) { } private io.openvidu.server.recording.Recording getActiveRecordingIfAllowedByParticipantRole( diff --git a/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingManager.java b/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingManager.java index f215be5f..1d2bd110 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingManager.java +++ b/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingManager.java @@ -694,8 +694,8 @@ public class RecordingManager { return; } if (session.getParticipants().size() == 0 - || session.onlyRecorderAndOrSttAndOrRtmpParticipant()) { - // Close session if there are no participants connected (RECORDER/STT/RTMP do + || session.onlyRecorderAndOrSttAndOrBroadcastParticipant()) { + // Close session if there are no participants connected (RECORDER/STT/BROADCAST do // not count) and publishing log.info("Closing session {} after automatic stop of recording {}", session.getSessionId(), recordingId); @@ -748,9 +748,9 @@ public class RecordingManager { return false; } if (session.getParticipants().size() == 0 - || session.onlyRecorderAndOrSttAndOrRtmpParticipant()) { + || session.onlyRecorderAndOrSttAndOrBroadcastParticipant()) { // Close session if there are no participants connected (except for - // RECORDER/STT/RTMP). This code will only be executed if recording is manually + // RECORDER/STT/BROADCAST). This code will only be executed if recording is manually // stopped during the automatic stop timeout, so the session must be also closed log.info( "Ongoing recording of session {} was explicetly stopped within timeout for automatic recording stop. Closing session",