Add support for up to 4 feeds
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
parent
198722eb41
commit
1f27354439
3 changed files with 71 additions and 35 deletions
|
@ -21,7 +21,7 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.mx_VideoFeed_remote {
|
.mx_VideoFeed_primary {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -33,7 +33,7 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_VideoFeed_local {
|
.mx_VideoFeed_secondary {
|
||||||
max-width: 25%;
|
max-width: 25%;
|
||||||
max-height: 25%;
|
max-height: 25%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -47,6 +47,34 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_VideoFeed_tertiary {
|
||||||
|
max-width: 25%;
|
||||||
|
max-height: 25%;
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
bottom: 10px;
|
||||||
|
z-index: 100;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&.mx_VideoFeed_video {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_VideoFeed_quaternary {
|
||||||
|
max-width: 25%;
|
||||||
|
max-height: 25%;
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: 10px;
|
||||||
|
z-index: 100;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&.mx_VideoFeed_video {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.mx_VideoFeed_mirror {
|
.mx_VideoFeed_mirror {
|
||||||
transform: scale(-1, 1);
|
transform: scale(-1, 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,13 @@ import DialpadContextMenu from '../context_menus/DialpadContextMenu';
|
||||||
import { CallFeed } from 'matrix-js-sdk/src/webrtc/callFeed';
|
import { CallFeed } from 'matrix-js-sdk/src/webrtc/callFeed';
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||||
|
|
||||||
|
const FEED_CLASS_NAMES = [
|
||||||
|
"mx_VideoFeed_primary",
|
||||||
|
"mx_VideoFeed_secondary",
|
||||||
|
"mx_VideoFeed_tertiary",
|
||||||
|
"mx_VideoFeed_quaternary",
|
||||||
|
];
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
// The call for us to display
|
// The call for us to display
|
||||||
call: MatrixCall,
|
call: MatrixCall,
|
||||||
|
@ -371,6 +378,34 @@ export default class CallView extends React.Component<IProps, IState> {
|
||||||
this.props.call.transferToCall(transfereeCall);
|
this.props.call.transferToCall(transfereeCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private renderFeeds(feeds: Array<CallFeed>, offset = 0) {
|
||||||
|
const sortedFeeds = [...feeds].sort((a, b) => {
|
||||||
|
if (b.purpose === SDPStreamMetadataPurpose.Screenshare && !b.isLocal()) return 1;
|
||||||
|
if (a.isLocal() && !b.isLocal()) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return sortedFeeds.map((feed, i) => {
|
||||||
|
i += offset;
|
||||||
|
// TODO: Later the CallView should probably be reworked to support
|
||||||
|
// any number of feeds but now we can't render more than 4 feeds
|
||||||
|
if (i >= 4) return;
|
||||||
|
// Here we check to hide local audio feeds to achieve the same UI/UX
|
||||||
|
// as before. But once again this might be subject to change
|
||||||
|
if (feed.isVideoMuted() && feed.isLocal()) return;
|
||||||
|
return (
|
||||||
|
<VideoFeed
|
||||||
|
key={feed.stream.id}
|
||||||
|
className={FEED_CLASS_NAMES[i]}
|
||||||
|
feed={feed}
|
||||||
|
call={this.props.call}
|
||||||
|
pipMode={this.props.pipMode}
|
||||||
|
onResize={this.props.onResize}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const callRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
|
const callRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
|
||||||
|
@ -594,20 +629,8 @@ export default class CallView extends React.Component<IProps, IState> {
|
||||||
mx_CallView_voice: true,
|
mx_CallView_voice: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const feeds = this.props.call.getLocalFeeds().map((feed, i) => {
|
// We pass offset of one to avoid a feed being rendered as primary
|
||||||
// Here we check to hide local audio feeds to achieve the same UI/UX
|
const feeds = this.renderFeeds(this.props.call.getLocalFeeds(), 1);
|
||||||
// as before. But once again this might be subject to change
|
|
||||||
if (feed.isVideoMuted()) return;
|
|
||||||
return (
|
|
||||||
<VideoFeed
|
|
||||||
key={i}
|
|
||||||
feed={feed}
|
|
||||||
call={this.props.call}
|
|
||||||
pipMode={this.props.pipMode}
|
|
||||||
onResize={this.props.onResize}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Saying "Connecting" here isn't really true, but the best thing
|
// Saying "Connecting" here isn't really true, but the best thing
|
||||||
// I can come up with, but this might be subject to change as well
|
// I can come up with, but this might be subject to change as well
|
||||||
|
@ -631,23 +654,7 @@ export default class CallView extends React.Component<IProps, IState> {
|
||||||
mx_CallView_video: true,
|
mx_CallView_video: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Later the CallView should probably be reworked to support
|
const feeds = this.renderFeeds(this.state.feeds);
|
||||||
// any number of feeds but now we can always expect there to be two
|
|
||||||
// feeds. This is because the js-sdk ignores any new incoming streams
|
|
||||||
const feeds = this.state.feeds.map((feed, i) => {
|
|
||||||
// Here we check to hide local audio feeds to achieve the same UI/UX
|
|
||||||
// as before. But once again this might be subject to change
|
|
||||||
if (feed.isVideoMuted() && feed.isLocal()) return;
|
|
||||||
return (
|
|
||||||
<VideoFeed
|
|
||||||
key={i}
|
|
||||||
feed={feed}
|
|
||||||
call={this.props.call}
|
|
||||||
pipMode={this.props.pipMode}
|
|
||||||
onResize={this.props.onResize}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
contentView = <div className={containerClasses} ref={this.contentRef} onMouseMove={this.onMouseMove}>
|
contentView = <div className={containerClasses} ref={this.contentRef} onMouseMove={this.onMouseMove}>
|
||||||
{feeds}
|
{feeds}
|
||||||
|
|
|
@ -37,6 +37,8 @@ interface IProps {
|
||||||
// a callback which is called when the video element is resized
|
// a callback which is called when the video element is resized
|
||||||
// due to a change in video metadata
|
// due to a change in video metadata
|
||||||
onResize?: (e: Event) => void,
|
onResize?: (e: Event) => void,
|
||||||
|
|
||||||
|
className: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
@ -121,8 +123,7 @@ export default class VideoFeed extends React.Component<IProps, IState> {
|
||||||
render() {
|
render() {
|
||||||
const videoClasses = {
|
const videoClasses = {
|
||||||
mx_VideoFeed: true,
|
mx_VideoFeed: true,
|
||||||
mx_VideoFeed_local: this.props.feed.isLocal(),
|
[this.props.className]: true,
|
||||||
mx_VideoFeed_remote: !this.props.feed.isLocal(),
|
|
||||||
mx_VideoFeed_voice: this.state.videoMuted,
|
mx_VideoFeed_voice: this.state.videoMuted,
|
||||||
mx_VideoFeed_video: !this.state.videoMuted,
|
mx_VideoFeed_video: !this.state.videoMuted,
|
||||||
mx_VideoFeed_mirror: (
|
mx_VideoFeed_mirror: (
|
||||||
|
|
Loading…
Reference in a new issue