Calls logic minor cleanup.
This commit is contained in:
@@ -106,3 +106,9 @@ export const LINK_PRIVACY_POLICY = 'https://tinode.co/privacy.html';
|
|||||||
|
|
||||||
// Link to Terms of Service.
|
// Link to Terms of Service.
|
||||||
export const LINK_TERMS_OF_SERVICE = 'https://tinode.co/terms.html';
|
export const LINK_TERMS_OF_SERVICE = 'https://tinode.co/terms.html';
|
||||||
|
|
||||||
|
// Video call states.
|
||||||
|
export const CALL_STATE_NONE = 0;
|
||||||
|
export const CALL_STATE_OUTGOING_INITATED = 1;
|
||||||
|
export const CALL_STATE_INCOMING_RECEIVED = 2;
|
||||||
|
export const CALL_STATE_IN_PROGRESS = 3;
|
||||||
|
|||||||
+14
-10
@@ -19,7 +19,8 @@ import SendMessage from '../widgets/send-message.jsx';
|
|||||||
|
|
||||||
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY,
|
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY,
|
||||||
MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE,
|
MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE,
|
||||||
READ_DELAY, QUOTED_REPLY_LENGTH } from '../config.js';
|
READ_DELAY, QUOTED_REPLY_LENGTH,
|
||||||
|
CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS } from '../config.js';
|
||||||
import { blobToBase64, fileToBase64,
|
import { blobToBase64, fileToBase64,
|
||||||
imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
||||||
import HashNavigation from '../lib/navigation.js';
|
import HashNavigation from '../lib/navigation.js';
|
||||||
@@ -78,6 +79,13 @@ function isPeerRestricted(acs) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldPresentCallPanel(callState) {
|
||||||
|
// Show call panel if either:
|
||||||
|
// - call is outgoing (and the client is waiting for the other side to pick up) or,
|
||||||
|
// - call is already in progress.
|
||||||
|
return callState == CALL_STATE_OUTGOING_INITATED || callState == CALL_STATE_IN_PROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
class MessagesView extends React.Component {
|
class MessagesView extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -196,11 +204,6 @@ class MessagesView extends React.Component {
|
|||||||
|
|
||||||
static getDerivedStateFromProps(nextProps, prevState) {
|
static getDerivedStateFromProps(nextProps, prevState) {
|
||||||
let nextState = {};
|
let nextState = {};
|
||||||
/*
|
|
||||||
if (nextProps.callState == 3 || nextProps.callState == 1) {
|
|
||||||
nextState.rtcPanel = { topic: nextProps.topic };
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if (!nextProps.topic) {
|
if (!nextProps.topic) {
|
||||||
// Default state: no topic.
|
// Default state: no topic.
|
||||||
nextState = {
|
nextState = {
|
||||||
@@ -216,7 +219,7 @@ class MessagesView extends React.Component {
|
|||||||
docPreview: null,
|
docPreview: null,
|
||||||
imagePreview: null,
|
imagePreview: null,
|
||||||
imagePostview: null,
|
imagePostview: null,
|
||||||
rtcPanel: null,//typeof nextProps.topic != 'undefined' && nextPropstopic.name == this.props.callTopic && (nextProps.callState == 1 || nextProps.callState == 3) ? { topic: nextProps.topic } : null,
|
rtcPanel: null,
|
||||||
typingIndicator: false,
|
typingIndicator: false,
|
||||||
scrollPosition: 0,
|
scrollPosition: 0,
|
||||||
fetchingMessages: false,
|
fetchingMessages: false,
|
||||||
@@ -293,7 +296,7 @@ class MessagesView extends React.Component {
|
|||||||
channel: topic.isChannelType()
|
channel: topic.isChannelType()
|
||||||
});
|
});
|
||||||
|
|
||||||
if (nextProps.callTopic == topic.name && (nextProps.callState == 1 || nextProps.callState == 3)) {
|
if (nextProps.callTopic == topic.name && shouldPresentCallPanel(nextProps.callState)) {
|
||||||
Object.assign(nextState, {
|
Object.assign(nextState, {
|
||||||
rtcPanel: nextProps.callTopic,
|
rtcPanel: nextProps.callTopic,
|
||||||
});
|
});
|
||||||
@@ -311,8 +314,9 @@ class MessagesView extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// same topic
|
// We are still in same topic. Show the call panel if necessary.
|
||||||
if (!prevState.rtcPanel && nextProps.callTopic == prevState.topic && (nextProps.callState == 1 || nextProps.callState == 3)) {
|
if (nextProps.callTopic == prevState.topic && !prevState.rtcPanel &&
|
||||||
|
shouldPresentCallPanel(nextProps.callState)) {
|
||||||
Object.assign(nextState, {
|
Object.assign(nextState, {
|
||||||
rtcPanel: nextProps.callTopic,
|
rtcPanel: nextProps.callTopic,
|
||||||
});
|
});
|
||||||
|
|||||||
+59
-117
@@ -17,7 +17,9 @@ import MessagesView from './messages-view.jsx';
|
|||||||
import SidepanelView from './sidepanel-view.jsx';
|
import SidepanelView from './sidepanel-view.jsx';
|
||||||
|
|
||||||
import { API_KEY, APP_NAME, DEFAULT_P2P_ACCESS_MODE, FORWARDED_PREVIEW_LENGTH, LOGGING_ENABLED,
|
import { API_KEY, APP_NAME, DEFAULT_P2P_ACCESS_MODE, FORWARDED_PREVIEW_LENGTH, LOGGING_ENABLED,
|
||||||
MEDIA_BREAKPOINT, RECEIVED_DELAY } from '../config.js';
|
MEDIA_BREAKPOINT, RECEIVED_DELAY,
|
||||||
|
CALL_STATE_NONE, CALL_STATE_OUTGOING_INITATED,
|
||||||
|
CALL_STATE_INCOMING_RECEIVED, CALL_STATE_IN_PROGRESS } from '../config.js';
|
||||||
import { PACKAGE_VERSION } from '../version.js';
|
import { PACKAGE_VERSION } from '../version.js';
|
||||||
import { base64ReEncode, makeImageUrl } from '../lib/blob-helpers.js';
|
import { base64ReEncode, makeImageUrl } from '../lib/blob-helpers.js';
|
||||||
import { detectServerAddress, isLocalHost, isSecureConnection } from '../lib/host-name.js';
|
import { detectServerAddress, isLocalHost, isSecureConnection } from '../lib/host-name.js';
|
||||||
@@ -163,9 +165,6 @@ class TinodeWeb extends React.Component {
|
|||||||
this.handleTeleSendAnswer = this.handleTeleSendAnswer.bind(this);
|
this.handleTeleSendAnswer = this.handleTeleSendAnswer.bind(this);
|
||||||
|
|
||||||
this.handleTeleAcceptCall = this.handleTeleAcceptCall.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);
|
this.sendMessageToTopic = this.sendMessageToTopic.bind(this);
|
||||||
}
|
}
|
||||||
@@ -219,9 +218,12 @@ class TinodeWeb extends React.Component {
|
|||||||
infoPanel: undefined,
|
infoPanel: undefined,
|
||||||
mobilePanel: 'sidepanel',
|
mobilePanel: 'sidepanel',
|
||||||
|
|
||||||
|
// Video calls.
|
||||||
callTopic: undefined,
|
callTopic: undefined,
|
||||||
callState: 0,
|
callState: CALL_STATE_NONE,
|
||||||
//isCallOriginator: false,
|
// If true, call state should be transitioned to CALL_STATE_IN_PROGRESS upon
|
||||||
|
// switching to the call topic.
|
||||||
|
callShouldStart: false,
|
||||||
|
|
||||||
contextMenuVisible: false,
|
contextMenuVisible: false,
|
||||||
contextMenuBounds: null,
|
contextMenuBounds: null,
|
||||||
@@ -486,7 +488,13 @@ class TinodeWeb extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleError(err, level, action, actionText) {
|
handleError(err, level, action, actionText) {
|
||||||
this.setState({errorText: err, errorLevel: level, errorAction: action, errorActionText: actionText});
|
this.setState({
|
||||||
|
errorText: err,
|
||||||
|
errorLevel: level,
|
||||||
|
errorAction: action,
|
||||||
|
errorActionText: actionText,
|
||||||
|
callShouldStart: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// User clicked Login button in the side panel.
|
// User clicked Login button in the side panel.
|
||||||
@@ -852,26 +860,7 @@ class TinodeWeb extends React.Component {
|
|||||||
this.receivedTimer = undefined;
|
this.receivedTimer = undefined;
|
||||||
topic.noteRecv(data.seq);
|
topic.noteRecv(data.seq);
|
||||||
}, RECEIVED_DELAY);
|
}, 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 */
|
/* Fnd topic: find contacts by tokens */
|
||||||
@@ -1293,11 +1282,20 @@ class TinodeWeb extends React.Component {
|
|||||||
|
|
||||||
// New topic was created, here is the new topic name.
|
// New topic was created, here is the new topic name.
|
||||||
handleNewTopicCreated(oldName, newName) {
|
handleNewTopicCreated(oldName, newName) {
|
||||||
|
let nextState = {};
|
||||||
|
if (this.state.callShouldStart) {
|
||||||
|
nextState = {callState: CALL_STATE_IN_PROGRESS, callShouldStart: false};
|
||||||
|
}
|
||||||
if (this.state.topicSelected == oldName && oldName != newName) {
|
if (this.state.topicSelected == oldName && oldName != newName) {
|
||||||
// If the current URl contains the old topic name, replace it with new.
|
// If the current URl contains the old topic name, replace it with new.
|
||||||
// Update the name of the selected topic first so the navigator doen't clear
|
// Update the name of the selected topic first so the navigator doen't clear
|
||||||
// the state.
|
// the state.
|
||||||
this.setState({topicSelected: newName}, () => {
|
const newTopic = {topicSelected: newName};
|
||||||
|
this.setState(...nextState, ...newTopic, () => {
|
||||||
|
HashNavigation.navigateTo(HashNavigation.setUrlTopic('', newName));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState(nextState, () => {
|
||||||
HashNavigation.navigateTo(HashNavigation.setUrlTopic('', newName));
|
HashNavigation.navigateTo(HashNavigation.setUrlTopic('', newName));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1679,91 +1677,35 @@ class TinodeWeb extends React.Component {
|
|||||||
handleStartVideoCall() {
|
handleStartVideoCall() {
|
||||||
this.setState({
|
this.setState({
|
||||||
callTopic: this.state.topicSelected,
|
callTopic: this.state.topicSelected,
|
||||||
callState: 1,
|
callState: CALL_STATE_OUTGOING_INITATED
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
let until = new Date(this.state.callLeaseExpires);
|
|
||||||
until.setSeconds(until.getSeconds() + 10);
|
|
||||||
topic.call('extend-lease', this.state.callSeq, undefined, until)
|
|
||||||
.then((ctrl) => {
|
|
||||||
this.handleTeleLeaseReply(ctrl, 2000);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTeleInvite(callTopic, callSeq, callState) {
|
handleTeleInvite(callTopic, callSeq, callState) {
|
||||||
if (callState == 1) {
|
switch (callState) {
|
||||||
|
case CALL_STATE_OUTGOING_INITATED:
|
||||||
let head = {mime: 'application/tinode-video-call'};
|
let head = {mime: 'application/tinode-video-call'};
|
||||||
this.handleSendMessage('started', undefined, undefined, head)
|
this.handleSendMessage('started', undefined, undefined, head)
|
||||||
.then((ctrl) => {
|
.then((ctrl) => {
|
||||||
if (ctrl.code < 200 || ctrl.code >= 300 || typeof ctrl.params == 'undefined' || typeof ctrl.params['seq'] == 'undefined') {
|
if (ctrl.code < 200 || ctrl.code >= 300 ||
|
||||||
|
typeof ctrl.params == 'undefined' || typeof ctrl.params['seq'] == 'undefined') {
|
||||||
this.handleCallClose();
|
this.handleCallClose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({callSeq: ctrl.params['seq']});
|
this.setState({callSeq: ctrl.params['seq']});
|
||||||
});
|
});
|
||||||
} else if (callState == 3) {
|
break;
|
||||||
|
case CALL_STATE_IN_PROGRESS:
|
||||||
const topic = this.tinode.getTopic(callTopic);
|
const topic = this.tinode.getTopic(callTopic);
|
||||||
if (!topic) {
|
if (!topic) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
topic.call('accept', callSeq).then((ctrl) => {
|
// We've accepted the call. Let the other side know.
|
||||||
this.handleTeleLeaseReply(ctrl, 2000);
|
topic.call('accept', callSeq).catch((err) => {
|
||||||
|
this.handleCallClose();
|
||||||
|
this.handleError(err.message, 'err');
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1818,21 +1760,29 @@ class TinodeWeb extends React.Component {
|
|||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
callTopic: undefined,
|
callTopic: undefined,
|
||||||
callState: 0,
|
callState: CALL_STATE_NONE
|
||||||
callLeaseExpires: undefined,
|
|
||||||
callTimeout: undefined
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTeleAcceptCall(topicName) {
|
handleTeleAcceptCall(topicName) {
|
||||||
|
const topic = this.tinode.getTopic(topicName);
|
||||||
|
if (!topic) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (topic.isSubscribed()) {
|
||||||
this.handleTopicSelected(this.state.callTopic);
|
this.handleTopicSelected(this.state.callTopic);
|
||||||
this.setState({
|
this.setState({
|
||||||
callState: 3
|
callState: CALL_STATE_IN_PROGRESS
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// We need to switch and subscribe to callTopic first.
|
||||||
|
this.setState({
|
||||||
|
callShouldStart: true,
|
||||||
|
}, () => this.handleTopicSelected(this.state.callTopic));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleInfoMessage(info) {
|
handleInfoMessage(info) {
|
||||||
//
|
|
||||||
if (info.what != 'call') {
|
if (info.what != 'call') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1840,12 +1790,11 @@ class TinodeWeb extends React.Component {
|
|||||||
case 'invite':
|
case 'invite':
|
||||||
console.log('invite: ', info);
|
console.log('invite: ', info);
|
||||||
if (info.from != this.state.myUserId) {
|
if (info.from != this.state.myUserId) {
|
||||||
// incoming call.
|
// Incoming call.
|
||||||
this.setState({
|
this.setState({
|
||||||
callTopic: info.src,
|
callTopic: info.src,
|
||||||
callState: 2,
|
callState: CALL_STATE_INCOMING_RECEIVED,
|
||||||
callSeq: info.seq
|
callSeq: info.seq
|
||||||
//sdp: info.sdp
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1854,28 +1803,21 @@ class TinodeWeb extends React.Component {
|
|||||||
// If another my session has accepted the call.
|
// If another my session has accepted the call.
|
||||||
if (info.topic == 'me' && info.from == this.state.myUserId) {
|
if (info.topic == 'me' && info.from == this.state.myUserId) {
|
||||||
this.setState({
|
this.setState({
|
||||||
callTopic: null,//tele.src,
|
callTopic: null,
|
||||||
callState: 0,
|
callState: CALL_STATE_NONE,
|
||||||
callSeq: null//tele.seq,
|
callSeq: null
|
||||||
//sdp: tele.sdp
|
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (info.topic == this.state.callTopic) {
|
if (info.topic == this.state.callTopic) {
|
||||||
// Update state.
|
// Update state.
|
||||||
this.setState({callState: 3});
|
this.setState({callState: CALL_STATE_IN_PROGRESS});
|
||||||
if (this.state.callTimeout) {
|
|
||||||
clearTimeout(this.state.callTimeout);
|
|
||||||
this.setState({callTimeout: undefined});
|
|
||||||
this.setLeaseTimer(this.state.callSeq, this.state.callLeaseExpires, Date.now(), 2000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'hang-up':
|
case 'hang-up':
|
||||||
//if (tele.topic == 'me') {
|
// Remote hangup.
|
||||||
// remote hangup.
|
|
||||||
this.handleCallClose();
|
this.handleCallClose();
|
||||||
break;
|
break;
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2081,7 +2023,7 @@ class TinodeWeb extends React.Component {
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
{this.state.callTopic && this.state.callState == 2 ?
|
{this.state.callTopic && this.state.callState == CALL_STATE_INCOMING_RECEIVED ?
|
||||||
<CallView
|
<CallView
|
||||||
tinode={this.tinode}
|
tinode={this.tinode}
|
||||||
onClose={this.handleCallClose}
|
onClose={this.handleCallClose}
|
||||||
|
|||||||
+36
-15
@@ -2,6 +2,8 @@ import React from 'react';
|
|||||||
|
|
||||||
import LetterTile from '../widgets/letter-tile.jsx';
|
import LetterTile from '../widgets/letter-tile.jsx';
|
||||||
|
|
||||||
|
import { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS } from '../config.js';
|
||||||
|
|
||||||
export default class RtcPanel extends React.PureComponent {
|
export default class RtcPanel extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -12,7 +14,6 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
isStarted: false,
|
isStarted: false,
|
||||||
localStream: undefined,
|
localStream: undefined,
|
||||||
pc: undefined,
|
pc: undefined,
|
||||||
remoteStream: undefined,
|
|
||||||
|
|
||||||
previousOnInfo: undefined
|
previousOnInfo: undefined
|
||||||
};
|
};
|
||||||
@@ -43,7 +44,7 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
this.remoteRef = React.createRef();
|
this.remoteRef = React.createRef();
|
||||||
|
|
||||||
this.onInfo = this.onInfo.bind(this);
|
this.onInfo = this.onInfo.bind(this);
|
||||||
this.launchStream = this.launchStream.bind(this);
|
this.start = this.start.bind(this);
|
||||||
|
|
||||||
this.createPeerConnection = this.createPeerConnection.bind(this);
|
this.createPeerConnection = this.createPeerConnection.bind(this);
|
||||||
|
|
||||||
@@ -77,8 +78,10 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
handleVideoCallAccepted(info) {
|
handleVideoCallAccepted(info) {
|
||||||
const pc = this.createPeerConnection();
|
const pc = this.createPeerConnection();
|
||||||
const stream = this.state.localStream;
|
const stream = this.state.localStream;
|
||||||
stream.getTracks().forEach(track => pc.addTrack(track, stream));
|
stream.getTracks().forEach(track => {
|
||||||
console.log('RtcPanel: info msg', info);
|
console.log('local stream adding track ', track.id, track.kind, track.readyState);
|
||||||
|
pc.addTrack(track, stream);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onInfo(info) {
|
onInfo(info) {
|
||||||
@@ -87,7 +90,6 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (info.event) {
|
switch (info.event) {
|
||||||
//case 'invite'
|
|
||||||
case 'accept':
|
case 'accept':
|
||||||
// Call accepted.
|
// Call accepted.
|
||||||
this.handleVideoCallAccepted(info);
|
this.handleVideoCallAccepted(info);
|
||||||
@@ -107,6 +109,7 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
componentDidUpdate(props) {
|
componentDidUpdate(props) {
|
||||||
const topic = this.props.topic;
|
const topic = this.props.topic;
|
||||||
if (this.onInfo != topic.onInfo) {
|
if (this.onInfo != topic.onInfo) {
|
||||||
@@ -114,28 +117,40 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
topic.onInfo = this.onInfo;
|
topic.onInfo = this.onInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if ((this.props.callState == 1 || this.props.callState == 3) && this.localRef.current) {
|
const topic = this.props.topic;
|
||||||
this.launchStream();
|
this.previousOnInfo = topic.onInfo;
|
||||||
|
topic.onInfo = this.onInfo;
|
||||||
|
if ((this.props.callState == CALL_STATE_OUTGOING_INITATED ||
|
||||||
|
this.props.callState == CALL_STATE_IN_PROGRESS) && this.localRef.current) {
|
||||||
|
this.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.props.topic.onInfo = this.previousOnInfo;
|
this.props.topic.onInfo = this.previousOnInfo;
|
||||||
|
console.log('will unmount. stop');
|
||||||
this.stop();
|
this.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
launchStream() {
|
start() {
|
||||||
if (this.state.localStream) {
|
if (this.state.localStream) {
|
||||||
console.log("You can't start a call because you already have one open!");
|
console.log("You can't start a call because you already have one open!");
|
||||||
} else {
|
} else {
|
||||||
|
if (this.props.callState == CALL_STATE_IN_PROGRESS) {
|
||||||
|
// We apparently just accepted the call.
|
||||||
|
this.props.onInvite(this.props.topic.name, this.props.seq, this.props.callState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// This is an outgoing call waiting for the other side to pick up.
|
||||||
|
// Start local video.
|
||||||
navigator.mediaDevices.getUserMedia(this.localStreamConstraints)
|
navigator.mediaDevices.getUserMedia(this.localStreamConstraints)
|
||||||
.then(stream => {
|
.then(stream => {
|
||||||
console.log('Adding local stream.', this.localRef.current);
|
|
||||||
this.setState({localStream: stream});
|
this.setState({localStream: stream});
|
||||||
this.localRef.current.srcObject = stream;
|
this.localRef.current.srcObject = stream;
|
||||||
// Send call invitation (or accept call).
|
// Send call invitation.
|
||||||
this.props.onInvite(this.props.topic.name, this.props.seq, this.props.callState);
|
this.props.onInvite(this.props.topic.name, this.props.seq, this.props.callState);
|
||||||
})
|
})
|
||||||
.catch(this.handleGetUserMediaError);
|
.catch(this.handleGetUserMediaError);
|
||||||
@@ -178,7 +193,7 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
this.props.onSendOffer(this.props.topic.name, this.props.seq, this.state.pc.localDescription.toJSON());
|
this.props.onSendOffer(this.props.topic.name, this.props.seq, this.state.pc.localDescription.toJSON());
|
||||||
})
|
})
|
||||||
.catch(reportError);
|
.catch(this.reportError);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleICECandidateEvent(event) {
|
handleICECandidateEvent(event) {
|
||||||
@@ -191,7 +206,7 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
var candidate = new RTCIceCandidate(info.payload);
|
var candidate = new RTCIceCandidate(info.payload);
|
||||||
|
|
||||||
this.state.pc.addIceCandidate(candidate)
|
this.state.pc.addIceCandidate(candidate)
|
||||||
.catch(reportError);
|
.catch(this.reportError);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleICEConnectionStateChangeEvent(event) {
|
handleICEConnectionStateChangeEvent(event) {
|
||||||
@@ -243,7 +258,6 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
this.handleCloseClick();
|
this.handleCloseClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
handleVideoOfferMsg(info) {
|
handleVideoOfferMsg(info) {
|
||||||
var localStream = null;
|
var localStream = null;
|
||||||
|
|
||||||
@@ -252,6 +266,7 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
var desc = new RTCSessionDescription(info.payload);
|
var desc = new RTCSessionDescription(info.payload);
|
||||||
|
|
||||||
pc.setRemoteDescription(desc).then(() => {
|
pc.setRemoteDescription(desc).then(() => {
|
||||||
|
console.log('!!! handleVideoOffer/setRemoteDescription -> getUserMesia');
|
||||||
return navigator.mediaDevices.getUserMedia(this.localStreamConstraints);
|
return navigator.mediaDevices.getUserMedia(this.localStreamConstraints);
|
||||||
})
|
})
|
||||||
.then(stream => {
|
.then(stream => {
|
||||||
@@ -259,7 +274,10 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
this.localRef.current.srcObject = stream;
|
this.localRef.current.srcObject = stream;
|
||||||
this.setState({localStream: stream});
|
this.setState({localStream: stream});
|
||||||
|
|
||||||
localStream.getTracks().forEach(track => pc.addTrack(track, localStream));
|
localStream.getTracks().forEach(track => {
|
||||||
|
console.log('local stream A adding track ', track.id, track.kind, track.readyState);
|
||||||
|
pc.addTrack(track, localStream);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return pc.createAnswer();
|
return pc.createAnswer();
|
||||||
@@ -284,11 +302,14 @@ export default class RtcPanel extends React.PureComponent {
|
|||||||
let tracks = stream.getTracks();
|
let tracks = stream.getTracks();
|
||||||
|
|
||||||
if (tracks != null) {
|
if (tracks != null) {
|
||||||
tracks.forEach(function(track) {
|
tracks.forEach((track) => {
|
||||||
track.stop();
|
track.stop();
|
||||||
|
track.enabled = false;
|
||||||
|
console.log('stopped track ', track.id, track.kind, track.readyState);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
el.srcObject = null;
|
el.srcObject = null;
|
||||||
|
el.src = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
|
|||||||
Reference in New Issue
Block a user