@wireapp/avs 0.0.3170 → 0.0.4297

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/avs_pc.js CHANGED
@@ -1,12 +1,99 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  var ENV_FIREFOX = 1;
4
+ var TIMEOUT_GATHER = 2000;
4
5
  var em_module;
5
6
  var logFn = null;
6
7
  var userMediaHandler = null;
7
- var mediaStreamHandler = null;
8
+ var audioStreamHandler = null;
9
+ var videoStreamHandler = null;
10
+ var insertableLegacy = false;
11
+ var insertableStreams = false;
8
12
  var pc_env = 0;
9
13
  var pc_envver = 0;
14
+ var worker;
15
+ // Use inlined worker instead....
16
+ //let worker = new Worker('/worker/avs-worker.js', {name: 'AVS worker'});
17
+ // This is the content of the avs-worker.js file, copied here.
18
+ var workerContent = "\n\nvar coders = {};\n\nconst HDR_VERSION = 0;\n\n/*\nHeader\n\n 1 1 1 1 1 1\n 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n| V=0 |E| RES |S|LEN |1|KLEN |\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n| KID... (length=KLEN) |\n+-------------------------------+\n| CTR... (length=LEN) |\n+-------------------------------+\n\nExtensions\n\n 0 1 2 3 4 5 6 7\n+-+-+-+-+-+-+-+-+---------------------------+\n|M| ELN | EID | VAL... (length=ELEN) |\n+-+-+-+-+-+-+-+-+---------------------------+\n*/\n\nfunction calcLen(val) {\n let l = 0;\n\n if (val == 0)\n\treturn 1;\n\n while (val != 0) {\n\tl++;\n\tval = val >>> 8;\t\n }\n\n return l;\n}\n\nfunction writeBytes(buf, p, len, val)\n{\n switch (len) {\n case 8:\n\tbuf[p] = (val >>> 56) & 0xff;\n\tp++;\n\n case 7:\n\tbuf[p] = (val >>> 48) & 0xff;\n\tp++;\n\n case 6:\n\tbuf[p] = (val >>> 40) & 0xff;\n\tp++;\n\t\n case 5:\n\tbuf[p] = (val >>> 32) & 0xff;\n\tp++;\n\n case 4:\n\tbuf[p] = (val >>> 24) & 0xff;\n\tp++;\n\n case 3:\n\tbuf[p] = (val >>> 16) & 0xff;\n\tp++;\n\n case 2:\n\tbuf[p] = (val >>> 8) & 0xff;\n\tp++;\n\n case 1:\n\tbuf[p] = val & 0xff;\n\tbreak;\n\n default:\n\treturn 0;\n }\n \n return len;\n}\n\nfunction readBytes(buf, p, len) {\n let l = len;\n let v = 0;\n\n while (l > 0) {\n\tv = v * 256;\n\tv = v + buf[p];\n\tp++;\n\tl--;\n }\n\n const lv = {\n\tlen: len,\n\tval: v\n };\n \n return lv;\n}\n\nfunction frameHeaderDecode(buf) {\n\n const MAX_EXTS = 16;\n let ext = buf[0] & 0x10;\n const flen = ((buf[1] >>> 4) & 0x7) + 1;\n const x = (buf[1] >>> 3) & 0x1;\n const klen = buf[1] & 0x7;\n let p = 2;\n let kid = -1;\n let fid = -1;\n let csrc = \"0\";\n let i = 0;\n\n if (x) {\n\tconst lv = readBytes(buf, p, klen + 1);\n\n\tp += lv.len;\n\tkid = lv.val;\n }\n else {\n\tkid = klen;\n }\n\n const lv = readBytes(buf, p, flen);\n p += lv.len;\n fid = lv.val;\n\n while(ext && p < buf.length && i < MAX_EXTS) {\n\tconst b = buf[p];\n\text = b & 0x80;\n\tconst elen = ((b >>> 4) & 0x7) + 1;\n\tconst eid = (b & 0xf);\n\n if (eid == 1 && elen == 4) {\n const csrco = readBytes(buf, p + 1, elen);\n csrc = csrco.val.toString();\n }\n p += elen + 1;\n i++;\n }\n\n if (kid < 0 || fid < 0) {\n\treturn null;\n }\n else {\n\tconst frameHdr = {\n\t len: p,\n\t frameId: fid,\n\t keyId: kid,\n\t csrc: csrc\n\t}\n\treturn frameHdr;\n }\n}\n\nfunction frameHeaderEncode(fid, kid, csrc)\n{\n const ab = new ArrayBuffer(32);\n const buf = new Uint8Array(ab);\n let sig = 0;\n let x = 0;\n let klen = 0;\n let flen = 0;\n let p = 2;\n let ext = (csrc > 0) ? 1 : 0;\n\n if (kid > 7) {\n\tx = 1;\n\tklen = calcLen(kid) - 1;\n }\n else {\n\tklen = kid;\n }\n\n flen = calcLen(fid);\n\n buf[0] = (HDR_VERSION << 5) + (ext << 4);\n buf[1] = (sig << 7) + ((flen - 1) << 4) + (x << 3) + klen;\n if (x) {\n\tp += writeBytes(buf, p, klen + 1, kid);\n }\n p += writeBytes(buf, p, flen, fid);\n\n if (csrc > 0) {\n buf[p] = 0x31;\n p++;\n p+= writeBytes(buf, p, 4, csrc);\n }\n return buf.subarray(0, p);\n}\n\nfunction xor_iv(iv, fid, kid) {\n const oiv = new Uint8Array(iv);\n\n oiv[0] = oiv[0] ^ ((fid >> 24) & 0xFF);\n oiv[1] = oiv[1] ^ ((fid >> 16) & 0xFF);\n oiv[2] = oiv[2] ^ ((fid >> 8) & 0xFF);\n oiv[3] = oiv[3] ^ ((fid ) & 0xFF);\n oiv[4] = oiv[4] ^ ((kid >> 24) & 0xFF);\n oiv[5] = oiv[5] ^ ((kid >> 16) & 0xFF);\n oiv[6] = oiv[6] ^ ((kid >> 8) & 0xFF);\n oiv[7] = oiv[7] ^ ((kid ) & 0xFF);\n\n return oiv;\n}\n\nfunction getMediaKey(self, index) {\n postMessage({\n\top: \"getMediaKey\",\n\tself: self,\n\tindex: index\n });\n}\n\nfunction getCurrentMediaKey(self, index) {\n postMessage({\n\top: \"getCurrentMediaKey\",\n\tself: self\n });\n}\n\nfunction doLog(str) {\n postMessage({\n\top: \"log\",\n\tlevel: 1,\n\tlogString: str\n });\n}\n\nfunction encryptFrame(coder, rtcFrame, controller) {\n const dataBuf = rtcFrame.data;\n const data = new Uint8Array(dataBuf);\n const t = Object.prototype.toString.call(rtcFrame);\n const isVideo = t === '[object RTCEncodedVideoFrame]';\n const userid = \"self\";\n\n const meta = rtcFrame.getMetadata();\n let ssrc = meta.synchronizationSource;\n\n if (isVideo)\n ssrc = coder.video.ssrc;\n\n if (isVideo && !coder.video.first_recv) {\n doLog(\"frame_enc: encrypt: first frame received type: video uid: \" +\n userid.substring(0,8) + \" fid: \" + coder.frameId + \" ssrc: \" + ssrc);\n coder.video.first_recv = true;\n coder.video.first_succ = false;\n }\n if (!isVideo && !coder.audio.first_recv) {\n doLog(\"frame_enc: encrypt: first frame received type: audio uid: \" +\n userid.substring(0,8) + \" fid: \" + coder.frameId + \" ssrc: \" + ssrc);\n coder.audio.first_recv = true;\n coder.audio.first_succ = false;\n }\n\n if (coder.currentKey == null) {\n getCurrentMediaKey(coder.self);\n return;\n }\n\n const baseiv = isVideo ? coder.video.iv : coder.audio.iv;\n const iv = xor_iv(baseiv, coder.frameId, coder.currentKey.id);\n\n const hdr = frameHeaderEncode(coder.frameId, coder.currentKey.id, ssrc);\n crypto.subtle.encrypt(\n {\n name: \"AES-GCM\",\n iv: iv,\n tagLength: 128,\n additionalData: hdr\n },\n coder.currentKey.key,\n data\n )\n .then(function(encdata){\n const enc8 = new Uint8Array(encdata); \t \n const enc = new Uint8Array(hdr.length + enc8.length);\n \n enc.set(hdr);\n enc.set(enc8, hdr.length);\n\n rtcFrame.data = enc.buffer;\n controller.enqueue(rtcFrame);\n\n if (isVideo && !coder.video.first_succ) {\n doLog(\"frame_enc: encrypt: first frame encrypted type: video uid: \" +\n userid.substring(0,8) + \" fid: \" + coder.frameId + \" csrc: \" + ssrc);\n coder.video.first_succ = true;\n }\n if (!isVideo && !coder.audio.first_succ) {\n doLog(\"frame_enc: encrypt: first frame encrypted type: audio uid: \" +\n userid.substring(0,8) + \" fid: \" + coder.frameId + \" csrc: \" + ssrc);\n coder.audio.first_succ = true;\n }\n\n coder.frameId++;\n });\n}\n\nfunction decryptFrame(track_id, coder, rtcFrame, controller) {\n const dataBuf = rtcFrame.data;\n const data = new Uint8Array(dataBuf);\n\n const t = Object.prototype.toString.call(rtcFrame);\n const isVideo = t === '[object RTCEncodedVideoFrame]'\n\n const frameHdr = frameHeaderDecode(data);\n\n if (frameHdr == null) {\n doLog('decryptFrame: failed to decode frame header');\n return;\n }\n\n const meta = rtcFrame.getMetadata();\n let ssrc = meta.synchronizationSource.toString();\n let csrc = null;\n if (frameHdr.csrc != \"0\") {\n csrc = frameHdr.csrc;\n }\n else if (meta.contributingSources && meta.contributingSources.length > 0) {\n csrc = meta.contributingSources[0].toString();\n }\n else {\n csrc = ssrc;\n }\n\n if (!csrc) {\n doLog('decryptFrame: no csrc for ssrc ' + ssrc);\n return;\n }\n\n let uinfo = null;\n if (isVideo) {\n uinfo = coder.video.users[csrc];\n }\n else {\n uinfo = coder.audio.users[csrc];\n }\n\n if (!uinfo) {\n doLog('decryptFrame: no userinfo for csrc: ' + csrc);\n return;\n }\n \n //console.log('frame_dec: video ' + isVideo + ' ssrc ' + ssrc + ' csrc ' + csrc + ' user ' + uinfo.userid.substring(0,8));\n\n if (isVideo && uinfo.transp_ssrcv != ssrc) {\n doLog(\"frame_dec: decrypt: first frame received type: video uid: \" +\n uinfo.userid.substring(0,8) + \" fid: \" + frameHdr.frameId + \" csrc: \" + csrc + \" ssrc: \" + ssrc + \" uinfo.ssrcv: \" + uinfo.ssrcv);\n uinfo.first_succ_video = false;\n\n /* Only call videoStreamHandler for selective video */\n if (uinfo.ssrcv != ssrc) {\n for (const [key, u] of Object.entries(coder.video.users)) {\n if (u.transp_ssrcv == ssrc) {\n postMessage({\n op: \"setvstream\",\n self: coder.self,\n userid: u.userid,\n clientid: u.clientid,\n ssrc: \"0\",\n track_id: \"0\",\n });\n u.transp_ssrcv = null;\n }\n }\n\n postMessage({\n op: \"setvstream\",\n self: coder.self,\n userid: uinfo.userid,\n clientid: uinfo.clientid,\n ssrc: ssrc,\n track_id: track_id,\n });\n }\n uinfo.transp_ssrcv = ssrc;\n }\n\n if (!isVideo && !uinfo.first_recv_audio) {\n doLog(\"frame_dec: decrypt: first frame received type: audio uid: \" +\n uinfo.userid.substring(0,8) + \" fid: \" + frameHdr.frameId + \" csrc: \" + csrc);\n uinfo.first_recv_audio = true;\n uinfo.first_succ_audio = false;\n }\n /*\n console.log(\"coder[\" + coder.self + \"]\"\n\t+ \" len=\" + frameHdr.len\n\t+ \" kid=\"+ frameHdr.keyId\n\t+ \" fid=\" + frameHdr.frameId);\n */\n\n let kinfo = null;\n for (i = 0; i < coder.keys.length; i++) {\n if (coder.keys[i].id == frameHdr.keyId) {\n kinfo = coder.keys[i];\n break;\n }\n }\n\n if (!kinfo) {\n getMediaKey(coder.self, frameHdr.keyId);\n return;\n }\n\n let iv = null;\n if (isVideo) {\n iv = xor_iv(uinfo.ivv, frameHdr.frameId, frameHdr.keyId);\n }\n else {\n iv = xor_iv(uinfo.iva, frameHdr.frameId, frameHdr.keyId);\n }\n\n const hdr = data.subarray(0, frameHdr.len);\n const dec = data.subarray(frameHdr.len);\n crypto.subtle.decrypt(\n {\n name: \"AES-GCM\",\n iv: iv,\n tagLength: 128,\n additionalData: hdr\n },\n kinfo.key,\n dec\n )\n .then(function(decdata){\n rtcFrame.data = decdata;\n controller.enqueue(rtcFrame);\n if (isVideo && !uinfo.first_succ_video) {\n doLog(\"frame_dec: decrypt: first frame decrypted type: video uid: \" +\n uinfo.userid.substring(0,8) + \" fid: \" + frameHdr.frameId + \" csrc: \" + csrc);\n uinfo.first_succ_video = true;\n }\n if (!isVideo && !uinfo.first_succ_audio) {\n doLog(\"frame_dec: decrypt: first frame decrypted type: audio uid: \" +\n uinfo.userid.substring(0,8) + \" fid: \" + frameHdr.frameId + \" csrc: \" + csrc);\n uinfo.first_succ_audio = true;\n }\n })\n .catch(err => {\n console.log(err);\n });\n}\n\nfunction setupSender(readableStream, writableStream, coder) {\n\tconst transformStream = new TransformStream({\n\t transform: (frame, controller) => {encryptFrame(coder, frame, controller);},\n\t});\n\treadableStream\n .pipeThrough(transformStream)\n .pipeTo(writableStream);\n}\n\nfunction setupReceiver(readableStream, writableStream, coder, track_id) {\n const transformStream = new TransformStream({\n\t transform: (frame, controller) => {decryptFrame(track_id, coder, frame, controller);},\n });\n readableStream\n .pipeThrough(transformStream)\n .pipeTo(writableStream); \n}\n\n\nonrtctransform = (event) => {\n let transform;\n const writableStream = event.transformer.writable;\n const readableStream = event.transformer.readable;\n const coder = coders[event.transformer.options.self];\n\n if (!writableStream) {\n pc_log(LOG_LEVEL_WARN, \"onrtctransform: no writable stream\");\n return;\n }\n if (event.transformer.options.name === \"senderTransform\")\n setupSender(readableStream, writableStream, coder);\n else if (event.transformer.options.name === 'receiverTransform') {\n const track_id = event.transformer.options.track_id;\n doLog(\"onrtctransform: receiver trackid=\" + track_id);\n setupReceiver(readableStream, writableStream, coder, track_id);\n }\n};\n\n\nonmessage = async (event) => {\n const {op, self} = event.data;\n doLog('AVS worker op=' + op + ' self=' + self);\n\n let coder = coders[self];\n if (!coder) {\n\tdoLog('AVS worker: no coder for self=' + self);\n } \n /*\n const {opinfo, readableStream, writableStream} = event.data;\n const mval = opinfo.mtype === 'video' ? 1 : 0; // corresponds to enum frame_media_type\n */\n if (op === 'create') {\n\tconst { iva, ivv } = event.data;\n\tif (!coder) {\n\t coder = {\n\t\tself: self,\n\t\tframeId: Math.floor(Math.random() * 4294967295),\n\t\tcurrentKey: null,\n\t\tkeys: [],\n\t\taudio: {\n\t\t first_recv: false,\n\t\t first_succ: false,\n\t\t iv: iva,\n\t\t ssrc: \"0\",\n\t\t users: {},\n\t\t},\n\t\tvideo: {\n\t\t first_recv: false,\n\t\t first_succ: false,\n\t\t iv: ivv,\n\t\t ssrc: \"0\",\n\t\t users: {},\n\t\t},\n\t }\n\t coders[self] = coder;\n\n\t doLog('AVS worker: adding coder for self=' + self);\n\t}\n }\n else if (op === 'destroy') {\n\tcoders[self] = null;\n }\n else if (op === 'updateSsrc') {\n\tconst { ssrca, ssrcv } = event.data;\n\tcoder.audio.ssrc = ssrca;\n\tcoder.video.ssrc = ssrcv;\n }\n else if (op === 'addUser') {\n if (!coder) {\n doLog('addUser: no coder');\n return;\n }\n const {userInfo} = event.data;\n \n doLog('addUser: adding audio ssrc: '+userInfo.ssrca);\n coder.audio.users[userInfo.ssrca] = userInfo;\n if (userInfo.ssrcv != 0) {\n coder.video.users[userInfo.ssrcv] = userInfo;\n }\n }\n else if (op === 'setupSender') {\n\tconst {readableStream, writableStream} = event.data;\n\n\tsetupSender(readableStream, writableStream, coder);\n }\n else if (op === 'setupReceiver') {\n const {readableStream, writableStream} = event.data;\n\n if (!coder) {\n\t doLog('setupSender: no coder for self=' + self);\n return;\n }\n\n setupReceiver(readableStream, writableStream, coder, null);\n }\n else if (op === 'setMediaKey') {\n const {index, current, key} = event.data;\n\n doLog(\"setMediaKey: got key for: \" + self\n\t\t + \" index=\" + index + \" current=\" + current\n\t\t + \" keyLen=\" + key.length);\n\n crypto.subtle.importKey(\n \"raw\",\n key,\n \"AES-GCM\",\n false,\n [\"encrypt\", \"decrypt\"]\n )\n .then(function(k){\n let kinfo = null;\n for (i = 0; i < coder.keys.length; i++) {\n if (coder.keys[i].id == index) {\n coder.keys[i].key = k;\n kinfo = coder.keys[i];\n break;\n }\n }\n if (!kinfo) {\n kinfo = {id:index, key:k};\n coder.keys.push(kinfo);\n }\n if (index == current)\n coder.currentKey = kinfo;\n\n while (coder.keys.length > 4) {\n coder.keys.shift();\n }\n });\n } \n};\n";
19
+ function callStreamHandler(pc, userid, clientid, ssrc, track_id) {
20
+ pc_log(LOG_LEVEL_INFO, "vsh: ".concat(videoStreamHandler, " rtc: ").concat(pc.rtc, " ssrc: ").concat(ssrc));
21
+ var uinfo = uinfo_from_device(pc, userid, clientid);
22
+ if (ssrc == "0") {
23
+ if (uinfo) {
24
+ uinfo.video_track_id = "0";
25
+ }
26
+ if (videoStreamHandler) {
27
+ pc_log(LOG_LEVEL_INFO, "calling vsh(".concat(pc.convid.substring(0, 8), ", ").concat(userid.substring(0, 8), ", ").concat(clientid.substring(0, 4), ") to remove renderer"));
28
+ videoStreamHandler(pc.convid, userid, clientid, null);
29
+ }
30
+ }
31
+ else if (pc.rtc) {
32
+ if (pc_env === ENV_FIREFOX) {
33
+ pc.rtc.getTransceivers().forEach(function (trans) {
34
+ var track = trans.receiver.track;
35
+ if (track.kind != 'video')
36
+ return;
37
+ pc_log(LOG_LEVEL_INFO, "vsh: id:".concat(track.id, " looking for: ").concat(track_id));
38
+ if (track.id === track_id) {
39
+ if (uinfo) {
40
+ uinfo.video_track_id = track_id;
41
+ }
42
+ var stream = new MediaStream([trans.receiver.track]);
43
+ if (videoStreamHandler) {
44
+ pc_log(LOG_LEVEL_INFO, "calling vsh(".concat(pc.convid.substring(0, 8), ", ").concat(userid.substring(0, 8), ", ").concat(clientid.substring(0, 4), ") with 1 stream"));
45
+ videoStreamHandler(pc.convid, userid, clientid, [stream]);
46
+ }
47
+ }
48
+ });
49
+ }
50
+ else {
51
+ var label_1 = pc.streams[ssrc];
52
+ pc.rtc.getTransceivers().forEach(function (trans) {
53
+ var track = trans.receiver.track;
54
+ pc_log(LOG_LEVEL_INFO, "vsh: label:".concat(track.label, " id:").concat(track.id, " looking for: ").concat(label_1));
55
+ if (trans.receiver.track.label === label_1) {
56
+ if (uinfo) {
57
+ uinfo.video_track_id = track.id;
58
+ }
59
+ var stream = new MediaStream([trans.receiver.track]);
60
+ if (videoStreamHandler) {
61
+ pc_log(LOG_LEVEL_INFO, "calling vsh(".concat(pc.convid.substring(0, 8), ", ").concat(userid.substring(0, 8), ", ").concat(clientid.substring(0, 4), ") with 1 stream"));
62
+ videoStreamHandler(pc.convid, userid, clientid, [stream]);
63
+ }
64
+ }
65
+ });
66
+ }
67
+ }
68
+ }
69
+ function createWorker() {
70
+ var blob = new Blob([workerContent], { type: 'text/javascript' });
71
+ var url = URL.createObjectURL(blob);
72
+ worker = new Worker(url, { name: 'AVS worker' });
73
+ worker.onmessage = function (event) {
74
+ var _a = event.data, op = _a.op, self = _a.self;
75
+ if (op === 'getMediaKey') {
76
+ var index = event.data.index;
77
+ ccallGetMediaKey(self, index);
78
+ }
79
+ else if (op === 'getCurrentMediaKey') {
80
+ ccallGetCurrentMediaKey(self);
81
+ }
82
+ else if (op === 'log') {
83
+ var _b = event.data, level = _b.level, logString = _b.logString;
84
+ pc_log(level, logString);
85
+ }
86
+ else if (op === 'setvstream') {
87
+ var _c = event.data, userid = _c.userid, clientid = _c.clientid, ssrc = _c.ssrc, track_id = _c.track_id;
88
+ pc_log(LOG_LEVEL_INFO, "setvstream: called");
89
+ var pcs = connectionsStore.getPeerConnectionBySelf(self);
90
+ if (pcs.length == 1) {
91
+ pc_log(LOG_LEVEL_INFO, "setvstream: calling videoStreamHandler: pc=".concat(pcs[0], ", ").concat(userid, "/").concat(clientid, " ssrc=").concat(ssrc));
92
+ callStreamHandler(pcs[0], userid, clientid, ssrc, track_id);
93
+ }
94
+ }
95
+ };
96
+ }
10
97
  /* The following constants closely reflect the values
11
98
  * defined in the the C-land counterpart peerconnection_js.c
12
99
  */
@@ -38,6 +125,9 @@ var LOG_LEVEL_ERROR = 3;
38
125
  var CALL_TYPE_NORMAL = 0;
39
126
  var CALL_TYPE_VIDEO = 1;
40
127
  var CALL_TYPE_FORCED_AUDIO = 2;
128
+ var CONV_TYPE_ONEONONE = 0;
129
+ var CONV_TYPE_GROUP = 1;
130
+ var CONV_TYPE_CONFERENCE = 2;
41
131
  var connectionsStore = (function () {
42
132
  var peerConnections = [null];
43
133
  var dataChannels = [null];
@@ -64,6 +154,11 @@ var connectionsStore = (function () {
64
154
  return !!pc && pc.convid === convid;
65
155
  });
66
156
  },
157
+ getPeerConnectionBySelf: function (self) {
158
+ return peerConnections.filter(function (pc) {
159
+ return !!pc && pc.self == self;
160
+ });
161
+ },
67
162
  removePeerConnection: function (index) { return removeItem(peerConnections, index); },
68
163
  storeDataChannel: function (dataChannel) {
69
164
  return storeItem(dataChannels, dataChannel);
@@ -72,9 +167,43 @@ var connectionsStore = (function () {
72
167
  removeDataChannel: function (index) { return removeItem(dataChannels, index); }
73
168
  };
74
169
  })();
75
- function pc_log(level, msg) {
170
+ function pc_log(level, msg, err) {
171
+ if (err === void 0) { err = null; }
172
+ em_module.ccall("pc_log", null, ["number", "string"], [level, msg]);
173
+ /* Log now goes through AVS for anonymization
76
174
  if (logFn)
77
- logFn(level, msg, 0);
175
+ logFn(level, msg, err);
176
+ */
177
+ }
178
+ function uinfo_from_ssrca(pc, ssrc) {
179
+ for (var _i = 0, _a = Object.keys(pc.users); _i < _a.length; _i++) {
180
+ var key = _a[_i];
181
+ var uinfo = pc.users[key];
182
+ if (uinfo.ssrca === ssrc) {
183
+ return uinfo;
184
+ }
185
+ }
186
+ return null;
187
+ }
188
+ function uinfo_from_device(pc, user_id, client_id) {
189
+ for (var _i = 0, _a = Object.keys(pc.users); _i < _a.length; _i++) {
190
+ var key = _a[_i];
191
+ var uinfo = pc.users[key];
192
+ if (uinfo.userid === user_id && uinfo.clientid === client_id) {
193
+ return uinfo;
194
+ }
195
+ }
196
+ return null;
197
+ }
198
+ function uinfo_from_video_track_id(pc, track_id) {
199
+ for (var _i = 0, _a = Object.keys(pc.users); _i < _a.length; _i++) {
200
+ var key = _a[_i];
201
+ var uinfo = pc.users[key];
202
+ if (uinfo.video_track_id === track_id) {
203
+ return uinfo;
204
+ }
205
+ }
206
+ return null;
78
207
  }
79
208
  function replace_track(pc, newTrack) {
80
209
  var rtc = pc.rtc;
@@ -83,25 +212,33 @@ function replace_track(pc, newTrack) {
83
212
  var senders = rtc.getSenders();
84
213
  if (!senders)
85
214
  return false;
86
- for (var _i = 0, senders_1 = senders; _i < senders_1.length; _i++) {
87
- var sender = senders_1[_i];
215
+ var _loop_1 = function (sender) {
88
216
  if (!sender)
89
- continue;
217
+ return "continue";
90
218
  if (!sender.track)
91
- continue;
219
+ return "continue";
92
220
  if (sender.track.kind === newTrack.kind) {
93
221
  var oldTrack = sender.track;
94
222
  if (!oldTrack) {
95
- pc_log(LOG_LEVEL_DEBUG, 'replace_track: oldtrack null');
223
+ pc_log(LOG_LEVEL_INFO, 'replace_track: oldtrack null');
96
224
  }
97
225
  else {
98
- var enabled = oldTrack.enabled;
99
- sender.replaceTrack(newTrack);
100
- sender.track.enabled = enabled;
101
- pc_log(LOG_LEVEL_DEBUG, "replace_track: kind=" + newTrack.kind + " enabled=" + sender.track.enabled);
102
- return true;
226
+ var enabled_1 = oldTrack.enabled;
227
+ sender.replaceTrack(newTrack).then(function () {
228
+ if (!!sender && !!sender.track) {
229
+ sender.track.enabled = enabled_1;
230
+ pc_log(LOG_LEVEL_INFO, "replace_track: kind=".concat(newTrack.kind, " enabled=").concat(sender.track.enabled));
231
+ }
232
+ });
233
+ return { value: true };
103
234
  }
104
235
  }
236
+ };
237
+ for (var _i = 0, senders_1 = senders; _i < senders_1.length; _i++) {
238
+ var sender = senders_1[_i];
239
+ var state_1 = _loop_1(sender);
240
+ if (typeof state_1 === "object")
241
+ return state_1.value;
105
242
  }
106
243
  return false;
107
244
  }
@@ -109,9 +246,10 @@ function update_tracks(pc, stream) {
109
246
  var rtc = pc.rtc;
110
247
  var tracks = stream.getTracks();
111
248
  var found = false;
112
- pc_log(LOG_LEVEL_INFO, "update_tracks: pc=" + pc.self + " tracks=" + tracks.length);
113
- if (!rtc)
114
- return;
249
+ pc_log(LOG_LEVEL_INFO, "update_tracks: pc=".concat(pc.self, " tracks=").concat(tracks.length));
250
+ if (!rtc) {
251
+ return Promise.resolve();
252
+ }
115
253
  var senders = rtc.getSenders();
116
254
  for (var _i = 0, senders_2 = senders; _i < senders_2.length; _i++) {
117
255
  var sender = senders_2[_i];
@@ -125,9 +263,9 @@ function update_tracks(pc, stream) {
125
263
  for (var _a = 0, tracks_1 = tracks; _a < tracks_1.length; _a++) {
126
264
  var track = tracks_1[_a];
127
265
  if (track)
128
- pc_log(LOG_LEVEL_DEBUG, "update_tracks: kind=" + track.kind + " sender=" + sender.track.kind);
266
+ pc_log(LOG_LEVEL_INFO, "update_tracks: kind=".concat(track.kind, " sender=").concat(sender.track.kind));
129
267
  else
130
- pc_log(LOG_LEVEL_DEBUG, "update_tracks: sender.track=" + sender.track + " track=" + track);
268
+ pc_log(LOG_LEVEL_INFO, "update_tracks: sender.track=".concat(sender.track, " track=").concat(track));
131
269
  if (sender.track) {
132
270
  if (sender.track.kind === track.kind) {
133
271
  found = true;
@@ -137,10 +275,15 @@ function update_tracks(pc, stream) {
137
275
  }
138
276
  }
139
277
  if (!found) {
140
- if (sender.track)
278
+ if (sender.track) {
141
279
  sender.track.enabled = false;
280
+ }
142
281
  }
143
282
  }
283
+ var videoSenderUpdates = [];
284
+ // We have to check old API, because in old API the transceiver with mid==1 is a receiver and in the new API it is
285
+ // a sender. We have to avoid adding tracks if transceiver is receiver.
286
+ var isOldAPI = rtc.getTransceivers().some(function (t) { return t.mid === "video"; });
144
287
  tracks.forEach(function (track) {
145
288
  if (track.kind === 'video') {
146
289
  pc.sending_video = true;
@@ -149,10 +292,71 @@ function update_tracks(pc, stream) {
149
292
  track.enabled = !pc.muted;
150
293
  }
151
294
  if (!replace_track(pc, track)) {
152
- pc_log(LOG_LEVEL_INFO, "update_tracks: adding track of kind=" + track.kind);
153
- rtc.addTrack(track, stream);
295
+ pc_log(LOG_LEVEL_INFO, "update_tracks: adding track of kind=".concat(track.kind, ", id=").concat(track.id));
296
+ if (track.kind === 'video' && pc.conv_type !== CONV_TYPE_ONEONONE) {
297
+ var transceivers = rtc.getTransceivers();
298
+ var _loop_2 = function (trans) {
299
+ if ((trans.mid === 'video' && isOldAPI) || (trans.mid === '1' && !isOldAPI)) {
300
+ pc_log(LOG_LEVEL_INFO, "update_tracks: adjust");
301
+ var _a = getEncodingParameter(trans.sender, pc.vstate === PC_VIDEO_STATE_SCREENSHARE), params_1 = _a.params, layerFound = _a.layerFound;
302
+ pc_log(LOG_LEVEL_INFO, 'add track: ' + layerFound);
303
+ rtc.addTrack(track, stream);
304
+ if (layerFound) {
305
+ videoSenderUpdates.push(trans.sender.setParameters(params_1).catch(function (e) { return pc_log(LOG_LEVEL_ERROR, "update_tracks: set params ".concat(e)); })
306
+ .then(function () {
307
+ pc_log(LOG_LEVEL_INFO, 'setParameters: ' + JSON.stringify(params_1));
308
+ })
309
+ .then());
310
+ }
311
+ }
312
+ };
313
+ for (var _i = 0, transceivers_1 = transceivers; _i < transceivers_1.length; _i++) {
314
+ var trans = transceivers_1[_i];
315
+ _loop_2(trans);
316
+ }
317
+ }
318
+ else {
319
+ rtc.addTrack(track, stream);
320
+ }
321
+ }
322
+ });
323
+ // Either the codecs did not need to be adjusted because we are in a 1:1 call, or we are not sending a video track.
324
+ // In that case, there is no need to wait for the asynchronous process
325
+ if (videoSenderUpdates.length === 0) {
326
+ return Promise.resolve();
327
+ }
328
+ // Wait until setup is finish
329
+ return Promise.all(videoSenderUpdates).catch(function (e) {
330
+ pc_log(LOG_LEVEL_ERROR, "update_tracks: error=".concat(e));
331
+ }).then();
332
+ }
333
+ function getEncodingParameter(sender, isScreenShare) {
334
+ pc_log(LOG_LEVEL_INFO, "update_tracks: adjust");
335
+ var params = sender.getParameters();
336
+ if (!params.encodings) {
337
+ pc_log(LOG_LEVEL_INFO, "update_tracks: no params");
338
+ params.encodings = [];
339
+ }
340
+ var layerFound = false;
341
+ params.encodings.forEach(function (coding) {
342
+ if (coding.rid === 'l') {
343
+ //@ts-ignore
344
+ coding.scalabilityMode = 'L1T1';
345
+ coding.active = !isScreenShare;
346
+ coding.scaleResolutionDownBy = 2.0;
347
+ coding.maxBitrate = 500000;
348
+ layerFound = true;
349
+ }
350
+ if (coding.rid === 'h') {
351
+ //@ts-ignore
352
+ coding.scalabilityMode = 'L1T1';
353
+ coding.scaleResolutionDownBy = 1.0;
354
+ coding.active = true;
355
+ coding.maxBitrate = isScreenShare ? 1500000 : 3000000;
356
+ layerFound = true;
154
357
  }
155
358
  });
359
+ return { params: params, layerFound: layerFound };
156
360
  }
157
361
  function sigState(stateStr) {
158
362
  var state = PC_SIG_STATE_UNKNOWN;
@@ -203,29 +407,46 @@ function ccallDcStateChangeHandler(pc, state) {
203
407
  function ccallDcDataHandler(pc, data) {
204
408
  em_module.ccall("dc_data_handler", null, ["number", "string", "number"], [pc.self, data, data.length]);
205
409
  }
410
+ function ccallGetMediaKey(self, index) {
411
+ em_module.ccall("pc_get_media_key", null, ["number", "number"], [self, index]);
412
+ }
413
+ function ccallGetCurrentMediaKey(self) {
414
+ em_module.ccall("pc_get_current_media_key", null, ["number"], [self]);
415
+ }
416
+ function gatheringComplete(pc) {
417
+ if (pc.gatherTimer != null) {
418
+ clearTimeout(pc.gatherTimer);
419
+ pc.gatherTimer = null;
420
+ }
421
+ var rtc = pc.rtc;
422
+ if (!rtc) {
423
+ return;
424
+ }
425
+ var sdp = rtc.localDescription;
426
+ if (!sdp) {
427
+ return;
428
+ }
429
+ ccallGatheringHandler(pc, sdp.type.toString(), sdp.sdp.toString());
430
+ }
206
431
  function gatheringHandler(pc) {
207
432
  var rtc = pc.rtc;
208
433
  if (!rtc) {
209
434
  return;
210
435
  }
211
436
  var state = rtc.iceGatheringState;
212
- pc_log(LOG_LEVEL_INFO, "ice gathering state=" + state);
437
+ pc_log(LOG_LEVEL_INFO, "ice gathering state=".concat(state));
213
438
  switch (state) {
214
439
  case "new":
215
440
  break;
216
441
  case "gathering":
217
442
  break;
218
443
  case "complete":
219
- var sdp = rtc.localDescription;
220
- if (!sdp) {
221
- return;
222
- }
223
- ccallGatheringHandler(pc, sdp.type.toString(), sdp.sdp.toString());
444
+ gatheringComplete(pc);
224
445
  break;
225
446
  }
226
447
  }
227
448
  function negotiationHandler(pc) {
228
- pc_log(LOG_LEVEL_INFO, "negotiationHandler: " + pc.self);
449
+ pc_log(LOG_LEVEL_INFO, "negotiationHandler: ".concat(pc.self));
229
450
  }
230
451
  function signallingHandler(pc) {
231
452
  var rtc = pc.rtc;
@@ -233,7 +454,7 @@ function signallingHandler(pc) {
233
454
  return;
234
455
  }
235
456
  var stateStr = rtc.signalingState;
236
- pc_log(LOG_LEVEL_INFO, "signalingHandler: state: " + stateStr);
457
+ pc_log(LOG_LEVEL_INFO, "signalingHandler: state: ".concat(stateStr));
237
458
  ccallSignallingHandler(pc, sigState(stateStr));
238
459
  }
239
460
  function setMute(pc) {
@@ -253,52 +474,28 @@ function setMute(pc) {
253
474
  function candidateHandler(pc, cand) {
254
475
  var mindex = cand ? cand.sdpMLineIndex : null;
255
476
  if (cand !== null)
256
- pc_log(LOG_LEVEL_DEBUG, "candidateHandler: cand=" + cand.candidate + " type=" + cand.type + " mindex=" + mindex);
477
+ pc_log(LOG_LEVEL_INFO, "candidateHandler: cand=".concat(cand.candidate, " type=").concat(cand.type, " mindex=").concat(mindex));
257
478
  else {
258
- pc_log(LOG_LEVEL_DEBUG, "candidateHandler: cand=NULL");
479
+ pc_log(LOG_LEVEL_INFO, "candidateHandler: cand=NULL");
259
480
  }
260
481
  if (!pc || !pc.rtc)
261
482
  return;
262
483
  if (!cand) {
263
484
  pc_log(LOG_LEVEL_INFO, 'candidateHandler: end-of-candidates');
264
- var sdp = pc.rtc.localDescription;
265
- if (sdp)
266
- ccallGatheringHandler(pc, sdp.type.toString(), sdp.sdp.toString());
485
+ gatheringComplete(pc);
267
486
  return;
268
487
  }
269
- if (pc_env === ENV_FIREFOX) {
270
- if (mindex != null) {
271
- var cmid = pc.cands[mindex];
272
- if (!cmid) {
273
- pc_log(LOG_LEVEL_DEBUG, "candidateHandler: adding mindex=" + mindex);
274
- pc.cands[mindex] = {
275
- mindex: mindex,
276
- hasRelay: false
277
- };
278
- }
279
- }
280
- }
488
+ /* As soon as we get the first relay, we start a gathering timer
489
+ * this was we ensure that gathering never takes more than the
490
+ * timeout period.
491
+ */
281
492
  if (cand.type === 'relay') {
282
- var sdp = pc.rtc.localDescription;
283
- if (!sdp) {
284
- return;
285
- }
286
- if (pc_env == ENV_FIREFOX) {
287
- if (mindex != null) {
288
- var rmid = pc.cands[mindex];
289
- if (rmid)
290
- rmid.hasRelay = true;
291
- }
292
- for (var _i = 0, _a = pc.cands; _i < _a.length; _i++) {
293
- var cc = _a[_i];
294
- if (cc && !cc.hasRelay) {
295
- pc_log(LOG_LEVEL_DEBUG, "candidateHandler: mindex=" + cc.mindex + " still missing relay");
296
- return;
297
- }
298
- }
493
+ if (pc.gatherTimer == null) {
494
+ pc.gatherTimer = setTimeout(function () {
495
+ pc.gatherTimer = null;
496
+ gatheringComplete(pc);
497
+ }, TIMEOUT_GATHER);
299
498
  }
300
- pc_log(LOG_LEVEL_INFO, 'candidateHandler: relay(s) found, finished gathering');
301
- ccallGatheringHandler(pc, sdp.type.toString(), sdp.sdp.toString());
302
499
  }
303
500
  }
304
501
  function connectionHandler(pc) {
@@ -306,42 +503,53 @@ function connectionHandler(pc) {
306
503
  if (!rtc) {
307
504
  return;
308
505
  }
309
- var state = rtc.iceConnectionState;
310
- pc_log(LOG_LEVEL_INFO, "connectionHandler state: " + state);
506
+ var state = rtc.connectionState;
507
+ pc_log(LOG_LEVEL_INFO, "connectionHandler state: ".concat(state));
311
508
  ccallConnectionHandler(pc, state);
312
509
  setMute(pc);
313
510
  }
314
511
  function setupDataChannel(pc, dc) {
315
512
  var dcHnd = connectionsStore.storeDataChannel(dc);
316
513
  dc.onopen = function () {
317
- pc_log(LOG_LEVEL_DEBUG, "dc-opened");
514
+ pc_log(LOG_LEVEL_INFO, "dc-opened");
318
515
  ccallDcStateChangeHandler(pc, DC_STATE_OPEN);
319
516
  };
320
517
  dc.onclose = function () {
321
- pc_log(LOG_LEVEL_DEBUG, "dc-closed");
518
+ pc_log(LOG_LEVEL_INFO, "dc-closed");
322
519
  ccallDcStateChangeHandler(pc, DC_STATE_CLOSED);
323
520
  };
324
- dc.onerror = function () {
325
- pc_log(LOG_LEVEL_DEBUG, "dc-error");
326
- ccallDcStateChangeHandler(pc, DC_STATE_ERROR);
521
+ dc.onerror = function (event) {
522
+ if (event instanceof RTCErrorEvent) {
523
+ pc_log(LOG_LEVEL_INFO, "dc-error: ".concat(event.error));
524
+ ccallDcStateChangeHandler(pc, DC_STATE_ERROR);
525
+ }
327
526
  };
328
527
  dc.onmessage = function (event) {
329
- pc_log(LOG_LEVEL_DEBUG, "dc-onmessage: data=" + event.data.length);
528
+ pc_log(LOG_LEVEL_INFO, "dc-onmessage: data=".concat(event.data.length));
330
529
  ccallDcDataHandler(pc, event.data.toString());
331
530
  };
332
531
  return dcHnd;
333
532
  }
334
533
  function dataChannelHandler(pc, event) {
335
534
  var dc = event.channel;
336
- pc_log(LOG_LEVEL_INFO, "dataChannelHandler: " + dc);
535
+ pc_log(LOG_LEVEL_INFO, "dataChannelHandler: ".concat(dc));
337
536
  var dcHnd = setupDataChannel(pc, dc);
338
537
  ccallDcEstabHandler(pc, dcHnd);
339
538
  }
340
539
  function pc_SetEnv(env) {
540
+ pc_log(LOG_LEVEL_INFO, "setEnv=".concat(env));
341
541
  pc_env = env;
342
542
  }
343
- function pc_New(self, convidPtr) {
344
- pc_log(LOG_LEVEL_DEBUG, "pc_New");
543
+ function pc_New(self, convidPtr, audioIvPtr, videoIvPtr, ivlen) {
544
+ pc_log(LOG_LEVEL_INFO, "pc_New");
545
+ var iva = new ArrayBuffer(ivlen);
546
+ var aptr = new Uint8Array(em_module.HEAPU8.buffer, audioIvPtr, ivlen);
547
+ var iva8 = new Uint8Array(iva);
548
+ iva8.set(aptr);
549
+ var ivv = new ArrayBuffer(ivlen);
550
+ var vptr = new Uint8Array(em_module.HEAPU8.buffer, videoIvPtr, ivlen);
551
+ var ivv8 = new Uint8Array(ivv);
552
+ ivv8.set(vptr);
345
553
  var pc = {
346
554
  self: self,
347
555
  convid: em_module.UTF8ToString(convidPtr),
@@ -352,55 +560,127 @@ function pc_New(self, convidPtr) {
352
560
  vstate: PC_VIDEO_STATE_STOPPED,
353
561
  sending_video: false,
354
562
  call_type: CALL_TYPE_NORMAL,
563
+ conv_type: CONV_TYPE_ONEONONE,
355
564
  muted: false,
356
- cands: [null, null, null],
565
+ users: {},
566
+ iva: iva8,
567
+ ivv: ivv8,
568
+ stats: {
569
+ ploss: 0,
570
+ lastploss: 0,
571
+ bytes: 0,
572
+ lastbytes: 0,
573
+ recv_apkts: 0,
574
+ recv_vpkts: 0,
575
+ sent_apkts: 0,
576
+ sent_vpkts: 0,
577
+ rtt: 0
578
+ },
579
+ streams: {},
580
+ gatherTimer: null
357
581
  };
582
+ worker.postMessage({ op: 'create', self: pc.self, iva: iva8, ivv: ivv8 });
358
583
  var hnd = connectionsStore.storePeerConnection(pc);
359
584
  return hnd;
360
585
  }
361
- function pc_Create(hnd) {
586
+ function pc_Create(hnd, privacy, conv_type) {
362
587
  var pc = connectionsStore.getPeerConnection(hnd);
363
588
  if (pc == null) {
364
589
  return;
365
590
  }
591
+ pc.conv_type = conv_type;
592
+ var transportPolicy = privacy !== 0 ? "relay" : "all";
593
+ var useEncoding = pc.conv_type === CONV_TYPE_CONFERENCE;
366
594
  var config = {
367
595
  bundlePolicy: "max-bundle",
368
596
  iceServers: pc.turnServers,
369
- rtcpMuxPolicy: 'require'
597
+ rtcpMuxPolicy: 'require',
598
+ iceTransportPolicy: transportPolicy,
599
+ encodedInsertableStreams: useEncoding,
600
+ forceEncodedVideoInsertableStreams: useEncoding,
601
+ forceEncodedAudioInsertableStreams: useEncoding,
370
602
  };
371
- pc_log(LOG_LEVEL_INFO, "pc_Create: configuring: " + pc.turnServers.length + " TURN servers");
603
+ pc_log(LOG_LEVEL_INFO, "pc_Create: configuring: ".concat(pc.turnServers.length, " TURN servers"));
372
604
  var rtc = new RTCPeerConnection(config);
605
+ pc.rtc = rtc;
373
606
  rtc.onicegatheringstatechange = function () { return gatheringHandler(pc); };
374
- rtc.oniceconnectionstatechange = function () { return connectionHandler(pc); };
607
+ rtc.onconnectionstatechange = function () { return connectionHandler(pc); };
375
608
  rtc.onicecandidate = function (event) { return candidateHandler(pc, event.candidate); };
376
609
  rtc.onsignalingstatechange = function (event) { return signallingHandler(pc); };
377
610
  rtc.ondatachannel = function (event) { return dataChannelHandler(pc, event); };
378
611
  rtc.onnegotiationneeded = function () { return negotiationHandler(pc); };
612
+ var label = '';
379
613
  rtc.ontrack = function (event) {
380
- pc_log(LOG_LEVEL_INFO, "onTrack: convid=" + pc.convid + " userid=" + pc.remote_userid + "/" + pc.remote_clientid + " streams=" + event.streams.length);
614
+ pc_log(LOG_LEVEL_INFO, "onTrack: self=".concat(pc.self, " convid=").concat(pc.convid.substring(0, 8), " userid=").concat(pc.remote_userid.substring(0, 8), "/").concat(pc.remote_clientid.substring(0, 4), " streams=").concat(event.streams.length));
381
615
  if (event.streams && event.streams.length > 0) {
382
616
  for (var _i = 0, _a = event.streams; _i < _a.length; _i++) {
383
617
  var stream = _a[_i];
384
- pc_log(LOG_LEVEL_INFO, "onTrack: convid=" + pc.convid + " stream=" + stream);
618
+ pc_log(LOG_LEVEL_INFO, "onTrack: convid=".concat(pc.convid.substring(0, 8), " stream=").concat(stream));
385
619
  for (var _b = 0, _c = stream.getTracks(); _b < _c.length; _b++) {
386
620
  var track = _c[_b];
387
- if (track)
388
- pc_log(LOG_LEVEL_INFO, "onTrack: convid=" + pc.convid + " track=" + track.kind);
621
+ if (track) {
622
+ if (pc_env === ENV_FIREFOX)
623
+ label = track.id;
624
+ else
625
+ label = track.label;
626
+ pc_log(LOG_LEVEL_INFO, "onTrack: convid=".concat(pc.convid.substring(0, 8), " track=").concat(track.id, "/").concat(track.label, "=>").concat(label, " kind=").concat(track.kind, " enabled=").concat(track.enabled, "/").concat(track.muted, "/undefined/").concat(track.readyState, " remote=undefined"));
627
+ if (!track.enabled)
628
+ track.enabled = true;
629
+ if (pc.conv_type === CONV_TYPE_CONFERENCE) {
630
+ try {
631
+ setupReceiverTransform(pc, event.receiver);
632
+ }
633
+ catch (err) {
634
+ pc_log(LOG_LEVEL_WARN, "onTrack: setupReceiverTransform failed: " + err, err);
635
+ }
636
+ }
637
+ }
389
638
  }
390
639
  }
391
640
  }
392
- if (mediaStreamHandler != null) {
393
- mediaStreamHandler(pc.convid, pc.remote_userid, pc.remote_clientid, event.streams);
641
+ if (event.track.kind == "audio" && audioStreamHandler) {
642
+ pc_log(LOG_LEVEL_INFO, "onTrack: calling ash(".concat(pc.convid.substring(0, 8), ", ").concat(label, ") with ").concat(event.streams.length, " streams"));
643
+ audioStreamHandler(pc.convid, hnd.toString() + label, event.streams);
644
+ }
645
+ if (event.track.kind == "video" && videoStreamHandler) {
646
+ var userid = pc.remote_userid;
647
+ var clientid = pc.remote_clientid;
648
+ // @TODO: Remove, because the `keys` from `pc.users[]` is are random strings and not track.id or track.label, so means `uinfo` will be `undefined` everytime!
649
+ var uinfo = pc.users[label];
650
+ if (uinfo) {
651
+ userid = uinfo.userid;
652
+ clientid = uinfo.clientid;
653
+ }
654
+ if (userid != "sft" && userid != "") {
655
+ pc_log(LOG_LEVEL_INFO, "onTrack: calling vsh(".concat(pc.convid.substring(0, 8), ", ").concat(userid.substring(0, 8), ", ").concat(clientid.substring(0, 4), ") with ").concat(event.streams.length, " streams"));
656
+ videoStreamHandler(pc.convid, userid, clientid, event.streams);
657
+ }
394
658
  }
395
659
  };
396
- pc.rtc = rtc;
397
660
  }
398
661
  function pc_Close(hnd) {
399
- pc_log(LOG_LEVEL_INFO, "pc_Close: hnd=" + hnd);
662
+ pc_log(LOG_LEVEL_INFO, "pc_Close: hnd=".concat(hnd));
400
663
  var pc = connectionsStore.getPeerConnection(hnd);
401
664
  if (pc == null) {
402
665
  return;
403
666
  }
667
+ if (pc.rtc) {
668
+ pc.rtc.getTransceivers().forEach(function (trans) {
669
+ var track = trans.receiver.track;
670
+ if (track && track.kind === "audio") {
671
+ var label = '';
672
+ if (pc_env == ENV_FIREFOX)
673
+ label = track.id;
674
+ else
675
+ label = track.label;
676
+ if (audioStreamHandler && pc.rtc) {
677
+ pc_log(LOG_LEVEL_INFO, "pc_Close: calling ash(".concat(pc.convid.substring(0, 8), ", ").concat(label, ") with 0 streams"));
678
+ audioStreamHandler(pc.convid, hnd.toString() + label, null);
679
+ }
680
+ }
681
+ });
682
+ }
683
+ worker.postMessage({ op: 'destroy', self: pc.self });
404
684
  connectionsStore.removePeerConnection(hnd);
405
685
  var rtc = pc.rtc;
406
686
  if (!rtc) {
@@ -410,7 +690,7 @@ function pc_Close(hnd) {
410
690
  pc.rtc = null;
411
691
  }
412
692
  function pc_AddTurnServer(hnd, urlPtr, usernamePtr, passwordPtr) {
413
- pc_log(LOG_LEVEL_INFO, "pc_AddTurnServer: hnd=" + hnd);
693
+ pc_log(LOG_LEVEL_INFO, "pc_AddTurnServer: hnd=".concat(hnd));
414
694
  var pc = connectionsStore.getPeerConnection(hnd);
415
695
  if (pc == null) {
416
696
  return;
@@ -418,7 +698,7 @@ function pc_AddTurnServer(hnd, urlPtr, usernamePtr, passwordPtr) {
418
698
  var url = em_module.UTF8ToString(urlPtr);
419
699
  var username = em_module.UTF8ToString(usernamePtr);
420
700
  var credential = em_module.UTF8ToString(passwordPtr);
421
- pc_log(LOG_LEVEL_INFO, "pc_AddTurnServer: hnd=" + hnd + " adding: " + username + ":" + credential + "@" + url);
701
+ pc_log(LOG_LEVEL_INFO, "pc_AddTurnServer: hnd=".concat(hnd, " adding: ").concat(url));
422
702
  var server = {
423
703
  urls: url,
424
704
  username: username,
@@ -431,15 +711,15 @@ function pc_HasVideo(hnd) {
431
711
  if (pc == null) {
432
712
  return 0;
433
713
  }
434
- pc_log(LOG_LEVEL_INFO, "pc_HasVideo(" + hnd + "): sending=" + pc.sending_video);
714
+ pc_log(LOG_LEVEL_INFO, "pc_HasVideo(".concat(hnd, "): sending=").concat(pc.sending_video));
435
715
  var senders = pc.rtc ? pc.rtc.getSenders() : [];
436
- pc_log(LOG_LEVEL_DEBUG, "pc_HasVideo: " + senders.length + " senders");
716
+ pc_log(LOG_LEVEL_INFO, "pc_HasVideo: " + senders.length + " senders");
437
717
  for (var _i = 0, senders_4 = senders; _i < senders_4.length; _i++) {
438
718
  var sender = senders_4[_i];
439
- pc_log(LOG_LEVEL_DEBUG, "pc_HasVideo: track=" + sender.track);
719
+ pc_log(LOG_LEVEL_INFO, "pc_HasVideo: track=" + sender.track);
440
720
  if (sender.track) {
441
721
  var track = sender.track;
442
- pc_log(LOG_LEVEL_DEBUG, "pc_HasVideo: track.kind=" + track.kind + " enabled=" + track.enabled);
722
+ pc_log(LOG_LEVEL_INFO, "pc_HasVideo: track.kind=" + track.kind + " enabled=" + track.enabled);
443
723
  if (track.kind === 'video' && track.enabled)
444
724
  return 1;
445
725
  }
@@ -448,12 +728,12 @@ function pc_HasVideo(hnd) {
448
728
  for (var _a = 0, txrxs_1 = txrxs; _a < txrxs_1.length; _a++) {
449
729
  var txrx = txrxs_1[_a];
450
730
  if (!txrx) {
451
- pc_log(LOG_LEVEL_DEBUG, "pc_HasVideo: no txrx");
731
+ pc_log(LOG_LEVEL_INFO, "pc_HasVideo: no txrx");
452
732
  continue;
453
733
  }
454
734
  var rx = txrx.receiver;
455
735
  var tx = txrx.sender;
456
- pc_log(LOG_LEVEL_DEBUG, "pc_HasVideo: txrx dir=" + txrx.direction + "/" + txrx.currentDirection + " rx=" + rx + " tx=" + tx);
736
+ pc_log(LOG_LEVEL_INFO, "pc_HasVideo: txrx dir=".concat(txrx.direction, "/").concat(txrx.currentDirection, " rx=").concat(rx, " tx=").concat(tx));
457
737
  }
458
738
  return 0;
459
739
  }
@@ -462,7 +742,7 @@ function pc_SetVideoState(hnd, vstate) {
462
742
  if (pc == null) {
463
743
  return;
464
744
  }
465
- pc_log(LOG_LEVEL_INFO, "pc_SetVideoState: hnd=" + hnd + " vstate=" + vstate + "/" + pc.vstate + " callType=" + pc.call_type + " active=" + pc.sending_video);
745
+ pc_log(LOG_LEVEL_INFO, "pc_SetVideoState: hnd=".concat(hnd, " vstate=").concat(vstate, "/").concat(pc.vstate, " callType=").concat(pc.call_type, " active=").concat(pc.sending_video));
466
746
  if (pc.vstate === vstate)
467
747
  return;
468
748
  var active = false;
@@ -487,14 +767,14 @@ function pc_SetVideoState(hnd, vstate) {
487
767
  should_update = true;
488
768
  else if (vstate === PC_VIDEO_STATE_SCREENSHARE)
489
769
  should_update = true;
490
- pc_log(LOG_LEVEL_DEBUG, "pc_SetVideoState: should_update=" + should_update + " vstate=" + vstate + " active=" + active);
770
+ pc_log(LOG_LEVEL_INFO, "pc_SetVideoState: should_update=".concat(should_update, " vstate=").concat(vstate, " active=").concat(active));
491
771
  if (should_update && userMediaHandler) {
492
772
  var use_video = vstate === PC_VIDEO_STATE_STARTED;
493
773
  var use_ss = vstate === PC_VIDEO_STATE_SCREENSHARE;
494
- pc_log(LOG_LEVEL_DEBUG, "pc_SetVideoState: calling umh(1, " + use_video + ", " + use_ss + ")");
774
+ pc_log(LOG_LEVEL_INFO, "pc_SetVideoState: calling umh(1, ".concat(use_video, ", ").concat(use_ss, ")"));
495
775
  userMediaHandler(pc.convid, true, use_video, use_ss)
496
776
  .then(function (stream) {
497
- update_tracks(pc, stream);
777
+ return update_tracks(pc, stream);
498
778
  });
499
779
  pc.sending_video = use_video || use_ss;
500
780
  }
@@ -522,8 +802,153 @@ function sdpMap(sdp, local, bundle) {
522
802
  });
523
803
  return sdpLines.join('\r\n');
524
804
  }
805
+ function sdpCbrMap(sdp) {
806
+ var sdpLines = [];
807
+ sdp.split('\r\n').forEach(function (sdpLine) {
808
+ var outline;
809
+ outline = sdpLine;
810
+ if (sdpLine.endsWith('sprop-stereo=0;useinbandfec=1')) {
811
+ outline = sdpLine + ";cbr=1";
812
+ }
813
+ else if (sdpLine.startsWith('a=ssrc-group:')) {
814
+ var group = sdpLine;
815
+ // in case of only one ssrc in group (no nack/rtx), remove attribute
816
+ var spaces = group.trim().split(' ').length;
817
+ if (spaces < 3) {
818
+ outline = null;
819
+ }
820
+ }
821
+ else if (sdpLine.startsWith('a=simulcast:recv l;h') && pc_env !== ENV_FIREFOX) {
822
+ // add conference attribute for chrome
823
+ sdpLines.push('a=x-google-flag:conference');
824
+ }
825
+ // reorder rids for firefox
826
+ else if (sdpLine.startsWith('a=simulcast:recv l;h') && pc_env === ENV_FIREFOX) {
827
+ outline = 'a=simulcast:recv h;l';
828
+ }
829
+ else if (sdpLine.startsWith('a=rid:l recv') && pc_env === ENV_FIREFOX) {
830
+ outline = 'a=rid:h recv';
831
+ }
832
+ else if (sdpLine.startsWith('a=rid:h recv') && pc_env === ENV_FIREFOX) {
833
+ outline = 'a=rid:l recv';
834
+ }
835
+ if (outline != null) {
836
+ sdpLines.push(outline);
837
+ }
838
+ });
839
+ return sdpLines.join('\r\n');
840
+ }
841
+ function sdpRidReOrder(sdp) {
842
+ var sdpLines = [];
843
+ sdp.split('\r\n').forEach(function (sdpLine) {
844
+ var outline;
845
+ outline = sdpLine;
846
+ if (sdpLine.startsWith('a=simulcast:send h;l') && pc_env === ENV_FIREFOX) {
847
+ outline = 'a=simulcast:send l;h';
848
+ }
849
+ else if (sdpLine.startsWith('a=rid:h send') && pc_env === ENV_FIREFOX) {
850
+ outline = 'a=rid:l send';
851
+ }
852
+ else if (sdpLine.startsWith('a=rid:l send') && pc_env === ENV_FIREFOX) {
853
+ outline = 'a=rid:h send';
854
+ }
855
+ if (outline != null) {
856
+ sdpLines.push(outline);
857
+ }
858
+ });
859
+ return sdpLines.join('\r\n');
860
+ }
861
+ function pc_SetMediaKey(hnd, index, current, keyPtr, keyLen) {
862
+ var pc = connectionsStore.getPeerConnection(hnd);
863
+ if (pc == null) {
864
+ return;
865
+ }
866
+ var buf = new ArrayBuffer(keyLen);
867
+ var ptr = new Uint8Array(em_module.HEAPU8.buffer, keyPtr, keyLen);
868
+ var buf8 = new Uint8Array(buf);
869
+ buf8.set(ptr);
870
+ worker.postMessage({
871
+ op: 'setMediaKey',
872
+ self: pc.self,
873
+ index: index,
874
+ current: current,
875
+ key: buf8
876
+ });
877
+ }
878
+ function pc_UpdateSsrc(hnd, ssrcaPtr, ssrcvPtr) {
879
+ var pc = connectionsStore.getPeerConnection(hnd);
880
+ if (pc == null) {
881
+ return;
882
+ }
883
+ var ssrca = em_module.UTF8ToString(ssrcaPtr);
884
+ var ssrcv = em_module.UTF8ToString(ssrcvPtr);
885
+ pc_log(LOG_LEVEL_INFO, "pc_UpdateSsrc: hnd=".concat(hnd, " ssrc=").concat(ssrca, " ssrcv=").concat(ssrcv));
886
+ worker.postMessage({
887
+ op: 'updateSsrc',
888
+ self: pc.self,
889
+ ssrca: ssrca,
890
+ ssrcv: ssrcv
891
+ });
892
+ }
893
+ function setupSenderTransform(pc, sender) {
894
+ if (!sender || !sender.track) {
895
+ return;
896
+ }
897
+ if (!insertableLegacy && !insertableStreams) {
898
+ pc_log(LOG_LEVEL_WARN, "setupSenderTransform: insertable streams not supported");
899
+ return;
900
+ }
901
+ if (pc_env === ENV_FIREFOX) {
902
+ sender.transform = new RTCRtpScriptTransform(worker, { name: "senderTransform", self: pc.self });
903
+ return;
904
+ }
905
+ var mtype = sender.track.kind === 'video' ? 1 : 0; // corresponds to enum frame_media_type
906
+ var senderStreams = null;
907
+ if (insertableStreams)
908
+ senderStreams = sender.createEncodedStreams();
909
+ else
910
+ senderStreams = mtype === 1 ? sender.createEncodedVideoStreams() : sender.createEncodedAudioStreams();
911
+ pc_log(LOG_LEVEL_INFO, "setupSenderTransform: senderStream: ".concat(senderStreams.readable, "/").concat(senderStreams.readableStream));
912
+ var readableStream = senderStreams.readable || senderStreams.readableStream;
913
+ var writableStream = senderStreams.writable || senderStreams.writableStream;
914
+ worker.postMessage({
915
+ op: 'setupSender',
916
+ self: pc.self,
917
+ readableStream: readableStream,
918
+ writableStream: writableStream,
919
+ }, [readableStream, writableStream]);
920
+ }
921
+ function setupReceiverTransform(pc, receiver) {
922
+ if (!receiver || !receiver.track) {
923
+ return;
924
+ }
925
+ if (!insertableLegacy && !insertableStreams) {
926
+ pc_log(LOG_LEVEL_WARN, "setupReceiverTransform: insertable streams not supported");
927
+ return;
928
+ }
929
+ if (pc_env == ENV_FIREFOX) {
930
+ receiver.transform = new RTCRtpScriptTransform(worker, { name: "receiverTransform", self: pc.self, track_id: receiver.track.id });
931
+ return;
932
+ }
933
+ var mtype = receiver.track.kind === 'video' ? 1 : 0; // corresponds to enum frame_media_type
934
+ var receiverStreams = null;
935
+ if (insertableStreams)
936
+ receiverStreams = receiver.createEncodedStreams();
937
+ else
938
+ receiverStreams = mtype === 1 ? receiver.createEncodedVideoStreams() : receiver.createEncodedAudioStreams();
939
+ pc_log(LOG_LEVEL_INFO, "setupReceiverTransform: receiverStream: ".concat(receiverStreams.readable, "/").concat(receiverStreams.readableStream));
940
+ var readableStream = receiverStreams.readable || receiverStreams.readableStream;
941
+ var writableStream = receiverStreams.writable || receiverStreams.writableStream;
942
+ worker.postMessage({
943
+ op: 'setupReceiver',
944
+ self: pc.self,
945
+ readableStream: readableStream,
946
+ writableStream: writableStream,
947
+ }, [readableStream, writableStream]);
948
+ }
525
949
  function createSdp(pc, callType, vstate, isOffer) {
526
950
  var rtc = pc.rtc;
951
+ pc_log(LOG_LEVEL_INFO, "createSdp: isOffer=".concat(isOffer, " rtc=").concat(rtc));
527
952
  if (!rtc) {
528
953
  return;
529
954
  }
@@ -531,12 +956,13 @@ function createSdp(pc, callType, vstate, isOffer) {
531
956
  pc.vstate = vstate;
532
957
  var use_video = vstate === PC_VIDEO_STATE_STARTED;
533
958
  var use_ss = vstate === PC_VIDEO_STATE_SCREENSHARE;
534
- pc_log(LOG_LEVEL_DEBUG, "createSdp: calling umh(1, " + use_video + ", " + use_ss + ")");
959
+ pc_log(LOG_LEVEL_INFO, "createSdp: calling umh(1, ".concat(use_video, ", ").concat(use_ss, ")"));
535
960
  pc.sending_video = use_video || use_ss;
536
961
  if (userMediaHandler) {
537
962
  userMediaHandler(pc.convid, true, use_video, use_ss)
538
963
  .then(function (stream) {
539
- update_tracks(pc, stream);
964
+ return update_tracks(pc, stream).then(function () { return stream; });
965
+ }).then(function (stream) {
540
966
  var doSdp = isOffer
541
967
  ? rtc.createOffer
542
968
  : rtc.createAnswer;
@@ -547,15 +973,17 @@ function createSdp(pc, callType, vstate, isOffer) {
547
973
  .then(function (sdp) {
548
974
  var typeStr = sdp.type;
549
975
  var sdpStr = sdp.sdp || '';
550
- pc_log(LOG_LEVEL_DEBUG, "createSdp: type=" + typeStr + " sdp=" + sdpStr);
976
+ pc_log(LOG_LEVEL_INFO, "createSdp: type=".concat(typeStr, " sdp=").concat(sdpStr));
551
977
  var modSdp = sdpMap(sdpStr, true, false);
552
978
  ccallLocalSdpHandler(pc, 0, typeStr, modSdp);
553
979
  })
554
980
  .catch(function (err) {
981
+ pc_log(LOG_LEVEL_WARN, 'createSdp: doSdp failed: ' + err, err);
555
982
  ccallLocalSdpHandler(pc, 1, "sdp-error", err.toString());
556
983
  });
557
984
  })
558
985
  .catch(function (err) {
986
+ pc_log(LOG_LEVEL_WARN, 'createSdp: userMedia failed: ' + err, err);
559
987
  ccallLocalSdpHandler(pc, 1, "media-error", err.toString());
560
988
  });
561
989
  }
@@ -565,19 +993,115 @@ function pc_CreateOffer(hnd, callType, vstate) {
565
993
  if (pc == null) {
566
994
  return;
567
995
  }
568
- pc_log(LOG_LEVEL_INFO, "pc_CreateOffer: hnd=" + hnd + " self=" + pc.self.toString(16) + " call_type=" + callType);
996
+ pc_log(LOG_LEVEL_INFO, "pc_CreateOffer: hnd=".concat(hnd, " self=").concat(pc.self.toString(16), " call_type=").concat(callType));
569
997
  createSdp(pc, callType, vstate, true);
570
998
  }
571
999
  function pc_CreateAnswer(hnd, callType, vstate) {
572
- pc_log(LOG_LEVEL_INFO, "pc_CreateAnswer: " + hnd + " callType=" + callType);
1000
+ pc_log(LOG_LEVEL_INFO, "pc_CreateAnswer: ".concat(hnd, " callType=").concat(callType));
573
1001
  var pc = connectionsStore.getPeerConnection(hnd);
1002
+ pc_log(LOG_LEVEL_INFO, 'pc_CreateAnswer: pc=' + pc);
574
1003
  if (pc == null) {
575
1004
  return;
576
1005
  }
577
1006
  createSdp(pc, callType, vstate, false);
578
1007
  }
1008
+ function pc_AddDecoderAnswer(hnd) {
1009
+ pc_log(LOG_LEVEL_INFO, "pc_AddDecoderAnswer: ".concat(hnd));
1010
+ var pc = connectionsStore.getPeerConnection(hnd);
1011
+ pc_log(LOG_LEVEL_INFO, 'pc_AddDecoderAnswer: pc=' + pc);
1012
+ if (pc == null) {
1013
+ return;
1014
+ }
1015
+ var rtc = pc.rtc;
1016
+ if (!rtc)
1017
+ return;
1018
+ rtc.createAnswer().then(function (sdp) {
1019
+ var typeStr = sdp.type;
1020
+ var sdpStr = sdp.sdp || '';
1021
+ //pc_log(LOG_LEVEL_INFO, `createSdp: type=${typeStr} sdp=${sdpStr}`);
1022
+ ccallLocalSdpHandler(pc, 0, typeStr, sdpStr);
1023
+ })
1024
+ .catch(function (err) {
1025
+ pc_log(LOG_LEVEL_WARN, 'addDecoderAnswer: createAnswer failed: ' + err, err);
1026
+ ccallLocalSdpHandler(pc, 1, "sdp-error", err.toString());
1027
+ });
1028
+ }
1029
+ /**
1030
+ * This methode is called by the jsflow
1031
+ *
1032
+ * @see: jsflow.c::jsflow_add_decoders_for_user
1033
+ */
1034
+ function pc_AddUserInfo(hnd, labelPtr, useridPtr, clientidPtr, ssrcaPtr, ssrcvPtr, audioIvPtr, videoIvPtr, ivlen) {
1035
+ pc_log(LOG_LEVEL_INFO, "pc_AddUserInfo2: hnd=".concat(hnd));
1036
+ var pc = connectionsStore.getPeerConnection(hnd);
1037
+ if (pc == null) {
1038
+ return;
1039
+ }
1040
+ var label = em_module.UTF8ToString(labelPtr);
1041
+ var userId = em_module.UTF8ToString(useridPtr);
1042
+ var clientId = em_module.UTF8ToString(clientidPtr);
1043
+ var ssrca = em_module.UTF8ToString(ssrcaPtr);
1044
+ var ssrcv = em_module.UTF8ToString(ssrcvPtr);
1045
+ var iva = new ArrayBuffer(ivlen);
1046
+ var aptr = new Uint8Array(em_module.HEAPU8.buffer, audioIvPtr, ivlen);
1047
+ var iva8 = new Uint8Array(iva);
1048
+ iva8.set(aptr);
1049
+ var ivv = new ArrayBuffer(ivlen);
1050
+ var vptr = new Uint8Array(em_module.HEAPU8.buffer, videoIvPtr, ivlen);
1051
+ var ivv8 = new Uint8Array(ivv);
1052
+ ivv8.set(vptr);
1053
+ var uinfo = {
1054
+ label: label,
1055
+ video_track_id: "0",
1056
+ userid: userId,
1057
+ clientid: clientId,
1058
+ ssrca: ssrca,
1059
+ ssrcv: ssrcv,
1060
+ iva: iva8,
1061
+ ivv: ivv8,
1062
+ frame_width: 0,
1063
+ frame_height: 0,
1064
+ audio_level: 0,
1065
+ first_recv_audio: false,
1066
+ first_succ_audio: false,
1067
+ first_succ_video: false,
1068
+ transp_ssrcv: null,
1069
+ };
1070
+ pc_log(LOG_LEVEL_INFO, "pc_AddUserInfo: label=".concat(label, " ").concat(userId.substring(0, 8), "/").concat(clientId.substring(0, 4), " ssrc:").concat(ssrca, "/").concat(ssrcv));
1071
+ pc.users[label] = uinfo;
1072
+ worker.postMessage({
1073
+ op: 'addUser',
1074
+ self: pc.self,
1075
+ userInfo: uinfo
1076
+ });
1077
+ }
1078
+ function pc_RemoveUserInfo(hnd, labelPtr) {
1079
+ var label = em_module.UTF8ToString(labelPtr);
1080
+ pc_log(LOG_LEVEL_INFO, "pc_RemoveUserInfo: hnd=".concat(hnd, " label=").concat(label));
1081
+ var pc = connectionsStore.getPeerConnection(hnd);
1082
+ if (pc == null) {
1083
+ return;
1084
+ }
1085
+ if (pc.users.hasOwnProperty(label)) {
1086
+ if (audioStreamHandler) {
1087
+ pc_log(LOG_LEVEL_INFO, "pcRemoveUserInfo: calling ash(".concat(pc.convid.substring(0, 8), ", ").concat(label, ") with 0 streams"));
1088
+ audioStreamHandler(pc.convid, hnd.toString() + label, null);
1089
+ }
1090
+ delete pc.users[label];
1091
+ }
1092
+ }
1093
+ function extractSSRCs(pc, sdp) {
1094
+ sdp.split('\r\n').forEach(function (l) {
1095
+ var m = l.match(/a=ssrc:(\d+) msid:(.*) (.*)/);
1096
+ if (m) {
1097
+ var ssrc = m[1];
1098
+ var label = m[3];
1099
+ pc.streams[ssrc] = label;
1100
+ }
1101
+ });
1102
+ }
579
1103
  function pc_SetRemoteDescription(hnd, typePtr, sdpPtr) {
580
- pc_log(LOG_LEVEL_INFO, "pc_SetRemoteDescription: hnd=" + hnd);
1104
+ pc_log(LOG_LEVEL_INFO, "pc_SetRemoteDescription: hnd=".concat(hnd));
581
1105
  var pc = connectionsStore.getPeerConnection(hnd);
582
1106
  if (pc == null) {
583
1107
  return;
@@ -593,15 +1117,22 @@ function pc_SetRemoteDescription(hnd, typePtr, sdpPtr) {
593
1117
  sdpStr = sdp.replace(/ DTLS\/SCTP (5000|webrtc-datachannel)/, ' UDP/DTLS/SCTP webrtc-datachannel');
594
1118
  sdpStr = sdpMap(sdpStr, false, false);
595
1119
  }
1120
+ /* Ensure that we force CBR on the offer */
1121
+ if (pc.conv_type == CONV_TYPE_CONFERENCE) {
1122
+ sdpStr = sdpCbrMap(sdpStr);
1123
+ }
1124
+ pc_log(LOG_LEVEL_INFO, "pc_SetRemoteDescription: hnd=".concat(hnd, " SDP=").concat(sdpStr));
596
1125
  rtc
597
1126
  .setRemoteDescription({ type: type, sdp: sdpStr })
598
1127
  .then(function () { })
599
1128
  .catch(function (err) {
600
- pc_log(LOG_LEVEL_WARN, "setRemoteDescription failed: " + err);
1129
+ pc_log(LOG_LEVEL_WARN, "setRemoteDescription failed: " + err, err);
601
1130
  });
1131
+ if (pc_env != ENV_FIREFOX)
1132
+ extractSSRCs(pc, sdp);
602
1133
  }
603
1134
  function pc_SetLocalDescription(hnd, typePtr, sdpPtr) {
604
- pc_log(LOG_LEVEL_INFO, "pc_SetLocalDescription: hnd=" + hnd);
1135
+ pc_log(LOG_LEVEL_INFO, "pc_SetLocalDescription: hnd=".concat(hnd));
605
1136
  var pc = connectionsStore.getPeerConnection(hnd);
606
1137
  if (pc == null) {
607
1138
  return;
@@ -617,59 +1148,74 @@ function pc_SetLocalDescription(hnd, typePtr, sdpPtr) {
617
1148
  sdpStr = sdpMap(sdp, true, false);
618
1149
  else
619
1150
  sdpStr = sdp;
620
- pc_log(LOG_LEVEL_DEBUG, "pc_SetLocalDesription: type=" + type + " sdp=" + sdpStr);
1151
+ //pc_log(LOG_LEVEL_INFO, `pc_SetLocalDesription: type=${type} sdp=${sdpStr}`);
621
1152
  rtc
622
1153
  .setLocalDescription({ type: type, sdp: sdpStr })
623
- .then(function () { })
1154
+ .then(function () {
1155
+ if (rtc && pc.conv_type === CONV_TYPE_CONFERENCE) {
1156
+ for (var _i = 0, _a = rtc.getSenders(); _i < _a.length; _i++) {
1157
+ var sender = _a[_i];
1158
+ setupSenderTransform(pc, sender);
1159
+ }
1160
+ }
1161
+ })
624
1162
  .catch(function (err) {
625
- pc_log(LOG_LEVEL_INFO, "setLocalDescription failed: " + err);
1163
+ pc_log(LOG_LEVEL_INFO, "setLocalDescription failed: " + err, err);
626
1164
  });
627
1165
  }
628
1166
  function pc_LocalDescription(hnd, typePtr) {
629
- pc_log(LOG_LEVEL_INFO, "pc_LocalDescription: hnd=" + hnd);
1167
+ pc_log(LOG_LEVEL_INFO, "pc_LocalDescription: hnd=".concat(hnd));
630
1168
  var pc = connectionsStore.getPeerConnection(hnd);
631
1169
  if (pc == null) {
632
- return;
1170
+ return 0;
633
1171
  }
634
1172
  var rtc = pc.rtc;
635
1173
  if (!rtc) {
636
- return;
1174
+ return 0;
637
1175
  }
638
1176
  var sdpDesc = rtc.localDescription;
639
1177
  if (!sdpDesc) {
640
- return;
1178
+ return 0;
641
1179
  }
642
1180
  if (typePtr != null) {
643
1181
  var type = em_module.UTF8ToString(typePtr);
644
1182
  if (type != sdpDesc.type) {
645
1183
  pc_log(LOG_LEVEL_WARN, "pc_LocalDescriptiont: wrong type");
646
- return null;
1184
+ return 0;
647
1185
  }
648
1186
  }
649
1187
  var sdp = sdpDesc.sdp.toString();
650
1188
  var sdpStr = sdp;
651
- pc_log(LOG_LEVEL_INFO, "pc_LocalDescription: env=" + pc_env);
1189
+ pc_log(LOG_LEVEL_INFO, "pc_LocalDescription: env=".concat(pc_env));
652
1190
  if (pc_env === ENV_FIREFOX) {
653
1191
  sdpStr = sdp.replace(' UDP/DTLS/SCTP', ' DTLS/SCTP');
654
1192
  sdpStr = sdpMap(sdpStr, true, false);
655
1193
  }
1194
+ /* Ensure that we force CBR on the offer */
1195
+ if (pc_env === ENV_FIREFOX && pc.conv_type == CONV_TYPE_CONFERENCE) {
1196
+ sdpStr = sdpRidReOrder(sdpStr);
1197
+ }
1198
+ pc_log(LOG_LEVEL_INFO, "pc_LocalDescription: hnd=".concat(sdpStr));
656
1199
  var sdpLen = em_module.lengthBytesUTF8(sdpStr) + 1; // +1 for '\0'
657
1200
  var ptr = em_module._malloc(sdpLen);
658
1201
  em_module.stringToUTF8(sdpStr, ptr, sdpLen);
659
1202
  return ptr;
660
1203
  }
1204
+ function pc_HeapFree(ptr) {
1205
+ em_module._free(ptr);
1206
+ }
661
1207
  function pc_IceGatheringState(hnd) {
662
- pc_log(LOG_LEVEL_INFO, "pc_IceGatheringState: hnd=" + hnd);
1208
+ pc_log(LOG_LEVEL_INFO, "pc_IceGatheringState: hnd=".concat(hnd));
1209
+ var state = PC_GATHER_STATE_UNKNOWN;
663
1210
  var pc = connectionsStore.getPeerConnection(hnd);
664
1211
  if (!pc) {
665
- return 0;
1212
+ return state;
666
1213
  }
667
1214
  var rtc = pc.rtc;
668
1215
  if (!rtc) {
669
- return;
1216
+ return state;
670
1217
  }
671
1218
  var stateStr = rtc.iceGatheringState;
672
- var state = PC_GATHER_STATE_UNKNOWN;
673
1219
  switch (stateStr) {
674
1220
  case "new":
675
1221
  state = PC_GATHER_STATE_NEW;
@@ -684,22 +1230,23 @@ function pc_IceGatheringState(hnd) {
684
1230
  return state;
685
1231
  }
686
1232
  function pc_SignalingState(hnd) {
687
- pc_log(LOG_LEVEL_INFO, "pc_SignalingState: hnd=" + hnd);
1233
+ pc_log(LOG_LEVEL_INFO, "pc_SignalingState: hnd=".concat(hnd));
1234
+ var state = PC_SIG_STATE_UNKNOWN;
688
1235
  var pc = connectionsStore.getPeerConnection(hnd);
689
1236
  if (!pc) {
690
- return 0;
1237
+ return state;
691
1238
  }
692
1239
  var rtc = pc.rtc;
693
1240
  if (!rtc) {
694
- return;
1241
+ return state;
695
1242
  }
696
1243
  var stateStr = rtc.signalingState;
697
- var state = sigState(stateStr);
698
- pc_log(LOG_LEVEL_INFO, "pc_SignalingState: hnd=" + hnd + " " + stateStr + " mapped: " + state);
1244
+ state = sigState(stateStr);
1245
+ pc_log(LOG_LEVEL_INFO, "pc_SignalingState: hnd=".concat(hnd, " ") + stateStr + " mapped: " + state);
699
1246
  return state;
700
1247
  }
701
1248
  function pc_ConnectionState(hnd) {
702
- pc_log(LOG_LEVEL_INFO, "pc_ConnectionState: hnd=" + hnd);
1249
+ pc_log(LOG_LEVEL_INFO, "pc_ConnectionState: hnd=".concat(hnd));
703
1250
  var pc = connectionsStore.getPeerConnection(hnd);
704
1251
  if (!pc) {
705
1252
  return 0;
@@ -709,7 +1256,7 @@ function pc_ConnectionState(hnd) {
709
1256
  */
710
1257
  var rtc = pc.rtc;
711
1258
  if (!rtc) {
712
- return;
1259
+ return 0;
713
1260
  }
714
1261
  var state = rtc.connectionState;
715
1262
  return state;
@@ -725,7 +1272,7 @@ function pc_SetMute(hnd, muted) {
725
1272
  function pc_GetMute(hnd) {
726
1273
  var pc = connectionsStore.getPeerConnection(hnd);
727
1274
  if (pc == null) {
728
- return;
1275
+ return 0;
729
1276
  }
730
1277
  return pc.muted;
731
1278
  }
@@ -739,14 +1286,14 @@ function pc_SetRemoteUserClientId(hnd, useridPtr, clientidPtr) {
739
1286
  }
740
1287
  /* Data Channel related */
741
1288
  function pc_CreateDataChannel(hnd, labelPtr) {
742
- pc_log(LOG_LEVEL_INFO, "pc_CreateDataChannel: hnd=" + hnd);
1289
+ pc_log(LOG_LEVEL_INFO, "pc_CreateDataChannel: hnd=".concat(hnd));
743
1290
  var pc = connectionsStore.getPeerConnection(hnd);
744
1291
  if (pc == null) {
745
- return;
1292
+ return 0;
746
1293
  }
747
1294
  var rtc = pc.rtc;
748
1295
  if (!rtc) {
749
- return;
1296
+ return 0;
750
1297
  }
751
1298
  var label = em_module.UTF8ToString(labelPtr);
752
1299
  var dc = rtc.createDataChannel(label);
@@ -757,7 +1304,7 @@ function pc_CreateDataChannel(hnd, labelPtr) {
757
1304
  return dcHnd;
758
1305
  }
759
1306
  function pc_DataChannelId(hnd) {
760
- pc_log(LOG_LEVEL_INFO, "pc_DataChannelId: hnd=" + hnd);
1307
+ pc_log(LOG_LEVEL_INFO, "pc_DataChannelId: hnd=".concat(hnd));
761
1308
  var dc = connectionsStore.getDataChannel(hnd);
762
1309
  if (dc == null) {
763
1310
  return -1;
@@ -765,13 +1312,13 @@ function pc_DataChannelId(hnd) {
765
1312
  return dc.id;
766
1313
  }
767
1314
  function pc_DataChannelState(hnd) {
768
- pc_log(LOG_LEVEL_INFO, "pc_DataChannelState: hnd=" + hnd);
1315
+ pc_log(LOG_LEVEL_INFO, "pc_DataChannelState: hnd=".concat(hnd));
1316
+ var state = DC_STATE_ERROR;
769
1317
  var dc = connectionsStore.getDataChannel(hnd);
770
1318
  if (dc == null) {
771
- return;
1319
+ return state;
772
1320
  }
773
1321
  var str = dc.readyState;
774
- var state = DC_STATE_ERROR;
775
1322
  if (str == "connecting") {
776
1323
  state = DC_STATE_CONNECTING;
777
1324
  }
@@ -787,13 +1334,13 @@ function pc_DataChannelState(hnd) {
787
1334
  return state;
788
1335
  }
789
1336
  function pc_DataChannelSend(hnd, dataPtr, dataLen) {
790
- pc_log(LOG_LEVEL_INFO, "pc_DataChannelSend: hnd=" + hnd);
1337
+ pc_log(LOG_LEVEL_INFO, "pc_DataChannelSend: hnd=".concat(hnd));
791
1338
  var dc = connectionsStore.getDataChannel(hnd);
792
1339
  if (dc == null) {
793
1340
  return;
794
1341
  }
795
1342
  if (dc.readyState !== 'open') {
796
- pc_log(LOG_LEVEL_WARN, "pc_DataChannelSend: hnd=" + hnd + " not open");
1343
+ pc_log(LOG_LEVEL_WARN, "pc_DataChannelSend: hnd=".concat(hnd, " not open"));
797
1344
  return;
798
1345
  }
799
1346
  //const data = new Uint8Array(em_module.HEAPU8.buffer, dataPtr, dataLen);
@@ -801,7 +1348,7 @@ function pc_DataChannelSend(hnd, dataPtr, dataLen) {
801
1348
  dc.send(data);
802
1349
  }
803
1350
  function pc_DataChannelClose(hnd) {
804
- pc_log(LOG_LEVEL_INFO, "pc_DataChannelClose: hnd=" + hnd);
1351
+ pc_log(LOG_LEVEL_INFO, "pc_DataChannelClose: hnd=".concat(hnd));
805
1352
  var dc = connectionsStore.getDataChannel(hnd);
806
1353
  if (dc == null) {
807
1354
  return;
@@ -810,33 +1357,44 @@ function pc_DataChannelClose(hnd) {
810
1357
  }
811
1358
  /* Internal functions, used by avs_wcall directly */
812
1359
  function pc_InitModule(module, logh) {
1360
+ createWorker();
813
1361
  em_module = module;
814
1362
  logFn = logh;
815
- pc_log(LOG_LEVEL_INFO, "pc_InitModule");
1363
+ var pt = RTCRtpSender.prototype;
1364
+ insertableStreams = !!pt.createEncodedStreams || "transform" in pt;
1365
+ insertableLegacy = !!pt.createEncodedVideoStreams;
1366
+ pc_log(LOG_LEVEL_INFO, "insertable: ".concat(insertableLegacy, "/").concat(insertableStreams));
816
1367
  var callbacks = [
817
- [pc_SetEnv, "vn"],
818
- [pc_New, "nns"],
819
- [pc_Create, "vn"],
820
- [pc_Close, "vn"],
821
- [pc_AddTurnServer, "vnsss"],
822
- [pc_IceGatheringState, "nn"],
823
- [pc_SignalingState, "n"],
824
- [pc_ConnectionState, "n"],
825
- [pc_CreateDataChannel, "ns"],
826
- [pc_CreateOffer, "nn"],
827
- [pc_CreateAnswer, "nn"],
828
- [pc_SetRemoteDescription, "nss"],
829
- [pc_SetLocalDescription, "nss"],
830
- [pc_LocalDescription, "sns"],
831
- [pc_SetMute, "vnn"],
832
- [pc_GetMute, "nn"],
833
- [pc_SetRemoteUserClientId, "vnss"],
834
- [pc_HasVideo, "nn"],
835
- [pc_SetVideoState, "vnn"],
836
- [pc_DataChannelId, "nn"],
837
- [pc_DataChannelState, "nn"],
838
- [pc_DataChannelSend, "vnsn"],
839
- [pc_DataChannelClose, "vn"]
1368
+ [pc_SetEnv, "vi"],
1369
+ [pc_New, "iiiiii"],
1370
+ [pc_Create, "viii"],
1371
+ [pc_Close, "vi"],
1372
+ [pc_HeapFree, "vi"],
1373
+ [pc_AddTurnServer, "viiii"],
1374
+ [pc_IceGatheringState, "ii"],
1375
+ [pc_SignalingState, "ii"],
1376
+ [pc_ConnectionState, "ii"],
1377
+ [pc_CreateDataChannel, "iii"],
1378
+ [pc_CreateOffer, "viii"],
1379
+ [pc_CreateAnswer, "viii"],
1380
+ [pc_AddDecoderAnswer, "vi"],
1381
+ [pc_AddUserInfo, "viiiiiiiii"],
1382
+ [pc_RemoveUserInfo, "vii"],
1383
+ [pc_SetRemoteDescription, "viii"],
1384
+ [pc_SetLocalDescription, "viii"],
1385
+ [pc_LocalDescription, "iii"],
1386
+ [pc_SetMute, "vii"],
1387
+ [pc_GetMute, "ii"],
1388
+ [pc_GetLocalStats, "vi"],
1389
+ [pc_SetRemoteUserClientId, "viii"],
1390
+ [pc_HasVideo, "ii"],
1391
+ [pc_SetVideoState, "vii"],
1392
+ [pc_DataChannelId, "ii"],
1393
+ [pc_DataChannelState, "ii"],
1394
+ [pc_DataChannelSend, "viii"],
1395
+ [pc_DataChannelClose, "vi"],
1396
+ [pc_SetMediaKey, "viiiii"],
1397
+ [pc_UpdateSsrc, "viii"],
840
1398
  ].map(function (_a) {
841
1399
  var callback = _a[0], signature = _a[1];
842
1400
  return em_module.addFunction(callback, signature);
@@ -846,8 +1404,14 @@ function pc_InitModule(module, logh) {
846
1404
  function pc_SetUserMediaHandler(umh) {
847
1405
  userMediaHandler = umh;
848
1406
  }
849
- function pc_SetMediaStreamHandler(msh) {
850
- mediaStreamHandler = msh;
1407
+ function pc_IsConferenceCallingSupported() {
1408
+ return insertableStreams || insertableLegacy;
1409
+ }
1410
+ function pc_SetAudioStreamHandler(ash) {
1411
+ audioStreamHandler = ash;
1412
+ }
1413
+ function pc_SetVideoStreamHandler(vsh) {
1414
+ videoStreamHandler = vsh;
851
1415
  }
852
1416
  function pc_ReplaceTrack(convid, newTrack) {
853
1417
  var pcs = connectionsStore.getPeerConnectionByConvid(convid);
@@ -864,21 +1428,127 @@ function pc_ReplaceTrack(convid, newTrack) {
864
1428
  function pc_GetStats(convid) {
865
1429
  var pcs = connectionsStore.getPeerConnectionByConvid(convid);
866
1430
  var statsPromises = [];
867
- var _loop_1 = function (pc) {
1431
+ var _loop_3 = function (pc) {
868
1432
  var rtc = pc.rtc;
869
1433
  if (rtc)
870
1434
  statsPromises.push(rtc.getStats().then(function (stats) { return ({ userid: pc.remote_userid, stats: stats }); }));
871
1435
  };
872
1436
  for (var _i = 0, pcs_2 = pcs; _i < pcs_2.length; _i++) {
873
1437
  var pc = pcs_2[_i];
874
- _loop_1(pc);
1438
+ _loop_3(pc);
875
1439
  }
876
1440
  return Promise.all(statsPromises);
877
1441
  }
1442
+ function pc_GetLocalStats(hnd) {
1443
+ pc_log(LOG_LEVEL_INFO, "pc_GetLocalStats: hnd=".concat(hnd));
1444
+ var pc = connectionsStore.getPeerConnection(hnd);
1445
+ if (pc == null) {
1446
+ return;
1447
+ }
1448
+ var rtc = pc.rtc;
1449
+ if (!rtc) {
1450
+ return;
1451
+ }
1452
+ var txrxs = rtc.getTransceivers();
1453
+ txrxs.forEach(function (txrx) {
1454
+ var rx = txrx.receiver;
1455
+ if (rx) {
1456
+ var ssrcs = rx.getSynchronizationSources();
1457
+ ssrcs.forEach(function (ssrc) {
1458
+ var ssrca = "";
1459
+ var aulevel = 0;
1460
+ if (typeof ssrc.audioLevel !== 'undefined')
1461
+ aulevel = ((ssrc.audioLevel * 512.0) | 0);
1462
+ if (pc.conv_type != CONV_TYPE_ONEONONE) {
1463
+ var uinfo = uinfo_from_ssrca(pc, ssrc.source.toString());
1464
+ if (uinfo) {
1465
+ uinfo.audio_level = aulevel;
1466
+ ssrca = uinfo.ssrca;
1467
+ }
1468
+ }
1469
+ em_module.ccall("pc_set_audio_level", null, ["number", "number", "number"], [pc.self, ssrca, aulevel]);
1470
+ });
1471
+ var csrcs = rx.getContributingSources();
1472
+ csrcs.forEach(function (csrc) {
1473
+ var uinfo = uinfo_from_ssrca(pc, csrc.source.toString());
1474
+ if (uinfo) {
1475
+ uinfo.audio_level = 0;
1476
+ if (typeof csrc.audioLevel !== 'undefined')
1477
+ uinfo.audio_level = ((csrc.audioLevel * 512.0) | 0);
1478
+ em_module.ccall("pc_set_audio_level", null, ["number", "number", "number"], [pc.self, uinfo.ssrca, uinfo.audio_level]);
1479
+ }
1480
+ });
1481
+ }
1482
+ });
1483
+ var self_audio_level = 0;
1484
+ var apkts = 0;
1485
+ var vpkts = 0;
1486
+ var ploss = 0;
1487
+ rtc.getStats()
1488
+ .then(function (stats) {
1489
+ var rtt = 0;
1490
+ stats.forEach(function (stat) {
1491
+ if (stat.type === 'inbound-rtp') {
1492
+ ploss = ploss + stat.packetsLost;
1493
+ var p = stat.packetsReceived;
1494
+ if (stat.kind === 'audio') {
1495
+ apkts = apkts + p;
1496
+ }
1497
+ else if (stat.kind === 'video') {
1498
+ var user_info = null;
1499
+ if (!!stat.trackIdentifier) {
1500
+ user_info = uinfo_from_video_track_id(pc, stat.trackIdentifier);
1501
+ }
1502
+ if (user_info !== null) {
1503
+ var frame_height = !!stat.frameHeight ? stat === null || stat === void 0 ? void 0 : stat.frameHeight : 0;
1504
+ var frame_width = !!stat.frameWidth ? stat === null || stat === void 0 ? void 0 : stat.frameWidth : 0;
1505
+ if (user_info.frame_width !== frame_width || user_info.frame_height !== frame_height) {
1506
+ user_info.frame_width = frame_width;
1507
+ user_info.frame_height = frame_height;
1508
+ pc_log(LOG_LEVEL_INFO, "pc_user_resolution: label=".concat(user_info.label, " ").concat(user_info.userid.substring(0, 8), "/").concat(user_info.clientid.substring(0, 4), " resolution:").concat(user_info.frame_width, "x").concat(user_info.frame_height));
1509
+ }
1510
+ }
1511
+ vpkts = vpkts + p;
1512
+ }
1513
+ }
1514
+ else if (stat.type === 'outbound-rtp') {
1515
+ var p = stat.packetsSent;
1516
+ if (stat.kind === 'audio') {
1517
+ pc.stats.sent_apkts = p;
1518
+ }
1519
+ else if (stat.kind === 'video') {
1520
+ pc.stats.sent_vpkts = p;
1521
+ }
1522
+ }
1523
+ else if (stat.type === 'candidate-pair') {
1524
+ rtt = stat.currentRoundTripTime * 1000;
1525
+ }
1526
+ else if (stat.type === 'media-source') {
1527
+ if (stat.kind === 'audio')
1528
+ self_audio_level = stat.audioLevel ? ((stat.audioLevel * 512.0) | 0) : 0;
1529
+ }
1530
+ });
1531
+ pc.stats.recv_apkts = apkts;
1532
+ pc.stats.recv_vpkts = vpkts;
1533
+ pc.stats.ploss = ploss - pc.stats.lastploss;
1534
+ pc.stats.lastploss = ploss;
1535
+ em_module.ccall("pc_set_stats", null, ["number", "number", "number", "number", "number", "number", "number", "number"], [
1536
+ pc.self, self_audio_level,
1537
+ pc.stats.recv_apkts,
1538
+ pc.stats.recv_vpkts,
1539
+ pc.stats.sent_apkts,
1540
+ pc.stats.sent_vpkts,
1541
+ pc.stats.ploss,
1542
+ rtt
1543
+ ]);
1544
+ }).catch(function (err) { return pc_log(LOG_LEVEL_INFO, "pc_GetLocalStats: failed hnd=".concat(hnd, " err=").concat(err), err); });
1545
+ }
878
1546
  exports.default = {
879
1547
  init: pc_InitModule,
880
1548
  setUserMediaHandler: pc_SetUserMediaHandler,
881
- setMediaStreamHandler: pc_SetMediaStreamHandler,
1549
+ setAudioStreamHandler: pc_SetAudioStreamHandler,
1550
+ setVideoStreamHandler: pc_SetVideoStreamHandler,
1551
+ isConferenceCallingSupported: pc_IsConferenceCallingSupported,
882
1552
  replaceTrack: pc_ReplaceTrack,
883
1553
  getStats: pc_GetStats
884
1554
  };