Sin descripción

mobileSip.js 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. var outgoingSession = null,
  2. timeInterval = null,
  3. incomingSession = null,
  4. currentSession = null,
  5. calState, nativeStream = null,
  6. callVideoState = null,
  7. callVideoFail = null,
  8. dbCallVideoState = null;
  9. var bigVideoStyle = {
  10. "background-color": "#000000",
  11. "width": "100%",
  12. "height": "100%",
  13. "top": "0",
  14. "right": "0",
  15. "z-index": "1"
  16. }
  17. var smallVideoStyle = {
  18. "background-color": "#EEEEEE",
  19. "width": "20%",
  20. "height": "20%",
  21. "top": "10px",
  22. "right": "10px",
  23. "z-index": "2"
  24. }
  25. var localStream = null,
  26. userAgent = null,
  27. superviseMan = null,
  28. videoInputDevices = [],
  29. currentVideoIndex = 0,
  30. timer = null,
  31. oppoStream = null,
  32. peerData = null,
  33. timeOut = null;
  34. var myVideoView = document.getElementById('myVideo'); //我的本地视频
  35. var yourVideoView = document.getElementById('yourVideo'); //对方视频信息
  36. var getWidthScale = document.documentElement.clientWidth;
  37. $(function() {
  38. $(".videoMy video").css({
  39. "width": getWidthScale * 1.5 * 0.2 + "px",
  40. "margin-left": -getWidthScale * 1.5 * 0.2 / 2 + "px"
  41. })
  42. //yourVideoView.load()
  43. mediumInfo() //获取摄像头信息
  44. })
  45. //视频窗口大小调整
  46. function videoSize() {
  47. if(meetingState) {
  48. $(".videoYour video").css({
  49. "width": getWidthScale * 1 + "px",
  50. "margin-left": -getWidthScale * 1 / 2 + "px"
  51. })
  52. meetingState = false
  53. } else {
  54. $(".videoYour video").css({
  55. "width": getWidthScale * 2.7 + "px",
  56. "margin-left": -getWidthScale * 2.7 / 2 + "px"
  57. })
  58. }
  59. }
  60. //切换摄像头
  61. function shotCut() {
  62. if(currentVideoIndex == 1) {
  63. currentVideoIndex = 0;
  64. } else {
  65. currentVideoIndex = 1;
  66. };
  67. try {
  68. var ls = muteSession.connection.getLocalStreams()[0];
  69. //将传输的媒体流直接关闭掉
  70. ls.getTracks().forEach(function(track) {
  71. if(track.kind == 'video') {
  72. track.stop();
  73. }
  74. });
  75. //关闭本地媒体流
  76. if(nativeStream) {
  77. nativeStream.getVideoTracks()[0].stop();
  78. }
  79. navigator.mediaDevices.getUserMedia({
  80. audio: false, //这里是为了摄像头切换时,回显本地媒体,禁止本地声音
  81. video: {
  82. deviceId: videoInputDevices[currentVideoIndex].deviceId
  83. },
  84. }).then((stream) => {
  85. const tracks = stream.getVideoTracks()[0]; //摄像头切换只替换视频通道
  86. var sender = muteSession.connection.getSenders().find(function(s) {
  87. return s.track.kind == tracks.kind;
  88. });
  89. sender.replaceTrack(tracks);
  90. //本地摄像头切换
  91. nativeStream = stream
  92. myVideoView.srcObject = nativeStream;
  93. //微信端浏览器适配,需要先stop,然后执行这个函数
  94. myVideoView.onloadedmetadata = function() { //媒体流直接关闭掉后这里会重新执行
  95. if(nativeStream.active) { //在这里需要做判断,判断媒体流处于活动状态
  96. myVideoView.play();
  97. }
  98. }
  99. }).catch((res) => {
  100. alert('getUserMedia() error1: ' + res.name);
  101. })
  102. } catch(e) {
  103. alert(JSON.stringify(e));
  104. }
  105. }
  106. //监测当前传输速率
  107. function monitoringData() {
  108. //发送的数据
  109. muteSession.connection.getSenders().forEach(getData => {
  110. if(getData.track.kind === "audio") {
  111. getData.getStats().then(reports => {
  112. reports.forEach(report => {
  113. if(report.type === "outbound-rtp") {
  114. console.log("发送的数据audio===" + report.bytesSent)
  115. }
  116. })
  117. })
  118. } else if(getData.track.kind === "video") {
  119. getData.getStats().then(reports => {
  120. reports.forEach(report => {
  121. if(report.type === "outbound-rtp") {
  122. console.log("发送的数据video===" + report.bytesSent)
  123. // $(".senderSpeedVideo").text(report.bytesSent)
  124. }
  125. })
  126. })
  127. }
  128. })
  129. //接收的数据
  130. muteSession.connection.getReceivers().forEach(getData => {
  131. if(getData.track.kind === "audio") {
  132. getData.getStats().then(reports => {
  133. reports.forEach(report => {
  134. if(report.type === "inbound-rtp") {
  135. console.log("接收的数据audio===" + report.bytesReceived)
  136. // $(".receiverSpeedAudio").text(report.bytesReceived)
  137. }
  138. })
  139. })
  140. } else if(getData.track.kind === "video") {
  141. getData.getStats().then(reports => {
  142. reports.forEach(report => {
  143. if(report.type === "inbound-rtp") {
  144. console.log("接收的数据video===" + report.bytesReceived)
  145. // $(".receiverSpeedVideo").text(report.bytesReceived)
  146. $(".receiverSpeedVideo").show()
  147. $(".refreshImg").show()
  148. $(".receiverSpeedVideo").text("黑屏重置按钮")
  149. setTimeout(function() {
  150. $(".receiverSpeedVideo").hide()
  151. }, 5000)
  152. }
  153. })
  154. })
  155. }
  156. })
  157. }
  158. $(".internetSpeed img").click(function() {
  159. yourVideoView.play();
  160. })
  161. //获取摄像头,音频设备信息
  162. function mediumInfo() {
  163. navigator.mediaDevices.enumerateDevices()
  164. .then(gotDevices).catch(handleError);
  165. function gotDevices(deviceInfos) {
  166. deviceInfos.forEach(function(n) {
  167. if(n.kind === 'videoinput') {
  168. videoInputDevices.push(n);
  169. }
  170. })
  171. }
  172. function handleError(error) {
  173. //alert(JSON.stringify(error));
  174. }
  175. }
  176. //注册成功事件
  177. function registered() {
  178. $(".registStatus").show()
  179. if($(".superviseBtn").text() == "我是市民") {
  180. VideoReqBindAgent()
  181. } else if($(".superviseBtn").text() == "我是督办专员") {
  182. $(".registStatus").text("连接成功")
  183. $("#account").val(extenNum)
  184. }
  185. }
  186. //电话呼入事件
  187. function newRTCSession() {
  188. $(".mui-content").hide();
  189. $(".callHtml").show();
  190. $(".dropIcon").hide()
  191. $(".answerIcon").show();
  192. if(!nativeStream) {
  193. captureLocalMediaVideo()
  194. }
  195. localMediaStream()
  196. }
  197. //确认呼叫后触发
  198. function confirmed() {
  199. $(".dropIcon").show()
  200. $(".answerIcon").hide()
  201. //延时函数
  202. timeOut = setTimeout(function() {
  203. monitoringData()
  204. }, 10000)
  205. }
  206. //peerconnection 媒体传输事件
  207. function peerconnection() {
  208. $(".videoYour").show();
  209. $(".customerImg").show();
  210. $(".rightImg").hide();
  211. }
  212. //点击对方视频框
  213. $(".videoYour").click(function() {
  214. if(!$(this).attr("index")) {
  215. $(this).css(bigVideoStyle)
  216. $(".videoYour video").css({
  217. "width": getWidthScale * 2.7 + "px",
  218. "margin-left": -getWidthScale * 2.7 / 2 + "px"
  219. })
  220. $(".videoMy").css(smallVideoStyle)
  221. $(".videoMy video").css({
  222. "width": getWidthScale * 1.5 * 0.2 + "px",
  223. "margin-left": -getWidthScale * 1.5 * 0.2 / 2 + "px"
  224. })
  225. $(this).attr("index", "1")
  226. $(".videoMy").removeAttr("index")
  227. }
  228. })
  229. //点击我方视频框
  230. $(".videoMy").click(function() {
  231. if(!$(this).attr("index")) {
  232. $(this).css(bigVideoStyle)
  233. $(".videoMy video").css({
  234. "width": getWidthScale * 1.5 + "px",
  235. "margin-left": -getWidthScale * 1.5 / 2 + "px"
  236. })
  237. $(".videoYour").css(smallVideoStyle)
  238. $(".videoYour video").css({
  239. "width": getWidthScale * 2.7 * 0.2 + "px",
  240. "margin-left": -getWidthScale * 2.7 * 0.2 / 2 + "px"
  241. })
  242. $(this).attr("index", "1")
  243. $(".videoYour").removeAttr("index")
  244. }
  245. })
  246. //视频呼叫
  247. $(".videoCall").click(function() {
  248. if($(".registStatus").text() == "已注销") {
  249. alert("话机已注销,如有需要请重新进入")
  250. return
  251. }
  252. callVideoState = true;
  253. callVideoFail = true;
  254. calState = $(this).attr("data-attr");
  255. $(".videoMy").show();
  256. $(".answerIcon").hide()
  257. $(".leftText").html("连接中");
  258. videoSize(); //视频窗口大小
  259. if(!nativeStream) {
  260. captureLocalMediaVideo()
  261. }
  262. localMediaStream(); //获取本地媒体流
  263. })
  264. //静音
  265. $(".muteBtn").click(function() {
  266. muteSession.mute({
  267. 'audio': true, // Local audio is muted
  268. })
  269. $(".muteBtn").hide();
  270. $(".unMuteBtn").show();
  271. })
  272. //取消静音
  273. $(".unMuteBtn").click(function() {
  274. muteSession.unmute({
  275. 'audio': true, // Local audio is muted
  276. })
  277. $(".muteBtn").show();
  278. $(".unMuteBtn").hide();
  279. })
  280. //关闭摄像头 摄像头切换时会遇到问题
  281. $(".cameraBtn").click(function() {
  282. muteSession.mute({
  283. 'video': true, // Local audio is muted
  284. })
  285. $(".cameraBtn").hide();
  286. $(".unCameraBtn").show();
  287. })
  288. //取消关闭摄像头
  289. $(".unCameraBtn").click(function() {
  290. muteSession.unmute({
  291. 'video': true, // Local audio is muted
  292. })
  293. $(".cameraBtn").show();
  294. $(".unCameraBtn").hide();
  295. })
  296. //视频呼叫
  297. function videoCall() {
  298. $(".mui-content").hide();
  299. $(".callHtml").show();
  300. var sip_phone_number_ = callNum.toString();
  301. var options = {
  302. 'eventHandlers': eventHandlers,
  303. 'mediaConstraints': {
  304. 'audio': true,
  305. 'video': true
  306. },
  307. 'mediaStream': localStream
  308. };
  309. callVideoState = false;
  310. dbCallVideoState = false;
  311. outgoingSession = userAgent.call(sip_phone_number_, options);
  312. }
  313. //接听
  314. function answerCall() {
  315. clearTimeout(timeInterval)
  316. videoSize(); //视频窗口大小
  317. if(incomingSession) {
  318. incomingSession.answer({
  319. 'mediaConstraints': {
  320. 'audio': true,
  321. 'video': true
  322. },
  323. 'mediaStream': localStream
  324. });
  325. incomingSession = null;
  326. }
  327. }
  328. //挂断
  329. function hangupCall() {
  330. $(".receiverSpeedVideo").text("")
  331. clearTimeout(timeOut)
  332. clearInterval(timer)
  333. closeMediaVideo()
  334. $(".refreshImg").hide()
  335. userAgent.terminateSessions();
  336. console.log('挂断----------->');
  337. if($(".superviseBtn").text() == "我是督办专员") {
  338. $(".mui-content").show();
  339. $(".callHtml").hide();
  340. videoDesExten()
  341. } else if($(".superviseBtn").text() == "我是市民") {
  342. if(acceptExtenNum) {
  343. window.location.href = "acceptingMan.html?extenNum=" + $("#account").val() +
  344. "&telephone=" + $("#telephone").val() +
  345. "&mathRanDom=" + Math.random() +
  346. "&acceptExtenNum=" + acceptExtenNum
  347. } else {
  348. window.location.href = "acceptingMan.html?extenNum=" + $("#account").val() +
  349. "&telephone=" + $("#telephone").val() +
  350. "&mathRanDom=" + Math.random()
  351. }
  352. }
  353. }
  354. //注销
  355. function unReg() {
  356. // window.localStorage.setItem('mathRanDom',Math.random())
  357. if(!superviseMan) {
  358. userAgent.unregister(true);
  359. $(".registStatus").html("已注销")
  360. $(".mui-content").show();
  361. $(".callHtml").hide();
  362. $(".dropIcon").hide();
  363. $(".answerIcon").hide();
  364. console.log('注销----------->');
  365. } else {
  366. if(acceptExtenNum) {
  367. window.location.href = "acceptingMan.html?extenNum=" + $("#account").val() +
  368. "&telephone=" + $("#telephone").val() +
  369. "&mathRanDom=" + Math.random() +
  370. "&acceptExtenNum=" + acceptExtenNum
  371. } else {
  372. window.location.href = "acceptingMan.html?extenNum=" + $("#account").val() +
  373. "&telephone=" + $("#telephone").val() +
  374. "&mathRanDom=" + Math.random()
  375. }
  376. }
  377. }
  378. //开启本地摄像头
  379. function captureLocalMediaVideo() {
  380. navigator.mediaDevices.getUserMedia({
  381. video: {
  382. deviceId: videoInputDevices[currentVideoIndex].deviceId
  383. },
  384. audio: false
  385. }).then((stream) => {
  386. nativeStream = stream;
  387. myVideoView.srcObject = nativeStream;
  388. myVideoView.onloadedmetadata = function() {
  389. if(nativeStream.active) { //在这里需要做判断
  390. myVideoView.play();
  391. }
  392. }
  393. }).catch((res) => {
  394. alert('getUserMedia() error2: ' + res.name);
  395. })
  396. }
  397. //获取本地媒体流
  398. function localMediaStream() {
  399. navigator.mediaDevices.getUserMedia({
  400. video: {
  401. deviceId: videoInputDevices[currentVideoIndex].deviceId
  402. },
  403. audio: true
  404. }).then((stream) => {
  405. localStream = stream;
  406. if(callVideoState) {
  407. extenBind()
  408. }
  409. if(dbCallVideoState) {
  410. videoReqIdeAgent()
  411. }
  412. }).catch((res) => {
  413. // alert('getUserMedia() error3: ' + res.name);
  414. setTimeout(function() {
  415. localMediaStream()
  416. }, 1000)
  417. })
  418. // navigator.getUserMedia({
  419. // video: {
  420. // deviceId: videoInputDevices[currentVideoIndex].deviceId
  421. // },
  422. // audio: true
  423. // }, function(stream) {
  424. // localStream = stream;
  425. // if (callVideoState) { extenBind() }
  426. // if (dbCallVideoState) { videoReqIdeAgent() }
  427. // }, function(e) {
  428. // alert('getUserMedia() error: ' + e.name);
  429. // });
  430. }
  431. // 关闭摄像头
  432. function closeMediaVideo() {
  433. if(nativeStream) {
  434. nativeStream.getTracks().forEach(function(track) {
  435. track.stop();
  436. });
  437. }
  438. if(localStream) {
  439. localStream.getTracks().forEach(function(track) {
  440. track.stop();
  441. });
  442. }
  443. if(oppoStream) {
  444. oppoStream.getTracks().forEach(function(track) {
  445. track.stop();
  446. });
  447. }
  448. //yourVideoView.remove();
  449. }
  450. function sipCallRTCSession(e, state) {
  451. console.log(e.session)
  452. console.log(state) // 1是呼出,2是呼入
  453. e.session.on("confirmed", function(data){
  454. console.log("confirmed")
  455. if(e.session.connection.getReceivers){
  456. peerconnection()
  457. callVideoFail = false
  458. console.log(e.session.connection.getReceivers())
  459. remoteStream = new MediaStream();
  460. e.session.connection.getReceivers().forEach(element => {
  461. // track可能一个音轨或者视频轨迹
  462. remoteStream.addTrack(element.track)
  463. })
  464. $(".videoYour").empty();
  465. $(".videoYour").append('<video id="yourVideo" autoplay ></video>');
  466. yourVideoView = document.getElementById('yourVideo');
  467. // console.log(remoteStream) confirmed
  468. videoSize()
  469. yourVideoView.srcObject = remoteStream
  470. yourVideoView.onloadedmetadata = function() {
  471. yourVideoView.play();
  472. yourVideoView.muted = true;
  473. state===1?console.log("呼叫成功"):console.log("接听成功")
  474. }
  475. }
  476. })
  477. }
  478. function testStart() {
  479. console.info("get input info: sip_uri = ", sip_uri_, " sip_password = ", sip_password_, " ws_uri = ", ws_uri_);
  480. var socket = new JsSIP.WebSocketInterface(ws_uri_);
  481. var configuration = {
  482. sockets: [socket],
  483. outbound_proxy_set: ws_uri_,
  484. uri: sip_uri_, //与用户代理关联的SIP URI(字符串)。这是您的提供商提供给您的SIP地址
  485. password: sip_password_, //SIP身份验证密码
  486. contact_uri: 'sip:' + $("#account").val() +contact_uri,
  487. register: true, //指示启动时JsSIP用户代理是否应自动注册
  488. session_timers: false, //启用会话计时器(根据RFC 4028)
  489. register_expires: 60,
  490. };
  491. userAgent = new JsSIP.UA(configuration);
  492. // JsSIP.debug.enable('JsSIP:*');
  493. JsSIP.debug.disable('JsSIP:*');
  494. //注册成功
  495. userAgent.on('registered', function(data) {
  496. console.info("registered: ", data.response.status_code, ",", data.response.reason_phrase);
  497. registered();
  498. captureLocalMediaVideo()
  499. });
  500. //注册失败
  501. userAgent.on('registrationFailed', function(data) {
  502. console.log('注册失败----------->');
  503. });
  504. //在注册到期前几秒钟触发,可在这里重新注册
  505. userAgent.on('registrationExpiring', function() {
  506. // console.log('注册到期----------->');
  507. // userAgent.register(); //重新注册执行的函数
  508. });
  509. //每次传输连接尝试均触发。
  510. userAgent.on('connecting ', function(data) {
  511. console.log('建立连接----------->');
  512. })
  513. //建立传输连接时触发。
  514. userAgent.on('connected ', function(data) {
  515. console.log('连接成功----------->');
  516. })
  517. //当传输连接尝试(或自动重新尝试)失败时触发。。
  518. userAgent.on('disconnected ', function(data) {
  519. console.log('连接失败----------->')
  520. })
  521. //为传入或传出会话/呼叫激发。
  522. userAgent.on('newRTCSession', function(data) {
  523. console.log('建立会话----------->')
  524. console.info('onNewRTCSession: ', data);
  525. muteSession = data.session
  526. var originator = data.originator;
  527. var session = data.session;
  528. var request = data.request;
  529. if(data.originator == 'remote') {
  530. console.log("电话呼入----------->"); //电话呼入
  531. sipCallRTCSession(data, 2)
  532. incomingSession = data.session;
  533. newRTCSession();
  534. timeInterval = setInterval(function() {
  535. if(incomingSession.isEnded()) {
  536. unReg()
  537. clearTimeout(timeInterval)
  538. }
  539. }, 2000)
  540. } else {
  541. sipCallRTCSession(data, 1)
  542. outgoingSession = data.session;
  543. outgoingSession.on('connecting', function(data) {
  544. currentSession = outgoingSession;
  545. outgoingSession = null;
  546. });
  547. }
  548. //接受呼叫时激发
  549. data.session.on('accepted', function(data) {
  550. console.info("接受呼叫----------->");
  551. if(data.originator == 'remote' && currentSession == null) {
  552. currentSession = incomingSession;
  553. incomingSession = null;
  554. }
  555. });
  556. //确认呼叫后激发
  557. data.session.on('confirmed', function(data) {
  558. console.info("确认呼叫----------->");
  559. $(".leftText").html("通话中");
  560. confirmed();
  561. if(data.originator == 'remote' && currentSession == null) {
  562. currentSession = incomingSession;
  563. incomingSession = null;
  564. }
  565. });
  566. //SDP传递之前激发。可以修改传入和传出SDP的机制。
  567. data.session.on('sdp', function(data) {
  568. console.info("sdp消息----------->");
  569. });
  570. //接收或生成请求的SIP类响应时激发。该事件在SDP处理之前触发,以便在需要时对其进行微调,甚至通过删除数据对象中响应参数的主体来删除它
  571. data.session.on('progress', function(data) {
  572. console.info("接收到sip响应----------->");
  573. if(originator != 'remote') {
  574. $(".dropIcon").show()
  575. }
  576. });
  577. });
  578. //连接到信令服务器,并恢复以前的状态,如果以前停止。重新开始时,如果UA配置中的参数设置为register:true,则向SIP域注册。
  579. userAgent.start();
  580. //网页中有些不稳定,所以开启了定时注册
  581. timer = setInterval(function() {
  582. userAgent.register(); //注册到期时,重新注册,这个函数不会影响,话机状态
  583. console.log("重新注册了----------->")
  584. }, 30 * 1000)
  585. }
  586. var eventHandlers = {
  587. 'progress': function(e) {
  588. console.log('接收到响应----------->');
  589. },
  590. 'failed': function(e) {
  591. if(callVideoFail) {
  592. // setTimeout(function() {
  593. // videoCall()
  594. // }, 2000)
  595. }
  596. console.log('呼叫失败');
  597. },
  598. 'ended': function(e) {
  599. console.log('通话结束----------->');
  600. unReg();
  601. },
  602. 'confirmed': function(e) {
  603. console.log('确认呼叫----------->');
  604. }
  605. };