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%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
|
@ -33,7 +33,7 @@ limitations under the License.
|
|||
}
|
||||
}
|
||||
|
||||
.mx_VideoFeed_local {
|
||||
.mx_VideoFeed_secondary {
|
||||
max-width: 25%;
|
||||
max-height: 25%;
|
||||
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 {
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,13 @@ import DialpadContextMenu from '../context_menus/DialpadContextMenu';
|
|||
import { CallFeed } from 'matrix-js-sdk/src/webrtc/callFeed';
|
||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||
|
||||
const FEED_CLASS_NAMES = [
|
||||
"mx_VideoFeed_primary",
|
||||
"mx_VideoFeed_secondary",
|
||||
"mx_VideoFeed_tertiary",
|
||||
"mx_VideoFeed_quaternary",
|
||||
];
|
||||
|
||||
interface IProps {
|
||||
// The call for us to display
|
||||
call: MatrixCall,
|
||||
|
@ -371,6 +378,34 @@ export default class CallView extends React.Component<IProps, IState> {
|
|||
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() {
|
||||
const client = MatrixClientPeg.get();
|
||||
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,
|
||||
});
|
||||
|
||||
const feeds = this.props.call.getLocalFeeds().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()) return;
|
||||
return (
|
||||
<VideoFeed
|
||||
key={i}
|
||||
feed={feed}
|
||||
call={this.props.call}
|
||||
pipMode={this.props.pipMode}
|
||||
onResize={this.props.onResize}
|
||||
/>
|
||||
);
|
||||
});
|
||||
// We pass offset of one to avoid a feed being rendered as primary
|
||||
const feeds = this.renderFeeds(this.props.call.getLocalFeeds(), 1);
|
||||
|
||||
// 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
|
||||
|
@ -631,23 +654,7 @@ export default class CallView extends React.Component<IProps, IState> {
|
|||
mx_CallView_video: true,
|
||||
});
|
||||
|
||||
// TODO: Later the CallView should probably be reworked to support
|
||||
// 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}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const feeds = this.renderFeeds(this.state.feeds);
|
||||
|
||||
contentView = <div className={containerClasses} ref={this.contentRef} onMouseMove={this.onMouseMove}>
|
||||
{feeds}
|
||||
|
|
|
@ -37,6 +37,8 @@ interface IProps {
|
|||
// a callback which is called when the video element is resized
|
||||
// due to a change in video metadata
|
||||
onResize?: (e: Event) => void,
|
||||
|
||||
className: string,
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -121,8 +123,7 @@ export default class VideoFeed extends React.Component<IProps, IState> {
|
|||
render() {
|
||||
const videoClasses = {
|
||||
mx_VideoFeed: true,
|
||||
mx_VideoFeed_local: this.props.feed.isLocal(),
|
||||
mx_VideoFeed_remote: !this.props.feed.isLocal(),
|
||||
[this.props.className]: true,
|
||||
mx_VideoFeed_voice: this.state.videoMuted,
|
||||
mx_VideoFeed_video: !this.state.videoMuted,
|
||||
mx_VideoFeed_mirror: (
|
||||
|
|
Loading…
Reference in a new issue