Added support for moving video to new window. Fixed various bugs.

master
Håvar Aambø Fosstveit 2018-11-14 13:23:22 +01:00
parent 0d334d532b
commit e695909911
13 changed files with 188 additions and 12 deletions

View File

@ -16,7 +16,7 @@ import {
const logger = new Logger('RoomClient'); const logger = new Logger('RoomClient');
const ROOM_OPTIONS = let ROOM_OPTIONS =
{ {
requestTimeout : requestTimeout, requestTimeout : requestTimeout,
transportOptions : transportOptions, transportOptions : transportOptions,
@ -71,6 +71,9 @@ export default class RoomClient
// Socket.io peer connection // Socket.io peer connection
this._signalingSocket = io(signalingUrl); this._signalingSocket = io(signalingUrl);
if (this._device.flag === 'firefox')
ROOM_OPTIONS = Object.assign({ iceTransportPolicy: 'relay' }, ROOM_OPTIONS);
// mediasoup-client Room instance. // mediasoup-client Room instance.
this._room = new mediasoupClient.Room(ROOM_OPTIONS); this._room = new mediasoupClient.Room(ROOM_OPTIONS);
this._room.roomId = roomId; this._room.roomId = roomId;
@ -160,6 +163,21 @@ export default class RoomClient
{ {
this._dispatch(stateActions.toggleAdvancedMode()); this._dispatch(stateActions.toggleAdvancedMode());
this.notify('Toggled advanced mode.'); this.notify('Toggled advanced mode.');
break;
}
case '1': // Set democratic view
{
this._dispatch(stateActions.setDisplayMode('democratic'));
this.notify('Changed layout to democratic view.');
break;
}
case '2': // Set filmstrip view
{
this._dispatch(stateActions.setDisplayMode('filmstrip'));
this.notify('Changed layout to filmstrip view.');
break;
} }
} }
} }
@ -213,9 +231,9 @@ export default class RoomClient
if (called) if (called)
return; return;
called = true; called = true;
callback(new Error('Callback timeout')); callback(new Error('Request timeout.'));
}, },
5000 ROOM_OPTIONS.requestTimeout
); );
return (...args) => return (...args) =>

View File

@ -58,7 +58,7 @@ Chat.propTypes =
Chat.defaultProps = Chat.defaultProps =
{ {
senderPlaceHolder : 'Type a message...', senderPlaceHolder : 'Type a message...',
autofocus : true, autofocus : false,
displayName : null displayName : null
}; };

View File

@ -56,7 +56,6 @@ const FullScreenView = (props) =>
videoTrack={consumer ? consumer.track : null} videoTrack={consumer ? consumer.track : null}
videoVisible={consumerVisible} videoVisible={consumerVisible}
videoProfile={consumerProfile} videoProfile={consumerProfile}
toggleFullscreen={() => toggleConsumerFullscreen(consumer)}
/> />
</div> </div>
); );

View File

@ -86,6 +86,5 @@ FullView.propTypes =
{ {
videoTrack : PropTypes.any, videoTrack : PropTypes.any,
videoVisible : PropTypes.bool, videoVisible : PropTypes.bool,
videoProfile : PropTypes.string, videoProfile : PropTypes.string
toggleFullscreen : PropTypes.func.isRequired
}; };

View File

@ -39,6 +39,7 @@ class Peer extends Component
onMuteMic, onMuteMic,
onUnmuteMic, onUnmuteMic,
toggleConsumerFullscreen, toggleConsumerFullscreen,
toggleConsumerWindow,
style style
} = this.props; } = this.props;
@ -126,6 +127,15 @@ class Peer extends Component
}} }}
/> />
<div
className={classnames('button', 'newwindow')}
onClick={(e) =>
{
e.stopPropagation();
toggleConsumerWindow(webcamConsumer);
}}
/>
<div <div
className={classnames('button', 'fullscreen')} className={classnames('button', 'fullscreen')}
onClick={(e) => onClick={(e) =>
@ -155,6 +165,15 @@ class Peer extends Component
visible : this.state.controlsVisible visible : this.state.controlsVisible
})} })}
> >
<div
className={classnames('button', 'newwindow')}
onClick={(e) =>
{
e.stopPropagation();
toggleConsumerWindow(screenConsumer);
}}
/>
<div <div
className={classnames('button', 'fullscreen')} className={classnames('button', 'fullscreen')}
onClick={(e) => onClick={(e) =>
@ -190,7 +209,8 @@ Peer.propTypes =
onUnmuteMic : PropTypes.func.isRequired, onUnmuteMic : PropTypes.func.isRequired,
streamDimensions : PropTypes.object, streamDimensions : PropTypes.object,
style : PropTypes.object, style : PropTypes.object,
toggleConsumerFullscreen : PropTypes.func.isRequired toggleConsumerFullscreen : PropTypes.func.isRequired,
toggleConsumerWindow : PropTypes.func.isRequired
}; };
const mapStateToProps = (state, { name }) => const mapStateToProps = (state, { name }) =>
@ -228,6 +248,11 @@ const mapDispatchToProps = (dispatch) =>
{ {
if (consumer) if (consumer)
dispatch(stateActions.toggleConsumerFullscreen(consumer.id)); dispatch(stateActions.toggleConsumerFullscreen(consumer.id));
},
toggleConsumerWindow : (consumer) =>
{
if (consumer)
dispatch(stateActions.toggleConsumerWindow(consumer.id));
} }
}; };
}; };

View File

@ -16,6 +16,7 @@ import Notifications from './Notifications';
import ToolAreaButton from './ToolArea/ToolAreaButton'; import ToolAreaButton from './ToolArea/ToolAreaButton';
import ToolArea from './ToolArea/ToolArea'; import ToolArea from './ToolArea/ToolArea';
import FullScreenView from './FullScreenView'; import FullScreenView from './FullScreenView';
import VideoWindow from './VideoWindow/VideoWindow';
import Draggable from 'react-draggable'; import Draggable from 'react-draggable';
import { idle } from '../utils'; import { idle } from '../utils';
import Sidebar from './Sidebar'; import Sidebar from './Sidebar';
@ -88,6 +89,8 @@ class Room extends React.Component
<FullScreenView advancedMode={room.advancedMode} /> <FullScreenView advancedMode={room.advancedMode} />
<VideoWindow advancedMode={room.advancedMode} />
<div className='room-wrapper'> <div className='room-wrapper'>
<div data-component='Logo' /> <div data-component='Logo' />
<AudioPeers /> <AudioPeers />

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import Spinner from 'react-spinner'; import Spinner from 'react-spinner';
export default class PeerView extends React.Component export default class ScreenView extends React.Component
{ {
constructor(props) constructor(props)
{ {
@ -157,7 +157,7 @@ export default class PeerView extends React.Component
} }
} }
PeerView.propTypes = ScreenView.propTypes =
{ {
isMe : PropTypes.bool, isMe : PropTypes.bool,
advancedMode : PropTypes.bool, advancedMode : PropTypes.bool,

View File

@ -0,0 +1,98 @@
import React from 'react';
import { connect } from 'react-redux';
import NewWindow from 'react-new-window';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import * as appPropTypes from '../appPropTypes';
import * as stateActions from '../../redux/stateActions';
import FullView from '../FullView';
const VideoWindow = (props) =>
{
const {
advancedMode,
consumer,
toggleConsumerWindow,
toolbarsVisible
} = props;
if (!consumer)
return null;
const consumerVisible = (
Boolean(consumer) &&
!consumer.locallyPaused &&
!consumer.remotelyPaused
);
let consumerProfile;
if (consumer)
consumerProfile = consumer.profile;
return (
<NewWindow onUnload={toggleConsumerWindow}>
<div data-component='FullScreenView'>
{consumerVisible && !consumer.supported ?
<div className='incompatible-video'>
<p>incompatible video</p>
</div>
:null
}
<div className='controls'>
<div
className={classnames('button', 'fullscreen', 'room-controls', {
visible : toolbarsVisible
})}
onClick={(e) =>
{
e.stopPropagation();
toggleConsumerWindow();
}}
/>
</div>
<FullView
advancedMode={advancedMode}
videoTrack={consumer ? consumer.track : null}
videoVisible={consumerVisible}
videoProfile={consumerProfile}
/>
</div>
</NewWindow>
);
};
VideoWindow.propTypes =
{
advancedMode : PropTypes.bool,
consumer : appPropTypes.Consumer,
toggleConsumerWindow : PropTypes.func.isRequired,
toolbarsVisible : PropTypes.bool
};
const mapStateToProps = (state) =>
{
return {
consumer : state.consumers[state.room.windowConsumer],
toolbarsVisible : state.room.toolbarsVisible
};
};
const mapDispatchToProps = (dispatch) =>
{
return {
toggleConsumerWindow : () =>
{
dispatch(stateActions.toggleConsumerWindow(null));
}
};
};
const VideoWindowContainer = connect(
mapStateToProps,
mapDispatchToProps
)(VideoWindow);
export default VideoWindowContainer;

View File

@ -6,6 +6,7 @@ const initialState =
showSettings : false, showSettings : false,
advancedMode : false, advancedMode : false,
fullScreenConsumer : null, // ConsumerID fullScreenConsumer : null, // ConsumerID
windowConsumer : null, // ConsumerID
toolbarsVisible : true, toolbarsVisible : true,
mode : 'democratic', mode : 'democratic',
selectedPeerName : null, selectedPeerName : null,
@ -62,6 +63,17 @@ const room = (state = initialState, action) =>
return { ...state, fullScreenConsumer: currentConsumer ? null : consumerId }; return { ...state, fullScreenConsumer: currentConsumer ? null : consumerId };
} }
case 'TOGGLE_WINDOW_CONSUMER':
{
const { consumerId } = action.payload;
const currentConsumer = state.windowConsumer;
if (currentConsumer === consumerId)
return { ...state, windowConsumer: null };
else
return { ...state, windowConsumer: consumerId };
}
case 'SET_TOOLBARS_VISIBLE': case 'SET_TOOLBARS_VISIBLE':
{ {
const { toolbarsVisible } = action.payload; const { toolbarsVisible } = action.payload;

View File

@ -389,6 +389,14 @@ export const toggleConsumerFullscreen = (consumerId) =>
}; };
}; };
export const toggleConsumerWindow = (consumerId) =>
{
return {
type : 'TOGGLE_WINDOW_CONSUMER',
payload : { consumerId }
};
};
export const setToolbarsVisible = (toolbarsVisible) => ({ export const setToolbarsVisible = (toolbarsVisible) => ({
type : 'SET_TOOLBARS_VISIBLE', type : 'SET_TOOLBARS_VISIBLE',
payload : { toolbarsVisible } payload : { toolbarsVisible }

View File

@ -28,6 +28,7 @@
"react-dom": "^16.5.2", "react-dom": "^16.5.2",
"react-draggable": "^3.0.5", "react-draggable": "^3.0.5",
"react-dropdown": "^1.5.0", "react-dropdown": "^1.5.0",
"react-new-window": "0.0.9",
"react-redux": "^5.0.7", "react-redux": "^5.0.7",
"react-spinner": "^0.2.7", "react-spinner": "^0.2.7",
"react-tooltip": "^3.9.0", "react-tooltip": "^3.9.0",

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g>
<path
d="M23.78700473 7.7610694C23.78700473 7.7610694 19.32738673 2.3867608 19.32738673 2.3867608C19.13984773 2.1607585 18.91713373 2.0882379 18.63693973 2.2176245C18.36703673 2.3422016 18.22715573 2.5841415 18.22715573 2.9368427C18.22715573 2.9368427 18.22715573 5.6735307 18.22715573 5.6735307C16.60026573 6.0262319 15.09099273 6.6909889 13.72054573 7.6906705C12.03598073 8.9196554 10.69300173 10.4408914 9.74082913 12.3174694C9.56878473 12.6565904 9.61472063 13.0060384 9.85793833 13.2765524C10.07145773 13.5142954 10.41981173 13.5447094 10.65379573 13.3611024C10.66553573 13.3469524 10.66553573 13.3469524 10.67727573 13.3469524C10.84110373 13.2202534 11.00363973 13.1043994 11.15725573 13.0083964C11.31983073 12.9069714 11.66067273 12.7122784 12.18733073 12.4444524C12.71395073 12.1762954 13.21736773 11.9365244 13.72058873 11.7532424C14.22400573 11.5696774 14.85607473 11.3852164 15.59343573 11.2311224C16.34257473 11.0749524 17.07997473 10.9913044 17.79417273 10.9913044C17.79417273 10.9913044 18.22715973 10.9913044 18.22715973 10.9913044C18.22715973 10.9913044 18.22715973 13.6574994 18.22715973 13.6574994C18.22715973 14.0102004 18.36723673 14.2509614 18.63694373 14.3767174C18.73010373 14.4203774 18.81250973 14.4332974 18.87092773 14.4332974C19.04645473 14.4332974 19.19826973 14.3622874 19.32739073 14.2076254C19.32739073 14.2076254 23.78708673 8.8613254 23.78708673 8.8613254C24.03351273 8.5660564 24.03300473 8.0574684 23.78700873 7.7610674C23.78700873 7.7610674 23.78700873 7.7610674 23.78700873 7.7610674M19.51465573 11.7673384C19.51465573 11.7673384 19.51465573 10.2720364 19.51465573 10.2720364C19.51465573 9.8630814 19.26897373 9.5103804 18.94108373 9.4962344C18.68362273 9.4537944 18.29731573 9.4396544 17.79417273 9.4396544C16.12032873 9.4396544 14.43478673 9.7782104 12.76090373 10.4694194C14.54011773 8.6497074 16.61200773 7.5365769 18.96455973 7.1263967C19.28071173 7.0713227 19.51473473 6.7454039 19.51473473 6.3364497C19.51473473 6.3364497 19.51473473 4.8128558 19.51473473 4.8128558C19.51473473 4.8128558 22.41761773 8.3111524 22.41761773 8.3111524C22.41761773 8.3111524 19.51465573 11.7673414 19.51465573 11.7673414" />
<path
d="M17.17360373 20.0049884C17.17360373 20.0615284 17.10341373 20.1461164 17.04499073 20.1461164C17.04499073 20.1461164 1.44180703 20.1461164 1.44180703 20.1461164C1.35991303 20.1461164 1.32469783 20.1036764 1.32469783 20.0049884C1.32469783 20.0049884 1.32469783 6.3082043 1.32469783 6.3082043C1.32469783 6.2095143 1.35991283 6.1670295 1.44180703 6.1670295C1.44180703 6.1670295 14.34107173 6.1670295 14.34107173 6.1670295C14.34107173 6.1670295 14.34107173 4.5871826 14.34107173 4.5871826C14.34107173 4.5871826 1.44180703 4.5871826 1.44180703 4.5871826C0.70440653 4.5871826 0.10735711 5.2784393 0.02542373 6.139068C0.02542373 6.139068 0.02542373 6.3082043 0.02542373 6.3082043C0.02542373 6.3082043 0.02542373 20.0050354 0.02542373 20.0050354C0.02542373 20.0050354 0.02542373 20.1744544 0.02542373 20.1744544C0.10731799 21.0348004 0.70440653 21.7118644 1.44180703 21.7118644C1.44180703 21.7118644 17.04499073 21.7118644 17.04499073 21.7118644C17.44280173 21.7118644 17.78516873 21.5460284 18.05162873 21.2180354C18.32380073 20.8830634 18.46141273 20.4705254 18.46141273 20.0049884C18.46141273 20.0049884 18.46141273 15.3501814 18.46141273 15.3501814C18.46141273 15.3501814 17.17364273 15.3501814 17.17364273 15.3501814C17.17364273 15.3501814 17.17364273 20.0049884 17.17364273 20.0049884C17.17364273 20.0049884 17.17360373 20.0049884 17.17360373 20.0049884" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -189,6 +189,11 @@
background-image: url('/resources/images/icon_fullscreen_black.svg'); background-image: url('/resources/images/icon_fullscreen_black.svg');
background-color: rgba(#fff, 0.7); background-color: rgba(#fff, 0.7);
} }
&.newwindow {
background-image: url('/resources/images/icon_new_window_black.svg');
background-color: rgba(#fff, 0.7);
}
} }
} }
} }