webRtc.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. const JSWebrtc = {
  2. Player: null,
  3. CreateVideoElements: function() {
  4. var elements = document.querySelectorAll('.jswebrtc')
  5. for (var i = 0; i < elements.length; i++) {
  6. new JSWebrtc.VideoElement(elements[i])
  7. }
  8. },
  9. FillQuery: function(query_string, obj) {
  10. obj.user_query = {}
  11. if (query_string.length === 0) return
  12. if (query_string.indexOf('?') >= 0) query_string = query_string.split('?')[1]
  13. var queries = query_string.split('&')
  14. for (var i = 0; i < queries.length; i++) {
  15. var query = queries[i].split('=')
  16. obj[query[0]] = query[1]
  17. obj.user_query[query[0]] = query[1]
  18. }
  19. if (obj.domain) obj.vhost = obj.domain
  20. },
  21. ParseUrl: function(rtmp_url) {
  22. var a = document.createElement('a')
  23. a.href = rtmp_url
  24. .replace('rtmp://', 'http://')
  25. .replace('webrtc://', 'http://')
  26. .replace('rtc://', 'http://')
  27. var vhost = a.hostname
  28. var app = a.pathname.substr(1, a.pathname.lastIndexOf('/') - 1)
  29. var stream = a.pathname.substr(a.pathname.lastIndexOf('/') + 1)
  30. app = app.replace('...vhost...', '?vhost=')
  31. if (app.indexOf('?') >= 0) {
  32. var params = app.substr(app.indexOf('?'))
  33. app = app.substr(0, app.indexOf('?'))
  34. if (params.indexOf('vhost=') > 0) {
  35. vhost = params.substr(params.indexOf('vhost=') + 'vhost='.length)
  36. if (vhost.indexOf('&') > 0) {
  37. vhost = vhost.substr(0, vhost.indexOf('&'))
  38. }
  39. }
  40. }
  41. if (a.hostname === vhost) {
  42. var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
  43. if (re.test(a.hostname)) vhost = '__defaultVhost__'
  44. }
  45. var schema = 'rtmp'
  46. if (rtmp_url.indexOf('://') > 0) schema = rtmp_url.substr(0, rtmp_url.indexOf('://'))
  47. var port = a.port
  48. if (!port) {
  49. if (schema === 'http') {
  50. port = 80
  51. } else if (schema === 'https') {
  52. port = 443
  53. } else if (schema === 'rtmp') {
  54. port = 1935
  55. } else if (schema === 'webrtc' || schema === 'rtc') {
  56. port = 1985
  57. }
  58. }
  59. var ret = {
  60. url: rtmp_url,
  61. schema: schema,
  62. server: a.hostname,
  63. port: port,
  64. vhost: vhost,
  65. app: app,
  66. stream: stream
  67. }
  68. JSWebrtc.FillQuery(a.search, ret)
  69. return ret
  70. },
  71. HttpPost: function(url, data) {
  72. return new Promise(function(resolve, reject) {
  73. var xhr = new XMLHttpRequest()
  74. xhr.onreadystatechange = function() {
  75. if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status < 300) {
  76. var respone = JSON.parse(xhr.responseText)
  77. xhr.onreadystatechange = new Function()
  78. xhr = null
  79. resolve(respone)
  80. }
  81. }
  82. xhr.open('POST', url, true)
  83. xhr.timeout = 5e3
  84. xhr.responseType = 'text'
  85. xhr.setRequestHeader('Content-Type', 'application/json')
  86. xhr.send(data)
  87. })
  88. },
  89. httpGet: function(url) {
  90. return new Promise(function(resolve, reject) {
  91. var xhr = new XMLHttpRequest()
  92. xhr.onreadystatechange = function() {
  93. if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status < 300) {
  94. var respone = JSON.parse(xhr.responseText)
  95. xhr.onreadystatechange = new Function()
  96. xhr = null
  97. resolve(respone)
  98. }
  99. }
  100. xhr.open('GET', url, true)
  101. xhr.timeout = 1000
  102. xhr.setRequestHeader('Content-Type', 'application/json')
  103. xhr.send(null)
  104. })
  105. }
  106. }
  107. JSWebrtc.Player = (function() {
  108. 'use strict'
  109. class Player {
  110. constructor(url, options) {
  111. this.options = options || {}
  112. if (!url.match(/^webrtc?:\/\//)) {
  113. // eslint-disable-next-line no-throw-literal
  114. throw 'JSWebrtc just work with webrtc'
  115. }
  116. if (!this.options.video) {
  117. // eslint-disable-next-line no-throw-literal
  118. throw 'VideoElement is null'
  119. }
  120. this.urlParams = JSWebrtc.ParseUrl(url)
  121. this.pc = null
  122. this.autoplay = !!options.autoplay || false
  123. this.paused = true
  124. if (this.autoplay) this.options.video.muted = true
  125. this.startLoading()
  126. }
  127. startLoading() {
  128. var _self = this
  129. if (_self.pc) {
  130. _self.pc.close()
  131. }
  132. _self.pc = new RTCPeerConnection(null)
  133. _self.pc.ontrack = function(event) {
  134. _self.options.video['srcObject'] = event.streams[0]
  135. }
  136. _self.pc.addTransceiver('audio', {
  137. direction: 'recvonly'
  138. })
  139. _self.pc.addTransceiver('video', {
  140. direction: 'recvonly'
  141. })
  142. _self.pc
  143. .createOffer()
  144. .then(async function(offer) {
  145. await _self.pc.setLocalDescription(offer)
  146. return offer
  147. })
  148. .then(function(offer) {
  149. return new Promise(function(resolve, reject) {
  150. var port = _self.urlParams.port || 1985
  151. var api = _self.urlParams.user_query.play || '/rtc/v1/play/'
  152. if (api.lastIndexOf('/') !== api.length - 1) {
  153. api += '/'
  154. }
  155. var url = 'http://' + _self.urlParams.server + ':' + port + api
  156. for (var key in _self.urlParams.user_query) {
  157. if (key !== 'api' && key !== 'play') {
  158. url += '&' + key + '=' + _self.urlParams.user_query[key]
  159. }
  160. }
  161. var data = {
  162. api: url,
  163. streamurl: _self.urlParams.url,
  164. clientip: null,
  165. sdp: offer.sdp
  166. }
  167. JSWebrtc.HttpPost(url, JSON.stringify(data)).then(
  168. function(res) {
  169. resolve(res.sdp)
  170. },
  171. function(rej) {
  172. reject(rej)
  173. }
  174. )
  175. })
  176. })
  177. .then(function(answer) {
  178. return _self.pc.setRemoteDescription(
  179. new RTCSessionDescription({
  180. type: 'answer',
  181. sdp: answer
  182. })
  183. )
  184. })
  185. .catch(function(reason) {
  186. throw reason
  187. })
  188. if (this.autoplay) {
  189. this.play()
  190. }
  191. }
  192. play(ev) {
  193. if (this.animationId) {
  194. return
  195. }
  196. this.animationId = requestAnimationFrame(this.update.bind(this))
  197. this.paused = false
  198. }
  199. pause(ev) {
  200. if (this.paused) {
  201. return
  202. }
  203. cancelAnimationFrame(this.animationId)
  204. this.animationId = null
  205. this.isPlaying = false
  206. this.paused = true
  207. this.options.video.pause()
  208. if (this.options.onPause) {
  209. this.options.onPause(this)
  210. }
  211. }
  212. stop(ev) {
  213. this.pause()
  214. }
  215. destroy() {
  216. this.pause()
  217. this.pc && this.pc.close() && this.pc.destroy()
  218. this.audioOut && this.audioOut.destroy()
  219. }
  220. update() {
  221. this.animationId = requestAnimationFrame(this.update.bind(this))
  222. if (this.options.video.readyState < 4) {
  223. return
  224. }
  225. if (!this.isPlaying) {
  226. this.isPlaying = true
  227. this.options.video.play()
  228. if (this.options.onPlay) {
  229. this.options.onPlay(this)
  230. }
  231. }
  232. }
  233. }
  234. return Player
  235. })()
  236. export default JSWebrtc