Telegram Web K with changes to work inside I2P https://web.telegram.i2p/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
5.2 KiB

3 years ago
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*
* Originally from:
* https://github.com/evgeny-nadymov/telegram-react
* Copyright (C) 2018 Evgeny Nadymov
* https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE
*/
import { indexOfAndSplice } from '../../helpers/array';
import { safeAssign } from '../../helpers/object';
import { GroupCallParticipantVideoSourceGroup } from '../../layer';
import { SDPBuilder, WebRTCLineType, WEBRTC_MEDIA_PORT } from './sdpBuilder';
import { AudioCodec, GroupCallConnectionTransport, Ssrc, UpdateGroupCallConnectionData, VideoCodec } from './types';
export class ConferenceEntry {
public source: number;
public sourceGroups: GroupCallParticipantVideoSourceGroup[];
public transceiver: RTCRtpTransceiver;
public originalDirection: RTCRtpTransceiverDirection;
public direction: RTCRtpTransceiverDirection;
public port: string;
public endpoint: string;
public peerId: PeerId;
constructor(public mid: string, public type: WebRTCLineType) {
this.port = WEBRTC_MEDIA_PORT;
}
public setDirection(direction: RTCRtpTransceiverDirection) {
if(!this.originalDirection) {
this.originalDirection = direction;
}
return this.direction = direction;
}
public setPort(port: string) {
return this.port = port;
}
public setEndpoint(endpoint: string) {
return this.endpoint = endpoint;
}
public setPeerId(peerId: PeerId) {
return this.peerId = peerId;
}
public createTransceiver(connection: RTCPeerConnection, init?: RTCRtpTransceiverInit) {
if(init?.direction) {
this.setDirection(init.direction);
}
return this.transceiver = connection.addTransceiver(this.type, init);
}
public setSource(source: number | GroupCallParticipantVideoSourceGroup[]) {
let sourceGroups: GroupCallParticipantVideoSourceGroup[];
if(Array.isArray(source)) {
sourceGroups = source;
source = sourceGroups[0].sources[0];
}
this.sourceGroups = sourceGroups;
return this.source = source;
}
public shouldBeSkipped(isAnswer?: boolean) {
return isAnswer && this.direction === 'inactive';
}
}
export function generateSsrc(type: WebRTCLineType, source: number | GroupCallParticipantVideoSourceGroup[], endpoint?: string): Ssrc {
let sourceGroups: GroupCallParticipantVideoSourceGroup[];
if(Array.isArray(source)) {
sourceGroups = source;
source = sourceGroups[0].sources[0];
}
return {
endpoint,
type,
source,
sourceGroups,
};
}
export default class LocalConferenceDescription implements UpdateGroupCallConnectionData {
public readonly sessionId: string;
// public ssrcs: Ssrc[];
public readonly transport: GroupCallConnectionTransport;
public readonly audio?: AudioCodec;
public readonly video: VideoCodec;
private maxSeenId: number;
public readonly entries: ConferenceEntry[];
private entriesByMid: Map<ConferenceEntry['mid'], ConferenceEntry>;
private entriesBySource: Map<ConferenceEntry['source'], ConferenceEntry>;
private entriesByPeerId: Map<ConferenceEntry['peerId'], Set<ConferenceEntry>>;
constructor(public connection: RTCPeerConnection) {
this.sessionId = '' + Date.now();
// this.ssrcs = [];
this.maxSeenId = -1;
this.entries = [];
this.entriesByMid = new Map();
this.entriesBySource = new Map();
this.entriesByPeerId = new Map();
}
public setData(data: UpdateGroupCallConnectionData) {
return safeAssign(this, data);
}
public createEntry(type: WebRTCLineType) {
const mid = '' + ++this.maxSeenId;
const entry = new ConferenceEntry(mid, type);
this.entries.push(entry);
this.entriesByMid.set(mid, entry);
return entry;
}
public deleteEntry(entry: ConferenceEntry) {
indexOfAndSplice(this.entries, entry);
this.entriesByMid.delete(entry.mid);
this.entriesBySource.delete(entry.source);
const set = this.entriesByPeerId.get(entry.peerId);
if(set) {
set.delete(entry);
if(!set.size) {
this.entriesByPeerId.delete(entry.peerId);
}
}
}
public setEntrySource(entry: ConferenceEntry, source: Parameters<ConferenceEntry['setSource']>[0]) {
entry.setSource(source);
this.entriesBySource.set(entry.source, entry);
}
public setEntryPeerId(entry: ConferenceEntry, peerId: ConferenceEntry['peerId']) {
entry.setPeerId(peerId);
let set = this.entriesByPeerId.get(peerId);
if(!set) {
this.entriesByPeerId.set(peerId, set = new Set());
}
set.add(entry);
}
public findEntry(verify: Parameters<LocalConferenceDescription['entries']['find']>[0]) {
return this.entries.find(verify);
}
public getEntryByMid(mid: ConferenceEntry['mid']) {
return this.entriesByMid.get(mid);
}
public getEntryBySource(source: ConferenceEntry['source']) {
return this.entriesBySource.get(source);
}
public getEntriesByPeerId(peerId: ConferenceEntry['peerId']) {
return this.entriesByPeerId.get(peerId);
}
public generateSdp(options: Omit<Parameters<SDPBuilder['addConference']>[0], 'conference'>) {
return SDPBuilder.fromConference({
conference: this,
...options
});
}
}