@skyway-sdk/sfu-bot
Version:
The official Next Generation JavaScript SDK for SkyWay
216 lines • 9.47 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SFUConnection = void 0;
const common_1 = require("@skyway-sdk/common");
const core_1 = require("@skyway-sdk/core");
const errors_1 = require("../errors");
const util_1 = require("../util");
const receiver_1 = require("./receiver");
const sender_1 = require("./sender");
const log = new common_1.Logger('packages/sfu-bot/src/connection/index.ts');
/**@internal */
class SFUConnection {
/**@internal */
constructor(_api, channel, localPerson, remoteMember, _transportRepository, _context) {
this._api = _api;
this.channel = channel;
this.localPerson = localPerson;
this.remoteMember = remoteMember;
this._transportRepository = _transportRepository;
this._context = _context;
this.type = 'sfu';
this.onDisconnect = new common_1.Event();
this.onClose = new common_1.Event();
this.closed = false;
/**@private */
this._receivers = {};
/**@private */
this._senders = {};
}
/**@internal */
addSender(publication) {
const sender = new sender_1.Sender(publication, this.channel, this._api, this._transportRepository, this.localPerson, this.remoteMember, this.localPerson.iceManager, this._context);
this._senders[publication.id] = sender;
return sender;
}
/**@internal */
removeSender(originPublicationId) {
log.debug('removeSender', originPublicationId);
const sender = this._senders[originPublicationId];
if (!sender) {
return;
}
sender.unproduce();
}
startSubscribing(subscription) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const receiver = new receiver_1.Receiver(subscription, this._api, this._transportRepository, this.localPerson, this.remoteMember, this.localPerson.iceManager, this._context);
this._receivers[subscription.id] = receiver;
const ts = log.debug('[start] _startSubscribing consume');
const { stream, codec } = yield receiver.consume().catch((e) => {
log.error('[failed] _startSubscribing consume', (0, core_1.createError)({
operationName: 'SFUConnection.startSubscribing',
context: this._context,
channel: this.channel,
info: Object.assign(Object.assign({}, errors_1.errors.internal), { detail: 'failed to receiver.consume' }),
error: e,
path: log.prefix,
payload: { subscription: subscription.toJSON() },
}));
throw e;
});
log.elapsed(ts, '[end] _startSubscribing consume');
stream.setIsEnabled(subscription.publication.state === 'enabled');
subscription.codec = codec;
subscription._setStream(stream);
if (this.localPerson._analytics &&
!this.localPerson._analytics.isClosed()) {
const preferredEncoding = subscription.preferredEncoding;
const encodings = (_a = subscription.publication.origin) === null || _a === void 0 ? void 0 : _a.encodings;
if (!preferredEncoding || !encodings || encodings.length === 0) {
return;
}
const layer = (0, util_1.getLayerFromEncodings)(preferredEncoding, encodings);
// 再送時に他の処理をブロックしないためにawaitしない
void this.localPerson._analytics.client.sendSubscriptionUpdatePreferredEncodingReport({
subscriptionId: subscription.id,
preferredEncodingIndex: layer,
updatedAt: Date.now(),
});
}
});
}
/**@internal */
stopSubscribing(subscription) {
return __awaiter(this, void 0, void 0, function* () {
const connection = this._receivers[subscription.id];
if (!connection) {
return;
}
connection.unconsume();
});
}
/**@internal */
stopPublishing(publication) {
return __awaiter(this, void 0, void 0, function* () {
this.removeSender(publication.id);
});
}
/**@internal */
close({ reason } = {}) {
if (this.closed) {
return;
}
log.debug('close sfu connection', {
remote: this.remoteMember,
local: this.localPerson,
reason,
});
this.closed = true;
Object.values(this._senders).forEach((sender) => {
sender.close();
});
Object.values(this._receivers).forEach((receiver) => {
receiver.close();
});
this._senders = {};
this._receivers = {};
this.onClose.emit();
}
_getReceiver(subscriptionId) {
return this._receivers[subscriptionId];
}
changePreferredEncoding(subscription) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const preferredEncoding = subscription.preferredEncoding;
const encodings = (_a = subscription.publication.origin) === null || _a === void 0 ? void 0 : _a.encodings;
log.debug('changePreferredEncoding', {
preferredEncoding,
encodings,
subscription,
});
if (!preferredEncoding) {
throw (0, core_1.createError)({
operationName: 'SFUConnection.changePreferredEncoding',
context: this._context,
channel: this.channel,
info: errors_1.errors.invalidPreferredEncoding,
path: log.prefix,
payload: { subscription },
});
}
if (!encodings || encodings.length === 0) {
throw (0, core_1.createError)({
operationName: 'SFUConnection.changePreferredEncoding',
context: this._context,
channel: this.channel,
info: errors_1.errors.invalidEncodings,
path: log.prefix,
payload: { subscription },
});
}
const layer = (0, util_1.getLayerFromEncodings)(preferredEncoding, encodings);
const receiver = this._getReceiver(subscription.id);
if (!receiver) {
throw (0, core_1.createError)({
operationName: 'SFUConnection.changePreferredEncoding',
context: this._context,
channel: this.channel,
info: errors_1.errors.receiverNotFound,
path: log.prefix,
payload: { subscription },
});
}
const transport = receiver.transport;
if (!transport) {
throw (0, core_1.createError)({
operationName: 'SFUConnection.changePreferredEncoding',
context: this._context,
channel: this.channel,
info: Object.assign(Object.assign({}, errors_1.errors.internal), { detail: 'transport not found' }),
path: log.prefix,
payload: { subscription },
});
}
const consumer = receiver.consumer;
if (!consumer) {
throw (0, core_1.createError)({
operationName: 'SFUConnection.changePreferredEncoding',
context: this._context,
channel: this.channel,
info: errors_1.errors.consumerNotFound,
path: log.prefix,
payload: { subscription },
});
}
yield this._api.changeConsumerLayer({
transportId: transport.id,
consumerId: consumer.id,
publicationId: subscription.publication.id,
spatialLayer: layer,
});
if (this.localPerson._analytics &&
!this.localPerson._analytics.isClosed()) {
// 再送時に他の処理をブロックしないためにawaitしない
void this.localPerson._analytics.client.sendSubscriptionUpdatePreferredEncodingReport({
subscriptionId: subscription.id,
preferredEncodingIndex: layer,
updatedAt: Date.now(),
});
}
});
}
}
exports.SFUConnection = SFUConnection;
//# sourceMappingURL=index.js.map