@jsxc/jsxc
Version:
Real-time XMPP chat application with video calls, file transfer and encrypted communication
184 lines (142 loc) • 5.59 kB
text/typescript
import { IConnection } from './Connection.interface';
import Account from '../Account';
import * as JSM from 'jingle';
import { createRegistry } from 'jxt';
import Log from '../util/Log';
import UUID from '../util/UUID';
import JID from '@src/JID';
import { IJID } from '../JID.interface';
import { VideoDialog } from '../ui/VideoDialog';
import JingleSessionFactory from '../JingleSessionFactory';
import JingleAbstractSession from '../JingleAbstractSession';
import JingleMediaSession from '@src/JingleMediaSession';
import { IOTalkJingleMediaSession } from '@vendor/Jingle.interface';
import IceServers, { ICEServer } from '@src/IceServers';
import Client from '@src/Client';
let jxt = createRegistry();
jxt.use(require('jxt-xmpp-types'));
jxt.use(require('jxt-xmpp'));
let IqStanza = jxt.getDefinition('iq', 'jabber:client');
interface IOfferOptions {
offerToReceiveAudio?: boolean;
offerToReceiveVideo?: boolean;
}
export default class JingleHandler {
protected manager: JSM;
protected static videoDialog: VideoDialog;
protected static instances: JingleHandler[] = [];
constructor(protected account: Account, protected connection: IConnection) {
this.manager = new JSM({
// peerConnectionConstraints: this.getPeerConstraints(),
jid: connection.getJID().full,
selfID: connection.getJID().full,
iceServers: Client.getOption('RTCPeerConfig').iceServers,
});
this.manager.on('change:connectionState', function () {
Log.info('change:connectionState', arguments);
});
this.manager.on('log:*', function (level, msg) {
Log.debug('[JINGLE][' + level + ']', msg);
});
this.manager.on('send', data => {
let iq = new IqStanza(data);
let iqElement = $.parseXML(iq.toString()).getElementsByTagName('iq')[0];
iqElement.querySelectorAll('payload-type[name="telephone-event"]').forEach(el => el.remove());
if (!iqElement.getAttribute('id')) {
iqElement.setAttribute('id', UUID.v4() + ':sendIQ');
}
(<any>this.connection).send(iqElement); //@REVIEW
});
this.manager.on('incoming', session => {
this.onIncoming(session);
});
IceServers.registerUpdateHook(iceServers => {
this.setICEServers(iceServers);
});
JingleHandler.instances.push(this);
}
public async initiate(
peerJID: IJID,
stream: MediaStream,
offerOptions?: IOfferOptions,
sessionId?: string
): Promise<JingleMediaSession> {
let iceServers = await IceServers.get();
this.setICEServers(iceServers);
let session: IOTalkJingleMediaSession = this.manager.createMediaSession(peerJID.full, sessionId, stream);
return new Promise<JingleMediaSession>(resolve => {
session.start(offerOptions, () => {
let jingleSession = JingleSessionFactory.create(this.account, session);
resolve(jingleSession);
});
});
}
public terminate(jid: IJID, reason?: string, silent?: boolean);
public terminate(reason?: string, silent?: boolean);
public terminate() {
if (arguments[0] instanceof JID) {
this.manager.endPeerSessions(arguments[0].full, arguments[1], arguments[2]);
} else {
this.manager.endAllSessions(arguments[0], arguments[1]);
}
}
public addICEServer(server: ICEServer | string) {
this.manager.addICEServer(server);
}
public setICEServers(servers: ICEServer[]) {
this.manager.iceServers = servers;
}
public setPeerConstraints(constraints) {
this.manager.config.peerConnectionConstraints = constraints;
}
public onJingle = (iq: Element) => {
let req;
try {
req = jxt.parse(iq.outerHTML);
} catch (err) {
Log.error('Error while parsing jingle: ', err);
return;
}
this.manager.process(req.toJSON());
return true;
};
protected onIncoming(session: IOTalkJingleMediaSession): JingleAbstractSession {
return JingleSessionFactory.create(this.account, session);
}
// private onIncomingFileTransfer(session: IOTalkJingleMediaSession) {
// Log.debug('incoming file transfer from ' + session.peerID);
// let peerJID = new JID(session.peerID);
// let contact = this.account.getContact(peerJID);
// if (!contact) {
// Log.warn('Reject file transfer, because the contact is not in your contact list');
// return;
// }
// session.accept();
// // let chatWindow = contact.getChatWindow();
// // let message = new Message({
// // peer: contact.getJid(),
// // direction: Message.DIRECTION.IN,
// // attachment: new Attachment({
// // name: session.receiver.metadata.name,
// // type: session.receiver.metadata.type || 'application/octet-stream'
// // })
// // });
// // message.save();
// // chatWindow.receiveIncomingMessage(message);
// //
// // session.receiver.on('progress', function(sent, size) {
// // message.updateProgress(sent, size);
// // });
// }
public static terminateAll(reason?: string) {
JingleHandler.instances.forEach(instance => {
instance.terminate(reason);
});
}
public static getVideoDialog(): VideoDialog {
if (!JingleHandler.videoDialog || !JingleHandler.videoDialog.isReady()) {
JingleHandler.videoDialog = new VideoDialog();
}
return JingleHandler.videoDialog;
}
}