Some code review changes.
This commit is contained in:
@@ -107,11 +107,6 @@ export const LINK_PRIVACY_POLICY = 'https://tinode.co/privacy.html';
|
||||
// Link to Terms of Service.
|
||||
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;
|
||||
// Video calls/WebRTC configuration.
|
||||
export const CALL_WEBRTC_CONFIG = {
|
||||
iceServers: [
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// 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;
|
||||
|
||||
// Mime type used for video call messages.
|
||||
export const CALL_MESSAGE_MIME_TYPE = 'application/x-tinode-webrtc';
|
||||
+3
-1
@@ -2,6 +2,8 @@
|
||||
|
||||
import { Tinode } from 'tinode-sdk';
|
||||
|
||||
import { CALL_MESSAGE_MIME_TYPE } from '../constants.js'
|
||||
|
||||
// Make shortcut icon appear with a green dot + show unread count in title.
|
||||
export function updateFavicon(count) {
|
||||
const oldIcon = document.getElementById('shortcut-icon');
|
||||
@@ -208,7 +210,7 @@ export function cancelablePromise(promise) {
|
||||
|
||||
// Returns true if specified mime type represents a Tinode video call.
|
||||
export function isVideoCall(mime) {
|
||||
return mime == 'application/tinode-video-call';
|
||||
return mime == CALL_MESSAGE_MIME_TYPE;
|
||||
}
|
||||
|
||||
// Clips string to the specified length.
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
// IncomingCallView: displays Accept & Reject buttons for incoming calls.
|
||||
import React from 'react';
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
|
||||
import Tinode from 'tinode-sdk';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
||||
import BadgeList from '../widgets/badge-list.jsx';
|
||||
import MenuCancel from '../widgets/menu-cancel.jsx';
|
||||
|
||||
import { CALL_STATE_INCOMING_RECEIVED, MAX_TITLE_LENGTH } from '../config.js';
|
||||
import { MAX_TITLE_LENGTH } from '../config.js';
|
||||
import { CALL_STATE_INCOMING_RECEIVED } from '../constants.js';
|
||||
|
||||
import { makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import { clipStr } from '../lib/utils.js'
|
||||
|
||||
const RING_SOUND = new Audio("audio/phone_ring.mp3");
|
||||
const RING_SOUND = new Audio('audio/phone_ring.mp3');
|
||||
|
||||
class IncomingCallView extends React.Component {
|
||||
export default class IncomingCallView extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -119,12 +118,8 @@ class IncomingCallView extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
let panelTitle = 'Unknown';
|
||||
if (this.props.callState == CALL_STATE_INCOMING_RECEIVED) {
|
||||
panelTitle = <FormattedMessage id="calls_incoming_title"
|
||||
defaultMessage="Incoming Call" description="Incoming call title (Incoming call view)" />;
|
||||
}
|
||||
let panelTitle = <FormattedMessage id="calls_incoming_title"
|
||||
defaultMessage="Incoming Call" description="Incoming call title (Incoming call view)" />;
|
||||
|
||||
return (
|
||||
<div id="info-view">
|
||||
@@ -170,5 +165,3 @@ class IncomingCallView extends React.Component {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default injectIntl(IncomingCallView);
|
||||
|
||||
@@ -21,10 +21,12 @@ import SendMessage from '../widgets/send-message.jsx';
|
||||
|
||||
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY,
|
||||
MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE,
|
||||
READ_DELAY, QUOTED_REPLY_LENGTH, CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS } from '../config.js';
|
||||
READ_DELAY, QUOTED_REPLY_LENGTH } from '../config.js';
|
||||
import { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS } from '../constants.js';
|
||||
import { blobToBase64, fileToBase64, imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import HashNavigation from '../lib/navigation.js';
|
||||
import { bytesToHumanSize, shortDateFormat } from '../lib/strformat.js';
|
||||
import { isVideoCall } from '../lib/utils.js';
|
||||
|
||||
// Run timer with this frequency (ms) for checking notification queue.
|
||||
const NOTIFICATION_EXEC_INTERVAL = 300;
|
||||
@@ -177,7 +179,6 @@ class MessagesView extends React.Component {
|
||||
if (prevState.topic && !Tinode.isNewGroupTopicName(prevState.topic)) {
|
||||
this.leave(prevState.topic);
|
||||
if (prevState.rtcPanel) {
|
||||
console.log('hangup: ', prevState.topic);
|
||||
this.handleCallHangup(prevState.topic, prevProps.callSeq);
|
||||
}
|
||||
}
|
||||
@@ -1146,13 +1147,21 @@ class MessagesView extends React.Component {
|
||||
);
|
||||
prevDate = thisDate;
|
||||
}
|
||||
let duration;
|
||||
if (msg.head && isVideoCall(msg.head.mime)) {
|
||||
topic.messageVersions(msg, (cur, before, unused1, unused2) => {
|
||||
if (cur.content == 'finished' && before.content == 'accepted') {
|
||||
duration = msg.ts - before.ts;
|
||||
}
|
||||
});
|
||||
}
|
||||
messageNodes.push(
|
||||
<ChatMessage
|
||||
tinode={this.props.tinode}
|
||||
content={msg.content}
|
||||
mimeType={msg.head ? msg.head.mime : null}
|
||||
timestamp={msg.ts}
|
||||
duration={msg.origTs ? msg.ts - msg.origTs : null}
|
||||
duration={duration}
|
||||
response={isReply}
|
||||
seq={msg.seq}
|
||||
isGroup={groupTopic}
|
||||
|
||||
+13
-14
@@ -18,9 +18,10 @@ import MessagesView from './messages-view.jsx';
|
||||
import SidepanelView from './sidepanel-view.jsx';
|
||||
|
||||
import { API_KEY, APP_NAME, DEFAULT_P2P_ACCESS_MODE, FORWARDED_PREVIEW_LENGTH, LOGGING_ENABLED,
|
||||
MEDIA_BREAKPOINT, RECEIVED_DELAY,
|
||||
CALL_STATE_NONE, CALL_STATE_OUTGOING_INITATED,
|
||||
CALL_STATE_INCOMING_RECEIVED, CALL_STATE_IN_PROGRESS } from '../config.js';
|
||||
MEDIA_BREAKPOINT, RECEIVED_DELAY } from '../config.js';
|
||||
import { CALL_STATE_NONE, CALL_STATE_OUTGOING_INITATED,
|
||||
CALL_STATE_INCOMING_RECEIVED, CALL_STATE_IN_PROGRESS,
|
||||
CALL_MESSAGE_MIME_TYPE } from '../constants.js';
|
||||
import { PACKAGE_VERSION } from '../version.js';
|
||||
import { base64ReEncode, makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import { detectServerAddress, isLocalHost, isSecureConnection } from '../lib/host-name.js';
|
||||
@@ -1037,7 +1038,7 @@ class TinodeWeb extends React.Component {
|
||||
|
||||
// TODO: check if return is required.
|
||||
return topic.publishDraft(msg, Promise.all(completion))
|
||||
.then(_ => {
|
||||
.then((ctrl) => {
|
||||
if (topic.isArchived()) {
|
||||
topic.archive(false);
|
||||
}
|
||||
@@ -1698,11 +1699,10 @@ class TinodeWeb extends React.Component {
|
||||
handleCallInvite(callTopic, callSeq, callState) {
|
||||
switch (callState) {
|
||||
case CALL_STATE_OUTGOING_INITATED:
|
||||
let head = {mime: 'application/tinode-video-call'};
|
||||
let head = {mime: CALL_MESSAGE_MIME_TYPE };
|
||||
this.handleSendMessage('started', undefined, undefined, head)
|
||||
.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 || !ctrl.params || !ctrl.params.seq) {
|
||||
this.handleCallClose();
|
||||
return;
|
||||
}
|
||||
@@ -1715,7 +1715,7 @@ class TinodeWeb extends React.Component {
|
||||
return;
|
||||
}
|
||||
// We've accepted the call. Let the other side know.
|
||||
topic.call('accept', callSeq).catch((err) => {
|
||||
topic.videoCall('accept', callSeq).catch((err) => {
|
||||
this.handleCallClose();
|
||||
this.handleError(err.message, 'err');
|
||||
});
|
||||
@@ -1729,7 +1729,7 @@ class TinodeWeb extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('ringing', callSeq);
|
||||
topic.videoCall('ringing', callSeq);
|
||||
}
|
||||
|
||||
handleCallHangup(callTopic, callSeq) {
|
||||
@@ -1738,7 +1738,7 @@ class TinodeWeb extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('hang-up', callSeq);
|
||||
topic.videoCall('hang-up', callSeq);
|
||||
}
|
||||
|
||||
handleCallSendOffer(callTopic, callSeq, sdp) {
|
||||
@@ -1747,7 +1747,7 @@ class TinodeWeb extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('offer', callSeq, sdp);
|
||||
topic.videoCall('offer', callSeq, sdp);
|
||||
}
|
||||
|
||||
handleCallIceCandidate(callTopic, callSeq, candidate) {
|
||||
@@ -1756,7 +1756,7 @@ class TinodeWeb extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('ice-candidate', callSeq, candidate);
|
||||
topic.videoCall('ice-candidate', callSeq, candidate);
|
||||
}
|
||||
handleCallSendAnswer(callTopic, callSeq, sdp) {
|
||||
const topic = this.tinode.getTopic(callTopic);
|
||||
@@ -1764,7 +1764,7 @@ class TinodeWeb extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.call('answer', callSeq, sdp);
|
||||
topic.videoCall('answer', callSeq, sdp);
|
||||
}
|
||||
|
||||
handleCallClose() {
|
||||
@@ -1802,7 +1802,6 @@ class TinodeWeb extends React.Component {
|
||||
}
|
||||
switch (info.event) {
|
||||
case 'invite':
|
||||
console.log('invite: ', info);
|
||||
if (info.from != this.state.myUserId) {
|
||||
// Incoming call.
|
||||
this.setState({
|
||||
|
||||
+11
-26
@@ -4,8 +4,8 @@ import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import LetterTile from '../widgets/letter-tile.jsx';
|
||||
|
||||
import { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS, CALL_WEBRTC_CONFIG,
|
||||
MAX_TITLE_LENGTH } from '../config.js';
|
||||
import { CALL_WEBRTC_CONFIG, MAX_TITLE_LENGTH } from '../config.js';
|
||||
import { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS } from '../constants.js';
|
||||
|
||||
import { clipStr } from '../lib/utils.js'
|
||||
|
||||
@@ -64,19 +64,16 @@ export default class CallPanel extends React.PureComponent {
|
||||
const pc = this.createPeerConnection();
|
||||
const stream = this.state.localStream;
|
||||
stream.getTracks().forEach(track => {
|
||||
console.log('local stream adding track ', track.id, track.kind, track.readyState);
|
||||
pc.addTrack(track, stream);
|
||||
});
|
||||
}
|
||||
|
||||
onInfo(info) {
|
||||
console.log('info --> ', info);
|
||||
if (info.what != 'call') {
|
||||
return;
|
||||
}
|
||||
switch (info.event) {
|
||||
case 'accept':
|
||||
// Call accepted.
|
||||
this.handleVideoCallAccepted(info);
|
||||
break;
|
||||
case 'offer':
|
||||
@@ -106,7 +103,6 @@ export default class CallPanel extends React.PureComponent {
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.topic.onInfo = this.previousOnInfo;
|
||||
console.log('will unmount. stop');
|
||||
this.stop();
|
||||
}
|
||||
|
||||
@@ -143,16 +139,12 @@ export default class CallPanel extends React.PureComponent {
|
||||
pc.ontrack = this.handleTrackEvent;
|
||||
|
||||
this.setState({pc: pc});
|
||||
console.log('Created RTCPeerConnnection');
|
||||
return pc;
|
||||
}
|
||||
|
||||
handleVideoAnswerMsg(info) {
|
||||
console.log("*** Call recipient has accepted our call");
|
||||
|
||||
// Configure the remote description, which is the SDP payload
|
||||
// in our "video-answer" message.
|
||||
|
||||
// in 'info' message.
|
||||
var desc = new RTCSessionDescription(info.payload);
|
||||
this.state.pc.setRemoteDescription(desc).catch(this.reportError);
|
||||
}
|
||||
@@ -186,18 +178,16 @@ export default class CallPanel extends React.PureComponent {
|
||||
|
||||
handleICEConnectionStateChangeEvent(event) {
|
||||
switch (this.state.pc.iceConnectionState) {
|
||||
case "closed":
|
||||
case "failed":
|
||||
case 'closed':
|
||||
case 'failed':
|
||||
this.handleCloseClick();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleSignalingStateChangeEvent(event) {
|
||||
switch (this.state.pc.signalingState) {
|
||||
case "closed":
|
||||
this.handleCloseClick();
|
||||
break;
|
||||
if (this.state.pc.signalingState == 'closed') {
|
||||
this.handleCloseClick();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,18 +202,17 @@ export default class CallPanel extends React.PureComponent {
|
||||
}
|
||||
|
||||
handleGetUserMediaError(e) {
|
||||
console.log('-->', e);
|
||||
switch(e.name) {
|
||||
case "NotFoundError":
|
||||
case 'NotFoundError':
|
||||
console.log("Unable to open your call because no camera and/or microphone" +
|
||||
"were found.");
|
||||
break;
|
||||
case "SecurityError":
|
||||
case "PermissionDeniedError":
|
||||
case 'SecurityError':
|
||||
case 'PermissionDeniedError':
|
||||
// Do nothing; this is the same as the user canceling the call.
|
||||
break;
|
||||
default:
|
||||
console.log("Error opening your camera and/or microphone: " + e.message);
|
||||
console.log('Error opening your camera and/or microphone: ' + e.message);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -240,7 +229,6 @@ export default class CallPanel extends React.PureComponent {
|
||||
var desc = new RTCSessionDescription(info.payload);
|
||||
|
||||
pc.setRemoteDescription(desc).then(() => {
|
||||
console.log('!!! handleVideoOffer/setRemoteDescription -> getUserMesia');
|
||||
return navigator.mediaDevices.getUserMedia(this.localStreamConstraints);
|
||||
})
|
||||
.then(stream => {
|
||||
@@ -249,7 +237,6 @@ export default class CallPanel extends React.PureComponent {
|
||||
this.setState({localStream: stream});
|
||||
|
||||
localStream.getTracks().forEach(track => {
|
||||
console.log('local stream A adding track ', track.id, track.kind, track.readyState);
|
||||
pc.addTrack(track, localStream);
|
||||
});
|
||||
})
|
||||
@@ -279,7 +266,6 @@ export default class CallPanel extends React.PureComponent {
|
||||
tracks.forEach((track) => {
|
||||
track.stop();
|
||||
track.enabled = false;
|
||||
console.log('stopped track ', track.id, track.kind, track.readyState);
|
||||
});
|
||||
}
|
||||
el.srcObject = null;
|
||||
@@ -316,7 +302,6 @@ export default class CallPanel extends React.PureComponent {
|
||||
if (track.kind != kind) {
|
||||
return;
|
||||
}
|
||||
console.log('local stream: toggling track ', track.id, track.kind, track.readyState);
|
||||
track.enabled = !track.enabled;
|
||||
});
|
||||
// Make sure we redraw the UI properly.
|
||||
|
||||
@@ -149,7 +149,7 @@ class BaseChatMessage extends React.PureComponent {
|
||||
</i></>
|
||||
} else if (isVideoCall(this.props.mimeType)) {
|
||||
// Video calls.
|
||||
const direction = this.props.response ? "call_received" : "call_made";
|
||||
const direction = this.props.response ? 'call_received' : 'call_made';
|
||||
const text = this.props.response ?
|
||||
<FormattedMessage id="calls_incoming"
|
||||
defaultMessage="Incoming Call" description="Incoming call label" /> :
|
||||
@@ -157,7 +157,7 @@ class BaseChatMessage extends React.PureComponent {
|
||||
defaultMessage="Outgoing Call" description="Outgoing call label" />;
|
||||
const isCallDropped = this.props.content == "disconnected";
|
||||
content = <><i className="material-icons" style={{color: isCallDropped ? "red" : "green"}}>{direction}</i>{text}
|
||||
{ !isCallDropped ?
|
||||
{ !isCallDropped && this.props.duration ?
|
||||
[' (', <FormattedDuration seconds={this.props.duration / 1000} format="{hours} {minutes} {seconds}" />, ')'] :
|
||||
null}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user