Video calls
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
// InfoView: panel with topic/user info.
|
||||
import React from 'react';
|
||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import Tinode from 'tinode-sdk';
|
||||
|
||||
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
||||
import BadgeList from '../widgets/badge-list.jsx';
|
||||
import MenuCancel from '../widgets/menu-cancel.jsx';
|
||||
|
||||
import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH, NO_ACCESS_MODE } from '../config.js';
|
||||
|
||||
import { makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import { arrayEqual, theCard } from '../lib/utils.js';
|
||||
|
||||
function _clip(str, length) {
|
||||
return str && str.substring(0, length);
|
||||
}
|
||||
|
||||
class CallView extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
topic: null,
|
||||
fullName: undefined,
|
||||
avatar: null,
|
||||
trustedBadges: [],
|
||||
previousMetaDesc: undefined,
|
||||
offerSent: false,
|
||||
};
|
||||
|
||||
this.resetDesc = this.resetDesc.bind(this);
|
||||
this.onMetaDesc = this.onMetaDesc.bind(this);
|
||||
this.handleRejectCall = this.handleRejectCall.bind(this);
|
||||
this.handleAcceptCall = this.handleAcceptCall.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
this.resetDesc(topic, this.props);
|
||||
if (this.props.callState == 2) {
|
||||
this.props.onRinging(this.props.topic, this.props.seq);
|
||||
}
|
||||
}
|
||||
|
||||
// No need to separately handle component mount.
|
||||
componentDidUpdate(props) {
|
||||
const topic = this.props.tinode.getTopic(props.topic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.onMetaDesc != topic.onMetaDesc) {
|
||||
this.previousMetaDesc = topic.onMetaDesc;
|
||||
topic.onMetaDesc = this.onMetaDesc;
|
||||
}
|
||||
|
||||
if (this.state.topic != props.topic) {
|
||||
this.setState({topic: props.topic});
|
||||
this.resetDesc(topic, props);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
this.setState({topic: null});
|
||||
topic.onMetaDesc = this.previousMetaDesc;
|
||||
}
|
||||
|
||||
resetDesc(topic, props) {
|
||||
const defacs = topic.getDefaultAccess() || {};
|
||||
const acs = topic.getAccessMode();
|
||||
const badges = [];
|
||||
if (topic.trusted) {
|
||||
for (const [key, val] of Object.entries(topic.trusted)) {
|
||||
if (val) {
|
||||
badges.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
fullName: _clip(topic.public ? topic.public.fn : undefined, MAX_TITLE_LENGTH),
|
||||
avatar: makeImageUrl(topic.public ? topic.public.photo : null),
|
||||
trustedBadges: badges,
|
||||
});
|
||||
}
|
||||
|
||||
onMetaDesc(desc) {
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
this.resetDesc(topic, this.props);
|
||||
|
||||
if (this.previousMetaDesc && this.previousMetaDesc != this.onMetaDesc) {
|
||||
this.previousMetaDesc(desc);
|
||||
}
|
||||
}
|
||||
|
||||
handleAcceptCall() {
|
||||
this.props.onAcceptCall(this.props.topic);
|
||||
}
|
||||
|
||||
handleRejectCall() {
|
||||
this.props.onReject(this.props.topic, this.props.seq);
|
||||
this.props.onClose();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
let panelTitle = 'Unknown';
|
||||
switch (this.props.callState) {
|
||||
case 1:
|
||||
panelTitle = 'Calling';
|
||||
break;
|
||||
case 2:
|
||||
panelTitle = 'Incoming Call From';
|
||||
break;
|
||||
case 3:
|
||||
panelTitle = 'Call Established';
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="info-view">
|
||||
<div className="caption-panel" id="info-caption-panel">
|
||||
<div className="panel-title" id="info-title">{panelTitle}</div>
|
||||
<div>
|
||||
<MenuCancel onCancel={this.handleRejectCall} />
|
||||
</div>
|
||||
</div>
|
||||
<div id="info-view-content" className="scrollable-panel">
|
||||
<div className="panel-form-column">
|
||||
<center>
|
||||
<AvatarUpload
|
||||
tinode={this.props.tinode}
|
||||
avatar={this.state.avatar}
|
||||
readOnly={true}
|
||||
uid={this.props.topic}
|
||||
title={this.state.fullName} />
|
||||
</center>
|
||||
<div className="group" style={{padding: "10px", textAlign: "center"}}>
|
||||
<div className="large ellipsized">{this.state.fullName}</div>
|
||||
</div>
|
||||
<div className="group" style={{textAlign: "center"}}>
|
||||
<BadgeList trustedBadges={this.state.trustedBadges} />
|
||||
</div>
|
||||
<div id="actions" className="group" style={{padding: "20px", textAlign: "center"}}>
|
||||
{this.props.callState >= 1 && this.props.callState < 3 ?
|
||||
<button onClick={this.handleRejectCall} style={{borderRadius: "10px", backgroundColor: "red"}}>
|
||||
<i className="material-icons">call_end</i>
|
||||
</button>
|
||||
:
|
||||
null
|
||||
}
|
||||
{this.props.callState >= 2 && this.props.callState < 3 ?
|
||||
<button onClick={this.handleAcceptCall} style={{borderRadius: "10px", backgroundColor: "green"}}>
|
||||
<i className="material-icons">call</i>
|
||||
</button>
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default injectIntl(CallView);
|
||||
@@ -14,6 +14,7 @@ import Invitation from '../widgets/invitation.jsx';
|
||||
import LetterTile from '../widgets/letter-tile.jsx';
|
||||
import LoadSpinner from '../widgets/load-spinner.jsx';
|
||||
import LogoView from './logo-view.jsx';
|
||||
import RtcPanel from '../widgets/rtc-panel.jsx';
|
||||
import SendMessage from '../widgets/send-message.jsx';
|
||||
|
||||
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY,
|
||||
@@ -113,6 +114,8 @@ class MessagesView extends React.Component {
|
||||
this.handlePickReply = this.handlePickReply.bind(this);
|
||||
this.handleCancelReply = this.handleCancelReply.bind(this);
|
||||
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
||||
this.handleRtcClick = this.handleRtcClick.bind(this);
|
||||
this.handleRtcClose = this.handleRtcClose.bind(this);
|
||||
|
||||
this.chatMessageRefs = {};
|
||||
this.getOrCreateMessageRef = this.getOrCreateMessageRef.bind(this);
|
||||
@@ -173,7 +176,17 @@ class MessagesView extends React.Component {
|
||||
topic.onPres = this.handleSubsUpdated;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (this.props.callTopic == this.props.topic && !this.state.rtcPanel) {
|
||||
this.handleRtcClick();
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if (this.state.rtcPanel == null && topic && topic.name == this.props.callTopic && (this.props.callState == 1 || this.props.callState == 3)) {
|
||||
console.log('--> setting rtc panel, call state = ', this.props.callState);
|
||||
this.setState({rtcPanel: { topic: this.props.callTopic }});
|
||||
}
|
||||
*/
|
||||
if (!this.props.applicationVisible) {
|
||||
// If application is not visible, flush all unsent 'read' notifications.
|
||||
this.clearNotificationQueue();
|
||||
@@ -189,6 +202,11 @@ class MessagesView extends React.Component {
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
let nextState = {};
|
||||
/*
|
||||
if (nextProps.callState == 3 || nextProps.callState == 1) {
|
||||
nextState.rtcPanel = { topic: nextProps.topic };
|
||||
}
|
||||
*/
|
||||
if (!nextProps.topic) {
|
||||
// Default state: no topic.
|
||||
nextState = {
|
||||
@@ -204,6 +222,7 @@ class MessagesView extends React.Component {
|
||||
docPreview: null,
|
||||
imagePreview: null,
|
||||
imagePostview: null,
|
||||
rtcPanel: null,//typeof nextProps.topic != 'undefined' && nextPropstopic.name == this.props.callTopic && (nextProps.callState == 1 || nextProps.callState == 3) ? { topic: nextProps.topic } : null,
|
||||
typingIndicator: false,
|
||||
scrollPosition: 0,
|
||||
fetchingMessages: false,
|
||||
@@ -229,6 +248,7 @@ class MessagesView extends React.Component {
|
||||
docPreview: null,
|
||||
imagePreview: null,
|
||||
imagePostview: null,
|
||||
rtcPanel: null,
|
||||
typingIndicator: false,
|
||||
scrollPosition: 0,
|
||||
fetchingMessages: false,
|
||||
@@ -278,6 +298,12 @@ class MessagesView extends React.Component {
|
||||
latestClearId: topic.maxClearId(),
|
||||
channel: topic.isChannelType()
|
||||
});
|
||||
|
||||
if (nextProps.callTopic == topic.name && (nextProps.callState == 1 || nextProps.callState == 3)) {
|
||||
Object.assign(nextState, {
|
||||
rtcPanel: nextProps.callTopic,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Invalid topic.
|
||||
Object.assign(nextState, {
|
||||
@@ -290,6 +316,13 @@ class MessagesView extends React.Component {
|
||||
channel: false
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// same topic
|
||||
if (!prevState.rtcPanel && nextProps.callTopic == prevState.topic && (nextProps.callState == 1 || nextProps.callState == 3)) {
|
||||
Object.assign(nextState, {
|
||||
rtcPanel: nextProps.callTopic,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (nextProps.acs) {
|
||||
@@ -750,6 +783,28 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleRtcClick() {
|
||||
this.setState({
|
||||
rtcPanel: {
|
||||
/*
|
||||
file: file,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: file.type
|
||||
*/
|
||||
topic: this.state.topic
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
handleRtcClose() {
|
||||
this.props.onVideoCallClosed();
|
||||
this.setState({
|
||||
rtcPanel: null
|
||||
});
|
||||
}
|
||||
|
||||
// sendImageAttachment sends the image bits inband as Drafty message.
|
||||
sendImageAttachment(caption, blob) {
|
||||
const mime = this.state.imagePreview.mime;
|
||||
@@ -934,6 +989,25 @@ class MessagesView extends React.Component {
|
||||
onClose={this.handleClosePreview}
|
||||
onSendMessage={this.sendFileAttachment} />
|
||||
);
|
||||
} else if (this.state.rtcPanel) {
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
component2 = (
|
||||
<RtcPanel
|
||||
topic={topic}
|
||||
seq={this.props.callSeq}
|
||||
callState={this.props.callState}
|
||||
onError={this.props.onError}
|
||||
onClose={this.handleRtcClose}
|
||||
onHangup={this.props.onTeleHangup}
|
||||
|
||||
onInvite={this.props.onTeleInvite}
|
||||
onSendOffer={this.props.onTeleSendOffer}
|
||||
onIceCandidate={this.props.onTeleIceCandidate}
|
||||
onSendAnswer={this.props.onTeleSendAnswer}
|
||||
//content={this.state.imagePostview}
|
||||
//onClose={this.handleClosePreview}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
const isChannel = topic.isChannelType();
|
||||
@@ -1124,7 +1198,7 @@ class MessagesView extends React.Component {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
//<button onClick={this.handleRtcClick} >abc</button>
|
||||
component = <div id="topic-view">{component2}</div>
|
||||
}
|
||||
return component;
|
||||
|
||||
+282
-1
@@ -12,6 +12,7 @@ import ContextMenu from '../widgets/context-menu.jsx';
|
||||
import ForwardDialog from '../widgets/forward-dialog.jsx';
|
||||
|
||||
import InfoView from './info-view.jsx';
|
||||
import CallView from './call-view.jsx';
|
||||
import MessagesView from './messages-view.jsx';
|
||||
import SidepanelView from './sidepanel-view.jsx';
|
||||
|
||||
@@ -63,6 +64,11 @@ const messages = defineMessages({
|
||||
id: 'menu_item_info',
|
||||
defaultMessage: 'Info',
|
||||
description: 'Show extended topic information'
|
||||
},
|
||||
menu_item_video_call: {
|
||||
id: 'menu_item_video_call',
|
||||
defaultMessage: 'Video Call',
|
||||
description: 'Start video call'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -145,6 +151,22 @@ class TinodeWeb extends React.Component {
|
||||
this.handleShowForwardDialog = this.handleShowForwardDialog.bind(this);
|
||||
this.handleHideForwardDialog = this.handleHideForwardDialog.bind(this);
|
||||
|
||||
this.handleStartVideoCall = this.handleStartVideoCall.bind(this);
|
||||
this.handleTeleMessage = this.handleTeleMessage.bind(this);
|
||||
this.handleCallClose = this.handleCallClose.bind(this);
|
||||
|
||||
this.handleTeleInvite = this.handleTeleInvite.bind(this);
|
||||
this.handleTeleRinging = this.handleTeleRinging.bind(this);
|
||||
this.handleTeleHangup = this.handleTeleHangup.bind(this);
|
||||
this.handleTeleSendOffer = this.handleTeleSendOffer.bind(this);
|
||||
this.handleTeleIceCandidate = this.handleTeleIceCandidate.bind(this);
|
||||
this.handleTeleSendAnswer = this.handleTeleSendAnswer.bind(this);
|
||||
|
||||
this.handleTeleAcceptCall = this.handleTeleAcceptCall.bind(this);
|
||||
this.handleTeleUpdateLease = this.handleTeleUpdateLease.bind(this);
|
||||
this.handleTeleLeaseReply = this.handleTeleLeaseReply.bind(this);
|
||||
this.setLeaseTimer = this.setLeaseTimer.bind(this);
|
||||
|
||||
this.sendMessageToTopic = this.sendMessageToTopic.bind(this);
|
||||
}
|
||||
|
||||
@@ -197,6 +219,10 @@ class TinodeWeb extends React.Component {
|
||||
infoPanel: undefined,
|
||||
mobilePanel: 'sidepanel',
|
||||
|
||||
callTopic: undefined,
|
||||
callState: 0,
|
||||
//isCallOriginator: false,
|
||||
|
||||
contextMenuVisible: false,
|
||||
contextMenuBounds: null,
|
||||
contextMenuClickAt: null,
|
||||
@@ -252,6 +278,7 @@ class TinodeWeb extends React.Component {
|
||||
this.tinode.onConnect = this.handleConnected;
|
||||
this.tinode.onDisconnect = this.handleDisconnect;
|
||||
this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration;
|
||||
this.tinode.onTeleMessage = this.handleTeleMessage;
|
||||
}).then(() => {
|
||||
// Initialize desktop alerts.
|
||||
if (this.state.desktopAlertsEnabled) {
|
||||
@@ -825,7 +852,26 @@ class TinodeWeb extends React.Component {
|
||||
this.receivedTimer = undefined;
|
||||
topic.noteRecv(data.seq);
|
||||
}, RECEIVED_DELAY);
|
||||
|
||||
/*
|
||||
if (typeof data.head != 'undefined' && data.head['mime'] == 'application/tinode-video-call' && topic.msgRecvCount(data.seq) == 0) {
|
||||
this.setState({
|
||||
callTopic: data.topic,
|
||||
callState: 2
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
// Incoming call.
|
||||
if (data.from != this.state.myUserId && data.seq > topic.maxMsgSeq()) {
|
||||
this.setState({
|
||||
callTopic: data.topic,
|
||||
callState: 2
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* Fnd topic: find contacts by tokens */
|
||||
@@ -1355,6 +1401,7 @@ class TinodeWeb extends React.Component {
|
||||
this.tinode.onConnect = this.handleConnected;
|
||||
this.tinode.onDisconnect = this.handleDisconnect;
|
||||
this.tinode.onAutoreconnectIteration = this.handleAutoreconnectIteration;
|
||||
this.tinode.onTeleMessage = this.handleTeleMessage;
|
||||
HashNavigation.navigateTo('');
|
||||
}
|
||||
|
||||
@@ -1498,6 +1545,10 @@ class TinodeWeb extends React.Component {
|
||||
title: this.props.intl.formatMessage(messages.menu_item_info),
|
||||
handler: this.handleShowInfoView
|
||||
} : null,
|
||||
subscribed && Tinode.isP2PTopicName(topicName) ? {
|
||||
title: this.props.intl.formatMessage(messages.menu_item_video_call),
|
||||
handler: this.handleStartVideoCall
|
||||
} : null,
|
||||
subscribed ? 'messages_clear' : null,
|
||||
subscribed && deleter ? 'messages_clear_hard' : null,
|
||||
muted ? (blocked ? null : 'topic_unmute') : 'topic_mute',
|
||||
@@ -1628,6 +1679,209 @@ class TinodeWeb extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleStartVideoCall() {
|
||||
this.setState({
|
||||
callTopic: this.state.topicSelected,
|
||||
callState: 1,
|
||||
});
|
||||
}
|
||||
|
||||
setLeaseTimer(seq, leaseExp, now, shift) {
|
||||
if (leaseExp < now) {
|
||||
// Lease has expired.
|
||||
this.handleCallClose();
|
||||
return;
|
||||
}
|
||||
let period = leaseExp - now - shift;
|
||||
if (period < 0) {
|
||||
period = 0;
|
||||
}
|
||||
console.log('X: setting timeout to ', period, ', seq = ', seq, ', leaseExp = ', leaseExp, ', now = ', now, ', shift = ', shift);
|
||||
|
||||
//setTimeout(() => {console.log("before callTimeout")}, period - 500);
|
||||
let callTimeout = setTimeout(this.handleTeleUpdateLease, period);
|
||||
console.log('setting call timeout -> ', callTimeout);
|
||||
let callState = {
|
||||
callLeaseExpires: leaseExp,
|
||||
callTimeout: callTimeout
|
||||
};
|
||||
|
||||
if (seq) {
|
||||
callState.callSeq = seq;
|
||||
}
|
||||
this.setState(callState);
|
||||
}
|
||||
|
||||
handleTeleLeaseReply(ctrl, shift) {
|
||||
if (ctrl.code < 200 || ctrl.code >= 300 || !('params' in ctrl)) {
|
||||
this.handleCallClose();
|
||||
return;
|
||||
}
|
||||
const ds = ctrl.params['lease-expires'];
|
||||
if (!ds) {
|
||||
this.handleCallClose();
|
||||
return;
|
||||
}
|
||||
const leaseExp = new Date(ds);
|
||||
const now = Date.now();
|
||||
this.setLeaseTimer(ctrl.params['seq'], leaseExp.getTime(), now, shift);
|
||||
}
|
||||
|
||||
handleTeleUpdateLease() {
|
||||
console.log('update lease event');
|
||||
const topic = this.tinode.getTopic(this.state.callTopic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
const now = Date.now();
|
||||
if (now >= this.state.callLeaseExpires) {
|
||||
// Lease has expired.
|
||||
this.handleCallClose();
|
||||
return;
|
||||
}
|
||||
/*
|
||||
if (!extend) {
|
||||
this.handleCallClose();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
let until = new Date(this.state.callLeaseExpires); //this.state.callLeaseExpires.getSeconds() + 10;
|
||||
until.setSeconds(until.getSeconds() + 10);
|
||||
topic.call('extend-lease', this.state.callSeq, undefined, until)
|
||||
.then((ctrl) => {
|
||||
this.handleTeleLeaseReply(ctrl, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
handleTeleInvite(callTopic, callSeq, callState) {
|
||||
const topic = this.tinode.getTopic(this.state.topicSelected);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callState == 1) {
|
||||
topic.call('invite').then((ctrl) => {
|
||||
if (ctrl.params && ctrl.params['sip-code'] == 100) {
|
||||
this.handleTeleLeaseReply(ctrl, 0);
|
||||
}
|
||||
});
|
||||
} else if (callState == 3) {
|
||||
topic.call('accept', callSeq).then((ctrl) => {
|
||||
this.handleTeleLeaseReply(ctrl, 2000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleTeleRinging(callTopic, callSeq) {
|
||||
const topic = this.tinode.getTopic(callTopic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('ringing', callSeq);
|
||||
}
|
||||
|
||||
handleTeleHangup(callTopic, callSeq) {
|
||||
const topic = this.tinode.getTopic(callTopic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('hang-up', callSeq);
|
||||
}
|
||||
|
||||
handleTeleSendOffer(callTopic, callSeq, sdp) {
|
||||
const topic = this.tinode.getTopic(callTopic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('offer', callSeq, sdp);
|
||||
}
|
||||
|
||||
handleTeleIceCandidate(callTopic, callSeq, candidate) {
|
||||
const topic = this.tinode.getTopic(callTopic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('ice-candidate', callSeq, candidate);
|
||||
}
|
||||
handleTeleSendAnswer(callTopic, callSeq, sdp) {
|
||||
const topic = this.tinode.getTopic(callTopic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('answer', callSeq, sdp);
|
||||
}
|
||||
|
||||
handleCallClose() {
|
||||
if (this.state.callTimeout) {
|
||||
console.log('closing call timeout ', this.state.callTimeout);
|
||||
clearTimeout(this.state.callTimeout);
|
||||
}
|
||||
this.setState({
|
||||
callTopic: undefined,
|
||||
callState: 0,
|
||||
callLeaseExpires: undefined,
|
||||
callTimeout: undefined
|
||||
});
|
||||
}
|
||||
|
||||
handleTeleAcceptCall(topicName) {
|
||||
this.handleTopicSelected(this.state.callTopic);
|
||||
this.setState({
|
||||
callState: 3
|
||||
});
|
||||
}
|
||||
|
||||
handleTeleMessage(tele) {
|
||||
//
|
||||
switch (tele.what) {
|
||||
case 'invite':
|
||||
console.log('invite: ', tele);
|
||||
if (tele.from != this.state.myUserId) {
|
||||
// incoming call.
|
||||
this.setState({
|
||||
callTopic: tele.src,
|
||||
callState: 2,
|
||||
callSeq: tele.seq,
|
||||
sdp: tele.sdp
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'accept':
|
||||
console.log('TinodeWeb: received accept msg ', tele);
|
||||
// If another my session has accepted the call.
|
||||
if (tele.topic == 'me' && tele.from == this.state.myUserId) {
|
||||
this.setState({
|
||||
callTopic: null,//tele.src,
|
||||
callState: 0,
|
||||
callSeq: null,//tele.seq,
|
||||
//sdp: tele.sdp
|
||||
});
|
||||
}
|
||||
if (tele.topic == this.state.callTopic) {
|
||||
// Update state.
|
||||
this.setState({callState: 3});
|
||||
if (this.state.callTimeout) {
|
||||
clearTimeout(this.state.callTimeout);
|
||||
this.setState({callTimeout: undefined});
|
||||
this.setLeaseTimer(this.state.callSeq, this.state.callLeaseExpires, Date.now(), 2000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'hang-up':
|
||||
//if (tele.topic == 'me') {
|
||||
// remote hangup.
|
||||
this.handleCallClose();
|
||||
break;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="app-container" ref={this.selfRef}>
|
||||
@@ -1765,6 +2019,17 @@ class TinodeWeb extends React.Component {
|
||||
forwardMessage={this.state.forwardMessage}
|
||||
onCancelForwardMessage={this.handleHideForwardDialog}
|
||||
|
||||
callTopic={this.state.callTopic}
|
||||
callSeq={this.state.callSeq}
|
||||
callState={this.state.callState}
|
||||
onTeleHangup={this.handleTeleHangup}
|
||||
|
||||
onTeleInvite={this.handleTeleInvite}
|
||||
onTeleSendOffer={this.handleTeleSendOffer}
|
||||
onTeleIceCandidate={this.handleTeleIceCandidate}
|
||||
onTeleSendAnswer={this.handleTeleSendAnswer}
|
||||
//onTemeMedia
|
||||
|
||||
errorText={this.state.errorText}
|
||||
errorLevel={this.state.errorLevel}
|
||||
errorAction={this.state.errorAction}
|
||||
@@ -1779,7 +2044,8 @@ class TinodeWeb extends React.Component {
|
||||
showContextMenu={this.handleShowContextMenu}
|
||||
onChangePermissions={this.handleChangePermissions}
|
||||
onNewChat={this.handleNewChatInvitation}
|
||||
sendMessage={this.handleSendMessage} />
|
||||
sendMessage={this.handleSendMessage}
|
||||
onVideoCallClosed={this.handleCallClose} />
|
||||
|
||||
{this.state.infoPanel ?
|
||||
<InfoView
|
||||
@@ -1817,6 +2083,21 @@ class TinodeWeb extends React.Component {
|
||||
:
|
||||
null
|
||||
}
|
||||
|
||||
{this.state.callTopic && this.state.callState == 2 ?
|
||||
<CallView
|
||||
tinode={this.tinode}
|
||||
onClose={this.handleCallClose}
|
||||
topic={this.state.callTopic}
|
||||
seq={this.state.callSeq}
|
||||
callState={this.state.callState}
|
||||
onRinging={this.handleTeleRinging}
|
||||
onAcceptCall={this.handleTeleAcceptCall}
|
||||
onReject={this.handleTeleHangup}
|
||||
/>
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user