audio.html 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <link rel="stylesheet" type="text/css" href="./css/index.css" />
  8. <title id="title"></title>
  9. <style>
  10. html, body {
  11. height: 100%;
  12. }
  13. body {
  14. margin: 0;
  15. }
  16. video {
  17. width: 100%;
  18. height: 100%;
  19. position: absolute;
  20. left: 0;
  21. top: 0;
  22. z-index: -1;
  23. }
  24. </style>
  25. </head>
  26. <body>
  27. <!-- <video class="Bvideo" id="Big_video" preload autoplay onclick="Bvideoselc()"></video> -->
  28. <!-- <video class="Svideo" id="sm_video" preload muted autoplay onclick="Svideoselc()"></video> -->
  29. <audio id="my_audio" autoplay></audio>
  30. <div class="contentColumnC" style="width: 100%;margin-top: 60px;"">
  31. <div id="ICnote"></div>
  32. <img class="iconImg" style="margin-top: 5px;" src="./img/logo.png" alt="" onclick="guaduan()"/>
  33. <div class="contentInRowC" style="width: 100%;margin-top: 10px;">
  34. <div id="markNote"></div>
  35. <img class="calling" src="./img/loading2.gif" alt="" />
  36. </div>
  37. </div>
  38. <div style="width: 100%;margin-top: 100px;">
  39. <div class="contentColumnC">
  40. <img id='dianhua_Img' class="guadanImg" style="margin-top: 5px;" src="./img/jietong.png" alt="" onclick="guaduan()"/>
  41. </div>
  42. </div>
  43. <div>
  44. <div id="sdpkNote"></div>
  45. </div>
  46. </body>
  47. <script type="text/javascript" src="./js/lib/uniwebviewsdk.js"></script>
  48. <script>
  49. let language = getQueryVariable('language');
  50. let title,state1,state2,state3,state4,state5,ICnote;
  51. const title_div = document.getElementById('title');
  52. const ICnote_div = document.getElementById('ICnote');
  53. let localStream = null;
  54. let localCall = 0;
  55. let localCandidata=null;
  56. let peer = null;
  57. let video=null;
  58. let jietong=false;
  59. let payload=null;
  60. let markindex=0;
  61. // const Big_video = document.getElementById('Big_video');
  62. // const sm_video = document.getElementById('sm_video');
  63. // const my_audio = document.getElementById('my_audio');
  64. const dianhua_Img = document.getElementById('dianhua_Img');
  65. const markNote = document.getElementById('markNote');
  66. const sdpkNote = document.getElementById('sdpkNote');
  67. //====================================================
  68. function getQueryVariable(variable) {
  69. var query = decodeURI(window.location.search.substring(1));
  70. var vars = query.split("&");
  71. for (var i = 0; i < vars.length; i++) {
  72. var pair = vars[i].split("=");
  73. if (pair[0] == variable) {
  74. return pair[1];
  75. }
  76. }
  77. return (false);
  78. }
  79. function Bvideoselc(){
  80. if(localStream!=null){
  81. //Big_video.srcObject =localStream;
  82. Big_video.setAttribute('autoplay', true); /* THIS */
  83. }
  84. }
  85. function Svideoselc(){
  86. if(localStream!=null){
  87. //sm_video.srcObject =localStream;
  88. sm_video.setAttribute('autoplay', true); /* THIS */
  89. }
  90. }
  91. function guaduan(){
  92. if(jietong){
  93. if(peer){
  94. peer.close();
  95. }
  96. uni.postMessage({
  97. data: {
  98. data:'', // 回传
  99. type:88
  100. },
  101. });
  102. }
  103. else{
  104. jietong=true;
  105. markNote.innerHTML=state2;
  106. if(payload!=null){
  107. RCstartWebRct(payload);
  108. }
  109. dianhua_Img.src = "./img/guaduandd.png"
  110. }
  111. }
  112. function duifangguaduan(){
  113. if(jietong){
  114. if(peer){
  115. peer.close();
  116. }
  117. markNote.innerHTML=state4;
  118. }
  119. }
  120. //====================================================
  121. function appAct (obj) {
  122. if(obj.type==1){//主动发起im通话
  123. localCall=1;
  124. //startWebRct(obj.type);
  125. markNote.innerHTML=state1;
  126. }
  127. else if(obj.type==2){//收到发起方sdp offer
  128. if(localCall==1){//发起方收到接受方 sdp answer
  129. markNote.innerHTML=state2;
  130. RCremoteData(obj.payload);
  131. }
  132. else{//接受方 收到发起方sdp offer
  133. //markNote.innerHTML=state1;
  134. payload=obj.payload;
  135. if(jietong){
  136. //markNote.innerHTML=state2;
  137. RCstartWebRct(obj.payload);//启动wbrtc
  138. }
  139. }
  140. }
  141. else if(obj.type==3){//收到candidate
  142. //markNote.innerHTML=state2;
  143. //sdpkNote.innerHTML=JSON.stringify(obj.payload);
  144. for(var i=0;i<obj.payload.length;i++){//收到candidate 添加到Rct
  145. peer.addIceCandidate(obj.payload[i]);
  146. }
  147. if(localCall!=1){//接收方收到candidate 回应自己的candidate给发起方
  148. uni.postMessage({
  149. data: {
  150. data:localCandidata, //应答方回应candidate
  151. type:3
  152. },
  153. });
  154. }
  155. }
  156. }
  157. async function startCapture(displayMediaOptions) {
  158. try {
  159. localStream = await navigator.mediaDevices.getUserMedia(displayMediaOptions);
  160. // Big_video.srcObject =localStream;
  161. // Big_video.setAttribute('autoplay', true); /* THIS */
  162. // markindex=markindex+1;
  163. // uni.postMessage({
  164. // data: {
  165. // data:markindex, // 回传
  166. // type:99999
  167. // },
  168. // });
  169. uni.postMessage({
  170. data: {
  171. data:'', // 回传
  172. type:99
  173. },
  174. });
  175. } catch(err) {
  176. console.error(err);
  177. }
  178. }
  179. async function startWebRct(type){
  180. peer = new RTCPeerConnection(
  181. {
  182. iceServers:[
  183. {
  184. urls:'stun:stun.l.google.com:19302',
  185. }
  186. ]
  187. }
  188. );
  189. //添加本地音视频
  190. localStream.getTracks().forEach((track) => {
  191. peer.addTrack(track, localStream)
  192. });
  193. //创建本地offer
  194. const offer = peer.createOffer({
  195. offerToReceiveAudio:1,
  196. offerToReceiveVideo:0
  197. });
  198. //记录本地offer
  199. offer.then(value => {
  200. peer.setLocalDescription(value);
  201. uni.postMessage({
  202. data: {
  203. data:value, // 回传并推送offer
  204. type:2
  205. },
  206. });
  207. }).catch(error => {
  208. });
  209. peer.onconnectionstatechange = function (ev) {
  210. if(peer.connectionState=="closed"){
  211. markNote.innerHTML=state5;
  212. }
  213. if(peer.connectionState=="connected"){
  214. markNote.innerHTML=state3;
  215. }
  216. if(peer.connectionState=="connecting"){
  217. markNote.innerHTML=state2;
  218. }
  219. if(peer.connectionState=="disconnected"){
  220. markNote.innerHTML=state4;
  221. }
  222. };
  223. localCandidata=[]
  224. peer.onicecandidate = function (event) {
  225. if (event.candidate){
  226. localCandidata.push(event.candidate);
  227. }
  228. }
  229. startCommunicate();
  230. }
  231. //发起方收到 远端SDP answer 保存并发送candidate
  232. async function RCremoteData(rcData){//收到remoteAnswer
  233. //记录远端offer
  234. await peer.setRemoteDescription(rcData)
  235. uni.postMessage({
  236. data: {
  237. data:localCandidata, // 发起方先发candidate
  238. type:3
  239. },
  240. });
  241. }
  242. function startCommunicate(){
  243. peer.ontrack = (e) => {
  244. if(e.streams[0]){
  245. var otherVideos = document.querySelector('#my_audio');
  246. //var otherVideos = document.querySelector('#Big_video');
  247. otherVideos.srcObject = e.streams[0];
  248. //otherVideos.setAttribute('autoplay', true); /* THIS */
  249. uni.postMessage({
  250. data: {
  251. data:JSON.stringify(e.streams[0]), // 回传并推送offer
  252. type:'sss'
  253. },
  254. });
  255. }
  256. // sm_video.srcObject =localStream;
  257. // sm_video.setAttribute('autoplay', true); /* THIS */
  258. }
  259. }
  260. async function RCstartWebRct(payload){
  261. peer = new RTCPeerConnection(
  262. {
  263. iceServers:[
  264. {
  265. urls:'stun:stun.l.google.com:19302',
  266. }
  267. ],
  268. offerExtmapAllowMixed:false
  269. }
  270. );
  271. // uni.postMessage({
  272. // data: {
  273. // data:1, //应答方回应candidate
  274. // type:33333
  275. // },
  276. // });
  277. //添加本地音视频
  278. localStream.getTracks().forEach((track) => {
  279. peer.addTrack(track, localStream)
  280. })
  281. localCandidata=[];
  282. peer.onicecandidate = function (event) {
  283. if (event.candidate){
  284. //let strcandidate=JSON.stringify(event.candidate);
  285. localCandidata.push(event.candidate);
  286. }
  287. }
  288. startCommunicate();
  289. // uni.postMessage({
  290. // data: {
  291. // data:2, //应答方回应candidate
  292. // type:33333
  293. // },
  294. // });
  295. peer.onconnectionstatechange = function (ev) {
  296. if(peer.connectionState=="closed"){
  297. markNote.innerHTML=state5;
  298. }
  299. if(peer.connectionState=="connected"){
  300. markNote.innerHTML=state3;
  301. }
  302. if(peer.connectionState=="connecting"){
  303. markNote.innerHTML=state2;
  304. }
  305. if(peer.connectionState=="disconnected"){
  306. markNote.innerHTML=state4;
  307. }
  308. };
  309. //记录远端offer
  310. //记录远端offer
  311. const offer = new RTCSessionDescription(payload);
  312. uni.postMessage({
  313. data: {
  314. data:offer, //应答方回应candidate
  315. type:33333
  316. },
  317. });
  318. await peer.setRemoteDescription(offer);
  319. //await peer.setRemoteDescription(payload)//iOS发起的通话 安卓音频适配异常----------------
  320. // uni.postMessage({
  321. // data: {
  322. // data:4, //应答方回应candidate
  323. // type:33333
  324. // },
  325. // });
  326. const remoteAnswer = await peer.createAnswer();
  327. // uni.postMessage({
  328. // data: {
  329. // data:remoteAnswer, //应答方回应candidate
  330. // type:33333
  331. // },
  332. // });
  333. //记录本地offer
  334. await peer.setLocalDescription(remoteAnswer);
  335. //推送remoteAnswer
  336. uni.postMessage({
  337. data: {
  338. data:remoteAnswer, // 回传并推送offer
  339. type:2
  340. },
  341. });
  342. }
  343. function initRtc() {
  344. if(language=='yuenan'){//越南语
  345. ICnote='CTE Rider yêu cầu IM Voice Call';
  346. title='IM Cuộc gọi thoại';
  347. state1='Đang gọi';
  348. state2='Đang kết nối';
  349. state3='Đã kết nối';
  350. state4='Bị treo';
  351. state5='Kết thúc cuộc gọi';
  352. }
  353. if(language=='zh-Hans'){//简体中文
  354. ICnote='CTE骑手请求IM语音通话'
  355. title='IM 语音通话';
  356. state1='正在呼叫';
  357. state2='正在接通';
  358. state3='已接通';
  359. state4='已挂断';
  360. state5='结束通话';
  361. }
  362. if(language=='zh-Hant'){//繁体中文
  363. ICnote='CTE騎手請求IM語音通話'
  364. title='IM 語音通話';
  365. state1='正在呼叫';
  366. state2='正在接通';
  367. state3='已接通';
  368. state4='已掛斷';
  369. state5='結束通話';
  370. }
  371. markNote.innerHTML=title;
  372. ICnote_div.innerHTML=ICnote;
  373. title_div.innerHTML=title;
  374. setTimeout(() => {
  375. startCapture({ video: true, audio: true});
  376. //startCapture({audio: true});
  377. }, 1000)
  378. return;
  379. }
  380. function releaseTack(){
  381. if(peer){
  382. peer.close();
  383. }
  384. }
  385. window.onload=initRtc;
  386. window.onunload=releaseTack;
  387. </script>
  388. </html>