Rtcp.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. const log$l = new Logger("rtcp");
  2. class Rtcp extends EventEmitter {
  3. constructor(e) {
  4. super();
  5. E(this, "connection", null);
  6. E(this, "inputChannel", null);
  7. E(this, "mediaStream");
  8. E(this, "socket");
  9. E(this, "connected", !1);
  10. E(this, "candidates", []);
  11. E(this, "isAnswered", !1);
  12. E(this, "isFlushing", !1);
  13. E(this, "inputReady", !1);
  14. E(this, "workers");
  15. E(this, "actived", !0);
  16. E(this, "heartbeat");
  17. E(this, "onIcecandidate", e=>{
  18. if (e.candidate != null) {
  19. const t = JSON.stringify(e.candidate);
  20. log$l.debug(`Got ice candidate: ${t}`),
  21. this.network.socket.send({
  22. id: "ice_candidate",
  23. data: btoa(t)
  24. })
  25. }
  26. }
  27. );
  28. E(this, "onIcecandidateerror", e=>{
  29. log$l.error("onicecandidateerror", e.errorCode, e.errorText, e)
  30. }
  31. );
  32. E(this, "onIceStateChange", e=>{
  33. switch (e.target.iceGatheringState) {
  34. case "gathering":
  35. log$l.info("ice gathering");
  36. break;
  37. case "complete":
  38. log$l.info("Ice gathering completed")
  39. }
  40. }
  41. );
  42. E(this, "onIceConnectionStateChange", ()=>{
  43. if (!!this.connection)
  44. switch (log$l.info(`iceConnectionState: ${this.connection.iceConnectionState}`),
  45. this.connection.iceConnectionState) {
  46. case "connected":
  47. {
  48. this.connected = !0;
  49. break
  50. }
  51. case "disconnected":
  52. {
  53. this.connected = !1,
  54. this.emit("rtcDisconnected");
  55. break
  56. }
  57. case "failed":
  58. {
  59. this.emit("rtcDisconnected"),
  60. this.connected = !1;
  61. break
  62. }
  63. }
  64. }
  65. );
  66. E(this, "setRemoteDescription", async(e,t)=>{
  67. var a, s, l;
  68. if (!this.connection)
  69. return;
  70. const r = JSON.parse(atob(e))
  71. , n = new RTCSessionDescription(r);
  72. await this.connection.setRemoteDescription(n);
  73. const o = await this.connection.createAnswer();
  74. if (o.sdp = (a = o.sdp) == null ? void 0 : a.replace(/(a=fmtp:111 .*)/g, "$1;stereo=1;sprop-stereo=1"),
  75. ((l = (s = o.sdp) == null ? void 0 : s.match(/a=mid:1/g)) == null ? void 0 : l.length) == 2) {
  76. const u = o.sdp.lastIndexOf("a=mid:1");
  77. o.sdp = o.sdp.slice(0, u) + "a=mid:2" + o.sdp.slice(u + 7)
  78. }
  79. try {
  80. await this.connection.setLocalDescription(o)
  81. } catch (u) {
  82. log$l.error("error", u)
  83. }
  84. this.isAnswered = !0,
  85. this.network.rtcp.flushCandidate(),
  86. this.network.socket.send({
  87. id: "answer",
  88. data: btoa(JSON.stringify(o))
  89. }),
  90. t.srcObject = this.mediaStream
  91. }
  92. );
  93. E(this, "flushCandidate", ()=>{
  94. this.isFlushing || !this.isAnswered || (this.isFlushing = !0,
  95. this.candidates.forEach(e=>{
  96. const t = atob(e)
  97. , r = JSON.parse(t);
  98. if (/172\./.test(r.candidate))
  99. return;
  100. const n = new RTCIceCandidate(r);
  101. this.connection && this.connection.addIceCandidate(n).then(()=>{}
  102. , o=>{
  103. log$l.info("add candidate failed", o)
  104. }
  105. )
  106. }
  107. ),
  108. this.isFlushing = !1)
  109. }
  110. );
  111. E(this, "input", e=>{
  112. var t;
  113. !this.actived || !this.inputChannel || this.inputChannel.readyState === "open" && ((t = this.inputChannel) == null || t.send(e))
  114. }
  115. );
  116. this.network = e,
  117. this.workers = new Workers(this,new Logger("decode")),
  118. this.workers.registerLogger(new Logger("decode")),
  119. this.workers.registerFunction("data", t=>{
  120. this.emit("data", t)
  121. }
  122. ),
  123. this.heartbeat = new Heartbeat({
  124. ping: t=>{
  125. e.room.actionsHandler.echo(t)
  126. }
  127. ,
  128. pong(t, r) {
  129. var n;
  130. r && t > 500 && log$l.warn(`high hb value ${t}, traceId:` + r),
  131. (n = e.room.stats) == null || n.assign({
  132. hb: t
  133. })
  134. }
  135. })
  136. }
  137. start() {
  138. this.connection = new RTCPeerConnection;
  139. const e = Date.now();
  140. this.connection.ondatachannel = t=>{
  141. log$l.info(`ondatachannel: ${t.channel.label}`),
  142. this.inputChannel = t.channel,
  143. this.inputChannel.onopen = ()=>{
  144. var r;
  145. log$l.info("The input channel has opened, id:", (r = this.inputChannel) == null ? void 0 : r.id),
  146. this.inputReady = !0,
  147. this.emit("rtcConnected"),
  148. this.network.room.currentNetworkOptions.reconnect || (log$l.infoAndReportMeasurement({
  149. metric: "datachannelOpenedAt",
  150. startTime: this.network.room._startTime,
  151. group: "joinRoom"
  152. }),
  153. log$l.infoAndReportMeasurement({
  154. metric: "datachannelOpenedCost",
  155. startTime: e,
  156. group: "joinRoom"
  157. }))
  158. }
  159. ,
  160. this.inputChannel.onclose = ()=>{
  161. var r;
  162. return log$l.info("The input channel has closed, id:", (r = this.inputChannel) == null ? void 0 : r.id)
  163. }
  164. ,
  165. this.inputChannel.onmessage = r=>{
  166. this.workers.dataHandle(r.data)
  167. }
  168. }
  169. ,
  170. this.connection.oniceconnectionstatechange = this.onIceConnectionStateChange,
  171. this.connection.onicegatheringstatechange = this.onIceStateChange,
  172. this.connection.onicecandidate = this.onIcecandidate,
  173. this.connection.onicecandidateerror = this.onIcecandidateerror,
  174. this.network.socket.send({
  175. id: "init_webrtc",
  176. data: JSON.stringify({
  177. is_mobile: !0
  178. })
  179. })
  180. }
  181. addCandidate(e) {
  182. e === "" ? this.network.rtcp.flushCandidate() : this.candidates.push(e)
  183. }
  184. disconnect() {
  185. var e, t, r;
  186. this.heartbeat.stop(),
  187. log$l.info("ready to close datachannel, id", (e = this.inputChannel) == null ? void 0 : e.id),
  188. (t = this.inputChannel) == null || t.close(),
  189. (r = this.connection) == null || r.close(),
  190. this.connection = null,
  191. this.inputChannel = null
  192. }
  193. sendStringData(e) {
  194. this.input(e)
  195. }
  196. sendData(e) {
  197. let t = "";
  198. try {
  199. t = JSON.stringify(e)
  200. } catch (r) {
  201. log$l.error(r);
  202. return
  203. }
  204. this.input(t)
  205. }
  206. }