src/datapipe/DataChannelDataPipe.js
import {DataPipe} from './DataPipe';
import {DataPipeStatus} from './DataPipeStatus';
import {DataPipeType} from './DataPipeType';
import {bindMethods} from '../utils';
export class DataChannelDataPipe extends DataPipe {
constructor(id, type, stack, participants, label) {
super(id, type, stack, participants, label);
if (participants.length !== 2) {
throw new TypeError('participants parameter must have 2 elements');
}
bindMethods(this, ['onStatus', 'onQsCalling', 'onQsEstablished', 'onQsEndCall', 'onQsData']);
this.rcv = 0;
this.handleCalling = this.type === DataPipeType.OUTGOING;
this.makeBindings();
}
_connectOutgoing() {
this.status = DataPipeStatus.CONNECTING;
this.stack.call(this.participants[1], {data: true});
return this.when(DataPipeStatus.CONNECTED);
}
_connectIncoming() {
this.status = DataPipeStatus.CONNECTING;
this.stack.answer(this.internalId, {data: true});
return this.when(DataPipeStatus.CONNECTED);
}
/**
* @Override
*/
connect() {
if (this.status !== DataPipeStatus.UNCONNECTED) {
return Promise.reject(new Error('invalid-state'));
} else if (this.type == DataPipeType.OUTGOING) {
return this._connectOutgoing();
} else {
return this._connectIncoming();
}
}
_reject() {
this.stack.hangup(this.internalId);
return this.when(DataPipeStatus.DISCONNECTED);
}
/**
* @Override
*/
disconnect() {
if (this.status !== DataPipeStatus.CONNECTING && this.status !== DataPipeStatus.CONNECTED) {
return Promise.reject(new Error('invalid-state'));
}
return this._reject();
}
/**
* @Override
*/
reject() {
if (this.status !== DataPipeStatus.UNCONNECTED) {
return Promise.reject(new Error('invalid-state'));
} else if (this.type != DataPipeType.INCOMING) {
return Promise.reject(new Error('invalid-state'));
}
return this._reject();
}
/**
* @Override
*/
send(data) {
if (this.status !== DataPipeStatus.CONNECTED) {
return Promise.reject(new Error('invalid-state'));
}
this.stack.sendDataChannel(this.internalId, data);
return Promise.resolve(this);
}
/**
* @private
* @return {DataChannelDataPipe}
*/
makeBindings() {
this.on('status', this.onStatus);
if (this.type === DataPipeType.OUTGOING) {
this.stack.on('qs-calling', this.onQsCalling);
}
this.stack.on('qs-established', this.onQsEstablished);
this.stack.on('qs-end-call qs-lost-call', this.onQsEndCall);
this.stack.on('qs-data', this.onQsData);
return this;
}
/**
* @private
* @return {DataChannelDataPipe}
*/
destroyBindings() {
this.off('status', this.onStatus);
if (this.type === DataPipeType.OUTGOING) {
this.stack.off('qs-calling', this.onQsCalling);
}
this.stack.off('qs-established', this.onQsEstablished);
this.stack.off('qs-end-call qs-lost-call', this.onQsEndCall);
this.stack.off('qs-data', this.onQsData);
return this;
}
/**
* Destroy bindings when disconnected state reached.
* @private
*/
onStatus() {
if (this.status === DataPipeStatus.DISCONNECTED) {
this.destroyBindings();
}
}
/**
* @private
*/
onQsCalling(event) {
if (this.handleCalling) {
this.internalId = event.callid;
this.handleCalling = false;
}
}
/**
* @private
*/
onQsEstablished(event) {
if (event.callid !== this.internalId) {
return;
}
if (this.type === DataPipeType.OUTGOING) {
this.stack.sendDataChannel(this.internalId, JSON.stringify({label: this.label}));
}
}
/**
* @private
*/
onQsEndCall(event) {
if (event.callid !== this.internalId) {
return;
}
this.status = DataPipeStatus.DISCONNECTED;
}
/**
* @private
*/
onQsData(event) {
if (event.id !== this.internalId) {
return;
}
if (this.rcv === 0) {
if (this.type == DataPipeType.INCOMING) {
var data = JSON.parse(event.data);
this.label = data.label;
/* Send back same message as ACK */
this.stack.sendDataChannel(this.internalId, event.data);
}
this.status = DataPipeStatus.CONNECTED;
} else {
this.emit('data', event.data);
}
this.rcv++;
}
}