openvidu-server recording layout updated to use StreamManager API

pull/73/head
pabloFuente 2018-06-01 14:19:14 +02:00
parent 2f2a42c439
commit 9e79fe351e
15 changed files with 978 additions and 847 deletions

View File

@ -4,7 +4,7 @@ MAINTAINER openvidu@gmail.com
# Install Chrome
RUN apt-get update && apt-get install -y wget
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \
echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" | tee /etc/apt/sources.list.d/google-chrome.list && \
apt-get update && apt-get install -y google-chrome-stable
# Install media packages
@ -25,4 +25,3 @@ RUN ["chmod", "+x", "/entrypoint.sh"]
RUN mkdir /recordings
ENTRYPOINT /entrypoint.sh

View File

@ -11,8 +11,8 @@ fi
URL=${URL:-https://www.youtube.com/watch?v=JMuzlEQz3uo}
RESOLUTION=${RESOLUTION:-1920x1080}
FRAMERATE=${FRAMERATE:-24}
VIDEO_SIZE=$RESOLUTION
ARRAY=(${VIDEO_SIZE//x/ })
WIDTH="$(cut -d'x' -f1 <<< $RESOLUTION)"
HEIGHT="$(cut -d'x' -f2 <<< $RESOLUTION)"
VIDEO_ID=${VIDEO_ID:-video}
VIDEO_NAME=${VIDEO_NAME:-video}
VIDEO_FORMAT=${VIDEO_FORMAT:-mp4}
@ -21,8 +21,8 @@ RECORDING_JSON="${RECORDING_JSON}"
export URL
export RESOLUTION
export FRAMERATE
export VIDEO_SIZE
export ARRAY
export WIDTH
export HEIGHT
export VIDEO_ID
export VIDEO_NAME
export VIDEO_FORMAT
@ -83,7 +83,7 @@ touch xvfb.log
chmod 777 xvfb.log
function3() {
xvfb-run --server-num=${DISPLAY_NUM} --server-args="-ac -screen 0 ${RESOLUTION}x24 -noreset" google-chrome -no-sandbox -test-type -disable-infobars -window-size=${ARRAY[0]},${ARRAY[1]} -no-first-run -ignore-certificate-errors --kiosk $URL &> xvfb.log &
xvfb-run --server-num=${DISPLAY_NUM} --server-args="-ac -screen 0 ${RESOLUTION}x24 -noreset" google-chrome -start-maximized -no-sandbox -test-type -disable-infobars -window-size=$WIDTH,$HEIGHT -no-first-run -ignore-certificate-errors --kiosk $URL &> xvfb.log &
}
export -f function3
if [[ $CURRENT_UID != $USER_ID ]]; then

View File

@ -2,7 +2,7 @@ FROM ubuntu:16.04
MAINTAINER openvidu@gmail.com
# Install Kurento Media Server (KMS)
RUN echo "deb http://ubuntu.openvidu.io/6.7.0 xenial kms6" | tee /etc/apt/sources.list.d/kurento.list \
RUN echo "deb http://ubuntu.openvidu.io/6.7.2 xenial kms6" | tee /etc/apt/sources.list.d/kurento.list \
&& apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 5AFA7A83 \
&& apt-get update \
&& apt-get -y dist-upgrade \

View File

@ -17,6 +17,7 @@ import { DashboardComponent } from './components/dashboard/dashboard.component';
import { SessionDetailsComponent } from './components/session-details/session-details.component';
import { CredentialsDialogComponent } from './components/dashboard/credentials-dialog.component';
import { LayoutBestFitComponent } from './components/layouts/layout-best-fit/layout-best-fit.component';
import { OpenViduVideoComponent } from './components/layouts/ov-video.component';
@NgModule({
@ -26,6 +27,7 @@ import { LayoutBestFitComponent } from './components/layouts/layout-best-fit/lay
SessionDetailsComponent,
CredentialsDialogComponent,
LayoutBestFitComponent,
OpenViduVideoComponent,
],
imports: [
BrowserModule,

View File

@ -9,7 +9,7 @@
bottom: 0;
}
video {
app-ov-video video {
-o-object-fit: cover;
object-fit: cover;
display: block;
@ -39,8 +39,8 @@ video {
*/
/* Root OT object, this is where our CSS reset happens */
.OT_root,
.OT_root * {
.OT_root, .OT_root * {
color: #ffffff;
margin: 0;
padding: 0;
@ -63,20 +63,18 @@ video {
.OT_dialog {
position: relative;
-webkit-box-sizing: border-box;
box-sizing: border-box;
box-sizing: border-box;
max-width: 576px;
margin-right: auto;
margin-left: auto;
padding: 36px;
text-align: center; /* centers all the inline content */
text-align: center;
/* centers all the inline content */
background-color: #363636;
color: #fff;
-webkit-box-shadow: 2px 4px 6px #999;
box-shadow: 2px 4px 6px #999;
box-shadow: 2px 4px 6px #999;
font-family: 'Didact Gothic', sans-serif;
font-size: 13px;
line-height: 1.4;
@ -85,7 +83,7 @@ video {
.OT_dialog * {
font-family: inherit;
-webkit-box-sizing: inherit;
box-sizing: inherit;
box-sizing: inherit;
}
.OT_closeButton {
@ -105,14 +103,12 @@ video {
.OT_dialog-messages-main {
margin-bottom: 36px;
line-height: 36px;
font-weight: 300;
font-size: 24px;
}
.OT_dialog-messages-minor {
margin-bottom: 18px;
font-size: 13px;
line-height: 18px;
color: #A4A4A4;
@ -129,19 +125,17 @@ video {
.OT_dialog-button-title {
margin-bottom: 18px;
line-height: 18px;
font-weight: 300;
text-align: center;
font-size: 14px;
color: #999999;
}
.OT_dialog-button-title label {
color: #999999;
}
.OT_dialog-button-title a,
.OT_dialog-button-title a:link,
.OT_dialog-button-title a:active {
.OT_dialog-button-title a, .OT_dialog-button-title a:link, .OT_dialog-button-title a:active {
color: #02A1DE;
}
@ -153,10 +147,8 @@ video {
.OT_dialog-button {
display: inline-block;
margin-bottom: 18px;
padding: 0 1em;
background-color: #1CA3DC;
text-align: center;
cursor: pointer;
@ -171,7 +163,6 @@ video {
line-height: 36px;
padding-top: 9px;
padding-bottom: 9px;
font-weight: 100;
font-size: 24px;
}
@ -180,31 +171,28 @@ video {
line-height: 18px;
padding-top: 9px;
padding-bottom: 9px;
background-color: #444444;
color: #999999;
font-size: 16px;
}
.OT_dialog-progress-bar {
display: inline-block; /* prevents margin collapse */
display: inline-block;
/* prevents margin collapse */
width: 100%;
margin-top: 5px;
margin-bottom: 41px;
border: 1px solid #4E4E4E;
height: 8px;
}
.OT_dialog-progress-bar-fill {
height: 100%;
background-color: #29A4DA;
}
.OT_dialog-plugin-upgrading .OT_dialog-plugin-upgrade-percentage {
line-height: 54px;
font-size: 48px;
font-weight: 100;
}
@ -238,24 +226,22 @@ video {
min-height: 48px;
}
.OT_publisher .OT_video-element,
.OT_subscriber .OT_video-element {
.OT_publisher .OT_video-element, .OT_subscriber .OT_video-element {
display: block;
position: absolute;
width: 100%;
height: 100%;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
transform-origin: 0 0;
}
/* Styles that are applied when the video element should be mirrored */
.OT_publisher.OT_mirrored .OT_video-element {
-webkit-transform: scale(-1, 1);
transform: scale(-1, 1);
transform: scale(-1, 1);
-webkit-transform-origin: 50% 50%;
transform-origin: 50% 50%;
transform-origin: 50% 50%;
}
.OT_subscriber_error {
@ -264,21 +250,13 @@ video {
text-align: center;
}
.OT_subscriber_error > p {
.OT_subscriber_error>p {
padding: 20px;
}
/* The publisher/subscriber name/mute background */
.OT_publisher .OT_bar,
.OT_subscriber .OT_bar,
.OT_publisher .OT_name,
.OT_subscriber .OT_name,
.OT_publisher .OT_archiving,
.OT_subscriber .OT_archiving,
.OT_publisher .OT_archiving-status,
.OT_subscriber .OT_archiving-status,
.OT_publisher .OT_archiving-light-box,
.OT_subscriber .OT_archiving-light-box {
.OT_publisher .OT_bar, .OT_subscriber .OT_bar, .OT_publisher .OT_name, .OT_subscriber .OT_name, .OT_publisher .OT_archiving, .OT_subscriber .OT_archiving, .OT_publisher .OT_archiving-status, .OT_subscriber .OT_archiving-status, .OT_publisher .OT_archiving-light-box, .OT_subscriber .OT_archiving-light-box {
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
@ -290,19 +268,18 @@ video {
position: absolute;
}
.OT_publisher .OT_bar,
.OT_subscriber .OT_bar {
.OT_publisher .OT_bar, .OT_subscriber .OT_bar {
background: rgba(0, 0, 0, 0.4);
}
.OT_publisher .OT_edge-bar-item,
.OT_subscriber .OT_edge-bar-item {
z-index: 1; /* required to get audio level meter underneath */
.OT_publisher .OT_edge-bar-item, .OT_subscriber .OT_edge-bar-item {
z-index: 1;
/* required to get audio level meter underneath */
}
/* The publisher/subscriber name panel/archiving status bar */
.OT_publisher .OT_name,
.OT_subscriber .OT_name {
.OT_publisher .OT_name, .OT_subscriber .OT_name {
background-color: transparent;
color: #ffffff;
font-size: 15px;
@ -311,8 +288,7 @@ video {
padding: 0 4px 0 36px;
}
.OT_publisher .OT_archiving-status,
.OT_subscriber .OT_archiving-status {
.OT_publisher .OT_archiving-status, .OT_subscriber .OT_archiving-status {
background: rgba(0, 0, 0, 0.4);
top: auto;
bottom: 0;
@ -324,15 +300,11 @@ video {
font-weight: normal;
}
.OT_micro .OT_archiving-status,
.OT_micro:hover .OT_archiving-status,
.OT_mini .OT_archiving-status,
.OT_mini:hover .OT_archiving-status {
.OT_micro .OT_archiving-status, .OT_micro:hover .OT_archiving-status, .OT_mini .OT_archiving-status, .OT_mini:hover .OT_archiving-status {
display: none;
}
.OT_publisher .OT_archiving-light-box,
.OT_subscriber .OT_archiving-light-box {
.OT_publisher .OT_archiving-light-box, .OT_subscriber .OT_archiving-light-box {
background: rgba(0, 0, 0, 0.4);
top: auto;
bottom: 0;
@ -370,22 +342,18 @@ video {
-webkit-box-shadow: 0 0 0px 0px #c70019;
box-shadow: 0 0 0px 0px #c70019;
}
30% {
-webkit-box-shadow: 0 0 5px 1px #c70019;
box-shadow: 0 0 5px 1px #c70019;
}
50% {
-webkit-box-shadow: 0 0 5px 1px #c70019;
box-shadow: 0 0 5px 1px #c70019;
}
80% {
-webkit-box-shadow: 0 0 0px 0px #c70019;
box-shadow: 0 0 0px 0px #c70019;
}
100% {
-webkit-box-shadow: 0 0 0px 0px #c70019;
box-shadow: 0 0 0px 0px #c70019;
@ -397,64 +365,52 @@ video {
-webkit-box-shadow: 0 0 0px 0px #c70019;
box-shadow: 0 0 0px 0px #c70019;
}
30% {
-webkit-box-shadow: 0 0 5px 1px #c70019;
box-shadow: 0 0 5px 1px #c70019;
}
50% {
-webkit-box-shadow: 0 0 5px 1px #c70019;
box-shadow: 0 0 5px 1px #c70019;
}
80% {
-webkit-box-shadow: 0 0 0px 0px #c70019;
box-shadow: 0 0 0px 0px #c70019;
}
100% {
-webkit-box-shadow: 0 0 0px 0px #c70019;
box-shadow: 0 0 0px 0px #c70019;
}
}
.OT_mini .OT_bar,
.OT_bar.OT_mode-mini,
.OT_bar.OT_mode-mini-auto {
.OT_mini .OT_bar, .OT_bar.OT_mode-mini, .OT_bar.OT_mode-mini-auto {
bottom: 0;
height: auto;
}
.OT_mini .OT_name.OT_mode-off,
.OT_mini .OT_name.OT_mode-on,
.OT_mini .OT_name.OT_mode-auto,
.OT_mini:hover .OT_name.OT_mode-auto {
.OT_mini .OT_name.OT_mode-off, .OT_mini .OT_name.OT_mode-on, .OT_mini .OT_name.OT_mode-auto, .OT_mini:hover .OT_name.OT_mode-auto {
display: none;
}
.OT_publisher .OT_name,
.OT_subscriber .OT_name {
left: 10px;
right: 37px;
height: 34px;
padding-left: 0;
.OT_publisher .OT_name, .OT_subscriber .OT_name {
left: 10px;
right: 37px;
height: 34px;
padding-left: 0;
}
.OT_publisher .OT_mute,
.OT_subscriber .OT_mute {
border: none;
cursor: pointer;
display: block;
position: absolute;
text-align: center;
text-indent: -9999em;
background-color: transparent;
background-repeat: no-repeat;
.OT_publisher .OT_mute, .OT_subscriber .OT_mute {
border: none;
cursor: pointer;
display: block;
position: absolute;
text-align: center;
text-indent: -9999em;
background-color: transparent;
background-repeat: no-repeat;
}
.OT_publisher .OT_mute,
.OT_subscriber .OT_mute {
.OT_publisher .OT_mute, .OT_subscriber .OT_mute {
right: 0;
top: 0;
border-left: 1px solid rgba(255, 255, 255, 0.2);
@ -462,9 +418,7 @@ video {
width: 37px;
}
.OT_mini .OT_mute,
.OT_publisher.OT_mini .OT_mute.OT_mode-auto.OT_mode-on-hold,
.OT_subscriber.OT_mini .OT_mute.OT_mode-auto.OT_mode-on-hold {
.OT_mini .OT_mute, .OT_publisher.OT_mini .OT_mute.OT_mode-auto.OT_mode-on-hold, .OT_subscriber.OT_mini .OT_mute.OT_mode-auto.OT_mode-on-hold {
top: 50%;
left: 50%;
right: auto;
@ -501,77 +455,51 @@ video {
*/
/* Default display mode transitions for various chrome elements */
.OT_publisher .OT_edge-bar-item,
.OT_subscriber .OT_edge-bar-item {
.OT_publisher .OT_edge-bar-item, .OT_subscriber .OT_edge-bar-item {
-webkit-transition-property: top, bottom, opacity;
transition-property: top, bottom, opacity;
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
transition-duration: 0.5s;
-webkit-transition-timing-function: ease-in;
transition-timing-function: ease-in;
transition-timing-function: ease-in;
}
.OT_publisher .OT_edge-bar-item.OT_mode-off,
.OT_subscriber .OT_edge-bar-item.OT_mode-off,
.OT_publisher .OT_edge-bar-item.OT_mode-auto,
.OT_subscriber .OT_edge-bar-item.OT_mode-auto,
.OT_publisher .OT_edge-bar-item.OT_mode-mini-auto,
.OT_subscriber .OT_edge-bar-item.OT_mode-mini-auto {
.OT_publisher .OT_edge-bar-item.OT_mode-off, .OT_subscriber .OT_edge-bar-item.OT_mode-off, .OT_publisher .OT_edge-bar-item.OT_mode-auto, .OT_subscriber .OT_edge-bar-item.OT_mode-auto, .OT_publisher .OT_edge-bar-item.OT_mode-mini-auto, .OT_subscriber .OT_edge-bar-item.OT_mode-mini-auto {
top: -25px;
opacity: 0;
}
.OT_publisher .OT_edge-bar-item.OT_mode-off,
.OT_subscriber .OT_edge-bar-item.OT_mode-off {
.OT_publisher .OT_edge-bar-item.OT_mode-off, .OT_subscriber .OT_edge-bar-item.OT_mode-off {
display: none;
}
.OT_mini .OT_mute.OT_mode-auto,
.OT_publisher .OT_mute.OT_mode-mini-auto,
.OT_subscriber .OT_mute.OT_mode-mini-auto {
.OT_mini .OT_mute.OT_mode-auto, .OT_publisher .OT_mute.OT_mode-mini-auto, .OT_subscriber .OT_mute.OT_mode-mini-auto {
top: 50%;
}
.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-off,
.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-off,
.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,
.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,
.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-mini-auto,
.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-mini-auto {
.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-off, .OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-off, .OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto, .OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto, .OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-mini-auto, .OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-mini-auto {
top: auto;
bottom: -25px;
}
.OT_publisher .OT_edge-bar-item.OT_mode-on,
.OT_subscriber .OT_edge-bar-item.OT_mode-on,
.OT_publisher .OT_edge-bar-item.OT_mode-auto.OT_mode-on-hold,
.OT_subscriber .OT_edge-bar-item.OT_mode-auto.OT_mode-on-hold,
.OT_publisher:hover .OT_edge-bar-item.OT_mode-auto,
.OT_subscriber:hover .OT_edge-bar-item.OT_mode-auto,
.OT_publisher:hover .OT_edge-bar-item.OT_mode-mini-auto,
.OT_subscriber:hover .OT_edge-bar-item.OT_mode-mini-auto {
.OT_publisher .OT_edge-bar-item.OT_mode-on, .OT_subscriber .OT_edge-bar-item.OT_mode-on, .OT_publisher .OT_edge-bar-item.OT_mode-auto.OT_mode-on-hold, .OT_subscriber .OT_edge-bar-item.OT_mode-auto.OT_mode-on-hold, .OT_publisher:hover .OT_edge-bar-item.OT_mode-auto, .OT_subscriber:hover .OT_edge-bar-item.OT_mode-auto, .OT_publisher:hover .OT_edge-bar-item.OT_mode-mini-auto, .OT_subscriber:hover .OT_edge-bar-item.OT_mode-mini-auto {
top: 0;
opacity: 1;
}
.OT_mini .OT_mute.OT_mode-on,
.OT_mini:hover .OT_mute.OT_mode-auto,
.OT_mute.OT_mode-mini,
.OT_root:hover .OT_mute.OT_mode-mini-auto {
.OT_mini .OT_mute.OT_mode-on, .OT_mini:hover .OT_mute.OT_mode-auto, .OT_mute.OT_mode-mini, .OT_root:hover .OT_mute.OT_mode-mini-auto {
top: 50%;
}
.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-on,
.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-on,
.OT_publisher:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,
.OT_subscriber:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto {
.OT_publisher .OT_edge-bar-item.OT_edge-bottom.OT_mode-on, .OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-on, .OT_publisher:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto, .OT_subscriber:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto {
top: auto;
bottom: 0;
opacity: 1;
}
/* Contains the video element, used to fix video letter-boxing */
.OT_widget-container {
width: 100%;
height: 100%;
@ -581,13 +509,13 @@ video {
}
/* Load animation */
.OT_root .OT_video-loading {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
display: none;
background-color: rgba(0, 0, 0, .75);
}
@ -603,20 +531,21 @@ video {
-webkit-animation: OT_spin 2s linear infinite;
animation: OT_spin 2s linear infinite;
}
@-webkit-keyframes OT_spin {
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes OT_spin {
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
transform: rotate(360deg);
}
}
.OT_publisher.OT_loading .OT_video-loading,
.OT_subscriber.OT_loading .OT_video-loading {
.OT_publisher.OT_loading .OT_video-loading, .OT_subscriber.OT_loading .OT_video-loading {
display: block;
}
@ -637,9 +566,7 @@ video {
width: 100%;
height: 100%;
display: none;
opacity: .25;
background-repeat: no-repeat;
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDcxIDQ2NCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48bGluZWFyR3JhZGllbnQgaWQ9ImEiIHgyPSIwIiB5Mj0iMSI+PHN0b3Agb2Zmc2V0PSI2Ni42NiUiIHN0b3AtY29sb3I9IiNmZmYiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmYiIHN0b3Atb3BhY2l0eT0iMCIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCNhKSIgZD0iTTc5IDMwOGMxNC4yNS02LjUgNTQuMjUtMTkuNzUgNzEtMjkgOS0zLjI1IDI1LTIxIDI1LTIxczMuNzUtMTMgMy0yMmMtMS43NS02Ljc1LTE1LTQzLTE1LTQzLTIuNSAzLTQuNzQxIDMuMjU5LTcgMS0zLjI1LTcuNS0yMC41LTQ0LjUtMTYtNTcgMS4yNS03LjUgMTAtNiAxMC02LTExLjI1LTMzLjc1LTgtNjctOC02N3MuMDczLTcuMzQ2IDYtMTVjLTMuNDguNjM3LTkgNC05IDQgMi41NjMtMTEuNzI3IDE1LTIxIDE1LTIxIC4xNDgtLjMxMi0xLjMyMS0xLjQ1NC0xMCAxIDEuNS0yLjc4IDE2LjY3NS04LjY1NCAzMC0xMSAzLjc4Ny05LjM2MSAxMi43ODItMTcuMzk4IDIyLTIyLTIuMzY1IDMuMTMzLTMgNi0zIDZzMTUuNjQ3LTguMDg4IDQxLTZjLTE5Ljc1IDItMjQgNi0yNCA2czc0LjUtMTAuNzUgMTA0IDM3YzcuNSA5LjUgMjQuNzUgNTUuNzUgMTAgODkgMy43NS0xLjUgNC41LTQuNSA5IDEgLjI1IDE0Ljc1LTExLjUgNjMtMTkgNjItMi43NSAxLTQtMy00LTMtMTAuNzUgMjkuNS0xNCAzOC0xNCAzOC0yIDQuMjUtMy43NSAxOC41LTEgMjIgMS4yNSA0LjUgMjMgMjMgMjMgMjNsMTI3IDUzYzM3IDM1IDIzIDEzNSAyMyAxMzVMMCA0NjRzLTMtOTYuNzUgMTQtMTIwYzUuMjUtNi4yNSAyMS43NS0xOS43NSA2NS0zNnoiLz48L3N2Zz4=);
background-size: auto 76%;
@ -647,22 +574,23 @@ video {
.OT_fit-mode-cover .OT_video-element {
-o-object-fit: cover;
object-fit: cover;
object-fit: cover;
}
/* Workaround for iOS freezing issue when cropping videos */
/* https://bugs.webkit.org/show_bug.cgi?id=176439 */
@media only screen
and (orientation: portrait) {
@media only screen and (orientation: portrait) {
.OT_subscriber.OT_ForceContain.OT_fit-mode-cover .OT_video-element {
-o-object-fit: contain !important;
object-fit: contain !important;
object-fit: contain !important;
}
}
.OT_fit-mode-contain .OT_video-element {
-o-object-fit: contain;
object-fit: contain;
object-fit: contain;
}
.OT_fit-mode-cover .OT_video-poster {
@ -692,12 +620,13 @@ video {
.OT_audio-level-meter__bar {
position: absolute;
width: 192%; /* meter value can overflow of 8% */
width: 192%;
/* meter value can overflow of 8% */
height: 192%;
top: -96% /* half of the size */;
top: -96%/* half of the size */
;
right: -96%;
border-radius: 50%;
background-color: rgba(0, 0, 0, .8);
}
@ -706,9 +635,7 @@ video {
top: 22%;
right: 15%;
width: 40%;
opacity: .7;
background: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzkgODYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTkuNzU3IDQwLjkyNGMzLjczOC01LjE5MSAxMi43MTEtNC4zMDggMTIuNzExLTQuMzA4IDIuMjIzIDMuMDE0IDUuMTI2IDI0LjU4NiAzLjYyNCAyOC43MTgtMS40MDEgMS4zMDEtMTEuNjExIDEuNjI5LTEzLjM4LTEuNDM2LTEuMjI2LTguODA0LTIuOTU1LTIyLjk3NS0yLjk1NS0yMi45NzV6bTU4Ljc4NSAwYy0zLjczNy01LjE5MS0xMi43MTEtNC4zMDgtMTIuNzExLTQuMzA4LTIuMjIzIDMuMDE0LTUuMTI2IDI0LjU4Ni0zLjYyNCAyOC43MTggMS40MDEgMS4zMDEgMTEuNjExIDEuNjI5IDEzLjM4LTEuNDM2IDEuMjI2LTguODA0IDIuOTU1LTIyLjk3NSAyLjk1NS0yMi45NzV6Ii8+PHBhdGggZD0iTTY4LjY0NyA1OC42Yy43MjktNC43NTMgMi4zOC05LjU2MSAyLjM4LTE0LjgwNCAwLTIxLjQxMi0xNC4xMTUtMzguNzctMzEuNTI4LTM4Ljc3LTE3LjQxMiAwLTMxLjUyNyAxNy4zNTgtMzEuNTI3IDM4Ljc3IDAgNC41NDEuNTE1IDguOTM2IDEuODAyIDEyLjk1IDEuNjk4IDUuMjk1LTUuNTQyIDYuOTkxLTYuNjE2IDIuMDczQzIuNDEgNTUuMzk0IDAgNTEuNzg3IDAgNDguMTAzIDAgMjEuNTM2IDE3LjY4NSAwIDM5LjUgMCA2MS4zMTYgMCA3OSAyMS41MzYgNzkgNDguMTAzYzAgLjcxOC0yLjg5OSA5LjY5My0zLjI5MiAxMS40MDgtLjc1NCAzLjI5My03Ljc1MSAzLjU4OS03LjA2MS0uOTEyeiIvPjxwYXRoIGQ9Ik01LjA4NCA1MS4zODVjLS44MDQtMy43ODIuNTY5LTcuMzM1IDMuMTM0LTcuOTIxIDIuNjM2LS42MDMgNS40ODUgMi4xNSA2LjI4OSA2LjEzMi43OTcgMy45NDgtLjc1MiA3LjQ1Ny0zLjM4OCA3Ljg1OS0yLjU2Ni4zOTEtNS4yMzctMi4zMTgtNi4wMzQtNi4wN3ptNjguODM0IDBjLjgwNC0zLjc4Mi0uNTY4LTcuMzM1LTMuMTMzLTcuOTIxLTIuNjM2LS42MDMtNS40ODUgMi4xNS02LjI4OSA2LjEzMi0uNzk3IDMuOTQ4Ljc1MiA3LjQ1NyAzLjM4OSA3Ljg1OSAyLjU2NS4zOTEgNS4yMzctMi4zMTggNi4wMzQtNi4wN3ptLTIuMDM4IDguMjg4Yy0uOTI2IDE5LjY1OS0xNS4xMTIgMjQuNzU5LTI1Ljg1OSAyMC40NzUtNS40MDUtLjYwNi0zLjAzNCAxLjI2Mi0zLjAzNCAxLjI2MiAxMy42NjEgMy41NjIgMjYuMTY4IDMuNDk3IDMxLjI3My0yMC41NDktLjU4NS00LjUxMS0yLjM3OS0xLjE4Ny0yLjM3OS0xLjE4N3oiLz48cGF0aCBkPSJNNDEuNjYyIDc4LjQyMmw3LjU1My41NWMxLjE5Mi4xMDcgMi4xMiAxLjE1MyAyLjA3MiAyLjMzNWwtLjEwOSAyLjczOGMtLjA0NyAxLjE4Mi0xLjA1MSAyLjA1NC0yLjI0MyAxLjk0NmwtNy41NTMtLjU1Yy0xLjE5MS0uMTA3LTIuMTE5LTEuMTUzLTIuMDcyLTIuMzM1bC4xMDktMi43MzdjLjA0Ny0xLjE4MiAxLjA1Mi0yLjA1NCAyLjI0My0xLjk0N3oiLz48L2c+PC9zdmc+) no-repeat center;
}
@ -726,19 +653,16 @@ video {
}
.OT_audio-level-meter.OT_mode-off {
display: none;
}
.OT_audio-level-meter.OT_mode-on,
.OT_audio-only .OT_audio-level-meter.OT_mode-auto {
display: block;
}
.OT_audio-only.OT_publisher .OT_video-element,
.OT_audio-only.OT_subscriber .OT_video-element {
display: none;
}
.OT_audio-level-meter.OT_mode-on, .OT_audio-only .OT_audio-level-meter.OT_mode-auto {
display: block;
}
.OT_audio-only.OT_publisher .OT_video-element, .OT_audio-only.OT_subscriber .OT_video-element {
display: none;
}
.OT_video-disabled-indicator {
opacity: 1;
@ -826,12 +750,13 @@ video {
.OT_video-unsupported-bar {
display: none;
position: absolute;
width: 192%; /* copy the size of the audio meter bar for symmetry */
width: 192%;
/* copy the size of the audio meter bar for symmetry */
height: 192%;
top: -96% /* half of the size */;
top: -96%/* half of the size */
;
left: -96%;
border-radius: 50%;
background-color: rgba(0, 0, 0, .8);
}
@ -860,12 +785,12 @@ video {
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-ms-flex-align: center;
align-items: center;
text-align: center;
height: 100%;
margin-top: 40px;
}
}

View File

@ -1,7 +1,7 @@
<div id="layout" class="bounds">
<div *ngFor="let s of streams" class="OT_root OT_publisher custom-class">
<div *ngFor="let s of subscribers" class="OT_root OT_publisher custom-class">
<div class="OT_widget-container">
<video [id]="'native-video-' + s.streamId" autoplay="true" [srcObject]="s.getMediaStream()" (playing)="onVideoPlaying($event)"></video>
<app-ov-video [subscriber]="s"></app-ov-video>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
import { Component, OnInit, OnDestroy, HostListener, ViewEncapsulation, ApplicationRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { OpenVidu, Session, Stream, Subscriber, StreamEvent } from 'openvidu-browser';
import { OpenVidu, Session, Stream, Subscriber, StreamEvent, StreamManagerEvent } from 'openvidu-browser';
import { OpenViduLayout } from '../openvidu-layout';
@ -17,7 +17,7 @@ export class LayoutBestFitComponent implements OnInit, OnDestroy {
secret: string;
session: Session;
streams: Stream[] = [];
subscribers: Subscriber[] = [];
layout: any;
resizeTimeout;
@ -51,13 +51,17 @@ export class LayoutBestFitComponent implements OnInit, OnDestroy {
this.session = OV.initSession();
this.session.on('streamCreated', (event: StreamEvent) => {
const subscriber: Subscriber = this.session.subscribe(event.stream, '');
this.addRemoteStream(event.stream);
const subscriber: Subscriber = this.session.subscribe(event.stream, undefined);
subscriber.on('streamPlaying', (e: StreamManagerEvent) => {
const video: HTMLVideoElement = subscriber.videos[0].video;
video.parentElement.parentElement.classList.remove('custom-class');
this.openviduLayout.updateLayout();
});
this.addSubscriber(subscriber);
});
this.session.on('streamDestroyed', (event: StreamEvent) => {
event.preventDefault();
this.deleteRemoteStream(event.stream);
this.deleteSubscriber(<Subscriber>event.stream.streamManager);
this.openviduLayout.updateLayout();
});
@ -83,36 +87,29 @@ export class LayoutBestFitComponent implements OnInit, OnDestroy {
});
}
private addRemoteStream(stream: Stream): void {
this.streams.push(stream);
private addSubscriber(subscriber: Subscriber): void {
this.subscribers.push(subscriber);
this.appRef.tick();
}
private deleteRemoteStream(stream: Stream): void {
private deleteSubscriber(subscriber: Subscriber): void {
let index = -1;
for (let i = 0; i < this.streams.length; i++) {
if (this.streams[i].streamId === stream.streamId) {
for (let i = 0; i < this.subscribers.length; i++) {
if (this.subscribers[i] === subscriber) {
index = i;
break;
}
}
if (index > -1) {
this.streams.splice(index, 1);
this.subscribers.splice(index, 1);
}
this.appRef.tick();
}
leaveSession() {
if (this.session) { this.session.disconnect(); };
this.streams = [];
this.subscribers = [];
this.session = null;
}
onVideoPlaying(event) {
const video: HTMLVideoElement = event.target;
video.parentElement.parentElement.classList.remove('custom-class');
this.openviduLayout.updateLayout();
}
}

View File

@ -0,0 +1,26 @@
import { Component, Input, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { Subscriber } from 'openvidu-browser';
@Component({
selector: 'app-ov-video',
template: '<video #videoElement></video>'
})
export class OpenViduVideoComponent implements AfterViewInit {
@ViewChild('videoElement') elementRef: ElementRef;
_subscriber: Subscriber;
ngAfterViewInit() {
this._subscriber.addVideoElement(this.elementRef.nativeElement);
}
@Input()
set subscriber(subscriber: Subscriber) {
this._subscriber = subscriber;
if (!!this.elementRef) {
this._subscriber.addVideoElement(this.elementRef.nativeElement);
}
}
}

View File

@ -208,7 +208,6 @@ public class OpenViduServer implements JsonRpcConfigurer {
default:
URL url = new URL(publicUrl);
int port = url.getPort();
type = "custom";
@ -223,11 +222,6 @@ public class OpenViduServer implements JsonRpcConfigurer {
if (!OpenViduServer.publicUrl.startsWith("wss://")) {
OpenViduServer.publicUrl = "wss://" + OpenViduServer.publicUrl;
}
if (port == -1) {
OpenViduServer.publicUrl += ":" + openviduConf.getServerPort();
}
break;
}
if (OpenViduServer.publicUrl == null) {

View File

@ -2,7 +2,7 @@ spring.profiles.active=docker
server.address: 0.0.0.0
server.ssl.enabled: true
openvidu.recording.version: 2.0.1
openvidu.recording.version: 2.1.0

View File

@ -3,7 +3,7 @@ spring.profiles.active=ngrok
server.port: 5000
server.address: 0.0.0.0
server.ssl.enabled: false
openvidu.recording.version: 2.0.1
openvidu.recording.version: 2.1.0
kms.uris=[\"ws://localhost:8888/kurento\"]
openvidu.secret: MY_SECRET

View File

@ -1,6 +1,6 @@
server.address: 0.0.0.0
server.ssl.enabled: true
openvidu.recording.version: 2.0.1
openvidu.recording.version: 2.1.0

View File

@ -1 +1 @@
{"version":3,"sources":["webpack/bootstrap 347280613b71b908df0e"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAY,2BAA2B;AACvC;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA,kDAA0C,oBAAoB,WAAW","file":"inline.bundle.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t\"inline\": 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 347280613b71b908df0e"],"sourceRoot":"webpack:///"}
{"version":3,"sources":["webpack/bootstrap 20d6fb8adf9ed6d01cc2"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAY,2BAA2B;AACvC;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA,kDAA0C,oBAAoB,WAAW","file":"inline.bundle.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t\"inline\": 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 20d6fb8adf9ed6d01cc2"],"sourceRoot":"webpack:///"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long