Keine Beschreibung

mobileSip.js 17KB

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