Merge branch 'RC1-1.0' into develop
commit
fa91d9b9e2
|
|
@ -1,4 +1,9 @@
|
|||
# Changelog
|
||||
|
||||
### 1.0
|
||||
* Fixed toolarea button based on feedback from users
|
||||
* Added possibility to move video to separate window
|
||||
* Added SIP gateway
|
||||
|
||||
### RC1 1.0
|
||||
* First stable release?
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ Try it online at https://letsmeet.no. You can add /roomname to the URL for speci
|
|||
* File sharing
|
||||
* Different video layouts
|
||||
|
||||
There is also a SIP gateway that can be found [here](https://github.com/havfo/multiparty-meeting-sipgw). To test it, call: roomname@letsmeet.no.
|
||||
|
||||
## Installation
|
||||
|
||||
* Clone the project:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Multiparty Meeting</title>
|
||||
</head>
|
||||
<style>
|
||||
body{
|
||||
margin:auto;
|
||||
padding:0.5vmin;
|
||||
text-align:center;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 40%;
|
||||
width: 90%;
|
||||
transform: translate(-50%, 0%);
|
||||
background-image: url('/resources/images/background.svg');
|
||||
background-attachment: fixed;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
input:hover {opacity:0.9;}
|
||||
input[type=text]{
|
||||
font-size: 1.5em;
|
||||
padding: 1.5vmin;
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
border: 0;
|
||||
color: #fff;
|
||||
margin: 0.8vmin;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
button:hover {background-color: #28bd7b;}
|
||||
button{
|
||||
font-size: 1.5em;
|
||||
padding: 1.5vmin;
|
||||
margin: 0.8vmin;
|
||||
background-color: #38cd8b;
|
||||
border-radius: 1.8vmin;
|
||||
color: #fff;
|
||||
border: 0;
|
||||
}
|
||||
img{
|
||||
height: 15vmin;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<a>
|
||||
<img src='/resources/images/logo.svg'></img><br>
|
||||
</a>
|
||||
<input id="room" type="text" onkeypress="checkEnter(event)" value="" placeholder="your room name">
|
||||
<button onclick = "start(location.href)">Go to room</button>
|
||||
</body>
|
||||
<script>
|
||||
var room = document.getElementById("room");
|
||||
var stateObj = { foo: "bar" };
|
||||
room.addEventListener("input", function(e) {
|
||||
console.log(e.charCode);
|
||||
history.replaceState(stateObj, "Multiparty Meeting", "/"+room.value);
|
||||
},true);
|
||||
room.focus();
|
||||
function start(target){
|
||||
location.href;history.replaceState(stateObj, "Multiparty Meeting", "/");
|
||||
window.location = target;
|
||||
}
|
||||
function checkEnter(event){
|
||||
var x = event.charCode || event.keyCode;
|
||||
if (x == 13 ) {
|
||||
start(location.href);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
|
|
@ -168,7 +168,7 @@ gulp.task('css', () =>
|
|||
|
||||
gulp.task('html', () =>
|
||||
{
|
||||
return gulp.src('index.html')
|
||||
return gulp.src('*.html')
|
||||
.pipe(change(changeHTML))
|
||||
.pipe(gulp.dest(OUTPUT_DIR));
|
||||
});
|
||||
|
|
@ -241,7 +241,7 @@ gulp.task('browser', (done) =>
|
|||
gulp.task('watch', (done) =>
|
||||
{
|
||||
// Watch changes in HTML.
|
||||
gulp.watch([ 'index.html' ], gulp.series(
|
||||
gulp.watch([ '*.html' ], gulp.series(
|
||||
'html'
|
||||
));
|
||||
|
||||
|
|
|
|||
|
|
@ -179,6 +179,13 @@ export default class RoomClient
|
|||
this.notify('Changed layout to filmstrip view.');
|
||||
break;
|
||||
}
|
||||
|
||||
case 'm': // Toggle microphone
|
||||
{
|
||||
this.toggleMic();
|
||||
this.notify('Muted/unmuted your microphone.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -391,6 +398,16 @@ export default class RoomClient
|
|||
}
|
||||
}
|
||||
|
||||
toggleMic()
|
||||
{
|
||||
logger.debug('toggleMic()');
|
||||
|
||||
if (this._micProducer.locallyPaused)
|
||||
this.unmuteMic();
|
||||
else
|
||||
this.muteMic();
|
||||
}
|
||||
|
||||
muteMic()
|
||||
{
|
||||
logger.debug('muteMic()');
|
||||
|
|
@ -1349,7 +1366,7 @@ export default class RoomClient
|
|||
if (this._produce)
|
||||
{
|
||||
if (this._room.canSend('audio'))
|
||||
await this._setMicProducer();
|
||||
this._setMicProducer();
|
||||
|
||||
// Add our webcam (unless the cookie says no).
|
||||
if (this._room.canSend('video'))
|
||||
|
|
@ -1357,7 +1374,7 @@ export default class RoomClient
|
|||
const devicesCookie = cookiesManager.getDevices();
|
||||
|
||||
if (!devicesCookie || devicesCookie.webcamEnabled)
|
||||
await this.enableWebcam();
|
||||
this.enableWebcam();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,23 +108,29 @@ class Me extends React.Component
|
|||
>
|
||||
<div className={classnames('view-container', 'webcam')}>
|
||||
{connected ?
|
||||
<div className={classnames('controls', {
|
||||
visible : this.state.controlsVisible
|
||||
})}
|
||||
>
|
||||
<div className={classnames('controls', 'visible')}>
|
||||
<div
|
||||
data-tip='keyboard shortcut: ‘m‘'
|
||||
data-type='dark'
|
||||
data-place='bottom'
|
||||
data-for='me'
|
||||
className={classnames('button', 'mic', micState, {
|
||||
disabled : me.audioInProgress
|
||||
disabled : me.audioInProgress,
|
||||
visible : micState == 'off' || this.state.controlsVisible
|
||||
})}
|
||||
onClick={() =>
|
||||
{
|
||||
micState === 'on' ? onMuteMic() : onUnmuteMic();
|
||||
}}
|
||||
/>
|
||||
|
||||
<ReactTooltip
|
||||
id='me'
|
||||
effect='solid'
|
||||
/>
|
||||
<div
|
||||
className={classnames('button', 'webcam', webcamState, {
|
||||
disabled : me.webcamInProgress
|
||||
disabled : me.webcamInProgress,
|
||||
visible : webcamState == 'off' || this.state.controlsVisible
|
||||
})}
|
||||
onClick={() =>
|
||||
{
|
||||
|
|
@ -161,15 +167,6 @@ class Me extends React.Component
|
|||
</div>
|
||||
:null
|
||||
}
|
||||
|
||||
{this._tooltip ?
|
||||
<ReactTooltip
|
||||
effect='solid'
|
||||
delayShow={100}
|
||||
delayHide={100}
|
||||
/>
|
||||
:null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ class Peer extends Component
|
|||
onUnmuteMic,
|
||||
toggleConsumerFullscreen,
|
||||
toggleConsumerWindow,
|
||||
style
|
||||
style,
|
||||
windowConsumer
|
||||
} = this.props;
|
||||
|
||||
const micEnabled = (
|
||||
|
|
@ -128,7 +129,10 @@ class Peer extends Component
|
|||
/>
|
||||
|
||||
<div
|
||||
className={classnames('button', 'newwindow')}
|
||||
className={classnames('button', 'newwindow', {
|
||||
disabled : !videoVisible ||
|
||||
(windowConsumer === webcamConsumer.id)
|
||||
})}
|
||||
onClick={(e) =>
|
||||
{
|
||||
e.stopPropagation();
|
||||
|
|
@ -205,6 +209,7 @@ Peer.propTypes =
|
|||
micConsumer : appPropTypes.Consumer,
|
||||
webcamConsumer : appPropTypes.Consumer,
|
||||
screenConsumer : appPropTypes.Consumer,
|
||||
windowConsumer : PropTypes.number,
|
||||
onMuteMic : PropTypes.func.isRequired,
|
||||
onUnmuteMic : PropTypes.func.isRequired,
|
||||
streamDimensions : PropTypes.object,
|
||||
|
|
@ -229,7 +234,8 @@ const mapStateToProps = (state, { name }) =>
|
|||
peer,
|
||||
micConsumer,
|
||||
webcamConsumer,
|
||||
screenConsumer
|
||||
screenConsumer,
|
||||
windowConsumer : state.room.windowConsumer
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import Me from './Me';
|
|||
import Peers from './Peers';
|
||||
import AudioPeers from './PeerAudio/AudioPeers';
|
||||
import Notifications from './Notifications';
|
||||
import ToolAreaButton from './ToolArea/ToolAreaButton';
|
||||
// import ToolAreaButton from './ToolArea/ToolAreaButton';
|
||||
import ToolArea from './ToolArea/ToolArea';
|
||||
import FullScreenView from './FullScreenView';
|
||||
import VideoWindow from './VideoWindow/VideoWindow';
|
||||
|
|
@ -97,8 +97,6 @@ class Room extends React.Component
|
|||
|
||||
<Notifications />
|
||||
|
||||
<ToolAreaButton />
|
||||
|
||||
{room.advancedMode ?
|
||||
<div className='state' data-tip='Server status'>
|
||||
<div className={classnames('icon', room.state)} />
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import * as requestActions from '../redux/requestActions';
|
|||
import * as stateActions from '../redux/stateActions';
|
||||
import PropTypes from 'prop-types';
|
||||
import Dropdown from 'react-dropdown';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
|
||||
const modes = [ {
|
||||
value : 'democratic',
|
||||
|
|
@ -58,7 +59,14 @@ const Settings = ({
|
|||
onChange={(device) => handleChangeAudioDevice(device.value)}
|
||||
placeholder={audioDevicesText}
|
||||
/>
|
||||
|
||||
<ReactTooltip
|
||||
effect='solid'
|
||||
/>
|
||||
<div
|
||||
data-tip='keyboard shortcut: ‘a‘'
|
||||
data-type='dark'
|
||||
data-place='left'
|
||||
>
|
||||
<input
|
||||
id='room-mode'
|
||||
type='checkbox'
|
||||
|
|
@ -66,7 +74,13 @@ const Settings = ({
|
|||
onChange={onToggleAdvancedMode}
|
||||
/>
|
||||
<label htmlFor='room-mode'>Advanced mode</label>
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-tip='keyboard shortcut: type a digit'
|
||||
data-type='dark'
|
||||
data-place='left'
|
||||
>
|
||||
<Dropdown
|
||||
options={modes}
|
||||
value={findOption(modes, room.mode)}
|
||||
|
|
@ -74,6 +88,7 @@ const Settings = ({
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class ToolArea extends React.Component
|
|||
unreadMessages,
|
||||
unreadFiles,
|
||||
toggleToolArea,
|
||||
closeToolArea
|
||||
unread
|
||||
} = this.props;
|
||||
|
||||
const VisibleTab = {
|
||||
|
|
@ -50,11 +50,21 @@ class ToolArea extends React.Component
|
|||
})}
|
||||
>
|
||||
<div
|
||||
className={classNames('toolarea-close-button button', {
|
||||
on : toolAreaOpen
|
||||
})}
|
||||
onClick={closeToolArea}
|
||||
className='toolarea-button'
|
||||
onClick={toggleToolArea}
|
||||
>
|
||||
<span className='content'>
|
||||
<div
|
||||
className='toolarea-icon'
|
||||
/>
|
||||
<p>Toolbox</p>
|
||||
</span>
|
||||
{!toolAreaOpen && unread > 0 && (
|
||||
<span className={classNames('badge', { long: unread >= 10 })}>
|
||||
{unread}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className='tab-headers'>
|
||||
<TabHeader
|
||||
id='chat'
|
||||
|
|
@ -97,14 +107,17 @@ ToolArea.propTypes =
|
|||
unreadFiles : PropTypes.number.isRequired,
|
||||
toolAreaOpen : PropTypes.bool,
|
||||
toggleToolArea : PropTypes.func.isRequired,
|
||||
closeToolArea : PropTypes.func.isRequired
|
||||
closeToolArea : PropTypes.func.isRequired,
|
||||
unread : PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
currentToolTab : state.toolarea.currentToolTab,
|
||||
unreadMessages : state.toolarea.unreadMessages,
|
||||
unreadFiles : state.toolarea.unreadFiles,
|
||||
toolAreaOpen : state.toolarea.toolAreaOpen
|
||||
toolAreaOpen : state.toolarea.toolAreaOpen,
|
||||
unread : state.toolarea.unreadMessages +
|
||||
state.toolarea.unreadFiles
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class ToolAreaButton extends React.Component
|
|||
className={classnames('button toolarea-button', {
|
||||
on : toolAreaOpen
|
||||
})}
|
||||
data-tip='Open tool box'
|
||||
data-tip='Open tools'
|
||||
data-type='dark'
|
||||
onClick={() => toggleToolArea()}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ class NewWindow extends React.PureComponent
|
|||
{
|
||||
if (this.window)
|
||||
{
|
||||
if (this.fullscreen.fullscreenEnabled)
|
||||
if (this.fullscreen && this.fullscreen.fullscreenEnabled)
|
||||
{
|
||||
this.fullscreen.removeEventListener('fullscreenchange', this.handleFullscreenChange);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ function run()
|
|||
const peerName = randomString({ length: 8 }).toLowerCase();
|
||||
const urlParser = new UrlParse(window.location.href, true);
|
||||
let roomId = (urlParser.pathname).substr(1)
|
||||
? (urlParser.pathname).substr(1) : urlParser.query.roomId;
|
||||
? (urlParser.pathname).substr(1).toLowerCase() : urlParser.query.roomId.toLowerCase();
|
||||
const produce = urlParser.query.produce !== 'false';
|
||||
let displayName = urlParser.query.displayName;
|
||||
const isSipEndpoint = urlParser.query.sipEndpoint === 'true';
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ if (process.env.NODE_ENV === 'development')
|
|||
{
|
||||
const reduxLogger = createLogger(
|
||||
{
|
||||
predicate : (getState, action) => action.type !== 'SET_PRODUCER_VOLUME',
|
||||
// filter VOLUME level actions from log
|
||||
predicate : (getState, action) => ! (action.type == 'SET_PRODUCER_VOLUME'
|
||||
|| action.type == 'SET_CONSUMER_VOLUME'),
|
||||
duration : true,
|
||||
timestamp : false,
|
||||
level : 'log',
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
"redux-thunk": "^2.3.0",
|
||||
"resize-observer-polyfill": "^1.5.0",
|
||||
"riek": "^1.1.0",
|
||||
"socket.io-client": "^2.1.1",
|
||||
"url-parse": "^1.4.3",
|
||||
"webtorrent": "^0.102.4"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.2" width="67.32mm" height="67.32mm" viewBox="4682 4809 6732 6732" preserveAspectRatio="xMidYMid" fill-rule="evenodd" stroke-width="28.222" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:presentation="http://sun.com/xmlns/staroffice/presentation" xmlns:smil="http://www.w3.org/2001/SMIL20/" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xml:space="preserve">
|
||||
<defs class="ClipPathGroup">
|
||||
<clipPath id="presentation_clip_path" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="4682" y="4809" width="6732" height="6732"/>
|
||||
</clipPath>
|
||||
<clipPath id="presentation_clip_path_shrink" clipPathUnits="userSpaceOnUse">
|
||||
<rect x="4688" y="4815" width="6719" height="6719"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<defs class="TextShapeIndex">
|
||||
<g ooo:slide="id1" ooo:id-list="id3 id4 id5"/>
|
||||
</defs>
|
||||
<defs class="EmbeddedBulletChars">
|
||||
<g id="bullet-char-template(57356)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 580,1141 L 1163,571 580,0 -4,571 580,1141 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(57354)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 8,1128 L 1137,1128 1137,0 8,0 8,1128 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(10146)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 174,0 L 602,739 174,1481 1456,739 174,0 Z M 1358,739 L 309,1346 659,739 1358,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(10132)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 2015,739 L 1276,0 717,0 1260,543 174,543 174,936 1260,936 717,1481 1274,1481 2015,739 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(10007)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 0,-2 C -7,14 -16,27 -25,37 L 356,567 C 262,823 215,952 215,954 215,979 228,992 255,992 264,992 276,990 289,987 310,991 331,999 354,1012 L 381,999 492,748 772,1049 836,1024 860,1049 C 881,1039 901,1025 922,1006 886,937 835,863 770,784 769,783 710,716 594,584 L 774,223 C 774,196 753,168 711,139 L 727,119 C 717,90 699,76 672,76 641,76 570,178 457,381 L 164,-76 C 142,-110 111,-127 72,-127 30,-127 9,-110 8,-76 1,-67 -2,-52 -2,-32 -2,-23 -1,-13 0,-2 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(10004)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 285,-33 C 182,-33 111,30 74,156 52,228 41,333 41,471 41,549 55,616 82,672 116,743 169,778 240,778 293,778 328,747 346,684 L 369,508 C 377,444 397,411 428,410 L 1163,1116 C 1174,1127 1196,1133 1229,1133 1271,1133 1292,1118 1292,1087 L 1292,965 C 1292,929 1282,901 1262,881 L 442,47 C 390,-6 338,-33 285,-33 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(9679)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 813,0 C 632,0 489,54 383,161 276,268 223,411 223,592 223,773 276,916 383,1023 489,1130 632,1184 813,1184 992,1184 1136,1130 1245,1023 1353,916 1407,772 1407,592 1407,412 1353,268 1245,161 1136,54 992,0 813,0 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(8226)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 346,457 C 273,457 209,483 155,535 101,586 74,649 74,723 74,796 101,859 155,911 209,963 273,989 346,989 419,989 480,963 531,910 582,859 608,796 608,723 608,648 583,586 532,535 482,483 420,457 346,457 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(8211)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M -4,459 L 1135,459 1135,606 -4,606 -4,459 Z"/>
|
||||
</g>
|
||||
<g id="bullet-char-template(61548)" transform="scale(0.00048828125,-0.00048828125)">
|
||||
<path d="M 173,740 C 173,903 231,1043 346,1159 462,1274 601,1332 765,1332 928,1332 1067,1274 1183,1159 1299,1043 1357,903 1357,740 1357,577 1299,437 1183,322 1067,206 928,148 765,148 601,148 462,206 346,322 231,437 173,577 173,740 Z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<defs class="TextEmbeddedBitmaps"/>
|
||||
<g class="SlideGroup">
|
||||
<g>
|
||||
<g id="container-id1">
|
||||
<g id="id1" class="Slide" clip-path="url(#presentation_clip_path)">
|
||||
<g class="Page">
|
||||
<g class="com.sun.star.drawing.LineShape">
|
||||
<g id="id3">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="6253" y="6380" width="3525" height="3525"/>
|
||||
<path fill="none" stroke="rgb(204,0,0)" stroke-width="1016" stroke-linejoin="round" stroke-linecap="round" d="M 6761,9395 L 9268,6888"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.LineShape">
|
||||
<g id="id4">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="6253" y="6398" width="3525" height="3526"/>
|
||||
<path fill="none" stroke="rgb(204,0,0)" stroke-width="1016" stroke-linejoin="round" stroke-linecap="round" d="M 9269,9414 L 6762,6907"/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="com.sun.star.drawing.CustomShape">
|
||||
<g id="id5">
|
||||
<rect class="BoundingBox" stroke="none" fill="none" x="4681" y="4808" width="6734" height="6734"/>
|
||||
<path fill="none" stroke="rgb(204,0,0)" stroke-width="508" stroke-linejoin="round" d="M 8047,5063 C 9811,5063 11159,6410 11159,8174 11159,9938 9811,11286 8047,11286 6283,11286 4936,9938 4936,8174 4936,6410 6283,5063 8047,5063 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
|
|
@ -43,13 +43,17 @@
|
|||
background-repeat: no-repeat;
|
||||
background-color: rgba(#000, 0.5);
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition-property: opacity, background-color;
|
||||
transition-duration: 0.15s;
|
||||
|
||||
&.visible {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
+desktop() {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
opacity: 0.85;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
align-items: center;
|
||||
|
||||
+desktop() {
|
||||
left: 20px;
|
||||
width: 36px;
|
||||
left: 1.0em;
|
||||
width: 2.6em;
|
||||
}
|
||||
|
||||
+mobile() {
|
||||
left: 10px;
|
||||
width: 32px;
|
||||
left: 0.5em;
|
||||
width: 2.6em;
|
||||
}
|
||||
|
||||
> .button {
|
||||
|
|
@ -34,13 +34,13 @@
|
|||
justify-content: center;
|
||||
|
||||
+desktop() {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
height: 2.5em;
|
||||
width: 2.5em;
|
||||
}
|
||||
|
||||
+mobile() {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
height: 2.5em;
|
||||
width: 2.5em;
|
||||
}
|
||||
|
||||
&.on {
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
}
|
||||
|
||||
&.leave-meeting {
|
||||
background-image: url('/resources/images/leave-meeting.svg');
|
||||
background-image: url('/resources/images/cancel.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,93 @@
|
|||
}
|
||||
}
|
||||
|
||||
> .toolarea-button {
|
||||
text-align: center;
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: mixed;
|
||||
list-style: none;
|
||||
height: 115px;
|
||||
width: 35px;
|
||||
left: -35px;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
|
||||
> .badge {
|
||||
border-radius: 50%;
|
||||
writing-mode: horizontal-tb;
|
||||
font-size: 1rem;
|
||||
background: #b12525;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
margin-top: -10px;
|
||||
line-height: 1rem;
|
||||
margin-left: -0px;
|
||||
position: absolute;
|
||||
padding: 0.2rem 0.4rem;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
&.long {
|
||||
border-radius: 25% / 50%;
|
||||
margin-top: -13px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
}
|
||||
|
||||
> .content {
|
||||
border: 1px solid #AAA;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
border-bottom-left-radius: 6px;
|
||||
border-top-left-radius: 6px;
|
||||
background: #FFF;
|
||||
color: #333;
|
||||
z-index: 2;
|
||||
border-right-color: #FFF;
|
||||
|
||||
&:before, &:after {
|
||||
border: 1px solid #AAA;
|
||||
position: absolute;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
content: "";
|
||||
}
|
||||
|
||||
&:before {
|
||||
top: -6px;
|
||||
right: 0;
|
||||
border-bottom-right-radius: 6px;
|
||||
border-width: 0px 1px 1px 0px;
|
||||
box-shadow: 0px 3px 0 #FFF;
|
||||
}
|
||||
|
||||
&:after {
|
||||
bottom: -6px;
|
||||
right: 0;
|
||||
border-top-right-radius: 6px;
|
||||
border-width: 1px 1px 0px 0px;
|
||||
box-shadow: 0px -3px 0 #FFF;
|
||||
}
|
||||
|
||||
> .toolarea-icon {
|
||||
background-position: center;
|
||||
background-size: 75%;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 100%;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
|
||||
background-image: url('/resources/images/icon_tool_area_black.svg');
|
||||
}
|
||||
|
||||
> p {
|
||||
padding: 9px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
|
|
@ -158,10 +245,6 @@
|
|||
background-image: url('/resources/images/icon_tool_area_black.svg');
|
||||
}
|
||||
}
|
||||
|
||||
&.toolarea-close-button {
|
||||
background-image: url('/resources/images/arrow_right.svg');
|
||||
}
|
||||
}
|
||||
|
||||
> .badge {
|
||||
|
|
|
|||
|
|
@ -346,6 +346,25 @@ class Room extends EventEmitter
|
|||
);
|
||||
});
|
||||
|
||||
signalingPeer.socket.on('request-consumer-keyframe', (request, cb) =>
|
||||
{
|
||||
cb(null);
|
||||
|
||||
const { consumerId } = request;
|
||||
const mediaPeer = this._mediaRoom.getPeerByName(signalingPeer.peerName);
|
||||
const consumer = mediaPeer.consumers
|
||||
.find((_consumer) => _consumer.id === consumerId);
|
||||
|
||||
if (!consumer)
|
||||
{
|
||||
logger.warn('consumer with id "%s" not found', consumerId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
consumer.requestKeyFrame();
|
||||
});
|
||||
|
||||
signalingPeer.socket.on('disconnect', () =>
|
||||
{
|
||||
logger.debug('Peer "close" event [peer:"%s"]', signalingPeer.peerName);
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@ function handleTransport(transport, baseEvent, stream)
|
|||
});
|
||||
|
||||
const statsInterval = setInterval(() =>
|
||||
{
|
||||
if (typeof transport.getStats === 'function')
|
||||
{
|
||||
transport.getStats()
|
||||
.then((stats) =>
|
||||
|
|
@ -166,6 +168,7 @@ function handleTransport(transport, baseEvent, stream)
|
|||
}),
|
||||
stream);
|
||||
});
|
||||
}
|
||||
}, STATS_INTERVAL);
|
||||
|
||||
transport.on('close', (originator) =>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"compression": "^1.7.3",
|
||||
"debug": "^4.1.0",
|
||||
"express": "^4.16.3",
|
||||
"mediasoup": "^2.3.3",
|
||||
"mediasoup": "^2.4.3",
|
||||
"passport-dataporten": "^1.3.0",
|
||||
"socket.io": "^2.1.1"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -71,6 +71,11 @@ app.get('/login', (req, res, next) =>
|
|||
|
||||
dataporten.setupLogout(app, '/logout');
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
console.log(req.url);
|
||||
res.sendFile(`${__dirname}/public/chooseRoom.html`);
|
||||
})
|
||||
|
||||
app.get(
|
||||
'/auth-callback',
|
||||
dataporten.passport.authenticate('dataporten', { failureRedirect: '/login' }),
|
||||
|
|
|
|||
Loading…
Reference in New Issue