Rtcp.js 7.4 KB

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